Typeface.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / System / Windows / Media / Typeface.cs / 1 / 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);
            } 
        } 

        ///  
        /// Distance from character cell top to English baseline relative to em size.
        /// 
        internal double Baseline
        { 
            get
            { 
                return CachedTypeface.FirstFontFamily.Baseline; 
            }
        } 

        /// 
        /// Baseline to baseline distance relative to em size
        ///  
        internal double LineSpacing
        { 
            get 
            {
                return CachedTypeface.FirstFontFamily.LineSpacing; 
            }
        }

        ///  
        /// 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
        /// 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                  widthMax, 
            bool                    keepAWord,
            bool                    numberSubstitution,
            CultureInfo             cultureInfo,
            out int                 stringLengthFit 
            )
        { 
            stringLengthFit = 0; 

            if (CachedTypeface.NullFont) return false; 

            GlyphTypeface glyphTypeface = TryGetGlyphTypeface();

            if (glyphTypeface == null) return false; 

 
            stringLengthFit = 0; 
            IDictionary cmap = glyphTypeface.CharacterToGlyphMap;
 
            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; 
            }

            if(keepAWord)
            { 
                do
                { 
                    char ch = charBufferRange[i++]; 
                    int charClass = (int)Classification.GetUnicodeClassUTF16(ch);
                    charFlags = Classification.CharAttributeOf(charClass).Flags; 
                    charFastTextCheck &= charFlags;
                    cmap.TryGetValue(ch, out glyph);

                    totalWidth += emSize * glyphTypeface.GetAdvanceWidth(glyph); 

                } while( 
                        i < charBufferRange.Length 
                    &&  ((charFlags & charFlagsMask) == 0)
                    &&  (glyph != 0 || symbolTypeface) 
                    &&  glyph != blankGlyph
                    );

                // i is now at a character immediately following a leading blank 
            }
 
            while( 
                    i < charBufferRange.Length
                &&  totalWidth <= widthMax 
                &&  ((charFlags & charFlagsMask) == 0)
                &&  (glyph != 0 || symbolTypeface)
                )
            { 
                char ch = charBufferRange[i++];
                int charClass = (int)Classification.GetUnicodeClassUTF16(ch); 
                charFlags = Classification.CharAttributeOf(charClass).Flags; 
                charFastTextCheck &= charFlags;
                cmap.TryGetValue(ch, out glyph); 
                totalWidth += emSize * glyphTypeface.GetAdvanceWidth(glyph);
            }

            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,
            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); 

            IDictionary cmap = glyphTypeface.CharacterToGlyphMap; 
            nominalWidths = new int[charBufferRange.Length];
            idealWidth = 0;

            for (int i = 0; i < charBufferRange.Length; i++) 
            {
                ushort glyphIndex; 
                cmap.TryGetValue(charBufferRange[i], out glyphIndex); 
                double advance = emSize * glyphTypeface.GetAdvanceWidth(glyphIndex);
 
                nominalWidths[i] = (int) Math.Round(advance * toIdeal);
                idealWidth += nominalWidths[i];
            }
 
        }
 
 

        ///  
        /// 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);
            } 
        } 

        ///  
        /// Distance from character cell top to English baseline relative to em size.
        /// 
        internal double Baseline
        { 
            get
            { 
                return CachedTypeface.FirstFontFamily.Baseline; 
            }
        } 

        /// 
        /// Baseline to baseline distance relative to em size
        ///  
        internal double LineSpacing
        { 
            get 
            {
                return CachedTypeface.FirstFontFamily.LineSpacing; 
            }
        }

        ///  
        /// 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
        /// 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                  widthMax, 
            bool                    keepAWord,
            bool                    numberSubstitution,
            CultureInfo             cultureInfo,
            out int                 stringLengthFit 
            )
        { 
            stringLengthFit = 0; 

            if (CachedTypeface.NullFont) return false; 

            GlyphTypeface glyphTypeface = TryGetGlyphTypeface();

            if (glyphTypeface == null) return false; 

 
            stringLengthFit = 0; 
            IDictionary cmap = glyphTypeface.CharacterToGlyphMap;
 
            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; 
            }

            if(keepAWord)
            { 
                do
                { 
                    char ch = charBufferRange[i++]; 
                    int charClass = (int)Classification.GetUnicodeClassUTF16(ch);
                    charFlags = Classification.CharAttributeOf(charClass).Flags; 
                    charFastTextCheck &= charFlags;
                    cmap.TryGetValue(ch, out glyph);

                    totalWidth += emSize * glyphTypeface.GetAdvanceWidth(glyph); 

                } while( 
                        i < charBufferRange.Length 
                    &&  ((charFlags & charFlagsMask) == 0)
                    &&  (glyph != 0 || symbolTypeface) 
                    &&  glyph != blankGlyph
                    );

                // i is now at a character immediately following a leading blank 
            }
 
            while( 
                    i < charBufferRange.Length
                &&  totalWidth <= widthMax 
                &&  ((charFlags & charFlagsMask) == 0)
                &&  (glyph != 0 || symbolTypeface)
                )
            { 
                char ch = charBufferRange[i++];
                int charClass = (int)Classification.GetUnicodeClassUTF16(ch); 
                charFlags = Classification.CharAttributeOf(charClass).Flags; 
                charFastTextCheck &= charFlags;
                cmap.TryGetValue(ch, out glyph); 
                totalWidth += emSize * glyphTypeface.GetAdvanceWidth(glyph);
            }

            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,
            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); 

            IDictionary cmap = glyphTypeface.CharacterToGlyphMap; 
            nominalWidths = new int[charBufferRange.Length];
            idealWidth = 0;

            for (int i = 0; i < charBufferRange.Length; i++) 
            {
                ushort glyphIndex; 
                cmap.TryGetValue(charBufferRange[i], out glyphIndex); 
                double advance = emSize * glyphTypeface.GetAdvanceWidth(glyphIndex);
 
                nominalWidths[i] = (int) Math.Round(advance * toIdeal);
                idealWidth += nominalWidths[i];
            }
 
        }
 
 

        ///  
        /// 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