2006-08-11 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System.Drawing / System.Drawing / Font.cs
index 4f45c85b6efa6883955dacfe039ef7c72c26fdbf..841fc226c04340469dbe40fc303ecf03e7684b91 100644 (file)
@@ -33,6 +33,7 @@
 
 using System.Runtime.Serialization;
 using System.Runtime.InteropServices;
+using System.Security.Permissions;
 using System.ComponentModel;
 
 namespace System.Drawing
@@ -47,10 +48,17 @@ namespace System.Drawing
                private string  systemFontName;
                private float _size;
 
-               private void CreateFont(string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte charSet, bool isVertical) {
-                        Status         status;                  
-                        FontFamily     family;                      
+               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)
+               {
+#if ONLY_1_1
+                       if (familyName == null)
+                               throw new ArgumentNullException ("familyName");
+#endif
+                        FontFamily family;
                        // NOTE: If family name is null, empty or invalid,
                        // MS creates Microsoft Sans Serif font.
                        try {
@@ -61,7 +69,7 @@ namespace System.Drawing
                        }
 
                        setProperties (family, emSize, style, unit, charSet, isVertical);           
-                       status = GDIPlus.GdipCreateFont (family.NativeObject, emSize,  style, unit, out fontObject);
+                       Status status = GDIPlus.GdipCreateFont (family.NativeObject, emSize,  style, unit, out fontObject);
                        GDIPlus.CheckStatus (status);
                }
 
@@ -77,7 +85,7 @@ namespace System.Drawing
                        style = (FontStyle)info.GetValue("Style", typeof(FontStyle));
                        unit = (GraphicsUnit)info.GetValue("Unit", typeof(GraphicsUnit));
  
-                       CreateFont(name, size, style, unit, (byte)0, false);
+                       CreateFont(name, size, style, unit, DefaultCharSet, false);
                }
 
                void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
@@ -96,9 +104,11 @@ namespace System.Drawing
                public void Dispose ()
                {
                        if (fontObject != IntPtr.Zero) {
-                               GDIPlus.CheckStatus (GDIPlus.GdipDeleteFont (fontObject));
+                               Status status = GDIPlus.GdipDeleteFont (fontObject);
                                fontObject = IntPtr.Zero;
                                GC.SuppressFinalize (this);
+                               // check the status code (throw) at the last step
+                               GDIPlus.CheckStatus (status);
                        }
                }
 
@@ -246,19 +256,17 @@ namespace System.Drawing
 
                public IntPtr ToHfont ()
                {
+                       if (fontObject == IntPtr.Zero)
+                               throw new ArgumentException (Locale.GetText ("Object has been disposed."));
+
                        IntPtr Hfont;
                        OperatingSystem osInfo = Environment.OSVersion;
-
-                       // Sanity. Should we throw an exception?
-                       if (fontObject == IntPtr.Zero) {
-                               return IntPtr.Zero;
-                       }
-
                        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;
@@ -289,27 +297,27 @@ namespace System.Drawing
                }
 
                public Font (FontFamily family, float emSize,  GraphicsUnit unit)
-                       : this (family, emSize, FontStyle.Regular, unit, (byte)0, false)
+                       : this (family, emSize, FontStyle.Regular, unit, DefaultCharSet, false)
                {
                }
 
                public Font (string familyName, float emSize,  GraphicsUnit unit)
-                       : this (new FontFamily (familyName), emSize, FontStyle.Regular, unit, (byte)0, false)
+                       : this (new FontFamily (familyName), emSize, FontStyle.Regular, unit, DefaultCharSet, false)
                {
                }
 
                public Font (FontFamily family, float emSize)
-                       : this (family, emSize, FontStyle.Regular, GraphicsUnit.Point, (byte)0, false)
+                       : this (family, emSize, FontStyle.Regular, GraphicsUnit.Point, DefaultCharSet, false)
                {
                }
 
                public Font (FontFamily family, float emSize, FontStyle style)
-                       : this (family, emSize, style, GraphicsUnit.Point, (byte)0, false)
+                       : this (family, emSize, style, GraphicsUnit.Point, DefaultCharSet, false)
                {
                }
 
                public Font (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit)
-                       : this (family, emSize, style, unit, (byte)0, false)
+                       : this (family, emSize, style, unit, DefaultCharSet, false)
                {
                }
 
@@ -321,7 +329,9 @@ namespace System.Drawing
                public Font (FontFamily family, float emSize, FontStyle style,
                                GraphicsUnit unit, byte charSet, bool isVertical)
                {
-                       // MS does not accept null family
+                       if (family == null)
+                               throw new ArgumentNullException ("family");
+
                        Status status;
                        setProperties (family, emSize, style, unit, charSet, isVertical);               
                        status = GDIPlus.GdipCreateFont (family.NativeObject, emSize,  style,   unit,  out fontObject);
@@ -329,17 +339,17 @@ namespace System.Drawing
                }
 
                public Font (string familyName, float emSize)
-                       : this (familyName, emSize, FontStyle.Regular, GraphicsUnit.Point, (byte)0, false)
+                       : this (familyName, emSize, FontStyle.Regular, GraphicsUnit.Point, DefaultCharSet, false)
                {
                }
 
                public Font (string familyName, float emSize, FontStyle style)
-                       : this (familyName, emSize, style, GraphicsUnit.Point, (byte)0, false)
+                       : this (familyName, emSize, style, GraphicsUnit.Point, DefaultCharSet, false)
                {
                }
 
                public Font (string familyName, float emSize, FontStyle style, GraphicsUnit unit)
-                       : this (familyName, emSize, style, unit, (byte)0, false)
+                       : this (familyName, emSize, style, unit, DefaultCharSet, false)
                {
                }
 
@@ -361,10 +371,7 @@ namespace System.Drawing
 
                internal IntPtr NativeObject {            
                        get {
-                                       return fontObject;
-                       }
-                       set {
-                                       fontObject = value;
+                               return fontObject;
                        }
                }
 
@@ -512,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 && 
@@ -542,7 +548,8 @@ namespace System.Drawing
                {
                        IntPtr newObject;
                        LOGFONT o = (LOGFONT)lf;
-                       GDIPlus.GdipCreateFontFromLogfont (hdc, ref o, out newObject);
+                       Status status = GDIPlus.GdipCreateFontFromLogfont (hdc, ref o, out newObject);
+                       GDIPlus.CheckStatus (status);
                        return new Font (newObject, "Microsoft Sans Serif", FontStyle.Regular, 10);
                }
 
@@ -572,6 +579,7 @@ namespace System.Drawing
 
                }
 
+               [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
                public void ToLogFont (object logFont)
                {
                        Graphics g;
@@ -625,29 +633,80 @@ 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);
                        }
                }
 
                public float GetHeight (Graphics graphics)
                {
                        float size;
-                       
-                       GDIPlus.GdipGetFontHeight (fontObject, graphics.NativeObject, out size);
+                       Status status = GDIPlus.GdipGetFontHeight (fontObject, graphics.NativeObject, out size);
+                       GDIPlus.CheckStatus (status);
                        return size;
                }
 
                public float GetHeight (float dpi)
                {
                        float size;
-                       GDIPlus.GdipGetFontHeightGivenDPI (fontObject, dpi, out size);
+                       Status status = GDIPlus.GdipGetFontHeightGivenDPI (fontObject, dpi, out size);
+                       GDIPlus.CheckStatus (status);
                        return size;
                }