// // 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) // Sebastien Pouliot // // Copyright (C) 2004 - 2007 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.IO; using System.Runtime.InteropServices; using System.Text; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Drawing.Text; using System.Globalization; using System.Security; using System.Runtime.InteropServices.ComTypes; namespace System.Drawing { /// /// GDI+ API Functions /// internal static class GDIPlus { public const int FACESIZE = 32; public const int LANG_NEUTRAL = 0; public static IntPtr Display = IntPtr.Zero; public static bool UseX11Drawable = false; public static bool UseCarbonDrawable = false; public static bool UseCocoaDrawable = false; private const string GdiPlus = "gdiplus"; #region gdiplus.dll functions // startup / shutdown [DllImport(GdiPlus)] static internal extern Status GdiplusStartup(ref ulong token, ref GdiplusStartupInput input, ref GdiplusStartupOutput output); [DllImport(GdiPlus)] 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 (); #if false GdiPlusToken = 0; // This causes crashes in 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); } #endif } static GDIPlus () { int platform = (int) Environment.OSVersion.Platform; if ((platform == 4) || (platform == 6) || (platform == 128)) { if (Environment.GetEnvironmentVariable ("not_supported_MONO_MWF_USE_NEW_X11_BACKEND") != null || Environment.GetEnvironmentVariable ("MONO_MWF_MAC_FORCE_X11") != null) { UseX11Drawable = true; } else { IntPtr buf = Marshal.AllocHGlobal (8192); // This is kind of a hack but gets us sysname from uname (struct utsname *name) on // linux and darwin if (uname (buf) != 0) { // WTH: We couldn't detect the OS; lets default to X11 UseX11Drawable = true; } else { string os = Marshal.PtrToStringAnsi (buf); if (os == "Darwin") UseCarbonDrawable = true; else UseX11Drawable = true; } Marshal.FreeHGlobal (buf); } } 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{0}{0}" + "Please check http://www.mono-project.com/Problem:GDIPlusInit for details", Environment.NewLine); } // under MS 1.x this event is raised only for the default application domain AppDomain.CurrentDomain.ProcessExit += new EventHandler (ProcessExit); } static public bool RunningOnWindows () { return !UseX11Drawable && !UseCarbonDrawable && !UseCocoaDrawable; } static public bool RunningOnUnix () { return UseX11Drawable || UseCarbonDrawable || UseCocoaDrawable; } // 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)] internal static extern Status GdipCreateFromContext_macosx (IntPtr cgref, int width, int height, out IntPtr graphics); /* Linux only function calls*/ [DllImport(GdiPlus)] internal static extern Status GdipSetVisibleClip_linux (IntPtr graphics, ref Rectangle rect); [DllImport(GdiPlus)] internal static extern Status GdipCreateFromXDrawable_linux (IntPtr drawable, IntPtr display, out IntPtr graphics); // Stream functions for non-Win32 (libgdiplus specific) [DllImport(GdiPlus)] static internal extern Status GdipLoadImageFromDelegate_linux (StreamGetHeaderDelegate getHeader, StreamGetBytesDelegate getBytes, StreamPutBytesDelegate putBytes, StreamSeekDelegate doSeek, StreamCloseDelegate close, StreamSizeDelegate size, out IntPtr image); [DllImport(GdiPlus)] static internal extern Status GdipSaveImageToDelegate_linux (IntPtr image, StreamGetBytesDelegate getBytes, StreamPutBytesDelegate putBytes, StreamSeekDelegate doSeek, StreamCloseDelegate close, StreamSizeDelegate size, ref Guid encoderClsID, IntPtr encoderParameters); [DllImport(GdiPlus)] static internal extern Status GdipCreateMetafileFromDelegate_linux (StreamGetHeaderDelegate getHeader, StreamGetBytesDelegate getBytes, StreamPutBytesDelegate putBytes, StreamSeekDelegate doSeek, StreamCloseDelegate close, StreamSizeDelegate size, out IntPtr metafile); [DllImport(GdiPlus)] static internal extern Status GdipGetMetafileHeaderFromDelegate_linux (StreamGetHeaderDelegate getHeader, StreamGetBytesDelegate getBytes, StreamPutBytesDelegate putBytes, StreamSeekDelegate doSeek, StreamCloseDelegate close, StreamSizeDelegate size, IntPtr header); [DllImport(GdiPlus)] static internal extern Status GdipRecordMetafileFromDelegate_linux (StreamGetHeaderDelegate getHeader, StreamGetBytesDelegate getBytes, StreamPutBytesDelegate putBytes, StreamSeekDelegate doSeek, StreamCloseDelegate close, StreamSizeDelegate size, IntPtr hdc, EmfType type, ref RectangleF frameRect, MetafileFrameUnit frameUnit, [MarshalAs (UnmanagedType.LPWStr)] string description, out IntPtr metafile); [DllImport(GdiPlus)] static internal extern Status GdipRecordMetafileFromDelegateI_linux (StreamGetHeaderDelegate getHeader, StreamGetBytesDelegate getBytes, StreamPutBytesDelegate putBytes, StreamSeekDelegate doSeek, StreamCloseDelegate close, StreamSizeDelegate size, IntPtr hdc, EmfType type, ref Rectangle frameRect, MetafileFrameUnit frameUnit, [MarshalAs (UnmanagedType.LPWStr)] string description, out IntPtr metafile); [DllImport ("libc")] static extern int uname (IntPtr buf); #endregion } }