//
// System.Drawing.gdipFunctions.cs
//
// Authors:
// Alexandre Pigolkine (pigolkine@gmx.de)
// Jordi Mas i Hernandez (jordi@ximian.com)
// Sanjay Gupta (gsanjay@novell.com)
// Ravindra (rkumar@novell.com)
// Peter Dennis Bartok (pbartok@novell.com)
//
// Copyright (C) 2004 - 2006 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Security;
#if NET_2_0
using System.Runtime.InteropServices.ComTypes;
#else
using IStream = System.Runtime.InteropServices.UCOMIStream;
#endif
namespace System.Drawing
{
///
/// GDI+ API Functions
///
[SuppressUnmanagedCodeSecurity]
internal class GDIPlus
{
public const int FACESIZE = 32;
public const int LANG_NEUTRAL = 0;
public static IntPtr Display = IntPtr.Zero;
public static bool UseX11Drawable;
public static bool UseQuartzDrawable = (Environment.GetEnvironmentVariable ("MONO_MWF_USE_QUARTZ_BACKEND") != null);
public static bool UseCocoaDrawable = (Environment.GetEnvironmentVariable ("MONO_GDIP_USE_COCOA_BACKEND") != null);
#region gdiplus.dll functions
// startup / shutdown
[DllImport("gdiplus.dll")]
static internal extern Status GdiplusStartup(ref ulong token, ref GdiplusStartupInput input, ref GdiplusStartupOutput output);
[DllImport("gdiplus.dll")]
static internal extern void GdiplusShutdown(ref ulong token);
internal static ulong GdiPlusToken = 0;
static void ProcessExit (object sender, EventArgs e)
{
// Called all pending objects and claim any pending handle before
// shutting down
GC.Collect ();
GC.WaitForPendingFinalizers ();
GdiPlusToken = 0;
// This causes crashes in MS GDI+ because this call occurs before
// all managed GDI objects are finalized. When they are finalized they call
// into a shutdown GDI+ and we crash.
//GdiplusShutdown (ref GdiPlusToken);
// This causes crashes in Mono libgdiplus because this call
// occurs before all managed GDI objects are finalized
// When they are finalized they use the closed display and
// crash
//if (UseX11Drawable && Display != IntPtr.Zero) {
// XCloseDisplay (Display);
//}
}
static GDIPlus ()
{
// check for Unix platforms - see FAQ for more details
// http://www.mono-project.com/FAQ:_Technical#How_to_detect_the_execution_platform_.3F
int platform = (int) Environment.OSVersion.Platform;
UseX11Drawable = ((platform == 4) || (platform == 128));
GdiplusStartupInput input = GdiplusStartupInput.MakeGdiplusStartupInput();
GdiplusStartupOutput output = GdiplusStartupOutput.MakeGdiplusStartupOutput();
try {
GdiplusStartup (ref GdiPlusToken, ref input, ref output);
}
catch (TypeInitializationException) {
Console.Error.WriteLine (
"* ERROR: Can not initialize GDI+ library\n" +
"\n" +
"Please check http://www.mono-project.com/Problem:GDIPlusInit for details");
}
AppDomain.CurrentDomain.ProcessExit += new EventHandler (ProcessExit);
}
// Copies a Ptr to an array of Points and releases the memory
static public void FromUnManagedMemoryToPointI(IntPtr prt, Point [] pts)
{
int nPointSize = Marshal.SizeOf(pts[0]);
IntPtr pos = prt;
for (int i=0; i 0 && buf != IntPtr.Zero) {
Marshal.Copy (start_buf, 0, (IntPtr) (buf.ToInt64()), bytesRead);
}
start_buf_pos = 0;
start_buf_len = bytesRead;
return bytesRead;
}
public StreamGetHeaderDelegate GetHeaderDelegate {
get {
if (stream != null && stream.CanRead) {
if (sghd == null) {
sghd = new StreamGetHeaderDelegate (StreamGetHeaderImpl);
}
return sghd;
}
return null;
}
}
public int StreamGetBytesImpl (IntPtr buf, int bufsz, bool peek)
{
if (buf == IntPtr.Zero && peek) {
return -1;
}
if (bufsz > managedBuf.Length)
managedBuf = new byte[bufsz];
int bytesRead = 0;
long streamPosition = 0;
if (bufsz > 0) {
if (stream.CanSeek) {
streamPosition = stream.Position;
}
if (start_buf_len > 0) {
if (start_buf_len > bufsz) {
Array.Copy(start_buf, start_buf_pos, managedBuf, 0, bufsz);
start_buf_pos += bufsz;
start_buf_len -= bufsz;
bytesRead = bufsz;
bufsz = 0;
} else {
// this is easy
Array.Copy(start_buf, start_buf_pos, managedBuf, 0, start_buf_len);
bufsz -= start_buf_len;
bytesRead = start_buf_len;
start_buf_len = 0;
}
}
if (bufsz > 0) {
try {
bytesRead += stream.Read (managedBuf, bytesRead, bufsz);
} catch (IOException) {
return -1;
}
}
if (bytesRead > 0 && buf != IntPtr.Zero) {
Marshal.Copy (managedBuf, 0, (IntPtr) (buf.ToInt64()), bytesRead);
}
if (!stream.CanSeek && (bufsz == 10) && peek) {
// Special 'hack' to support peeking of the type for gdi+ on non-seekable streams
}
if (peek) {
if (stream.CanSeek) {
// If we are peeking bytes, then go back to original position before peeking
stream.Seek (streamPosition, SeekOrigin.Begin);
} else {
throw new NotSupportedException();
}
}
}
return bytesRead;
}
public StreamGetBytesDelegate GetBytesDelegate {
get {
if (stream != null && stream.CanRead) {
if (sgbd == null) {
sgbd = new StreamGetBytesDelegate (StreamGetBytesImpl);
}
return sgbd;
}
return null;
}
}
public long StreamSeekImpl (int offset, int whence)
{
// Make sure we have a valid 'whence'.
if ((whence < 0) || (whence > 2))
return -1;
// Invalidate the start_buf if we're actually going to call a Seek method.
start_buf_pos += start_buf_len;
start_buf_len = 0;
SeekOrigin origin;
// Translate 'whence' into a SeekOrigin enum member.
switch (whence)
{
case 0: origin = SeekOrigin.Begin; break;
case 1: origin = SeekOrigin.Current; break;
case 2: origin = SeekOrigin.End; break;
// The following line is redundant but necessary to avoid a
// "Use of unassigned local variable" error without actually
// initializing 'origin' to a dummy value.
default: return -1;
}
// Do the actual seek operation and return its result.
return stream.Seek ((long) offset, origin);
}
public StreamSeekDelegate SeekDelegate {
get {
if (stream != null && stream.CanSeek) {
if (skd == null) {
skd = new StreamSeekDelegate (StreamSeekImpl);
}
return skd;
}
return null;
}
}
public int StreamPutBytesImpl (IntPtr buf, int bufsz)
{
if (bufsz > managedBuf.Length)
managedBuf = new byte[bufsz];
Marshal.Copy (buf, managedBuf, 0, bufsz);
stream.Write (managedBuf, 0, bufsz);
return bufsz;
}
public StreamPutBytesDelegate PutBytesDelegate {
get {
if (stream != null && stream.CanWrite) {
if (spbd == null) {
spbd = new StreamPutBytesDelegate (StreamPutBytesImpl);
}
return spbd;
}
return null;
}
}
public void StreamCloseImpl ()
{
stream.Close ();
}
public StreamCloseDelegate CloseDelegate {
get {
if (stream != null) {
if (scd == null) {
scd = new StreamCloseDelegate (StreamCloseImpl);
}
return scd;
}
return null;
}
}
public long StreamSizeImpl ()
{
try {
return stream.Length;
} catch {
return -1;
}
}
public StreamSizeDelegate SizeDelegate {
get {
if (stream != null) {
if (ssd == null) {
ssd = new StreamSizeDelegate (StreamSizeImpl);
}
return ssd;
}
return null;
}
}
}
/* Mac only function calls */
[DllImport("gdiplus.dll")]
internal static extern Status GdipCreateFromQuartz_macosx (IntPtr cgref, int width, int height, out IntPtr graphics);
/* Linux only function calls*/
[DllImport("gdiplus.dll")]
internal static extern Status GdipSetVisibleClip_linux (IntPtr graphics, ref Rectangle rect);
[DllImport("gdiplus.dll")]
internal static extern Status GdipCreateFromXDrawable_linux (IntPtr drawable, IntPtr display, out IntPtr graphics);
// Stream functions for non-Win32 (libgdiplus specific(
[DllImport("gdiplus.dll")]
static internal extern Status GdipLoadImageFromDelegate_linux ( StreamGetHeaderDelegate getHeader, StreamGetBytesDelegate getBytes, StreamPutBytesDelegate putBytes,
StreamSeekDelegate doSeek, StreamCloseDelegate close, StreamSizeDelegate size, out IntPtr image);
[DllImport("gdiplus.dll")]
static internal extern Status GdipSaveImageToDelegate_linux ( IntPtr image, StreamGetBytesDelegate getBytes, StreamPutBytesDelegate putBytes,
StreamSeekDelegate doSeek, StreamCloseDelegate close, StreamSizeDelegate size, ref Guid encoderClsID, IntPtr encoderParameters );
#endregion
}
}