GlyphTypeface.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / Media / GlyphTypeface.cs / 1 / GlyphTypeface.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: GlyphTypeface implementation 
//
// History: 
//  06/04/2003 : mleonov - 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 
            // NOTE: This parameter is unused, and should be deleted. Not worth a breaking change just for this though.
            return ComputeGlyphOutline(glyphIndex, false, renderingEmSize); 
        }

        /// 
        /// 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 ----, 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 ----, 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.
        /// 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) 
        {
            CheckInitialized(); // This can only be called on fully initialized GlyphTypeface

            using (GlyphPathElement pathElement = new GlyphPathElement( 
                FaceIndex,
                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)MilGlyphRun.IsTrueType;
            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.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: GlyphTypeface implementation 
//
// History: 
//  06/04/2003 : mleonov - 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 
            // NOTE: This parameter is unused, and should be deleted. Not worth a breaking change just for this though.
            return ComputeGlyphOutline(glyphIndex, false, renderingEmSize); 
        }

        /// 
        /// 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 ----, 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 ----, 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.
        /// 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) 
        {
            CheckInitialized(); // This can only be called on fully initialized GlyphTypeface

            using (GlyphPathElement pathElement = new GlyphPathElement( 
                FaceIndex,
                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)MilGlyphRun.IsTrueType;
            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