2006-08-11 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System.Drawing / System.Drawing / Font.cs
index c6fd7b60b19be1fcc657ecf322a555651bc36f2e..841fc226c04340469dbe40fc303ecf03e7684b91 100644 (file)
@@ -1,12 +1,15 @@
 //
 // System.Drawing.Fonts.cs
 //
-// (C) 2004 Ximian, Inc.  http://www.ximian.com
+// Authors:
+//     Alexandre Pigolkine (pigolkine@gmx.de)
+//     Miguel de Icaza (miguel@ximian.com)
+//     Todd Berman (tberman@sevenl.com)
+//     Jordi Mas i Hernandez (jordi@ximian.com)
+//     Ravindra (rkumar@novell.com)
 //
-// Authors: 
-
-//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004 Ximian, Inc. (http://www.ximian.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
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-
 using System.Runtime.Serialization;
 using System.Runtime.InteropServices;
+using System.Security.Permissions;
 using System.ComponentModel;
 
-namespace System.Drawing {
-
+namespace System.Drawing
+{
        [Serializable]
        [ComVisible (true)]
        [Editor ("System.Drawing.Design.FontEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
@@ -42,35 +45,77 @@ namespace System.Drawing {
        public sealed class Font : MarshalByRefObject, ISerializable, ICloneable, IDisposable
        {
                private IntPtr  fontObject = IntPtr.Zero;
-               
+               private string  systemFontName;
+               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)
+               {
+#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 {
+                               family = new FontFamily (familyName);
+                       }
+                       catch (Exception){
+                               family = FontFamily.GenericSansSerif;
+                       }
+
+                       setProperties (family, emSize, style, unit, charSet, isVertical);           
+                       Status status = GDIPlus.GdipCreateFont (family.NativeObject, emSize,  style, unit, out fontObject);
+                       GDIPlus.CheckStatus (status);
+               }
+
                        private Font (SerializationInfo info, StreamingContext context)
                {
+                       string          name;
+                       float           size;
+                       FontStyle       style;
+                       GraphicsUnit    unit;
+
+                       name = (string)info.GetValue("Name", typeof(string));
+                       size = (float)info.GetValue("Size", typeof(float));
+                       style = (FontStyle)info.GetValue("Style", typeof(FontStyle));
+                       unit = (GraphicsUnit)info.GetValue("Unit", typeof(GraphicsUnit));
+                       CreateFont(name, size, style, unit, DefaultCharSet, false);
                }
 
                void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
                {
+                       info.AddValue("Name", Name);
+                       info.AddValue("Size", Size);
+                       info.AddValue("Style", Style);
+                       info.AddValue("Unit", Unit);
                }
-               
+
                ~Font()
-               {       
+               {
                        Dispose ();
                }
 
                public void Dispose ()
                {
-                       if (fontObject!=IntPtr.Zero) {
-                               lock (this)
-                               {
-                                       GDIPlus.CheckStatus (GDIPlus.GdipDeleteFont (fontObject));
-                               }
+                       if (fontObject != IntPtr.Zero) {
+                               Status status = GDIPlus.GdipDeleteFont (fontObject);
+                               fontObject = IntPtr.Zero;
                                GC.SuppressFinalize (this);
+                               // check the status code (throw) at the last step
+                               GDIPlus.CheckStatus (status);
                        }
-               }               
-               
+               }
+
                internal void unitConversion (GraphicsUnit fromUnit, GraphicsUnit toUnit, float nSrc, out float nTrg)
                {
                        float inchs = 0;
-                       nTrg = 0;               
+                       nTrg = 0;
                        
                        switch (fromUnit) {
                        case GraphicsUnit.Display:
@@ -85,17 +130,17 @@ namespace System.Drawing {
                        case GraphicsUnit.Millimeter:
                                inchs = nSrc / 25.4f;
                                break;
-                       case GraphicsUnit.Pixel:                                
+                       case GraphicsUnit.Pixel:
                        case GraphicsUnit.World:
                                inchs = nSrc / Graphics.systemDpiX;
                                break;
                        case GraphicsUnit.Point:
                                inchs = nSrc / 72f;
-                               break;                          
-                       default:                
-                               throw new ArgumentException("Invalid GraphicsUnit");                            
-                       }                       
-                       
+                               break;
+                       default:
+                               throw new ArgumentException("Invalid GraphicsUnit");
+                       }
+
                        switch (toUnit) {
                        case GraphicsUnit.Display:
                                nTrg = inchs * 75;
@@ -109,29 +154,31 @@ namespace System.Drawing {
                        case GraphicsUnit.Millimeter:
                                nTrg = inchs * 25.4f;
                                break;
-                       case GraphicsUnit.Pixel:                                
+                       case GraphicsUnit.Pixel:
                        case GraphicsUnit.World:
                                nTrg = inchs * Graphics.systemDpiX;
                                break;
                        case GraphicsUnit.Point:
                                nTrg = inchs * 72;
                                break;
-                       default:        
-                               throw new ArgumentException("Invalid GraphicsUnit");                            
-                       }                               
+                       default:
+                               throw new ArgumentException("Invalid GraphicsUnit");
+                       }
                }
-               
+
                internal void setProperties (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte charSet, bool isVertical)
-               {                       
-                       _name=family.Name;
-                       _fontFamily = family;
-                       _size = emSize;                 
+               {
+                       _name = family.Name;
+                       _fontFamily = family;                   
+                       _size = emSize;
+
+                       // MS throws ArgumentException, if unit is set to GraphicsUnit.Display
                        _unit = unit;
                        _style = style;
                        _gdiCharSet = charSet;
                        _gdiVerticalFont = isVertical;
                        
-                       unitConversion(unit, GraphicsUnit.Point, emSize, out  _sizeInPoints);
+                       unitConversion (unit, GraphicsUnit.Point, emSize, out  _sizeInPoints);
                                                
                        _bold = _italic = _strikeout = _underline = false;
 
@@ -150,207 +197,192 @@ namespace System.Drawing {
 
                public static Font FromHfont (IntPtr Hfont)
                {
-                       System.OperatingSystem  osInfo = System.Environment.OSVersion;
+                       OperatingSystem osInfo = Environment.OSVersion;
                        IntPtr                  newObject;
-                       IntPtr                  hdc;
-                       IntPtr                  oldFont;
-                       FontStyle               newStyle=FontStyle.Regular;
+                       IntPtr                  hdc;                    
+                       FontStyle               newStyle = FontStyle.Regular;
                        float                   newSize;
-                       LOGFONTA                lf = new LOGFONTA();
+                       LOGFONT                 lf = new LOGFONT ();
 
                        // Sanity. Should we throw an exception?
-                       if (Hfont==IntPtr.Zero) {
-                               Font result = new Font("Arial", (float)10.0, FontStyle.Regular);
+                       if (Hfont == IntPtr.Zero) {
+                               Font result = new Font ("Arial", (float)10.0, FontStyle.Regular);
                                return(result);
                        }
 
-                       if ((int)osInfo.Platform==128) {
+                       if ((int) osInfo.Platform == 128 || (int) osInfo.Platform == 4) {
                                // If we're on Unix we use our private gdiplus API to avoid Wine 
                                // dependencies in S.D
-
-                               lock (typeof (Font))
-                               {
-                                       Status s = GDIPlus.GdipCreateFontFromHfont(Hfont, out newObject, ref lf);
-                                       GDIPlus.CheckStatus (s);
-                               }
+                               Status s = GDIPlus.GdipCreateFontFromHfont (Hfont, out newObject, ref lf);
+                               GDIPlus.CheckStatus (s);
                        } else {
 
-                               // This needs testing, but I don't have a working win32 mono
-                               // environment. 
+                               // This needs testing
+                               // GetDC, SelectObject, ReleaseDC GetTextMetric and
+                               // GetFontFace are not really GDIPlus, see gdipFunctions.cs
 
-                               // GetDC, SelectObject, ReleaseDC GetTextMetric and GetFontFace are not 
-                               // really GDIPlus, see gdipFunctions.cs
+                               newStyle = FontStyle.Regular;
 
-                               newStyle=FontStyle.Regular;
-                               
-                               
-                               lock (typeof (Font))
-                               {
-                                       hdc=GDIPlus.GetDC (IntPtr.Zero);
-                                       oldFont=GDIPlus.SelectObject (hdc, Hfont);
-                                       GDIPlus.CheckStatus (GDIPlus.GdipCreateFontFromDC (hdc, out newObject));
-                                       GDIPlus.CheckStatus (GDIPlus.GdipGetLogFontA (newObject, IntPtr.Zero, ref lf));
-                                       GDIPlus.SelectObject (hdc, oldFont);
-                                       GDIPlus.ReleaseDC (hdc);
-                               }
+                               hdc = GDIPlus.GetDC (IntPtr.Zero);
+                               Font f = FromLogFont (lf, hdc);
+                               GDIPlus.ReleaseDC (hdc);
+                               return f;                               
                        }
-
-                       if (lf.lfItalic!=0) {
+                       
+                       if (lf.lfItalic != 0) {
                                newStyle |= FontStyle.Italic;
                        }
-                       if (lf.lfUnderline!=0) {
+
+                       if (lf.lfUnderline != 0) {
                                newStyle |= FontStyle.Underline;
                        }
-                       if (lf.lfStrikeOut!=0) {
+
+                       if (lf.lfStrikeOut != 0) {
                                newStyle |= FontStyle.Strikeout;
                        }
-                       if (lf.lfWeight>400) {
+
+                       if (lf.lfWeight > 400) {
                                newStyle |= FontStyle.Bold;
                        }
-                       if (lf.lfHeight<0) {
-                               newSize=lf.lfHeight*-1;
+
+                       if (lf.lfHeight < 0) {
+                               newSize = lf.lfHeight * -1;
                        } else {
-                               newSize=lf.lfHeight;
+                               newSize = lf.lfHeight;
                        }
 
-                       return (new Font(newObject, lf.lfFaceName, newStyle, newSize));
+                       return (new Font (newObject, lf.lfFaceName, newStyle, newSize));
                }
 
                public IntPtr ToHfont ()
                {
-                       IntPtr                  Hfont;
-                       System.OperatingSystem  osInfo = System.Environment.OSVersion;
+                       if (fontObject == IntPtr.Zero)
+                               throw new ArgumentException (Locale.GetText ("Object has been disposed."));
 
-                       // Sanity. Should we throw an exception?
-                       if (fontObject==IntPtr.Zero){                           
-                               return(IntPtr.Zero);
-                       }
-
-                       if ((int)osInfo.Platform==128) {
-                               // If we're on Unix we use our private gdiplus API
-                               GDIPlus.CheckStatus (GDIPlus.GdipGetHfont (fontObject, out Hfont));
+                       IntPtr Hfont;
+                       OperatingSystem osInfo = Environment.OSVersion;
+                       if ((int) osInfo.Platform == 128 || (int) osInfo.Platform == 4) {
+                               return fontObject;
                        } else {
-                               // This needs testing, but I don't have a working win32 mono
-                               // environment. 
-                               LOGFONTA lf = new LOGFONTA ();
-
-                               GDIPlus.CheckStatus (GDIPlus.GdipGetLogFontA (fontObject, IntPtr.Zero, ref lf));
-                               Hfont = GDIPlus.CreateFontIndirectA (ref lf);
+                               object olf = new LOGFONT ();
+                               ToLogFont(olf);
+                               LOGFONT lf = (LOGFONT)olf;
+                               Hfont = GDIPlus.CreateFontIndirect (ref lf);
                        }
-                       return(Hfont);
+                       return Hfont;
                }
 
-               internal Font(IntPtr newFontObject, string familyName, FontStyle style, float size)
+               internal Font (IntPtr newFontObject, string familyName, FontStyle style, float size)
                {
-                       FontFamily      fontFamily = new FontFamily(familyName);
-
-                       setProperties(fontFamily, size, style, GraphicsUnit.Pixel, 0, false);
-                       fontObject=newFontObject;
+                       FontFamily fontFamily;                  
+                       
+                       try {
+                               fontFamily = new FontFamily (familyName);
+                       }
+                       catch (Exception){
+                               fontFamily = FontFamily.GenericSansSerif;
+                       }
+                       
+                       setProperties (fontFamily, size, style, GraphicsUnit.Pixel, 0, false);
+                       fontObject = newFontObject;
                }
 
                public Font (Font original, FontStyle style)
                {
-                       lock (this)
-                       {   
-                               Status status;
-                               setProperties (original.FontFamily, original.Size, style, original.Unit, 
-                                       original.GdiCharSet, original.GdiVerticalFont);
+                       Status status;
+                       setProperties (original.FontFamily, original.Size, style, original.Unit, original.GdiCharSet, original.GdiVerticalFont);
                                
-                               status = GDIPlus.GdipCreateFont (_fontFamily.NativeObject,      Size,  Style,   Unit,  out fontObject);
-                               GDIPlus.CheckStatus (status);
-                       }
+                       status = GDIPlus.GdipCreateFont (_fontFamily.NativeObject,      Size,  Style,   Unit,  out fontObject);
+                       GDIPlus.CheckStatus (status);                   
                }
-               
+
                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)
                {
                }
 
                public Font (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte charSet)
-                       : this(family, emSize, style, unit, charSet, false)
+                       : this (family, emSize, style, unit, charSet, false)
                {
                }
-               
-               public Font (FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte charSet, bool isVertical)
+
+               public Font (FontFamily family, float emSize, FontStyle style,
+                               GraphicsUnit unit, byte charSet, bool isVertical)
                {
-                       lock (this)
-                       {
-                               Status status;
-                               setProperties (family, emSize, style, unit, charSet, isVertical);               
-                               status = GDIPlus.GdipCreateFont (family.NativeObject, emSize,  style,   unit,  out fontObject);
-                               GDIPlus.CheckStatus (status);
-                       }
+                       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);
+                       GDIPlus.CheckStatus (status);
                }
 
                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)
                {
                }
-               
+
                public Font (string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte charSet)
-                       : this(familyName, emSize, style, unit, charSet, false)
+                       : this (familyName, emSize, style, unit, charSet, false)
                {
                }
-               
-               public Font (string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte charSet, bool isVertical)
+
+               public Font (string familyName, float emSize, FontStyle style,
+                               GraphicsUnit unit, byte charSet, bool isVertical)
                {
-                       lock (this)
-                       {
-                               Status status;
-                               FontFamily family = new FontFamily (familyName);
-                               setProperties (family, emSize, style, unit, charSet, isVertical);
-                               
-                               status = GDIPlus.GdipCreateFont (family.NativeObject, emSize,  style,   unit,  out fontObject);
-                               GDIPlus.CheckStatus (status);
-                       }
-               }               
-               
+                       CreateFont(familyName, emSize, style, unit, charSet, isVertical);
+               }
+
                public object Clone ()
                {
-                       return new Font(this, Style);
+                       return new Font (this, Style);
                }
-               
+
                internal IntPtr NativeObject {            
                        get {
-                                       return fontObject;
+                               return fontObject;
                        }
+               }
+
+#if NET_2_0
+               internal string SysFontName {
                        set {
-                                       fontObject = value;
+                               systemFontName = value;
                        }
                }
-               
+#endif
+
                private bool _bold;
 
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
@@ -359,7 +391,7 @@ namespace System.Drawing {
                                return _bold;
                        }
                }
-               
+
                private FontFamily _fontFamily;
 
                [Browsable (false)]
@@ -368,7 +400,7 @@ namespace System.Drawing {
                                return _fontFamily;
                        }
                }
-               
+
                private byte _gdiCharSet;
 
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
@@ -377,7 +409,7 @@ namespace System.Drawing {
                                return _gdiCharSet;
                        }
                }
-               
+
                private bool _gdiVerticalFont;
 
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
@@ -386,15 +418,25 @@ namespace System.Drawing {
                                return _gdiVerticalFont;
                        }
                }
-               
-               private int _height;
 
                [Browsable (false)]
                public int Height {
                        get {
-                               return _height;
+                               return (int) Math.Ceiling (GetHeight ());
+                       }
+               }
+
+#if NET_2_0
+               [Browsable(false)]
+               public bool IsSystemFont {
+                       get {
+                               if (systemFontName == null)
+                                       return false;
+
+                               return StringComparer.InvariantCulture.Compare (systemFontName, string.Empty) != 0;
                        }
                }
+#endif
 
                private bool _italic;
 
@@ -415,11 +457,10 @@ namespace System.Drawing {
                                return _name;
                        }
                }
-
-               private float _size;
+               
                public float Size {
                        get {
-                               return _size;
+                               return _size;                   
                        }
                }
 
@@ -450,6 +491,14 @@ namespace System.Drawing {
                        }
                }
 
+#if NET_2_0
+               [Browsable(false)]
+               public string SystemFontName {
+                       get {
+                               return systemFontName;
+                       }
+               }
+#endif
                private bool _underline;
 
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
@@ -467,84 +516,203 @@ namespace System.Drawing {
                                return _unit;
                        }
                }
-               
+
                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 == FontFamily && fnt.Size == Size &&
-                               fnt.Style == Style && fnt.Unit == Unit &&
-                               fnt.GdiCharSet == GdiCharSet && fnt.GdiVerticalFont == GdiVerticalFont)
+
+                       if (fnt.FontFamily.Equals (FontFamily) && fnt.Size == Size &&
+                           fnt.Style == Style && fnt.Unit == Unit &&
+                           fnt.GdiCharSet == GdiCharSet && 
+                           fnt.GdiVerticalFont == GdiVerticalFont)
                                return true;
                        else
                                return false;
-                       
-               }               
+               }
 
-               public override int GetHashCode()
+               public override int GetHashCode ()
                {
-                       return _name.GetHashCode();
+                       return _name.GetHashCode ();
                }
-               
-               [MonoTODO]      
-               public static Font FromHdc(IntPtr hdc)
+
+               [MonoTODO]
+               public static Font FromHdc (IntPtr hdc)
                {
                        throw new NotImplementedException ();
-               }               
-               
-               
-               [MonoTODO]      
-               public static Font FromLogFont( object lf,  IntPtr hdc)
+               }
+
+               [MonoTODO("This is temporary implementation")]
+               public static Font FromLogFont (object lf,  IntPtr hdc)
                {
-                       throw new NotImplementedException ();
+                       IntPtr newObject;
+                       LOGFONT o = (LOGFONT)lf;
+                       Status status = GDIPlus.GdipCreateFontFromLogfont (hdc, ref o, out newObject);
+                       GDIPlus.CheckStatus (status);
+                       return new Font (newObject, "Microsoft Sans Serif", FontStyle.Regular, 10);
                }
-               
-               public float GetHeight()
+
+               public float GetHeight ()
                {
-                       return (float) _height;
+                       return GetHeight (Graphics.systemDpiY);
                }
-               
-               [MonoTODO]      
-               public static Font FromLogFont(object lf)
+
+               public static Font FromLogFont (object lf)
                {
-                       throw new NotImplementedException ();   
+                       if ((int) Environment.OSVersion.Platform == 128 || (int) Environment.OSVersion.Platform == 4) {
+                               return FromLogFont(lf, IntPtr.Zero);
+                       } else {
+                               IntPtr  hDC;
+
+                               hDC = IntPtr.Zero;
+
+                               try {
+                                       hDC = GDIPlus.GetDC(IntPtr.Zero);
+                                       return FromLogFont (lf, hDC);
+                               }
+
+                               finally {
+                                       GDIPlus.ReleaseDC(hDC);
+                               }
+                       }
+
                }
-               
-               [MonoTODO]      
-               public void ToLogFont(object logFont)
+
+               [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
+               public void ToLogFont (object logFont)
                {
-                       throw new NotImplementedException ();
-               }       
+                       Graphics g;
 
-               [MonoTODO]
-               public void ToLogFont(object logFont, Graphics graphics)
+                       g = null;
+
+                       if ((int) Environment.OSVersion.Platform == 128 || (int) Environment.OSVersion.Platform == 4) {
+                               // Unix
+                               Bitmap  img;
+
+                               img = null;
+
+                               try {
+                                       // We don't have a window we could associate the DC with
+                                       // so we use an image instead
+                                       img = new Bitmap(1, 1, Imaging.PixelFormat.Format32bppArgb);
+                                       g = Graphics.FromImage(img);
+                                       ToLogFont(logFont, g);
+                               }
+
+                               finally {
+                                       if (g != null) {
+                                               g.Dispose();
+                                       }
+
+                                       if (img != null) {
+                                               img.Dispose();
+                                       }
+                               }
+                       } else {
+                               // Windows
+                               IntPtr  hDC;
+
+                               hDC = IntPtr.Zero;
+
+                               try {
+
+                                       hDC = GDIPlus.GetDC(IntPtr.Zero);
+                                       g = Graphics.FromHdc(hDC);
+
+                                       ToLogFont (logFont, g);
+                               }
+
+                               finally {
+                                       if (g != null) {
+                                               g.Dispose();
+                                       }
+
+                                       GDIPlus.ReleaseDC(hDC);
+                               }
+                       }
+               }
+
+               [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
+               public void ToLogFont (object logFont, Graphics graphics)
                {
-                       throw new NotImplementedException ();
+                       if (graphics == null)
+                               throw new ArgumentNullException ("graphics");
+
+                       if (logFont == null) {
+#if NET_2_0
+                               throw new AccessViolationException ("logFont");
+#else
+                               throw new NullReferenceException ("logFont");
+#endif
+                       }
+
+                       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);
+                       }
                }
-               
-               [MonoTODO]      
-               public float GetHeight(Graphics graphics)
+
+               public float GetHeight (Graphics graphics)
                {
-                       if (Unit == GraphicsUnit.Pixel || Unit == GraphicsUnit.World)
-                               return GetHeight();
-                               
-                       throw new NotImplementedException ();
+                       float size;
+                       Status status = GDIPlus.GdipGetFontHeight (fontObject, graphics.NativeObject, out size);
+                       GDIPlus.CheckStatus (status);
+                       return size;
                }
 
-               [MonoTODO]
-               public float GetHeight(float dpi)
-               {                       
-                       return GetHeight();
+               public float GetHeight (float dpi)
+               {
+                       float size;
+                       Status status = GDIPlus.GdipGetFontHeightGivenDPI (fontObject, dpi, out size);
+                       GDIPlus.CheckStatus (status);
+                       return size;
                }
-               
-               
-               public override System.String ToString()
+
+               public override String ToString ()
                {
-                       return ("[Font: Name="+ _name +", Size="+ _size+", Style="+ _style  +", Units="+ _unit  +", GdiCharSet="+ _gdiCharSet
-                               +", GdiVerticalFont="+ _gdiVerticalFont + "]");                 
+                       return String.Format ("[Font: Name={0}, Size={1}, Units={2}, GdiCharSet={3}, GdiVerticalFont={4}]", _name, Size, (int)_unit, _gdiCharSet, _gdiVerticalFont);
                }
        }
 }