Typeface.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Media / Typeface.cs / 1305600 / Typeface.cs

                            //------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation
// 
//  File:      Typeface.cs
// 
//  Contents:  Typeface 
//
//  Created:   5-25-2003 Worachai Chaoweeraprasit (wchao) 
//
//-----------------------------------------------------------------------

using System; 
using System.Globalization;
using System.Security.Permissions; 
using System.Collections; 
using System.Collections.Generic;
using System.Diagnostics; 
using System.Security;
using System.Windows;
using System.Windows.Media.TextFormatting;
using System.Runtime.InteropServices; 
using System.ComponentModel;
 
using MS.Internal; 
using MS.Internal.FontFace;
using MS.Internal.FontCache; 
using MS.Internal.Shaping;
using MS.Internal.TextFormatting;

 
namespace System.Windows.Media
{ 
    ///  
    /// A Typeface is a combination of family, weight, style and stretch:
    ///  
    public class Typeface
    {
        private FontFamily              _fontFamily;
 
        // these _style, _weight and _stretch are only used for storing what was passed into the constructor.
        // Since FontFamily may change these values when it includes a style name implicitly, 
        private FontStyle               _style; 
        private FontWeight              _weight;
        private FontStretch             _stretch; 

        private FontFamily              _fallbackFontFamily;

        // Cached canonical values of the typeface. 
        private CachedTypeface         _cachedTypeface;
 
 
        /// 
        /// Construct a typeface 
        /// 
        /// font typeface name
        public Typeface(
            string typefaceName 
            )
            // assume face name is family name until we get face name resolved properly. 
            : this( 
                new FontFamily(typefaceName),
                FontStyles.Normal, 
                FontWeights.Normal,
                FontStretches.Normal
                )
        {} 

 
 
        /// 
        /// Construct a typeface 
        /// 
        /// Font family
        /// Font style
        /// Boldness of font 
        /// Width of characters
        public Typeface( 
            FontFamily      fontFamily, 
            FontStyle       style,
            FontWeight      weight, 
            FontStretch     stretch
            )
            : this(
                fontFamily, 
                style,
                weight, 
                stretch, 
                FontFamily.FontFamilyGlobalUI
                ) 
        {}


 
        /// 
        /// Construct a typeface 
        ///  
        /// Font family
        /// Font style 
        /// Boldness of font
        /// Width of characters
        /// fallback font family
        public Typeface( 
            FontFamily      fontFamily,
            FontStyle       style, 
            FontWeight      weight, 
            FontStretch     stretch,
            FontFamily      fallbackFontFamily 
            )
        {
            if(fontFamily == null)
            { 
                throw new ArgumentNullException("fontFamily");
            } 
 
            _fontFamily = fontFamily;
            _style = style; 
            _weight = weight;
            _stretch = stretch;
            _fallbackFontFamily = fallbackFontFamily;
        } 

 
 
        /// 
        /// Font family 
        /// 
        public FontFamily FontFamily
        {
            get { return _fontFamily; } 
        }
 
 
        /// 
        /// Font weight (light, bold, etc.) 
        /// 
        public FontWeight Weight
        {
            get { return _weight; } 
        }
 
 
        /// 
        /// Font style (italic, oblique) 
        /// 
        public FontStyle Style
        {
            get { return _style; } 
        }
 
 
        /// 
        /// Font Stretch (narrow, wide, etc.) 
        /// 
        public FontStretch Stretch
        {
            get { return _stretch; } 
        }
 
        ///  
        /// Returns true if FontStyle.Oblique is algorithmically simulated by
        /// slanting glyphs. Returns false otherwise. 
        /// 
        public bool IsObliqueSimulated
        {
            get 
            {
                return (CachedTypeface.TypefaceMetrics.StyleSimulations & StyleSimulations.ItalicSimulation) != 0; 
            } 
        }
 
        /// 
        /// Returns true if FontStyle.Bold is algorithmically simulated by
        /// thickening glyphs. Returns false otherwise.
        ///  
        public bool IsBoldSimulated
        { 
            get 
            {
                return (CachedTypeface.TypefaceMetrics.StyleSimulations & StyleSimulations.BoldSimulation) != 0; 
            }
        }

        ///  
        /// Obtain a glyph typeface that corresponds to the Typeface object constructed from an OpenType font family.
        /// If the Typeface was constructed from a composite font family, returns null. 
        ///  
        /// GlyphTypeface object that corresponds to this Typeface, or null if the Typeface
        /// was constructed from a composite font. 
        /// Whether glyphTypeface is not null.
        public bool TryGetGlyphTypeface(out GlyphTypeface glyphTypeface)
        {
            glyphTypeface = CachedTypeface.TypefaceMetrics as GlyphTypeface; 
            return glyphTypeface != null;
        } 
 

        ///  
        /// Fallback font family
        /// 
        internal FontFamily FallbackFontFamily
        { 
            get { return _fallbackFontFamily; }
        } 
 
        /// 
        /// (Western) x-height relative to em size. 
        /// 
        public double XHeight
        {
            get 
            {
                return CachedTypeface.TypefaceMetrics.XHeight; 
            } 
        }
 

        /// 
        /// Distance from baseline to top of English ----, relative to em size.
        ///  
        public double CapsHeight
        { 
            get 
            {
                return CachedTypeface.TypefaceMetrics.CapsHeight; 
            }
        }

 
        /// 
        /// Distance from baseline to underline position 
        ///  
        public double UnderlinePosition
        { 
            get
            {
                return CachedTypeface.TypefaceMetrics.UnderlinePosition;
            } 
        }
 
 
        /// 
        /// Underline thickness 
        /// 
        public double UnderlineThickness
        {
            get 
            {
                return CachedTypeface.TypefaceMetrics.UnderlineThickness; 
            } 
        }
 

        /// 
        /// Distance from baseline to strike-through position
        ///  
        public double StrikethroughPosition
        { 
            get 
            {
                return CachedTypeface.TypefaceMetrics.StrikethroughPosition; 
            }
        }

 
        /// 
        /// strike-through thickness 
        ///  
        public double StrikethroughThickness
        { 
            get
            {
                return CachedTypeface.TypefaceMetrics.StrikethroughThickness;
            } 
        }
 
        ///  
        /// Collection of culture-dependant face names.
        ///  
        public LanguageSpecificStringDictionary FaceNames
        {
            get
            { 
                return new LanguageSpecificStringDictionary(CachedTypeface.TypefaceMetrics.AdjustedFaceNames);
            } 
        } 

        internal double Baseline(double emSize, double toReal, double pixelsPerDip, TextFormattingMode textFormattingMode) 
        {
            return CachedTypeface.FirstFontFamily.Baseline(emSize, toReal, pixelsPerDip, textFormattingMode);
        }
 
        internal double LineSpacing(double emSize, double toReal, double pixelsPerDip, TextFormattingMode textFormattingMode)
        { 
            return CachedTypeface.FirstFontFamily.LineSpacing(emSize, toReal, pixelsPerDip, textFormattingMode); 
        }
 
        /// 
        /// Flag indicating if the typeface is of symbol type
        /// 
        internal bool Symbol 
        {
            get 
            { 
                return CachedTypeface.TypefaceMetrics.Symbol;
            } 
        }

        internal bool NullFont
        { 
            get
            { 
                return CachedTypeface.NullFont; 
            }
        } 

        // Tries to get a GlyphTypeface based on the Typeface properties. The
        // return value can be null. However, if CheckFastPathNominalGlyphs
        // returns true, then one can expect this function to return a valid 
        // GlyphTypeface that maps all the specified text.
        internal GlyphTypeface TryGetGlyphTypeface() 
        { 
            return CachedTypeface.TypefaceMetrics as GlyphTypeface;
        } 

        internal FontStyle CanonicalStyle
        {
            get 
            {
                return CachedTypeface.CanonicalStyle; 
            } 
        }
 
        internal FontWeight CanonicalWeight
        {
            get
            { 
                return CachedTypeface.CanonicalWeight;
            } 
        } 

        internal FontStretch CanonicalStretch 
        {
            get
            {
                return CachedTypeface.CanonicalStretch; 
            }
        } 
 

        ///  
        /// Scan through specified character string checking for valid character
        /// nominal glyph.
        /// 
        /// character buffer range 
        /// height of Em
        /// This is the factor by which we will scale up 
        /// the metrics. Typically this value to used to convert metrics from the real 
        /// space to the ideal space
        /// maximum width allowed 
        /// do not stop arbitrarily in the middle of a word
        /// digits require complex shaping
        /// CultureInfo of the text
        /// number of character fit in given width 
        /// whether the specified string can be optimized by nominal glyph lookup
        internal bool CheckFastPathNominalGlyphs( 
            CharacterBufferRange    charBufferRange, 
            double                  emSize,
            double                  scalingFactor, 
            double                  widthMax,
            bool                    keepAWord,
            bool                    numberSubstitution,
            CultureInfo             cultureInfo, 
            TextFormattingMode      textFormattingMode,
            bool                    isSideways, 
            out int                 stringLengthFit 
            )
        { 
            stringLengthFit = 0;

            if (CachedTypeface.NullFont) return false;
 
            GlyphTypeface glyphTypeface = TryGetGlyphTypeface();
 
            if (glyphTypeface == null) return false; 

            double totalWidth = 0; 
            int i = 0;

            ushort blankGlyph = glyphTypeface.BlankGlyphIndex;
            ushort glyph = blankGlyph; 

            ushort charFlagsMask = numberSubstitution ? 
                (ushort)(CharacterAttributeFlags.CharacterComplex | CharacterAttributeFlags.CharacterDigit) : 
                (ushort)CharacterAttributeFlags.CharacterComplex;
            ushort charFlags = 0; 
            ushort charFastTextCheck = (ushort)(CharacterAttributeFlags.CharacterFastText | CharacterAttributeFlags.CharacterIdeo);

            bool symbolTypeface = glyphTypeface.Symbol;
            if (symbolTypeface) 
            {
                // we don't care what code points are present if it's a non-Unicode font such as Symbol or Wingdings; 
                // the code points don't have any standardized meanings, and we always want to bypass shaping 
                charFlagsMask = 0;
            } 

            bool ignoreWidths = widthMax == double.MaxValue;
            ushort[] glyphIndices = BufferCache.GetUShorts(charBufferRange.Length);
            MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = ignoreWidths ? null : BufferCache.GetGlyphMetrics(charBufferRange.Length); 

            glyphTypeface.GetGlyphMetricsOptimized(charBufferRange, 
                                                   emSize, 
                                                   glyphIndices,
                                                   glyphMetrics, 
                                                   textFormattingMode,
                                                   isSideways
                                                   );
 
            double designToEm = emSize / glyphTypeface.DesignEmHeight;
 
            // 
            // This block will advance until one of:
            // 1. The end of the charBufferRange is reached 
            // 2. The charFlags have some of the charFlagsMask values
            // 3. The glyph is BlankGlyph (space)
            // 4. Glyph index is 0 (unless symbol font)
            // 
            // At this point totalWidth includes all of the widths including the stop character (which fits above)
            // i indexes the next character (not included in the width) 
            // 
            if(keepAWord)
            { 
                do
                {
                    char ch = charBufferRange[i++];
                    if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn) 
                    {
                        --i; 
                        break; 
                    }
                    else 
                    {
                        int charClass = (int)Classification.GetUnicodeClassUTF16(ch);
                        charFlags = Classification.CharAttributeOf(charClass).Flags;
                        charFastTextCheck &= charFlags; 

                        glyph = glyphIndices[i-1]; 
                        if (!ignoreWidths) 
                        {
                            totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor; 
                        }
                    }
                } while(
                        i < charBufferRange.Length 
                    &&  ((charFlags & charFlagsMask) == 0)
                    &&  (glyph != 0 || symbolTypeface) 
                    &&  glyph != blankGlyph 
                    );
 
                // i is now at a character immediately following a leading blank
            }

            // 
            // This block will advance until one of:
            // 1. The end of the charBufferRange is reached 
            // 2. The charFlags have some of the charFlagsMask values 
            // 3. Glyph index is 0 (unless symbol font)
            // 4. totalWidth > widthMax 
            //

            while(
                    i < charBufferRange.Length 
                &&  (ignoreWidths || totalWidth <= widthMax)
                &&  ((charFlags & charFlagsMask) == 0) 
                &&  (glyph != 0 || symbolTypeface) 
                )
            { 
                char ch = charBufferRange[i++];
                if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn)
                {
                    --i; 
                    break;
                } 
                else 
                {
                    int charClass = (int)Classification.GetUnicodeClassUTF16(ch); 
                    charFlags = Classification.CharAttributeOf(charClass).Flags;
                    charFastTextCheck &= charFlags;

                    glyph = glyphIndices[i-1]; 
                    if (!ignoreWidths)
                    { 
                        totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor; 
                    }
                } 
            }

            BufferCache.ReleaseUShorts(glyphIndices);
            glyphIndices = null; 
            BufferCache.ReleaseGlyphMetrics(glyphMetrics);
            glyphMetrics = null; 
 
            if (symbolTypeface)
            { 
                // always optimize for non-Unicode font as we don't support shaping or typographic features;
                // we also don't fall back from non-Unicode fonts so we don't care if there are missing glyphs
                stringLengthFit = i;
                return true; 
            }
 
            if (glyph == 0) 
            {
                // character is not supported by the font 
                return false;
            }

            if ((charFlags & charFlagsMask) != 0) 
            {
                // complex character encountered, exclude it 
                Debug.Assert(i > 0); 

                if(--i <= 0) 
                {
                    // first char is complex, fail the call
                    return false;
                } 
            }
 
            stringLengthFit = i; 
            TypographyAvailabilities typography = glyphTypeface.FontFaceLayoutInfo.TypographyAvailabilities;
 
            if ((charFastTextCheck & (byte) CharacterAttributeFlags.CharacterFastText) != 0)
            {
                // all input code points are Fast Text
                if ((typography & 
                         (  TypographyAvailabilities.FastTextTypographyAvailable
                          | TypographyAvailabilities.FastTextMajorLanguageLocalizedFormAvailable 
                         ) 
                     ) != 0
                   ) 
                {
                    // Considered too risky to optimize. It is either because the font
                    // has required features or the font has 'locl' lookup for major languages.
                    return false; 
                }
                else if ((typography & TypographyAvailabilities.FastTextExtraLanguageLocalizedFormAvailable) != 0) 
                { 
                    // The font has 'locl' lookup for FastText code points for non major languages.
                    // Check whether the input is major langauge. If it is, we are still good to optimize. 
                    return MajorLanguages.Contains(cultureInfo);
                }
                else
                { 
                    // No FastText flags are present, safe to optimize
                    return true; 
                } 
            }
            else if ((charFastTextCheck & (byte) CharacterAttributeFlags.CharacterIdeo) != 0) 
            {
                // The input are all ideographs, check the IdeoTypographyAvailable bit. It is safe if
                // the bit is not set.
                return ((typography & TypographyAvailabilities.IdeoTypographyAvailable) == 0); 
            }
            else 
            { 
                // for all the rest of the cases, just check whether there is any required typography
                // present at all. If none exists, it is optimizable. We might under-optimize here but 
                // it will be non-major languages.
                return ((typography & TypographyAvailabilities.Available) == 0);
            }
        } 

 
        ///  
        /// Lookup characters nominal glyphs and width
        ///  
        /// character buffer range
        /// height of Em
        ///  scaling factor from real to ideal unit 
        /// glyph nominal advances in ideal units 
        /// total width in ideal units
        /// true for success 
        /// This function is only used in fast path, and can only be called 
        /// if CheckFastPathNominalGlyphs has previously returned true.
        internal void GetCharacterNominalWidthsAndIdealWidth( 
            CharacterBufferRange charBufferRange,
            double               emSize,
            double               toIdeal,
            TextFormattingMode   textFormattingMode, 
            bool                 isSideways,
            out int[]            nominalWidths, 
            out int              idealWidth 
            )
        { 
            // This function should only be called if CheckFastPathNominalGlyphs has
            // returned true so we can assume the ITypefaceMetrics is a GlyphTypeface.
            GlyphTypeface glyphTypeface = TryGetGlyphTypeface();
            Invariant.Assert(glyphTypeface != null); 

            MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = BufferCache.GetGlyphMetrics(charBufferRange.Length); 
 
            glyphTypeface.GetGlyphMetricsOptimized(charBufferRange,
                                                   emSize, 
                                                   textFormattingMode,
                                                   isSideways,
                                                   glyphMetrics);
 
            nominalWidths = new int[charBufferRange.Length];
            idealWidth = 0; 
 
            if (TextFormattingMode.Display == textFormattingMode)
            { 
                double designToEm = emSize / glyphTypeface.DesignEmHeight;
                for (int i = 0; i < charBufferRange.Length; i++)
                {
                    nominalWidths[i] = (int)Math.Round(TextFormatterImp.RoundDipForDisplayMode(glyphMetrics[i].AdvanceWidth * designToEm) * toIdeal); 
                    idealWidth += nominalWidths[i];
                } 
            } 
            else
            { 
                double designToEm = emSize * toIdeal / glyphTypeface.DesignEmHeight;
                for (int i = 0; i < charBufferRange.Length; i++)
                {
                    nominalWidths[i] = (int)Math.Round(glyphMetrics[i].AdvanceWidth * designToEm); 
                    idealWidth += nominalWidths[i];
                } 
            } 

            BufferCache.ReleaseGlyphMetrics(glyphMetrics); 
        }

        /// 
        /// Create correspondent hash code for the object 
        /// 
        /// object hash code 
        public override int GetHashCode() 
        {
            int hash = _fontFamily.GetHashCode(); 

            if (_fallbackFontFamily != null)
                hash = HashFn.HashMultiply(hash) + _fallbackFontFamily.GetHashCode();
 
            hash = HashFn.HashMultiply(hash) + _style.GetHashCode();
            hash = HashFn.HashMultiply(hash) + _weight.GetHashCode(); 
            hash = HashFn.HashMultiply(hash) + _stretch.GetHashCode(); 
            return HashFn.HashScramble(hash);
        } 



        ///  
        /// Equality check
        ///  
        public override bool Equals(object o) 
        {
            Typeface t = o as Typeface; 
            if(t == null)
                return false;

            return  _style == t._style 
                &&  _weight == t._weight
                &&  _stretch == t._stretch 
                &&  _fontFamily.Equals(t._fontFamily) 
                &&  CompareFallbackFontFamily(t._fallbackFontFamily);
        } 


        internal bool CompareFallbackFontFamily(FontFamily fallbackFontFamily)
        { 
            if (fallbackFontFamily == null || _fallbackFontFamily == null)
                return fallbackFontFamily == _fallbackFontFamily; 
 
            return _fallbackFontFamily.Equals(fallbackFontFamily);
        } 

        //----------------------------------------
        // Private method
        //---------------------------------------- 
        private CachedTypeface CachedTypeface
        { 
            get 
            {
                if (_cachedTypeface == null) 
                {
                    CachedTypeface cachedTypeface = TypefaceMetricsCache.ReadonlyLookup(this) as CachedTypeface;

                    if (cachedTypeface == null) 
                    {
                       cachedTypeface = ConstructCachedTypeface(); 
                       TypefaceMetricsCache.Add(this, cachedTypeface); 
                    }
 
                    // For thread-safety, set the _cachedTypeface field only after we have a fully
                    // initialized CachedTypeface object.
                    _cachedTypeface = cachedTypeface;
                } 

                return _cachedTypeface; 
            } 
        }
 
        private CachedTypeface ConstructCachedTypeface()
        {
            FontStyle canonicalStyle     = _style;
            FontWeight canonicalWeight   = _weight; 
            FontStretch canonicalStretch = _stretch;
 
            // 
            // We always call FontFamily.FindFirstFontFamilyAndFace() method to resolve the
            // canonical styles since the implied styles in FontFamily name will override 
            // the given styles in the Typeface. But we don't always use the IFontFamily
            // instance returned from this method because an equal instance might already be
            // cached.
            // 
            FontFamily sourceFontFamily = FontFamily;
 
            IFontFamily firstFontFamily = sourceFontFamily.FindFirstFontFamilyAndFace( 
                ref canonicalStyle,
                ref canonicalWeight, 
                ref canonicalStretch
                );

            if (firstFontFamily == null) 
            {
                if (FallbackFontFamily != null) 
                { 
                    sourceFontFamily = FallbackFontFamily;
                    firstFontFamily = sourceFontFamily.FindFirstFontFamilyAndFace( 
                        ref canonicalStyle,
                        ref canonicalWeight,
                        ref canonicalStretch
                        ); 
                }
 
                if (firstFontFamily == null) 
                {
                    sourceFontFamily = null; 
                    firstFontFamily = FontFamily.LookupFontFamily(FontFamily.NullFontFamilyCanonicalName);
                }
            }
 
            // If it's a named font, map all occurrences of the same name to one cached IFontFamily.
            if (sourceFontFamily != null && sourceFontFamily.Source != null) 
            { 
                // We lookup in the cache to see if there is cached IFontFamily instance of the source FontFamily. Otherwise,
                // this IFontFamily value is added to the TypefaceMetrics cache. 
                IFontFamily cachedValue = TypefaceMetricsCache.ReadonlyLookup(sourceFontFamily.FamilyIdentifier) as IFontFamily;

                if (cachedValue != null)
                { 
                    firstFontFamily = cachedValue;
                } 
                else 
                {
                    TypefaceMetricsCache.Add(sourceFontFamily.FamilyIdentifier, firstFontFamily); 
                }
            }

            ITypefaceMetrics typefaceMetrics = firstFontFamily.GetTypefaceMetrics(canonicalStyle, canonicalWeight, canonicalStretch); 

            return new CachedTypeface( 
                canonicalStyle, 
                canonicalWeight,
                canonicalStretch, 
                firstFontFamily,
                typefaceMetrics,
                sourceFontFamily == null
                ); 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation
// 
//  File:      Typeface.cs
// 
//  Contents:  Typeface 
//
//  Created:   5-25-2003 Worachai Chaoweeraprasit (wchao) 
//
//-----------------------------------------------------------------------

using System; 
using System.Globalization;
using System.Security.Permissions; 
using System.Collections; 
using System.Collections.Generic;
using System.Diagnostics; 
using System.Security;
using System.Windows;
using System.Windows.Media.TextFormatting;
using System.Runtime.InteropServices; 
using System.ComponentModel;
 
using MS.Internal; 
using MS.Internal.FontFace;
using MS.Internal.FontCache; 
using MS.Internal.Shaping;
using MS.Internal.TextFormatting;

 
namespace System.Windows.Media
{ 
    ///  
    /// A Typeface is a combination of family, weight, style and stretch:
    ///  
    public class Typeface
    {
        private FontFamily              _fontFamily;
 
        // these _style, _weight and _stretch are only used for storing what was passed into the constructor.
        // Since FontFamily may change these values when it includes a style name implicitly, 
        private FontStyle               _style; 
        private FontWeight              _weight;
        private FontStretch             _stretch; 

        private FontFamily              _fallbackFontFamily;

        // Cached canonical values of the typeface. 
        private CachedTypeface         _cachedTypeface;
 
 
        /// 
        /// Construct a typeface 
        /// 
        /// font typeface name
        public Typeface(
            string typefaceName 
            )
            // assume face name is family name until we get face name resolved properly. 
            : this( 
                new FontFamily(typefaceName),
                FontStyles.Normal, 
                FontWeights.Normal,
                FontStretches.Normal
                )
        {} 

 
 
        /// 
        /// Construct a typeface 
        /// 
        /// Font family
        /// Font style
        /// Boldness of font 
        /// Width of characters
        public Typeface( 
            FontFamily      fontFamily, 
            FontStyle       style,
            FontWeight      weight, 
            FontStretch     stretch
            )
            : this(
                fontFamily, 
                style,
                weight, 
                stretch, 
                FontFamily.FontFamilyGlobalUI
                ) 
        {}


 
        /// 
        /// Construct a typeface 
        ///  
        /// Font family
        /// Font style 
        /// Boldness of font
        /// Width of characters
        /// fallback font family
        public Typeface( 
            FontFamily      fontFamily,
            FontStyle       style, 
            FontWeight      weight, 
            FontStretch     stretch,
            FontFamily      fallbackFontFamily 
            )
        {
            if(fontFamily == null)
            { 
                throw new ArgumentNullException("fontFamily");
            } 
 
            _fontFamily = fontFamily;
            _style = style; 
            _weight = weight;
            _stretch = stretch;
            _fallbackFontFamily = fallbackFontFamily;
        } 

 
 
        /// 
        /// Font family 
        /// 
        public FontFamily FontFamily
        {
            get { return _fontFamily; } 
        }
 
 
        /// 
        /// Font weight (light, bold, etc.) 
        /// 
        public FontWeight Weight
        {
            get { return _weight; } 
        }
 
 
        /// 
        /// Font style (italic, oblique) 
        /// 
        public FontStyle Style
        {
            get { return _style; } 
        }
 
 
        /// 
        /// Font Stretch (narrow, wide, etc.) 
        /// 
        public FontStretch Stretch
        {
            get { return _stretch; } 
        }
 
        ///  
        /// Returns true if FontStyle.Oblique is algorithmically simulated by
        /// slanting glyphs. Returns false otherwise. 
        /// 
        public bool IsObliqueSimulated
        {
            get 
            {
                return (CachedTypeface.TypefaceMetrics.StyleSimulations & StyleSimulations.ItalicSimulation) != 0; 
            } 
        }
 
        /// 
        /// Returns true if FontStyle.Bold is algorithmically simulated by
        /// thickening glyphs. Returns false otherwise.
        ///  
        public bool IsBoldSimulated
        { 
            get 
            {
                return (CachedTypeface.TypefaceMetrics.StyleSimulations & StyleSimulations.BoldSimulation) != 0; 
            }
        }

        ///  
        /// Obtain a glyph typeface that corresponds to the Typeface object constructed from an OpenType font family.
        /// If the Typeface was constructed from a composite font family, returns null. 
        ///  
        /// GlyphTypeface object that corresponds to this Typeface, or null if the Typeface
        /// was constructed from a composite font. 
        /// Whether glyphTypeface is not null.
        public bool TryGetGlyphTypeface(out GlyphTypeface glyphTypeface)
        {
            glyphTypeface = CachedTypeface.TypefaceMetrics as GlyphTypeface; 
            return glyphTypeface != null;
        } 
 

        ///  
        /// Fallback font family
        /// 
        internal FontFamily FallbackFontFamily
        { 
            get { return _fallbackFontFamily; }
        } 
 
        /// 
        /// (Western) x-height relative to em size. 
        /// 
        public double XHeight
        {
            get 
            {
                return CachedTypeface.TypefaceMetrics.XHeight; 
            } 
        }
 

        /// 
        /// Distance from baseline to top of English ----, relative to em size.
        ///  
        public double CapsHeight
        { 
            get 
            {
                return CachedTypeface.TypefaceMetrics.CapsHeight; 
            }
        }

 
        /// 
        /// Distance from baseline to underline position 
        ///  
        public double UnderlinePosition
        { 
            get
            {
                return CachedTypeface.TypefaceMetrics.UnderlinePosition;
            } 
        }
 
 
        /// 
        /// Underline thickness 
        /// 
        public double UnderlineThickness
        {
            get 
            {
                return CachedTypeface.TypefaceMetrics.UnderlineThickness; 
            } 
        }
 

        /// 
        /// Distance from baseline to strike-through position
        ///  
        public double StrikethroughPosition
        { 
            get 
            {
                return CachedTypeface.TypefaceMetrics.StrikethroughPosition; 
            }
        }

 
        /// 
        /// strike-through thickness 
        ///  
        public double StrikethroughThickness
        { 
            get
            {
                return CachedTypeface.TypefaceMetrics.StrikethroughThickness;
            } 
        }
 
        ///  
        /// Collection of culture-dependant face names.
        ///  
        public LanguageSpecificStringDictionary FaceNames
        {
            get
            { 
                return new LanguageSpecificStringDictionary(CachedTypeface.TypefaceMetrics.AdjustedFaceNames);
            } 
        } 

        internal double Baseline(double emSize, double toReal, double pixelsPerDip, TextFormattingMode textFormattingMode) 
        {
            return CachedTypeface.FirstFontFamily.Baseline(emSize, toReal, pixelsPerDip, textFormattingMode);
        }
 
        internal double LineSpacing(double emSize, double toReal, double pixelsPerDip, TextFormattingMode textFormattingMode)
        { 
            return CachedTypeface.FirstFontFamily.LineSpacing(emSize, toReal, pixelsPerDip, textFormattingMode); 
        }
 
        /// 
        /// Flag indicating if the typeface is of symbol type
        /// 
        internal bool Symbol 
        {
            get 
            { 
                return CachedTypeface.TypefaceMetrics.Symbol;
            } 
        }

        internal bool NullFont
        { 
            get
            { 
                return CachedTypeface.NullFont; 
            }
        } 

        // Tries to get a GlyphTypeface based on the Typeface properties. The
        // return value can be null. However, if CheckFastPathNominalGlyphs
        // returns true, then one can expect this function to return a valid 
        // GlyphTypeface that maps all the specified text.
        internal GlyphTypeface TryGetGlyphTypeface() 
        { 
            return CachedTypeface.TypefaceMetrics as GlyphTypeface;
        } 

        internal FontStyle CanonicalStyle
        {
            get 
            {
                return CachedTypeface.CanonicalStyle; 
            } 
        }
 
        internal FontWeight CanonicalWeight
        {
            get
            { 
                return CachedTypeface.CanonicalWeight;
            } 
        } 

        internal FontStretch CanonicalStretch 
        {
            get
            {
                return CachedTypeface.CanonicalStretch; 
            }
        } 
 

        ///  
        /// Scan through specified character string checking for valid character
        /// nominal glyph.
        /// 
        /// character buffer range 
        /// height of Em
        /// This is the factor by which we will scale up 
        /// the metrics. Typically this value to used to convert metrics from the real 
        /// space to the ideal space
        /// maximum width allowed 
        /// do not stop arbitrarily in the middle of a word
        /// digits require complex shaping
        /// CultureInfo of the text
        /// number of character fit in given width 
        /// whether the specified string can be optimized by nominal glyph lookup
        internal bool CheckFastPathNominalGlyphs( 
            CharacterBufferRange    charBufferRange, 
            double                  emSize,
            double                  scalingFactor, 
            double                  widthMax,
            bool                    keepAWord,
            bool                    numberSubstitution,
            CultureInfo             cultureInfo, 
            TextFormattingMode      textFormattingMode,
            bool                    isSideways, 
            out int                 stringLengthFit 
            )
        { 
            stringLengthFit = 0;

            if (CachedTypeface.NullFont) return false;
 
            GlyphTypeface glyphTypeface = TryGetGlyphTypeface();
 
            if (glyphTypeface == null) return false; 

            double totalWidth = 0; 
            int i = 0;

            ushort blankGlyph = glyphTypeface.BlankGlyphIndex;
            ushort glyph = blankGlyph; 

            ushort charFlagsMask = numberSubstitution ? 
                (ushort)(CharacterAttributeFlags.CharacterComplex | CharacterAttributeFlags.CharacterDigit) : 
                (ushort)CharacterAttributeFlags.CharacterComplex;
            ushort charFlags = 0; 
            ushort charFastTextCheck = (ushort)(CharacterAttributeFlags.CharacterFastText | CharacterAttributeFlags.CharacterIdeo);

            bool symbolTypeface = glyphTypeface.Symbol;
            if (symbolTypeface) 
            {
                // we don't care what code points are present if it's a non-Unicode font such as Symbol or Wingdings; 
                // the code points don't have any standardized meanings, and we always want to bypass shaping 
                charFlagsMask = 0;
            } 

            bool ignoreWidths = widthMax == double.MaxValue;
            ushort[] glyphIndices = BufferCache.GetUShorts(charBufferRange.Length);
            MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = ignoreWidths ? null : BufferCache.GetGlyphMetrics(charBufferRange.Length); 

            glyphTypeface.GetGlyphMetricsOptimized(charBufferRange, 
                                                   emSize, 
                                                   glyphIndices,
                                                   glyphMetrics, 
                                                   textFormattingMode,
                                                   isSideways
                                                   );
 
            double designToEm = emSize / glyphTypeface.DesignEmHeight;
 
            // 
            // This block will advance until one of:
            // 1. The end of the charBufferRange is reached 
            // 2. The charFlags have some of the charFlagsMask values
            // 3. The glyph is BlankGlyph (space)
            // 4. Glyph index is 0 (unless symbol font)
            // 
            // At this point totalWidth includes all of the widths including the stop character (which fits above)
            // i indexes the next character (not included in the width) 
            // 
            if(keepAWord)
            { 
                do
                {
                    char ch = charBufferRange[i++];
                    if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn) 
                    {
                        --i; 
                        break; 
                    }
                    else 
                    {
                        int charClass = (int)Classification.GetUnicodeClassUTF16(ch);
                        charFlags = Classification.CharAttributeOf(charClass).Flags;
                        charFastTextCheck &= charFlags; 

                        glyph = glyphIndices[i-1]; 
                        if (!ignoreWidths) 
                        {
                            totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor; 
                        }
                    }
                } while(
                        i < charBufferRange.Length 
                    &&  ((charFlags & charFlagsMask) == 0)
                    &&  (glyph != 0 || symbolTypeface) 
                    &&  glyph != blankGlyph 
                    );
 
                // i is now at a character immediately following a leading blank
            }

            // 
            // This block will advance until one of:
            // 1. The end of the charBufferRange is reached 
            // 2. The charFlags have some of the charFlagsMask values 
            // 3. Glyph index is 0 (unless symbol font)
            // 4. totalWidth > widthMax 
            //

            while(
                    i < charBufferRange.Length 
                &&  (ignoreWidths || totalWidth <= widthMax)
                &&  ((charFlags & charFlagsMask) == 0) 
                &&  (glyph != 0 || symbolTypeface) 
                )
            { 
                char ch = charBufferRange[i++];
                if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn)
                {
                    --i; 
                    break;
                } 
                else 
                {
                    int charClass = (int)Classification.GetUnicodeClassUTF16(ch); 
                    charFlags = Classification.CharAttributeOf(charClass).Flags;
                    charFastTextCheck &= charFlags;

                    glyph = glyphIndices[i-1]; 
                    if (!ignoreWidths)
                    { 
                        totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor; 
                    }
                } 
            }

            BufferCache.ReleaseUShorts(glyphIndices);
            glyphIndices = null; 
            BufferCache.ReleaseGlyphMetrics(glyphMetrics);
            glyphMetrics = null; 
 
            if (symbolTypeface)
            { 
                // always optimize for non-Unicode font as we don't support shaping or typographic features;
                // we also don't fall back from non-Unicode fonts so we don't care if there are missing glyphs
                stringLengthFit = i;
                return true; 
            }
 
            if (glyph == 0) 
            {
                // character is not supported by the font 
                return false;
            }

            if ((charFlags & charFlagsMask) != 0) 
            {
                // complex character encountered, exclude it 
                Debug.Assert(i > 0); 

                if(--i <= 0) 
                {
                    // first char is complex, fail the call
                    return false;
                } 
            }
 
            stringLengthFit = i; 
            TypographyAvailabilities typography = glyphTypeface.FontFaceLayoutInfo.TypographyAvailabilities;
 
            if ((charFastTextCheck & (byte) CharacterAttributeFlags.CharacterFastText) != 0)
            {
                // all input code points are Fast Text
                if ((typography & 
                         (  TypographyAvailabilities.FastTextTypographyAvailable
                          | TypographyAvailabilities.FastTextMajorLanguageLocalizedFormAvailable 
                         ) 
                     ) != 0
                   ) 
                {
                    // Considered too risky to optimize. It is either because the font
                    // has required features or the font has 'locl' lookup for major languages.
                    return false; 
                }
                else if ((typography & TypographyAvailabilities.FastTextExtraLanguageLocalizedFormAvailable) != 0) 
                { 
                    // The font has 'locl' lookup for FastText code points for non major languages.
                    // Check whether the input is major langauge. If it is, we are still good to optimize. 
                    return MajorLanguages.Contains(cultureInfo);
                }
                else
                { 
                    // No FastText flags are present, safe to optimize
                    return true; 
                } 
            }
            else if ((charFastTextCheck & (byte) CharacterAttributeFlags.CharacterIdeo) != 0) 
            {
                // The input are all ideographs, check the IdeoTypographyAvailable bit. It is safe if
                // the bit is not set.
                return ((typography & TypographyAvailabilities.IdeoTypographyAvailable) == 0); 
            }
            else 
            { 
                // for all the rest of the cases, just check whether there is any required typography
                // present at all. If none exists, it is optimizable. We might under-optimize here but 
                // it will be non-major languages.
                return ((typography & TypographyAvailabilities.Available) == 0);
            }
        } 

 
        ///  
        /// Lookup characters nominal glyphs and width
        ///  
        /// character buffer range
        /// height of Em
        ///  scaling factor from real to ideal unit 
        /// glyph nominal advances in ideal units 
        /// total width in ideal units
        /// true for success 
        /// This function is only used in fast path, and can only be called 
        /// if CheckFastPathNominalGlyphs has previously returned true.
        internal void GetCharacterNominalWidthsAndIdealWidth( 
            CharacterBufferRange charBufferRange,
            double               emSize,
            double               toIdeal,
            TextFormattingMode   textFormattingMode, 
            bool                 isSideways,
            out int[]            nominalWidths, 
            out int              idealWidth 
            )
        { 
            // This function should only be called if CheckFastPathNominalGlyphs has
            // returned true so we can assume the ITypefaceMetrics is a GlyphTypeface.
            GlyphTypeface glyphTypeface = TryGetGlyphTypeface();
            Invariant.Assert(glyphTypeface != null); 

            MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = BufferCache.GetGlyphMetrics(charBufferRange.Length); 
 
            glyphTypeface.GetGlyphMetricsOptimized(charBufferRange,
                                                   emSize, 
                                                   textFormattingMode,
                                                   isSideways,
                                                   glyphMetrics);
 
            nominalWidths = new int[charBufferRange.Length];
            idealWidth = 0; 
 
            if (TextFormattingMode.Display == textFormattingMode)
            { 
                double designToEm = emSize / glyphTypeface.DesignEmHeight;
                for (int i = 0; i < charBufferRange.Length; i++)
                {
                    nominalWidths[i] = (int)Math.Round(TextFormatterImp.RoundDipForDisplayMode(glyphMetrics[i].AdvanceWidth * designToEm) * toIdeal); 
                    idealWidth += nominalWidths[i];
                } 
            } 
            else
            { 
                double designToEm = emSize * toIdeal / glyphTypeface.DesignEmHeight;
                for (int i = 0; i < charBufferRange.Length; i++)
                {
                    nominalWidths[i] = (int)Math.Round(glyphMetrics[i].AdvanceWidth * designToEm); 
                    idealWidth += nominalWidths[i];
                } 
            } 

            BufferCache.ReleaseGlyphMetrics(glyphMetrics); 
        }

        /// 
        /// Create correspondent hash code for the object 
        /// 
        /// object hash code 
        public override int GetHashCode() 
        {
            int hash = _fontFamily.GetHashCode(); 

            if (_fallbackFontFamily != null)
                hash = HashFn.HashMultiply(hash) + _fallbackFontFamily.GetHashCode();
 
            hash = HashFn.HashMultiply(hash) + _style.GetHashCode();
            hash = HashFn.HashMultiply(hash) + _weight.GetHashCode(); 
            hash = HashFn.HashMultiply(hash) + _stretch.GetHashCode(); 
            return HashFn.HashScramble(hash);
        } 



        ///  
        /// Equality check
        ///  
        public override bool Equals(object o) 
        {
            Typeface t = o as Typeface; 
            if(t == null)
                return false;

            return  _style == t._style 
                &&  _weight == t._weight
                &&  _stretch == t._stretch 
                &&  _fontFamily.Equals(t._fontFamily) 
                &&  CompareFallbackFontFamily(t._fallbackFontFamily);
        } 


        internal bool CompareFallbackFontFamily(FontFamily fallbackFontFamily)
        { 
            if (fallbackFontFamily == null || _fallbackFontFamily == null)
                return fallbackFontFamily == _fallbackFontFamily; 
 
            return _fallbackFontFamily.Equals(fallbackFontFamily);
        } 

        //----------------------------------------
        // Private method
        //---------------------------------------- 
        private CachedTypeface CachedTypeface
        { 
            get 
            {
                if (_cachedTypeface == null) 
                {
                    CachedTypeface cachedTypeface = TypefaceMetricsCache.ReadonlyLookup(this) as CachedTypeface;

                    if (cachedTypeface == null) 
                    {
                       cachedTypeface = ConstructCachedTypeface(); 
                       TypefaceMetricsCache.Add(this, cachedTypeface); 
                    }
 
                    // For thread-safety, set the _cachedTypeface field only after we have a fully
                    // initialized CachedTypeface object.
                    _cachedTypeface = cachedTypeface;
                } 

                return _cachedTypeface; 
            } 
        }
 
        private CachedTypeface ConstructCachedTypeface()
        {
            FontStyle canonicalStyle     = _style;
            FontWeight canonicalWeight   = _weight; 
            FontStretch canonicalStretch = _stretch;
 
            // 
            // We always call FontFamily.FindFirstFontFamilyAndFace() method to resolve the
            // canonical styles since the implied styles in FontFamily name will override 
            // the given styles in the Typeface. But we don't always use the IFontFamily
            // instance returned from this method because an equal instance might already be
            // cached.
            // 
            FontFamily sourceFontFamily = FontFamily;
 
            IFontFamily firstFontFamily = sourceFontFamily.FindFirstFontFamilyAndFace( 
                ref canonicalStyle,
                ref canonicalWeight, 
                ref canonicalStretch
                );

            if (firstFontFamily == null) 
            {
                if (FallbackFontFamily != null) 
                { 
                    sourceFontFamily = FallbackFontFamily;
                    firstFontFamily = sourceFontFamily.FindFirstFontFamilyAndFace( 
                        ref canonicalStyle,
                        ref canonicalWeight,
                        ref canonicalStretch
                        ); 
                }
 
                if (firstFontFamily == null) 
                {
                    sourceFontFamily = null; 
                    firstFontFamily = FontFamily.LookupFontFamily(FontFamily.NullFontFamilyCanonicalName);
                }
            }
 
            // If it's a named font, map all occurrences of the same name to one cached IFontFamily.
            if (sourceFontFamily != null && sourceFontFamily.Source != null) 
            { 
                // We lookup in the cache to see if there is cached IFontFamily instance of the source FontFamily. Otherwise,
                // this IFontFamily value is added to the TypefaceMetrics cache. 
                IFontFamily cachedValue = TypefaceMetricsCache.ReadonlyLookup(sourceFontFamily.FamilyIdentifier) as IFontFamily;

                if (cachedValue != null)
                { 
                    firstFontFamily = cachedValue;
                } 
                else 
                {
                    TypefaceMetricsCache.Add(sourceFontFamily.FamilyIdentifier, firstFontFamily); 
                }
            }

            ITypefaceMetrics typefaceMetrics = firstFontFamily.GetTypefaceMetrics(canonicalStyle, canonicalWeight, canonicalStretch); 

            return new CachedTypeface( 
                canonicalStyle, 
                canonicalWeight,
                canonicalStretch, 
                firstFontFamily,
                typefaceMetrics,
                sourceFontFamily == null
                ); 
        }
    } 
} 

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

                        

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