Substitution.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 / Shaping / Substitution.cs / 1305600 / Substitution.cs

                            //+------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation, 2002
// 
//  File:      Sustitution.cs
// 
//  Contents:  OpentTypeLayout substitution classes 
//
//  contact:   sergeym 
//
//  History:   2002-03-23   Created (sergeym)
//
//----------------------------------------------------------------------- 

using System.Diagnostics; 
using System.Security; 
using System.Security.Permissions;
using System; 
using System.IO;

namespace MS.Internal.Shaping
{ 
    //
 
 

 
    [SecurityCritical(SecurityCriticalScope.Everything)]
    internal struct SingleSubstitutionSubtable
    {
        private const int offsetFormat = 0; 
        private const int offsetCoverage = 2;
        private const int offsetFormat1DeltaGlyphId = 4; 
        private const int offsetFormat2GlyphCount = 4; 
        private const int offsetFormat2SubstitutehArray = 6;
        private const int sizeFormat2SubstituteSize = 2; 

        private ushort Format(FontTable Table)
        {
            return Table.GetUShort(offset + offsetFormat); 
        }
 
        private CoverageTable Coverage(FontTable Table) 
        {
            return new CoverageTable(offset+Table.GetUShort(offset + offsetCoverage)); 
        }

        private short Format1DeltaGlyphId(FontTable Table)
        { 
            Invariant.Assert(Format(Table)==1);
            return Table.GetShort(offset + offsetFormat1DeltaGlyphId); 
        } 

        // Not used. This value should be equal to glyph count in Coverage. 
        // Keeping it for future reference
        //private ushort Foramt2GlyphCount(FontTable Table)
        //{
        //    Debug.Assert(Format(Table)==2); 
        //    return Table.GetUShort(offset + offsetFormat2GlyphCount);
        //} 
        private ushort Format2SubstituteGlyphId(FontTable Table,ushort Index) 
        {
            Invariant.Assert(Format(Table)==2); 
            return Table.GetUShort(offset + offsetFormat2SubstitutehArray +
                                            Index * sizeFormat2SubstituteSize);
        }
 
        public bool Apply(
                            FontTable          Table, 
                            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs 
                            int             FirstGlyph,     // where to apply it
                            out int         NextGlyph       // Next glyph to process 
                         )
        {
            Invariant.Assert(FirstGlyph >= 0);
 
            NextGlyph = FirstGlyph + 1; //In case we don't match;
 
            ushort GlyphId = GlyphInfo.Glyphs[FirstGlyph]; 
            int CoverageIndex = Coverage(Table).GetGlyphIndex(Table,GlyphId);
            if (CoverageIndex == -1) return false; 

            switch(Format(Table))
            {
                case 1: 
                    GlyphInfo.Glyphs[FirstGlyph] = (ushort)(GlyphId + Format1DeltaGlyphId(Table));
                    GlyphInfo.GlyphFlags[FirstGlyph] = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted); 
                    NextGlyph = FirstGlyph + 1; 
                    return true;
 
                case 2:
                    GlyphInfo.Glyphs[FirstGlyph] = Format2SubstituteGlyphId(Table,(ushort)CoverageIndex);
                    GlyphInfo.GlyphFlags[FirstGlyph] = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                    NextGlyph = FirstGlyph + 1; 
                    return true;
 
                default: 
                    NextGlyph = FirstGlyph+1;
                    return false; 
            }
        }

        public bool IsLookupCovered( 
                        FontTable table,
                        uint[] glyphBits, 
                        ushort minGlyphId, 
                        ushort maxGlyphId)
        { 
            return Coverage(table).IsAnyGlyphCovered(table,
                                                     glyphBits,
                                                     minGlyphId,
                                                     maxGlyphId 
                                                    );
        } 
 
        public CoverageTable GetPrimaryCoverage(FontTable table)
        { 
            return Coverage(table);
        }

        public SingleSubstitutionSubtable(int Offset) { offset = Offset; } 
        private int offset;
    } 
 

    ///  
    /// Critical - Everything in this struct is considered critical
    ///            because they either operate on raw font table bits or unsafe pointers.
    /// 
    [SecurityCritical(SecurityCriticalScope.Everything)] 
    internal struct LigatureSubstitutionSubtable
    { 
        private const int offsetFormat = 0; 
        private const int offsetCoverage = 2;
        private const int offsetLigatureSetCount = 4; 
        private const int offsetLigatureSetArray = 6;
        private const int sizeLigatureSet = 2;

        private ushort Format(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetFormat); 
        } 

        private CoverageTable Coverage(FontTable Table) 
        {
            return new CoverageTable(offset + Table.GetUShort(offset + offsetCoverage));
        }
 
        private ushort LigatureSetCount(FontTable Table)
        { 
            return Table.GetUShort(offset + offsetLigatureSetCount); 
        }
 
        private LigatureSetTable LigatureSet(FontTable Table, ushort Index)
        {
            return new LigatureSetTable(offset+Table.GetUShort(offset+
                                                               offsetLigatureSetArray + 
                                                               Index * sizeLigatureSet));
        } 
 
#region Ligature Substitution subtable private structures
        ///  
        /// Critical - Everything in this struct is considered critical
        ///            because they either operate on raw font table bits or unsafe pointers.
        /// 
        [SecurityCritical(SecurityCriticalScope.Everything)] 
        private struct LigatureSetTable
        { 
            private const int offsetLigatureCount = 0; 
            private const int offsetLigatureArray = 2;
            private const int sizeLigatureOffset  = 2; 

            public ushort LigatureCount(FontTable Table)
            {
                return Table.GetUShort(offset + offsetLigatureCount); 
            }
 
            public LigatureTable Ligature(FontTable Table, ushort Index) 
            {
                return new LigatureTable(offset + Table.GetUShort(offset + 
                    offsetLigatureArray +
                    Index * sizeLigatureOffset));
            }
 
            public LigatureSetTable(int Offset) { offset = Offset; }
            private int offset; 
        } 

        ///  
        /// Critical - Everything in this struct is considered critical
        ///            because they either operate on raw font table bits or unsafe pointers.
        /// 
        [SecurityCritical(SecurityCriticalScope.Everything)] 
        private struct LigatureTable
        { 
            private const int offsetLigatureGlyph = 0; 
            private const int offsetComponentCount = 2;
            private const int offsetComponentArray = 4; 
            private const int sizeComponent = 2;

            public ushort LigatureGlyph(FontTable Table)
            { 
                return Table.GetUShort(offset + offsetLigatureGlyph);
            } 
 
            public ushort ComponentCount(FontTable Table)
            { 
                return Table.GetUShort(offset + offsetComponentCount);
            }

            public ushort Component(FontTable Table, ushort Index) 
            {
                //LigaTable includes comps from 1 to N. So, (Index-1) 
                return Table.GetUShort(offset + offsetComponentArray + 
                    (Index-1) * sizeComponent);
            } 

            public LigatureTable(int Offset) { offset = Offset; }
            private int offset;
        } 
#endregion
 
        public unsafe bool Apply( 
                            IOpenTypeFont   Font,
                            FontTable       Table, 
                            int             CharCount,
                            UshortList      Charmap,        // Character to glyph map
                            GlyphInfoList   GlyphInfo,      // List of GlyphInfo
                            ushort          LookupFlags,    // Lookup flags for glyph lookups 
                            int             FirstGlyph,     // where to apply it
                            int             AfterLastGlyph, // how long is a context we can use 
                            out int         NextGlyph       // Next glyph to process 
                          )
        { 
            Invariant.Assert(FirstGlyph>=0);
            Invariant.Assert(AfterLastGlyph<=GlyphInfo.Length);

            NextGlyph = FirstGlyph + 1; //In case we don't match; 

            if (Format(Table) != 1) return false; // Unknown format 
 
            int glyphCount=GlyphInfo.Length;
            ushort glyphId = GlyphInfo.Glyphs[FirstGlyph]; 
            int CoverageIndex = Coverage(Table).GetGlyphIndex(Table,glyphId);
            if (CoverageIndex==-1) return false;

            int curGlyph; 
            ushort ligatureGlyph=0;
            bool match = false; 
            ushort compCount=0; 

            LigatureSetTable ligatureSet = LigatureSet(Table,(ushort)CoverageIndex); 
            ushort ligaCount = ligatureSet.LigatureCount(Table);
            for(ushort liga=0; liga=AfterLastGlyph) break; 

                    if (GlyphInfo.Glyphs[curGlyph]!=ligature.Component(Table,comp)) break; 
                }

                if (comp==compCount) //liga matched
                { 
                    match=true;
                    ligatureGlyph = ligature.LigatureGlyph(Table); 
                    break; //Liga found 
                }
            } 
            //If no ligature found, match will remain false after last iteration

            if (match)
            { 
                //Fix character and glyph Mapping
 
                //PERF: localize ligature character range 

                //Calculate Ligature CharCount 
                int totalLigaCharCount=0;
                int firstLigaChar=int.MaxValue;
                curGlyph=FirstGlyph;
                for(ushort comp=0;comp0)
                    { 
                        for(int glyph=prevGlyph+1; glyph1) //do fixing only if have glyphs in between 
                        {
                            for(int curChar=0; curCharprevGlyph && curCharmap 1)
                { 
                    GlyphInfo.Remove(GlyphInfo.Length-compCount+1,compCount-1); 
                }
 
                NextGlyph=prevGlyph-(compCount-1)+1;
            }

            return match; 
        }
 
        public bool IsLookupCovered( 
                        FontTable table,
                        uint[] glyphBits, 
                        ushort minGlyphId,
                        ushort maxGlyphId)
        {
            if (!Coverage(table).IsAnyGlyphCovered(table, 
                                                     glyphBits,
                                                     minGlyphId, 
                                                     maxGlyphId 
                                                    )
               ) return false; 

            ushort ligatureSetCount = LigatureSetCount(table);

            for(ushort setIndex = 0; setIndex < ligatureSetCount; setIndex++) 
            {
                LigatureSetTable ligatureSet = LigatureSet(table, setIndex); 
                ushort ligaCount = ligatureSet.LigatureCount(table); 

                for (ushort liga = 0; liga < ligaCount; liga++) 
                {
                    LigatureTable ligature = ligatureSet.Ligature(table, liga);
                    ushort compCount = ligature.ComponentCount(table);
 
                    bool ligatureIsComplex = true;
 
                    for(ushort compIndex = 1; compIndex < compCount; compIndex++) 
                    {
                        ushort glyphId = ligature.Component(table,compIndex); 

                        if (glyphId > maxGlyphId ||
                            glyphId < minGlyphId ||
                            (glyphBits[glyphId >> 5] & (1 << (glyphId % 32))) == 0 
                           )
                        { 
                            ligatureIsComplex = false; 
                            break;
                        } 
                    }

                    if (ligatureIsComplex) return true;
                } 
            }
 
            return false; 

        } 

        public CoverageTable GetPrimaryCoverage(FontTable table)
        {
            return Coverage(table); 
        }
 
        public LigatureSubstitutionSubtable(int Offset) { offset = Offset; } 
        private int offset;
    } 

    /// 
    /// Critical - Everything in this struct is considered critical
    ///            because they either operate on raw font table bits or unsafe pointers. 
    /// 
    [SecurityCritical(SecurityCriticalScope.Everything)] 
    internal struct MultipleSubstitutionSequenceTable 
    {
        private const int offsetGlyphCount = 0; 
        private const int offsetGlyphArray = 2;
        private const int sizeGlyphId      = 2;

        public ushort GlyphCount(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetGlyphCount); 
        } 

        public ushort Glyph(FontTable Table, ushort index) 
        {
            return Table.GetUShort(offset + offsetGlyphArray + index * sizeGlyphId);
        }
 
        public MultipleSubstitutionSequenceTable(int Offset) { offset = Offset; }
        private int offset; 
    } 

    ///  
    /// Critical - Everything in this struct is considered critical
    ///            because they either operate on raw font table bits or unsafe pointers.
    /// 
    [SecurityCritical(SecurityCriticalScope.Everything)] 
    internal struct MultipleSubstitutionSubtable
    { 
        private const int offsetFormat = 0; 
        private const int offsetCoverage = 2;
        private const int offsetSequenceCount = 4; 
        private const int offsetSequenceArray = 6;
        private const int sizeSequenceOffset = 2;

        private ushort Format(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetFormat); 
        } 

        private CoverageTable Coverage(FontTable Table) 
        {
            return new CoverageTable(offset + Table.GetUShort(offset + offsetCoverage));
        }
 
        // Not used. This value should be equal to glyph count in Coverage.
        // Keeping it for future reference 
        //private ushort SequenceCount(FontTable Table) 
        //{
        //    return Table.GetUShort(offset + offsetSequenceCount); 
        //}

        private MultipleSubstitutionSequenceTable Sequence(FontTable Table, int Index)
        { 
            return new MultipleSubstitutionSequenceTable(
                                        offset + 
                                        Table.GetUShort(offset + 
                                                        offsetSequenceArray +
                                                        Index * sizeSequenceOffset) 
                                       );
        }

        public unsafe bool Apply( 
            IOpenTypeFont   Font,
            FontTable       Table, 
            int             CharCount, 
            UshortList      Charmap,        // Character to glyph map
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo 
            ushort          LookupFlags,    // Lookup flags for glyph lookups
            int             FirstGlyph,     // where to apply it
            int             AfterLastGlyph, // how long is a context we can use
            out int         NextGlyph       // Next glyph to process 
            )
         { 
            NextGlyph = FirstGlyph + 1; // in case we don't match 

            if (Format(Table) != 1) return false; //unknown format 

            int oldGlyphCount=GlyphInfo.Length;

            ushort glyphId = GlyphInfo.Glyphs[FirstGlyph]; 
            int coverageIndex = Coverage(Table).GetGlyphIndex(Table,glyphId);
            if (coverageIndex==-1) return false; 
 
            MultipleSubstitutionSequenceTable sequence = Sequence(Table,coverageIndex);
 
            ushort sequenceLength = sequence.GlyphCount(Table);
            int lengthDelta = sequenceLength - 1;

            if (sequenceLength==0) 
            {
                // This is illegal, because mapping will be broken - 
                // corresponding char will be lost. Just leave it as it is. 
                // (char will be attached to the following glyph).
                GlyphInfo.Remove(FirstGlyph,1); 
            }
            else
            {
                ushort firstChar = GlyphInfo.FirstChars[FirstGlyph]; 
                ushort ligatureCount = GlyphInfo.LigatureCounts[FirstGlyph];
 
                if (lengthDelta > 0) 
                {
                    GlyphInfo.Insert(FirstGlyph,lengthDelta); 
                }

                //put glyphs in place
                for(ushort gl=0; gl base and marks decomposition 
            // 
            for(int ch=0;chFirstGlyph) Charmap[ch] = (ushort)(Charmap[ch]+lengthDelta);
            }

            NextGlyph = FirstGlyph + lengthDelta + 1; 

            return true; 
         } 

        public bool IsLookupCovered( 
                        FontTable table,
                        uint[] glyphBits,
                        ushort minGlyphId,
                        ushort maxGlyphId) 
        {
            return Coverage(table).IsAnyGlyphCovered(table, 
                                                     glyphBits, 
                                                     minGlyphId,
                                                     maxGlyphId 
                                                    );
        }

        public CoverageTable GetPrimaryCoverage(FontTable table) 
        {
            return Coverage(table); 
        } 

        public MultipleSubstitutionSubtable(int Offset) { offset = Offset; } 
        private int offset;
    }

    ///  
    /// Critical - Everything in this struct is considered critical
    ///            because they either operate on raw font table bits or unsafe pointers. 
    ///  
    [SecurityCritical(SecurityCriticalScope.Everything)]
    struct AlternateSubstitutionSubtable 
    {
        private const int offsetFormat              = 0;
        private const int offsetCoverage            = 2;
        private const int offsetAlternateSetCount   = 4; 
        private const int offsetAlternateSets       = 6;
        private const int sizeAlternateSetOffset    = 2; 
 
        private const ushort InvalidAlternateGlyph = 0xFFFF;
 
        public ushort Format(FontTable Table)
        {
            return Table.GetUShort(offset + offsetFormat);
        } 

        private CoverageTable Coverage(FontTable Table) 
        { 
            return new CoverageTable(offset + Table.GetUShort(offset + offsetCoverage));
        } 

        // Not used. This value should be equal to glyph count in Coverage.
        // Keeping it for future reference
        //private ushort AlternateSetCount(FontTable Table) 
        //{
        //    return Table.GetUShort(offset + offsetAlternateSetCount); 
        //} 

        private AlternateSetTable AlternateSet(FontTable Table, int index) 
        {
            return new AlternateSetTable(offset +
                                         Table.GetUShort(offset +
                                                         offsetAlternateSets + 
                                                         index * sizeAlternateSetOffset)
                                        ); 
        } 

        ///  
        /// Critical - Everything in this struct is considered critical
        ///            because they either operate on raw font table bits or unsafe pointers.
        /// 
        [SecurityCritical(SecurityCriticalScope.Everything)] 
        private struct AlternateSetTable
        { 
            private const int offsetGlyphCount = 0; 
            private const int offsetGlyphs     = 2;
            private const int sizeGlyph        = 2; 

            public ushort GlyphCount(FontTable Table)
            {
                return Table.GetUShort(offset + offsetGlyphCount); 
            }
 
            public ushort Alternate(FontTable Table, uint FeatureParam) 
            {
                Invariant.Assert(FeatureParam > 0); // Parameter 0 means feautre is disabled. 
                                                //Should be filtered out in GetNextEnabledGlyphRange

                // Off by one - alternate number 1 is stored under index 0
                uint index = FeatureParam - 1; 

                if (index >= GlyphCount(Table)) 
                { 
                    return AlternateSubstitutionSubtable.InvalidAlternateGlyph;
                } 

                return Table.GetUShort(offset + offsetGlyphs + (ushort)index*sizeGlyph);
            }
 
            public AlternateSetTable(int Offset) { offset = Offset; }
            private int offset; 
        } 

        public unsafe bool Apply( 
            FontTable       Table,
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo
            uint            FeatureParam,   // For this lookup - index of glyph alternate
            int             FirstGlyph,     // where to apply it 
            out int         NextGlyph       // Next glyph to process
            ) 
        { 
            NextGlyph = FirstGlyph + 1; // always move one glyph forward,
                                        // doesn't matter whether we matched context 

            if (Format(Table) != 1) return false; //Unknown format

            int oldGlyphCount=GlyphInfo.Length; 

            int coverageIndex = Coverage(Table). 
                                    GetGlyphIndex(Table,GlyphInfo.Glyphs[FirstGlyph]); 
            if (coverageIndex==-1) return false;
 
            AlternateSetTable alternateSet = AlternateSet(Table,coverageIndex);

            ushort alternateGlyph = alternateSet.Alternate(Table, FeatureParam);
 
            if (alternateGlyph != InvalidAlternateGlyph)
            { 
                GlyphInfo.Glyphs[FirstGlyph] = alternateGlyph; 
                GlyphInfo.GlyphFlags[FirstGlyph] = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                return true; 
            }

            return false;
        } 

        public bool IsLookupCovered( 
                        FontTable table, 
                        uint[] glyphBits,
                        ushort minGlyphId, 
                        ushort maxGlyphId)
        {
            return Coverage(table).IsAnyGlyphCovered(table,
                                                     glyphBits, 
                                                     minGlyphId,
                                                     maxGlyphId 
                                                    ); 
        }
 
        public CoverageTable GetPrimaryCoverage(FontTable table)
        {
            return Coverage(table);
        } 

        public AlternateSubstitutionSubtable(int Offset) { offset = Offset; } 
        private int offset; 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//+------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation, 2002
// 
//  File:      Sustitution.cs
// 
//  Contents:  OpentTypeLayout substitution classes 
//
//  contact:   sergeym 
//
//  History:   2002-03-23   Created (sergeym)
//
//----------------------------------------------------------------------- 

using System.Diagnostics; 
using System.Security; 
using System.Security.Permissions;
using System; 
using System.IO;

namespace MS.Internal.Shaping
{ 
    //
 
 

 
    [SecurityCritical(SecurityCriticalScope.Everything)]
    internal struct SingleSubstitutionSubtable
    {
        private const int offsetFormat = 0; 
        private const int offsetCoverage = 2;
        private const int offsetFormat1DeltaGlyphId = 4; 
        private const int offsetFormat2GlyphCount = 4; 
        private const int offsetFormat2SubstitutehArray = 6;
        private const int sizeFormat2SubstituteSize = 2; 

        private ushort Format(FontTable Table)
        {
            return Table.GetUShort(offset + offsetFormat); 
        }
 
        private CoverageTable Coverage(FontTable Table) 
        {
            return new CoverageTable(offset+Table.GetUShort(offset + offsetCoverage)); 
        }

        private short Format1DeltaGlyphId(FontTable Table)
        { 
            Invariant.Assert(Format(Table)==1);
            return Table.GetShort(offset + offsetFormat1DeltaGlyphId); 
        } 

        // Not used. This value should be equal to glyph count in Coverage. 
        // Keeping it for future reference
        //private ushort Foramt2GlyphCount(FontTable Table)
        //{
        //    Debug.Assert(Format(Table)==2); 
        //    return Table.GetUShort(offset + offsetFormat2GlyphCount);
        //} 
        private ushort Format2SubstituteGlyphId(FontTable Table,ushort Index) 
        {
            Invariant.Assert(Format(Table)==2); 
            return Table.GetUShort(offset + offsetFormat2SubstitutehArray +
                                            Index * sizeFormat2SubstituteSize);
        }
 
        public bool Apply(
                            FontTable          Table, 
                            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs 
                            int             FirstGlyph,     // where to apply it
                            out int         NextGlyph       // Next glyph to process 
                         )
        {
            Invariant.Assert(FirstGlyph >= 0);
 
            NextGlyph = FirstGlyph + 1; //In case we don't match;
 
            ushort GlyphId = GlyphInfo.Glyphs[FirstGlyph]; 
            int CoverageIndex = Coverage(Table).GetGlyphIndex(Table,GlyphId);
            if (CoverageIndex == -1) return false; 

            switch(Format(Table))
            {
                case 1: 
                    GlyphInfo.Glyphs[FirstGlyph] = (ushort)(GlyphId + Format1DeltaGlyphId(Table));
                    GlyphInfo.GlyphFlags[FirstGlyph] = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted); 
                    NextGlyph = FirstGlyph + 1; 
                    return true;
 
                case 2:
                    GlyphInfo.Glyphs[FirstGlyph] = Format2SubstituteGlyphId(Table,(ushort)CoverageIndex);
                    GlyphInfo.GlyphFlags[FirstGlyph] = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                    NextGlyph = FirstGlyph + 1; 
                    return true;
 
                default: 
                    NextGlyph = FirstGlyph+1;
                    return false; 
            }
        }

        public bool IsLookupCovered( 
                        FontTable table,
                        uint[] glyphBits, 
                        ushort minGlyphId, 
                        ushort maxGlyphId)
        { 
            return Coverage(table).IsAnyGlyphCovered(table,
                                                     glyphBits,
                                                     minGlyphId,
                                                     maxGlyphId 
                                                    );
        } 
 
        public CoverageTable GetPrimaryCoverage(FontTable table)
        { 
            return Coverage(table);
        }

        public SingleSubstitutionSubtable(int Offset) { offset = Offset; } 
        private int offset;
    } 
 

    ///  
    /// Critical - Everything in this struct is considered critical
    ///            because they either operate on raw font table bits or unsafe pointers.
    /// 
    [SecurityCritical(SecurityCriticalScope.Everything)] 
    internal struct LigatureSubstitutionSubtable
    { 
        private const int offsetFormat = 0; 
        private const int offsetCoverage = 2;
        private const int offsetLigatureSetCount = 4; 
        private const int offsetLigatureSetArray = 6;
        private const int sizeLigatureSet = 2;

        private ushort Format(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetFormat); 
        } 

        private CoverageTable Coverage(FontTable Table) 
        {
            return new CoverageTable(offset + Table.GetUShort(offset + offsetCoverage));
        }
 
        private ushort LigatureSetCount(FontTable Table)
        { 
            return Table.GetUShort(offset + offsetLigatureSetCount); 
        }
 
        private LigatureSetTable LigatureSet(FontTable Table, ushort Index)
        {
            return new LigatureSetTable(offset+Table.GetUShort(offset+
                                                               offsetLigatureSetArray + 
                                                               Index * sizeLigatureSet));
        } 
 
#region Ligature Substitution subtable private structures
        ///  
        /// Critical - Everything in this struct is considered critical
        ///            because they either operate on raw font table bits or unsafe pointers.
        /// 
        [SecurityCritical(SecurityCriticalScope.Everything)] 
        private struct LigatureSetTable
        { 
            private const int offsetLigatureCount = 0; 
            private const int offsetLigatureArray = 2;
            private const int sizeLigatureOffset  = 2; 

            public ushort LigatureCount(FontTable Table)
            {
                return Table.GetUShort(offset + offsetLigatureCount); 
            }
 
            public LigatureTable Ligature(FontTable Table, ushort Index) 
            {
                return new LigatureTable(offset + Table.GetUShort(offset + 
                    offsetLigatureArray +
                    Index * sizeLigatureOffset));
            }
 
            public LigatureSetTable(int Offset) { offset = Offset; }
            private int offset; 
        } 

        ///  
        /// Critical - Everything in this struct is considered critical
        ///            because they either operate on raw font table bits or unsafe pointers.
        /// 
        [SecurityCritical(SecurityCriticalScope.Everything)] 
        private struct LigatureTable
        { 
            private const int offsetLigatureGlyph = 0; 
            private const int offsetComponentCount = 2;
            private const int offsetComponentArray = 4; 
            private const int sizeComponent = 2;

            public ushort LigatureGlyph(FontTable Table)
            { 
                return Table.GetUShort(offset + offsetLigatureGlyph);
            } 
 
            public ushort ComponentCount(FontTable Table)
            { 
                return Table.GetUShort(offset + offsetComponentCount);
            }

            public ushort Component(FontTable Table, ushort Index) 
            {
                //LigaTable includes comps from 1 to N. So, (Index-1) 
                return Table.GetUShort(offset + offsetComponentArray + 
                    (Index-1) * sizeComponent);
            } 

            public LigatureTable(int Offset) { offset = Offset; }
            private int offset;
        } 
#endregion
 
        public unsafe bool Apply( 
                            IOpenTypeFont   Font,
                            FontTable       Table, 
                            int             CharCount,
                            UshortList      Charmap,        // Character to glyph map
                            GlyphInfoList   GlyphInfo,      // List of GlyphInfo
                            ushort          LookupFlags,    // Lookup flags for glyph lookups 
                            int             FirstGlyph,     // where to apply it
                            int             AfterLastGlyph, // how long is a context we can use 
                            out int         NextGlyph       // Next glyph to process 
                          )
        { 
            Invariant.Assert(FirstGlyph>=0);
            Invariant.Assert(AfterLastGlyph<=GlyphInfo.Length);

            NextGlyph = FirstGlyph + 1; //In case we don't match; 

            if (Format(Table) != 1) return false; // Unknown format 
 
            int glyphCount=GlyphInfo.Length;
            ushort glyphId = GlyphInfo.Glyphs[FirstGlyph]; 
            int CoverageIndex = Coverage(Table).GetGlyphIndex(Table,glyphId);
            if (CoverageIndex==-1) return false;

            int curGlyph; 
            ushort ligatureGlyph=0;
            bool match = false; 
            ushort compCount=0; 

            LigatureSetTable ligatureSet = LigatureSet(Table,(ushort)CoverageIndex); 
            ushort ligaCount = ligatureSet.LigatureCount(Table);
            for(ushort liga=0; liga=AfterLastGlyph) break; 

                    if (GlyphInfo.Glyphs[curGlyph]!=ligature.Component(Table,comp)) break; 
                }

                if (comp==compCount) //liga matched
                { 
                    match=true;
                    ligatureGlyph = ligature.LigatureGlyph(Table); 
                    break; //Liga found 
                }
            } 
            //If no ligature found, match will remain false after last iteration

            if (match)
            { 
                //Fix character and glyph Mapping
 
                //PERF: localize ligature character range 

                //Calculate Ligature CharCount 
                int totalLigaCharCount=0;
                int firstLigaChar=int.MaxValue;
                curGlyph=FirstGlyph;
                for(ushort comp=0;comp0)
                    { 
                        for(int glyph=prevGlyph+1; glyph1) //do fixing only if have glyphs in between 
                        {
                            for(int curChar=0; curCharprevGlyph && curCharmap 1)
                { 
                    GlyphInfo.Remove(GlyphInfo.Length-compCount+1,compCount-1); 
                }
 
                NextGlyph=prevGlyph-(compCount-1)+1;
            }

            return match; 
        }
 
        public bool IsLookupCovered( 
                        FontTable table,
                        uint[] glyphBits, 
                        ushort minGlyphId,
                        ushort maxGlyphId)
        {
            if (!Coverage(table).IsAnyGlyphCovered(table, 
                                                     glyphBits,
                                                     minGlyphId, 
                                                     maxGlyphId 
                                                    )
               ) return false; 

            ushort ligatureSetCount = LigatureSetCount(table);

            for(ushort setIndex = 0; setIndex < ligatureSetCount; setIndex++) 
            {
                LigatureSetTable ligatureSet = LigatureSet(table, setIndex); 
                ushort ligaCount = ligatureSet.LigatureCount(table); 

                for (ushort liga = 0; liga < ligaCount; liga++) 
                {
                    LigatureTable ligature = ligatureSet.Ligature(table, liga);
                    ushort compCount = ligature.ComponentCount(table);
 
                    bool ligatureIsComplex = true;
 
                    for(ushort compIndex = 1; compIndex < compCount; compIndex++) 
                    {
                        ushort glyphId = ligature.Component(table,compIndex); 

                        if (glyphId > maxGlyphId ||
                            glyphId < minGlyphId ||
                            (glyphBits[glyphId >> 5] & (1 << (glyphId % 32))) == 0 
                           )
                        { 
                            ligatureIsComplex = false; 
                            break;
                        } 
                    }

                    if (ligatureIsComplex) return true;
                } 
            }
 
            return false; 

        } 

        public CoverageTable GetPrimaryCoverage(FontTable table)
        {
            return Coverage(table); 
        }
 
        public LigatureSubstitutionSubtable(int Offset) { offset = Offset; } 
        private int offset;
    } 

    /// 
    /// Critical - Everything in this struct is considered critical
    ///            because they either operate on raw font table bits or unsafe pointers. 
    /// 
    [SecurityCritical(SecurityCriticalScope.Everything)] 
    internal struct MultipleSubstitutionSequenceTable 
    {
        private const int offsetGlyphCount = 0; 
        private const int offsetGlyphArray = 2;
        private const int sizeGlyphId      = 2;

        public ushort GlyphCount(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetGlyphCount); 
        } 

        public ushort Glyph(FontTable Table, ushort index) 
        {
            return Table.GetUShort(offset + offsetGlyphArray + index * sizeGlyphId);
        }
 
        public MultipleSubstitutionSequenceTable(int Offset) { offset = Offset; }
        private int offset; 
    } 

    ///  
    /// Critical - Everything in this struct is considered critical
    ///            because they either operate on raw font table bits or unsafe pointers.
    /// 
    [SecurityCritical(SecurityCriticalScope.Everything)] 
    internal struct MultipleSubstitutionSubtable
    { 
        private const int offsetFormat = 0; 
        private const int offsetCoverage = 2;
        private const int offsetSequenceCount = 4; 
        private const int offsetSequenceArray = 6;
        private const int sizeSequenceOffset = 2;

        private ushort Format(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetFormat); 
        } 

        private CoverageTable Coverage(FontTable Table) 
        {
            return new CoverageTable(offset + Table.GetUShort(offset + offsetCoverage));
        }
 
        // Not used. This value should be equal to glyph count in Coverage.
        // Keeping it for future reference 
        //private ushort SequenceCount(FontTable Table) 
        //{
        //    return Table.GetUShort(offset + offsetSequenceCount); 
        //}

        private MultipleSubstitutionSequenceTable Sequence(FontTable Table, int Index)
        { 
            return new MultipleSubstitutionSequenceTable(
                                        offset + 
                                        Table.GetUShort(offset + 
                                                        offsetSequenceArray +
                                                        Index * sizeSequenceOffset) 
                                       );
        }

        public unsafe bool Apply( 
            IOpenTypeFont   Font,
            FontTable       Table, 
            int             CharCount, 
            UshortList      Charmap,        // Character to glyph map
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo 
            ushort          LookupFlags,    // Lookup flags for glyph lookups
            int             FirstGlyph,     // where to apply it
            int             AfterLastGlyph, // how long is a context we can use
            out int         NextGlyph       // Next glyph to process 
            )
         { 
            NextGlyph = FirstGlyph + 1; // in case we don't match 

            if (Format(Table) != 1) return false; //unknown format 

            int oldGlyphCount=GlyphInfo.Length;

            ushort glyphId = GlyphInfo.Glyphs[FirstGlyph]; 
            int coverageIndex = Coverage(Table).GetGlyphIndex(Table,glyphId);
            if (coverageIndex==-1) return false; 
 
            MultipleSubstitutionSequenceTable sequence = Sequence(Table,coverageIndex);
 
            ushort sequenceLength = sequence.GlyphCount(Table);
            int lengthDelta = sequenceLength - 1;

            if (sequenceLength==0) 
            {
                // This is illegal, because mapping will be broken - 
                // corresponding char will be lost. Just leave it as it is. 
                // (char will be attached to the following glyph).
                GlyphInfo.Remove(FirstGlyph,1); 
            }
            else
            {
                ushort firstChar = GlyphInfo.FirstChars[FirstGlyph]; 
                ushort ligatureCount = GlyphInfo.LigatureCounts[FirstGlyph];
 
                if (lengthDelta > 0) 
                {
                    GlyphInfo.Insert(FirstGlyph,lengthDelta); 
                }

                //put glyphs in place
                for(ushort gl=0; gl base and marks decomposition 
            // 
            for(int ch=0;chFirstGlyph) Charmap[ch] = (ushort)(Charmap[ch]+lengthDelta);
            }

            NextGlyph = FirstGlyph + lengthDelta + 1; 

            return true; 
         } 

        public bool IsLookupCovered( 
                        FontTable table,
                        uint[] glyphBits,
                        ushort minGlyphId,
                        ushort maxGlyphId) 
        {
            return Coverage(table).IsAnyGlyphCovered(table, 
                                                     glyphBits, 
                                                     minGlyphId,
                                                     maxGlyphId 
                                                    );
        }

        public CoverageTable GetPrimaryCoverage(FontTable table) 
        {
            return Coverage(table); 
        } 

        public MultipleSubstitutionSubtable(int Offset) { offset = Offset; } 
        private int offset;
    }

    ///  
    /// Critical - Everything in this struct is considered critical
    ///            because they either operate on raw font table bits or unsafe pointers. 
    ///  
    [SecurityCritical(SecurityCriticalScope.Everything)]
    struct AlternateSubstitutionSubtable 
    {
        private const int offsetFormat              = 0;
        private const int offsetCoverage            = 2;
        private const int offsetAlternateSetCount   = 4; 
        private const int offsetAlternateSets       = 6;
        private const int sizeAlternateSetOffset    = 2; 
 
        private const ushort InvalidAlternateGlyph = 0xFFFF;
 
        public ushort Format(FontTable Table)
        {
            return Table.GetUShort(offset + offsetFormat);
        } 

        private CoverageTable Coverage(FontTable Table) 
        { 
            return new CoverageTable(offset + Table.GetUShort(offset + offsetCoverage));
        } 

        // Not used. This value should be equal to glyph count in Coverage.
        // Keeping it for future reference
        //private ushort AlternateSetCount(FontTable Table) 
        //{
        //    return Table.GetUShort(offset + offsetAlternateSetCount); 
        //} 

        private AlternateSetTable AlternateSet(FontTable Table, int index) 
        {
            return new AlternateSetTable(offset +
                                         Table.GetUShort(offset +
                                                         offsetAlternateSets + 
                                                         index * sizeAlternateSetOffset)
                                        ); 
        } 

        ///  
        /// Critical - Everything in this struct is considered critical
        ///            because they either operate on raw font table bits or unsafe pointers.
        /// 
        [SecurityCritical(SecurityCriticalScope.Everything)] 
        private struct AlternateSetTable
        { 
            private const int offsetGlyphCount = 0; 
            private const int offsetGlyphs     = 2;
            private const int sizeGlyph        = 2; 

            public ushort GlyphCount(FontTable Table)
            {
                return Table.GetUShort(offset + offsetGlyphCount); 
            }
 
            public ushort Alternate(FontTable Table, uint FeatureParam) 
            {
                Invariant.Assert(FeatureParam > 0); // Parameter 0 means feautre is disabled. 
                                                //Should be filtered out in GetNextEnabledGlyphRange

                // Off by one - alternate number 1 is stored under index 0
                uint index = FeatureParam - 1; 

                if (index >= GlyphCount(Table)) 
                { 
                    return AlternateSubstitutionSubtable.InvalidAlternateGlyph;
                } 

                return Table.GetUShort(offset + offsetGlyphs + (ushort)index*sizeGlyph);
            }
 
            public AlternateSetTable(int Offset) { offset = Offset; }
            private int offset; 
        } 

        public unsafe bool Apply( 
            FontTable       Table,
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo
            uint            FeatureParam,   // For this lookup - index of glyph alternate
            int             FirstGlyph,     // where to apply it 
            out int         NextGlyph       // Next glyph to process
            ) 
        { 
            NextGlyph = FirstGlyph + 1; // always move one glyph forward,
                                        // doesn't matter whether we matched context 

            if (Format(Table) != 1) return false; //Unknown format

            int oldGlyphCount=GlyphInfo.Length; 

            int coverageIndex = Coverage(Table). 
                                    GetGlyphIndex(Table,GlyphInfo.Glyphs[FirstGlyph]); 
            if (coverageIndex==-1) return false;
 
            AlternateSetTable alternateSet = AlternateSet(Table,coverageIndex);

            ushort alternateGlyph = alternateSet.Alternate(Table, FeatureParam);
 
            if (alternateGlyph != InvalidAlternateGlyph)
            { 
                GlyphInfo.Glyphs[FirstGlyph] = alternateGlyph; 
                GlyphInfo.GlyphFlags[FirstGlyph] = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                return true; 
            }

            return false;
        } 

        public bool IsLookupCovered( 
                        FontTable table, 
                        uint[] glyphBits,
                        ushort minGlyphId, 
                        ushort maxGlyphId)
        {
            return Coverage(table).IsAnyGlyphCovered(table,
                                                     glyphBits, 
                                                     minGlyphId,
                                                     maxGlyphId 
                                                    ); 
        }
 
        public CoverageTable GetPrimaryCoverage(FontTable table)
        {
            return Coverage(table);
        } 

        public AlternateSubstitutionSubtable(int Offset) { offset = Offset; } 
        private int offset; 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

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