GlyphTypeface.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / Windows / Media / GlyphTypeface.cs / 1 / GlyphTypeface.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: GlyphTypeface implementation 
//
// History: 
//  06/04/2003 : [....] - Moved GlyphTypeface from GlyphRun.cs
//
//---------------------------------------------------------------------------
using System; 
using System.Collections;
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Diagnostics;
using System.Globalization; 
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions; 

using System.Windows; 
using System.Windows.Media.Composition; 
using System.Windows.Media.TextFormatting;
using System.Windows.Markup; 

using MS.Internal.FontRasterization;

using MS.Internal; 
using MS.Internal.FontCache;
using MS.Internal.FontFace; 
using MS.Internal.PresentationCore; 

namespace System.Windows.Media 
{
    /// 
    /// Physical font face corresponds to a font file on the disk
    ///  
    public class GlyphTypeface : ITypefaceMetrics, ISupportInitialize
    { 
        //----------------------------------------------------- 
        //
        //  Constructors 
        //
        //-----------------------------------------------------

        #region Constructors 

        ///  
        /// Creates an uninitialized GlyphTypeface object. Caller should call ISupportInitialize.BeginInit() 
        /// to begin initializing the object and call ISupportInitialize.EndInit() to finish the initialization.
        ///  
        public GlyphTypeface()
        {
        }
 
        /// 
        /// Creates a new GlyphTypeface object from a .otf, .ttf or .ttc font face specified by typefaceSource. 
        /// The constructed GlyphTypeface does not use style simulations. 
        /// 
        /// Specifies the URI of a font file used by the newly created GlyphTypeface. 
        public GlyphTypeface(Uri typefaceSource) : this(typefaceSource, StyleSimulations.None)
        {}

        ///  
        /// Creates a new GlyphTypeface object from a .otf, .ttf or .ttc font face specified by typefaceSource.
        /// The constructed GlyphTypeface uses style simulations specified by styleSimulations parameter. 
        ///  
        /// Specifies the URI of a font file used by the newly created GlyphTypeface.
        /// Specifies style simulations to be applied to the newly created GlyphTypeface. 
        /// 
        /// Critical - as this calls the internal constructor that's critical.
        /// Safe - as the internal constructor does a Demand for FileIO for file
        ///        Uris for the case where fromPublic is true.  We block constructing 
        ///        GlyphTypeface directly in SEE since this'd allow guessing fonts on
        ///        a machine by trying to create a GlyphTypeface object. 
        /// 
        /// 
        [SecurityCritical] 
        public GlyphTypeface(Uri typefaceSource, StyleSimulations styleSimulations) :
                            this (typefaceSource, styleSimulations, /* fromPublic = */ true)
        {}
 
        /// 
        /// Creates a new GlyphTypeface object from a .otf, .ttf or .ttc font face specified by typefaceSource. 
        /// The constructed GlyphTypeface uses style simulations specified by styleSimulations parameter. 
        /// 
        /// Specifies the URI of a font file used by the newly created GlyphTypeface. 
        /// Specifies style simulations to be applied to the newly created GlyphTypeface.
        /// Specifies if the call to the constructor is from a public constructor
        /// or if its from an internal method. For public constructor we demand FileIO for all files whereas
        /// for internal calls we don't demand in the constructor.  
        /// 
        /// Critical - as the instance of GlyphTypeface created with this constructor can 
        ///            expose font information for the case where fromPublic is false. 
        /// 
        [SecurityCritical] 
        internal GlyphTypeface(Uri typefaceSource, StyleSimulations styleSimulations, bool fromPublic)
        {
            Initialize(typefaceSource, styleSimulations, fromPublic);
        } 

        ///  
        /// Critical - this method calls into other critical method. 
        /// 
        [SecurityCritical] 
        private void Initialize(Uri typefaceSource, StyleSimulations styleSimulations, bool fromPublic)
        {
            if (typefaceSource == null)
                throw new ArgumentNullException("typefaceSource"); 

            if (!typefaceSource.IsAbsoluteUri) 
                throw new ArgumentException(SR.Get(SRID.UriNotAbsolute), "typefaceSource"); 

            // remember the original Uri that contains face index 
            _originalUri = new SecurityCriticalDataClass(typefaceSource);

            // split the Uri into the font source Uri and face index
            Uri fontSourceUri; 
            int faceIndex;
            Util.SplitFontFaceIndex(typefaceSource, out fontSourceUri, out faceIndex); 
 
            _fileIOPermObj = new SecurityCriticalDataForSet(
                SecurityHelper.CreateUriReadPermission(fontSourceUri) 
                );

            // This permission demand is here so that untrusted callers are unable to check for file existence using GlyphTypeface ctor.
            // Sensitive font data is protected by demands as the user tries to access it. 
            // The demand below is skipped for non-public calls, because in such cases
            // fonts are exposed as logical fonts to the end user. 
            if (fromPublic) 
                DemandPermissionsForFontInformation();
 
            // We skip permission demands for FontSource because the above line already demands them for the right callers.
            _fontFace = new FontFaceLayoutInfo(new FontSource(fontSourceUri, true), faceIndex);
            CacheManager.Lookup(_fontFace);
 
            if ((styleSimulations & ~StyleSimulations.BoldItalicSimulation) != 0)
                throw new InvalidEnumArgumentException("styleSimulations", (int)styleSimulations, typeof(StyleSimulations)); 
            _styleSimulations = styleSimulations; 

            _initializationState = InitializationState.IsInitialized; // fully initialized 
        }

        #endregion Constructors
 
        //------------------------------------------------------
        // 
        //  Public Methods 
        //
        //----------------------------------------------------- 

        #region Public Methods

        ///  
        /// Return hash code for this GlyphTypeface.
        ///  
        /// Hash code. 
        /// 
        /// Critical - as this accesses _originalUri. 
        /// Safe - as this only does this to compute the hash code.
        /// 
        [SecurityCritical]
        public override int GetHashCode() 
        {
            CheckInitialized(); 
            return _originalUri.Value.GetHashCode() ^ (int)StyleSimulations; 
        }
 
        /// 
        /// Compares this GlyphTypeface with another object.
        /// 
        /// Object to compare with. 
        /// Whether this object is equal to the input object.
        ///  
        /// Critical - as this accesses _originalUri. 
        /// Safe - as this only does this to perform a comparison with another object.
        ///  
        [SecurityCritical]
        public override bool Equals(object o)
        {
            CheckInitialized(); 
            GlyphTypeface t = o as GlyphTypeface;
            if (t == null) 
                return false; 

            return StyleSimulations == t.StyleSimulations 
                && _originalUri.Value == t._originalUri.Value;
        }

        ///  
        /// Returns a geometry describing the path for a single glyph in the font.
        /// The path represents the glyph 
        /// without grid fitting applied for rendering at a specific resolution. 
        /// 
        /// Index of the glyph to get outline for. 
        /// Font size in drawing surface units.
        /// Size to hint for in points.
        /// 
        [CLSCompliant(false)] 
        public Geometry GetGlyphOutline(ushort glyphIndex, double renderingEmSize, double hintingEmSize)
        { 
            CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
            return ComputeGlyphOutline(glyphIndex, false, renderingEmSize, hintingEmSize);
        } 

        /// 
        /// Returns the binary image of font subset.
        ///  
        /// Collection of glyph indices to be included into the subset.
        /// Binary image of font subset. 
        ///  
        ///     Callers must have UnmanagedCode permission to call this API.
        ///     Callers must have FileIOPermission or WebPermission to font location to call this API. 
        /// 
        /// 
        ///     Critical - returns raw font data.
        ///     Safe - (1) unmanaged code demand.  This ensures PT callers can't directly access the TrueType subsetter in V1. 
        ///            (2) fileIO or web permission demand for location of font.  This ensures that even brokered access
        ///                    via print dialog (which asserts unmanaged code) only succeeds if user has access to font source location. 
        ///  
        [SecurityCritical]
        [CLSCompliant(false)] 
        public byte[] ComputeSubset(ICollection glyphs)
        {
            SecurityHelper.DemandUnmanagedCode();
            DemandPermissionsForFontInformation(); 
            CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
 
            if (glyphs == null) 
                throw new ArgumentNullException("glyphs");
 
            if (glyphs.Count <= 0)
                throw new ArgumentException(SR.Get(SRID.CollectionNumberOfElementsMustBeGreaterThanZero), "glyphs");

            if (glyphs.Count > ushort.MaxValue) 
                throw new ArgumentException(SR.Get(SRID.CollectionNumberOfElementsMustBeLessOrEqualTo, ushort.MaxValue), "glyphs");
 
            UnmanagedMemoryStream pinnedFontSource = FontSource.GetUnmanagedStream(); 

            try 
            {
                TrueTypeFontDriver trueTypeDriver = new TrueTypeFontDriver(pinnedFontSource, _originalUri.Value);
                trueTypeDriver.SetFace(FaceIndex);
 
                return trueTypeDriver.ComputeFontSubset(glyphs);
            } 
            catch (SEHException e) 
            {
                throw Util.ConvertInPageException(FontSource, e); 
            }
            finally
            {
                pinnedFontSource.Close(); 
            }
        } 
 
        /// 
        /// Returns a font file stream represented by this GlyphTypeface. 
        /// 
        /// A font file stream represented by this GlyphTypeface.
        /// 
        ///     Critical - returns raw font data. 
        ///     Safe - does a demand before it gives out the information asked.
        ///  
        [SecurityCritical] 
        public Stream GetFontStream()
        { 
            CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
            DemandPermissionsForFontInformation();
            return FontSource.GetStream();
        } 

        ///  
        /// Exposed to allow printing code to access GetFontStream() in partial trust 
        /// 
        ///  
        ///     Critical - returns a permission allowing access to GetFontStream in partial trust.
        ///                Caller must make sure there is no font data leak
        /// 
        [FriendAccessAllowed] 
        internal CodeAccessPermission CriticalFileReadPermission
        { 
            [SecurityCritical] 
            get
            { 
                CheckInitialized();
                return _fileIOPermObj.Value;
            }
        } 

        ///  
        /// Exposed to allow printing code to access FontUri in partial trust 
        /// 
        ///  
        ///     Critical - returns a permission allowing access to FontUri
        ///                Caller must make sure there is no data leak
        /// 
        [FriendAccessAllowed] 
        internal CodeAccessPermission CriticalUriDiscoveryPermission
        { 
            [SecurityCritical] 
            get
            { 
                CheckInitialized();
                return SecurityHelper.CreateUriDiscoveryPermission(_originalUri.Value);
            }
        } 

        #endregion Public Methods 
 
        //------------------------------------------------------
        // 
        //  Public Properties
        //
        //------------------------------------------------------
 
        #region Public Properties
 
        ///  
        /// Returns the original Uri of this glyph typeface object.
        ///  
        /// The Uri glyph typeface was constructed with.
        /// 
        ///     Callers must have FileIOPermission(FileIOPermissionAccess.PathDiscovery) for the given Uri to call this API.
        ///  
        /// 
        /// Critical - as this obtains Uri that can reveal local file system information. 
        /// Safe - as this does a discovery demand before it gives out the information asked. 
        /// 
        public Uri FontUri 
        {
            [SecurityCritical]
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                SecurityHelper.DemandUriDiscoveryPermission(_originalUri.Value); 
                return _originalUri.Value; 
            }
            [SecurityCritical] 
            set
            {
                CheckInitializing(); // This can only be called in initialization
 
                if (value == null)
                    throw new ArgumentNullException("value"); 
 
                if (!value.IsAbsoluteUri)
                    throw new ArgumentException(SR.Get(SRID.UriNotAbsolute), "value"); 

                _originalUri = new SecurityCriticalDataClass(value);
            }
        } 

        ///  
        /// This property is indexed by a Culture Identifier. 
        /// It returns the family name in the specified language, or,
        /// if the font does not provide a name for the specified language, 
        /// it returns the family name in English.
        /// The family name excludes weight, style and stretch.
        /// 
        public IDictionary FamilyNames 
        {
            get 
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return _fontFace.GetFamilyNameDictionary(); 
            }
        }

        ///  
        /// This property is indexed by a Culture Identifier.
        /// It returns the face name in the specified language, or, 
        /// if the font does not provide a name for the specified language, 
        /// it returns the face name in English.
        /// The face name may identify weight, style and/or stretch. 
        /// 
        public IDictionary FaceNames
        {
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return _fontFace.GetFaceNameDictionary(); 
            }
        } 

        /// 
        /// This property is indexed by a Culture Identifier.
        /// It returns the family name in the specified language, or, 
        /// if the font does not provide a name for the specified language,
        /// it returns the family name in English. 
        /// The Win32FamilyName name excludes regular or bold weights and style, 
        /// but includes other weights and stretch.
        ///  
        public IDictionary Win32FamilyNames
        {
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return _fontFace.GetWin32FamilyNameDictionary(); 
            } 
        }
 
        /// 
        /// This property is indexed by a Culture Identifier.
        /// It returns the face name in the specified language, or,
        /// if the font does not provide a name for the specified language, 
        /// it returns the face name in English.
        /// The face name may identify weight, style and/or stretch. 
        ///  
        IDictionary ITypefaceMetrics.AdjustedFaceNames
        { 
            get
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                IDictionary adjustedFaceNames = _fontFace.GetAdjustedFaceNameDictionary(); 
                IDictionary adjustedLanguageFaceNames = new Dictionary(adjustedFaceNames.Count);
 
                foreach (KeyValuePair pair in adjustedFaceNames) 
                {
                    adjustedLanguageFaceNames[XmlLanguage.GetLanguage(pair.Key.IetfLanguageTag)] = pair.Value; 
                }

                if (_styleSimulations != StyleSimulations.None)
                { 
                    adjustedLanguageFaceNames = FontDifferentiator.AppendSimulationsToFaceNames(adjustedLanguageFaceNames, _styleSimulations);
                } 
                return adjustedLanguageFaceNames; 
            }
        } 

        /// 
        /// This property is indexed by a Culture Identifier.
        /// It returns the face name in the specified language, or, 
        /// if the font does not provide a name for the specified language,
        /// it returns the face name in English. 
        /// The Win32Face name may identify weights other than regular or bold and/or style, 
        /// but may not identify stretch or other weights.
        ///  
        public IDictionary Win32FaceNames
        {
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return _fontFace.GetWin32FaceNameDictionary(); 
            } 
        }
 
        /// 
        /// This property is indexed by a Culture Identifier.
        /// Version string in the fonts NAME table.
        /// Version strings vary significantly in format - to obtain the version 
        /// as a numeric value use the 'Version' property,
        /// do not attempt to parse the VersionString. 
        ///  
        /// 
        /// Critical - as this accesses _fontFace which can reveal Windows font information. 
        /// Safe - as this does a demand before it gives out the information asked.
        /// 
        public IDictionary VersionStrings
        { 
            [SecurityCritical]
            get 
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                DemandPermissionsForFontInformation(); 
                return _fontFace.GetVersionStringDictionary();
            }
        }
 
        /// 
        /// This property is indexed by a Culture Identifier. 
        /// Copyright notice. 
        /// 
        ///  
        /// Critical - as this accesses _fontFace which can reveal Windows font information.
        /// Safe - as this does a demand before it gives out the information asked.
        /// 
        public IDictionary Copyrights 
        {
            [SecurityCritical] 
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                DemandPermissionsForFontInformation();
                return _fontFace.GetCopyrightDictionary();
            }
        } 

        ///  
        /// This property is indexed by a Culture Identifier. 
        /// Manufacturer Name.
        ///  
        /// 
        /// Critical - as this accesses _fontFace which can reveal Windows font information.
        /// Safe - as this does a demand before it gives out the information asked.
        ///  
        public IDictionary ManufacturerNames
        { 
            [SecurityCritical] 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                DemandPermissionsForFontInformation();
                return _fontFace.GetManufacturerNameDictionary();
            } 
        }
 
        ///  
        /// This property is indexed by a Culture Identifier.
        /// This is used to save any trademark notice/information for this font. 
        /// Such information should be based on legal advice.
        /// This is distinctly separate from the copyright.
        /// 
        ///  
        /// Critical - as this accesses _fontFace which can reveal Windows font information.
        /// Safe - as this does a demand before it gives out the information asked. 
        ///  
        public IDictionary Trademarks
        { 
            [SecurityCritical]
            get
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                DemandPermissionsForFontInformation();
                return _fontFace.GetTrademarkDictionary(); 
            } 
        }
 
        /// 
        /// This property is indexed by a Culture Identifier.
        /// Name of the designer of the typeface.
        ///  
        /// 
        /// Critical - as this accesses _fontFace which can reveal Windows font information. 
        /// Safe - as this does a demand before it gives out the information asked. 
        /// 
        public IDictionary DesignerNames 
        {
            [SecurityCritical]
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                DemandPermissionsForFontInformation(); 
                return _fontFace.GetDesignerNameDictionary(); 
            }
        } 

        /// 
        /// This property is indexed by a Culture Identifier.
        /// Description of the typeface. Can contain revision information, 
        /// usage recommendations, history, features, etc.
        ///  
        ///  
        /// Critical - as this accesses _fontFace which can reveal Windows font information.
        /// Safe - as this does a demand before it gives out the information asked. 
        /// 
        public IDictionary Descriptions
        {
            [SecurityCritical] 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                DemandPermissionsForFontInformation();
                return _fontFace.GetDescriptionDictionary(); 
            }
        }

        ///  
        /// This property is indexed by a Culture Identifier.
        /// URL of font vendor (with protocol, e.g., `http://, `ftp://). 
        /// If a unique serial number is embedded in the URL, 
        /// it can be used to register the font.
        ///  
        /// 
        /// Critical - as this accesses _fontFace which can reveal Windows font information.
        /// Safe - as this does a demand before it gives out the information asked.
        ///  
        public IDictionary VendorUrls
        { 
            [SecurityCritical] 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                DemandPermissionsForFontInformation();
                return _fontFace.GetVendorUrlDictionary();
            } 
        }
 
        ///  
        /// This property is indexed by a Culture Identifier.
        /// URL of typeface designer (with protocol, e.g., `http://, `ftp://). 
        /// 
        /// 
        /// Critical - as this accesses _fontFace which can reveal Windows font information.
        /// Safe - as this does a demand before it gives out the information asked. 
        /// 
        public IDictionary DesignerUrls 
        { 
            [SecurityCritical]
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                DemandPermissionsForFontInformation();
                return _fontFace.GetDesignerUrlDictionary(); 
            }
        } 
 
        /// 
        /// This property is indexed by a Culture Identifier. 
        /// Description of how the font may be legally used,
        /// or different example scenarios for licensed use.
        /// This field should be written in plain language, not legalese.
        ///  
        /// 
        /// Critical - as this accesses _fontFace which can reveal Windows font information. 
        /// Safe - as this does a demand before it gives out the information asked. 
        /// 
        public IDictionary LicenseDescriptions 
        {
            [SecurityCritical]
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                DemandPermissionsForFontInformation(); 
                return _fontFace.GetLicenseDescriptionDictionary(); 
            }
        } 

        /// 
        /// This property is indexed by a Culture Identifier.
        /// This can be the font name, or any other text that the designer 
        /// thinks is the best sample to display the font in.
        ///  
        ///  
        /// Critical - as this accesses _fontFace which can reveal Windows font information.
        /// Safe - as this does a demand before it gives out the information asked. 
        /// 
        public IDictionary SampleTexts
        {
            [SecurityCritical] 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                DemandPermissionsForFontInformation();
                return _fontFace.GetSampleTextDictionary(); 
            }
        }

        ///  
        /// Returns designed style (regular/italic/oblique) of this font face
        ///  
        /// Designed style of this font face. 
        public FontStyle Style
        { 
            get
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return _fontFace.Style; 
            }
        } 
 
        /// 
        /// Returns designed weight of this font face. 
        /// 
        /// Designed weight of this font face.
        public FontWeight Weight
        { 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return _fontFace.Weight;
            } 
        }

        /// 
        /// Returns designed stretch of this font face. 
        /// 
        /// Designed stretch of this font face. 
        public FontStretch Stretch 
        {
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return _fontFace.Stretch;
            } 
        }
 
        ///  
        /// Font face version interpreted from the font's 'NAME' table.
        ///  
        /// 
        /// Critical - as this accesses _fontFace which can reveal Windows font information.
        /// Safe - as this does a demand before it gives out the information asked.
        ///  
        public double Version
        { 
            [SecurityCritical] 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                DemandPermissionsForFontInformation();
                return _fontFace.Version;
            } 
        }
 
        ///  
        /// Height of character cell relative to em size.
        ///  
        public double Height
        {
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return (double)(_fontFace.DesignCellAscent + _fontFace.DesignCellDescent) / DesignEmHeight; 
            } 
        }
 
        /// 
        /// Distance from cell top to English baseline relative to em size.
        /// 
        public double Baseline 
        {
            get 
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return (double)_fontFace.DesignCellAscent / DesignEmHeight; 
            }
        }

        ///  
        /// Distance from baseline to top of English capital, relative to em size.
        ///  
        public double CapsHeight 
        {
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return (double)_fontFace.CapsHeight / DesignEmHeight;
            } 
        }
 
        ///  
        /// Western x-height relative to em size.
        ///  
        public double XHeight
        {
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return (double)_fontFace.xHeight / DesignEmHeight; 
            } 
        }
 
        /// 
        /// Returns true if this font does not conform to Unicode encoding:
        /// it may be considered as a simple collection of symbols indexed by a codepoint.
        ///  
        public bool Symbol
        { 
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return _fontFace.Symbol;
            }
        }
 
        /// 
        /// Position of underline relative to baseline relative to em size. 
        /// The value is usually negative, to place the underline below the baseline. 
        /// 
        public double UnderlinePosition 
        {
            get
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return (double)_fontFace.UnderlinePosition / DesignEmHeight;
            } 
        } 

        ///  
        /// Thickness of underline relative to em size.
        /// 
        public double UnderlineThickness
        { 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return (double)_fontFace.UnderlineThickness / DesignEmHeight;
            } 
        }

        /// 
        /// Position of strikeThrough relative to baseline relative to em size. 
        /// The value is usually positive, to place the Strikethrough above the baseline.
        ///  
        public double StrikethroughPosition 
        {
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return (double)_fontFace.StrikethroughPosition / DesignEmHeight;
            } 
        }
 
        ///  
        /// Thickness of Strikethrough relative to em size.
        ///  
        public double StrikethroughThickness
        {
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return (double)_fontFace.StrikethroughThickness / DesignEmHeight; 
            } 
        }
 
        /// 
        /// EmbeddingRights property describes font embedding permissions
        /// specified in this glyph typeface.
        ///  
        /// 
        /// Critical - as this accesses _fontFace which can reveal Windows font information. 
        /// Safe - as this does a demand before it gives out the information asked. 
        /// 
        public FontEmbeddingRight EmbeddingRights 
        {
            [SecurityCritical]
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                DemandPermissionsForFontInformation(); 
                return _fontFace.EmbeddingRights; 
            }
        } 

        #region ITypefaceMetrics implementation

        ///  
        /// Distance from baseline to top of English capital, relative to em size.
        ///  
        double ITypefaceMetrics.CapsHeight 
        {
            get 
            {
                return CapsHeight;
            }
        } 

        ///  
        /// Western x-height relative to em size. 
        /// 
        double ITypefaceMetrics.XHeight 
        {
            get
            {
                return XHeight; 
            }
        } 
 
        /// 
        /// Returns true if this font does not conform to Unicode encoding: 
        /// it may be considered as a simple collection of symbols indexed by a codepoint.
        /// 
        bool ITypefaceMetrics.Symbol
        { 
            get
            { 
                return Symbol; 
            }
        } 

        /// 
        /// Position of underline relative to baseline relative to em size.
        /// The value is usually negative, to place the underline below the baseline. 
        /// 
        double ITypefaceMetrics.UnderlinePosition 
        { 
            get
            { 
                return UnderlinePosition;
            }
        }
 
        /// 
        /// Thickness of underline relative to em size. 
        ///  
        double ITypefaceMetrics.UnderlineThickness
        { 
            get
            {
                return UnderlineThickness;
            } 
        }
 
        ///  
        /// Position of strikeThrough relative to baseline relative to em size.
        /// The value is usually positive, to place the Strikethrough above the baseline. 
        /// 
        double ITypefaceMetrics.StrikethroughPosition
        {
            get 
            {
                return StrikethroughPosition; 
            } 
        }
 
        /// 
        /// Thickness of Strikethrough relative to em size.
        /// 
        double ITypefaceMetrics.StrikethroughThickness 
        {
            get 
            { 
                return StrikethroughThickness;
            } 
        }

        #endregion
 

        // The next several properties return non CLS-compliant types.  This is 
        // tracked by bug 1792236.  For now, suppress the compiler warning. 
        //
        #pragma warning disable 3003 

        /// 
        /// Returns advance width for a given glyph.
        ///  
        public IDictionary AdvanceWidths
        { 
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return new GlyphIndexer(this.GetAdvanceWidth, _fontFace.GlyphCount);
            }
        }
 
        /// 
        /// Returns Advance height for a given glyph (Used for example in vertical layout). 
        ///  
        public IDictionary AdvanceHeights
        { 
            get
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return new GlyphIndexer(this.GetAdvanceHeight, _fontFace.GlyphCount); 
            }
        } 
 
        /// 
        /// Distance from leading end of advance vector to left edge of black box. 
        /// Positive when left edge of black box is within the alignment rectangle
        /// defined by the advance width and font cell height.
        /// Negative when left edge of black box overhangs the alignment rectangle.
        ///  
        public IDictionary LeftSideBearings
        { 
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return new GlyphIndexer(this.GetLeftSidebearing, _fontFace.GlyphCount);
            }
        }
 
        /// 
        /// Distance from right edge of black box to right end of advance vector. 
        /// Positive when trailing edge of black box is within the alignment rectangle 
        /// defined by the advance width and font cell height.
        /// Negative when right edge of black box overhangs the alignment rectangle. 
        /// 
        public IDictionary RightSideBearings
        {
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return new GlyphIndexer(this.GetRightSidebearing, _fontFace.GlyphCount); 
            }
        } 

        /// 
        /// Distance from top end of (vertical) advance vector to top edge of black box.
        /// Positive when top edge of black box is within the alignment rectangle 
        /// defined by the advance height and font cell height.
        /// (The font cell height is a horizontal dimension in vertical layout). 
        /// Negative when top edge of black box overhangs the alignment rectangle. 
        /// 
        public IDictionary TopSideBearings 
        {
            get
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return new GlyphIndexer(this.GetTopSidebearing, _fontFace.GlyphCount);
            } 
        } 

        ///  
        /// Distance from bottom edge of black box to bottom end of advance vector.
        /// Positive when bottom edge of black box is within the alignment rectangle
        /// defined by the advance width and font cell height.
        /// (The font cell height is a horizontal dimension in vertical layout). 
        /// Negative when bottom edge of black box overhangs the alignment rectangle.
        ///  
        public IDictionary BottomSideBearings 
        {
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return new GlyphIndexer(this.GetBottomSidebearing, _fontFace.GlyphCount);
            } 
        }
 
        ///  
        /// Offset down from horizontal Western baseline to bottom  of glyph black box.
        ///  
        public IDictionary DistancesFromHorizontalBaselineToBlackBoxBottom
        {
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return new GlyphIndexer(this.GetBaseline, _fontFace.GlyphCount); 
            } 
        }
 
        /// 
        /// Returns nominal mapping of Unicode codepoint to glyph index as defined by the font 'CMAP' table.
        /// 
        ///  
        ///   Critical: May potentially leak a writeable cmap.
        ///   Safe: The cmap IDictionary exposure is read only. 
        ///   
        public IDictionary CharacterToGlyphMap
        { 
            [SecurityCritical]
            get
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return _fontFace.CharacterMap;
            } 
        } 

        #pragma warning restore 3003 

        /// 
        /// Returns algorithmic font style simulations to be applied to the GlyphTypeface.
        ///  
        public StyleSimulations StyleSimulations
        { 
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return _styleSimulations;
            }
            set
            { 
                CheckInitializing();
                _styleSimulations = value; 
            } 
        }
 
        /// 
        /// Obtains the number of glyphs in the glyph typeface.
        /// 
        /// The number of glyphs in the glyph typeface. 
        public int GlyphCount
        { 
            get 
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return _fontFace.GlyphCount;
            }
        }
 
        #endregion Public Properties
 
        //----------------------------------------------------- 
        //
        //  Internal Methods 
        //
        //------------------------------------------------------

        #region Internal Methods 

        ///  
        /// Returns the nominal advance width for a glyph. 
        /// 
        /// Glyph index in the font. 
        /// The nominal advance width for the glyph relative to the em size of the font.
        /// 
        /// Critical - as this has unsafe block.
        /// Safe - as this only gives width information which is safe to give out. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal double GetAdvanceWidth(ushort glyph) 
        {
            CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 

            // We manually expand GetGlyphMetrics call because GetAdvanceWidth is a very frequently used function.
            // When we get to using GetAdvanceHeight for vertical writing, we need to consider doing the same optimization there.
            unsafe 
            {
                FontFaceLayoutInfo.GlyphMetrics * cachedGlyphMetrics = _fontFace.Metrics(glyph); 
 
                double aw = (double)cachedGlyphMetrics->advanceWidth / DesignEmHeight;
 
                if ((_styleSimulations & StyleSimulations.BoldSimulation) != 0)
                {
                    // Bold simulation increases advance width and advance height by 2% of em size,
                    // except for glyphs that are empty or have zero advance widths. 
                    // So, we compensate for the simulation when aw != 0 && left < right && ah != 0 && bottom > top
                    if (cachedGlyphMetrics->advanceWidth != 0 && 
                        cachedGlyphMetrics->lsb < cachedGlyphMetrics->advanceWidth - cachedGlyphMetrics->rsb && 
                        cachedGlyphMetrics->advanceHeight != 0 &&
                        cachedGlyphMetrics->advanceHeight - cachedGlyphMetrics->tsb - cachedGlyphMetrics->bsb > 0) 
                    {
                        aw += 0.02;
                    }
                } 
                return aw;
            } 
        } 

        ///  
        /// Returns the nominal advance width for a glyph in font design units.
        /// 
        /// Glyph index in the font.
        /// The nominal advance width for the glyph in font design units. 
        internal double GetAdvanceWidthInDesignUnits(ushort glyph)
        { 
            return GetAdvanceWidth(glyph) * DesignEmHeight; 
        }
 

        /// 
        /// This function will demand appropriate permissions depending on what
        /// the source of the font information is.  The value of _fileIOPermObj 
        /// is set correctly whenever _originalUri gets set.
        ///  
        internal void DemandPermissionsForFontInformation() 
        {
            if (_fileIOPermObj.Value != null) 
            {
                _fileIOPermObj.Value.Demand();
            }
        } 

        private double GetAdvanceHeight(ushort glyph) 
        { 
            double aw, ah, lsb, rsb, tsb, bsb, baseline;
            GetGlyphMetrics( 
                glyph,
                1.0,
                out aw,
                out ah, 
                out lsb,
                out rsb, 
                out tsb, 
                out bsb,
                out baseline 
            );
            return ah;
        }
 
        private double GetLeftSidebearing(ushort glyph)
        { 
            return (double)_fontFace.GetLeftSidebearing(glyph) / DesignEmHeight; 
        }
 
        private double GetRightSidebearing(ushort glyph)
        {
            return (double)_fontFace.GetRightSidebearing(glyph) / DesignEmHeight;
        } 

        private double GetTopSidebearing(ushort glyph) 
        { 
            return (double)_fontFace.GetTopSidebearing(glyph) / DesignEmHeight;
        } 

        private double GetBottomSidebearing(ushort glyph)
        {
            return (double)_fontFace.GetBottomSidebearing(glyph) / DesignEmHeight; 
        }
 
        private double GetBaseline(ushort glyph) 
        {
            return (double)_fontFace.GetBaseline(glyph) / DesignEmHeight; 
        }

        /// 
        /// Optimized version of obtaining all of glyph metrics from font cache at once 
        /// without repeated checks and divisions.
        ///  
        ///  
        /// Critical - as this uses unsafe code.
        /// Safe - as this only gives information which is safe to give out. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal void GetGlyphMetrics(
            ushort      glyph, 
            double      renderingEmSize,
            out double  aw, 
            out double  ah, 
            out double  lsb,
            out double  rsb, 
            out double  tsb,
            out double  bsb,
            out double  baseline
            ) 
        {
            CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
 
            unsafe
            { 
                FontFaceLayoutInfo.GlyphMetrics * cachedGlyphMetrics = _fontFace.Metrics(glyph);

                double designToEm = renderingEmSize / DesignEmHeight;
 
                aw = designToEm * cachedGlyphMetrics->advanceWidth;
                ah = designToEm * cachedGlyphMetrics->advanceHeight; 
                lsb = designToEm * cachedGlyphMetrics->lsb; 
                rsb = designToEm * cachedGlyphMetrics->rsb;
                tsb = designToEm * cachedGlyphMetrics->tsb; 
                bsb = designToEm * cachedGlyphMetrics->bsb;
                baseline = designToEm * cachedGlyphMetrics->baseline;

                if ((_styleSimulations & StyleSimulations.BoldSimulation) != 0) 
                {
                    // Bold simulation increases advance width and advance height by 2% of em size, 
                    // except for glyphs that are empty or have zero advance widths. 
                    // So, we compensate for the simulation when aw != 0 && left < right && ah != 0 && bottom > top
                    if (cachedGlyphMetrics->advanceWidth != 0 && 
                        cachedGlyphMetrics->lsb < cachedGlyphMetrics->advanceWidth - cachedGlyphMetrics->rsb &&
                        cachedGlyphMetrics->advanceHeight != 0 &&
                        cachedGlyphMetrics->advanceHeight - cachedGlyphMetrics->tsb - cachedGlyphMetrics->bsb > 0)
                    { 
                        aw += 0.02 * renderingEmSize;
                        ah += 0.02 * renderingEmSize; 
                    } 
                }
            } 
        }

        /// 
        /// Returns a geometry describing the path for a single glyph in the font. 
        /// The path represents the glyph
        /// without grid fitting applied for rendering at a specific resolution. 
        ///  
        /// Index of the glyph to get outline for.
        /// Specifies whether the glyph should be rotated sideways. 
        /// Font size in drawing surface units.
        /// Size to hint for in points.
        /// Geometry containing glyph outline.
        ///  
        /// Critical - as this calls GetGlyphs() which is critical.
        /// Safe - as this doesn't expose font information but just gives out a Geometry. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal Geometry ComputeGlyphOutline(ushort glyphIndex, bool sideways, double renderingEmSize, double hintingEmSize) 
        {
            CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
            using (GlyphPathElement pathElement = new GlyphPathElement(
                _fontFace.FaceIndex, 
                _fontFace.FontSource,
                GetRenderingFlags(sideways), 
                DesignEmHeight 
            ))
            { 
                PathGeometry pathGeometry;
                unsafe
                {
                    void*[] glyphOutlines = new void*[1]; 
                    FontCacheAccessor fontCacheAccessor = new FontCacheAccessor();
                    ushort[] glyphIndices = new ushort[1] { glyphIndex }; 
                    fontCacheAccessor.GetGlyphs( 
                        pathElement,
                        glyphIndices, 
                        glyphOutlines
                    );

                    void * outline = glyphOutlines[0]; 

                    Debug.Assert(outline != null); 
 
                    if (FontTechnology == FontTechnology.PostscriptOpenType)
                        ConvertPostscriptOutline(outline, renderingEmSize, sideways, out pathGeometry); 
                    else
                        ConvertTrueTypeOutline(outline, renderingEmSize, sideways, out pathGeometry);

                    // Make sure fontCacheAccessor doesn't go out of scope before the outlines get converted. 
                    GC.KeepAlive(fontCacheAccessor);
                } 
 
                // Make sure to always return Geometry.Empty from public methods for empty geometries.
                if (pathGeometry == null || pathGeometry.IsEmpty()) 
                    return Geometry.Empty;
                return pathGeometry;
            }
        } 

        ///  
        /// Critical - unsafe code, accepts pointer parameters, etc. 
        /// 
        [SecurityCritical] 
        private unsafe void ConvertTrueTypeOutline(void* trueTypeOutline, double renderingEmSize, bool sideways, out PathGeometry pathGeometry)
        {
            GlyphPathData * outline = (GlyphPathData *)trueTypeOutline;
 
            // scale factor from design units to user coordinate system
 
            double designToUserScale = renderingEmSize / DesignEmHeight; 
            Matrix designToUser = new Matrix(designToUserScale, 0, 0, -designToUserScale, 0, 0);
            if (sideways) 
            {
                designToUser.Rotate(-90.0);
                designToUser.Translate(outline->verOriginY * designToUserScale, outline->verOriginX * designToUserScale);
            } 

            ushort* endp = GlyphPathData.EndPointNumbers(outline); 
            short* x = GlyphPathData.X(outline); 
            short* y = GlyphPathData.Y(outline);
            byte* flags = GlyphPathData.Flags(outline); 

            // k is the index of the first point of the current contour
            int k = 0;
 
            pathGeometry = null;
 
            // j is the index of the current contour 
            for (int j = 0; j < outline->numberOfContours; ++j)
            { 
                int lastPointIndex = endp[j];
                if (lastPointIndex <= k)
                {
                    k = lastPointIndex + 1; 
                    continue; //  empty contour
                } 
 
                Point startPoint;
 
                PathFigure figure = new PathFigure();

                // The first point on the curve
                if (OnCurve(flags[k])) 
                {
                    // Easy case 
                    startPoint = designToUser.Transform(new Point(x[k], y[k])); 
                    ++k;
                } 
                else
                {
                    // Is last contour point on the curve
                    if (OnCurve(flags[lastPointIndex])) 
                    {
                        // Make the last point the first point and decrement the last point 
                        startPoint = designToUser.Transform(new Point(x[lastPointIndex], y[lastPointIndex])); 
                        --lastPointIndex;
                    } 
                    else
                    {
                        // First and last point are off the countour, fake a mid point
                        Point firstPoint = designToUser.Transform(new Point(x[k], y[k])); 
                        Point lastPoint = designToUser.Transform(new Point(x[lastPointIndex], y[lastPointIndex]));
                        startPoint = new Point( 
                            (firstPoint.X + lastPoint.X) / 2, 
                            (firstPoint.Y + lastPoint.Y) / 2
                        ); 
                    }
                }

                figure.StartPoint = startPoint; 

                bool inBezier = false; 
                Point bezierB = new Point(); 
                while (k <= lastPointIndex)
                { 
                    Point currentPoint = designToUser.Transform(new Point(x[k], y[k]));

                    if (OnCurve(flags[k]))
                    { 
                        if (!inBezier)
                        { 
                            figure.Segments.Add(new LineSegment(currentPoint, true)); 
                        }
                        else 
                        {
                            figure.Segments.Add(new QuadraticBezierSegment(bezierB, currentPoint, true));
                            inBezier = false;
                        } 
                    }
                    else 
                    { 
                        if (inBezier)
                        { 
                            figure.Segments.Add(new QuadraticBezierSegment(
                                bezierB,
                                new Point(
                                    (bezierB.X + currentPoint.X) / 2, 
                                    (bezierB.Y + currentPoint.Y) / 2
                                ), 
                                true) 
                            );
                        } 
                        inBezier = true;
                        bezierB = currentPoint;
                    }
                    ++k; 
                }
 
                // explicitly set k to the start point of the next contour 
                // since in some cases lastPointIndex is not equal to endp[j]
                k = endp[j] + 1; 

                // close the figure, assume start point is always on curve
                if (inBezier)
                { 
                    figure.Segments.Add(new QuadraticBezierSegment(bezierB, startPoint, true));
                } 
 
                figure.IsClosed = true;
 
                if (pathGeometry == null)
                {
                    pathGeometry = new PathGeometry();
                    pathGeometry.FillRule = FillRule.Nonzero; 
                }
 
                pathGeometry.Figures.Add(figure); 
            }
        } 

        /// 
        /// Critical - unsafe code, accepts pointer parameters, etc.
        ///  
        [SecurityCritical]
        private unsafe void ConvertPostscriptOutline(void * outline, double renderingEmSize, bool sideways, out PathGeometry pathGeometry) 
        { 
            int * postscriptOutline = (int *)outline;
 
            // scale factor from design units to user coordinate system

            double designToUserScale = renderingEmSize / DesignEmHeight;
            Matrix designToUser = new Matrix(designToUserScale, 0, 0, -designToUserScale, 0, 0); 
            if (sideways)
            { 
                int verOriginX = postscriptOutline[0]; 
                int verOriginY = postscriptOutline[1];
 
                designToUser.Rotate(-90.0);
                designToUser.Translate(verOriginY * designToUserScale, verOriginX * designToUserScale);
            }
 
            // Skip vertical origin and length to get to the actual contour data.
            int * p = postscriptOutline + 3; 
            Debug.Assert(postscriptOutline[2] % sizeof(int) == 0); 
            int * end = p + (postscriptOutline[2] / sizeof(int));
 
            pathGeometry = null;

            // Current figure.
            PathFigure figure = null; 

            for (;;) 
            { 
                if (p >= end)
                    break; 

                int tokenValue = *p;

                switch ((OutlineTokenType)tokenValue) 
                {
                case OutlineTokenType.MoveTo: 
                    { 
                        ++p;
                        if (p + 1 >= end) 
                            throw new FileFormatException(_originalUri.Value);

                        Point point = designToUser.Transform(
                            new Point(p[0] * CFFConversionFactor, p[1] * CFFConversionFactor) 
                            );
 
                        if (figure == null) 
                            figure = new PathFigure();
 
                        figure.StartPoint = point;

                        p += 2;
                        break; 
                    }
 
                case OutlineTokenType.LineTo: 
                    {
                        ++p; 
                        if (p + 1 >= end)
                            throw new FileFormatException(_originalUri.Value);

                        Point point = designToUser.Transform( 
                            new Point(p[0] * CFFConversionFactor, p[1] * CFFConversionFactor)
                            ); 
 
                        if (figure == null)
                            throw new FileFormatException(_originalUri.Value); 

                        figure.Segments.Add(new LineSegment(point, true));

                        p += 2; 
                        break;
                    } 
 
                case OutlineTokenType.CurveTo:
                    { 
                        ++p;
                        if (p + 5 >= end)
                            throw new FileFormatException(_originalUri.Value);
 
                        Point point0 = designToUser.Transform(
                            new Point(p[0] * CFFConversionFactor, p[1] * CFFConversionFactor) 
                            ); 
                        Point point1 = designToUser.Transform(
                            new Point(p[2] * CFFConversionFactor, p[3] * CFFConversionFactor) 
                            );
                        Point point2 = designToUser.Transform(
                            new Point(p[4] * CFFConversionFactor, p[5] * CFFConversionFactor)
                            ); 

                        if (figure == null) 
                            throw new FileFormatException(_originalUri.Value); 

                        figure.Segments.Add(new BezierSegment(point0, point1, point2, true)); 
                        p += 6;
                        break;
                    }
 
                case OutlineTokenType.ClosePath:
                    if (figure == null) 
                        throw new FileFormatException(_originalUri.Value); 

                    figure.IsClosed = true; 

                    if (pathGeometry == null)
                    {
                        pathGeometry = new PathGeometry(); 
                        pathGeometry.FillRule = FillRule.Nonzero;
                    } 
 
                    pathGeometry.Figures.Add(figure);
                    figure = null; 
                    ++p;
                    break;

                default: 
                    throw new FileFormatException(_originalUri.Value);
                } 
            } 
        }
 

        /// 
        /// Get advance widths of unshaped characters
        ///  
        /// character string
        /// character length 
        /// character em size 
        /// unshaped advance widths 
        /// true if all characters map to missing glyph 
        /// array of character advance widths
        /// 
        /// Critical - takes unsafe char string and returns information in an unsafe int array
        ///  
        [SecurityCritical]
        internal unsafe void GetAdvanceWidthsUnshaped( 
            char* unsafeCharString, 
            int stringLength,
            double emSize, 
            int* advanceWidthsUnshaped,
            bool nullFont
            )
        { 
            CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
            Invariant.Assert(stringLength > 0); 
 
            if (!nullFont)
            { 
                IDictionary cmap = CharacterToGlyphMap;
                for (int i = 0; i < stringLength; i++)
                {
                    ushort glyphIndex; 
                    cmap.TryGetValue(unsafeCharString[i], out glyphIndex);
                    advanceWidthsUnshaped[i] = (int)Math.Round(emSize * GetAdvanceWidth(glyphIndex)); 
                } 
            }
            else 
            {
                int missingGlyphWidth = (int)Math.Round(emSize * GetAdvanceWidth(0));
                for (int i = 0; i < stringLength; i++)
                { 
                    advanceWidthsUnshaped[i] = missingGlyphWidth;
                } 
            } 
        }
 
        /// 
        /// Compute an unshaped glyphrun object from specified character-based info
        /// 
        internal GlyphRun ComputeUnshapedGlyphRun( 
            Point origin,
            CharacterBufferRange charBufferRange, 
            IList charWidths, 
            double emSize,
            double emHintingSize, 
            bool nullGlyph,
            CultureInfo cultureInfo,
            string deviceFontName
            ) 
        {
            Debug.Assert(charBufferRange.Length > 0); 
 
            CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
 
            ushort[] nominalGlyphs = new ushort[charBufferRange.Length];


            // compute glyph positions 

            if (nullGlyph) 
            { 
                for (int i = 0; i < charBufferRange.Length; i++)
                { 
                    nominalGlyphs[i] = 0;
                }
            }
            else 
            {
                IDictionary cmap = CharacterToGlyphMap; 
 
                for (int i = 0; i < charBufferRange.Length; i++)
                { 
                    ushort glyphIndex;
                    cmap.TryGetValue(charBufferRange[i], out glyphIndex);
                    nominalGlyphs[i] = glyphIndex;
                } 
            }
 
            return GlyphRun.TryCreate( 
                this,
                0,      // bidiLevel 
                false,  // sideway
                emSize,
                nominalGlyphs,
                origin, 
                charWidths,
                null,   // glyphOffsets 
                new PartialList(charBufferRange.CharacterBuffer, charBufferRange.OffsetToFirstChar, charBufferRange.Length), 
                deviceFontName,   // device font
                null,   // 1:1 mapping 
                null,   // caret stops at every codepoint
                XmlLanguage.GetLanguage(cultureInfo.IetfLanguageTag)
                );
        } 

 
        #endregion Internal Methods 

        //----------------------------------------------------- 
        //
        //  Internal Properties
        //
        //----------------------------------------------------- 

        #region Internal Properties 
 
        internal FontSource FontSource
        { 
            get
            {
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return _fontFace.FontSource; 
            }
        } 
 
        /// 
        /// 0 for TTF files 
        /// Face index within TrueType font collection for TTC files
        /// 
        internal int FaceIndex
        { 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return _fontFace.FaceIndex;
            } 
        }

        internal FontFaceLayoutInfo FontFaceLayoutInfo
        { 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return _fontFace;
            } 
        }

        internal ushort BlankGlyphIndex
        { 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return _fontFace.BlankGlyph;
            } 
        }

        internal FontFaceLayoutInfo.RenderingHints RenderingHints
        { 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return _fontFace.FontRenderingHints;
            } 
        }

        internal FontTechnology FontTechnology
        { 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                return _fontFace.FontTechnology;
            } 
        }

        internal short FontContrastAdjustment
        { 
            get
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface 
                Debug.Assert(-3 <= _fontFace.FontContrastAdjustment && _fontFace.FontContrastAdjustment <= 4);
                return _fontFace.FontContrastAdjustment; 
            }
        }

        internal ushort DesignEmHeight 
        {
            get 
            { 
                CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
                return _fontFace.DesignEmHeight; 
            }
        }

        #endregion Internal Properties 

        //----------------------------------------------------- 
        // 
        //  Private Methods
        // 
        //------------------------------------------------------

        #region Private Methods
 
        private static bool OnCurve(byte flag)
        { 
            return (flag & 0x01) != 0; 
        }
 
        private ushort GetRenderingFlags(bool sideways)
        {
            ushort renderingFlags = 0;
            if ((_styleSimulations & StyleSimulations.BoldSimulation) != 0) 
                renderingFlags |= (ushort)RenderingFlags.BoldSimulation;
            if ((_styleSimulations & StyleSimulations.ItalicSimulation) != 0) 
            { 
                renderingFlags |= (ushort)RenderingFlags.ItalicSimulation;
                if (sideways) 
                    renderingFlags |= (ushort)RenderingFlags.SidewaysItalicSimulation;
            }
            if (FontTechnology != FontTechnology.PostscriptOpenType)
                renderingFlags |= (ushort)MIL_GLYPHRUN_FLAGS.MilGlyphRunIsTrueType; 
            return renderingFlags;
        } 
 
        #endregion Private Methods
 
        #region ISupportInitialize interface

        void ISupportInitialize.BeginInit()
        { 
            if (_initializationState == InitializationState.IsInitialized)
            { 
                // Cannont initialize a GlyphRun this is completely initialized. 
                throw new InvalidOperationException(SR.Get(SRID.OnlyOneInitialization));
            } 

            if (_initializationState == InitializationState.IsInitializing)
            {
                // Cannot initialize a GlyphRun this already being initialized. 
                throw new InvalidOperationException(SR.Get(SRID.InInitialization));
            } 
 
            _initializationState = InitializationState.IsInitializing;
        } 

        /// 
        /// Critical - this method calls into critical method.
        ///  
        [SecurityCritical]
        void ISupportInitialize.EndInit() 
        { 
            if (_initializationState != InitializationState.IsInitializing)
            { 
                // Cannot EndInit a GlyphRun that is not being initialized.
                throw new InvalidOperationException(SR.Get(SRID.NotInInitialization));
            }
 
            Initialize(
                (_originalUri == null ? null : _originalUri.Value), 
                 _styleSimulations, 
                 true
                 ); 
        }

        private void CheckInitialized()
        { 
            if (_initializationState != InitializationState.IsInitialized)
            { 
                throw new InvalidOperationException(SR.Get(SRID.InitializationIncomplete)); 
            }
        } 

        private void CheckInitializing()
        {
            if (_initializationState != InitializationState.IsInitializing) 
            {
                throw new InvalidOperationException(SR.Get(SRID.NotInInitialization)); 
            } 
        }
 
        #endregion

        //-----------------------------------------------------
        // 
        //  Private Nested Classes
        // 
        //------------------------------------------------------ 

        #region Private Nested Classes 

        private delegate double GlyphAccessor(ushort glyphIndex);

        ///  
        /// This class is a helper to implement named indexers
        /// for glyph metrics. 
        ///  
        private class GlyphIndexer : IDictionary
        { 
            internal GlyphIndexer(GlyphAccessor accessor, ushort numberOfGlyphs)
            {
                _accessor = accessor;
                _numberOfGlyphs = numberOfGlyphs; 
            }
 
            #region IDictionary Members 

            public void Add(ushort key, double value) 
            {
                throw new NotSupportedException();
            }
 
            public bool ContainsKey(ushort key)
            { 
                return (key < _numberOfGlyphs); 
            }
 
            public ICollection Keys
            {
                get { return new SequentialUshortCollection(_numberOfGlyphs); }
            } 

            public bool Remove(ushort key) 
            { 
                throw new NotSupportedException();
            } 

            public bool TryGetValue(ushort key, out double value)
            {
                if (ContainsKey(key)) 
                {
                    value = this[key]; 
                    return true; 
                }
                else 
                {
                    value = new double();
                    return false;
                } 
            }
 
            public ICollection Values 
            {
                get { return new ValueCollection(this); } 
            }

            public double this[ushort key]
            { 
                get
                { 
                    return _accessor(key); 
                }
                set 
                {
                    throw new NotSupportedException();
                }
            } 

            #endregion 
 
            #region ICollection> Members
 
            public void Add(KeyValuePair item)
            {
                throw new NotSupportedException();
            } 

            public void Clear() 
            { 
                throw new NotSupportedException();
            } 

            public bool Contains(KeyValuePair item)
            {
                return ContainsKey(item.Key); 
            }
 
            public void CopyTo(KeyValuePair[] array, int arrayIndex) 
            {
                if (array == null) 
                {
                    throw new ArgumentNullException("array");
                }
 
                if (array.Rank != 1)
                { 
                    throw new ArgumentException(SR.Get(SRID.Collection_BadRank)); 
                }
 
                // The extra "arrayIndex >= array.Length" check in because even if _collection.Count
                // is 0 the index is not allowed to be equal or greater than the length
                // (from the MSDN ICollection docs)
                if (arrayIndex < 0 || arrayIndex >= array.Length || (arrayIndex + Count) > array.Length) 
                {
                    throw new ArgumentOutOfRangeException("arrayIndex"); 
                } 

                for (ushort i = 0; i < Count; ++i) 
                    array[arrayIndex + i] = new KeyValuePair(i, this[i]);
            }

            public int Count 
            {
                get { return _numberOfGlyphs; } 
            } 

            public bool IsReadOnly 
            {
                get { return true; }
            }
 
            public bool Remove(KeyValuePair item)
            { 
                throw new NotSupportedException(); 
            }
 
            #endregion

            #region IEnumerable> Members
 
            public IEnumerator> GetEnumerator()
            { 
                for (ushort i = 0; i < Count; ++i) 
                    yield return new KeyValuePair(i, this[i]);
            } 

            #endregion

            #region IEnumerable Members 

            IEnumerator IEnumerable.GetEnumerator() 
            { 
                return ((IEnumerable>)this).GetEnumerator();
            } 

            #endregion

            private class ValueCollection : ICollection 
            {
                public ValueCollection(GlyphIndexer glyphIndexer) 
                { 
                    _glyphIndexer = glyphIndexer;
                } 

                #region ICollection Members

                public void Add(double item) 
                {
                    throw new NotSupportedException(); 
                } 

                public void Clear() 
                {
                    throw new NotSupportedException();
                }
 
                public bool Contains(double item)
                { 
                    foreach (double d in this) 
                    {
                        if (d == item) 
                            return true;
                    }
                    return false;
                } 

                public void CopyTo(double[] array, int arrayIndex) 
                { 
                    if (array == null)
                    { 
                        throw new ArgumentNullException("array");
                    }

                    if (array.Rank != 1) 
                    {
                        throw new ArgumentException(SR.Get(SRID.Collection_BadRank)); 
                    } 

                    // The extra "arrayIndex >= array.Length" check in because even if _collection.Count 
                    // is 0 the index is not allowed to be equal or greater than the length
                    // (from the MSDN ICollection docs)
                    if (arrayIndex < 0 || arrayIndex >= array.Length || (arrayIndex + Count) > array.Length)
                    { 
                        throw new ArgumentOutOfRangeException("arrayIndex");
                    } 
 
                    for (ushort i = 0; i < Count; ++i)
                        array[arrayIndex + i] = _glyphIndexer[i]; 
                }

                public int Count
                { 
                    get { return _glyphIndexer._numberOfGlyphs; }
                } 
 
                public bool IsReadOnly
                { 
                    get { return true; }
                }

                public bool Remove(double item) 
                {
                    throw new NotSupportedException(); 
                } 

                #endregion 

                #region IEnumerable Members

                public IEnumerator GetEnumerator() 
                {
                    for (ushort i = 0; i < Count; ++i) 
                        yield return _glyphIndexer[i]; 
                }
 
                #endregion

                #region IEnumerable Members
 
                IEnumerator IEnumerable.GetEnumerator()
                { 
                    return ((IEnumerable)this).GetEnumerator(); 
                }
 
                #endregion

                private GlyphIndexer _glyphIndexer;
            } 

            private GlyphAccessor _accessor; 
            private ushort _numberOfGlyphs; 
        }
 
        #endregion Private Nested Classes

        //------------------------------------------------------
        // 
        //  Private Fields
        // 
        //----------------------------------------------------- 

        #region Private Fields 

        private FontFaceLayoutInfo  _fontFace;

        private StyleSimulations    _styleSimulations; 

        ///  
        /// The Uri that was passed in to constructor. 
        /// 
        ///  
        ///     This is critical as we do a demand based on this value public functions.
        ///     Only setting this Uri is critical, getting is fine.  Hence using the
        ///     SecurityCriticalDataForSet object.  Note that the object itself does not
        ///     need to be Critical, it's just setting it that makes it Critical. 
        /// 
        private SecurityCriticalDataClass _originalUri; 
 
        /// 
        /// Critical - as this object controls the Demand that'll be made before accessssing the 
        ///            security sensitive contents of the font file.  This also only Critical
        ///            for set.  This should be correctly whenever _originalUri is set.
        ///
        /// Caching object for perf reasons. 
        /// 
        private SecurityCriticalDataForSet _fileIOPermObj; 
 
        private const double CFFConversionFactor = 1.0 / 65536.0;
 
        private InitializationState _initializationState;

        /// 
        /// Initialization states of GlyphTypeface object. 
        /// 
        private enum InitializationState 
        { 
            /// 
            /// The state in which the GlyphTypeface has not been initialized. 
            /// At this state, all operations on the object would cause InvalidOperationException.
            /// The object can only transit to 'IsInitializing' state with BeginInit() call.
            /// 
            Uninitialized, 

            ///  
            /// The state in which the GlyphTypeface is being initialized. At this state, user can 
            /// set values into the required properties. The object can only transit to 'IsInitialized' state
            /// with EndInit() call. 
            /// 
            IsInitializing,

            ///  
            /// The state in which the GlyphTypeface object is fully initialized. At this state the object
            /// is fully functional. There is no valid transition out of the state. 
            ///  
            IsInitialized,
        } 

        #endregion Private Fields
    }
} 

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