FontFaceLayoutInfo.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / MS / Internal / FontCache / FontFaceLayoutInfo.cs / 1407647 / FontFaceLayoutInfo.cs

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

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 
    {

        private FontTechnology _fontTechnology;
        private TypographyAvailabilities _typographyAvailabilities; 
        private FontEmbeddingRight _embeddingRights;
 
        private bool _embeddingRightsInitialized; 
        private bool _gsubInitialized;
        private bool _gposInitialized; 
        private bool _gdefInitialized;
        private bool _fontTechnologyInitialized;
        private bool _typographyAvailabilitiesInitialized;
 
        private byte[] _gsubCache;
        private byte[] _gposCache; 
 
        private byte[] _gsub;
        private byte[] _gpos; 
        private byte[] _gdef;

        Text.TextInterface.Font _font;
 
        ushort _blankGlyphIndex;
 
 
        //-----------------------------------------------------
        // 
        //  Constructors
        //
        //-----------------------------------------------------
 
        #region Constructors
 
 
        /// 
        /// Critical -  Calls into the critical CreateOpenTypeLayoutCache. 
        /// 
        [SecurityCritical]
        internal FontFaceLayoutInfo(Text.TextInterface.Font font)
        { 
            _fontTechnologyInitialized = false;
            _typographyAvailabilitiesInitialized = false; 
            _gsubInitialized            = false; 
            _gposInitialized            = false;
            _gdefInitialized            = false; 
            _embeddingRightsInitialized = false;
            _gsubCache = null;
            _gposCache = null;
            _gsub = null; 
            _gpos = null;
            _gdef = null; 
 
            _font = font;
            _cmap = new IntMap(_font); 
            _cmap.TryGetValue(' ', out _blankGlyphIndex);
        }

        #endregion Constructors 

        internal IntMap CharacterMap 
        { 
            get
            { 
                return _cmap;
            }
        }
 
        internal ushort BlankGlyph
        { 
            get 
            {
                return _blankGlyphIndex; 
            }
        }

        ///  
        /// Critical: This calls into critical DesignUnitsPerEm.
        /// TreatAsSafe: This data is safe to expose. 
        ///  
        internal ushort DesignEmHeight
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get
            {
                return _font.Metrics.DesignUnitsPerEm; 
            }
        } 
 
        private static class Os2EmbeddingFlags
        { 
            public const ushort RestrictedLicense = 0x0002;
            public const ushort PreviewAndPrint = 0x0004;
            public const ushort Editable = 0x0008;
 
            // The font is installable if all bits in the InstallableMask are set to zero.
            public const ushort InstallableMask = RestrictedLicense | PreviewAndPrint | Editable; 
 
            public const ushort NoSubsetting = 0x0100;
            public const ushort BitmapOnly = 0x0200; 
        }

        internal FontEmbeddingRight EmbeddingRights
        { 
            /// 
            /// Analyzes os/2 fsType value and construct FontEmbeddingRight enum value from it. 
            ///  
            /// 
            ///     Critical: This code writes critical information into FontFaceLayoutInfo. 
            ///     TreatAsSafe: It does this only using font data and not user defined parameters.
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            {
                if (!_embeddingRightsInitialized) 
                { 
                    // If there is no os/2 table, default to restricted font.
                    // This is the precedence that has been set by T2Embed, Word, etc. 
                    // No one has complained about this because these fonts are generally lower in quality and are less likely to be embedded.
                    FontEmbeddingRight rights = FontEmbeddingRight.RestrictedLicense;

                    ushort fsType; 
                    bool success;
 
                    MS.Internal.Text.TextInterface.FontFace fontFace = _font.GetFontFace(); 
                    try
                    { 
                        success = fontFace.ReadFontEmbeddingRights(out fsType);
                    }
                    finally
                    { 
                        fontFace.Release();
                    } 
 
                    if (success)
                    { 
                        // Start with the most restrictive flags.
                        // In case a font uses conflicting flags,
                        // expose the least restrictive combination in order to be compatible with existing applications.
 
                        if ((fsType & Os2EmbeddingFlags.InstallableMask) == 0)
                        { 
                            // The font is installable if all bits in the InstallableMask are set to zero. 
                            switch (fsType & (Os2EmbeddingFlags.NoSubsetting | Os2EmbeddingFlags.BitmapOnly))
                            { 
                                case 0:
                                    rights = FontEmbeddingRight.Installable;
                                    break;
                                case Os2EmbeddingFlags.NoSubsetting: 
                                    rights = FontEmbeddingRight.InstallableButNoSubsetting;
                                    break; 
                                case Os2EmbeddingFlags.BitmapOnly: 
                                    rights = FontEmbeddingRight.InstallableButWithBitmapsOnly;
                                    break; 
                                case Os2EmbeddingFlags.NoSubsetting | Os2EmbeddingFlags.BitmapOnly:
                                    rights = FontEmbeddingRight.InstallableButNoSubsettingAndWithBitmapsOnly;
                                    break;
                            } 
                        }
                        else if ((fsType & Os2EmbeddingFlags.Editable) != 0) 
                        { 
                            switch (fsType & (Os2EmbeddingFlags.NoSubsetting | Os2EmbeddingFlags.BitmapOnly))
                            { 
                                case 0:
                                    rights = FontEmbeddingRight.Editable;
                                    break;
                                case Os2EmbeddingFlags.NoSubsetting: 
                                    rights = FontEmbeddingRight.EditableButNoSubsetting;
                                    break; 
                                case Os2EmbeddingFlags.BitmapOnly: 
                                    rights = FontEmbeddingRight.EditableButWithBitmapsOnly;
                                    break; 
                                case Os2EmbeddingFlags.NoSubsetting | Os2EmbeddingFlags.BitmapOnly:
                                    rights = FontEmbeddingRight.EditableButNoSubsettingAndWithBitmapsOnly;
                                    break;
                            } 
                        }
                        else if ((fsType & Os2EmbeddingFlags.PreviewAndPrint) != 0) 
                        { 
                            switch (fsType & (Os2EmbeddingFlags.NoSubsetting | Os2EmbeddingFlags.BitmapOnly))
                            { 
                                case 0:
                                    rights = FontEmbeddingRight.PreviewAndPrint;
                                    break;
                                case Os2EmbeddingFlags.NoSubsetting: 
                                    rights = FontEmbeddingRight.PreviewAndPrintButNoSubsetting;
                                    break; 
                                case Os2EmbeddingFlags.BitmapOnly: 
                                    rights = FontEmbeddingRight.PreviewAndPrintButWithBitmapsOnly;
                                    break; 
                                case Os2EmbeddingFlags.NoSubsetting | Os2EmbeddingFlags.BitmapOnly:
                                    rights = FontEmbeddingRight.PreviewAndPrintButNoSubsettingAndWithBitmapsOnly;
                                    break;
                            } 
                        }
                        else 
                        { 
                            // Otherwise, the font either has Os2EmbeddingFlags.RestrictedLicense set, or
                            // it has a reserved bit 0 set, which is invalid per specification. 
                            // Either way, rights should remain FontEmbeddingRight.RestrictedLicense.
                        }
                    }
                    _embeddingRights = rights; 
                    _embeddingRightsInitialized = true;
                } 
                return _embeddingRights; 
            }
        } 

        internal FontTechnology FontTechnology
        {
            get 
            {
                if (!_fontTechnologyInitialized) 
                { 
                    ComputeFontTechnology();
                    _fontTechnologyInitialized = true; 
                }
                return _fontTechnology;
            }
        } 

        ///  
        /// Critical - calls critical method ComputeTypographyAvailabilities 
        /// 
        internal TypographyAvailabilities TypographyAvailabilities 
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get
            { 
                if (!_typographyAvailabilitiesInitialized)
                { 
                    ComputeTypographyAvailabilities(); 
                    _typographyAvailabilitiesInitialized = true;
                } 
                return _typographyAvailabilities;
            }
        }
 
        /// 
        /// Critical: This calls into critical GlyphCount. 
        /// TreatAsSafe: This data is safe to expose. 
        /// 
        internal ushort GlyphCount 
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get
            { 
                ushort glyphCount;
 
                MS.Internal.Text.TextInterface.FontFace fontFace = _font.GetFontFace(); 
                try
                { 
                    glyphCount = fontFace.GlyphCount;
                }
                finally
                { 
                    fontFace.Release();
                } 
 
                return glyphCount;
            } 
        }

        /// 
        /// Critical - calls critical method TryGetFontTable, returns critical info. 
        /// 
        [SecurityCritical] 
        private byte[] GetFontTable(Text.TextInterface.OpenTypeTableTag openTypeTableTag) 
        {
            byte[] table; 

            MS.Internal.Text.TextInterface.FontFace fontFace = _font.GetFontFace();
            try
            { 
                if (!fontFace.TryGetFontTable(openTypeTableTag, out table))
                { 
                    table = null; 
                }
            } 
            finally
            {
                fontFace.Release();
            } 

            return table; 
        } 

        // OpenType support 

        /// 
        /// Critical - calls critical method GetFontTable
        ///  
        [SecurityCritical]
        internal byte[] Gsub() 
        { 
            if (!_gsubInitialized)
            { 
                _gsub = GetFontTable(Text.TextInterface.OpenTypeTableTag.TTO_GSUB);
                _gsubInitialized = true;
            }
            return _gsub; 
        }
 
        ///  
        /// Critical - calls critical method GetFontTable
        ///  
        [SecurityCritical]
        internal byte[] Gpos()
        {
            if (!_gposInitialized) 
            {
                _gpos = GetFontTable(Text.TextInterface.OpenTypeTableTag.TTO_GPOS); 
                _gposInitialized = true; 
            }
            return _gpos; 
        }

        /// 
        /// Critical - calls critical method GetFontTable 
        /// 
        [SecurityCritical] 
        internal byte[] Gdef() 
        {
            if (!_gdefInitialized) 
            {
                _gdef = GetFontTable(Text.TextInterface.OpenTypeTableTag.TTO_GDEF);
                _gdefInitialized = true;
            } 
            return _gdef;
        } 
 
        /// 
        ///     Critical: Calls unsafe code 
        /// 
        [SecurityCritical]
        internal byte[] GetTableCache(OpenTypeTags tableTag)
        { 
            switch (tableTag)
            { 
                case OpenTypeTags.GSUB: 
                    if (Gsub() != null)
                    { 
                        return _gsubCache;
                    }
                    break;
                case OpenTypeTags.GPOS: 
                    if (Gpos() != null)
                    { 
                        return _gposCache; 
                    }
                    break; 
                default:
                    throw new NotSupportedException();
            }
 
            return null;
        } 
 
        internal byte[] AllocateTableCache(OpenTypeTags tableTag, int size)
        { 
            switch (tableTag)
            {
                case OpenTypeTags.GSUB:
                    { 
                        _gsubCache = new byte[size];
                        return _gsubCache; 
                    } 
                case OpenTypeTags.GPOS:
                    { 
                        _gposCache = new byte[size];
                        return _gposCache;
                    }
                default: 
                    {
                        throw new NotSupportedException(); 
                    } 
            }
        } 

        /// 
        /// Critical: This calls into critical Type.
        /// TreatAsSafe: Does not expose any critical data. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void ComputeFontTechnology() 
        {
            MS.Internal.Text.TextInterface.FontFace fontFace = _font.GetFontFace(); 
            try
            {
                if (fontFace.Type == Text.TextInterface.FontFaceType.TrueTypeCollection)
                { 
                    _fontTechnology = FontTechnology.TrueTypeCollection;
                } 
                else if (fontFace.Type == Text.TextInterface.FontFaceType.CFF) 
                {
                    _fontTechnology = FontTechnology.PostscriptOpenType; 
                }
                else
                {
                    _fontTechnology = FontTechnology.TrueType; 
                }
            } 
            finally 
            {
                fontFace.Release(); 
            }
        }

        ///  
        /// 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 (OpenType layout table access)
        /// Also uses pointers 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void ComputeTypographyAvailabilities() 
        {
            int glyphBitsLength = (GlyphCount + 31) >> 5; 
            uint[] glyphBits = BufferCache.GetUInts(glyphBitsLength);
            Array.Clear(glyphBits, 0, glyphBitsLength);

            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++)
            { 
                uint[] codepoints = fastTextRanges[i].GetFullRange(); 
                ushort[] glyphIndices = BufferCache.GetUShorts(codepoints.Length);
 
                unsafe
                {
                    fixed (uint *pCodepoints = &codepoints[0])
                    { 
                        fixed (ushort *pGlyphIndices = &glyphIndices[0])
                        { 
                            CharacterMap.TryGetValues(pCodepoints, checked((uint)codepoints.Length), pGlyphIndices); 
                        }
                    } 
                }

                for (int j = 0; j < codepoints.Length; j++)
                { 
                    ushort glyphId = glyphIndices[j];
                    if (glyphId != 0) 
                    { 
                        glyphBits[glyphId >> 5] |= (uint)(1 << (glyphId % 32));
 
                        if (glyphId > maxGlyphId) maxGlyphId = glyphId;
                        if (glyphId < minGlyphId) minGlyphId = glyphId;
                    }
                } 

                BufferCache.ReleaseUShorts(glyphIndices); 
            } 

            // 
            // 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
                _typographyAvailabilities = TypographyAvailabilities.None; 
                return;
            } 
            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((ScriptTags)complexScripts[i].scriptTag, (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
                _typographyAvailabilities = TypographyAvailabilities.None;
                return;
            } 
            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 < glyphBitsLength; 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
                _typographyAvailabilities = TypographyAvailabilities.None; 
                return;
            }
            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; 
            }
 
            _typographyAvailabilities = typography; 

            // Note: we don't worry about calling ReleaseUInts in case of early out for a failure 
            // above.  Releasing glyphBits is a performance optimization that is not necessary
            // for correctness, and not interesting in the rare failure case.
            BufferCache.ReleaseUInts(glyphBits);
        } 

 
        #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
        { 
            private Text.TextInterface.Font     _font; 
            private Dictionary     _cmap;
 
            internal IntMap(Text.TextInterface.Font font)
            {
                _font     = font;
                _cmap     = null; 

            } 
 
            private Dictionary CMap
            { 
                get
                {
                    if (_cmap == null)
                    { 
                        lock (this)
                        { 
                            if (_cmap == null) 
                            {
                                _cmap = new Dictionary(); 
                                ushort glyphIndex;
                                for (int codePoint = 0; codePoint <= FontFamilyMap.LastUnicodeScalar; ++codePoint)
                                {
                                    if (TryGetValue(codePoint, out glyphIndex)) 
                                    {
                                        _cmap.Add(codePoint, glyphIndex); 
                                    } 
                                }
                            } 
                        }
                    }
                    return _cmap;
                } 
            }
            #region IDictionary Members 
            public void Add(int key, ushort value) 
            {
                throw new NotSupportedException(); 
            }

            /// 
            /// Critical: This calls into critical HasCharacter. 
            /// TreatAsSafe: This data is safe to expose.
            ///  
            [SecurityCritical,SecurityTreatAsSafe] 
            public bool ContainsKey(int key)
            { 
                return _font.HasCharacter(checked((uint)key));
            }

            public ICollection Keys 
            {
                get 
                { 
                    return CMap.Keys;
                } 
            }

            public bool Remove(int key)
            { 
                throw new NotSupportedException();
            } 
 
            /// 
            ///     Critical: This code calls into an unsafe block and calls critical GetArrayOfGlyphIndices. 
            ///     TreatAsSafe: Creates its own known-sized buffers to pass into critical code and
            //                   does not modify or return any critical data.
            /// 
            [SecurityCritical,SecurityTreatAsSafe] 
            public bool TryGetValue(int key, out ushort value)
            { 
                ushort localValue; 
                unsafe
                { 
                    uint uKey = checked((uint)key);
                    uint *pKey = &uKey;

                    MS.Internal.Text.TextInterface.FontFace fontFace = _font.GetFontFace(); 
                    try
                    { 
                        fontFace.GetArrayOfGlyphIndices(pKey, 1, &localValue); 
                    }
                    finally 
                    {
                        fontFace.Release();
                    }
 
                    value = localValue;
                } 
 
                // if a glyph is not present, index 0 is returned
                return (value != 0); 
            }

            /// 
            ///     Critical: This code calls critical GetArrayOfGlyphIndices. 
            /// 
            [SecurityCritical] 
            internal unsafe void TryGetValues(uint *pKeys, uint characterCount, ushort *pIndices) 
            {
                MS.Internal.Text.TextInterface.FontFace fontFace = _font.GetFontFace(); 
                try
                {
                    fontFace.GetArrayOfGlyphIndices(pKeys, characterCount, pIndices);
                } 
                finally
                { 
                    fontFace.Release(); 
                }
            } 

            public ICollection Values
            {
                get 
                {
                    return CMap.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 CMap.Count; } 
            }
 
            public bool IsReadOnly
            {
                get { return true; }
            } 

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

            #endregion

            #region IEnumerable> Members 

            public IEnumerator> GetEnumerator() 
            { 
                return CMap.GetEnumerator();
            } 

            #endregion

            #region IEnumerable Members 

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

            #endregion
        }
 
        #endregion
 
        //------------------------------------------------------ 
        //
        //  Private Fields 
        //
        //-----------------------------------------------------

        #region Private Fields 
        private IntMap _cmap;
 
        // '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, 0x3098),    // hiragana
            new UnicodeRange(0x309B, 0x309F),    // hiragana 
            new UnicodeRange(0x30A0, 0x30FF)     // kana
        }; 
 
        #endregion Private Fields
    } 

    /// 
    /// 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; 
            _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 byte[] GetTableCache(OpenTypeTags tableTag) 
        {
            return _layout.GetTableCache(tableTag); 
        }

        /// 
        /// Allocate space for layout table cache. 
        /// 
        ///  
        ///   Critical:    Calls critical code 
        ///  
        [SecurityCritical] 
        public byte[] 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;
        }

        // 
        // In order to get the glyph indices of all of the fast ranges efficiently,
        // it's necessary for us to pass a full array to TextInterface components 
        // containing all the codepoints we want glyph indices for. 
        // Generate such an array here on demand
        // 
        internal uint[] GetFullRange()
        {
            int smaller = Math.Min(lastChar, firstChar);
            int larger = Math.Max(lastChar, firstChar); 
            int arrayLength = larger - smaller + 1;
 
            uint[] unicodeArray = new uint[arrayLength]; 
            for (int i = 0; i < arrayLength; i++)
            { 
                unicodeArray[i] = checked((uint)(smaller + i));
            }

            return unicodeArray; 
        }
 
        internal int firstChar; 
        internal int lastChar;
    } 

    /// 
    /// Major language targetted for optimization
    ///  
    internal static class MajorLanguages
    { 
        ///  
        /// check if input script and langSys is considered a major language.
        ///  
        ///  true if it is a major language 
        internal static bool Contains(ScriptTags script, LanguageTags langSys)
        {
            for (int i = 0; i < majorLanguages.Length; i++) 
            {
                if (script == majorLanguages[i].Script && 
                    (langSys == LanguageTags.Default || langSys == majorLanguages[i].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 MajorLanguageDesc[] majorLanguages = new MajorLanguageDesc[]
            { 
                new MajorLanguageDesc(new CultureInfo("en"), ScriptTags.Latin,          LanguageTags.English),  // English neutral culture
                new MajorLanguageDesc(new CultureInfo("de"), ScriptTags.Latin,          LanguageTags.German),   // German neutral culture 
                new MajorLanguageDesc(new CultureInfo("ja"), ScriptTags.CJKIdeographic, LanguageTags.Japanese),  // Japanese neutral culture 
                new MajorLanguageDesc(new CultureInfo("ja"), ScriptTags.Hiragana,       LanguageTags.Japanese)  // Japanese neutral culture
            }; 

        private struct MajorLanguageDesc
        {
            internal MajorLanguageDesc(CultureInfo culture, ScriptTags script, LanguageTags langSys) 
            {
                Culture = culture; 
                Script = script; 
                LangSys = langSys;
            } 

            internal readonly CultureInfo Culture;
            internal readonly ScriptTags Script;
            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 
//  08/08/2008 : [....] - Integrating with DWrite.
// 
//---------------------------------------------------------------------------

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 
    {

        private FontTechnology _fontTechnology;
        private TypographyAvailabilities _typographyAvailabilities; 
        private FontEmbeddingRight _embeddingRights;
 
        private bool _embeddingRightsInitialized; 
        private bool _gsubInitialized;
        private bool _gposInitialized; 
        private bool _gdefInitialized;
        private bool _fontTechnologyInitialized;
        private bool _typographyAvailabilitiesInitialized;
 
        private byte[] _gsubCache;
        private byte[] _gposCache; 
 
        private byte[] _gsub;
        private byte[] _gpos; 
        private byte[] _gdef;

        Text.TextInterface.Font _font;
 
        ushort _blankGlyphIndex;
 
 
        //-----------------------------------------------------
        // 
        //  Constructors
        //
        //-----------------------------------------------------
 
        #region Constructors
 
 
        /// 
        /// Critical -  Calls into the critical CreateOpenTypeLayoutCache. 
        /// 
        [SecurityCritical]
        internal FontFaceLayoutInfo(Text.TextInterface.Font font)
        { 
            _fontTechnologyInitialized = false;
            _typographyAvailabilitiesInitialized = false; 
            _gsubInitialized            = false; 
            _gposInitialized            = false;
            _gdefInitialized            = false; 
            _embeddingRightsInitialized = false;
            _gsubCache = null;
            _gposCache = null;
            _gsub = null; 
            _gpos = null;
            _gdef = null; 
 
            _font = font;
            _cmap = new IntMap(_font); 
            _cmap.TryGetValue(' ', out _blankGlyphIndex);
        }

        #endregion Constructors 

        internal IntMap CharacterMap 
        { 
            get
            { 
                return _cmap;
            }
        }
 
        internal ushort BlankGlyph
        { 
            get 
            {
                return _blankGlyphIndex; 
            }
        }

        ///  
        /// Critical: This calls into critical DesignUnitsPerEm.
        /// TreatAsSafe: This data is safe to expose. 
        ///  
        internal ushort DesignEmHeight
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get
            {
                return _font.Metrics.DesignUnitsPerEm; 
            }
        } 
 
        private static class Os2EmbeddingFlags
        { 
            public const ushort RestrictedLicense = 0x0002;
            public const ushort PreviewAndPrint = 0x0004;
            public const ushort Editable = 0x0008;
 
            // The font is installable if all bits in the InstallableMask are set to zero.
            public const ushort InstallableMask = RestrictedLicense | PreviewAndPrint | Editable; 
 
            public const ushort NoSubsetting = 0x0100;
            public const ushort BitmapOnly = 0x0200; 
        }

        internal FontEmbeddingRight EmbeddingRights
        { 
            /// 
            /// Analyzes os/2 fsType value and construct FontEmbeddingRight enum value from it. 
            ///  
            /// 
            ///     Critical: This code writes critical information into FontFaceLayoutInfo. 
            ///     TreatAsSafe: It does this only using font data and not user defined parameters.
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            {
                if (!_embeddingRightsInitialized) 
                { 
                    // If there is no os/2 table, default to restricted font.
                    // This is the precedence that has been set by T2Embed, Word, etc. 
                    // No one has complained about this because these fonts are generally lower in quality and are less likely to be embedded.
                    FontEmbeddingRight rights = FontEmbeddingRight.RestrictedLicense;

                    ushort fsType; 
                    bool success;
 
                    MS.Internal.Text.TextInterface.FontFace fontFace = _font.GetFontFace(); 
                    try
                    { 
                        success = fontFace.ReadFontEmbeddingRights(out fsType);
                    }
                    finally
                    { 
                        fontFace.Release();
                    } 
 
                    if (success)
                    { 
                        // Start with the most restrictive flags.
                        // In case a font uses conflicting flags,
                        // expose the least restrictive combination in order to be compatible with existing applications.
 
                        if ((fsType & Os2EmbeddingFlags.InstallableMask) == 0)
                        { 
                            // The font is installable if all bits in the InstallableMask are set to zero. 
                            switch (fsType & (Os2EmbeddingFlags.NoSubsetting | Os2EmbeddingFlags.BitmapOnly))
                            { 
                                case 0:
                                    rights = FontEmbeddingRight.Installable;
                                    break;
                                case Os2EmbeddingFlags.NoSubsetting: 
                                    rights = FontEmbeddingRight.InstallableButNoSubsetting;
                                    break; 
                                case Os2EmbeddingFlags.BitmapOnly: 
                                    rights = FontEmbeddingRight.InstallableButWithBitmapsOnly;
                                    break; 
                                case Os2EmbeddingFlags.NoSubsetting | Os2EmbeddingFlags.BitmapOnly:
                                    rights = FontEmbeddingRight.InstallableButNoSubsettingAndWithBitmapsOnly;
                                    break;
                            } 
                        }
                        else if ((fsType & Os2EmbeddingFlags.Editable) != 0) 
                        { 
                            switch (fsType & (Os2EmbeddingFlags.NoSubsetting | Os2EmbeddingFlags.BitmapOnly))
                            { 
                                case 0:
                                    rights = FontEmbeddingRight.Editable;
                                    break;
                                case Os2EmbeddingFlags.NoSubsetting: 
                                    rights = FontEmbeddingRight.EditableButNoSubsetting;
                                    break; 
                                case Os2EmbeddingFlags.BitmapOnly: 
                                    rights = FontEmbeddingRight.EditableButWithBitmapsOnly;
                                    break; 
                                case Os2EmbeddingFlags.NoSubsetting | Os2EmbeddingFlags.BitmapOnly:
                                    rights = FontEmbeddingRight.EditableButNoSubsettingAndWithBitmapsOnly;
                                    break;
                            } 
                        }
                        else if ((fsType & Os2EmbeddingFlags.PreviewAndPrint) != 0) 
                        { 
                            switch (fsType & (Os2EmbeddingFlags.NoSubsetting | Os2EmbeddingFlags.BitmapOnly))
                            { 
                                case 0:
                                    rights = FontEmbeddingRight.PreviewAndPrint;
                                    break;
                                case Os2EmbeddingFlags.NoSubsetting: 
                                    rights = FontEmbeddingRight.PreviewAndPrintButNoSubsetting;
                                    break; 
                                case Os2EmbeddingFlags.BitmapOnly: 
                                    rights = FontEmbeddingRight.PreviewAndPrintButWithBitmapsOnly;
                                    break; 
                                case Os2EmbeddingFlags.NoSubsetting | Os2EmbeddingFlags.BitmapOnly:
                                    rights = FontEmbeddingRight.PreviewAndPrintButNoSubsettingAndWithBitmapsOnly;
                                    break;
                            } 
                        }
                        else 
                        { 
                            // Otherwise, the font either has Os2EmbeddingFlags.RestrictedLicense set, or
                            // it has a reserved bit 0 set, which is invalid per specification. 
                            // Either way, rights should remain FontEmbeddingRight.RestrictedLicense.
                        }
                    }
                    _embeddingRights = rights; 
                    _embeddingRightsInitialized = true;
                } 
                return _embeddingRights; 
            }
        } 

        internal FontTechnology FontTechnology
        {
            get 
            {
                if (!_fontTechnologyInitialized) 
                { 
                    ComputeFontTechnology();
                    _fontTechnologyInitialized = true; 
                }
                return _fontTechnology;
            }
        } 

        ///  
        /// Critical - calls critical method ComputeTypographyAvailabilities 
        /// 
        internal TypographyAvailabilities TypographyAvailabilities 
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get
            { 
                if (!_typographyAvailabilitiesInitialized)
                { 
                    ComputeTypographyAvailabilities(); 
                    _typographyAvailabilitiesInitialized = true;
                } 
                return _typographyAvailabilities;
            }
        }
 
        /// 
        /// Critical: This calls into critical GlyphCount. 
        /// TreatAsSafe: This data is safe to expose. 
        /// 
        internal ushort GlyphCount 
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get
            { 
                ushort glyphCount;
 
                MS.Internal.Text.TextInterface.FontFace fontFace = _font.GetFontFace(); 
                try
                { 
                    glyphCount = fontFace.GlyphCount;
                }
                finally
                { 
                    fontFace.Release();
                } 
 
                return glyphCount;
            } 
        }

        /// 
        /// Critical - calls critical method TryGetFontTable, returns critical info. 
        /// 
        [SecurityCritical] 
        private byte[] GetFontTable(Text.TextInterface.OpenTypeTableTag openTypeTableTag) 
        {
            byte[] table; 

            MS.Internal.Text.TextInterface.FontFace fontFace = _font.GetFontFace();
            try
            { 
                if (!fontFace.TryGetFontTable(openTypeTableTag, out table))
                { 
                    table = null; 
                }
            } 
            finally
            {
                fontFace.Release();
            } 

            return table; 
        } 

        // OpenType support 

        /// 
        /// Critical - calls critical method GetFontTable
        ///  
        [SecurityCritical]
        internal byte[] Gsub() 
        { 
            if (!_gsubInitialized)
            { 
                _gsub = GetFontTable(Text.TextInterface.OpenTypeTableTag.TTO_GSUB);
                _gsubInitialized = true;
            }
            return _gsub; 
        }
 
        ///  
        /// Critical - calls critical method GetFontTable
        ///  
        [SecurityCritical]
        internal byte[] Gpos()
        {
            if (!_gposInitialized) 
            {
                _gpos = GetFontTable(Text.TextInterface.OpenTypeTableTag.TTO_GPOS); 
                _gposInitialized = true; 
            }
            return _gpos; 
        }

        /// 
        /// Critical - calls critical method GetFontTable 
        /// 
        [SecurityCritical] 
        internal byte[] Gdef() 
        {
            if (!_gdefInitialized) 
            {
                _gdef = GetFontTable(Text.TextInterface.OpenTypeTableTag.TTO_GDEF);
                _gdefInitialized = true;
            } 
            return _gdef;
        } 
 
        /// 
        ///     Critical: Calls unsafe code 
        /// 
        [SecurityCritical]
        internal byte[] GetTableCache(OpenTypeTags tableTag)
        { 
            switch (tableTag)
            { 
                case OpenTypeTags.GSUB: 
                    if (Gsub() != null)
                    { 
                        return _gsubCache;
                    }
                    break;
                case OpenTypeTags.GPOS: 
                    if (Gpos() != null)
                    { 
                        return _gposCache; 
                    }
                    break; 
                default:
                    throw new NotSupportedException();
            }
 
            return null;
        } 
 
        internal byte[] AllocateTableCache(OpenTypeTags tableTag, int size)
        { 
            switch (tableTag)
            {
                case OpenTypeTags.GSUB:
                    { 
                        _gsubCache = new byte[size];
                        return _gsubCache; 
                    } 
                case OpenTypeTags.GPOS:
                    { 
                        _gposCache = new byte[size];
                        return _gposCache;
                    }
                default: 
                    {
                        throw new NotSupportedException(); 
                    } 
            }
        } 

        /// 
        /// Critical: This calls into critical Type.
        /// TreatAsSafe: Does not expose any critical data. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void ComputeFontTechnology() 
        {
            MS.Internal.Text.TextInterface.FontFace fontFace = _font.GetFontFace(); 
            try
            {
                if (fontFace.Type == Text.TextInterface.FontFaceType.TrueTypeCollection)
                { 
                    _fontTechnology = FontTechnology.TrueTypeCollection;
                } 
                else if (fontFace.Type == Text.TextInterface.FontFaceType.CFF) 
                {
                    _fontTechnology = FontTechnology.PostscriptOpenType; 
                }
                else
                {
                    _fontTechnology = FontTechnology.TrueType; 
                }
            } 
            finally 
            {
                fontFace.Release(); 
            }
        }

        ///  
        /// 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 (OpenType layout table access)
        /// Also uses pointers 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void ComputeTypographyAvailabilities() 
        {
            int glyphBitsLength = (GlyphCount + 31) >> 5; 
            uint[] glyphBits = BufferCache.GetUInts(glyphBitsLength);
            Array.Clear(glyphBits, 0, glyphBitsLength);

            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++)
            { 
                uint[] codepoints = fastTextRanges[i].GetFullRange(); 
                ushort[] glyphIndices = BufferCache.GetUShorts(codepoints.Length);
 
                unsafe
                {
                    fixed (uint *pCodepoints = &codepoints[0])
                    { 
                        fixed (ushort *pGlyphIndices = &glyphIndices[0])
                        { 
                            CharacterMap.TryGetValues(pCodepoints, checked((uint)codepoints.Length), pGlyphIndices); 
                        }
                    } 
                }

                for (int j = 0; j < codepoints.Length; j++)
                { 
                    ushort glyphId = glyphIndices[j];
                    if (glyphId != 0) 
                    { 
                        glyphBits[glyphId >> 5] |= (uint)(1 << (glyphId % 32));
 
                        if (glyphId > maxGlyphId) maxGlyphId = glyphId;
                        if (glyphId < minGlyphId) minGlyphId = glyphId;
                    }
                } 

                BufferCache.ReleaseUShorts(glyphIndices); 
            } 

            // 
            // 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
                _typographyAvailabilities = TypographyAvailabilities.None; 
                return;
            } 
            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((ScriptTags)complexScripts[i].scriptTag, (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
                _typographyAvailabilities = TypographyAvailabilities.None;
                return;
            } 
            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 < glyphBitsLength; 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
                _typographyAvailabilities = TypographyAvailabilities.None; 
                return;
            }
            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; 
            }
 
            _typographyAvailabilities = typography; 

            // Note: we don't worry about calling ReleaseUInts in case of early out for a failure 
            // above.  Releasing glyphBits is a performance optimization that is not necessary
            // for correctness, and not interesting in the rare failure case.
            BufferCache.ReleaseUInts(glyphBits);
        } 

 
        #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
        { 
            private Text.TextInterface.Font     _font; 
            private Dictionary     _cmap;
 
            internal IntMap(Text.TextInterface.Font font)
            {
                _font     = font;
                _cmap     = null; 

            } 
 
            private Dictionary CMap
            { 
                get
                {
                    if (_cmap == null)
                    { 
                        lock (this)
                        { 
                            if (_cmap == null) 
                            {
                                _cmap = new Dictionary(); 
                                ushort glyphIndex;
                                for (int codePoint = 0; codePoint <= FontFamilyMap.LastUnicodeScalar; ++codePoint)
                                {
                                    if (TryGetValue(codePoint, out glyphIndex)) 
                                    {
                                        _cmap.Add(codePoint, glyphIndex); 
                                    } 
                                }
                            } 
                        }
                    }
                    return _cmap;
                } 
            }
            #region IDictionary Members 
            public void Add(int key, ushort value) 
            {
                throw new NotSupportedException(); 
            }

            /// 
            /// Critical: This calls into critical HasCharacter. 
            /// TreatAsSafe: This data is safe to expose.
            ///  
            [SecurityCritical,SecurityTreatAsSafe] 
            public bool ContainsKey(int key)
            { 
                return _font.HasCharacter(checked((uint)key));
            }

            public ICollection Keys 
            {
                get 
                { 
                    return CMap.Keys;
                } 
            }

            public bool Remove(int key)
            { 
                throw new NotSupportedException();
            } 
 
            /// 
            ///     Critical: This code calls into an unsafe block and calls critical GetArrayOfGlyphIndices. 
            ///     TreatAsSafe: Creates its own known-sized buffers to pass into critical code and
            //                   does not modify or return any critical data.
            /// 
            [SecurityCritical,SecurityTreatAsSafe] 
            public bool TryGetValue(int key, out ushort value)
            { 
                ushort localValue; 
                unsafe
                { 
                    uint uKey = checked((uint)key);
                    uint *pKey = &uKey;

                    MS.Internal.Text.TextInterface.FontFace fontFace = _font.GetFontFace(); 
                    try
                    { 
                        fontFace.GetArrayOfGlyphIndices(pKey, 1, &localValue); 
                    }
                    finally 
                    {
                        fontFace.Release();
                    }
 
                    value = localValue;
                } 
 
                // if a glyph is not present, index 0 is returned
                return (value != 0); 
            }

            /// 
            ///     Critical: This code calls critical GetArrayOfGlyphIndices. 
            /// 
            [SecurityCritical] 
            internal unsafe void TryGetValues(uint *pKeys, uint characterCount, ushort *pIndices) 
            {
                MS.Internal.Text.TextInterface.FontFace fontFace = _font.GetFontFace(); 
                try
                {
                    fontFace.GetArrayOfGlyphIndices(pKeys, characterCount, pIndices);
                } 
                finally
                { 
                    fontFace.Release(); 
                }
            } 

            public ICollection Values
            {
                get 
                {
                    return CMap.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 CMap.Count; } 
            }
 
            public bool IsReadOnly
            {
                get { return true; }
            } 

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

            #endregion

            #region IEnumerable> Members 

            public IEnumerator> GetEnumerator() 
            { 
                return CMap.GetEnumerator();
            } 

            #endregion

            #region IEnumerable Members 

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

            #endregion
        }
 
        #endregion
 
        //------------------------------------------------------ 
        //
        //  Private Fields 
        //
        //-----------------------------------------------------

        #region Private Fields 
        private IntMap _cmap;
 
        // '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, 0x3098),    // hiragana
            new UnicodeRange(0x309B, 0x309F),    // hiragana 
            new UnicodeRange(0x30A0, 0x30FF)     // kana
        }; 
 
        #endregion Private Fields
    } 

    /// 
    /// 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; 
            _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 byte[] GetTableCache(OpenTypeTags tableTag) 
        {
            return _layout.GetTableCache(tableTag); 
        }

        /// 
        /// Allocate space for layout table cache. 
        /// 
        ///  
        ///   Critical:    Calls critical code 
        ///  
        [SecurityCritical] 
        public byte[] 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;
        }

        // 
        // In order to get the glyph indices of all of the fast ranges efficiently,
        // it's necessary for us to pass a full array to TextInterface components 
        // containing all the codepoints we want glyph indices for. 
        // Generate such an array here on demand
        // 
        internal uint[] GetFullRange()
        {
            int smaller = Math.Min(lastChar, firstChar);
            int larger = Math.Max(lastChar, firstChar); 
            int arrayLength = larger - smaller + 1;
 
            uint[] unicodeArray = new uint[arrayLength]; 
            for (int i = 0; i < arrayLength; i++)
            { 
                unicodeArray[i] = checked((uint)(smaller + i));
            }

            return unicodeArray; 
        }
 
        internal int firstChar; 
        internal int lastChar;
    } 

    /// 
    /// Major language targetted for optimization
    ///  
    internal static class MajorLanguages
    { 
        ///  
        /// check if input script and langSys is considered a major language.
        ///  
        ///  true if it is a major language 
        internal static bool Contains(ScriptTags script, LanguageTags langSys)
        {
            for (int i = 0; i < majorLanguages.Length; i++) 
            {
                if (script == majorLanguages[i].Script && 
                    (langSys == LanguageTags.Default || langSys == majorLanguages[i].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 MajorLanguageDesc[] majorLanguages = new MajorLanguageDesc[]
            { 
                new MajorLanguageDesc(new CultureInfo("en"), ScriptTags.Latin,          LanguageTags.English),  // English neutral culture
                new MajorLanguageDesc(new CultureInfo("de"), ScriptTags.Latin,          LanguageTags.German),   // German neutral culture 
                new MajorLanguageDesc(new CultureInfo("ja"), ScriptTags.CJKIdeographic, LanguageTags.Japanese),  // Japanese neutral culture 
                new MajorLanguageDesc(new CultureInfo("ja"), ScriptTags.Hiragana,       LanguageTags.Japanese)  // Japanese neutral culture
            }; 

        private struct MajorLanguageDesc
        {
            internal MajorLanguageDesc(CultureInfo culture, ScriptTags script, LanguageTags langSys) 
            {
                Culture = culture; 
                Script = script; 
                LangSys = langSys;
            } 

            internal readonly CultureInfo Culture;
            internal readonly ScriptTags Script;
            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