File: commonui\System\Drawing\Advanced\Font.cs
Project: ndp\fx\src\System.Drawing.csproj (System.Drawing)
//------------------------------------------------------------------------------
// <copyright file="Font.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Drawing {
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System;
    using System.Drawing.Design;
    using System.Runtime.InteropServices;
    using System.Runtime.Serialization;
    using System.ComponentModel;
    using Microsoft.Win32;
    using System.Drawing;
    using System.Drawing.Internal;
    using System.Globalization;
    using System.Security;
    using System.Security.Permissions;
    using System.Runtime.Versioning;
 
     /*
     * Represent a font object
     */
 
    /// <include file='doc\Font.uex' path='docs/doc[@for="Font"]/*' />
    /// <devdoc>
    ///    Defines a particular format for text,
    ///    including font face, size, and style attributes.
    /// </devdoc>
    [
    TypeConverterAttribute(typeof(FontConverter)),
    EditorAttribute("System.Drawing.Design.FontEditor, " + AssemblyRef.SystemDrawingDesign, typeof(UITypeEditor)),
    ]
    [Serializable]
    [ComVisible(true)]
    public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDisposable {
        const int LogFontCharSetOffset = 23;
        const int LogFontNameOffset = 28;
 
        IntPtr          nativeFont;
        float           fontSize;
        FontStyle       fontStyle;
        FontFamily      fontFamily;
        GraphicsUnit    fontUnit;
        byte            gdiCharSet = SafeNativeMethods.DEFAULT_CHARSET; 
        bool            gdiVerticalFont;
        string          systemFontName = "";
        string          originalFontName;
 
        ///<devdoc>
        ///     Creates the GDI+ native font object.
        ///</devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        private void CreateNativeFont()
        {
            Debug.Assert(this.nativeFont == IntPtr.Zero, "nativeFont already initialized, this will generate a handle leak.");
            Debug.Assert(this.fontFamily != null, "fontFamily not initialized.");
 
            // Note: GDI+ creates singleton font family objects (from the corresponding font file) and reference count them so
            // if creating the font object from an external FontFamily, this object's FontFamily will share the same native object.
            int status = SafeNativeMethods.Gdip.GdipCreateFont(
                                    new HandleRef(this, this.fontFamily.NativeFamily),
                                    this.fontSize,
                                    this.fontStyle,
                                    this.fontUnit,
                                    out this.nativeFont );
 
            // Special case this common error message to give more information
            if (status == SafeNativeMethods.Gdip.FontStyleNotFound)
            {
                throw new ArgumentException(SR.GetString(SR.GdiplusFontStyleNotFound, this.fontFamily.Name, this.fontStyle.ToString()));
            }
            else if (status != SafeNativeMethods.Gdip.Ok)
            {
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
        }
 
        /**
         * Constructor used in deserialization
         */         
        [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")]
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        private Font(SerializationInfo info, StreamingContext context) {
            Debug.Assert(info != null, "Didn't expect a null parameter");
 
            string name = null;
            float size = -1f;
            FontStyle style = FontStyle.Regular;
            GraphicsUnit unit = GraphicsUnit.Point;
            SingleConverter sc = new SingleConverter();
 
            SerializationInfoEnumerator sie = info.GetEnumerator();
            for (; sie.MoveNext();) {
                if (String.Equals(sie.Name, "Name", StringComparison.OrdinalIgnoreCase))
                    name = (string) sie.Value;
                else if (String.Equals(sie.Name, "Size", StringComparison.OrdinalIgnoreCase))
                {
                    if (sie.Value is System.String)
                    {
                        size = (float) sc.ConvertFrom(sie.Value);
                    }
                    else
                    {
                        size = (float) sie.Value;
                    }
                }
                else if (String.Compare(sie.Name, "Style", true, CultureInfo.InvariantCulture) == 0)
                    style = (FontStyle) sie.Value;
                else if (String.Compare(sie.Name, "Unit", true, CultureInfo.InvariantCulture) == 0)
                    unit = (GraphicsUnit) sie.Value;
                else {
                    Debug.Fail("Unknown serialization item for font: " + sie.Name);
                }
            }
 
            Initialize(name, size, style, unit, SafeNativeMethods.DEFAULT_CHARSET, IsVerticalName(name));
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.ISerializable.GetObjectData"]/*' />
        /// <devdoc>
        ///     ISerializable private implementation
        /// </devdoc>
        /// <internalonly/>
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
        void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) {
            // Serialize the original Font name rather than the fallback font name if we have one
            // See VSWhidbey 602074
            si.AddValue("Name", String.IsNullOrEmpty(OriginalFontName) ? Name : OriginalFontName);
            si.AddValue("Size", Size);
            si.AddValue("Style", Style);
            si.AddValue("Unit", Unit);
        }
 
        
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Drawing.Font'/> class from
        ///       the specified existing <see cref='System.Drawing.Font'/> and <see cref='System.Drawing.FontStyle'/>.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(Font prototype, FontStyle newStyle) 
        {
            // Copy over the originalFontName because it won't get initialized
            this.originalFontName = prototype.OriginalFontName;
            Initialize(prototype.FontFamily, prototype.Size, newStyle, prototype.Unit, SafeNativeMethods.DEFAULT_CHARSET, false);
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font1"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the <see cref='System.Drawing.Font'/> class with
        ///    the specified attributes.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(FontFamily family, float emSize, FontStyle style, GraphicsUnit unit)  {
            Initialize(family, emSize, style, unit, SafeNativeMethods.DEFAULT_CHARSET, false);
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font9"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the <see cref='System.Drawing.Font'/> class with
        ///    the specified attributes.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet) {
            Initialize(family, emSize, style, unit, gdiCharSet, false);
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font11"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the <see cref='System.Drawing.Font'/> class with
        ///    the specified attributes.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet, bool gdiVerticalFont) {
            Initialize(family, emSize, style, unit, gdiCharSet, gdiVerticalFont); 
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font10"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the <see cref='System.Drawing.Font'/> class with
        ///    the specified attributes.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet) {
            Initialize(familyName, emSize, style, unit, gdiCharSet, IsVerticalName(familyName));
        }
 
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font12"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the <see cref='System.Drawing.Font'/> class with
        ///    the specified attributes.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet, bool gdiVerticalFont) {
            if (float.IsNaN(emSize) || float.IsInfinity(emSize) || emSize <= 0) {
                throw new ArgumentException(SR.GetString(SR.InvalidBoundArgument, "emSize", emSize, 0, "System.Single.MaxValue"), "emSize");
            }
 
            Initialize(familyName, emSize, style, unit, gdiCharSet, gdiVerticalFont);
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font2"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the <see cref='System.Drawing.Font'/> class with
        ///    the specified attributes.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(FontFamily family, float emSize, FontStyle style) {
            Initialize(family, emSize, style, GraphicsUnit.Point, SafeNativeMethods.DEFAULT_CHARSET, false);
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font3"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the <see cref='System.Drawing.Font'/> class with
        ///    the specified attributes.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(FontFamily family, float emSize, GraphicsUnit unit) {
            Initialize(family, emSize, FontStyle.Regular, unit, SafeNativeMethods.DEFAULT_CHARSET, false);
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font4"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the <see cref='System.Drawing.Font'/> class with
        ///    the specified attributes.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(FontFamily family, float emSize) {
            Initialize(family, emSize, FontStyle.Regular, GraphicsUnit.Point, SafeNativeMethods.DEFAULT_CHARSET, false);
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font5"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the <see cref='System.Drawing.Font'/> class with
        ///    the specified attributes.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(string familyName, float emSize, FontStyle style, GraphicsUnit unit) {
            Initialize(familyName, emSize, style, unit, SafeNativeMethods.DEFAULT_CHARSET, IsVerticalName(familyName));
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font6"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Drawing.Font'/> class with
        ///       the specified
        ///       attributes.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(string familyName, float emSize, FontStyle style) {
            Initialize(familyName, emSize, style, GraphicsUnit.Point, SafeNativeMethods.DEFAULT_CHARSET, IsVerticalName(familyName));
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font7"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the <see cref='System.Drawing.Font'/> class with
        ///    the specified attributes.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(string familyName, float emSize, GraphicsUnit unit) {
            Initialize(familyName, emSize, FontStyle.Regular, unit, SafeNativeMethods.DEFAULT_CHARSET, IsVerticalName(familyName));
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Font8"]/*' />
        /// <devdoc>
        ///    Initializes a new instance of the <see cref='System.Drawing.Font'/> class with
        ///    the specified attributes.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public Font(string familyName, float emSize) {
            Initialize(familyName, emSize, FontStyle.Regular, GraphicsUnit.Point, SafeNativeMethods.DEFAULT_CHARSET, IsVerticalName(familyName));
        }
 
        /// <devdoc>
        ///     Constructor to initialize fields from an exisiting native GDI+ object reference.
        ///     Used by ToLogFont.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        private Font(IntPtr nativeFont, byte gdiCharSet, bool gdiVerticalFont) 
        {
            Debug.Assert(this.nativeFont == IntPtr.Zero, "GDI+ native font already initialized, this will generate a handle leak" );
            Debug.Assert(nativeFont != IntPtr.Zero, "nativeFont is null");
            
            int          status       = 0;
            float        size         = 0;
            GraphicsUnit unit         = GraphicsUnit.Point;
            FontStyle    style        = FontStyle.Regular;
            IntPtr       nativeFamily = IntPtr.Zero;
 
            this.nativeFont = nativeFont;
 
            status = SafeNativeMethods.Gdip.GdipGetFontUnit(new HandleRef(this, nativeFont), out unit);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            status = SafeNativeMethods.Gdip.GdipGetFontSize(new HandleRef(this, nativeFont), out size);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            status = SafeNativeMethods.Gdip.GdipGetFontStyle(new HandleRef(this, nativeFont), out style);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            status = SafeNativeMethods.Gdip.GdipGetFamily(new HandleRef(this, nativeFont), out nativeFamily);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            SetFontFamily(new FontFamily(nativeFamily));
            
            Initialize(this.fontFamily, size, style, unit, gdiCharSet, gdiVerticalFont);
        }
 
        /// <devdoc>
        ///     Initializes this object's fields.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        private void Initialize(string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet, bool gdiVerticalFont) 
        {
            this.originalFontName = familyName;
 
            SetFontFamily(new FontFamily(StripVerticalName(familyName), true /* createDefaultOnFail */ ));
            Initialize( this.fontFamily, emSize, style, unit, gdiCharSet, gdiVerticalFont );
        }
 
        /// <devdoc>
        ///     Initializes this object's fields.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        private void Initialize(FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet, bool gdiVerticalFont) 
        {
            if (family == null) 
            {
                throw new ArgumentNullException("family");
            }
 
            if ( float.IsNaN( emSize ) || float.IsInfinity(emSize) || emSize <= 0 ) 
            {
                throw new ArgumentException(SR.GetString(SR.InvalidBoundArgument, "emSize", emSize, 0, "System.Single.MaxValue"), "emSize");
            }
 
            int status;
 
            this.fontSize        = emSize;
            this.fontStyle       = style;
            this.fontUnit        = unit;
            this.gdiCharSet      = gdiCharSet;
            this.gdiVerticalFont = gdiVerticalFont;
 
            if (this.fontFamily == null)
            {
                // GDI+ FontFamily is a singleton object.
                SetFontFamily(new FontFamily(family.NativeFamily));
            }
 
            if( this.nativeFont == IntPtr.Zero )
            {
                CreateNativeFont();
            }
 
            // Get actual size.
            status = SafeNativeMethods.Gdip.GdipGetFontSize(new HandleRef(this, this.nativeFont), out this.fontSize);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.FromHfont"]/*' />
        /// <devdoc>
        ///    Creates a <see cref='System.Drawing.Font'/> from the specified Windows
        ///    handle.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public static Font FromHfont(IntPtr hfont) {
            IntSecurity.ObjectFromWin32Handle.Demand();
 
            SafeNativeMethods.LOGFONT lf = new SafeNativeMethods.LOGFONT();
            SafeNativeMethods.GetObject(new HandleRef(null, hfont), lf);
 
            Font result;
            IntPtr screenDC = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef);
            try {
                result = Font.FromLogFont(lf, screenDC);
            }
            finally {
                UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, screenDC));
            }
 
            return result;
        }
 
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.FromLogFont"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public static Font FromLogFont(object lf) {
            IntPtr screenDC = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef);
            Font result;
            try {
                result = Font.FromLogFont(lf, screenDC);
            }
            finally {
                UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, screenDC));
            }
            return result;
 
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.FromLogFont1"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public static Font FromLogFont(object lf, IntPtr hdc) {
            IntSecurity.ObjectFromWin32Handle.Demand();
 
            IntPtr font = IntPtr.Zero;
            int status;
 
            if (Marshal.SystemDefaultCharSize == 1)
                status = SafeNativeMethods.Gdip.GdipCreateFontFromLogfontA(new HandleRef(null, hdc), lf, out font);
            else
                status = SafeNativeMethods.Gdip.GdipCreateFontFromLogfontW(new HandleRef(null, hdc), lf, out font);
 
            // Special case this incredibly common error message to give more information
            if (status == SafeNativeMethods.Gdip.NotTrueTypeFont)
                throw new ArgumentException(SR.GetString(SR.GdiplusNotTrueTypeFont_NoName));
            else if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            // GDI+ returns font = 0 even though the status is Ok.
            if (font == IntPtr.Zero)
                throw new ArgumentException(SR.GetString(SR.GdiplusNotTrueTypeFont, lf.ToString()));
 
            bool gdiVerticalFont;
            if (Marshal.SystemDefaultCharSize == 1) {
                gdiVerticalFont = (Marshal.ReadByte(lf, LogFontNameOffset) == (byte)(short)'@');
            }
            else {
                gdiVerticalFont = (Marshal.ReadInt16(lf, LogFontNameOffset) == (short)'@');
            }
 
            return new Font(font, Marshal.ReadByte(lf, LogFontCharSetOffset), gdiVerticalFont);
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.FromHdc"]/*' />
        /// <devdoc>
        ///    Creates a Font from the specified Windows
        ///    handle to a device context.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public static Font FromHdc(IntPtr hdc) {
            IntSecurity.ObjectFromWin32Handle.Demand();
 
            IntPtr font = IntPtr.Zero;
 
            int status = SafeNativeMethods.Gdip.GdipCreateFontFromDC(new HandleRef(null, hdc), ref font);
 
            // Special case this incredibly common error message to give more information
            if (status == SafeNativeMethods.Gdip.NotTrueTypeFont)
                throw new ArgumentException(SR.GetString(SR.GdiplusNotTrueTypeFont_NoName));
            else if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return new Font(font, 0, false);
        }
 
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Clone"]/*' />
        /// <devdoc>
        ///    Creates an exact copy of this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public object Clone() 
        {
            IntPtr cloneFont = IntPtr.Zero;
 
            int status = SafeNativeMethods.Gdip.GdipCloneFont(new HandleRef(this, nativeFont), out cloneFont);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            Font newCloneFont = new Font(cloneFont, this.gdiCharSet, this.gdiVerticalFont);
 
            return newCloneFont;
        }
 
        
        /// <devdoc>
        ///     Get native GDI+ object pointer.
        ///     This property triggers the creation of the GDI+ native object if not initialized yet.
        /// </devdoc>
        internal IntPtr NativeFont
        {
            get
            {
                Debug.Assert( this.nativeFont != IntPtr.Zero, "this.nativeFont == IntPtr.Zero." );
                return this.nativeFont;
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.FontFamily"]/*' />
        /// <devdoc>
        ///    Gets the <see cref='System.Drawing.FontFamily'/> of this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        [Browsable(false)]
        public FontFamily FontFamily 
        {
            get 
            {
                Debug.Assert(this.fontFamily != null, "fontFamily should never be null");
                return this.fontFamily;
            }
        }
 
        [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")]
	private void SetFontFamily(FontFamily family) {
            this.fontFamily = family;
 
            // GDI+ creates ref-counted singleton FontFamily objects based on the family name so all managed 
            // objects with same family name share the underlying GDI+ native pointer.  The unmanged object is
            // destroyed when its ref-count gets to zero.
            // Make sure this.fontFamily is not finalized so the underlying singleton object is kept alive.
	    // SECREVIEW : This security assert here is safe.
            //
            new System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode).Assert();
            GC.SuppressFinalize(this.fontFamily);
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Finalize"]/*' />
        /// <devdoc>
        ///    Cleans up Windows resources for this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        ~Font() 
        {
            Dispose(false);
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Dispose"]/*' />
        /// <devdoc>
        ///    Cleans up Windows resources for this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
        [SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed")]
        void Dispose(bool disposing) {
            if (this.nativeFont != IntPtr.Zero) {
                try {
#if DEBUG
                    int status =
#endif
                    SafeNativeMethods.Gdip.GdipDeleteFont(new HandleRef(this, this.nativeFont));
#if DEBUG
                    Debug.Assert(status == SafeNativeMethods.Gdip.Ok, "GDI+ returned an error status: " + status.ToString(CultureInfo.InvariantCulture));
#endif
                }
                catch( Exception ex ) {
                    if( ClientUtils.IsCriticalException( ex ) ) {
                        throw;
                    }
 
                    Debug.Fail( "Exception thrown during Dispose: " + ex.ToString() );
                }
                finally {
                    this.nativeFont = IntPtr.Zero;
                }
            }
        }
 
        private static bool IsVerticalName(string familyName) 
        {
            return familyName != null && familyName.Length > 0 && familyName[0] == '@';
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Bold"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets a value indicating whether this <see cref='System.Drawing.Font'/> is bold.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool Bold {
            get {
                return(Style & FontStyle.Bold) != 0;
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.GdiCharSet"]/*' />
        /// <devdoc>
        ///     Returns the GDI char set for this instance of a font. This will only
        ///     be valid if this font was created from a classic GDI font definition,
        ///     like a LOGFONT or HFONT, or it was passed into the constructor.
        ///
        ///     This is here for compatability with native Win32 intrinsic controls
        ///     on non-Unicode platforms.
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public byte GdiCharSet {
            get {
                return gdiCharSet;
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.GdiVerticalFont"]/*' />
        /// <devdoc>
        ///     Determines if this font was created to represt a GDI vertical font.
        ///     his will only be valid if this font was created from a classic GDI
        ///     font definition, like a LOGFONT or HFONT, or it was passed into the 
        ///     constructor.
        ///
        ///     This is here for compatability with native Win32 intrinsic controls
        ///     on non-Unicode platforms.
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool GdiVerticalFont {
            get {
                return gdiVerticalFont;
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Italic"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets a value indicating whether this <see cref='System.Drawing.Font'/> is Italic.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool Italic {
            get {
                return(Style & FontStyle.Italic) != 0;
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Name"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets the face name of this <see cref='System.Drawing.Font'/> .
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Editor("System.Drawing.Design.FontNameEditor, " + AssemblyRef.SystemDrawingDesign, typeof(UITypeEditor))]
        [TypeConverterAttribute(typeof(FontConverter.FontNameConverter))]
        public string Name {
            get { return this.FontFamily.Name;}
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.OriginalFontName"]/*' />
        /// <devdoc>
        ///    <para>
        ///       This property is required by the framework and not intended to be used directly.
        ///    </para>
        /// </devdoc>
        [Browsable(false)]
        public string OriginalFontName
        {
            get { return this.originalFontName; }
        }
        
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Strikeout"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets a value indicating whether this <see cref='System.Drawing.Font'/> is strikeout (has a line
        ///       through it).
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool Strikeout {
            get {
                return(Style & FontStyle.Strikeout) != 0;
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Underline"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets a value indicating whether this <see cref='System.Drawing.Font'/> is underlined.
        ///    </para>
        /// </devdoc>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool Underline {
            get {
                return(Style & FontStyle.Underline) != 0;
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Equals"]/*' />
        /// <devdoc>
        ///    Returns a value indicating whether the
        ///    specified object is a <see cref='System.Drawing.Font'/> equivalent to this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        public override bool Equals(object obj)
        {
            if (obj == this) 
            {
                return true;
            }
 
            Font font = obj as Font;
            
            if (font == null) 
            {
                return false;
            }
 
            // Note: If this and/or the passed-in font are disposed, this method can still return true since we check for cached properties
            // here - We cannot fix this, see VSW#484721.
 
            // We need to call properties on the passed-in object since it could be a proxy in a remoting scenario and proxies don't
            // have access to private/internal fields - See VSW#464151.
            return  font.FontFamily.Equals(this.FontFamily)  &&
                font.GdiVerticalFont == this.GdiVerticalFont &&
                font.GdiCharSet      == this.GdiCharSet      &&
                font.Style           == this.Style           &&
                font.Size            == this.Size            &&
                font.Unit            == this.Unit;
        } 
  
        
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.GetHashCode"]/*' />
        /// <devdoc>
        ///    Gets the hash code for this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        public override int GetHashCode() 
        {
            return unchecked((int)((((UInt32)fontStyle << 13) | ((UInt32)fontStyle >> 19)) ^
                         (((UInt32)fontUnit  << 26) | ((UInt32)fontUnit  >>  6)) ^
                         (((UInt32)fontSize  <<  7) | ((UInt32)fontSize  >> 25))));
        }
 
        private static string StripVerticalName(string familyName) {
            if (familyName != null && familyName.Length > 1 && familyName[0] == '@') {
                return familyName.Substring(1);
            }
            return familyName;
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.ToString"]/*' />
        /// <devdoc>
        ///    Returns a human-readable string
        ///    representation of this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        public override string ToString()
        {
            return string.Format(   CultureInfo.CurrentCulture, "[{0}: Name={1}, Size={2}, Units={3}, GdiCharSet={4}, GdiVerticalFont={5}]", 
                                    GetType().Name, 
                                    this.FontFamily.Name, 
                                    this.fontSize, 
                                    (int) this.fontUnit,
                                    this.gdiCharSet, 
                                    this.gdiVerticalFont );
        }
 
        
 
        // Operations
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.ToLogFont"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        public void ToLogFont(object logFont) {
            IntPtr screenDC = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef);
            try {
                Graphics graphics = Graphics.FromHdcInternal(screenDC);
 
                try {
                    this.ToLogFont(logFont, graphics);
                }
                finally {
                    graphics.Dispose();
                }
            }
            finally {
                UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, screenDC));
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.ToLogFont1"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public unsafe void ToLogFont(object logFont, Graphics graphics) {
            IntSecurity.ObjectFromWin32Handle.Demand();
 
            if (graphics == null)
                throw new ArgumentNullException("graphics");
 
            int status;
 
            // handle proper marshalling of LogFontName as Unicode or ANSI
            if (Marshal.SystemDefaultCharSize == 1)
                status = SafeNativeMethods.Gdip.GdipGetLogFontA(new HandleRef(this, this.NativeFont), new HandleRef(graphics, graphics.NativeGraphics), logFont);
            else
                status = SafeNativeMethods.Gdip.GdipGetLogFontW(new HandleRef(this, this.NativeFont), new HandleRef(graphics, graphics.NativeGraphics), logFont);
 
            // append "@" to the begining of the string if we are 
            // a gdiVerticalFont.
            //
            if (gdiVerticalFont) {
                if (Marshal.SystemDefaultCharSize == 1) {
 
                    // copy contents of name, over 1 byte
                    //
                    for (int i=30; i>=0; i--) {
                        Marshal.WriteByte(logFont, 
                                          LogFontNameOffset + i + 1, 
                                          Marshal.ReadByte(logFont, LogFontNameOffset + i));
                    }
 
                    // write ANSI '@' sign at begining of name
                    //
                    Marshal.WriteByte(logFont, LogFontNameOffset, (byte)(int)'@');
                }
                else {
                    // copy contents of name, over 2 bytes (UNICODE)
                    //
                    for (int i=60; i>=0; i-=2) {
                        Marshal.WriteInt16(logFont, 
                                           LogFontNameOffset + i + 2, 
                                           Marshal.ReadInt16(logFont, LogFontNameOffset + i));
                    }
 
                    // write UNICODE '@' sign at begining of name
                    //
                    Marshal.WriteInt16(logFont, LogFontNameOffset, (short)'@');
                }
            }
 
            if (Marshal.ReadByte(logFont, LogFontCharSetOffset) == 0) {
                Marshal.WriteByte(logFont, LogFontCharSetOffset, gdiCharSet);
            }
            
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.ToHfont"]/*' />
        /// <devdoc>
        ///    Returns a handle to this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public IntPtr ToHfont() {
            SafeNativeMethods.LOGFONT lf = new SafeNativeMethods.LOGFONT();
               
            IntSecurity.ObjectFromWin32Handle.Assert();
 
            try {
                this.ToLogFont(lf);
            }
            finally {
                System.Security.CodeAccessPermission.RevertAssert();
            }
 
            IntPtr handle = IntUnsafeNativeMethods.IntCreateFontIndirect(lf);
 
            if (handle == IntPtr.Zero) {
                throw new Win32Exception();
            }
 
            return handle;
 
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.GetHeight"]/*' />
        /// <devdoc>
        ///    Returns the height of this Font in the
        ///    specified graphics context.
        /// </devdoc>
        public float GetHeight(Graphics graphics) {
            if (graphics == null)
                throw new ArgumentNullException("graphics");
 
            float ht;
 
            int status = SafeNativeMethods.Gdip.GdipGetFontHeight(new HandleRef(this, this.NativeFont), new HandleRef(graphics, graphics.NativeGraphics), out ht);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return ht;
        }
 
                /// <include file='doc\Font.uex' path='docs/doc[@for="Font.GetHeight1"]/*' />
        /// <devdoc>
        /// </devdoc>
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        public float GetHeight() {
            
            IntPtr screenDC = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef);
            float height = 0.0f;
            try {
                using (Graphics graphics = Graphics.FromHdcInternal(screenDC)) {
                    height = GetHeight(graphics);
                }
            }
            finally {
                UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, screenDC));                    
            }
                    
            return height;        
        }
 
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.GetHeight2"]/*' />
        /// <devdoc>
        /// </devdoc>
        public float GetHeight(float dpi) {
 
            float ht;
 
            int status = SafeNativeMethods.Gdip.GdipGetFontHeightGivenDPI(new HandleRef(this, this.NativeFont), dpi, out ht);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return ht;
        }
 
        
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Style"]/*' />
        /// <devdoc>
        ///    Gets style information for this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        [
        Browsable(false)
        ]
        public FontStyle Style {
            get {
                return fontStyle;
            }
        }
 
        // Return value is in Unit (the unit the font was created in)
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Size"]/*' />
        /// <devdoc>
        ///    Gets the size of this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        public float Size {
            get {
                return fontSize;
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.SizeInPoints"]/*' />
        /// <devdoc>
        ///    Gets the size, in points, of this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        [Browsable(false)]
        public float SizeInPoints {
             [ResourceExposure(ResourceScope.None)]
             [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
             get {
                if (Unit == GraphicsUnit.Point)
                    return Size;
                else {
                    float emHeightInPoints;
                    
                    IntPtr screenDC = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef);
                    
                    try {
                        using( Graphics graphics = Graphics.FromHdcInternal(screenDC)){
                            float pixelsPerPoint      = (float) (graphics.DpiY / 72.0);
                            float lineSpacingInPixels = this.GetHeight(graphics);
                            float emHeightInPixels    = lineSpacingInPixels * FontFamily.GetEmHeight(Style)  / FontFamily.GetLineSpacing(Style);
                            
                            emHeightInPoints    = emHeightInPixels / pixelsPerPoint;
                        }
                    }
                    finally {
                        UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, screenDC));
                    }
 
                    return emHeightInPoints;
                }
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Unit"]/*' />
        /// <devdoc>
        ///    Gets the unit of measure for this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        [TypeConverterAttribute(typeof(FontConverter.FontUnitConverter))]
        public GraphicsUnit Unit {
            get {
                return fontUnit;
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.Height"]/*' />
        /// <devdoc>
        ///    Gets the height of this <see cref='System.Drawing.Font'/>.
        /// </devdoc>
        [
        Browsable(false)
        ]
        public int Height {
            get {
                return(int) Math.Ceiling(GetHeight());
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.IsSystemFont"]/*' />
        /// <devdoc>
        ///    Returns true if this <see cref='System.Drawing.Font'/> is a SystemFont.
        /// </devdoc>
        [
        Browsable(false)
        ]
        public bool IsSystemFont {
            get {
                return !String.IsNullOrEmpty(this.systemFontName);
            }
        }
 
        /// <include file='doc\Font.uex' path='docs/doc[@for="Font.SystemFontName"]/*' />
        /// <devdoc>
        ///    Gets the name of this <see cref='System.Drawing.SystemFont'/>.
        /// </devdoc>
        [
        Browsable(false)
        ]
        public string SystemFontName {
            get {
                return this.systemFontName;
            }
        }
 
        // This is used by SystemFonts when constructing a system Font objects.
        internal void SetSystemFontName(string systemFontName) {
            this.systemFontName = systemFontName;
        }
    }
}