FontFaceLayoutInfo.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / MS / Internal / FontCache / FontFaceLayoutInfo.cs / 1 / FontFaceLayoutInfo.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Description: The FontFaceLayoutInfo class 
//
// History: 
//  07/23/2003 : mleonov - Big rewrite to change cache structure 
//
//--------------------------------------------------------------------------- 

using System;
using System.Diagnostics;
using System.Globalization; 
using System.IO;
using System.Security; 
using System.ComponentModel; 
using System.Collections;
using System.Collections.Generic; 
using System.Security.Permissions;
using System.Windows;
using System.Windows.Media;
using System.Runtime.InteropServices; 

using MS.Win32; 
using MS.Utility; 
using MS.Internal;
using MS.Internal.FontFace; 
using MS.Internal.Shaping;

using MS.Internal.PresentationCore;
 
namespace MS.Internal.FontCache
{ 
    [FriendAccessAllowed] 
    internal sealed class FontFaceLayoutInfo : IFontCacheElement
    { 
        //-----------------------------------------------------
        //
        //  Constructors
        // 
        //-----------------------------------------------------
 
        #region Constructors 

        internal FontFaceLayoutInfo(FontSource fontSource, int faceIndex) 
        {
            _fontSource = fontSource;
            _faceIndex = faceIndex;
            _timeStamp = _fontSource.SkipLastWriteTime(); 
        }
 
        ///  
        /// Critical -  Calls into the critical RetrieveKey method.
        ///  
        [SecurityCritical]
        internal FontFaceLayoutInfo(CheckedPointer key)
        {
            RetrieveKey(key); 
        }
 
        #endregion Constructors 

        // layout: struct | FileName | 4byte aligned CMAP (17 int pointers to planes) 
        // the structure size should be aligned on 2 byte boundary, because file name is stored
        // immediately after the structure.
        // As usual, individual structure members need to be properly aligned.
        [StructLayout(LayoutKind.Explicit, Size = Layout.keyOffset + 8)] 
        private struct Layout
        { 
            [FieldOffset(0)] 
            internal ushort designEmHeight;
            [FieldOffset(2)] 
            internal ushort glyphCount;
            [FieldOffset(4)]
            internal ushort designCellAscent;
            [FieldOffset(6)] 
            internal ushort designCellDescent;
 
            [FieldOffset(8)] 
            internal short  fontContrastAdjustment;
 
            [FieldOffset(10)]
            internal short  xHeight;
            [FieldOffset(12)]
            internal short  capsHeight; 

            [FieldOffset(14)] 
            internal ushort blankGlyph; 
            [FieldOffset(16)]
            internal ushort invalidGlyph; 

            [FieldOffset(18)]
            internal ushort underlineSize;
            [FieldOffset(20)] 
            internal short  underlinePosition;
 
            [FieldOffset(22)] 
            internal ushort strikeThroughSize;
            [FieldOffset(24)] 
            internal short  strikeThroughPosition;

            [FieldOffset(26)]
            internal ushort symbol; 

            // RenderingHints is a ushort enum, so 2 bytes are enough. 
            [FieldOffset(28)] 
            internal RenderingHints renderingHints;
 
            [FieldOffset(30)]
            internal ushort embeddingRights;

            [FieldOffset(32)] 
            internal long timeStamp;
 
            [FieldOffset(40)] 
            internal long gsubScripts;
            [FieldOffset(48)] 
            internal long gposScripts;

            [FieldOffset(56)]
            internal int offAdvanceWidths;    // offset of the advance width array 
            [FieldOffset(60)]
            internal int offGsub;             // ditto for GSUB 
            [FieldOffset(64)] 
            internal int offGpos;             // ditto for GPOS
            [FieldOffset(68)] 
            internal int offGdef;             // ditto for GDEF
            [FieldOffset(72)]
            internal int offJstf;             // ditto for JSTF
 
            [FieldOffset(76)]
            internal int familyNames; 
            [FieldOffset(80)] 
            internal int win32FamilyNames;
            [FieldOffset(84)] 
            internal int faceNames;
            [FieldOffset(88)]
            internal int win32faceNames;
            [FieldOffset(92)] 
            internal int versionStrings;
            [FieldOffset(96)] 
            internal int copyrights; 
            [FieldOffset(100)]
            internal int manufacturerNames; 
            [FieldOffset(104)]
            internal int trademarks;
            [FieldOffset(108)]
            internal int designerNames; 
            [FieldOffset(112)]
            internal int descriptions; 
            [FieldOffset(116)] 
            internal int vendorUrls;
            [FieldOffset(120)] 
            internal int designerUrls;
            [FieldOffset(124)]
            internal int licenseDescriptions;
            [FieldOffset(128)] 
            internal int sampleTexts;
 
            [FieldOffset(132)] 
            internal FontStyle style;
            [FieldOffset(136)] 
            internal FontWeight weight;
            [FieldOffset(140)]
            internal FontStretch stretch;
 
            [FieldOffset(144)]
            internal double version; 
 
            [FieldOffset(152)]
            internal int offGaspRanges; 

            [FieldOffset(156)]
            internal TypographyAvailabilities typographyAvailabilities;
 
            [FieldOffset(160)]
            internal FontTechnology fontTechnology; 
 
            [FieldOffset(164)]
            internal int offGsubCache; 

            [FieldOffset(168)]
            internal int gsubCacheLength;
 
            [FieldOffset(172)]
            internal int offGposCache; 
 
            [FieldOffset(176)]
            internal int gposCacheLength; 

            // family and face names adjusted by the font differentiator
            [FieldOffset(180)]
            internal int adjustedFaceNames; 

            // this should be equal to the offset immediately after the previous field 
            internal const int keyOffset = 184; 

            // key starts here 
            [FieldOffset(keyOffset)]
            internal int faceIndex;
            [FieldOffset(keyOffset + 4)]
            internal int uriStringSizeInBytes; 

 
 
            internal static CheckedPointer GetUriString(CheckedPointer This)
            { 
                unsafe
                {
                    return This + sizeof(Layout);
                } 
            }
 
            ///  
            ///     Critical: Calls into probe which is critical and also has unsafe code blocks
            ///     TreatAsSafe: It advances the pointer by the requisite number of bytes . 
            ///     Calls to probe and '+ are bounds checked.
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            internal static CheckedPointer GetCmap(CheckedPointer This) 
            {
                unsafe 
                { 
                    Layout* l = (Layout*)This.Probe(0, sizeof(Layout));
                    return GetUriString(This) + Util.Align4(l->uriStringSizeInBytes); 
                }
            }
        }
 
        [StructLayout(LayoutKind.Explicit, Size = 12)]
        private struct CachedName 
        { 
            [FieldOffset(0)]
            internal int language; 

            [FieldOffset(4)]
            internal int nameSize;
 
            /// 
            /// Offset to the name string 
            ///  
            [FieldOffset(8)]
            internal int nameString; 
        }

        [StructLayout(LayoutKind.Explicit, Size = 4)]
        private struct CachedNames 
        {
            [FieldOffset(0)] 
            internal int numberOfNames; 

            // followed by array of CachedName structures 
        }

        internal FontSource FontSource
        { 
            get
            { 
                return _fontSource; 
            }
        } 

        internal int FaceIndex
        {
            get 
            {
                return _faceIndex; 
            } 
        }
 
        int IFontCacheElement.Type
        {
            get
            { 
                return 3;
            } 
        } 

        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks
        ///     TreatAsSafe: This stores data about the font into a pointer. This data is safe to
        ///     expose and the pointer operations are bounds checked.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private void StoreKeyInternal(CheckedPointer d, out int realSize) 
        { 
            unsafe
            { 
                int* k = (int*)d.Probe(0, sizeof(int));
                *k = _faceIndex;
                realSize = sizeof(int);
                d += sizeof(int); 
                realSize += Util.StringAndLengthCopyToCheckedPointer(d, FontSource.GetUriString());
            } 
        } 

        void IFontCacheElement.StoreKey(CheckedPointer d, out int realSize) 
        {
            Debug.Assert(!_fontSource.IsAppSpecific);
            StoreKeyInternal(d, out realSize);
        } 

        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks. 
        ///     Calls into the critical FontSource constructor.
        ///  
        [SecurityCritical]
        public void RetrieveKey(CheckedPointer p)
        {
            unsafe 
            {
                _faceIndex = *(int*)p.Probe(0, sizeof(int)); 
                string fileName = Util.StringAndLengthCopyFromCheckedPointer(p + sizeof(int)); 
                _fontSource = new FontSource(new Uri(fileName, UriKind.Absolute), false);
            } 
            _timeStamp = _fontSource.SkipLastWriteTime();
        }

        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks
        ///     TreatAsSafe: The call to probe is bounds checked and also the pointers returned 
        ///     are used locally and not passed around. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        bool IFontCacheElement.Match(CheckedPointer p)
        {
            unsafe
            { 
                Layout* l = (Layout*)p.Probe(0, sizeof(Layout));
                string fontUriString = FontSource.GetUriString(); 
                if (Util.StringSize(fontUriString) != l->uriStringSizeInBytes) 
                    return false;
 
                if (_timeStamp != l->timeStamp)
                    return false;

                if (_faceIndex != l->faceIndex) 
                    return false;
 
                return Util.StringEqualIgnoreCase(Layout.GetUriString(p), fontUriString); 
            }
        } 

        /// 
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks. It
        ///     accesses _layout which is a pointer 
        ///     TreatAsSafe: This data is ok to give out, also storing the checked pointer is
        ///     ok 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        void IFontCacheElement.GetData(CheckedPointer block, ElementCacher cacher) 
        {
            unsafe
            {
                _cacher = cacher; 
                _layout = (Layout*)block.Probe(0, sizeof(Layout));
                _timeStamp = _layout->timeStamp; 
                _cmap = new IntMap(Layout.GetCmap(block), _cacher); 
                _cmap.SetGlyphCount(_layout->glyphCount);
            } 
        }

        /// 
        /// Critical - As this function accesses FileName that contains absolute font path. 
        /// Safe - As this is only used to compute the cache element size.
        ///  
        int IFontCacheElement.Size 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                unsafe
                { 
                    return
                        sizeof(Layout) + 
                        Util.Align4(Util.StringSize(FontSource.GetUriString())) + 
                        IntMap.InitialSize();
                } 
            }
        }

        bool IFontCacheElement.IsAppSpecific 
        {
            get 
            { 
                return _fontSource.IsAppSpecific;
            } 
        }

        int IFontCacheElement.GetHashCode()
        { 
            int hash = FontSource.GetHashCode();
            hash = HashFn.HashMultiply(hash) + _faceIndex; 
            return HashFn.HashScramble(hash); 
        }
 
        /// 
        /// Critical - As this function obtains UnmanagedMemoryStream from FontSource.Pin()
        ///            which is Critical.
        /// Safe - As this is only used to add font information to the cache which is safe. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        void IFontCacheElement.AddToCache(CheckedPointer newPointer, ElementCacher cacher) 
        {
            _cacher = cacher; 
            int realSize;
            StoreKeyInternal(newPointer + Layout.keyOffset, out realSize);

            unsafe 
            {
                _layout = (Layout*)newPointer.Probe(0, sizeof(Layout)); 
 
                Debug.Assert(_timeStamp != 0);
 
                _layout->timeStamp = _timeStamp;

                // initialize optional table pointers
                _layout->offGsub = 
                    _layout->offGpos =
                    _layout->offGdef = 
                    _layout->offJstf = 
                    _layout->offGaspRanges =
                    Util.nullOffset; 

                _cmap = new IntMap(Layout.GetCmap(newPointer), _cacher);
            }
            _cmap.Init(); 

            UnmanagedMemoryStream pinnedFontSource = _fontSource.GetUnmanagedStream(); 
 
            try
            { 
                TrueTypeFontDriver ttd = new TrueTypeFontDriver(pinnedFontSource, _fontSource.Uri);
                ttd.SetFace(_faceIndex);
                ttd.GetLayoutFontFaceInfo(this);
                ttd.GetShapingFontFaceInfo(this); 
            }
            catch (SEHException e) 
            { 
                throw Util.ConvertInPageException(_fontSource, e);
            } 
            finally
            {
                pinnedFontSource.Close();
            } 

            unsafe 
            { 
                _layout->offGsubCache = Util.nullOffset;
                _layout->offGposCache = Util.nullOffset; 
                CreateOpenTypeLayoutCache();

                _layout->typographyAvailabilities = ComputeTypographyAvailabilities();
            } 

        } 
 
        /// 
        ///   Critical: Returns a writeable cmap. 
        ///  
        internal IntMap CharacterMap
        {
            [SecurityCritical] 
            get
            { 
                return _cmap; 
            }
        } 

        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This code exposes DesignEmHeight which is ok to expose 
        ///     The risk here is if _layout is null, but that is mitigated by probe.
        ///  
        internal ushort DesignEmHeight 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                unsafe { return _layout->designEmHeight; }
            } 
            [SecurityCritical]
            set 
            { 
                unsafe { _layout->designEmHeight = value; }
            } 
        }

        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing. 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty 
        ///      but that is mitigated by probe 
        /// 
        internal ushort DesignCellAscent 
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get
            { 
                unsafe { return _layout->designCellAscent; }
            } 
            [SecurityCritical] 
            set
            { 
                unsafe { _layout->designCellAscent = value; }
            }
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing. 
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe 
        /// 
        internal ushort DesignCellDescent
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                unsafe { return _layout->designCellDescent; } 
            }
            [SecurityCritical] 
            set
            {
                unsafe { _layout->designCellDescent = value; }
            } 
        }
 
        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe
        /// 
        internal short xHeight 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get 
            {
                unsafe { return _layout->xHeight; } 
            }
            [SecurityCritical]
            set
            { 
                unsafe { _layout->xHeight = value; }
            } 
        } 

        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///     but that is mitigated by probe 
        /// 
        internal short CapsHeight 
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            {
                unsafe { return _layout->capsHeight; }
            }
            [SecurityCritical] 
            set
            { 
                unsafe { _layout->capsHeight = value; } 
            }
        } 

        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe 
        ///  
        internal ushort BlankGlyph
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get
            {
                unsafe { return _layout->blankGlyph; } 
            }
            [SecurityCritical] 
            set 
            {
                unsafe { _layout->blankGlyph = value; } 
            }
        }

        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///  
        internal ushort InvalidGlyph 
        {
            [SecurityCritical] 
            set
            {
                unsafe { _layout->invalidGlyph = value; }
            } 
        }
 
        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe
        /// 
        internal ushort UnderlineThickness 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get 
            {
                unsafe { return _layout->underlineSize; } 
            }
            [SecurityCritical]
            set
            { 
                unsafe { _layout->underlineSize = value; }
            } 
        } 

        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe 
        /// 
        internal short UnderlinePosition 
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            {
                unsafe { return _layout->underlinePosition; }
            }
            [SecurityCritical] 
            set
            { 
                unsafe { _layout->underlinePosition = value; } 
            }
        } 

        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe 
        ///  
        internal ushort StrikethroughThickness
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get
            {
                unsafe { return _layout->strikeThroughSize; } 
            }
            [SecurityCritical] 
            set 
            {
                unsafe { _layout->strikeThroughSize = value; } 
            }
        }

        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty 
        ///      but that is mitigated by probe
        ///  
        internal short StrikethroughPosition
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            {
                unsafe { return _layout->strikeThroughPosition; } 
            } 
            [SecurityCritical]
            set 
            {
                unsafe { _layout->strikeThroughPosition = value; }
            }
        } 

        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing. 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty 
        ///      but that is mitigated by probe
        /// 
        internal bool Symbol
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            { 
                unsafe { return _layout->symbol != 0; }
            } 
            [SecurityCritical]
            set
            {
                unsafe { _layout->symbol = value ? (ushort)1 : (ushort)0; } 
            }
        } 
 
        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing. 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe
        ///  
        internal RenderingHints FontRenderingHints
        { 
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                unsafe { return _layout->renderingHints; }
            }
            [SecurityCritical]
            set 
            {
                unsafe { _layout->renderingHints = value; } 
            } 
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing,
        ///         the data is sensitive and is not OK to expose to untrusted clients.
        ///  
        internal FontEmbeddingRight EmbeddingRights
        { 
            [SecurityCritical] 
            get
            { 
                unsafe { return (FontEmbeddingRight)_layout->embeddingRights; }
            }
            [SecurityCritical]
            set 
            {
                // Make sure no truncation happens when storing the enum value as a ushort. 
                Invariant.Assert(value == (FontEmbeddingRight)(short)value); 

                unsafe { _layout->embeddingRights = (ushort)value; } 
            }
        }

        ///  
        ///     Critical: This calls into an unsafe code block, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty 
        ///      but that is mitigated by probe
        ///  
        internal FontTechnology FontTechnology
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            {
                unsafe { return _layout->fontTechnology; } 
            } 
            [SecurityCritical]
            set 
            {
                unsafe { _layout->fontTechnology = value; }
            }
        } 

 
        ///  
        ///     Critical: This calls into an unsafe code block, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe
        /// 
        internal short FontContrastAdjustment 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get 
            {
                unsafe { return _layout->fontContrastAdjustment; } 
            }
            [SecurityCritical]
            set
            { 
                unsafe { _layout->fontContrastAdjustment = value; }
            } 
        } 

 
        /// 
        ///     Critical: This calls into an unsafe code block, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty 
        ///      but that is mitigated by probe
        ///  
        internal FontStyle Style 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                unsafe { return _layout->style; }
            } 
            [SecurityCritical]
            set 
            { 
                unsafe { _layout->style = value; }
            } 
        }

        /// 
        ///     Critical: This calls into an unsafe code block, misusing the setter can result in spoofing. 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty 
        ///      but that is mitigated by probe 
        /// 
        internal FontWeight Weight 
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get
            { 
                unsafe { return _layout->weight; }
            } 
            [SecurityCritical] 
            set
            { 
                unsafe { _layout->weight = value; }
            }
        }
 
        /// 
        ///     Critical: This calls into an unsafe code block, misusing the setter can result in spoofing. 
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe 
        /// 
        internal FontStretch Stretch
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                unsafe { return _layout->stretch; } 
            }
            [SecurityCritical] 
            set
            {
                unsafe { _layout->stretch = value; }
            } 
        }
        ///  
        ///     Critical: This calls into an unsafe code block and exposes font version, 
        ///     which contains extra font information not strictly needed for rendering.
        ///  
        internal double Version
        {
            [SecurityCritical]
            get 
            {
                unsafe { return _layout->version; } 
            } 
        }
        ///  
        ///     Critical: This calls into an unsafe code block
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///     which is mitigated by tracking all sets to this 
        ///     variable
        ///  
        internal TypographyAvailabilities TypographyAvailabilities 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                unsafe { return _layout->typographyAvailabilities; }
            } 
        }
 
        [Flags] 
        internal enum GaspFlags : ushort
        { 
            GASP_GRIDFIT = 1,
            GASP_DOGRAY = 2,
            GASP_SYMMETRIC_GRIDFIT = 4,
            GASP_SYMMETRIC_SMOOTHING = 8 
        }
 
        internal struct GaspRange 
        {
            public ushort ppem; 
            public GaspFlags flags;
        };

        ///  
        ///     Critical: This calls into an unsafe code block. This code
        ///     acceses cacher, allocates memory and manipulates pointers 
        ///     TreatAsSafe: The pointer calls are bounds checked and 
        ///     checked for validity in _cacher and ok to expose.
        ///  
        internal GaspRange[] GaspRanges
        {

            [SecurityCritical, SecurityTreatAsSafe] 
            set
            { 
                unsafe 
                {
                    _layout->offGaspRanges = _cacher.Alloc(sizeof(ushort) + value.Length * 2 * sizeof(ushort)); 
                    ushort* gaspRanges = (ushort*)_cacher[_layout->offGaspRanges];
                    *gaspRanges++ = (ushort)value.Length;
                    foreach (GaspRange range in value)
                    { 
                        *gaspRanges++ = range.ppem;
                        *gaspRanges++ = (ushort)range.flags; 
                    } 
                }
            } 
        }


        // horizontal/vertical metrics are stored in this format: 
        // ushort   number of glyphs
        // followed by array of GlyphMetrics structures 
        [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 14)] 
        internal struct GlyphMetrics
        { 
            // horizontal metrics
            internal ushort advanceWidth;
            internal short lsb;    // left sidebearing
            internal short rsb;    // right sidebearing 

            // vertical metrics 
            internal ushort advanceHeight; 
            internal short tsb;    // top sidebearing
            internal short bsb;    // bottom sidebearing 

            internal short baseline; // distance to the bottom black pixel from base line Y
        };
 
        /// 
        ///     Critical: This calls into an unsafe code block, misusing the setter can result in spoofing and memory overrun. 
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is in setting this variable since
        ///     it is used to index into unmanaged memory. 
        /// 
        internal ushort GlyphCount
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                unsafe 
                {
                    return _layout->glyphCount; 
                }
            }
            [SecurityCritical]
            set 
            {
                unsafe 
                { 
                    _layout->glyphCount = value;
                } 
            }
        }

        ///  
        ///     Critical: This calls into an unsafe code block
        ///     TreatAsSafe: Allocating memory and assigning it to layout 
        ///     is ok. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void CreateAdvanceWidthsArray()
        {
            unsafe
            { 
                _layout->offAdvanceWidths = _cacher.Alloc(GlyphCount * sizeof(GlyphMetrics));
            } 
        } 

        ///  
        ///     Critical: Calls unsafe code blocks. It returns a pointer
        /// 
        [SecurityCritical]
        internal unsafe GlyphMetrics* Metrics(ushort glyphIndex) 
        {
            if (glyphIndex >= GlyphCount) 
                throw new ArgumentOutOfRangeException("glyphIndex", SR.Get(SRID.GlyphIndexOutOfRange, glyphIndex)); 

            Invariant.Assert(_layout->offAdvanceWidths != Util.nullOffset && _layout->offAdvanceWidths != 0); 

            GlyphMetrics* metrics = (GlyphMetrics*)_cacher[_layout->offAdvanceWidths];
            return metrics + glyphIndex;
        } 

        // horizontal metrics 
 
        /// 
        ///     Critical: This calls into an unsafe code block 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///     which is mitigated by tracking all sets to this
        ///     variable. Also this code does not expose the pointer 
        ///     it retrieves from Metrics
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        internal ushort GetAdvanceWidth(ushort glyphIndex)
        { 
            unsafe { return Metrics(glyphIndex)->advanceWidth; }
        }

        ///  
        ///     Critical: Calls unsafe code blocks, can result in spoofing.
        ///  
        [SecurityCritical] 
        internal void SetAdvanceWidth(ushort glyphIndex, ushort advanceWidth)
        { 
            unsafe { Metrics(glyphIndex)->advanceWidth = advanceWidth; }
        }

        ///  
        ///     Critical: This calls into an unsafe code block
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty 
        ///     which is mitigated by tracking all sets to this
        ///     variable. Also this code does not expose the pointer 
        ///     it retrieves from Metrics
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal short GetLeftSidebearing(ushort glyphIndex) 
        {
            unsafe { return Metrics(glyphIndex)->lsb; } 
        } 

        ///  
        ///     Critical: This calls into an unsafe code block, can result in spoofing.
        /// 
        [SecurityCritical]
        internal void SetLeftSidebearing(ushort glyphIndex, short lsb) 
        {
            unsafe { Metrics(glyphIndex)->lsb = lsb; } 
        } 

        ///  
        ///     Critical: This calls into an unsafe code block
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///     which is mitigated by tracking all sets to this 
        ///     variable. Also this code does not expose the pointer
        ///     it retrieves from Metrics 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal short GetRightSidebearing(ushort glyphIndex) 
        {
            unsafe { return Metrics(glyphIndex)->rsb; }
        }
 
        /// 
        ///     Critical: This calls into an unsafe code block, can result in spoofing. 
        ///  
        [SecurityCritical]
        internal void SetRightSidebearing(ushort glyphIndex, short rsb) 
        {
            unsafe { Metrics(glyphIndex)->rsb = rsb; }
        }
 
        // vertical metrics
 
        ///  
        ///     Critical: This calls into an unsafe code block
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///     which is mitigated by tracking all sets to this
        ///     variable. Also this code does not expose the pointer
        ///     it retrieves from Metrics 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal ushort GetAdvanceHeight(ushort glyphIndex) 
        {
            unsafe { return Metrics(glyphIndex)->advanceHeight; } 
        }

        /// 
        ///     Critical: This calls into an unsafe code block, can result in spoofing. 
        /// 
        [SecurityCritical] 
        internal void SetAdvanceHeight(ushort glyphIndex, ushort advanceHeight) 
        {
            unsafe { Metrics(glyphIndex)->advanceHeight = advanceHeight; } 
        }

        /// 
        ///     Critical: This calls into an unsafe code block 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty 
        ///     which is mitigated by tracking all sets to this 
        ///     variable. Also this code does not expose the pointer
        ///     it retrieves from Metrics 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal short GetTopSidebearing(ushort glyphIndex)
        { 
            unsafe { return Metrics(glyphIndex)->tsb; }
        } 
 
        /// 
        ///     Critical: This calls into an unsafe code block, can result in spoofing. 
        /// 
        [SecurityCritical]
        internal void SetTopSidebearing(ushort glyphIndex, short tsb)
        { 
            unsafe { Metrics(glyphIndex)->tsb = tsb; }
        } 
 
        /// 
        ///     Critical: This calls into an unsafe code block 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///     which is mitigated by tracking all sets to this
        ///     variable. Also this code does not expose the pointer 
        ///     it retrieves from Metrics
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        internal short GetBottomSidebearing(ushort glyphIndex)
        { 
            unsafe { return Metrics(glyphIndex)->bsb; }
        }

        ///  
        ///     Critical: This calls into an unsafe code block, can result in spoofing.
        ///  
        [SecurityCritical] 
        internal void SetBottomSidebearing(ushort glyphIndex, short bsb)
        { 
            unsafe { Metrics(glyphIndex)->bsb = bsb; }
        }

        ///  
        ///     Critical: This calls into an unsafe code block
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty 
        ///     which is mitigated by tracking all sets to this
        ///     variable. Also this code does not expose the pointer 
        ///     it retrieves from Metrics
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal short GetBaseline(ushort glyphIndex) 
        {
            unsafe { return Metrics(glyphIndex)->baseline; } 
        } 

        ///  
        ///     Critical: This calls into an unsafe code block, can result in spoofing.
        /// 
        [SecurityCritical]
        internal void SetBaseline(ushort glyphIndex, short baseline) 
        {
            unsafe { Metrics(glyphIndex)->baseline = baseline; } 
        } 

 
        // OpenType support

        /// 
        ///     Critical: Calls unsafe code blocks and returns a pointer 
        /// 
        [SecurityCritical] 
        internal unsafe byte* Gsub() 
        {
            if (_layout->offGsub == Util.nullOffset) 
                return null;
            return _cacher[_layout->offGsub];
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks and returns a pointer 
        ///  
        [SecurityCritical]
        internal unsafe byte* Gpos() 
        {
            if (_layout->offGpos == Util.nullOffset)
                return null;
            return _cacher[_layout->offGpos]; 
        }
 
        ///  
        ///     Critical: Calls unsafe code blocks and returns a pointer
        ///  
        [SecurityCritical]
        internal unsafe byte* Gdef()
        {
            if (_layout->offGdef == Util.nullOffset) 
                return null;
            return _cacher[_layout->offGdef]; 
        } 

        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks, can result in spoofing.
        /// 
        [SecurityCritical]
        private int SetTable(CheckedPointer tablePointer) 
        {
            unsafe 
            { 
                if (tablePointer.Size < sizeof(int))
                    return Util.nullOffset; 

                int layoutOffset = _cacher.Alloc(tablePointer.Size);
                CheckedPointer table = _cacher.GetCheckedPointer(layoutOffset);
                tablePointer.CopyTo(table); 

                // Table size is stored as the first integer in the cached table. 
                int* tableSize = (int*)table.Probe(0, sizeof(int)); 
                *tableSize = tablePointer.Size;
                return layoutOffset; 
            }
        }

        ///  
        ///     Critical: Calls unsafe code
        ///  
        [SecurityCritical] 
        internal unsafe CheckedPointer GetTableCache(OpenTypeTags tableTag)
        { 
            switch (tableTag)
            {
                case OpenTypeTags.GSUB :
                    if (_layout->offGsubCache != Util.nullOffset) 
                    {
                        return new CheckedPointer(_cacher[_layout->offGsubCache], _layout->gsubCacheLength); 
                    } 
                    break;
                case OpenTypeTags.GPOS : 
                    if (_layout->offGposCache != Util.nullOffset)
                    {
                        return new CheckedPointer(_cacher[_layout->offGposCache], _layout->gposCacheLength);
                    } 
                    break;
                default: 
                    throw new NotSupportedException(); 
            }
 
            return new CheckedPointer();
        }

        ///  
        ///     Critical: Calls critical and unsafe code
        ///  
        [SecurityCritical] 
        internal unsafe CheckedPointer AllocateTableCache(OpenTypeTags tableTag, int size)
        { 
            int layoutOffset = _cacher.Alloc(size);

            switch (tableTag)
            { 
                case OpenTypeTags.GSUB :
                { 
                    _layout->offGsubCache    = layoutOffset; 
                    _layout->gsubCacheLength = size;
                    break; 
                }
                case OpenTypeTags.GPOS :
                {
                    _layout->offGposCache    = layoutOffset; 
                    _layout->gposCacheLength = size;
                    break; 
                } 
                default:
                { 
                    throw new NotSupportedException();
                }
            }
 
            if (layoutOffset == Util.nullOffset)
            { 
                return new CheckedPointer(); 
            }
 
            //


            return new CheckedPointer(_cacher[layoutOffset], size); 
        }
 
        ///  
        /// Compiles cache data needed for OpenType layout services
        ///  
        /// 
        /// Critical - calls critical code (OpenType layout table access)
        /// 
        [SecurityCritical] 
        private void CreateOpenTypeLayoutCache()
        { 
            int maxLayoutCacheSize = 0x4000; // 16K 

            GsubGposTables gsubGpos = new GsubGposTables(this); 

            //

 

 
 

 

            OpenTypeLayout.CreateLayoutCache(gsubGpos, maxLayoutCacheSize);
        }
 
        /// 
        /// Computes the typography availabilities. 
        /// It checks the presence of a set of required features in the font 
        /// for ranges of unicode code points and set the corresponding bits
        /// in the TypographyAvailabilities enum. TypographyAvailabilities enum is 
        /// used to determind whether fast path can be used to format the input.
        /// 
        /// 
        /// Critical - calls critical code (GetComplexLanguageList) 
        /// TreatAsSafe - returns safe information about the font
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        private TypographyAvailabilities ComputeTypographyAvailabilities()
        { 
            uint[] glyphBits = new uint[(GlyphCount + 31) >> 5];
            ushort minGlyphId = 65535;
            ushort maxGlyphId = 0;
 
            WritingSystem[] complexScripts;
            TypographyAvailabilities typography = TypographyAvailabilities.None; 
 
            GsubGposTables GsubGpos = new GsubGposTables(this);
 
            // preparing the glyph bits. When the bit is set, it means the corresponding
            // glyph needs to be checked against.
            for (int i = 0; i < fastTextRanges.Length; i++)
            { 
                int firstChar = fastTextRanges[i].firstChar;
                int lastChar = fastTextRanges[i].lastChar; 
 
                for (int ch = firstChar; ch <= lastChar; ch++)
                { 
                    ushort glyphId;
                    if (CharacterMap.TryGetValue(ch, out glyphId))
                    {
                        glyphBits[glyphId >> 5] |= (uint)(1 << (glyphId % 32)); 

                        if (glyphId > maxGlyphId) maxGlyphId = glyphId; 
                        if (glyphId < minGlyphId) minGlyphId = glyphId; 
                    }
                } 
            }

            //
            // Step 1: call OpenType layout engine to test presence of 
            // 'locl' feature. Based on the returned writing systems, set
            // FastTextMajorLanguageLocalizedFormAvailable bit and 
            // FastTextExtraLanguageLocalizedFormAvailable bit 
            //
            OpenTypeLayoutResult result; 
            unsafe
            {
                result = OpenTypeLayout.GetComplexLanguageList(
                             GsubGpos, 
                             LoclFeature,
                             glyphBits, 
                             minGlyphId, 
                             maxGlyphId,
                             out complexScripts 
                        );
            }

            if (result != OpenTypeLayoutResult.Success) 
            {
                // The check failed. We abort and don't keep partial results that are not reliable 
                return TypographyAvailabilities.None; 
            }
            else if (complexScripts != null) 
            {
                // This is the bits for localized form we would want to set
                // if both bits for localized form were set, we can end the loop earlier
                TypographyAvailabilities loclBitsTest = 
                      TypographyAvailabilities.FastTextMajorLanguageLocalizedFormAvailable
                    | TypographyAvailabilities.FastTextExtraLanguageLocalizedFormAvailable; 
 
                for (int i = 0; i < complexScripts.Length && typography != loclBitsTest; i++)
                { 
                    if (MajorLanguages.Contains((LanguageTags)complexScripts[i].langSysTag))
                    {
                        typography |= TypographyAvailabilities.FastTextMajorLanguageLocalizedFormAvailable;
                    } 
                    else
                    { 
                        typography |= TypographyAvailabilities.FastTextExtraLanguageLocalizedFormAvailable; 
                    }
                } 
            }

            //
            // step 2: continue to find out whether there is common features availabe 
            // in the font for the unicode ranges and set the FastTextTypographyAvailable bit
            // 
            unsafe 
            {
                result = OpenTypeLayout.GetComplexLanguageList( 
                    GsubGpos,
                    RequiredTypographyFeatures,
                    glyphBits,
                    minGlyphId, 
                    maxGlyphId,
                    out complexScripts 
                    ); 
            }
 
            if (result != OpenTypeLayoutResult.Success)
            {
                // The check failed. We abort and don't keep partial results that are not reliable
                return TypographyAvailabilities.None; 
            }
            else if (complexScripts != null) 
            { 
                typography |= TypographyAvailabilities.FastTextTypographyAvailable;
            } 

            //
            // Step 3: call OpenType layout engine to find out if there is any feature present for
            // ideographs. Because there are many ideographs to check for, an alternative is to 
            // check for all scripts with the required features in the font by setting all
            // glyph bits to 1, then see whether CJKIdeograph is in the returned list. 
            // 
            for (int i = 0; i < glyphBits.Length; i++)
            { 
                glyphBits[i] = 0xFFFFFFFF;
            }

            unsafe 
            {
                result = OpenTypeLayout.GetComplexLanguageList( 
                             GsubGpos, 
                             RequiredFeatures,
                             glyphBits, 
                             minGlyphId,
                             maxGlyphId,
                             out complexScripts
                        ); 
            }
 
            if (result != OpenTypeLayoutResult.Success) 
            {
                // The check failed. We abort and don't keep partial results that are not reliable 
                return TypographyAvailabilities.None;
            }
            else if (complexScripts != null)
            { 
                for (int i = 0; i < complexScripts.Length; i++)
                { 
                    if (complexScripts[i].scriptTag == (uint)ScriptTags.CJKIdeographic) 
                    {
                        typography |= TypographyAvailabilities.IdeoTypographyAvailable; 
                    }
                    else
                    {
                        typography |= TypographyAvailabilities.Available; 
                    }
                } 
            } 

            if (typography != TypographyAvailabilities.None) 
            {
                // if any of the bits were set, set TypographyAvailabilities.Avaialble bit
                // as well to indicate some lookup is available.
                typography |= TypographyAvailabilities.Available; 
            }
 
            return typography; 
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks, can result in spoofing.
        /// 
        [SecurityCritical] 
        internal unsafe void SetGsub(CheckedPointer gsub)
        { 
            _layout->offGsub = SetTable(gsub); 
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks, can result in spoofing.
        /// 
        [SecurityCritical] 
        internal unsafe void SetGpos(CheckedPointer gpos)
        { 
            _layout->offGpos = SetTable(gpos); 
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks, can result in spoofing.
        /// 
        [SecurityCritical] 
        internal unsafe void SetGdef(CheckedPointer gdef)
        { 
            _layout->offGdef = SetTable(gdef); 
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks, can result in spoofing.
        /// 
        [SecurityCritical] 
        internal unsafe void SetJstf(CheckedPointer jstf)
        { 
            _layout->offJstf = SetTable(jstf); 
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks to store a list of names into a filemapping object, can result in spoofing.
        /// 
        [SecurityCritical] 
        private int ConvertNames(LocalizedName[] names)
        { 
            if (names == null) 
                return Util.nullOffset;
            unsafe 
            {
                int cacheOffset = _cacher.Alloc(sizeof(CachedNames) + names.Length * sizeof(CachedName));
                CachedNames* cachedNames = (CachedNames*)_cacher[cacheOffset];
                cachedNames->numberOfNames = names.Length; 

                CachedName* cachedName = (CachedName*)((byte*)cachedNames + sizeof(CachedNames)); 
 
                for (int i = 0; i < names.Length; ++i)
                { 
                    // GetEquivalentCulture() should always succeed, because we started with information in a
                    //  a TrueType file, which contained an LCID.
                    cachedName->language = names[i].OriginalLCID;
                    cachedName->nameSize = Util.StringSize(names[i].Name); 
                    cachedName->nameString = _cacher.Alloc(cachedName->nameSize);
                    Util.StringCopyToCheckedPointer(_cacher.GetCheckedPointer(cachedName->nameString), names[i].Name); 
                    ++cachedName; 
                }
                return cacheOffset; 
            }
        }

        ///  
        ///     Critical: Calls unsafe code blocks to set the various fields in _layout
        ///     TreatAsSafe: The pointers themselves are not exposed. Also the construction 
        ///     of _layout is tracked to ensure that it cannot be hijacked. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void AddLocalizedNames(ref TrueTypeFontDriver.ParsedNameTable nameTable, bool skipFontDifferentiation)
        {
            unsafe
            { 
                _layout->version = nameTable.version;
                _layout->familyNames = ConvertNames(nameTable.familyNames); 
                _layout->win32FamilyNames = ConvertNames(nameTable.win32FamilyNames); 
                _layout->faceNames = ConvertNames(nameTable.faceNames);
                _layout->win32faceNames = ConvertNames(nameTable.win32faceNames); 

                // Run font differentiator to adjust family and face names.
                FontStyle adjustedStyle = _layout->style;
                FontWeight adjustedWeight = _layout->weight; 
                FontStretch adjustedStretch = _layout->stretch;
 
                LocalizedName[] oldFaceNames = nameTable.faceNames; 
                if (!skipFontDifferentiation)
                { 
                    FontDifferentiator.AdjustFamilyAndFaceInformation(ref nameTable, ref adjustedStyle, ref adjustedWeight, ref adjustedStretch);
                }

                // We store only adjusted face names in cache at this point, but if we decide to expose the rest, 
                // this is the right place to store this information in the cache.
 
                if (nameTable.faceNames == null) 
                {
                    // We have only legacy face names. 
                    _layout->adjustedFaceNames = _layout->win32faceNames;
                }
                else
                { 
                    if (oldFaceNames == nameTable.faceNames)
                    { 
                        // Font differentiator didn't modify preferred face names. 
                        _layout->adjustedFaceNames = _layout->faceNames;
                    } 
                    else
                    {
                        // Font differentiator modified preferred face names.
                        _layout->adjustedFaceNames = ConvertNames(nameTable.faceNames); 
                    }
                } 
 
                _layout->versionStrings = ConvertNames(nameTable.versionStrings);
                _layout->copyrights = ConvertNames(nameTable.copyrights); 
                _layout->manufacturerNames = ConvertNames(nameTable.manufacturerNames);
                _layout->trademarks = ConvertNames(nameTable.trademarks);
                _layout->designerNames = ConvertNames(nameTable.designerNames);
                _layout->descriptions = ConvertNames(nameTable.descriptions); 
                _layout->vendorUrls = ConvertNames(nameTable.vendorUrls);
                _layout->designerUrls = ConvertNames(nameTable.designerUrls); 
                _layout->licenseDescriptions = ConvertNames(nameTable.licenseDescriptions); 
                _layout->sampleTexts = ConvertNames(nameTable.sampleTexts);
            } 
        }

        /// 
        ///     Critical: This code yieds accesses unsafe method ElementCacher and uses _layout 
        ///     TreatAsSafe: This code exposes and IDictionary object for Family Names which is ok
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        internal unsafe IDictionary GetFamilyNameDictionary()
        { 
            return new LocalizedNameDictionary(
                _cacher,
                _layout->familyNames,       // primary lookup
                _layout->win32FamilyNames   // fall back lookup 
                );
        } 
 
        /// 
        ///     Critical: This calls into unsafe code to retrieve the family name 
        ///     TreatAsSafe:This information is ok to give out and returns a dictionary
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal unsafe IDictionary GetWin32FamilyNameDictionary() 
        {
            return new LocalizedNameDictionary(_cacher, _layout->win32FamilyNames); 
        } 

        ///  
        ///     Critical: This calls into unsafe code to retrieve the face name
        ///     TreatAsSafe:This information is ok to give out
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal unsafe IDictionary GetFaceNameDictionary()
        { 
            return new LocalizedNameDictionary( 
                _cacher,
                _layout->faceNames,         // primary lookup 
                _layout->win32faceNames     // fall back lookup
                );
        }
 
        /// 
        ///     Critical: This calls into unsafe code to retrieve the face name 
        ///     TreatAsSafe:This information is ok to give out 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal unsafe IDictionary GetWin32FaceNameDictionary()
        {
            return new LocalizedNameDictionary(_cacher, _layout->win32faceNames);
        } 

        ///  
        ///     Critical: This calls into unsafe code to retrieve the adjusted family name 
        ///     TreatAsSafe: This information is ok to give out.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal unsafe IDictionary GetAdjustedFaceNameDictionary()
        {
            return new LocalizedNameDictionary(_cacher, _layout->adjustedFaceNames); 
        }
 
        ///  
        ///     Critical: This calls into unsafe code to retrieve the version string,
        ///     and this exposes extra font information not needed for rendering. 
        /// 
        [SecurityCritical]
        internal unsafe IDictionary GetVersionStringDictionary()
        { 
            return new LocalizedNameDictionary(_cacher, _layout->versionStrings);
        } 
 
        /// 
        ///     Critical: This calls into unsafe code to retrieve copyright information, 
        ///     and this exposes extra font information not needed for rendering.
        /// 
        [SecurityCritical]
        internal unsafe IDictionary GetCopyrightDictionary() 
        {
            return new LocalizedNameDictionary(_cacher, _layout->copyrights); 
        } 

        ///  
        ///     Critical: This calls into unsafe code to retrieve the manufacturer name,
        ///     and this exposes extra font information not needed for rendering.
        /// 
        [SecurityCritical] 
        internal unsafe IDictionary GetManufacturerNameDictionary()
        { 
            return new LocalizedNameDictionary(_cacher, _layout->manufacturerNames); 
        }
        ///  
        ///     Critical: This calls into unsafe code to retrieve trademark,
        ///     and this exposes extra font information not needed for rendering.
        /// 
        [SecurityCritical] 
        internal unsafe IDictionary GetTrademarkDictionary()
        { 
            return new LocalizedNameDictionary(_cacher, _layout->trademarks); 
        }
 
        /// 
        ///     Critical: This calls into unsafe code to retrieve the Designer Name,
        ///     and this exposes extra font information not needed for rendering.
        ///  
        [SecurityCritical]
        internal unsafe IDictionary GetDesignerNameDictionary() 
        { 
            return new LocalizedNameDictionary(_cacher, _layout->designerNames);
        } 

        /// 
        ///     Critical: This calls into unsafe code to retrieve the dscription,
        ///     and this exposes extra font information not needed for rendering. 
        /// 
        [SecurityCritical] 
        internal unsafe IDictionary GetDescriptionDictionary() 
        {
            return new LocalizedNameDictionary(_cacher, _layout->descriptions); 
        }

        /// 
        ///     Critical: This calls into unsafe code to retrieve the Vendor Url, 
        ///     and this exposes extra font information not needed for rendering.
        ///  
        [SecurityCritical] 
        internal unsafe IDictionary GetVendorUrlDictionary()
        { 
            return new LocalizedNameDictionary(_cacher, _layout->vendorUrls);
        }

        ///  
        ///     Critical: This calls into unsafe code to retrieve the dsigner uri,
        ///     and this exposes extra font information not needed for rendering. 
        ///  
        [SecurityCritical]
        internal unsafe IDictionary GetDesignerUrlDictionary() 
        {
            return new LocalizedNameDictionary(_cacher, _layout->designerUrls);
        }
 
        /// 
        ///     Critical: This calls into unsafe code to retrieve the Licensce, 
        ///     and this exposes extra font information not needed for rendering. 
        /// 
        [SecurityCritical] 
        internal unsafe IDictionary GetLicenseDescriptionDictionary()
        {
            return new LocalizedNameDictionary(_cacher, _layout->licenseDescriptions);
        } 

        ///  
        ///     Critical: This calls into unsafe code to retrieve the sample text 
        /// 
        [SecurityCritical] 
        internal unsafe IDictionary GetSampleTextDictionary()
        {
            return new LocalizedNameDictionary(_cacher, _layout->sampleTexts);
        } 
        #region IntMap
 
        ///  
        /// IntMap represents mapping from UTF32 code points to glyph indices.
        /// The IDictionary part is eventually returned from public APIs and is made read-only. 
        /// Internal methods are used by the font driver to create the cmap.
        /// 
        internal sealed class IntMap : IDictionary
        { 
            internal static int InitialSize()
            { 
                unsafe { return sizeof(int) + NumberOfPlanes * sizeof(int); } 
            }
 
            /// 
            ///     Critical: Calls into probe which is critical and also has unsafe code blocks, can be used to spoof cmap.
            /// 
            [SecurityCritical] 
            internal IntMap(CheckedPointer p, ElementCacher cacher)
            { 
                unsafe { _data = (byte*)p.Probe(0, InitialSize()); } 
                _cacher = cacher;
            } 

            /// 
            ///    Critical: This code accesses unsafe code blocks
            ///    TreatAsSafe: This information is ok to return for get but bad for set 
            /// 
            internal unsafe int CharacterCount 
            { 
                [SecurityCritical, SecurityTreatAsSafe]
                get 
                {
                    return *(int*)_data;
                }
                [SecurityCritical] 
                set
                { 
                    *(int*)_data = value; 
                }
            } 

            /// 
            ///    Critical: Calls into critical code which does an unsafe operation FillMemory.
            ///    TreatAsSafe: Ok to expose, since GetPlanePointer will return a valid value and number of planes is a const. 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            internal void Init() 
            {
                CharacterCount = 0; 
                unsafe { Util.FillMemory(GetPlanePointer(0), NumberOfPlanes * sizeof(int), EmptyPlane); }
            }

            ///  
            /// Glyph count is used for validating cmap contents.
            /// If we discover that glyph index we are about to set or return is outside of glyph range, 
            /// we throw an exception. 
            /// 
            ///  
            ///     Critical: Setting this from unauthorized functions increases the risk of failure in functions that
            ///     work with _glyphcount
            /// 
            [SecurityCritical] 
            internal void SetGlyphCount(ushort glyphCount)
            { 
                _glyphCount = new SecurityCriticalDataForSet(glyphCount); 
            }
 
            /// 
            ///   Critical: This code calls into unsafe code blocks and gets a pointer back. It uses
            ///   this to initialize a character entry. Can be used to spoof cmap.
            ///  
            [SecurityCritical]
            internal void SetCharacterEntry(int i, ushort value) 
            { 
                // Some fonts have cmap entries that point to glyphs outside of the font.
                // Just skip such entries. 
                if (value >= _glyphCount.Value)
                    return;

                int plane = CreatePlane(i >> 16); 
                int page = CreatePage(plane, i >> 8 & 0xff);
                unsafe 
                { 
                    ushort* characterEntry = GetGlyphPointer(page, i & 0xff);
                    if (*characterEntry == 0 && value != 0) 
                        ++CharacterCount;
                    *characterEntry = value;
                }
            } 

            ///  
            ///    Critical: Calls into unsafe code block and returns a pointer 
            /// 
            [SecurityCritical] 
            private unsafe int* GetPlanePointer(int i)
            {
                if (i < 0 || i >= NumberOfPlanes)
                    throw new ArgumentOutOfRangeException("c", SR.Get(SRID.CodePointOutOfRange, i)); 
                return ((int*)_data) + i + 1;
            } 
 
            /// 
            ///    Critical: Calls into unsafe code 
            ///    TreatAsSafe: This code does not expose the pointer and is safe to call
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            private unsafe int GetPlane(int i) 
            {
                return *GetPlanePointer(i); 
            } 

            ///  
            ///    Critical: Calls into unsafe code block and exposes a pointer
            /// 
            [SecurityCritical]
            private unsafe int* GetPagePointer(int plane, int i) 
            {
                Invariant.Assert(0 <= i && i < NumberOfPages); 
                return ((int*)_cacher[plane]) + i; 
            }
 

            /// 
            ///    Critical: Calls into unsafe code block
            ///    TreatAsSafe: This code does not expose the pointer and is safe to call 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            private unsafe int GetPage(int plane, int i) 
            {
                return *GetPagePointer(plane, i); 
            }

            /// 
            ///    Critical: Calls into unsafe code block 
            /// 
            [SecurityCritical] 
            private unsafe ushort* GetGlyphPointer(int page, int key) 
            {
                Invariant.Assert(0 <= key && key < PageSize); 
                return (ushort*)_cacher[page] + key;
            }

            ///  
            ///    Critical: Calls into unsafe code block
            ///    TreatAsSafe: This code does not expose the pointer and is safe to call 
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            private unsafe ushort GetGlyph(int page, int key) 
            {
                return *GetGlyphPointer(page, key);
            }
 

            ///  
            ///    Critical: Calls into unsafe code block 
            ///    TreatAsSafe: Ok to expose this function. It uses _cacher which is
            ///    bounds checked. 
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            private int CreatePlane(int i)
            { 
                unsafe
                { 
                    int* plane = GetPlanePointer(i); 
                    if (*plane == EmptyPlane)
                    { 
                        *plane = _cacher.Alloc(NumberOfPages * sizeof(int));
                        Util.FillMemory(_cacher[*plane], NumberOfPages * sizeof(int), EmptyPage);
                    }
                    return *plane; 
                }
            } 
 
            /// 
            ///    Critical: Calls into unsafe code block 
            ///    TreatAsSafe: Ok to expose, it used cacher which is bounds checked, it
            ///    uses GetPlanePointer which uses a const int and hence the index into
            ///    the array cannot be breached.
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            private int CreatePage(int plane, int i) 
            { 
                unsafe
                { 
                    int* page = GetPagePointer(plane, i);
                    if (*page == EmptyPage)
                    {
                        *page = _cacher.Alloc(PageSize * sizeof(short)); 
                        Util.FillMemory(_cacher[*page], PageSize * sizeof(short), 0);
                    } 
                    return *page; 
                }
            } 

            #region IDictionary Members
            public void Add(int key, ushort value)
            { 
                throw new NotSupportedException();
            } 
 
            public bool ContainsKey(int key)
            { 
                ushort glyphIndex;
                return TryGetValue(key, out glyphIndex);
            }
 
            public ICollection Keys
            { 
                get 
                {
                    // This is inefficient, but Keys is not used too often to justify optimizing it. 
                    int[] keys = new int[Count];
                    int i = 0;
                    foreach (KeyValuePair pair in this)
                    { 
                        keys[i++] = pair.Key;
                    } 
                    Debug.Assert(i == Count); 
                    return keys;
                } 
            }

            public bool Remove(int key)
            { 
                throw new NotSupportedException();
            } 
 
            public bool TryGetValue(int key, out ushort value)
            { 
                try
                {
                    int plane = GetPlane(key >> 16);
                    if (plane != EmptyPlane) 
                    {
                        int page = GetPage(plane, key >> 8 & 0xff); 
                        if (page != EmptyPage) 
                        {
                            ushort glyphIndex = GetGlyph(page, key & 0xff); 
                            Debug.Assert(glyphIndex < _glyphCount.Value);
                            if (glyphIndex != 0)
                            {
                                value = glyphIndex; 
                                return true;
                            } 
                        } 
                    }
                } 
                catch (ArgumentOutOfRangeException)
                {
                    // GetPlane() throws ArgumentOutOfRangeException if the key value is outside of the valid Unicode range.
                    // Since IDictionary semantics requre returning false for non-existent keys, we need to catch it. 
                }
                value = new ushort(); 
                return false; 
            }
 
            public ICollection Values
            {
                get
                { 
                    // This is inefficient, but Values is not used too often to justify optimizing it.
                    ushort[] values = new ushort[Count]; 
                    int i = 0; 
                    foreach (KeyValuePair pair in this)
                    { 
                        values[i++] = pair.Value;
                    }
                    Debug.Assert(i == Count);
                    return values; 
                }
            } 
 
            ushort IDictionary.this[int i]
            { 
                get
                {
                    ushort glyphIndex;
                    if (!TryGetValue(i, out glyphIndex)) 
                        throw new KeyNotFoundException();
                    return glyphIndex; 
                } 
                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");
                } 
 
                foreach (KeyValuePair pair in this)
                    array[arrayIndex++] = pair; 
            }

            public int Count
            { 
                get { return CharacterCount; }
            } 
 
            public bool IsReadOnly
            { 
                get { return true; }
            }

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

            #endregion 

            #region IEnumerable> Members

            public IEnumerator> GetEnumerator() 
            {
                for (int i = 0; i < NumberOfPlanes; ++i) 
                { 
                    int plane = GetPlane(i);
                    if (plane != EmptyPlane) 
                    {
                        for (int j = 0; j < NumberOfPages; ++j)
                        {
                            int page = GetPage(plane, j); 
                            if (page != EmptyPage)
                            { 
                                for (int k = 0; k < PageSize; ++k) 
                                {
                                    ushort glyph = GetGlyph(page, k); 
                                    if (glyph != 0)
                                        yield return new KeyValuePair(
                                            (i << 16) | (j << 8) | k,
                                            glyph 
                                            );
                                } 
                            } 
                        }
                    } 
                }
            }

            #endregion 

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

            #endregion 
            /// 
            ///  Critical:This code holds a pointer and is unsafe to let out 
            ///  
            [SecurityCritical]
            private unsafe byte* _data; 
            private ElementCacher _cacher;
            /// 
            ///  Critical:This code is used to dereference a memory location and is hence critical
            ///  
            private SecurityCriticalDataForSet _glyphCount;
 
            private const int NumberOfPlanes = 17; 
            private const int NumberOfPages = 256;
            private const int PageSize = 256; 
            private const int EmptyPlane = Util.nullOffset;
            private const int EmptyPage = Util.nullOffset;
        }
 
        internal enum RenderingHints : ushort
        { 
            Regular = 0, 
            LegacyEastAsian = 1
        }; 

        #endregion

        //------------------------------------------------------ 
        //
        //  Private Fields 
        // 
        //-----------------------------------------------------
 
        #region Private Fields
        private ElementCacher _cacher;
        /// 
        ///   Critical: Holds reference to an unmanaged pointer 
        /// 
        [SecurityCritical] 
        private unsafe Layout* _layout; 
        private IntMap _cmap;
        private int _faceIndex; 
        private long _timeStamp;

        private FontSource _fontSource;
 
        // 'locl' feature which is language sensitive
        private static readonly uint[] LoclFeature = new uint[] 
        { 
           (uint)OpenTypeTags.locl
        }; 

        // common features for fast text
        // They are insensitive to languages
        private static readonly uint[] RequiredTypographyFeatures = new uint[] 
        {
           (uint)OpenTypeTags.ccmp, 
           (uint)OpenTypeTags.rlig, 
           (uint)OpenTypeTags.liga,
           (uint)OpenTypeTags.clig, 
           (uint)OpenTypeTags.calt,
           (uint)OpenTypeTags.kern,
           (uint)OpenTypeTags.mark,
           (uint)OpenTypeTags.mkmk 
        };
 
        // All required features 
        private static readonly uint[] RequiredFeatures = new uint[]
        { 
           (uint)OpenTypeTags.locl,
           (uint)OpenTypeTags.ccmp,
           (uint)OpenTypeTags.rlig,
           (uint)OpenTypeTags.liga, 
           (uint)OpenTypeTags.clig,
           (uint)OpenTypeTags.calt, 
           (uint)OpenTypeTags.kern, 
           (uint)OpenTypeTags.mark,
           (uint)OpenTypeTags.mkmk 
        };

        private static readonly UnicodeRange[] fastTextRanges = new UnicodeRange[]
        { 
            new UnicodeRange(0x20  , 0x7e  ),    // basic latin
            new UnicodeRange(0xA1  , 0xFF  ),    // latin-1 supplement, 
            new UnicodeRange(0x0100, 0x17F ),    // latin extended-A 
            new UnicodeRange(0x0180, 0x024F),    // latin extended-B
            new UnicodeRange(0x1E00, 0x1EFF),    // latin extended additional (Vietnamese precomposed) 
            new UnicodeRange(0x3040, 0x309F),    // hiragana
            new UnicodeRange(0x30A0, 0x30FF)     // kana
        };
 
        #endregion Private Fields
 
        #region Private Types 

        // LocalizedNameDictionary implements IDictionary in terms 
        // of one or two arrays of CachedName structures. Each array is assumed to be
        // sorted by LCID.
        //
        // If two arrays are specified, we use the first array for primary lookup and 
        // the second array as a fallback. We use integer indexes internally to refer to
        // culture/name pairs. We can tell from its value whether an index refers to the 
        // first or second array (see the GetCachedName method). An index must be less 
        // than the *sum* of the sizes of the two arrays, specified by the Limit property.
        // 
        // If the fallback array contains keys which are also in the primary array, we
        // don't want to enumerate them or include them in the Count. For this reason,
        // Count may be less than Limit. We use the IsDuplicateKey method during enumeration
        // to determine whether to skip an index, and we use GetCountWithoutDuplicates to 
        // calculate the count.
        // 
        private unsafe struct LocalizedNameDictionary : IDictionary 
        {
            private ElementCacher _cacher; 

            // primary table of strings
            /// 
            ///     Critical:This holds reference to a pointer 
            /// 
            [SecurityCritical] 
            private CachedName* _cachedName; 
            /// 
            ///     Critical:This holds data that is used to make decisions on dereferencing a pointer 
            /// 
            private SecurityCriticalDataForSet _numberOfNames;

            // secondary table of strings 
            /// 
            ///     Critical:This holds reference to a pointer 
            ///  
            [SecurityCritical]
            private CachedName* _cachedNameFallback; 
            /// 
            ///     Critical:This holds data that is used to make decisions on dereferencing a pointer
            /// 
            private SecurityCriticalDataForSet _numberOfNamesFallback; 

            // number of strings, excluding duplicates; may be computed lazily 
            private int _count; 

            ///  
            /// Construct a dictionary using a single array of cached strings.
            /// 
            internal LocalizedNameDictionary(ElementCacher cacher, int cacheOffset)
                : 
                this(cacher, cacheOffset, Util.nullOffset)
            { 
            } 

            ///  
            /// Construct a dictionary with a primary and fallback array of cached strings.
            /// 
            /// 
            ///     Critical:This accesses elementcacher and is unsafe 
            ///     TreatAsSafe: Calling this is ok also it does not expose the pointers.
            ///  
            [SecurityCritical, SecurityTreatAsSafe] 
            internal LocalizedNameDictionary(ElementCacher cacher, int cacheOffset, int cacheOffsetFallback)
            { 
                _cacher = cacher;

                // It's quite common for a font to provide only a Win32-compatible table.
                // If there's only one table we always want to make it the primary table 
                // for reasons of efficiency.
                if (cacheOffset == Util.nullOffset) 
                { 
                    cacheOffset = cacheOffsetFallback;
                    cacheOffsetFallback = Util.nullOffset; 
                }

                // Initialize the primary table.
                if (cacheOffset != Util.nullOffset) 
                {
                    CachedNames* cachedNames = (CachedNames*)_cacher[cacheOffset]; 
                    _cachedName = (CachedName*)((byte*)cachedNames + sizeof(CachedNames)); 
                    _numberOfNames = new SecurityCriticalDataForSet(cachedNames->numberOfNames);
                } 
                else
                {
                    _cachedName = null;
                    _numberOfNames = new SecurityCriticalDataForSet(0); 
                }
 
                // Initialize the secondary table. 
                if (cacheOffsetFallback != Util.nullOffset)
                { 
                    CachedNames* cachedNames = (CachedNames*)_cacher[cacheOffsetFallback];
                    _cachedNameFallback = (CachedName*)((byte*)cachedNames + sizeof(CachedNames));
                    _numberOfNamesFallback = new SecurityCriticalDataForSet(cachedNames->numberOfNames);
                } 
                else
                { 
                    _cachedNameFallback = null; 
                    _numberOfNamesFallback = new SecurityCriticalDataForSet(0);
                } 

                // Initialize count.
                if (_numberOfNamesFallback.Value == 0 || _numberOfNames.Value == 0)
                { 
                    // If there's only one non-empty table then we don't need to check
                    // for duplicate keys. 
                    _count = _numberOfNamesFallback.Value + _numberOfNames.Value; 
                }
                else 
                {
                    // Compute count lazily because we need to check for duplicates.
                    _count = -1;
                } 
            }
 
            ///  
            ///     Critical:This accesses elementcacher and is unsafe it also returns a pointer
            ///  
            [SecurityCritical]
            private CachedName* GetCachedName(int index)
            {
                // We should be checking bounds farther up the stack, e.g., in Enumerator class. 
                Invariant.Assert(index >= 0 && index < Limit);
 
                // Look in primary or secondary table depending on value of index. 
                if (index < _numberOfNames.Value)
                { 
                    return _cachedName + index;
                }
                else
                { 
                    return _cachedNameFallback + (index - _numberOfNames.Value);
                } 
            } 

            ///  
            ///     Critical:This accesses elementcacher which is unsafe
            ///     TreatAsSafe: This code accesses GetCachedName which returns a pointer ,returning this data is ok
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            private int GetLCID(int index)
            { 
                return GetCachedName(index)->language; 
            }
 

            /// 
            ///     Critical:This accesses elementcacher and GetCachedName
            ///     TreatAsSafe: Returning this data is ok also the two functions 
            ///     safeguard against invalid values
            ///  
            [SecurityCritical, SecurityTreatAsSafe] 
            private string GetName(int index)
            { 
                CachedName* cachedName = GetCachedName(index);
                return Util.StringCopyFromCheckedPointer(_cacher.GetCheckedPointer(cachedName->nameString), cachedName->nameSize);
            }
 
            /// 
            /// Look up an LCID in the specified table. 
            ///  
            /// LCID to look up.
            /// Offset to add to returned index if found. 
            /// Array of CachedName structures.
            /// Size of the array.
            /// Index of match (plus offset) or -1 if not found.
            ///  
            ///     Critical:This accesses elementcacher and is unsafe it also accepts a pointer
            ///  
            [SecurityCritical] 
            private int FindLCID(int lcid, int offset, CachedName* cachedName, int numberOfNames)
            { 
                // Look up name based on LCID using binary search.
                int min = 0, lim = numberOfNames;
                while (min < lim)
                { 
                    int i = (min + lim) / 2;
                    int key = cachedName[i].language; 
                    if (lcid < key) 
                        lim = i;
                    else if (lcid > key) 
                        min = i + 1;
                    else
                        return i + offset;
                } 
                return -1;
            } 
            ///  
            ///     Critical: This code calls accesses _cachedName
            ///     TreatAsSafe: The pointer is not exposed and LCID is ok to give out 
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            private int FindPrimaryLCID(int lcid)
            { 
                return FindLCID(
                    lcid,               // LCID to look for 
                    0,                  // no offset 
                    _cachedName,        // look in primary array
                    _numberOfNames.Value); 
            }
            /// 
            ///     Critical: This code calls accesses _cachedNameFallBack
            ///     TreatAsSafe: The pointer is not exposed and the call to FindLCID is safe 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            private int FindSecondaryLCID(int lcid) 
            {
                return FindLCID( 
                    lcid,                   // LCID to look for
                    _numberOfNames.Value,         // offset added to result if found
                    _cachedNameFallback,    // look in secondary array
                    _numberOfNamesFallback.Value); 
            }
 
            ///  
            /// Look up an LCID in both tables.
            ///  
            private int FindLCID(int lcid)
            {
                // Look up in primary name table.
                int i = FindPrimaryLCID(lcid); 

                // Fall back to secondary name table. 
                if (i < 0 && _numberOfNamesFallback.Value != 0) 
                {
                    i = FindSecondaryLCID(lcid); 
                }

                return i;
            } 

            ///  
            /// Returns the name for the given LCID or null if not found. 
            /// 
            internal string GetNameFromLCID(int lcid) 
            {
                int i = FindLCID(lcid);
                return (i >= 0) ? GetName(i) : null;
            } 

            ///  
            /// Determines whether the specified index is a duplicate key, which 
            /// should be skipped during enumeration.
            ///  
            /// 
            ///     Critical:This accesses elementcacher and is unsafe
            ///     TreatAsSafe: Calling this is ok since all it returns is whether a key is duped
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            internal bool IsDuplicateKey(int index) 
            { 
                // We should be checking bounds higher up the stack, e.g., in Enumerator class.
                Invariant.Assert(index >= 0 && index < Limit); 

                // Keys in the primary table are not duplicates by definition.
                if (index < _numberOfNames.Value)
                    return false; 

                // If we find the LCID in the primary table then it's a duplicate. 
                int lcid = _cachedNameFallback[index - _numberOfNames.Value].language; 
                return FindPrimaryLCID(lcid) >= 0;
            } 

            /// 
            /// Computes the count (if not already known). The count excludes
            /// indexes for which IsDuplicateKey is true. 
            /// 
            ///  
            ///     Critical:This accesses elementcacher and is unsafe 
            ///     TreatAsSafe: Calling this is ok does not return the critical data
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            private int GetCountWithoutDuplicates()
            {
                if (_count < 0) 
                {
                    // include all keys in the primary table 
                    _count = _numberOfNames.Value; 

                    // iterate over the secondary table including only non-duplicates 
                    for (int i = 0; i < _numberOfNamesFallback.Value; ++i)
                    {
                        int lcid = _cachedNameFallback[i].language;
                        if (FindPrimaryLCID(lcid) < 0) 
                        {
                            // not a duplicate 
                            _count++; 
                        }
                    } 
                }

                return _count;
            } 

            ///  
            /// Limit value for indexes. May differ from Count because the range 
            /// of indexes may include duplicate keys which are not enumerated or
            /// included in the Count. 
            /// 
            internal int Limit
            {
                get 
                {
                    return _numberOfNames.Value + _numberOfNamesFallback.Value; 
                } 
            }
 
            #region IDictionary Members

            bool IDictionary.Remove(CultureInfo key)
            { 
                throw new NotSupportedException();
            } 
 
            void IDictionary.Add(CultureInfo key, string value)
            { 
                throw new NotSupportedException();
            }

            ICollection IDictionary.Keys 
            {
                get 
                { 
                    // OK, this is very slow, but semantically correct.
                    // Keys are not used that often anyway. 
                    CultureInfo[] keys = new CultureInfo[GetCountWithoutDuplicates()];

                    // Enumerator will automatically skip duplicates.
                    int i = 0; 
                    foreach (KeyValuePair pair in this)
                    { 
                        keys[i++] = pair.Key; 
                    }
 
                    // Debug check for enumeration logic.
                    Debug.Assert(i == keys.Length);

                    return keys; 
                }
            } 
 
            string IDictionary.this[CultureInfo key]
            { 
                get
                {
                    return GetNameFromLCID(key.LCID);
                } 
                set
                { 
                    throw new NotSupportedException(); 
                }
            } 

            bool IDictionary.TryGetValue(CultureInfo key, out string value)
            {
                int i = FindLCID(key.LCID); 
                if (i >= 0)
                { 
                    value = GetName(i); 
                    return true;
                } 
                else
                {
                    value = null;
                    return false; 
                }
            } 
 
            ICollection IDictionary.Values
            { 
                get
                {
                    // OK, this is very slow, but semantically correct.
                    // Values are not used that often anyway. 
                    string[] values = new string[GetCountWithoutDuplicates()];
 
                    // Enumerator will automatically skip duplicates. 
                    int i = 0;
                    foreach (KeyValuePair pair in this) 
                    {
                        values[i++] = pair.Value;
                    }
 
                    // Debug check for enumeration logic.
                    Debug.Assert(i == values.Length); 
 
                    return values;
                } 
            }

            bool IDictionary.ContainsKey(CultureInfo key)
            { 
                return FindLCID(key.LCID) >= 0;
            } 
 
            #endregion
 
            #region ICollection> Members

            bool ICollection>.Contains(KeyValuePair item)
            { 
                int i = FindLCID(item.Key.LCID);
                return (i >= 0 && String.Compare(GetName(i), item.Value, StringComparison.OrdinalIgnoreCase) == 0); 
            } 

            void ICollection>.Add(KeyValuePair item) 
            {
                throw new NotSupportedException();
            }
 
            bool ICollection>.Remove(KeyValuePair item)
            { 
                throw new NotSupportedException(); 
            }
 
            bool ICollection>.IsReadOnly
            {
                get
                { 
                    return true;
                } 
            } 

            void ICollection>.Clear() 
            {
                throw new NotSupportedException();
            }
 
            int ICollection>.Count
            { 
                get 
                {
                    return GetCountWithoutDuplicates(); 
                }
            }

            void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) 
            {
                int index = arrayIndex; 
                foreach (KeyValuePair pair in this) 
                {
                    array[index] = pair; 
                    ++index;
                }
            }
 
            #endregion
 
            #region IEnumerable> Members 

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

            IEnumerator IEnumerable.GetEnumerator() 
            {
                return new Enumerator(this);
            }
 
            #endregion
 
            // 
            // Enumerator class for LocalizedNameTable. Internally, we represent the current
            // position as an integer index. We enumerate by incrementing the index, taking 
            // into account that some indexes are invalid (i.e., duplicate keys).
            //
            private class Enumerator : IEnumerator>
            { 
                private int _currentIndex;
                private LocalizedNameDictionary _parent; 
 
                public Enumerator(LocalizedNameDictionary parent)
                { 
                    _parent = parent;
                    _currentIndex = -1;
                }
 
                private void FailIfOutOfRange()
                { 
                    if (_currentIndex < 0) 
                        throw new InvalidOperationException(SR.Get(SRID.Enumerator_NotStarted));
 
                    if (_currentIndex >= _parent.Limit)
                        throw new InvalidOperationException(SR.Get(SRID.Enumerator_ReachedEnd));
                }
 
                private CultureInfo GetCurrentCulture()
                { 
                    return CultureInfo.GetCultureInfo(_parent.GetLCID(_currentIndex)); 
                }
 
                private string GetCurrentName()
                {
                    return _parent.GetName(_currentIndex);
                } 

                #region IEnumerator> Members 
 
                public bool MoveNext()
                { 
                    // We may need to increment the index more than once to skip
                    // duplicate keys.
                    do
                    { 
                        ++_currentIndex;
 
                        // stop if we're at the end 
                        if (_currentIndex >= _parent.Limit)
                        { 
                            // prevent cycling
                            _currentIndex = _parent.Limit;
                            return false;
                        } 

                    } while (_parent.IsDuplicateKey(_currentIndex)); 
 
                    return true;
                } 

                KeyValuePair IEnumerator>.Current
                {
                    get 
                    {
                        FailIfOutOfRange(); 
                        return new KeyValuePair(GetCurrentCulture(), GetCurrentName()); 
                    }
                } 

                object IEnumerator.Current
                {
                    get 
                    {
                        return ((IEnumerator>)this).Current; 
                    } 
                }
 
                public void Reset()
                {
                    _currentIndex = -1;
                } 

                #endregion 
 
                #region IDisposable Members
 
                public void Dispose() { }

                #endregion
            } 
        }
 
        #endregion 
    }
 
    /// 
    /// An implementation of IOpenTypeFont which only provides GSUB and GPOS tables
    /// It is used by OTLS API to determine the optimizable script.
    ///  
    /// 
    /// OTLS API always accepts IOpenTypeFont as input parameter. To be consistent, we 
    /// implement this IOpenTypeFont just for OpenTypeLayout.GetComplexLanguangeList(..) method. 
    /// 
    internal sealed class GsubGposTables : IOpenTypeFont 
    {
        /// 
        ///   Critical:    Gsub() and Gpos() return pointers
        ///   
        [SecurityCritical]
        internal GsubGposTables(FontFaceLayoutInfo layout) 
        { 
            _layout    = layout;
            unsafe 
            {
                _gsubTable = new FontTable(_layout.Gsub());
                _gposTable = new FontTable(_layout.Gpos());
            } 
        }
 
        ///  
        /// Returns font table data
        ///  
        public FontTable GetFontTable(OpenTypeTags TableTag)
        {
            switch (TableTag)
            { 
                case OpenTypeTags.GSUB:
                    { 
                        return _gsubTable; 
                    }
                case OpenTypeTags.GPOS: 
                    {
                        return _gposTable;
                    }
                default: 
                    {
                        throw new NotSupportedException(); 
                    } 
            }
        } 

        /// 
        /// Returns glyph coordinate
        ///  
        public LayoutOffset GetGlyphPointCoord(ushort Glyph, ushort PointIndex)
        { 
            throw new NotSupportedException(); 
        }
 
        /// 
        /// Returns cache for layout table. If cache not found, return null Checked pointer
        /// 
        ///  
        ///   Critical:    Calls critical code
        ///   
        [SecurityCritical] 
        public CheckedPointer GetTableCache(OpenTypeTags tableTag)
        { 
            return _layout.GetTableCache(tableTag);
        }

        ///  
        /// Allocate space for layout table cache.
        ///  
        ///  
        ///   Critical:    Calls critical code
        ///   
        [SecurityCritical]
        public CheckedPointer AllocateTableCache(OpenTypeTags tableTag, int size)
        {
            return _layout.AllocateTableCache(tableTag, size); 
        }
 
        private FontTable           _gsubTable; 
        private FontTable           _gposTable;
        private FontFaceLayoutInfo  _layout; 
    }

    /// 
    /// A unicode range identified by a pair of first and last unicode code point 
    /// 
    internal struct UnicodeRange 
    { 
        internal UnicodeRange(int first, int last)
        { 
            firstChar = first;
            lastChar = last;
        }
 
        internal int firstChar;
        internal int lastChar; 
    } 

    ///  
    /// Major language targetted for optimization
    /// 
    internal static class MajorLanguages
    { 
        /// 
        /// check if input langSys is considered a major language. 
        ///  
        ///  true if it is a major language 
        internal static bool Contains(LanguageTags langSys) 
        {
            if (langSys == LanguageTags.Default) return true;

            for (int i = 0; i < majorLanguages.Length; i++) 
            {
                if (majorLanguages[i].LangSys == langSys) 
                    return true; 
            }
            return false; 
        }

        /// 
        /// check if input culture is considered a major language. 
        /// 
        ///  true if it is a major language  
        internal static bool Contains(CultureInfo culture) 
        {
            if (culture == null) return false; 

            // explicitly check for InvariantCulture. We don't need to check for its parent.
            if (culture == CultureInfo.InvariantCulture) return true;
 
            for (int i = 0; i < majorLanguages.Length; i++)
            { 
                if (majorLanguages[i].Culture.Equals(culture) 
                   || majorLanguages[i].Culture.Equals(culture.Parent)
                   ) 
                {
                    return true;
                }
            } 
            return false;
        } 
 
        // major languages
        private static readonly LangSysCulturePair[] majorLanguages = new LangSysCulturePair[] 
            {
                new LangSysCulturePair(new CultureInfo("en"), LanguageTags.English),  // English neutral culture
                new LangSysCulturePair(new CultureInfo("de"), LanguageTags.German),   // German neutral culture
                new LangSysCulturePair(new CultureInfo("ja"), LanguageTags.Japanese)  // Japanese neutral culture 
            };
 
        private struct LangSysCulturePair 
        {
            internal LangSysCulturePair(CultureInfo culture, LanguageTags langSys) 
            {
                Culture = culture;
                LangSys = langSys;
            } 

            internal readonly CultureInfo Culture; 
            internal readonly LanguageTags LangSys; 
        }
    } 


    /// 
    /// An enum flag indicating the availabilities of various open type 
    /// look ups.
    ///  
    ///  
    /// The enum is used to determine whether fast path is applicable.
    /// Ideo     refers to Ideographs 
    /// FastText refers to Other optimizable text
    /// We keep a minimum set of flags here to allow us reliably optimize
    /// the most common inputs. It is not to prevent under-optimization for
    /// all cases. 
    /// 
    [Flags] 
    internal enum TypographyAvailabilities 
    {
        ///  
        /// No required OpenType typography features is available
        /// 
        None = 0,
 
        /// 
        /// There are some lookup available for required typography 
        /// features 
        /// 
        Available = 1, 

        /// 
        /// There are some lookup available for required typography features
        /// for Ideographic script. 
        /// 
        IdeoTypographyAvailable = 2, 
 
        /// 
        /// There are lookup available for required typography features 
        /// for fast text
        /// 
        FastTextTypographyAvailable = 4,
 
        /// 
        /// There are localized form available for major Ui lanaguages for fast text 
        ///  
        ///  MajorLanguages class
        FastTextMajorLanguageLocalizedFormAvailable = 8, 

        /// 
        /// There are localized form for non major Ui language available for fast text
        ///  
        FastTextExtraLanguageLocalizedFormAvailable = 16,
    } 
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Description: The FontFaceLayoutInfo class 
//
// History: 
//  07/23/2003 : mleonov - Big rewrite to change cache structure 
//
//--------------------------------------------------------------------------- 

using System;
using System.Diagnostics;
using System.Globalization; 
using System.IO;
using System.Security; 
using System.ComponentModel; 
using System.Collections;
using System.Collections.Generic; 
using System.Security.Permissions;
using System.Windows;
using System.Windows.Media;
using System.Runtime.InteropServices; 

using MS.Win32; 
using MS.Utility; 
using MS.Internal;
using MS.Internal.FontFace; 
using MS.Internal.Shaping;

using MS.Internal.PresentationCore;
 
namespace MS.Internal.FontCache
{ 
    [FriendAccessAllowed] 
    internal sealed class FontFaceLayoutInfo : IFontCacheElement
    { 
        //-----------------------------------------------------
        //
        //  Constructors
        // 
        //-----------------------------------------------------
 
        #region Constructors 

        internal FontFaceLayoutInfo(FontSource fontSource, int faceIndex) 
        {
            _fontSource = fontSource;
            _faceIndex = faceIndex;
            _timeStamp = _fontSource.SkipLastWriteTime(); 
        }
 
        ///  
        /// Critical -  Calls into the critical RetrieveKey method.
        ///  
        [SecurityCritical]
        internal FontFaceLayoutInfo(CheckedPointer key)
        {
            RetrieveKey(key); 
        }
 
        #endregion Constructors 

        // layout: struct | FileName | 4byte aligned CMAP (17 int pointers to planes) 
        // the structure size should be aligned on 2 byte boundary, because file name is stored
        // immediately after the structure.
        // As usual, individual structure members need to be properly aligned.
        [StructLayout(LayoutKind.Explicit, Size = Layout.keyOffset + 8)] 
        private struct Layout
        { 
            [FieldOffset(0)] 
            internal ushort designEmHeight;
            [FieldOffset(2)] 
            internal ushort glyphCount;
            [FieldOffset(4)]
            internal ushort designCellAscent;
            [FieldOffset(6)] 
            internal ushort designCellDescent;
 
            [FieldOffset(8)] 
            internal short  fontContrastAdjustment;
 
            [FieldOffset(10)]
            internal short  xHeight;
            [FieldOffset(12)]
            internal short  capsHeight; 

            [FieldOffset(14)] 
            internal ushort blankGlyph; 
            [FieldOffset(16)]
            internal ushort invalidGlyph; 

            [FieldOffset(18)]
            internal ushort underlineSize;
            [FieldOffset(20)] 
            internal short  underlinePosition;
 
            [FieldOffset(22)] 
            internal ushort strikeThroughSize;
            [FieldOffset(24)] 
            internal short  strikeThroughPosition;

            [FieldOffset(26)]
            internal ushort symbol; 

            // RenderingHints is a ushort enum, so 2 bytes are enough. 
            [FieldOffset(28)] 
            internal RenderingHints renderingHints;
 
            [FieldOffset(30)]
            internal ushort embeddingRights;

            [FieldOffset(32)] 
            internal long timeStamp;
 
            [FieldOffset(40)] 
            internal long gsubScripts;
            [FieldOffset(48)] 
            internal long gposScripts;

            [FieldOffset(56)]
            internal int offAdvanceWidths;    // offset of the advance width array 
            [FieldOffset(60)]
            internal int offGsub;             // ditto for GSUB 
            [FieldOffset(64)] 
            internal int offGpos;             // ditto for GPOS
            [FieldOffset(68)] 
            internal int offGdef;             // ditto for GDEF
            [FieldOffset(72)]
            internal int offJstf;             // ditto for JSTF
 
            [FieldOffset(76)]
            internal int familyNames; 
            [FieldOffset(80)] 
            internal int win32FamilyNames;
            [FieldOffset(84)] 
            internal int faceNames;
            [FieldOffset(88)]
            internal int win32faceNames;
            [FieldOffset(92)] 
            internal int versionStrings;
            [FieldOffset(96)] 
            internal int copyrights; 
            [FieldOffset(100)]
            internal int manufacturerNames; 
            [FieldOffset(104)]
            internal int trademarks;
            [FieldOffset(108)]
            internal int designerNames; 
            [FieldOffset(112)]
            internal int descriptions; 
            [FieldOffset(116)] 
            internal int vendorUrls;
            [FieldOffset(120)] 
            internal int designerUrls;
            [FieldOffset(124)]
            internal int licenseDescriptions;
            [FieldOffset(128)] 
            internal int sampleTexts;
 
            [FieldOffset(132)] 
            internal FontStyle style;
            [FieldOffset(136)] 
            internal FontWeight weight;
            [FieldOffset(140)]
            internal FontStretch stretch;
 
            [FieldOffset(144)]
            internal double version; 
 
            [FieldOffset(152)]
            internal int offGaspRanges; 

            [FieldOffset(156)]
            internal TypographyAvailabilities typographyAvailabilities;
 
            [FieldOffset(160)]
            internal FontTechnology fontTechnology; 
 
            [FieldOffset(164)]
            internal int offGsubCache; 

            [FieldOffset(168)]
            internal int gsubCacheLength;
 
            [FieldOffset(172)]
            internal int offGposCache; 
 
            [FieldOffset(176)]
            internal int gposCacheLength; 

            // family and face names adjusted by the font differentiator
            [FieldOffset(180)]
            internal int adjustedFaceNames; 

            // this should be equal to the offset immediately after the previous field 
            internal const int keyOffset = 184; 

            // key starts here 
            [FieldOffset(keyOffset)]
            internal int faceIndex;
            [FieldOffset(keyOffset + 4)]
            internal int uriStringSizeInBytes; 

 
 
            internal static CheckedPointer GetUriString(CheckedPointer This)
            { 
                unsafe
                {
                    return This + sizeof(Layout);
                } 
            }
 
            ///  
            ///     Critical: Calls into probe which is critical and also has unsafe code blocks
            ///     TreatAsSafe: It advances the pointer by the requisite number of bytes . 
            ///     Calls to probe and '+ are bounds checked.
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            internal static CheckedPointer GetCmap(CheckedPointer This) 
            {
                unsafe 
                { 
                    Layout* l = (Layout*)This.Probe(0, sizeof(Layout));
                    return GetUriString(This) + Util.Align4(l->uriStringSizeInBytes); 
                }
            }
        }
 
        [StructLayout(LayoutKind.Explicit, Size = 12)]
        private struct CachedName 
        { 
            [FieldOffset(0)]
            internal int language; 

            [FieldOffset(4)]
            internal int nameSize;
 
            /// 
            /// Offset to the name string 
            ///  
            [FieldOffset(8)]
            internal int nameString; 
        }

        [StructLayout(LayoutKind.Explicit, Size = 4)]
        private struct CachedNames 
        {
            [FieldOffset(0)] 
            internal int numberOfNames; 

            // followed by array of CachedName structures 
        }

        internal FontSource FontSource
        { 
            get
            { 
                return _fontSource; 
            }
        } 

        internal int FaceIndex
        {
            get 
            {
                return _faceIndex; 
            } 
        }
 
        int IFontCacheElement.Type
        {
            get
            { 
                return 3;
            } 
        } 

        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks
        ///     TreatAsSafe: This stores data about the font into a pointer. This data is safe to
        ///     expose and the pointer operations are bounds checked.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private void StoreKeyInternal(CheckedPointer d, out int realSize) 
        { 
            unsafe
            { 
                int* k = (int*)d.Probe(0, sizeof(int));
                *k = _faceIndex;
                realSize = sizeof(int);
                d += sizeof(int); 
                realSize += Util.StringAndLengthCopyToCheckedPointer(d, FontSource.GetUriString());
            } 
        } 

        void IFontCacheElement.StoreKey(CheckedPointer d, out int realSize) 
        {
            Debug.Assert(!_fontSource.IsAppSpecific);
            StoreKeyInternal(d, out realSize);
        } 

        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks. 
        ///     Calls into the critical FontSource constructor.
        ///  
        [SecurityCritical]
        public void RetrieveKey(CheckedPointer p)
        {
            unsafe 
            {
                _faceIndex = *(int*)p.Probe(0, sizeof(int)); 
                string fileName = Util.StringAndLengthCopyFromCheckedPointer(p + sizeof(int)); 
                _fontSource = new FontSource(new Uri(fileName, UriKind.Absolute), false);
            } 
            _timeStamp = _fontSource.SkipLastWriteTime();
        }

        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks
        ///     TreatAsSafe: The call to probe is bounds checked and also the pointers returned 
        ///     are used locally and not passed around. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        bool IFontCacheElement.Match(CheckedPointer p)
        {
            unsafe
            { 
                Layout* l = (Layout*)p.Probe(0, sizeof(Layout));
                string fontUriString = FontSource.GetUriString(); 
                if (Util.StringSize(fontUriString) != l->uriStringSizeInBytes) 
                    return false;
 
                if (_timeStamp != l->timeStamp)
                    return false;

                if (_faceIndex != l->faceIndex) 
                    return false;
 
                return Util.StringEqualIgnoreCase(Layout.GetUriString(p), fontUriString); 
            }
        } 

        /// 
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks. It
        ///     accesses _layout which is a pointer 
        ///     TreatAsSafe: This data is ok to give out, also storing the checked pointer is
        ///     ok 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        void IFontCacheElement.GetData(CheckedPointer block, ElementCacher cacher) 
        {
            unsafe
            {
                _cacher = cacher; 
                _layout = (Layout*)block.Probe(0, sizeof(Layout));
                _timeStamp = _layout->timeStamp; 
                _cmap = new IntMap(Layout.GetCmap(block), _cacher); 
                _cmap.SetGlyphCount(_layout->glyphCount);
            } 
        }

        /// 
        /// Critical - As this function accesses FileName that contains absolute font path. 
        /// Safe - As this is only used to compute the cache element size.
        ///  
        int IFontCacheElement.Size 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                unsafe
                { 
                    return
                        sizeof(Layout) + 
                        Util.Align4(Util.StringSize(FontSource.GetUriString())) + 
                        IntMap.InitialSize();
                } 
            }
        }

        bool IFontCacheElement.IsAppSpecific 
        {
            get 
            { 
                return _fontSource.IsAppSpecific;
            } 
        }

        int IFontCacheElement.GetHashCode()
        { 
            int hash = FontSource.GetHashCode();
            hash = HashFn.HashMultiply(hash) + _faceIndex; 
            return HashFn.HashScramble(hash); 
        }
 
        /// 
        /// Critical - As this function obtains UnmanagedMemoryStream from FontSource.Pin()
        ///            which is Critical.
        /// Safe - As this is only used to add font information to the cache which is safe. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        void IFontCacheElement.AddToCache(CheckedPointer newPointer, ElementCacher cacher) 
        {
            _cacher = cacher; 
            int realSize;
            StoreKeyInternal(newPointer + Layout.keyOffset, out realSize);

            unsafe 
            {
                _layout = (Layout*)newPointer.Probe(0, sizeof(Layout)); 
 
                Debug.Assert(_timeStamp != 0);
 
                _layout->timeStamp = _timeStamp;

                // initialize optional table pointers
                _layout->offGsub = 
                    _layout->offGpos =
                    _layout->offGdef = 
                    _layout->offJstf = 
                    _layout->offGaspRanges =
                    Util.nullOffset; 

                _cmap = new IntMap(Layout.GetCmap(newPointer), _cacher);
            }
            _cmap.Init(); 

            UnmanagedMemoryStream pinnedFontSource = _fontSource.GetUnmanagedStream(); 
 
            try
            { 
                TrueTypeFontDriver ttd = new TrueTypeFontDriver(pinnedFontSource, _fontSource.Uri);
                ttd.SetFace(_faceIndex);
                ttd.GetLayoutFontFaceInfo(this);
                ttd.GetShapingFontFaceInfo(this); 
            }
            catch (SEHException e) 
            { 
                throw Util.ConvertInPageException(_fontSource, e);
            } 
            finally
            {
                pinnedFontSource.Close();
            } 

            unsafe 
            { 
                _layout->offGsubCache = Util.nullOffset;
                _layout->offGposCache = Util.nullOffset; 
                CreateOpenTypeLayoutCache();

                _layout->typographyAvailabilities = ComputeTypographyAvailabilities();
            } 

        } 
 
        /// 
        ///   Critical: Returns a writeable cmap. 
        ///  
        internal IntMap CharacterMap
        {
            [SecurityCritical] 
            get
            { 
                return _cmap; 
            }
        } 

        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This code exposes DesignEmHeight which is ok to expose 
        ///     The risk here is if _layout is null, but that is mitigated by probe.
        ///  
        internal ushort DesignEmHeight 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                unsafe { return _layout->designEmHeight; }
            } 
            [SecurityCritical]
            set 
            { 
                unsafe { _layout->designEmHeight = value; }
            } 
        }

        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing. 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty 
        ///      but that is mitigated by probe 
        /// 
        internal ushort DesignCellAscent 
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get
            { 
                unsafe { return _layout->designCellAscent; }
            } 
            [SecurityCritical] 
            set
            { 
                unsafe { _layout->designCellAscent = value; }
            }
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing. 
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe 
        /// 
        internal ushort DesignCellDescent
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                unsafe { return _layout->designCellDescent; } 
            }
            [SecurityCritical] 
            set
            {
                unsafe { _layout->designCellDescent = value; }
            } 
        }
 
        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe
        /// 
        internal short xHeight 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get 
            {
                unsafe { return _layout->xHeight; } 
            }
            [SecurityCritical]
            set
            { 
                unsafe { _layout->xHeight = value; }
            } 
        } 

        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///     but that is mitigated by probe 
        /// 
        internal short CapsHeight 
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            {
                unsafe { return _layout->capsHeight; }
            }
            [SecurityCritical] 
            set
            { 
                unsafe { _layout->capsHeight = value; } 
            }
        } 

        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe 
        ///  
        internal ushort BlankGlyph
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get
            {
                unsafe { return _layout->blankGlyph; } 
            }
            [SecurityCritical] 
            set 
            {
                unsafe { _layout->blankGlyph = value; } 
            }
        }

        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///  
        internal ushort InvalidGlyph 
        {
            [SecurityCritical] 
            set
            {
                unsafe { _layout->invalidGlyph = value; }
            } 
        }
 
        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe
        /// 
        internal ushort UnderlineThickness 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get 
            {
                unsafe { return _layout->underlineSize; } 
            }
            [SecurityCritical]
            set
            { 
                unsafe { _layout->underlineSize = value; }
            } 
        } 

        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe 
        /// 
        internal short UnderlinePosition 
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            {
                unsafe { return _layout->underlinePosition; }
            }
            [SecurityCritical] 
            set
            { 
                unsafe { _layout->underlinePosition = value; } 
            }
        } 

        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe 
        ///  
        internal ushort StrikethroughThickness
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get
            {
                unsafe { return _layout->strikeThroughSize; } 
            }
            [SecurityCritical] 
            set 
            {
                unsafe { _layout->strikeThroughSize = value; } 
            }
        }

        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty 
        ///      but that is mitigated by probe
        ///  
        internal short StrikethroughPosition
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            {
                unsafe { return _layout->strikeThroughPosition; } 
            } 
            [SecurityCritical]
            set 
            {
                unsafe { _layout->strikeThroughPosition = value; }
            }
        } 

        ///  
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing. 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty 
        ///      but that is mitigated by probe
        /// 
        internal bool Symbol
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            { 
                unsafe { return _layout->symbol != 0; }
            } 
            [SecurityCritical]
            set
            {
                unsafe { _layout->symbol = value ? (ushort)1 : (ushort)0; } 
            }
        } 
 
        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing. 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe
        ///  
        internal RenderingHints FontRenderingHints
        { 
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                unsafe { return _layout->renderingHints; }
            }
            [SecurityCritical]
            set 
            {
                unsafe { _layout->renderingHints = value; } 
            } 
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks, misusing the setter can result in spoofing,
        ///         the data is sensitive and is not OK to expose to untrusted clients.
        ///  
        internal FontEmbeddingRight EmbeddingRights
        { 
            [SecurityCritical] 
            get
            { 
                unsafe { return (FontEmbeddingRight)_layout->embeddingRights; }
            }
            [SecurityCritical]
            set 
            {
                // Make sure no truncation happens when storing the enum value as a ushort. 
                Invariant.Assert(value == (FontEmbeddingRight)(short)value); 

                unsafe { _layout->embeddingRights = (ushort)value; } 
            }
        }

        ///  
        ///     Critical: This calls into an unsafe code block, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty 
        ///      but that is mitigated by probe
        ///  
        internal FontTechnology FontTechnology
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            {
                unsafe { return _layout->fontTechnology; } 
            } 
            [SecurityCritical]
            set 
            {
                unsafe { _layout->fontTechnology = value; }
            }
        } 

 
        ///  
        ///     Critical: This calls into an unsafe code block, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe
        /// 
        internal short FontContrastAdjustment 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get 
            {
                unsafe { return _layout->fontContrastAdjustment; } 
            }
            [SecurityCritical]
            set
            { 
                unsafe { _layout->fontContrastAdjustment = value; }
            } 
        } 

 
        /// 
        ///     Critical: This calls into an unsafe code block, misusing the setter can result in spoofing.
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty 
        ///      but that is mitigated by probe
        ///  
        internal FontStyle Style 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                unsafe { return _layout->style; }
            } 
            [SecurityCritical]
            set 
            { 
                unsafe { _layout->style = value; }
            } 
        }

        /// 
        ///     Critical: This calls into an unsafe code block, misusing the setter can result in spoofing. 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty 
        ///      but that is mitigated by probe 
        /// 
        internal FontWeight Weight 
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get
            { 
                unsafe { return _layout->weight; }
            } 
            [SecurityCritical] 
            set
            { 
                unsafe { _layout->weight = value; }
            }
        }
 
        /// 
        ///     Critical: This calls into an unsafe code block, misusing the setter can result in spoofing. 
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///      but that is mitigated by probe 
        /// 
        internal FontStretch Stretch
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                unsafe { return _layout->stretch; } 
            }
            [SecurityCritical] 
            set
            {
                unsafe { _layout->stretch = value; }
            } 
        }
        ///  
        ///     Critical: This calls into an unsafe code block and exposes font version, 
        ///     which contains extra font information not strictly needed for rendering.
        ///  
        internal double Version
        {
            [SecurityCritical]
            get 
            {
                unsafe { return _layout->version; } 
            } 
        }
        ///  
        ///     Critical: This calls into an unsafe code block
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///     which is mitigated by tracking all sets to this 
        ///     variable
        ///  
        internal TypographyAvailabilities TypographyAvailabilities 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                unsafe { return _layout->typographyAvailabilities; }
            } 
        }
 
        [Flags] 
        internal enum GaspFlags : ushort
        { 
            GASP_GRIDFIT = 1,
            GASP_DOGRAY = 2,
            GASP_SYMMETRIC_GRIDFIT = 4,
            GASP_SYMMETRIC_SMOOTHING = 8 
        }
 
        internal struct GaspRange 
        {
            public ushort ppem; 
            public GaspFlags flags;
        };

        ///  
        ///     Critical: This calls into an unsafe code block. This code
        ///     acceses cacher, allocates memory and manipulates pointers 
        ///     TreatAsSafe: The pointer calls are bounds checked and 
        ///     checked for validity in _cacher and ok to expose.
        ///  
        internal GaspRange[] GaspRanges
        {

            [SecurityCritical, SecurityTreatAsSafe] 
            set
            { 
                unsafe 
                {
                    _layout->offGaspRanges = _cacher.Alloc(sizeof(ushort) + value.Length * 2 * sizeof(ushort)); 
                    ushort* gaspRanges = (ushort*)_cacher[_layout->offGaspRanges];
                    *gaspRanges++ = (ushort)value.Length;
                    foreach (GaspRange range in value)
                    { 
                        *gaspRanges++ = range.ppem;
                        *gaspRanges++ = (ushort)range.flags; 
                    } 
                }
            } 
        }


        // horizontal/vertical metrics are stored in this format: 
        // ushort   number of glyphs
        // followed by array of GlyphMetrics structures 
        [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 14)] 
        internal struct GlyphMetrics
        { 
            // horizontal metrics
            internal ushort advanceWidth;
            internal short lsb;    // left sidebearing
            internal short rsb;    // right sidebearing 

            // vertical metrics 
            internal ushort advanceHeight; 
            internal short tsb;    // top sidebearing
            internal short bsb;    // bottom sidebearing 

            internal short baseline; // distance to the bottom black pixel from base line Y
        };
 
        /// 
        ///     Critical: This calls into an unsafe code block, misusing the setter can result in spoofing and memory overrun. 
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is in setting this variable since
        ///     it is used to index into unmanaged memory. 
        /// 
        internal ushort GlyphCount
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                unsafe 
                {
                    return _layout->glyphCount; 
                }
            }
            [SecurityCritical]
            set 
            {
                unsafe 
                { 
                    _layout->glyphCount = value;
                } 
            }
        }

        ///  
        ///     Critical: This calls into an unsafe code block
        ///     TreatAsSafe: Allocating memory and assigning it to layout 
        ///     is ok. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void CreateAdvanceWidthsArray()
        {
            unsafe
            { 
                _layout->offAdvanceWidths = _cacher.Alloc(GlyphCount * sizeof(GlyphMetrics));
            } 
        } 

        ///  
        ///     Critical: Calls unsafe code blocks. It returns a pointer
        /// 
        [SecurityCritical]
        internal unsafe GlyphMetrics* Metrics(ushort glyphIndex) 
        {
            if (glyphIndex >= GlyphCount) 
                throw new ArgumentOutOfRangeException("glyphIndex", SR.Get(SRID.GlyphIndexOutOfRange, glyphIndex)); 

            Invariant.Assert(_layout->offAdvanceWidths != Util.nullOffset && _layout->offAdvanceWidths != 0); 

            GlyphMetrics* metrics = (GlyphMetrics*)_cacher[_layout->offAdvanceWidths];
            return metrics + glyphIndex;
        } 

        // horizontal metrics 
 
        /// 
        ///     Critical: This calls into an unsafe code block 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///     which is mitigated by tracking all sets to this
        ///     variable. Also this code does not expose the pointer 
        ///     it retrieves from Metrics
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        internal ushort GetAdvanceWidth(ushort glyphIndex)
        { 
            unsafe { return Metrics(glyphIndex)->advanceWidth; }
        }

        ///  
        ///     Critical: Calls unsafe code blocks, can result in spoofing.
        ///  
        [SecurityCritical] 
        internal void SetAdvanceWidth(ushort glyphIndex, ushort advanceWidth)
        { 
            unsafe { Metrics(glyphIndex)->advanceWidth = advanceWidth; }
        }

        ///  
        ///     Critical: This calls into an unsafe code block
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty 
        ///     which is mitigated by tracking all sets to this
        ///     variable. Also this code does not expose the pointer 
        ///     it retrieves from Metrics
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal short GetLeftSidebearing(ushort glyphIndex) 
        {
            unsafe { return Metrics(glyphIndex)->lsb; } 
        } 

        ///  
        ///     Critical: This calls into an unsafe code block, can result in spoofing.
        /// 
        [SecurityCritical]
        internal void SetLeftSidebearing(ushort glyphIndex, short lsb) 
        {
            unsafe { Metrics(glyphIndex)->lsb = lsb; } 
        } 

        ///  
        ///     Critical: This calls into an unsafe code block
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///     which is mitigated by tracking all sets to this 
        ///     variable. Also this code does not expose the pointer
        ///     it retrieves from Metrics 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal short GetRightSidebearing(ushort glyphIndex) 
        {
            unsafe { return Metrics(glyphIndex)->rsb; }
        }
 
        /// 
        ///     Critical: This calls into an unsafe code block, can result in spoofing. 
        ///  
        [SecurityCritical]
        internal void SetRightSidebearing(ushort glyphIndex, short rsb) 
        {
            unsafe { Metrics(glyphIndex)->rsb = rsb; }
        }
 
        // vertical metrics
 
        ///  
        ///     Critical: This calls into an unsafe code block
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty
        ///     which is mitigated by tracking all sets to this
        ///     variable. Also this code does not expose the pointer
        ///     it retrieves from Metrics 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal ushort GetAdvanceHeight(ushort glyphIndex) 
        {
            unsafe { return Metrics(glyphIndex)->advanceHeight; } 
        }

        /// 
        ///     Critical: This calls into an unsafe code block, can result in spoofing. 
        /// 
        [SecurityCritical] 
        internal void SetAdvanceHeight(ushort glyphIndex, ushort advanceHeight) 
        {
            unsafe { Metrics(glyphIndex)->advanceHeight = advanceHeight; } 
        }

        /// 
        ///     Critical: This calls into an unsafe code block 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty 
        ///     which is mitigated by tracking all sets to this 
        ///     variable. Also this code does not expose the pointer
        ///     it retrieves from Metrics 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal short GetTopSidebearing(ushort glyphIndex)
        { 
            unsafe { return Metrics(glyphIndex)->tsb; }
        } 
 
        /// 
        ///     Critical: This calls into an unsafe code block, can result in spoofing. 
        /// 
        [SecurityCritical]
        internal void SetTopSidebearing(ushort glyphIndex, short tsb)
        { 
            unsafe { Metrics(glyphIndex)->tsb = tsb; }
        } 
 
        /// 
        ///     Critical: This calls into an unsafe code block 
        ///     TreatAsSafe: This data is ok to expose. The
        ///     risk is if this pointer "_layout" is empty
        ///     which is mitigated by tracking all sets to this
        ///     variable. Also this code does not expose the pointer 
        ///     it retrieves from Metrics
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        internal short GetBottomSidebearing(ushort glyphIndex)
        { 
            unsafe { return Metrics(glyphIndex)->bsb; }
        }

        ///  
        ///     Critical: This calls into an unsafe code block, can result in spoofing.
        ///  
        [SecurityCritical] 
        internal void SetBottomSidebearing(ushort glyphIndex, short bsb)
        { 
            unsafe { Metrics(glyphIndex)->bsb = bsb; }
        }

        ///  
        ///     Critical: This calls into an unsafe code block
        ///     TreatAsSafe: This data is ok to expose. The 
        ///     risk is if this pointer "_layout" is empty 
        ///     which is mitigated by tracking all sets to this
        ///     variable. Also this code does not expose the pointer 
        ///     it retrieves from Metrics
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal short GetBaseline(ushort glyphIndex) 
        {
            unsafe { return Metrics(glyphIndex)->baseline; } 
        } 

        ///  
        ///     Critical: This calls into an unsafe code block, can result in spoofing.
        /// 
        [SecurityCritical]
        internal void SetBaseline(ushort glyphIndex, short baseline) 
        {
            unsafe { Metrics(glyphIndex)->baseline = baseline; } 
        } 

 
        // OpenType support

        /// 
        ///     Critical: Calls unsafe code blocks and returns a pointer 
        /// 
        [SecurityCritical] 
        internal unsafe byte* Gsub() 
        {
            if (_layout->offGsub == Util.nullOffset) 
                return null;
            return _cacher[_layout->offGsub];
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks and returns a pointer 
        ///  
        [SecurityCritical]
        internal unsafe byte* Gpos() 
        {
            if (_layout->offGpos == Util.nullOffset)
                return null;
            return _cacher[_layout->offGpos]; 
        }
 
        ///  
        ///     Critical: Calls unsafe code blocks and returns a pointer
        ///  
        [SecurityCritical]
        internal unsafe byte* Gdef()
        {
            if (_layout->offGdef == Util.nullOffset) 
                return null;
            return _cacher[_layout->offGdef]; 
        } 

        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks, can result in spoofing.
        /// 
        [SecurityCritical]
        private int SetTable(CheckedPointer tablePointer) 
        {
            unsafe 
            { 
                if (tablePointer.Size < sizeof(int))
                    return Util.nullOffset; 

                int layoutOffset = _cacher.Alloc(tablePointer.Size);
                CheckedPointer table = _cacher.GetCheckedPointer(layoutOffset);
                tablePointer.CopyTo(table); 

                // Table size is stored as the first integer in the cached table. 
                int* tableSize = (int*)table.Probe(0, sizeof(int)); 
                *tableSize = tablePointer.Size;
                return layoutOffset; 
            }
        }

        ///  
        ///     Critical: Calls unsafe code
        ///  
        [SecurityCritical] 
        internal unsafe CheckedPointer GetTableCache(OpenTypeTags tableTag)
        { 
            switch (tableTag)
            {
                case OpenTypeTags.GSUB :
                    if (_layout->offGsubCache != Util.nullOffset) 
                    {
                        return new CheckedPointer(_cacher[_layout->offGsubCache], _layout->gsubCacheLength); 
                    } 
                    break;
                case OpenTypeTags.GPOS : 
                    if (_layout->offGposCache != Util.nullOffset)
                    {
                        return new CheckedPointer(_cacher[_layout->offGposCache], _layout->gposCacheLength);
                    } 
                    break;
                default: 
                    throw new NotSupportedException(); 
            }
 
            return new CheckedPointer();
        }

        ///  
        ///     Critical: Calls critical and unsafe code
        ///  
        [SecurityCritical] 
        internal unsafe CheckedPointer AllocateTableCache(OpenTypeTags tableTag, int size)
        { 
            int layoutOffset = _cacher.Alloc(size);

            switch (tableTag)
            { 
                case OpenTypeTags.GSUB :
                { 
                    _layout->offGsubCache    = layoutOffset; 
                    _layout->gsubCacheLength = size;
                    break; 
                }
                case OpenTypeTags.GPOS :
                {
                    _layout->offGposCache    = layoutOffset; 
                    _layout->gposCacheLength = size;
                    break; 
                } 
                default:
                { 
                    throw new NotSupportedException();
                }
            }
 
            if (layoutOffset == Util.nullOffset)
            { 
                return new CheckedPointer(); 
            }
 
            //


            return new CheckedPointer(_cacher[layoutOffset], size); 
        }
 
        ///  
        /// Compiles cache data needed for OpenType layout services
        ///  
        /// 
        /// Critical - calls critical code (OpenType layout table access)
        /// 
        [SecurityCritical] 
        private void CreateOpenTypeLayoutCache()
        { 
            int maxLayoutCacheSize = 0x4000; // 16K 

            GsubGposTables gsubGpos = new GsubGposTables(this); 

            //

 

 
 

 

            OpenTypeLayout.CreateLayoutCache(gsubGpos, maxLayoutCacheSize);
        }
 
        /// 
        /// Computes the typography availabilities. 
        /// It checks the presence of a set of required features in the font 
        /// for ranges of unicode code points and set the corresponding bits
        /// in the TypographyAvailabilities enum. TypographyAvailabilities enum is 
        /// used to determind whether fast path can be used to format the input.
        /// 
        /// 
        /// Critical - calls critical code (GetComplexLanguageList) 
        /// TreatAsSafe - returns safe information about the font
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        private TypographyAvailabilities ComputeTypographyAvailabilities()
        { 
            uint[] glyphBits = new uint[(GlyphCount + 31) >> 5];
            ushort minGlyphId = 65535;
            ushort maxGlyphId = 0;
 
            WritingSystem[] complexScripts;
            TypographyAvailabilities typography = TypographyAvailabilities.None; 
 
            GsubGposTables GsubGpos = new GsubGposTables(this);
 
            // preparing the glyph bits. When the bit is set, it means the corresponding
            // glyph needs to be checked against.
            for (int i = 0; i < fastTextRanges.Length; i++)
            { 
                int firstChar = fastTextRanges[i].firstChar;
                int lastChar = fastTextRanges[i].lastChar; 
 
                for (int ch = firstChar; ch <= lastChar; ch++)
                { 
                    ushort glyphId;
                    if (CharacterMap.TryGetValue(ch, out glyphId))
                    {
                        glyphBits[glyphId >> 5] |= (uint)(1 << (glyphId % 32)); 

                        if (glyphId > maxGlyphId) maxGlyphId = glyphId; 
                        if (glyphId < minGlyphId) minGlyphId = glyphId; 
                    }
                } 
            }

            //
            // Step 1: call OpenType layout engine to test presence of 
            // 'locl' feature. Based on the returned writing systems, set
            // FastTextMajorLanguageLocalizedFormAvailable bit and 
            // FastTextExtraLanguageLocalizedFormAvailable bit 
            //
            OpenTypeLayoutResult result; 
            unsafe
            {
                result = OpenTypeLayout.GetComplexLanguageList(
                             GsubGpos, 
                             LoclFeature,
                             glyphBits, 
                             minGlyphId, 
                             maxGlyphId,
                             out complexScripts 
                        );
            }

            if (result != OpenTypeLayoutResult.Success) 
            {
                // The check failed. We abort and don't keep partial results that are not reliable 
                return TypographyAvailabilities.None; 
            }
            else if (complexScripts != null) 
            {
                // This is the bits for localized form we would want to set
                // if both bits for localized form were set, we can end the loop earlier
                TypographyAvailabilities loclBitsTest = 
                      TypographyAvailabilities.FastTextMajorLanguageLocalizedFormAvailable
                    | TypographyAvailabilities.FastTextExtraLanguageLocalizedFormAvailable; 
 
                for (int i = 0; i < complexScripts.Length && typography != loclBitsTest; i++)
                { 
                    if (MajorLanguages.Contains((LanguageTags)complexScripts[i].langSysTag))
                    {
                        typography |= TypographyAvailabilities.FastTextMajorLanguageLocalizedFormAvailable;
                    } 
                    else
                    { 
                        typography |= TypographyAvailabilities.FastTextExtraLanguageLocalizedFormAvailable; 
                    }
                } 
            }

            //
            // step 2: continue to find out whether there is common features availabe 
            // in the font for the unicode ranges and set the FastTextTypographyAvailable bit
            // 
            unsafe 
            {
                result = OpenTypeLayout.GetComplexLanguageList( 
                    GsubGpos,
                    RequiredTypographyFeatures,
                    glyphBits,
                    minGlyphId, 
                    maxGlyphId,
                    out complexScripts 
                    ); 
            }
 
            if (result != OpenTypeLayoutResult.Success)
            {
                // The check failed. We abort and don't keep partial results that are not reliable
                return TypographyAvailabilities.None; 
            }
            else if (complexScripts != null) 
            { 
                typography |= TypographyAvailabilities.FastTextTypographyAvailable;
            } 

            //
            // Step 3: call OpenType layout engine to find out if there is any feature present for
            // ideographs. Because there are many ideographs to check for, an alternative is to 
            // check for all scripts with the required features in the font by setting all
            // glyph bits to 1, then see whether CJKIdeograph is in the returned list. 
            // 
            for (int i = 0; i < glyphBits.Length; i++)
            { 
                glyphBits[i] = 0xFFFFFFFF;
            }

            unsafe 
            {
                result = OpenTypeLayout.GetComplexLanguageList( 
                             GsubGpos, 
                             RequiredFeatures,
                             glyphBits, 
                             minGlyphId,
                             maxGlyphId,
                             out complexScripts
                        ); 
            }
 
            if (result != OpenTypeLayoutResult.Success) 
            {
                // The check failed. We abort and don't keep partial results that are not reliable 
                return TypographyAvailabilities.None;
            }
            else if (complexScripts != null)
            { 
                for (int i = 0; i < complexScripts.Length; i++)
                { 
                    if (complexScripts[i].scriptTag == (uint)ScriptTags.CJKIdeographic) 
                    {
                        typography |= TypographyAvailabilities.IdeoTypographyAvailable; 
                    }
                    else
                    {
                        typography |= TypographyAvailabilities.Available; 
                    }
                } 
            } 

            if (typography != TypographyAvailabilities.None) 
            {
                // if any of the bits were set, set TypographyAvailabilities.Avaialble bit
                // as well to indicate some lookup is available.
                typography |= TypographyAvailabilities.Available; 
            }
 
            return typography; 
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks, can result in spoofing.
        /// 
        [SecurityCritical] 
        internal unsafe void SetGsub(CheckedPointer gsub)
        { 
            _layout->offGsub = SetTable(gsub); 
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks, can result in spoofing.
        /// 
        [SecurityCritical] 
        internal unsafe void SetGpos(CheckedPointer gpos)
        { 
            _layout->offGpos = SetTable(gpos); 
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks, can result in spoofing.
        /// 
        [SecurityCritical] 
        internal unsafe void SetGdef(CheckedPointer gdef)
        { 
            _layout->offGdef = SetTable(gdef); 
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks, can result in spoofing.
        /// 
        [SecurityCritical] 
        internal unsafe void SetJstf(CheckedPointer jstf)
        { 
            _layout->offJstf = SetTable(jstf); 
        }
 
        /// 
        ///     Critical: Calls unsafe code blocks to store a list of names into a filemapping object, can result in spoofing.
        /// 
        [SecurityCritical] 
        private int ConvertNames(LocalizedName[] names)
        { 
            if (names == null) 
                return Util.nullOffset;
            unsafe 
            {
                int cacheOffset = _cacher.Alloc(sizeof(CachedNames) + names.Length * sizeof(CachedName));
                CachedNames* cachedNames = (CachedNames*)_cacher[cacheOffset];
                cachedNames->numberOfNames = names.Length; 

                CachedName* cachedName = (CachedName*)((byte*)cachedNames + sizeof(CachedNames)); 
 
                for (int i = 0; i < names.Length; ++i)
                { 
                    // GetEquivalentCulture() should always succeed, because we started with information in a
                    //  a TrueType file, which contained an LCID.
                    cachedName->language = names[i].OriginalLCID;
                    cachedName->nameSize = Util.StringSize(names[i].Name); 
                    cachedName->nameString = _cacher.Alloc(cachedName->nameSize);
                    Util.StringCopyToCheckedPointer(_cacher.GetCheckedPointer(cachedName->nameString), names[i].Name); 
                    ++cachedName; 
                }
                return cacheOffset; 
            }
        }

        ///  
        ///     Critical: Calls unsafe code blocks to set the various fields in _layout
        ///     TreatAsSafe: The pointers themselves are not exposed. Also the construction 
        ///     of _layout is tracked to ensure that it cannot be hijacked. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void AddLocalizedNames(ref TrueTypeFontDriver.ParsedNameTable nameTable, bool skipFontDifferentiation)
        {
            unsafe
            { 
                _layout->version = nameTable.version;
                _layout->familyNames = ConvertNames(nameTable.familyNames); 
                _layout->win32FamilyNames = ConvertNames(nameTable.win32FamilyNames); 
                _layout->faceNames = ConvertNames(nameTable.faceNames);
                _layout->win32faceNames = ConvertNames(nameTable.win32faceNames); 

                // Run font differentiator to adjust family and face names.
                FontStyle adjustedStyle = _layout->style;
                FontWeight adjustedWeight = _layout->weight; 
                FontStretch adjustedStretch = _layout->stretch;
 
                LocalizedName[] oldFaceNames = nameTable.faceNames; 
                if (!skipFontDifferentiation)
                { 
                    FontDifferentiator.AdjustFamilyAndFaceInformation(ref nameTable, ref adjustedStyle, ref adjustedWeight, ref adjustedStretch);
                }

                // We store only adjusted face names in cache at this point, but if we decide to expose the rest, 
                // this is the right place to store this information in the cache.
 
                if (nameTable.faceNames == null) 
                {
                    // We have only legacy face names. 
                    _layout->adjustedFaceNames = _layout->win32faceNames;
                }
                else
                { 
                    if (oldFaceNames == nameTable.faceNames)
                    { 
                        // Font differentiator didn't modify preferred face names. 
                        _layout->adjustedFaceNames = _layout->faceNames;
                    } 
                    else
                    {
                        // Font differentiator modified preferred face names.
                        _layout->adjustedFaceNames = ConvertNames(nameTable.faceNames); 
                    }
                } 
 
                _layout->versionStrings = ConvertNames(nameTable.versionStrings);
                _layout->copyrights = ConvertNames(nameTable.copyrights); 
                _layout->manufacturerNames = ConvertNames(nameTable.manufacturerNames);
                _layout->trademarks = ConvertNames(nameTable.trademarks);
                _layout->designerNames = ConvertNames(nameTable.designerNames);
                _layout->descriptions = ConvertNames(nameTable.descriptions); 
                _layout->vendorUrls = ConvertNames(nameTable.vendorUrls);
                _layout->designerUrls = ConvertNames(nameTable.designerUrls); 
                _layout->licenseDescriptions = ConvertNames(nameTable.licenseDescriptions); 
                _layout->sampleTexts = ConvertNames(nameTable.sampleTexts);
            } 
        }

        /// 
        ///     Critical: This code yieds accesses unsafe method ElementCacher and uses _layout 
        ///     TreatAsSafe: This code exposes and IDictionary object for Family Names which is ok
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        internal unsafe IDictionary GetFamilyNameDictionary()
        { 
            return new LocalizedNameDictionary(
                _cacher,
                _layout->familyNames,       // primary lookup
                _layout->win32FamilyNames   // fall back lookup 
                );
        } 
 
        /// 
        ///     Critical: This calls into unsafe code to retrieve the family name 
        ///     TreatAsSafe:This information is ok to give out and returns a dictionary
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal unsafe IDictionary GetWin32FamilyNameDictionary() 
        {
            return new LocalizedNameDictionary(_cacher, _layout->win32FamilyNames); 
        } 

        ///  
        ///     Critical: This calls into unsafe code to retrieve the face name
        ///     TreatAsSafe:This information is ok to give out
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal unsafe IDictionary GetFaceNameDictionary()
        { 
            return new LocalizedNameDictionary( 
                _cacher,
                _layout->faceNames,         // primary lookup 
                _layout->win32faceNames     // fall back lookup
                );
        }
 
        /// 
        ///     Critical: This calls into unsafe code to retrieve the face name 
        ///     TreatAsSafe:This information is ok to give out 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal unsafe IDictionary GetWin32FaceNameDictionary()
        {
            return new LocalizedNameDictionary(_cacher, _layout->win32faceNames);
        } 

        ///  
        ///     Critical: This calls into unsafe code to retrieve the adjusted family name 
        ///     TreatAsSafe: This information is ok to give out.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal unsafe IDictionary GetAdjustedFaceNameDictionary()
        {
            return new LocalizedNameDictionary(_cacher, _layout->adjustedFaceNames); 
        }
 
        ///  
        ///     Critical: This calls into unsafe code to retrieve the version string,
        ///     and this exposes extra font information not needed for rendering. 
        /// 
        [SecurityCritical]
        internal unsafe IDictionary GetVersionStringDictionary()
        { 
            return new LocalizedNameDictionary(_cacher, _layout->versionStrings);
        } 
 
        /// 
        ///     Critical: This calls into unsafe code to retrieve copyright information, 
        ///     and this exposes extra font information not needed for rendering.
        /// 
        [SecurityCritical]
        internal unsafe IDictionary GetCopyrightDictionary() 
        {
            return new LocalizedNameDictionary(_cacher, _layout->copyrights); 
        } 

        ///  
        ///     Critical: This calls into unsafe code to retrieve the manufacturer name,
        ///     and this exposes extra font information not needed for rendering.
        /// 
        [SecurityCritical] 
        internal unsafe IDictionary GetManufacturerNameDictionary()
        { 
            return new LocalizedNameDictionary(_cacher, _layout->manufacturerNames); 
        }
        ///  
        ///     Critical: This calls into unsafe code to retrieve trademark,
        ///     and this exposes extra font information not needed for rendering.
        /// 
        [SecurityCritical] 
        internal unsafe IDictionary GetTrademarkDictionary()
        { 
            return new LocalizedNameDictionary(_cacher, _layout->trademarks); 
        }
 
        /// 
        ///     Critical: This calls into unsafe code to retrieve the Designer Name,
        ///     and this exposes extra font information not needed for rendering.
        ///  
        [SecurityCritical]
        internal unsafe IDictionary GetDesignerNameDictionary() 
        { 
            return new LocalizedNameDictionary(_cacher, _layout->designerNames);
        } 

        /// 
        ///     Critical: This calls into unsafe code to retrieve the dscription,
        ///     and this exposes extra font information not needed for rendering. 
        /// 
        [SecurityCritical] 
        internal unsafe IDictionary GetDescriptionDictionary() 
        {
            return new LocalizedNameDictionary(_cacher, _layout->descriptions); 
        }

        /// 
        ///     Critical: This calls into unsafe code to retrieve the Vendor Url, 
        ///     and this exposes extra font information not needed for rendering.
        ///  
        [SecurityCritical] 
        internal unsafe IDictionary GetVendorUrlDictionary()
        { 
            return new LocalizedNameDictionary(_cacher, _layout->vendorUrls);
        }

        ///  
        ///     Critical: This calls into unsafe code to retrieve the dsigner uri,
        ///     and this exposes extra font information not needed for rendering. 
        ///  
        [SecurityCritical]
        internal unsafe IDictionary GetDesignerUrlDictionary() 
        {
            return new LocalizedNameDictionary(_cacher, _layout->designerUrls);
        }
 
        /// 
        ///     Critical: This calls into unsafe code to retrieve the Licensce, 
        ///     and this exposes extra font information not needed for rendering. 
        /// 
        [SecurityCritical] 
        internal unsafe IDictionary GetLicenseDescriptionDictionary()
        {
            return new LocalizedNameDictionary(_cacher, _layout->licenseDescriptions);
        } 

        ///  
        ///     Critical: This calls into unsafe code to retrieve the sample text 
        /// 
        [SecurityCritical] 
        internal unsafe IDictionary GetSampleTextDictionary()
        {
            return new LocalizedNameDictionary(_cacher, _layout->sampleTexts);
        } 
        #region IntMap
 
        ///  
        /// IntMap represents mapping from UTF32 code points to glyph indices.
        /// The IDictionary part is eventually returned from public APIs and is made read-only. 
        /// Internal methods are used by the font driver to create the cmap.
        /// 
        internal sealed class IntMap : IDictionary
        { 
            internal static int InitialSize()
            { 
                unsafe { return sizeof(int) + NumberOfPlanes * sizeof(int); } 
            }
 
            /// 
            ///     Critical: Calls into probe which is critical and also has unsafe code blocks, can be used to spoof cmap.
            /// 
            [SecurityCritical] 
            internal IntMap(CheckedPointer p, ElementCacher cacher)
            { 
                unsafe { _data = (byte*)p.Probe(0, InitialSize()); } 
                _cacher = cacher;
            } 

            /// 
            ///    Critical: This code accesses unsafe code blocks
            ///    TreatAsSafe: This information is ok to return for get but bad for set 
            /// 
            internal unsafe int CharacterCount 
            { 
                [SecurityCritical, SecurityTreatAsSafe]
                get 
                {
                    return *(int*)_data;
                }
                [SecurityCritical] 
                set
                { 
                    *(int*)_data = value; 
                }
            } 

            /// 
            ///    Critical: Calls into critical code which does an unsafe operation FillMemory.
            ///    TreatAsSafe: Ok to expose, since GetPlanePointer will return a valid value and number of planes is a const. 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            internal void Init() 
            {
                CharacterCount = 0; 
                unsafe { Util.FillMemory(GetPlanePointer(0), NumberOfPlanes * sizeof(int), EmptyPlane); }
            }

            ///  
            /// Glyph count is used for validating cmap contents.
            /// If we discover that glyph index we are about to set or return is outside of glyph range, 
            /// we throw an exception. 
            /// 
            ///  
            ///     Critical: Setting this from unauthorized functions increases the risk of failure in functions that
            ///     work with _glyphcount
            /// 
            [SecurityCritical] 
            internal void SetGlyphCount(ushort glyphCount)
            { 
                _glyphCount = new SecurityCriticalDataForSet(glyphCount); 
            }
 
            /// 
            ///   Critical: This code calls into unsafe code blocks and gets a pointer back. It uses
            ///   this to initialize a character entry. Can be used to spoof cmap.
            ///  
            [SecurityCritical]
            internal void SetCharacterEntry(int i, ushort value) 
            { 
                // Some fonts have cmap entries that point to glyphs outside of the font.
                // Just skip such entries. 
                if (value >= _glyphCount.Value)
                    return;

                int plane = CreatePlane(i >> 16); 
                int page = CreatePage(plane, i >> 8 & 0xff);
                unsafe 
                { 
                    ushort* characterEntry = GetGlyphPointer(page, i & 0xff);
                    if (*characterEntry == 0 && value != 0) 
                        ++CharacterCount;
                    *characterEntry = value;
                }
            } 

            ///  
            ///    Critical: Calls into unsafe code block and returns a pointer 
            /// 
            [SecurityCritical] 
            private unsafe int* GetPlanePointer(int i)
            {
                if (i < 0 || i >= NumberOfPlanes)
                    throw new ArgumentOutOfRangeException("c", SR.Get(SRID.CodePointOutOfRange, i)); 
                return ((int*)_data) + i + 1;
            } 
 
            /// 
            ///    Critical: Calls into unsafe code 
            ///    TreatAsSafe: This code does not expose the pointer and is safe to call
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            private unsafe int GetPlane(int i) 
            {
                return *GetPlanePointer(i); 
            } 

            ///  
            ///    Critical: Calls into unsafe code block and exposes a pointer
            /// 
            [SecurityCritical]
            private unsafe int* GetPagePointer(int plane, int i) 
            {
                Invariant.Assert(0 <= i && i < NumberOfPages); 
                return ((int*)_cacher[plane]) + i; 
            }
 

            /// 
            ///    Critical: Calls into unsafe code block
            ///    TreatAsSafe: This code does not expose the pointer and is safe to call 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            private unsafe int GetPage(int plane, int i) 
            {
                return *GetPagePointer(plane, i); 
            }

            /// 
            ///    Critical: Calls into unsafe code block 
            /// 
            [SecurityCritical] 
            private unsafe ushort* GetGlyphPointer(int page, int key) 
            {
                Invariant.Assert(0 <= key && key < PageSize); 
                return (ushort*)_cacher[page] + key;
            }

            ///  
            ///    Critical: Calls into unsafe code block
            ///    TreatAsSafe: This code does not expose the pointer and is safe to call 
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            private unsafe ushort GetGlyph(int page, int key) 
            {
                return *GetGlyphPointer(page, key);
            }
 

            ///  
            ///    Critical: Calls into unsafe code block 
            ///    TreatAsSafe: Ok to expose this function. It uses _cacher which is
            ///    bounds checked. 
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            private int CreatePlane(int i)
            { 
                unsafe
                { 
                    int* plane = GetPlanePointer(i); 
                    if (*plane == EmptyPlane)
                    { 
                        *plane = _cacher.Alloc(NumberOfPages * sizeof(int));
                        Util.FillMemory(_cacher[*plane], NumberOfPages * sizeof(int), EmptyPage);
                    }
                    return *plane; 
                }
            } 
 
            /// 
            ///    Critical: Calls into unsafe code block 
            ///    TreatAsSafe: Ok to expose, it used cacher which is bounds checked, it
            ///    uses GetPlanePointer which uses a const int and hence the index into
            ///    the array cannot be breached.
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            private int CreatePage(int plane, int i) 
            { 
                unsafe
                { 
                    int* page = GetPagePointer(plane, i);
                    if (*page == EmptyPage)
                    {
                        *page = _cacher.Alloc(PageSize * sizeof(short)); 
                        Util.FillMemory(_cacher[*page], PageSize * sizeof(short), 0);
                    } 
                    return *page; 
                }
            } 

            #region IDictionary Members
            public void Add(int key, ushort value)
            { 
                throw new NotSupportedException();
            } 
 
            public bool ContainsKey(int key)
            { 
                ushort glyphIndex;
                return TryGetValue(key, out glyphIndex);
            }
 
            public ICollection Keys
            { 
                get 
                {
                    // This is inefficient, but Keys is not used too often to justify optimizing it. 
                    int[] keys = new int[Count];
                    int i = 0;
                    foreach (KeyValuePair pair in this)
                    { 
                        keys[i++] = pair.Key;
                    } 
                    Debug.Assert(i == Count); 
                    return keys;
                } 
            }

            public bool Remove(int key)
            { 
                throw new NotSupportedException();
            } 
 
            public bool TryGetValue(int key, out ushort value)
            { 
                try
                {
                    int plane = GetPlane(key >> 16);
                    if (plane != EmptyPlane) 
                    {
                        int page = GetPage(plane, key >> 8 & 0xff); 
                        if (page != EmptyPage) 
                        {
                            ushort glyphIndex = GetGlyph(page, key & 0xff); 
                            Debug.Assert(glyphIndex < _glyphCount.Value);
                            if (glyphIndex != 0)
                            {
                                value = glyphIndex; 
                                return true;
                            } 
                        } 
                    }
                } 
                catch (ArgumentOutOfRangeException)
                {
                    // GetPlane() throws ArgumentOutOfRangeException if the key value is outside of the valid Unicode range.
                    // Since IDictionary semantics requre returning false for non-existent keys, we need to catch it. 
                }
                value = new ushort(); 
                return false; 
            }
 
            public ICollection Values
            {
                get
                { 
                    // This is inefficient, but Values is not used too often to justify optimizing it.
                    ushort[] values = new ushort[Count]; 
                    int i = 0; 
                    foreach (KeyValuePair pair in this)
                    { 
                        values[i++] = pair.Value;
                    }
                    Debug.Assert(i == Count);
                    return values; 
                }
            } 
 
            ushort IDictionary.this[int i]
            { 
                get
                {
                    ushort glyphIndex;
                    if (!TryGetValue(i, out glyphIndex)) 
                        throw new KeyNotFoundException();
                    return glyphIndex; 
                } 
                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");
                } 
 
                foreach (KeyValuePair pair in this)
                    array[arrayIndex++] = pair; 
            }

            public int Count
            { 
                get { return CharacterCount; }
            } 
 
            public bool IsReadOnly
            { 
                get { return true; }
            }

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

            #endregion 

            #region IEnumerable> Members

            public IEnumerator> GetEnumerator() 
            {
                for (int i = 0; i < NumberOfPlanes; ++i) 
                { 
                    int plane = GetPlane(i);
                    if (plane != EmptyPlane) 
                    {
                        for (int j = 0; j < NumberOfPages; ++j)
                        {
                            int page = GetPage(plane, j); 
                            if (page != EmptyPage)
                            { 
                                for (int k = 0; k < PageSize; ++k) 
                                {
                                    ushort glyph = GetGlyph(page, k); 
                                    if (glyph != 0)
                                        yield return new KeyValuePair(
                                            (i << 16) | (j << 8) | k,
                                            glyph 
                                            );
                                } 
                            } 
                        }
                    } 
                }
            }

            #endregion 

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

            #endregion 
            /// 
            ///  Critical:This code holds a pointer and is unsafe to let out 
            ///  
            [SecurityCritical]
            private unsafe byte* _data; 
            private ElementCacher _cacher;
            /// 
            ///  Critical:This code is used to dereference a memory location and is hence critical
            ///  
            private SecurityCriticalDataForSet _glyphCount;
 
            private const int NumberOfPlanes = 17; 
            private const int NumberOfPages = 256;
            private const int PageSize = 256; 
            private const int EmptyPlane = Util.nullOffset;
            private const int EmptyPage = Util.nullOffset;
        }
 
        internal enum RenderingHints : ushort
        { 
            Regular = 0, 
            LegacyEastAsian = 1
        }; 

        #endregion

        //------------------------------------------------------ 
        //
        //  Private Fields 
        // 
        //-----------------------------------------------------
 
        #region Private Fields
        private ElementCacher _cacher;
        /// 
        ///   Critical: Holds reference to an unmanaged pointer 
        /// 
        [SecurityCritical] 
        private unsafe Layout* _layout; 
        private IntMap _cmap;
        private int _faceIndex; 
        private long _timeStamp;

        private FontSource _fontSource;
 
        // 'locl' feature which is language sensitive
        private static readonly uint[] LoclFeature = new uint[] 
        { 
           (uint)OpenTypeTags.locl
        }; 

        // common features for fast text
        // They are insensitive to languages
        private static readonly uint[] RequiredTypographyFeatures = new uint[] 
        {
           (uint)OpenTypeTags.ccmp, 
           (uint)OpenTypeTags.rlig, 
           (uint)OpenTypeTags.liga,
           (uint)OpenTypeTags.clig, 
           (uint)OpenTypeTags.calt,
           (uint)OpenTypeTags.kern,
           (uint)OpenTypeTags.mark,
           (uint)OpenTypeTags.mkmk 
        };
 
        // All required features 
        private static readonly uint[] RequiredFeatures = new uint[]
        { 
           (uint)OpenTypeTags.locl,
           (uint)OpenTypeTags.ccmp,
           (uint)OpenTypeTags.rlig,
           (uint)OpenTypeTags.liga, 
           (uint)OpenTypeTags.clig,
           (uint)OpenTypeTags.calt, 
           (uint)OpenTypeTags.kern, 
           (uint)OpenTypeTags.mark,
           (uint)OpenTypeTags.mkmk 
        };

        private static readonly UnicodeRange[] fastTextRanges = new UnicodeRange[]
        { 
            new UnicodeRange(0x20  , 0x7e  ),    // basic latin
            new UnicodeRange(0xA1  , 0xFF  ),    // latin-1 supplement, 
            new UnicodeRange(0x0100, 0x17F ),    // latin extended-A 
            new UnicodeRange(0x0180, 0x024F),    // latin extended-B
            new UnicodeRange(0x1E00, 0x1EFF),    // latin extended additional (Vietnamese precomposed) 
            new UnicodeRange(0x3040, 0x309F),    // hiragana
            new UnicodeRange(0x30A0, 0x30FF)     // kana
        };
 
        #endregion Private Fields
 
        #region Private Types 

        // LocalizedNameDictionary implements IDictionary in terms 
        // of one or two arrays of CachedName structures. Each array is assumed to be
        // sorted by LCID.
        //
        // If two arrays are specified, we use the first array for primary lookup and 
        // the second array as a fallback. We use integer indexes internally to refer to
        // culture/name pairs. We can tell from its value whether an index refers to the 
        // first or second array (see the GetCachedName method). An index must be less 
        // than the *sum* of the sizes of the two arrays, specified by the Limit property.
        // 
        // If the fallback array contains keys which are also in the primary array, we
        // don't want to enumerate them or include them in the Count. For this reason,
        // Count may be less than Limit. We use the IsDuplicateKey method during enumeration
        // to determine whether to skip an index, and we use GetCountWithoutDuplicates to 
        // calculate the count.
        // 
        private unsafe struct LocalizedNameDictionary : IDictionary 
        {
            private ElementCacher _cacher; 

            // primary table of strings
            /// 
            ///     Critical:This holds reference to a pointer 
            /// 
            [SecurityCritical] 
            private CachedName* _cachedName; 
            /// 
            ///     Critical:This holds data that is used to make decisions on dereferencing a pointer 
            /// 
            private SecurityCriticalDataForSet _numberOfNames;

            // secondary table of strings 
            /// 
            ///     Critical:This holds reference to a pointer 
            ///  
            [SecurityCritical]
            private CachedName* _cachedNameFallback; 
            /// 
            ///     Critical:This holds data that is used to make decisions on dereferencing a pointer
            /// 
            private SecurityCriticalDataForSet _numberOfNamesFallback; 

            // number of strings, excluding duplicates; may be computed lazily 
            private int _count; 

            ///  
            /// Construct a dictionary using a single array of cached strings.
            /// 
            internal LocalizedNameDictionary(ElementCacher cacher, int cacheOffset)
                : 
                this(cacher, cacheOffset, Util.nullOffset)
            { 
            } 

            ///  
            /// Construct a dictionary with a primary and fallback array of cached strings.
            /// 
            /// 
            ///     Critical:This accesses elementcacher and is unsafe 
            ///     TreatAsSafe: Calling this is ok also it does not expose the pointers.
            ///  
            [SecurityCritical, SecurityTreatAsSafe] 
            internal LocalizedNameDictionary(ElementCacher cacher, int cacheOffset, int cacheOffsetFallback)
            { 
                _cacher = cacher;

                // It's quite common for a font to provide only a Win32-compatible table.
                // If there's only one table we always want to make it the primary table 
                // for reasons of efficiency.
                if (cacheOffset == Util.nullOffset) 
                { 
                    cacheOffset = cacheOffsetFallback;
                    cacheOffsetFallback = Util.nullOffset; 
                }

                // Initialize the primary table.
                if (cacheOffset != Util.nullOffset) 
                {
                    CachedNames* cachedNames = (CachedNames*)_cacher[cacheOffset]; 
                    _cachedName = (CachedName*)((byte*)cachedNames + sizeof(CachedNames)); 
                    _numberOfNames = new SecurityCriticalDataForSet(cachedNames->numberOfNames);
                } 
                else
                {
                    _cachedName = null;
                    _numberOfNames = new SecurityCriticalDataForSet(0); 
                }
 
                // Initialize the secondary table. 
                if (cacheOffsetFallback != Util.nullOffset)
                { 
                    CachedNames* cachedNames = (CachedNames*)_cacher[cacheOffsetFallback];
                    _cachedNameFallback = (CachedName*)((byte*)cachedNames + sizeof(CachedNames));
                    _numberOfNamesFallback = new SecurityCriticalDataForSet(cachedNames->numberOfNames);
                } 
                else
                { 
                    _cachedNameFallback = null; 
                    _numberOfNamesFallback = new SecurityCriticalDataForSet(0);
                } 

                // Initialize count.
                if (_numberOfNamesFallback.Value == 0 || _numberOfNames.Value == 0)
                { 
                    // If there's only one non-empty table then we don't need to check
                    // for duplicate keys. 
                    _count = _numberOfNamesFallback.Value + _numberOfNames.Value; 
                }
                else 
                {
                    // Compute count lazily because we need to check for duplicates.
                    _count = -1;
                } 
            }
 
            ///  
            ///     Critical:This accesses elementcacher and is unsafe it also returns a pointer
            ///  
            [SecurityCritical]
            private CachedName* GetCachedName(int index)
            {
                // We should be checking bounds farther up the stack, e.g., in Enumerator class. 
                Invariant.Assert(index >= 0 && index < Limit);
 
                // Look in primary or secondary table depending on value of index. 
                if (index < _numberOfNames.Value)
                { 
                    return _cachedName + index;
                }
                else
                { 
                    return _cachedNameFallback + (index - _numberOfNames.Value);
                } 
            } 

            ///  
            ///     Critical:This accesses elementcacher which is unsafe
            ///     TreatAsSafe: This code accesses GetCachedName which returns a pointer ,returning this data is ok
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            private int GetLCID(int index)
            { 
                return GetCachedName(index)->language; 
            }
 

            /// 
            ///     Critical:This accesses elementcacher and GetCachedName
            ///     TreatAsSafe: Returning this data is ok also the two functions 
            ///     safeguard against invalid values
            ///  
            [SecurityCritical, SecurityTreatAsSafe] 
            private string GetName(int index)
            { 
                CachedName* cachedName = GetCachedName(index);
                return Util.StringCopyFromCheckedPointer(_cacher.GetCheckedPointer(cachedName->nameString), cachedName->nameSize);
            }
 
            /// 
            /// Look up an LCID in the specified table. 
            ///  
            /// LCID to look up.
            /// Offset to add to returned index if found. 
            /// Array of CachedName structures.
            /// Size of the array.
            /// Index of match (plus offset) or -1 if not found.
            ///  
            ///     Critical:This accesses elementcacher and is unsafe it also accepts a pointer
            ///  
            [SecurityCritical] 
            private int FindLCID(int lcid, int offset, CachedName* cachedName, int numberOfNames)
            { 
                // Look up name based on LCID using binary search.
                int min = 0, lim = numberOfNames;
                while (min < lim)
                { 
                    int i = (min + lim) / 2;
                    int key = cachedName[i].language; 
                    if (lcid < key) 
                        lim = i;
                    else if (lcid > key) 
                        min = i + 1;
                    else
                        return i + offset;
                } 
                return -1;
            } 
            ///  
            ///     Critical: This code calls accesses _cachedName
            ///     TreatAsSafe: The pointer is not exposed and LCID is ok to give out 
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            private int FindPrimaryLCID(int lcid)
            { 
                return FindLCID(
                    lcid,               // LCID to look for 
                    0,                  // no offset 
                    _cachedName,        // look in primary array
                    _numberOfNames.Value); 
            }
            /// 
            ///     Critical: This code calls accesses _cachedNameFallBack
            ///     TreatAsSafe: The pointer is not exposed and the call to FindLCID is safe 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            private int FindSecondaryLCID(int lcid) 
            {
                return FindLCID( 
                    lcid,                   // LCID to look for
                    _numberOfNames.Value,         // offset added to result if found
                    _cachedNameFallback,    // look in secondary array
                    _numberOfNamesFallback.Value); 
            }
 
            ///  
            /// Look up an LCID in both tables.
            ///  
            private int FindLCID(int lcid)
            {
                // Look up in primary name table.
                int i = FindPrimaryLCID(lcid); 

                // Fall back to secondary name table. 
                if (i < 0 && _numberOfNamesFallback.Value != 0) 
                {
                    i = FindSecondaryLCID(lcid); 
                }

                return i;
            } 

            ///  
            /// Returns the name for the given LCID or null if not found. 
            /// 
            internal string GetNameFromLCID(int lcid) 
            {
                int i = FindLCID(lcid);
                return (i >= 0) ? GetName(i) : null;
            } 

            ///  
            /// Determines whether the specified index is a duplicate key, which 
            /// should be skipped during enumeration.
            ///  
            /// 
            ///     Critical:This accesses elementcacher and is unsafe
            ///     TreatAsSafe: Calling this is ok since all it returns is whether a key is duped
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            internal bool IsDuplicateKey(int index) 
            { 
                // We should be checking bounds higher up the stack, e.g., in Enumerator class.
                Invariant.Assert(index >= 0 && index < Limit); 

                // Keys in the primary table are not duplicates by definition.
                if (index < _numberOfNames.Value)
                    return false; 

                // If we find the LCID in the primary table then it's a duplicate. 
                int lcid = _cachedNameFallback[index - _numberOfNames.Value].language; 
                return FindPrimaryLCID(lcid) >= 0;
            } 

            /// 
            /// Computes the count (if not already known). The count excludes
            /// indexes for which IsDuplicateKey is true. 
            /// 
            ///  
            ///     Critical:This accesses elementcacher and is unsafe 
            ///     TreatAsSafe: Calling this is ok does not return the critical data
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            private int GetCountWithoutDuplicates()
            {
                if (_count < 0) 
                {
                    // include all keys in the primary table 
                    _count = _numberOfNames.Value; 

                    // iterate over the secondary table including only non-duplicates 
                    for (int i = 0; i < _numberOfNamesFallback.Value; ++i)
                    {
                        int lcid = _cachedNameFallback[i].language;
                        if (FindPrimaryLCID(lcid) < 0) 
                        {
                            // not a duplicate 
                            _count++; 
                        }
                    } 
                }

                return _count;
            } 

            ///  
            /// Limit value for indexes. May differ from Count because the range 
            /// of indexes may include duplicate keys which are not enumerated or
            /// included in the Count. 
            /// 
            internal int Limit
            {
                get 
                {
                    return _numberOfNames.Value + _numberOfNamesFallback.Value; 
                } 
            }
 
            #region IDictionary Members

            bool IDictionary.Remove(CultureInfo key)
            { 
                throw new NotSupportedException();
            } 
 
            void IDictionary.Add(CultureInfo key, string value)
            { 
                throw new NotSupportedException();
            }

            ICollection IDictionary.Keys 
            {
                get 
                { 
                    // OK, this is very slow, but semantically correct.
                    // Keys are not used that often anyway. 
                    CultureInfo[] keys = new CultureInfo[GetCountWithoutDuplicates()];

                    // Enumerator will automatically skip duplicates.
                    int i = 0; 
                    foreach (KeyValuePair pair in this)
                    { 
                        keys[i++] = pair.Key; 
                    }
 
                    // Debug check for enumeration logic.
                    Debug.Assert(i == keys.Length);

                    return keys; 
                }
            } 
 
            string IDictionary.this[CultureInfo key]
            { 
                get
                {
                    return GetNameFromLCID(key.LCID);
                } 
                set
                { 
                    throw new NotSupportedException(); 
                }
            } 

            bool IDictionary.TryGetValue(CultureInfo key, out string value)
            {
                int i = FindLCID(key.LCID); 
                if (i >= 0)
                { 
                    value = GetName(i); 
                    return true;
                } 
                else
                {
                    value = null;
                    return false; 
                }
            } 
 
            ICollection IDictionary.Values
            { 
                get
                {
                    // OK, this is very slow, but semantically correct.
                    // Values are not used that often anyway. 
                    string[] values = new string[GetCountWithoutDuplicates()];
 
                    // Enumerator will automatically skip duplicates. 
                    int i = 0;
                    foreach (KeyValuePair pair in this) 
                    {
                        values[i++] = pair.Value;
                    }
 
                    // Debug check for enumeration logic.
                    Debug.Assert(i == values.Length); 
 
                    return values;
                } 
            }

            bool IDictionary.ContainsKey(CultureInfo key)
            { 
                return FindLCID(key.LCID) >= 0;
            } 
 
            #endregion
 
            #region ICollection> Members

            bool ICollection>.Contains(KeyValuePair item)
            { 
                int i = FindLCID(item.Key.LCID);
                return (i >= 0 && String.Compare(GetName(i), item.Value, StringComparison.OrdinalIgnoreCase) == 0); 
            } 

            void ICollection>.Add(KeyValuePair item) 
            {
                throw new NotSupportedException();
            }
 
            bool ICollection>.Remove(KeyValuePair item)
            { 
                throw new NotSupportedException(); 
            }
 
            bool ICollection>.IsReadOnly
            {
                get
                { 
                    return true;
                } 
            } 

            void ICollection>.Clear() 
            {
                throw new NotSupportedException();
            }
 
            int ICollection>.Count
            { 
                get 
                {
                    return GetCountWithoutDuplicates(); 
                }
            }

            void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) 
            {
                int index = arrayIndex; 
                foreach (KeyValuePair pair in this) 
                {
                    array[index] = pair; 
                    ++index;
                }
            }
 
            #endregion
 
            #region IEnumerable> Members 

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

            IEnumerator IEnumerable.GetEnumerator() 
            {
                return new Enumerator(this);
            }
 
            #endregion
 
            // 
            // Enumerator class for LocalizedNameTable. Internally, we represent the current
            // position as an integer index. We enumerate by incrementing the index, taking 
            // into account that some indexes are invalid (i.e., duplicate keys).
            //
            private class Enumerator : IEnumerator>
            { 
                private int _currentIndex;
                private LocalizedNameDictionary _parent; 
 
                public Enumerator(LocalizedNameDictionary parent)
                { 
                    _parent = parent;
                    _currentIndex = -1;
                }
 
                private void FailIfOutOfRange()
                { 
                    if (_currentIndex < 0) 
                        throw new InvalidOperationException(SR.Get(SRID.Enumerator_NotStarted));
 
                    if (_currentIndex >= _parent.Limit)
                        throw new InvalidOperationException(SR.Get(SRID.Enumerator_ReachedEnd));
                }
 
                private CultureInfo GetCurrentCulture()
                { 
                    return CultureInfo.GetCultureInfo(_parent.GetLCID(_currentIndex)); 
                }
 
                private string GetCurrentName()
                {
                    return _parent.GetName(_currentIndex);
                } 

                #region IEnumerator> Members 
 
                public bool MoveNext()
                { 
                    // We may need to increment the index more than once to skip
                    // duplicate keys.
                    do
                    { 
                        ++_currentIndex;
 
                        // stop if we're at the end 
                        if (_currentIndex >= _parent.Limit)
                        { 
                            // prevent cycling
                            _currentIndex = _parent.Limit;
                            return false;
                        } 

                    } while (_parent.IsDuplicateKey(_currentIndex)); 
 
                    return true;
                } 

                KeyValuePair IEnumerator>.Current
                {
                    get 
                    {
                        FailIfOutOfRange(); 
                        return new KeyValuePair(GetCurrentCulture(), GetCurrentName()); 
                    }
                } 

                object IEnumerator.Current
                {
                    get 
                    {
                        return ((IEnumerator>)this).Current; 
                    } 
                }
 
                public void Reset()
                {
                    _currentIndex = -1;
                } 

                #endregion 
 
                #region IDisposable Members
 
                public void Dispose() { }

                #endregion
            } 
        }
 
        #endregion 
    }
 
    /// 
    /// An implementation of IOpenTypeFont which only provides GSUB and GPOS tables
    /// It is used by OTLS API to determine the optimizable script.
    ///  
    /// 
    /// OTLS API always accepts IOpenTypeFont as input parameter. To be consistent, we 
    /// implement this IOpenTypeFont just for OpenTypeLayout.GetComplexLanguangeList(..) method. 
    /// 
    internal sealed class GsubGposTables : IOpenTypeFont 
    {
        /// 
        ///   Critical:    Gsub() and Gpos() return pointers
        ///   
        [SecurityCritical]
        internal GsubGposTables(FontFaceLayoutInfo layout) 
        { 
            _layout    = layout;
            unsafe 
            {
                _gsubTable = new FontTable(_layout.Gsub());
                _gposTable = new FontTable(_layout.Gpos());
            } 
        }
 
        ///  
        /// Returns font table data
        ///  
        public FontTable GetFontTable(OpenTypeTags TableTag)
        {
            switch (TableTag)
            { 
                case OpenTypeTags.GSUB:
                    { 
                        return _gsubTable; 
                    }
                case OpenTypeTags.GPOS: 
                    {
                        return _gposTable;
                    }
                default: 
                    {
                        throw new NotSupportedException(); 
                    } 
            }
        } 

        /// 
        /// Returns glyph coordinate
        ///  
        public LayoutOffset GetGlyphPointCoord(ushort Glyph, ushort PointIndex)
        { 
            throw new NotSupportedException(); 
        }
 
        /// 
        /// Returns cache for layout table. If cache not found, return null Checked pointer
        /// 
        ///  
        ///   Critical:    Calls critical code
        ///   
        [SecurityCritical] 
        public CheckedPointer GetTableCache(OpenTypeTags tableTag)
        { 
            return _layout.GetTableCache(tableTag);
        }

        ///  
        /// Allocate space for layout table cache.
        ///  
        ///  
        ///   Critical:    Calls critical code
        ///   
        [SecurityCritical]
        public CheckedPointer AllocateTableCache(OpenTypeTags tableTag, int size)
        {
            return _layout.AllocateTableCache(tableTag, size); 
        }
 
        private FontTable           _gsubTable; 
        private FontTable           _gposTable;
        private FontFaceLayoutInfo  _layout; 
    }

    /// 
    /// A unicode range identified by a pair of first and last unicode code point 
    /// 
    internal struct UnicodeRange 
    { 
        internal UnicodeRange(int first, int last)
        { 
            firstChar = first;
            lastChar = last;
        }
 
        internal int firstChar;
        internal int lastChar; 
    } 

    ///  
    /// Major language targetted for optimization
    /// 
    internal static class MajorLanguages
    { 
        /// 
        /// check if input langSys is considered a major language. 
        ///  
        ///  true if it is a major language 
        internal static bool Contains(LanguageTags langSys) 
        {
            if (langSys == LanguageTags.Default) return true;

            for (int i = 0; i < majorLanguages.Length; i++) 
            {
                if (majorLanguages[i].LangSys == langSys) 
                    return true; 
            }
            return false; 
        }

        /// 
        /// check if input culture is considered a major language. 
        /// 
        ///  true if it is a major language  
        internal static bool Contains(CultureInfo culture) 
        {
            if (culture == null) return false; 

            // explicitly check for InvariantCulture. We don't need to check for its parent.
            if (culture == CultureInfo.InvariantCulture) return true;
 
            for (int i = 0; i < majorLanguages.Length; i++)
            { 
                if (majorLanguages[i].Culture.Equals(culture) 
                   || majorLanguages[i].Culture.Equals(culture.Parent)
                   ) 
                {
                    return true;
                }
            } 
            return false;
        } 
 
        // major languages
        private static readonly LangSysCulturePair[] majorLanguages = new LangSysCulturePair[] 
            {
                new LangSysCulturePair(new CultureInfo("en"), LanguageTags.English),  // English neutral culture
                new LangSysCulturePair(new CultureInfo("de"), LanguageTags.German),   // German neutral culture
                new LangSysCulturePair(new CultureInfo("ja"), LanguageTags.Japanese)  // Japanese neutral culture 
            };
 
        private struct LangSysCulturePair 
        {
            internal LangSysCulturePair(CultureInfo culture, LanguageTags langSys) 
            {
                Culture = culture;
                LangSys = langSys;
            } 

            internal readonly CultureInfo Culture; 
            internal readonly LanguageTags LangSys; 
        }
    } 


    /// 
    /// An enum flag indicating the availabilities of various open type 
    /// look ups.
    ///  
    ///  
    /// The enum is used to determine whether fast path is applicable.
    /// Ideo     refers to Ideographs 
    /// FastText refers to Other optimizable text
    /// We keep a minimum set of flags here to allow us reliably optimize
    /// the most common inputs. It is not to prevent under-optimization for
    /// all cases. 
    /// 
    [Flags] 
    internal enum TypographyAvailabilities 
    {
        ///  
        /// No required OpenType typography features is available
        /// 
        None = 0,
 
        /// 
        /// There are some lookup available for required typography 
        /// features 
        /// 
        Available = 1, 

        /// 
        /// There are some lookup available for required typography features
        /// for Ideographic script. 
        /// 
        IdeoTypographyAvailable = 2, 
 
        /// 
        /// There are lookup available for required typography features 
        /// for fast text
        /// 
        FastTextTypographyAvailable = 4,
 
        /// 
        /// There are localized form available for major Ui lanaguages for fast text 
        ///  
        ///  MajorLanguages class
        FastTextMajorLanguageLocalizedFormAvailable = 8, 

        /// 
        /// There are localized form for non major Ui language available for fast text
        ///  
        FastTextExtraLanguageLocalizedFormAvailable = 16,
    } 
} 


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

Link Menu

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