WindowsFont.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Misc / GDI / WindowsFont.cs / 1 / WindowsFont.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

#if WINFORMS_NAMESPACE 
namespace System.Windows.Forms.Internal 
#elif DRAWING_NAMESPACE
namespace System.Drawing.Internal 
#else
namespace System.Experimental.Gdi
#endif
{ 
    using System;
    using System.Internal; 
    using System.Runtime.InteropServices; 
    using System.ComponentModel;
    using System.Diagnostics; 
    using System.Drawing;
    using System.Drawing.Text;
    using System.Security;
    using System.Security.Permissions; 
    using System.Globalization;
 
    ///  
    ///     
    ///         Encapsulates a GDI Font object. 
    ///     
    /// 
#if WINFORMS_PUBLIC_GRAPHICS_LIBRARY
    public 
#else
    internal 
#endif 
    sealed partial class WindowsFont : MarshalByRefObject, ICloneable, IDisposable
    { 
        const int LogFontNameOffset = 28;

        // Handle to the native Windows font object.
        // 
        private IntPtr hFont;
        private float  fontSize = -1.0f; //invalid value. 
        private int    lineSpacing; 
        private bool   ownHandle;
        private bool   ownedByCacheManager; 
        private bool   everOwnedByCacheManager;

        private IntNativeMethods.LOGFONT logFont;
        private FontStyle style; 

        // Note: These defaults are according to the ones in GDI+ but those are not necessarily the same as the system 
        // default font.  The GetSystemDefaultHFont() method should be used if needed. 
        private const string defaultFaceName   = "Microsoft Sans Serif";
        private const float  defaultFontSize   = 8.25f; 
        private const int    defaultFontHeight = 13;

#if GDI_FINALIZATION_WATCH
       private string AllocationSite = DbgUtil.StackTrace; 
#endif
 
        ///  
        ///     Creates the font handle.
        ///  
        private void CreateFont()
        {
            Debug.Assert( hFont == IntPtr.Zero, "hFont is not null, this will generate a handle leak." );
            Debug.Assert( this.logFont != null, "WindowsFont.logFont not initialized." ); 

            this.hFont = IntUnsafeNativeMethods.CreateFontIndirect(this.logFont); 
 
#if TRACK_HFONT
            Debug.WriteLine( DbgUtil.StackTraceToStr(String.Format( "HFONT[0x{0:x8}] = CreateFontIndirect( LOGFONT={1} )", (int) this.hFont, this.logFont))); 
#endif
            if (this.hFont == IntPtr.Zero)
            {
                this.logFont.lfFaceName     = defaultFaceName; 
                this.logFont.lfOutPrecision = IntNativeMethods.OUT_TT_ONLY_PRECIS; // True Type only.
 
                this.hFont = IntUnsafeNativeMethods.CreateFontIndirect(this.logFont); 

#if TRACK_HFONT 
            Debug.WriteLine( DbgUtil.StackTraceToStr(String.Format( "HFONT[0x{0:x8}] = CreateFontIndirect( LOGFONT={1} )", (int) this.hFont, this.logFont)));
#endif

            } 

            // Update logFont height and other adjusted parameters. 
            // 
            IntUnsafeNativeMethods.GetObject(new HandleRef(this, this.hFont), this.logFont);
 
            // We created the hFont, we will delete it on dispose.
            this.ownHandle = true;
        }
 
        /// Constructors.
 
        ///  
        ///     Contructor to construct font from a face name.
        /// > 
        public WindowsFont( string faceName ) :
            this(faceName, defaultFontSize, FontStyle.Regular, IntNativeMethods.DEFAULT_CHARSET, WindowsFontQuality.Default)
        {
         // Default size in WinForms is 8.25f. 
        }
 
        ///  
        ///     Contructor to construct font from a face name, a desired size and with the specified style.
        /// > 
        public WindowsFont( string faceName, float size ) :
            this(faceName, size, FontStyle.Regular, IntNativeMethods.DEFAULT_CHARSET, WindowsFontQuality.Default)
        {
        } 

        ///  
        ///     Contructor to construct font from a face name, a desired size and with the specified style. 
        /// >
        public WindowsFont( string faceName, float size, FontStyle style ) : 
            this(faceName, size, style, IntNativeMethods.DEFAULT_CHARSET, WindowsFontQuality.Default)
        {
        }
 
        /// 
        ///     Contructor to construct font from a face name, a desired size in points and with the specified style 
        ///     and character set. The screen dc is used for calculating the font em height. 
        /// >
        public WindowsFont( string faceName, float size, FontStyle style, byte charSet, WindowsFontQuality fontQuality ) 
        {
            Debug.Assert( size > 0.0f, "size has a negative value." );
            const byte True  = 1;
            const byte False = 0; 
            this.logFont = new IntNativeMethods.LOGFONT();
 
            // 
            // Get the font height from the specified size.  size is in point units and height in logical
            // units (pixels when using MM_TEXT) so we need to make the conversion using the number of 
            // pixels per logical inch along the screen height.
            //
            int pixelsY = (int) Math.Ceiling( WindowsGraphicsCacheManager.MeasurementGraphics.DeviceContext.DpiY * size / 72); // 1 point = 1/72 inch.;
 
            //
            // The lfHeight represents the font cell height (line spacing) which includes the internal 
            // leading; we specify a negative size value (in pixels) for the height so the font mapper 
            // provides the closest match for the character height rather than the cell height (MSDN).
            // 
            this.logFont.lfHeight       = -pixelsY;
            this.logFont.lfFaceName     = faceName != null ? faceName : defaultFaceName;
            this.logFont.lfCharSet      = charSet;
            this.logFont.lfOutPrecision = IntNativeMethods.OUT_TT_PRECIS; 
            this.logFont.lfQuality      = (byte) fontQuality;
            this.logFont.lfWeight       = (style & FontStyle.Bold)      == FontStyle.Bold      ? IntNativeMethods.FW_BOLD : IntNativeMethods.FW_NORMAL; 
            this.logFont.lfItalic       = (style & FontStyle.Italic)    == FontStyle.Italic    ? True : False; 
            this.logFont.lfUnderline    = (style & FontStyle.Underline) == FontStyle.Underline ? True : False;
            this.logFont.lfStrikeOut    = (style & FontStyle.Strikeout) == FontStyle.Strikeout ? True : False; 

            // Let the Size be recomputed to be consistent with the Height (there may be some precision loss coming from size to height).
            // this.fontSize = size;
            this.style    = style; 

            CreateFont(); 
        } 

        ///  
        ///     Contructor to construct font from a LOGFONT structure.
        ///     Pass false in the createHandle param to create a 'compatible' font (handle-less, to be used for measuring/comparing) or
        ///     when the handle has already been created.
        ///  
        private WindowsFont( IntNativeMethods.LOGFONT lf, bool createHandle )
        { 
            Debug.Assert( lf != null, "lf is null" ); 

            this.logFont = lf; 

            if (this.logFont.lfFaceName == null)
            {
                this.logFont.lfFaceName = defaultFaceName; 
            }
 
            this.style = FontStyle.Regular; 
            if (lf.lfWeight == IntNativeMethods.FW_BOLD)
            { 
                this.style |= FontStyle.Bold;
            }
            if (lf.lfItalic == 1)
            { 
                this.style |= FontStyle.Italic;
            } 
            if (lf.lfUnderline == 1) 
            {
                this.style |= FontStyle.Underline; 
            }
            if (lf.lfStrikeOut == 1)
            {
                this.style |= FontStyle.Strikeout; 
            }
 
            if( createHandle ) 
            {
                CreateFont(); 
            }
        }

        ///  
        ///     Contructs a WindowsFont object from an existing System.Drawing.Font object (GDI+), based on the screen dc MapMode
        ///     and resolution (normally: MM_TEXT and 96 dpi). 
        ///  
        public static WindowsFont FromFont(Font font)
        { 
            return FromFont(font, WindowsFontQuality.Default);
        }
        public static WindowsFont FromFont(Font font, WindowsFontQuality fontQuality)
        { 
            string familyName = font.FontFamily.Name;
 
            // Strip vertical-font mark from the name if needed. 
            if (familyName != null && familyName.Length > 1 && familyName[0] == '@')
            { 
                familyName = familyName.Substring(1);
            }

            // Note: Creating the WindowsFont from Font using a LOGFONT structure from GDI+ (Font.ToLogFont(logFont)) may sound like 
            // a better choice (more accurate) for doing this but tests show that is not the case (see WindowsFontTests test suite),
            // the results are the same.  Also, that approach has some issues when the Font is created in a different application 
            // domain since the LOGFONT cannot be marshalled properly, see VSW#451960. 
            // Now, creating it using the Font.SizeInPoints makes it GraphicsUnit-independent.
 
            return new WindowsFont(familyName, font.SizeInPoints, font.Style, font.GdiCharSet, fontQuality);
        }

 
        /// 
        ///     Creates a WindowsFont from the font selected in the supplied dc. 
        ///  
        public static WindowsFont FromHdc( IntPtr hdc )
        { 
            IntPtr hFont = IntUnsafeNativeMethods.GetCurrentObject(new HandleRef(null, hdc), IntNativeMethods.OBJ_FONT);

            // don't call DeleteObject on handle from GetCurrentObject, it is the one selected in the hdc.
 
            return FromHfont( hFont );
        } 
 
        /// 
        ///     Creates a WindowsFont from the handle to a native GDI font.  It does not take ownership of the 
        ///     passed-in handle, the caller needs to delete the hFont when done with the WindowsFont.
        /// 
        public static WindowsFont FromHfont( IntPtr hFont )
        { 
            return FromHfont( hFont, false );
        } 
 
        /// 
        ///     Creates a WindowsFont from the handle to a native GDI font and optionally takes ownership of managing 
        ///     the lifetime of the handle.
        /// 
        public static WindowsFont FromHfont( IntPtr hFont, bool takeOwnership )
        { 
            IntNativeMethods.LOGFONT lf = new IntNativeMethods.LOGFONT();
            IntUnsafeNativeMethods.GetObject(new HandleRef(null, hFont), lf); 
 
            WindowsFont wf = new WindowsFont( lf, /*createHandle*/ false );
            wf.hFont = hFont; 
            wf.ownHandle = takeOwnership; // if true, hFont will be deleted on dispose.

            return wf;
        } 

        ~WindowsFont() 
        { 
            Dispose(false);
        } 

        public void Dispose()
        {
            Dispose(true); 
        }
 
        internal void Dispose(bool disposing) 
        {
            bool deletedHandle = false; 
            if (this.ownHandle)
            {
                if (!ownedByCacheManager || !disposing) {
 
                    // If we were ever owned by the CacheManger and we're being disposed
                    // we can be sure that we're not in use by any DC's (otherwise Dispose() wouldn't have been called) 
                    // skip the check IsFontInUse check in this case. 
                    // Also skip the check if disposing == false, because the cache is thread-static
                    // and that means we're being called from the finalizer. 
                    if (everOwnedByCacheManager || !disposing || !DeviceContexts.IsFontInUse(this)) {
                        Debug.Assert( this.hFont != IntPtr.Zero, "Unexpected null hFont." );
                        DbgUtil.AssertFinalization(this, disposing);
 
                        IntUnsafeNativeMethods.DeleteObject(new HandleRef(this, this.hFont));
#if TRACK_HFONT 
                        Debug.WriteLine( DbgUtil.StackTraceToStr(String.Format( "DeleteObject(HFONT[0x{0:x8}]))", (int) this.hFont))); 
#endif
                        this.hFont = IntPtr.Zero; 
                        this.ownHandle = false;
                        deletedHandle = true;
                    }
                } 
            }
 
            if (disposing && (deletedHandle || !ownHandle)) 
            {
                GC.SuppressFinalize(this); 
            }
        }

        ///  
        ///    Returns a value indicating whether the specified object is a WindowsFont equivalent to this object.
        ///  
        public override bool Equals( object font ) 
        {
            WindowsFont winFont = font as WindowsFont; 

            if( winFont == null )
            {
                return false; 
            }
 
            if( winFont == this ) 
            {
                return true; 
            }

            // WARNING: don't use non-public fields/properties here, the passed-in font object could be a proxy in a
            //          remoting scenario and proxies cannot access internal or private members.  VSW#465265 & 465647 

            // Compare params used to create the font. 
            return  this.Name           == winFont.Name            && 
                    this.LogFontHeight  == winFont.LogFontHeight   && // Equivalent to comparing Size but always at hand.
                    this.Style          == winFont.Style           && 
                    this.CharSet        == winFont.CharSet         &&
                    this.Quality        == winFont.Quality;
        }
 
        /// 
        ///    Gets the hash code for this WindowsFont. 
        ///  
        public override int GetHashCode()
        { 
            // similar to Font.GetHashCode().
            return (int)((((UInt32)this.Style   << 13) | ((UInt32)this.Style   >> 19)) ^
                         (((UInt32)this.CharSet << 26) | ((UInt32)this.CharSet >>  6)) ^
                         (((UInt32)this.Size    <<  7) | ((UInt32)this.Size    >> 25))); 
        }
 
        ///  
        ///     Clones this object.
        ///  
        public object Clone()
        {
            return new WindowsFont( this.logFont, true );
        } 

        public override string ToString() 
        { 
            return string.Format(CultureInfo.CurrentCulture, "[{0}: Name={1}, Size={2} points, Height={3} pixels, Sytle={4}]", GetType().Name,  logFont.lfFaceName, this.Size, this.Height, this.Style);
        } 

        ////////////////////////////////////////////
        ///  Properties
 
        /// 
        ///       Returns this object's native Win32 font handle.  Should NOT be deleted externally. 
        ///       Compare with ToHfont method. 
        /// 
        public IntPtr Hfont 
        {
            get
            {
                //Assert removed. We need to be able to check for Hfont == IntPtr.Zero to determine if the object was disposed. 
                //Debug.Assert(this.hFont != IntPtr.Zero, "hFont is null, are you using a disposed object?");
                return this.hFont; 
            } 
        }
 
        /// 
        ///     Determines whether the font has the italic style or not.
        /// 
        public bool Italic 
        {
            get 
            { 
                return logFont.lfItalic == 1;
            } 
        }

        public bool OwnedByCacheManager
        { 
            get {
                return ownedByCacheManager; 
            } 
            set {
                if (value) { 
                    everOwnedByCacheManager = true;
                }
                ownedByCacheManager = value;
            } 
        }
 
        ///  
        ///     Rendering quality.
        ///  
        public WindowsFontQuality Quality
        {
            get
            { 
                return (WindowsFontQuality) this.logFont.lfQuality;
            } 
        } 

        ///  
        ///     Gets the font style.
        /// 
        public FontStyle Style
        { 
            get
            { 
                return this.style; 
            }
        } 

        /// 
        ///     Gets the line spacing (cell height) of this font in (screen) pixels using the screen resolution.
        ///     Gets the line spacing (cell height), in pixels (using the screen DC resolution), of this font. 
        ///     The line spacing is the vertical distance between the base lines of two consecutive lines of text.
        ///     Thus, the line spacing includes the blank space between lines along with the height of the character 
        ///     itself. 
        /// 
        public int Height 
        {
            //

            get 
            {
                if( this.lineSpacing == 0 ) 
                { 
                    // Observe that the font text metrics are obtained using the resolution of the screen.
                    WindowsGraphics wg  = WindowsGraphicsCacheManager.MeasurementGraphics; 

                    // No need to reset the font (if changed) since we always set the font before using the MeasurementGraphics
                    // in WindowsGraphics methods.
                    wg.DeviceContext.SelectFont(this); 

                    IntNativeMethods.TEXTMETRIC tm = (IntNativeMethods.TEXTMETRIC) wg.GetTextMetrics(); 
                    this.lineSpacing = tm.tmHeight; 
                }
 
                return this.lineSpacing;
            }
        }
 
        /// 
        ///     Gets the font character set. 
        ///     This is used by the system font mapper when searching for the physical font that best matches the logical font. 
        /// 
        public byte CharSet 
        {
            get
            {
                return logFont.lfCharSet; 
            }
        } 
 
        /// 
        ///     Specifies the height, in logical units, of the font's character cell or character. The character height value (em height) 
        ///     is the character cell height value minus the internal-leading value.
        /// 
        public int LogFontHeight
        { 
            get
            { 
                return logFont.lfHeight; 
            }
        } 

        /// 
        ///     The font's face name.
        ///  
        public string Name
        { 
            get 
            {
                return logFont.lfFaceName; 
            }
        }

        ///  
        ///     Gets the character height (as opposed to the cell height) of the font represented by this object in points.
        ///     Consider 
        ///  
        public float Size
        { 
            get
            {
                if( this.fontSize < 0.0f )
                { 
                    WindowsGraphics wg  = WindowsGraphicsCacheManager.MeasurementGraphics;
 
                    // No need to reset the font (if changed) since we always set the font before using the MeasurementGraphics 
                    // in WindowsGraphics methods.
                    wg.DeviceContext.SelectFont(this); 

                    IntNativeMethods.TEXTMETRIC tm = (IntNativeMethods.TEXTMETRIC) wg.GetTextMetrics();

                    // 
                    // Convert the font character height to points.  If lfHeight is negative, Windows
                    // treats the absolute value of that number as a desired font height compatible with 
                    // the point size; in this case lfHeight will roughly match the tmHeight field of 
                    // the TEXTMETRIC structure less the tmInternalLeading field.
                    // 
                    int height = this.logFont.lfHeight > 0 ? tm.tmHeight : (tm.tmHeight - tm.tmInternalLeading);

                    //
                    /* 
                    switch (this.unit)
                    { 
                        case GraphicsUnit.Pixel:       worldEmSize = height * dpi / 72.0f;   break; 
                        case GraphicsUnit.Point:       worldEmSize = height * dpi / 72.0f;   break;
                        case GraphicsUnit.Inch:        worldEmSize = height * dpi;           break; 
                        case GraphicsUnit.Document:    worldEmSize = height * dpi / 300.0f;  break;
                        case GraphicsUnit.Millimeter:  worldEmSize = height * dpi / 25.4f;   break;
                    }
                    */ 

                    this.fontSize = height * 72f / wg.DeviceContext.DpiY; 
                } 

                return this.fontSize; 
            }
        }

        ///  
        ///     Attempts to match the TextRenderingHint of the specified Graphics object with a LOGFONT.lfQuality value.
        ///  
        public static WindowsFontQuality WindowsFontQualityFromTextRenderingHint(Graphics g) 
        {
            if (g == null) 
            {
                return WindowsFontQuality.Default;
            }
 
            switch (g.TextRenderingHint)
            { 
                case TextRenderingHint.ClearTypeGridFit: 
                    // See WindowsFontQuality enum for the flags supported in the different OS systems.
                    if (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1) 
                    {
                        return WindowsFontQuality.ClearTypeNatural;
                    }
                    else 
                    {
                        return WindowsFontQuality.ClearType; 
                    } 

                case TextRenderingHint.AntiAliasGridFit: 
                    return WindowsFontQuality.AntiAliased;

                case TextRenderingHint.AntiAlias:
                    return WindowsFontQuality.AntiAliased; 

                case TextRenderingHint.SingleBitPerPixelGridFit: 
                    return WindowsFontQuality.Proof; 

                case TextRenderingHint.SingleBitPerPixel: 
                    return WindowsFontQuality.Draft;

                default:
                case TextRenderingHint.SystemDefault: 
                    return WindowsFontQuality.Default;
 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

#if WINFORMS_NAMESPACE 
namespace System.Windows.Forms.Internal 
#elif DRAWING_NAMESPACE
namespace System.Drawing.Internal 
#else
namespace System.Experimental.Gdi
#endif
{ 
    using System;
    using System.Internal; 
    using System.Runtime.InteropServices; 
    using System.ComponentModel;
    using System.Diagnostics; 
    using System.Drawing;
    using System.Drawing.Text;
    using System.Security;
    using System.Security.Permissions; 
    using System.Globalization;
 
    ///  
    ///     
    ///         Encapsulates a GDI Font object. 
    ///     
    /// 
#if WINFORMS_PUBLIC_GRAPHICS_LIBRARY
    public 
#else
    internal 
#endif 
    sealed partial class WindowsFont : MarshalByRefObject, ICloneable, IDisposable
    { 
        const int LogFontNameOffset = 28;

        // Handle to the native Windows font object.
        // 
        private IntPtr hFont;
        private float  fontSize = -1.0f; //invalid value. 
        private int    lineSpacing; 
        private bool   ownHandle;
        private bool   ownedByCacheManager; 
        private bool   everOwnedByCacheManager;

        private IntNativeMethods.LOGFONT logFont;
        private FontStyle style; 

        // Note: These defaults are according to the ones in GDI+ but those are not necessarily the same as the system 
        // default font.  The GetSystemDefaultHFont() method should be used if needed. 
        private const string defaultFaceName   = "Microsoft Sans Serif";
        private const float  defaultFontSize   = 8.25f; 
        private const int    defaultFontHeight = 13;

#if GDI_FINALIZATION_WATCH
       private string AllocationSite = DbgUtil.StackTrace; 
#endif
 
        ///  
        ///     Creates the font handle.
        ///  
        private void CreateFont()
        {
            Debug.Assert( hFont == IntPtr.Zero, "hFont is not null, this will generate a handle leak." );
            Debug.Assert( this.logFont != null, "WindowsFont.logFont not initialized." ); 

            this.hFont = IntUnsafeNativeMethods.CreateFontIndirect(this.logFont); 
 
#if TRACK_HFONT
            Debug.WriteLine( DbgUtil.StackTraceToStr(String.Format( "HFONT[0x{0:x8}] = CreateFontIndirect( LOGFONT={1} )", (int) this.hFont, this.logFont))); 
#endif
            if (this.hFont == IntPtr.Zero)
            {
                this.logFont.lfFaceName     = defaultFaceName; 
                this.logFont.lfOutPrecision = IntNativeMethods.OUT_TT_ONLY_PRECIS; // True Type only.
 
                this.hFont = IntUnsafeNativeMethods.CreateFontIndirect(this.logFont); 

#if TRACK_HFONT 
            Debug.WriteLine( DbgUtil.StackTraceToStr(String.Format( "HFONT[0x{0:x8}] = CreateFontIndirect( LOGFONT={1} )", (int) this.hFont, this.logFont)));
#endif

            } 

            // Update logFont height and other adjusted parameters. 
            // 
            IntUnsafeNativeMethods.GetObject(new HandleRef(this, this.hFont), this.logFont);
 
            // We created the hFont, we will delete it on dispose.
            this.ownHandle = true;
        }
 
        /// Constructors.
 
        ///  
        ///     Contructor to construct font from a face name.
        /// > 
        public WindowsFont( string faceName ) :
            this(faceName, defaultFontSize, FontStyle.Regular, IntNativeMethods.DEFAULT_CHARSET, WindowsFontQuality.Default)
        {
         // Default size in WinForms is 8.25f. 
        }
 
        ///  
        ///     Contructor to construct font from a face name, a desired size and with the specified style.
        /// > 
        public WindowsFont( string faceName, float size ) :
            this(faceName, size, FontStyle.Regular, IntNativeMethods.DEFAULT_CHARSET, WindowsFontQuality.Default)
        {
        } 

        ///  
        ///     Contructor to construct font from a face name, a desired size and with the specified style. 
        /// >
        public WindowsFont( string faceName, float size, FontStyle style ) : 
            this(faceName, size, style, IntNativeMethods.DEFAULT_CHARSET, WindowsFontQuality.Default)
        {
        }
 
        /// 
        ///     Contructor to construct font from a face name, a desired size in points and with the specified style 
        ///     and character set. The screen dc is used for calculating the font em height. 
        /// >
        public WindowsFont( string faceName, float size, FontStyle style, byte charSet, WindowsFontQuality fontQuality ) 
        {
            Debug.Assert( size > 0.0f, "size has a negative value." );
            const byte True  = 1;
            const byte False = 0; 
            this.logFont = new IntNativeMethods.LOGFONT();
 
            // 
            // Get the font height from the specified size.  size is in point units and height in logical
            // units (pixels when using MM_TEXT) so we need to make the conversion using the number of 
            // pixels per logical inch along the screen height.
            //
            int pixelsY = (int) Math.Ceiling( WindowsGraphicsCacheManager.MeasurementGraphics.DeviceContext.DpiY * size / 72); // 1 point = 1/72 inch.;
 
            //
            // The lfHeight represents the font cell height (line spacing) which includes the internal 
            // leading; we specify a negative size value (in pixels) for the height so the font mapper 
            // provides the closest match for the character height rather than the cell height (MSDN).
            // 
            this.logFont.lfHeight       = -pixelsY;
            this.logFont.lfFaceName     = faceName != null ? faceName : defaultFaceName;
            this.logFont.lfCharSet      = charSet;
            this.logFont.lfOutPrecision = IntNativeMethods.OUT_TT_PRECIS; 
            this.logFont.lfQuality      = (byte) fontQuality;
            this.logFont.lfWeight       = (style & FontStyle.Bold)      == FontStyle.Bold      ? IntNativeMethods.FW_BOLD : IntNativeMethods.FW_NORMAL; 
            this.logFont.lfItalic       = (style & FontStyle.Italic)    == FontStyle.Italic    ? True : False; 
            this.logFont.lfUnderline    = (style & FontStyle.Underline) == FontStyle.Underline ? True : False;
            this.logFont.lfStrikeOut    = (style & FontStyle.Strikeout) == FontStyle.Strikeout ? True : False; 

            // Let the Size be recomputed to be consistent with the Height (there may be some precision loss coming from size to height).
            // this.fontSize = size;
            this.style    = style; 

            CreateFont(); 
        } 

        ///  
        ///     Contructor to construct font from a LOGFONT structure.
        ///     Pass false in the createHandle param to create a 'compatible' font (handle-less, to be used for measuring/comparing) or
        ///     when the handle has already been created.
        ///  
        private WindowsFont( IntNativeMethods.LOGFONT lf, bool createHandle )
        { 
            Debug.Assert( lf != null, "lf is null" ); 

            this.logFont = lf; 

            if (this.logFont.lfFaceName == null)
            {
                this.logFont.lfFaceName = defaultFaceName; 
            }
 
            this.style = FontStyle.Regular; 
            if (lf.lfWeight == IntNativeMethods.FW_BOLD)
            { 
                this.style |= FontStyle.Bold;
            }
            if (lf.lfItalic == 1)
            { 
                this.style |= FontStyle.Italic;
            } 
            if (lf.lfUnderline == 1) 
            {
                this.style |= FontStyle.Underline; 
            }
            if (lf.lfStrikeOut == 1)
            {
                this.style |= FontStyle.Strikeout; 
            }
 
            if( createHandle ) 
            {
                CreateFont(); 
            }
        }

        ///  
        ///     Contructs a WindowsFont object from an existing System.Drawing.Font object (GDI+), based on the screen dc MapMode
        ///     and resolution (normally: MM_TEXT and 96 dpi). 
        ///  
        public static WindowsFont FromFont(Font font)
        { 
            return FromFont(font, WindowsFontQuality.Default);
        }
        public static WindowsFont FromFont(Font font, WindowsFontQuality fontQuality)
        { 
            string familyName = font.FontFamily.Name;
 
            // Strip vertical-font mark from the name if needed. 
            if (familyName != null && familyName.Length > 1 && familyName[0] == '@')
            { 
                familyName = familyName.Substring(1);
            }

            // Note: Creating the WindowsFont from Font using a LOGFONT structure from GDI+ (Font.ToLogFont(logFont)) may sound like 
            // a better choice (more accurate) for doing this but tests show that is not the case (see WindowsFontTests test suite),
            // the results are the same.  Also, that approach has some issues when the Font is created in a different application 
            // domain since the LOGFONT cannot be marshalled properly, see VSW#451960. 
            // Now, creating it using the Font.SizeInPoints makes it GraphicsUnit-independent.
 
            return new WindowsFont(familyName, font.SizeInPoints, font.Style, font.GdiCharSet, fontQuality);
        }

 
        /// 
        ///     Creates a WindowsFont from the font selected in the supplied dc. 
        ///  
        public static WindowsFont FromHdc( IntPtr hdc )
        { 
            IntPtr hFont = IntUnsafeNativeMethods.GetCurrentObject(new HandleRef(null, hdc), IntNativeMethods.OBJ_FONT);

            // don't call DeleteObject on handle from GetCurrentObject, it is the one selected in the hdc.
 
            return FromHfont( hFont );
        } 
 
        /// 
        ///     Creates a WindowsFont from the handle to a native GDI font.  It does not take ownership of the 
        ///     passed-in handle, the caller needs to delete the hFont when done with the WindowsFont.
        /// 
        public static WindowsFont FromHfont( IntPtr hFont )
        { 
            return FromHfont( hFont, false );
        } 
 
        /// 
        ///     Creates a WindowsFont from the handle to a native GDI font and optionally takes ownership of managing 
        ///     the lifetime of the handle.
        /// 
        public static WindowsFont FromHfont( IntPtr hFont, bool takeOwnership )
        { 
            IntNativeMethods.LOGFONT lf = new IntNativeMethods.LOGFONT();
            IntUnsafeNativeMethods.GetObject(new HandleRef(null, hFont), lf); 
 
            WindowsFont wf = new WindowsFont( lf, /*createHandle*/ false );
            wf.hFont = hFont; 
            wf.ownHandle = takeOwnership; // if true, hFont will be deleted on dispose.

            return wf;
        } 

        ~WindowsFont() 
        { 
            Dispose(false);
        } 

        public void Dispose()
        {
            Dispose(true); 
        }
 
        internal void Dispose(bool disposing) 
        {
            bool deletedHandle = false; 
            if (this.ownHandle)
            {
                if (!ownedByCacheManager || !disposing) {
 
                    // If we were ever owned by the CacheManger and we're being disposed
                    // we can be sure that we're not in use by any DC's (otherwise Dispose() wouldn't have been called) 
                    // skip the check IsFontInUse check in this case. 
                    // Also skip the check if disposing == false, because the cache is thread-static
                    // and that means we're being called from the finalizer. 
                    if (everOwnedByCacheManager || !disposing || !DeviceContexts.IsFontInUse(this)) {
                        Debug.Assert( this.hFont != IntPtr.Zero, "Unexpected null hFont." );
                        DbgUtil.AssertFinalization(this, disposing);
 
                        IntUnsafeNativeMethods.DeleteObject(new HandleRef(this, this.hFont));
#if TRACK_HFONT 
                        Debug.WriteLine( DbgUtil.StackTraceToStr(String.Format( "DeleteObject(HFONT[0x{0:x8}]))", (int) this.hFont))); 
#endif
                        this.hFont = IntPtr.Zero; 
                        this.ownHandle = false;
                        deletedHandle = true;
                    }
                } 
            }
 
            if (disposing && (deletedHandle || !ownHandle)) 
            {
                GC.SuppressFinalize(this); 
            }
        }

        ///  
        ///    Returns a value indicating whether the specified object is a WindowsFont equivalent to this object.
        ///  
        public override bool Equals( object font ) 
        {
            WindowsFont winFont = font as WindowsFont; 

            if( winFont == null )
            {
                return false; 
            }
 
            if( winFont == this ) 
            {
                return true; 
            }

            // WARNING: don't use non-public fields/properties here, the passed-in font object could be a proxy in a
            //          remoting scenario and proxies cannot access internal or private members.  VSW#465265 & 465647 

            // Compare params used to create the font. 
            return  this.Name           == winFont.Name            && 
                    this.LogFontHeight  == winFont.LogFontHeight   && // Equivalent to comparing Size but always at hand.
                    this.Style          == winFont.Style           && 
                    this.CharSet        == winFont.CharSet         &&
                    this.Quality        == winFont.Quality;
        }
 
        /// 
        ///    Gets the hash code for this WindowsFont. 
        ///  
        public override int GetHashCode()
        { 
            // similar to Font.GetHashCode().
            return (int)((((UInt32)this.Style   << 13) | ((UInt32)this.Style   >> 19)) ^
                         (((UInt32)this.CharSet << 26) | ((UInt32)this.CharSet >>  6)) ^
                         (((UInt32)this.Size    <<  7) | ((UInt32)this.Size    >> 25))); 
        }
 
        ///  
        ///     Clones this object.
        ///  
        public object Clone()
        {
            return new WindowsFont( this.logFont, true );
        } 

        public override string ToString() 
        { 
            return string.Format(CultureInfo.CurrentCulture, "[{0}: Name={1}, Size={2} points, Height={3} pixels, Sytle={4}]", GetType().Name,  logFont.lfFaceName, this.Size, this.Height, this.Style);
        } 

        ////////////////////////////////////////////
        ///  Properties
 
        /// 
        ///       Returns this object's native Win32 font handle.  Should NOT be deleted externally. 
        ///       Compare with ToHfont method. 
        /// 
        public IntPtr Hfont 
        {
            get
            {
                //Assert removed. We need to be able to check for Hfont == IntPtr.Zero to determine if the object was disposed. 
                //Debug.Assert(this.hFont != IntPtr.Zero, "hFont is null, are you using a disposed object?");
                return this.hFont; 
            } 
        }
 
        /// 
        ///     Determines whether the font has the italic style or not.
        /// 
        public bool Italic 
        {
            get 
            { 
                return logFont.lfItalic == 1;
            } 
        }

        public bool OwnedByCacheManager
        { 
            get {
                return ownedByCacheManager; 
            } 
            set {
                if (value) { 
                    everOwnedByCacheManager = true;
                }
                ownedByCacheManager = value;
            } 
        }
 
        ///  
        ///     Rendering quality.
        ///  
        public WindowsFontQuality Quality
        {
            get
            { 
                return (WindowsFontQuality) this.logFont.lfQuality;
            } 
        } 

        ///  
        ///     Gets the font style.
        /// 
        public FontStyle Style
        { 
            get
            { 
                return this.style; 
            }
        } 

        /// 
        ///     Gets the line spacing (cell height) of this font in (screen) pixels using the screen resolution.
        ///     Gets the line spacing (cell height), in pixels (using the screen DC resolution), of this font. 
        ///     The line spacing is the vertical distance between the base lines of two consecutive lines of text.
        ///     Thus, the line spacing includes the blank space between lines along with the height of the character 
        ///     itself. 
        /// 
        public int Height 
        {
            //

            get 
            {
                if( this.lineSpacing == 0 ) 
                { 
                    // Observe that the font text metrics are obtained using the resolution of the screen.
                    WindowsGraphics wg  = WindowsGraphicsCacheManager.MeasurementGraphics; 

                    // No need to reset the font (if changed) since we always set the font before using the MeasurementGraphics
                    // in WindowsGraphics methods.
                    wg.DeviceContext.SelectFont(this); 

                    IntNativeMethods.TEXTMETRIC tm = (IntNativeMethods.TEXTMETRIC) wg.GetTextMetrics(); 
                    this.lineSpacing = tm.tmHeight; 
                }
 
                return this.lineSpacing;
            }
        }
 
        /// 
        ///     Gets the font character set. 
        ///     This is used by the system font mapper when searching for the physical font that best matches the logical font. 
        /// 
        public byte CharSet 
        {
            get
            {
                return logFont.lfCharSet; 
            }
        } 
 
        /// 
        ///     Specifies the height, in logical units, of the font's character cell or character. The character height value (em height) 
        ///     is the character cell height value minus the internal-leading value.
        /// 
        public int LogFontHeight
        { 
            get
            { 
                return logFont.lfHeight; 
            }
        } 

        /// 
        ///     The font's face name.
        ///  
        public string Name
        { 
            get 
            {
                return logFont.lfFaceName; 
            }
        }

        ///  
        ///     Gets the character height (as opposed to the cell height) of the font represented by this object in points.
        ///     Consider 
        ///  
        public float Size
        { 
            get
            {
                if( this.fontSize < 0.0f )
                { 
                    WindowsGraphics wg  = WindowsGraphicsCacheManager.MeasurementGraphics;
 
                    // No need to reset the font (if changed) since we always set the font before using the MeasurementGraphics 
                    // in WindowsGraphics methods.
                    wg.DeviceContext.SelectFont(this); 

                    IntNativeMethods.TEXTMETRIC tm = (IntNativeMethods.TEXTMETRIC) wg.GetTextMetrics();

                    // 
                    // Convert the font character height to points.  If lfHeight is negative, Windows
                    // treats the absolute value of that number as a desired font height compatible with 
                    // the point size; in this case lfHeight will roughly match the tmHeight field of 
                    // the TEXTMETRIC structure less the tmInternalLeading field.
                    // 
                    int height = this.logFont.lfHeight > 0 ? tm.tmHeight : (tm.tmHeight - tm.tmInternalLeading);

                    //
                    /* 
                    switch (this.unit)
                    { 
                        case GraphicsUnit.Pixel:       worldEmSize = height * dpi / 72.0f;   break; 
                        case GraphicsUnit.Point:       worldEmSize = height * dpi / 72.0f;   break;
                        case GraphicsUnit.Inch:        worldEmSize = height * dpi;           break; 
                        case GraphicsUnit.Document:    worldEmSize = height * dpi / 300.0f;  break;
                        case GraphicsUnit.Millimeter:  worldEmSize = height * dpi / 25.4f;   break;
                    }
                    */ 

                    this.fontSize = height * 72f / wg.DeviceContext.DpiY; 
                } 

                return this.fontSize; 
            }
        }

        ///  
        ///     Attempts to match the TextRenderingHint of the specified Graphics object with a LOGFONT.lfQuality value.
        ///  
        public static WindowsFontQuality WindowsFontQualityFromTextRenderingHint(Graphics g) 
        {
            if (g == null) 
            {
                return WindowsFontQuality.Default;
            }
 
            switch (g.TextRenderingHint)
            { 
                case TextRenderingHint.ClearTypeGridFit: 
                    // See WindowsFontQuality enum for the flags supported in the different OS systems.
                    if (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1) 
                    {
                        return WindowsFontQuality.ClearTypeNatural;
                    }
                    else 
                    {
                        return WindowsFontQuality.ClearType; 
                    } 

                case TextRenderingHint.AntiAliasGridFit: 
                    return WindowsFontQuality.AntiAliased;

                case TextRenderingHint.AntiAlias:
                    return WindowsFontQuality.AntiAliased; 

                case TextRenderingHint.SingleBitPerPixelGridFit: 
                    return WindowsFontQuality.Proof; 

                case TextRenderingHint.SingleBitPerPixel: 
                    return WindowsFontQuality.Draft;

                default:
                case TextRenderingHint.SystemDefault: 
                    return WindowsFontQuality.Default;
 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK