2006-08-11 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System.Drawing / System.Drawing / Font.cs
index d3d120e2b90c38056e1748127028c210e831d303..841fc226c04340469dbe40fc303ecf03e7684b91 100644 (file)
@@ -49,6 +49,8 @@ namespace System.Drawing
                private float _size;
 
                private const byte DefaultCharSet = 1;
+               private static int CharSetOffset = -1;
+               private static int FaceNameOffset = -1;
 
                private void CreateFont (string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte charSet, bool isVertical)
                {
@@ -262,8 +264,9 @@ namespace System.Drawing
                        if ((int) osInfo.Platform == 128 || (int) osInfo.Platform == 4) {
                                return fontObject;
                        } else {
-                               LOGFONT lf = new LOGFONT ();
-                               ToLogFont(lf);
+                               object olf = new LOGFONT ();
+                               ToLogFont(olf);
+                               LOGFONT lf = (LOGFONT)olf;
                                Hfont = GDIPlus.CreateFontIndirect (ref lf);
                        }
                        return Hfont;
@@ -516,11 +519,10 @@ namespace System.Drawing
 
                public override bool Equals (object obj)
                {
-                       if (! (obj is Font))
+                       Font fnt = (obj as Font);
+                       if (fnt == null)
                                return false;
-                               
-                       Font fnt = (Font) obj;                  
-                       
+
                        if (fnt.FontFamily.Equals (FontFamily) && fnt.Size == Size &&
                            fnt.Style == Style && fnt.Unit == Unit &&
                            fnt.GdiCharSet == GdiCharSet && 
@@ -634,12 +636,61 @@ namespace System.Drawing
                [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
                public void ToLogFont (object logFont, Graphics graphics)
                {
-                       if (graphics == null) {
+                       if (graphics == null)
                                throw new ArgumentNullException ("graphics");
+
+                       if (logFont == null) {
+#if NET_2_0
+                               throw new AccessViolationException ("logFont");
+#else
+                               throw new NullReferenceException ("logFont");
+#endif
                        }
 
-                       if (Marshal.SizeOf(logFont) >= Marshal.SizeOf(typeof(LOGFONT))) {
-                               GDIPlus.CheckStatus (GDIPlus.GdipGetLogFont(NativeObject, graphics.NativeObject, logFont));
+                       Type st = logFont.GetType ();
+                       if (!st.IsLayoutSequential)
+                               throw new ArgumentException ("logFont", Locale.GetText ("Layout must be sequential."));
+
+                       // note: there is no exception if 'logFont' isn't big enough
+                       Type lf = typeof (LOGFONT);
+                       int size = Marshal.SizeOf (lf);
+                       if (Marshal.SizeOf (logFont) >= size) {
+                               Status status;
+                               IntPtr copy = Marshal.AllocHGlobal (size);
+                               try {
+                                       Marshal.StructureToPtr (logFont, copy, false);
+
+                                       status = GDIPlus.GdipGetLogFont (NativeObject, graphics.NativeObject, logFont);
+                                       if (status != Status.Ok) {
+                                               // reset to original values
+                                               Marshal.PtrToStructure (copy, logFont);
+                                       }
+                               }
+                               finally {
+                                       Marshal.FreeHGlobal (copy);
+                               }
+
+                               if (CharSetOffset == -1) {
+                                       CharSetOffset = (int) Marshal.OffsetOf (lf, "lfCharSet");
+                                       FaceNameOffset = (int) Marshal.OffsetOf (lf, "lfFaceName");
+                               }
+
+                               // note: Marshal.WriteByte(object,*) methods are unimplemented on Mono
+                               GCHandle gch = GCHandle.Alloc (logFont, GCHandleType.Pinned);
+                               try {
+                                       IntPtr ptr = gch.AddrOfPinnedObject ();
+                                       // if GDI+ lfCharSet is 0, then we return (S.D.) 1, otherwise the value is unchanged
+                                       if (Marshal.ReadByte (ptr, CharSetOffset) == 0) {
+                                               // set lfCharSet to 1 
+                                               Marshal.WriteByte (ptr, CharSetOffset, 1);
+                                       }
+                               }
+                               finally {
+                                       gch.Free ();
+                               }
+
+                               // now we can throw, if required
+                               GDIPlus.CheckStatus (status);
                        }
                }