Positioning.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / MS / Internal / Shaping / Positioning.cs / 1 / Positioning.cs

                            //+------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation, 2002
// 
//  File:      Positioning.cs
// 
//  Contents:  OpentTypeLayout positioning 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
{ 
    //
 
 

 



 

 
 

    ///  
    /// Critical - Everything in this class is considered critical
    ///            because they either operate on raw font table bits or unsafe pointers.
    /// 
    [SecurityCritical(SecurityCriticalScope.Everything)] 
    internal static class Positioning
    { 
        public static int DesignToPixels(ushort DesignUnitsPerEm, ushort PixelsPerEm, int Value) 
        {
            //Result requested in design units 
            if (DesignUnitsPerEm==0) return Value;

            int  rounding = ((int)DesignUnitsPerEm)/2;;
 
            if (Value >= 0)
            { 
                // Half of Units per Em 
                rounding = ((int)DesignUnitsPerEm)/2;
            } 
            else
            {
                // -(Half of Units per Em). +1 to ensure rounding
                rounding = -((int)DesignUnitsPerEm >> 1)+1; 
            }
 
            return (Value*(int)PixelsPerEm + rounding)/DesignUnitsPerEm; 
        }
 

        /// 
        ///  Align to anchors between two glyphs (e.g. mark and base)
        ///  by changing adv.width and offsets for both of them 
        /// 
        ///  
        ///  
        /// 
        ///  
        /// 
        /// 
        /// 
        ///  
        /// 
        ///  
        ///  
        /// 
        public static unsafe void AlignAnchors( 
                                        IOpenTypeFont   Font,
                                        FontTable          Table,
                                        LayoutMetrics   Metrics,
                                        GlyphInfoList   GlyphInfo, 
                                        int*            Advances,
                                        LayoutOffset*   Offsets, 
                                        int             StaticGlyph, 
                                        int             MobileGlyph,
                                        AnchorTable     StaticAnchor, 
                                        AnchorTable     MobileAnchor,
                                        bool            UseAdvances
                                      )
        { 
            Invariant.Assert(StaticGlyph>=0 && StaticGlyph=0 && MobileGlyph 
    /// 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 DeviceTable 
    {
        private const int offsetStartSize = 0;
        private const int offsetEndSize = 2;
        private const int offsetDeltaFormat = 4; 
        private const int offsetDeltaValueArray = 6;
        private const int sizeDeltaValue = 2; 
 
        private ushort StartSize(FontTable Table)
        { 
            return Table.GetUShort(offset + offsetStartSize);
        }

        private ushort EndSize(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetEndSize); 
        } 

        private ushort DeltaFormat(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetDeltaFormat);
        }
 
        private ushort DeltaValue(FontTable Table, ushort Index)
        { 
            return Table.GetUShort( offset + offsetDeltaValueArray + 
                                             Index * sizeDeltaValue);
        } 

        public int Value(FontTable Table, ushort PixelsPerEm)
        {
            if (IsNull()) return 0; 

            ushort startSize = StartSize(Table); 
            ushort endSize   = EndSize(Table); 

            if (PixelsPerEmendSize) return 0; 

            ushort sizeIndex = (ushort)(PixelsPerEm-startSize);
            ushort valueIndex, shiftUp, shiftDown;
 
            switch (DeltaFormat(Table))
            { 
                case 1: 
                    valueIndex = (ushort)(sizeIndex>>3);
                    shiftUp    = (ushort)(16 + 2*(sizeIndex&0x0007)); 
                    shiftDown  = 30;
                    break;

                case 2: 
                    valueIndex = (ushort)(sizeIndex>>2);
                    shiftUp    = (ushort)(16 + 4*(sizeIndex&0x0003)); 
                    shiftDown  = 28; 
                    break;
 
                case 3:
                    valueIndex = (ushort)(sizeIndex>>1);
                    shiftUp    = (ushort)(16 + 8*(sizeIndex&0x0001));
                    shiftDown  = 24; 
                    break;
 
                default: 
                    return 0; //Unknown format
            } 

            int delta = DeltaValue(Table,valueIndex);
            delta <<= shiftUp;      //clear leading bits
            delta >>= shiftDown;    //extend sign and clear trailing bits 

            return delta; 
        } 

        public DeviceTable(int Offset) { offset = Offset; } 
        bool IsNull() { return (offset==0); }
        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 ValueRecordTable
    {
        const ushort XPlacmentFlag = 0x0001;
        const ushort YPlacmentFlag = 0x0002; 
        const ushort XAdvanceFlag   = 0x0004;
        const ushort YAdvanceFlag  = 0x0008; 
        const ushort XPlacementDeviceFlag = 0x0010; 
        const ushort YPlacementDeviceFlag = 0x0020;
        const ushort XAdvanceDeviceFlag  = 0x0040; 
        const ushort YAdvanceDeviceFlag  = 0x0080;

        private static ushort[] BitCount =
                    new ushort[16] { 0, 2, 2, 4,  2, 4, 4, 6,  2, 4, 4, 6,  4, 6, 6, 8 }; 

        public static ushort Size(ushort Format) 
        { 
            return (ushort)(BitCount[Format&0x000F]+BitCount[(Format>>4)&0x000F]);
        } 

        public void AdjustPos(  FontTable Table,
                                LayoutMetrics Metrics,
                                ref LayoutOffset GlyphOffset, 
                                ref int    GlyphAdvance
                             ) 
        { 
            int curOffset=offset;
 
            if ((format&XPlacmentFlag)!=0)
            {
                GlyphOffset.dx += Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth,
                                                                Table.GetShort(curOffset)); 
                curOffset+=2;
            } 
 
            if ((format&YPlacmentFlag)!=0)
            { 
                GlyphOffset.dy += Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmHeight,
                                                                Table.GetShort(curOffset));

                curOffset+=2; 
            }
 
            if ((format&XAdvanceFlag)!=0) 
            {
                    GlyphAdvance += Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth, 
                                                                    Table.GetShort(curOffset));
                curOffset+=2;
            }
 
            if ((format&YAdvanceFlag)!=0)
            { 
                    GlyphAdvance += Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmHeight, 
                        Table.GetShort(curOffset));
                curOffset+=2; 
            }

            if ((format&XPlacementDeviceFlag)!=0)
            { 
                int deviceTableOffset = Table.GetOffset(curOffset);
                if (deviceTableOffset != FontTable.NullOffset) 
                { 
                    DeviceTable deviceTable  = new DeviceTable(baseTableOffset+deviceTableOffset);
                    GlyphOffset.dx += deviceTable.Value(Table,Metrics.PixelsEmWidth); 
                }

                curOffset+=2;
            } 

            if ((format&YPlacementDeviceFlag)!=0) 
            { 
                int deviceTableOffset = Table.GetOffset(curOffset);
                if (deviceTableOffset != FontTable.NullOffset) 
                {
                    DeviceTable deviceTable  = new DeviceTable(baseTableOffset+deviceTableOffset);
                    GlyphOffset.dy += deviceTable.Value(Table,Metrics.PixelsEmHeight);
                } 

                curOffset+=2; 
            } 

            if ((format&XAdvanceDeviceFlag)!=0) 
            {
                if (Metrics.Direction==TextFlowDirection.LTR || Metrics.Direction==TextFlowDirection.RTL)
                {
                    int deviceTableOffset = Table.GetOffset(curOffset); 
                    if (deviceTableOffset != FontTable.NullOffset)
                    { 
                        DeviceTable deviceTable  = new DeviceTable(baseTableOffset+deviceTableOffset); 
                        GlyphAdvance += deviceTable.Value(Table,Metrics.PixelsEmWidth);
                    } 
                }

                curOffset+=2;
            } 

            if ((format&YAdvanceDeviceFlag)!=0) 
            { 
                if (Metrics.Direction==TextFlowDirection.TTB || Metrics.Direction==TextFlowDirection.BTT)
                { 
                    int deviceTableOffset = Table.GetOffset(curOffset);
                    if (deviceTableOffset != FontTable.NullOffset)
                    {
                        DeviceTable deviceTable  = new DeviceTable(baseTableOffset+deviceTableOffset); 
                        GlyphAdvance += deviceTable.Value(Table,Metrics.PixelsEmHeight);
                    } 
                } 

                curOffset+=2; 
            }
        }

        public ValueRecordTable(int Offset, int BaseTableOffset, ushort Format) 
        {
            offset = Offset; 
            baseTableOffset = BaseTableOffset; 
            format=Format;
        } 

        private ushort format;
        private int baseTableOffset;
        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 AnchorTable
    { 
        private const int offsetFormat = 0;
        private const int offsetXCoordinate = 2; 
        private const int offsetYCoordinate = 4; 
        private const int offsetFormat2AnchorPoint = 6;
        private const int offsetFormat3XDeviceTable = 6; 
        private const int offsetFormat3YDeviceTable = 8;

        private short XCoordinate(FontTable Table)
        { 
            return Table.GetShort(offset + offsetXCoordinate);
        } 
 
        private short YCoordinate(FontTable Table)
        { 
            return Table.GetShort(offset + offsetYCoordinate);
        }

        private ushort Format2AnchorPoint(FontTable Table) 
        {
            Invariant.Assert(format==2); 
            return Table.GetUShort(offset + offsetFormat2AnchorPoint); 
        }
 
        private DeviceTable Format3XDeviceTable(FontTable Table)
        {
            Invariant.Assert(format==3);
            int DeviceOffset = Table.GetUShort(offset + offsetFormat3XDeviceTable); 

            if (DeviceOffset!=0) 
            { 
                return new DeviceTable(offset + DeviceOffset);
            } 
            else
            {
                return new DeviceTable(0);
            } 
        }
 
        private DeviceTable Format3YDeviceTable(FontTable Table) 
        {
            Invariant.Assert(format==3); 

            int DeviceOffset = Table.GetUShort(offset + offsetFormat3YDeviceTable);

            if (DeviceOffset!=0) 
            {
                return new DeviceTable(offset + DeviceOffset); 
            } 
            else
            { 
                return new DeviceTable(0);
            }
        }
 
        public bool NeedContourPoint(FontTable Table)
        { 
            return (format==2); 
        }
 
        public ushort ContourPointIndex(FontTable Table)
        {
            Invariant.Assert(NeedContourPoint(Table));
            return Format2AnchorPoint(Table); 
        }
 
        public LayoutOffset AnchorCoordinates( 
                                    FontTable       Table,
                                    LayoutMetrics   Metrics, 
                                    LayoutOffset    ContourPoint
                                )
        {
            LayoutOffset Point = new LayoutOffset(); 

            switch (format) 
            { 
                case 1: //Simple coordinates
                        Point.dx = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth,XCoordinate(Table)); 
                        Point.dy = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmHeight,YCoordinate(Table));
                        break;

                case 2: //Coordinates + anchor point 
                        if (ContourPoint.dx==int.MinValue)
                        { 
                            Point.dx = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth,XCoordinate(Table)); 
                            Point.dy = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmHeight,YCoordinate(Table));
                        } 
                        else
                        {
                            Point.dx = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth,ContourPoint.dx);
                            Point.dy = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth,ContourPoint.dy); 
                        }
                        break; 
 
                case 3: //Coordinates + Device table
                        Point.dx = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth,XCoordinate(Table))+ 
                                        Format3XDeviceTable(Table).Value(Table,Metrics.PixelsEmWidth);
                        Point.dy = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmHeight,YCoordinate(Table))+
                                        Format3YDeviceTable(Table).Value(Table,Metrics.PixelsEmHeight);
                        break; 

                default: //Unknown format 
                    Point.dx = 0; 
                    Point.dx = 0;
                    break; 
            }

            return Point;
        } 

 
        public AnchorTable(FontTable Table, int Offset) 
        {
            offset = Offset; 
            if (offset != 0)
                format = Table.GetUShort(offset + offsetFormat);
            else
                format = 0; 
        }
 
        public bool IsNull() { return (offset==0); } 
        private int offset;
        private ushort format; 
    }

    /// 
    /// 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 SinglePositioningSubtable
    { 
        private const int offsetFormat = 0;
        private const int offsetCoverage = 2;
        private const int offsetValueFormat = 4;
        private const int offsetFormat1Value = 6; 
        private const int offsetFormat2ValueCount = 6;
        private const int offsetFormat2ValueArray = 8; 
 
        private ushort Format(FontTable Table)
        { 
            return Table.GetUShort(offset + offsetFormat);
        }

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

        private ushort ValueFormat(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetValueFormat);
        }
 
        private ValueRecordTable Format1ValueRecord(FontTable Table)
        { 
            Invariant.Assert(Format(Table)==1); 

            return new ValueRecordTable(offset + offsetFormat1Value, 
                                        offset,
                                        ValueFormat(Table));
        }
 
        private ValueRecordTable Format2ValueRecord(FontTable Table, ushort Index)
        { 
            Invariant.Assert(Format(Table)==2); 

            return new ValueRecordTable(offset + 
                                            offsetFormat2ValueArray +
                                            Index * ValueRecordTable.Size(ValueFormat(Table)),
                                        offset,
                                        ValueFormat(Table)); 
        }
 
        public unsafe bool Apply( 
            FontTable               Table,
            LayoutMetrics           Metrics,        // LayoutMetrics 
            GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs
            int*                    Advances,       // Glyph adv.widths
            LayoutOffset*           Offsets,        // Glyph offsets
            int                     FirstGlyph,     // where to apply lookup 
            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;
 
            int glyphCount=GlyphInfo.Length;
            ushort glyphId = GlyphInfo.Glyphs[FirstGlyph]; 
 
            int coverageIndex = Coverage(Table).GetGlyphIndex(Table,glyphId);
            if (coverageIndex == -1) return false; 

            ValueRecordTable valueRecord;

            switch (Format(Table)) 
            {
                case 1: 
                    valueRecord = Format1ValueRecord(Table); 
                    break;
                case 2: 
                    valueRecord = Format2ValueRecord(Table,(ushort)coverageIndex);
                    break;
                default:
                    return false; 
            }
 
            valueRecord.AdjustPos(Table, Metrics, ref Offsets[FirstGlyph], ref Advances[FirstGlyph]); 

            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 SinglePositioningSubtable(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 PairPositioningSubtable
    { 
        private const int offsetFormat = 0;
        private const int offsetCoverage = 2; 
        private const int offsetValueFormat1 = 4; 
        private const int offsetValueFormat2 = 6;
        private const int offsetFormat1PairSetCount = 8; 
        private const int offsetFormat1PairSetArray = 10;
        private const int sizeFormat1PairSetOffset = 2;
        private const int offsetFormat2ClassDef1 = 8;
        private const int offsetFormat2ClassDef2 = 10; 
        private const int offsetFormat2Class1Count = 12;
        private const int offsetFormat2Class2Count = 14; 
        private const int offsetFormat2ValueRecordArray = 16; 

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

        private ushort SecondValueFormat(FontTable Table) 
        { 
            return Table.GetUShort(offset + offsetValueFormat2);
        } 

        // Not used. This value should be equal to glyph count in coverage table
        // Keeping it for future reference
        //private ushort Format1PairSetCount(FontTable Table) 
        //{
        //    Debug.Assert(Format(Table)==1); 
        //    return Table.GetUShort(offset + offsetFormat1PairSetCount); 
        //}
 
        private PairSetTable Format1PairSet(FontTable Table, ushort Index)
        {
            Invariant.Assert(Format(Table)==1);
            return new PairSetTable(offset + Table.GetUShort(offset + 
                                                             offsetFormat1PairSetArray +
                                                             Index * sizeFormat1PairSetOffset), 
                                    FirstValueFormat(Table), 
                                    SecondValueFormat(Table));
        } 

        private ClassDefTable Format2Class1Table(FontTable Table)
        {
            Invariant.Assert(Format(Table)==2); 
            return new ClassDefTable(offset+Table.GetUShort(offset + offsetFormat2ClassDef1));
        } 
 
        private ClassDefTable Format2Class2Table(FontTable Table)
        { 
            Invariant.Assert(Format(Table)==2);
            return new ClassDefTable(offset+Table.GetUShort(offset + offsetFormat2ClassDef2));
        }
 
        private ushort Format2Class1Count(FontTable Table)
        { 
            Invariant.Assert(Format(Table)==2); 
            return Table.GetUShort(offset + offsetFormat2Class1Count);
        } 

        private ushort Format2Class2Count(FontTable Table)
        {
            Invariant.Assert(Format(Table)==2); 
            return Table.GetUShort(offset + offsetFormat2Class2Count);
        } 
 
        private ValueRecordTable Format2FirstValueRecord(FontTable Table,
                                             ushort Class2Count, 
                                             ushort Class1Index,
                                             ushort Class2Index
                                            )
        { 
            Invariant.Assert(Format(Table)==2);
 
            ushort firstValueFormat  = FirstValueFormat(Table), 
                   secondValueFormat = SecondValueFormat(Table);
            int    recordSize = ValueRecordTable.Size(firstValueFormat) + 
                                ValueRecordTable.Size(secondValueFormat);

            return new ValueRecordTable(offset + offsetFormat2ValueRecordArray +
                                            (Class1Index*Class2Count+Class2Index)*recordSize, 
                                        offset,
                                        firstValueFormat); 
        } 

        private ValueRecordTable Format2SecondValueRecord(FontTable Table, 
                                              ushort Class2Count,
                                              ushort Class1Index,
                                              ushort Class2Index
                                             ) 
        {
            Invariant.Assert(Format(Table)==2); 
 
            ushort firstValueFormat   = FirstValueFormat(Table),
                   secondValueFormat = SecondValueFormat(Table); 
            int secondRecordOffset = ValueRecordTable.Size(firstValueFormat),
                recordSize = secondRecordOffset + ValueRecordTable.Size(secondValueFormat);

            return new ValueRecordTable(offset + 
                                           offsetFormat2ValueRecordArray +
                                           (Class1Index*Class2Count+Class2Index)*recordSize + 
                                           secondRecordOffset, 
                                        offset,
                                        secondValueFormat 
                                       );
        }

#region Pair positioing child 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 PairSetTable
        {
            private const int offsetPairValueCount = 0; 
            private const int offsetPairValueArray = 2;
            private const int offsetPairValueSecondGlyph = 0; 
            private const int offsetPairValueValue1 = 2; 

            public ushort PairValueCount(FontTable Table) 
            {
                return Table.GetUShort(offset + offsetPairValueCount);
            }
 
            public ushort PairValueGlyph(FontTable Table, ushort Index)
            { 
                return Table.GetUShort( offset + offsetPairValueArray + 
                    Index*pairValueRecordSize +
                    offsetPairValueSecondGlyph); 
            }

            public ValueRecordTable FirstValueRecord(FontTable Table, ushort Index, ushort Format)
            { 
                return new ValueRecordTable(offset + offsetPairValueArray +
                    Index*pairValueRecordSize + 
                    offsetPairValueValue1, 
                    offset,
                    Format); 
            }

            public ValueRecordTable SecondValueRecord(FontTable Table, ushort Index, ushort Format)
            { 
                return new ValueRecordTable(offset + offsetPairValueArray +
                    Index*pairValueRecordSize + 
                    secondValueRecordOffset, 
                    offset,
                    Format); 
            }

            //Search for second glyph in pair. returns -1 if not found
            public int FindPairValue(FontTable Table, ushort Glyph) 
            {
                //PERF: binary search 
                ushort pairCount = PairValueCount(Table); 
                for(ushort  i=0; i=0); 
            Invariant.Assert(AfterLastGlyph<=GlyphInfo.Length); 

            NextGlyph = FirstGlyph+1; //Always move to the next glyph, whether matched or not 

            int glyphCount=GlyphInfo.Length;
            ushort firstGlyphId = GlyphInfo.Glyphs[FirstGlyph];
 
            int secondGlyph = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo,FirstGlyph+1,LookupFlags,LayoutEngine.LookForward);
            if (secondGlyph>=AfterLastGlyph) return false; 
 
            ushort secondGlyphId = GlyphInfo.Glyphs[secondGlyph];
 
            ValueRecordTable firstValueRecord, secondValueRecord;

            switch (Format(Table))
            { 
                case 1:
                { 
                    int coverageIndex = Coverage(Table).GetGlyphIndex(Table,firstGlyphId); 
                    if (coverageIndex==-1) return false;
 
                    PairSetTable pairSet = Format1PairSet(Table,(ushort)coverageIndex);

                    int pairValueIndex = pairSet.FindPairValue(Table, secondGlyphId);
                    if (pairValueIndex == -1) return false; 

                    firstValueRecord  = pairSet.FirstValueRecord(Table,(ushort)pairValueIndex,FirstValueFormat(Table)); 
                    secondValueRecord = pairSet.SecondValueRecord(Table,(ushort)pairValueIndex,SecondValueFormat(Table)); 

                    break; 
                }
                case 2:
                {
                    int coverageIndex = Coverage(Table).GetGlyphIndex(Table,firstGlyphId); 
                    if (coverageIndex == -1) return false;
 
                    ushort firstClassIndex = Format2Class1Table(Table).GetClass(Table,firstGlyphId); 
                    if (firstClassIndex >= Format2Class1Count(Table)) return false; //this is invalid font;
                    ushort secondClassIndex = Format2Class2Table(Table).GetClass(Table,secondGlyphId); 
                    if (secondClassIndex >= Format2Class2Count(Table)) return false; //this is invalid font;

                    ushort class2Count = Format2Class2Count(Table);
                    firstValueRecord = Format2FirstValueRecord(Table, 
                                                               class2Count,
                                                               firstClassIndex, 
                                                               secondClassIndex 
                                                              );
                    secondValueRecord = Format2SecondValueRecord(Table, 
                                                                 class2Count,
                                                                 firstClassIndex,
                                                                 secondClassIndex
                                                                ); 
                    break;
                } 
                default: 
                    return false;
            } 

            //Now adjust positions
            firstValueRecord.AdjustPos (Table, Metrics, ref Offsets[FirstGlyph],  ref Advances[FirstGlyph]);
            secondValueRecord.AdjustPos(Table, Metrics, ref Offsets[secondGlyph], ref Advances[secondGlyph]); 

            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 PairPositioningSubtable(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 MarkArray
    {
        private const int offsetClassArray = 2;
        private const int sizeClassRecord = 4; 
        private const int offsetClassRecordClass = 0;
        private const int offsetClassRecordAnchor = 2; 
 
        public ushort Class(FontTable Table, ushort Index)
        { 
            return Table.GetUShort(offset + offsetClassArray +
                                            Index*sizeClassRecord +
                                            offsetClassRecordClass);
        } 

        public AnchorTable MarkAnchor(FontTable Table, ushort Index) 
        { 
            int anchorTableOffset = Table.GetUShort(offset + offsetClassArray +
                                                    Index*sizeClassRecord+ 
                                                    offsetClassRecordAnchor
                                                   );
            if (anchorTableOffset == 0)
            { 
                return new AnchorTable(Table, 0);
            } 
 
            return new AnchorTable(Table,offset + anchorTableOffset);
        } 

        public MarkArray(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 MarkToBasePositioningSubtable
    {
        private const int offsetFormat = 0; 
        private const int offsetCoverage = 2;
        private const int offsetBaseCoverage = 4; 
        private const int offsetClassCount = 6; 
        private const int offsetMarkArray = 8;
        private const int offsetBaseArray = 10; 

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

        private CoverageTable BaseCoverage(FontTable Table)
        { 
            return new CoverageTable(offset + Table.GetUShort(offset +
                                                                  offsetBaseCoverage)); 
        } 

        private ushort ClassCount(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetClassCount);
        }
 
        private MarkArray Marks(FontTable Table)
        { 
            return new MarkArray(offset + Table.GetUShort(offset + offsetMarkArray)); 
        }
 
        private BaseArray Bases(FontTable Table)
        {
            return new BaseArray(offset + Table.GetUShort(offset + offsetBaseArray));
        } 

#region Mark to base positioning child 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 BaseArray
        { 
            private const int offsetAnchorArray = 2;
            private const int sizeAnchorOffset = 2; 
 
            public AnchorTable BaseAnchor(FontTable Table, ushort BaseIndex,
                ushort MarkClassCount, 
                ushort MarkClass)
            {
                int anchorTableOffset = Table.GetUShort(offset + offsetAnchorArray +
                                                        (BaseIndex*MarkClassCount + MarkClass) * 
                                                        sizeAnchorOffset
                                                       ); 
                if (anchorTableOffset == 0) 
                {
                    return new AnchorTable(Table, 0); 
                }

                return new AnchorTable(Table, offset + anchorTableOffset);
            } 

            public BaseArray(int Offset)  { offset = Offset; } 
            private int offset; 
        }
#endregion 

        public unsafe bool Apply(
            IOpenTypeFont   Font,
            FontTable       Table, 
            LayoutMetrics   Metrics,        // LayoutMetrics
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs 
            ushort          LookupFlags,    // Lookup flags for glyph lookups 
            int*            Advances,       // Glyph adv.widths
            LayoutOffset*   Offsets,        // Glyph offsets 
            int             FirstGlyph,     // where to apply lookup
            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; //Always move to the next glyph, whether matched or not 

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

            int glyphCount=GlyphInfo.Length; 

            int markGlyph=FirstGlyph; 
 
            //Lookup works with marks only
            if ((GlyphInfo.GlyphFlags[markGlyph]&(ushort)GlyphFlags.GlyphTypeMask)!=(ushort)GlyphFlags.Mark) return false; 

            int markCoverageIndex = MarkCoverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[markGlyph]);
            if (markCoverageIndex==-1) return false;
 
            //Find preceeding base (precisely, not mark ). Uses special lookup flag
            int baseGlyph = LayoutEngine.GetNextGlyphInLookup(Font, 
                                                              GlyphInfo, 
                                                              FirstGlyph - 1,
                                                              LayoutEngine.LookupFlagFindBase, 
                                                              LayoutEngine.LookBackward);
            if (baseGlyph<0) return false;

            int baseCoverageIndex = BaseCoverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[baseGlyph]); 
            if (baseCoverageIndex == -1) return false;
 
            ushort classCount = ClassCount(Table); 
            MarkArray marks = Marks(Table);
 
            ushort markClass = marks.Class(Table,(ushort)markCoverageIndex);
            if (markClass>=classCount) return false; //Invalid mark class

            AnchorTable markAnchor = marks.MarkAnchor(Table,(ushort)markCoverageIndex); 
            if (markAnchor.IsNull())
            { 
                return false; 
            }
 
            AnchorTable baseAnchor = Bases(Table).BaseAnchor(Table,(ushort)baseCoverageIndex,classCount,markClass);
            if (baseAnchor.IsNull())
            {
                return false; 
            }
 
            Positioning.AlignAnchors(Font,Table,Metrics,GlyphInfo,Advances,Offsets, 
                                        baseGlyph,markGlyph,baseAnchor,markAnchor,false);
            return true; 
        }

        public bool IsLookupCovered(
                        FontTable table, 
                        uint[] glyphBits,
                        ushort minGlyphId, 
                        ushort maxGlyphId) 
        {
            // 
            return false;
        }

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

        public MarkToBasePositioningSubtable(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 MarkToMarkPositioningSubtable 
    {
        private const int offsetFormat = 0;
        private const int offsetCoverage = 2;
        private const int offsetMark2Coverage = 4; 
        private const int offsetClassCount = 6;
        private const int offsetMark1Array = 8; 
        private const int offsetMark2Array = 10; 

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

        private ushort Mark1ClassCount(FontTable Table) 
        { 
            return Table.GetUShort(offset + offsetClassCount);
        } 

        private MarkArray Mark1Array(FontTable Table)
        {
            return new MarkArray(offset + Table.GetUShort(offset + offsetMark1Array)); 
        }
 
        private Mark2Array Marks2(FontTable Table) 
        {
            return new Mark2Array(offset + Table.GetUShort(offset + offsetMark2Array)); 
        }

#region Mark to mark positioning child 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 Mark2Array 
        {
            private const int offsetCount = 0;
            private const int offsetAnchors = 2;
            private const int sizeAnchorOffset = 2; 

            public AnchorTable Anchor(FontTable Table, 
                ushort Mark2Index, 
                ushort Mark1ClassCount,
                ushort Mark1Class) 
            {
                int anchorTableOffset = Table.GetUShort(offset + offsetAnchors +
                                                        (Mark2Index*Mark1ClassCount+Mark1Class) *
                                                        sizeAnchorOffset 
                                                       );
                if (anchorTableOffset == 0) 
                { 
                    return new AnchorTable(Table, 0);
                } 

                return new AnchorTable(Table, offset + anchorTableOffset);
            }
#endregion 

            public Mark2Array(int Offset)  { offset = Offset; } 
            private int offset; 
        }
 
        public unsafe bool Apply(
            IOpenTypeFont   Font,
            FontTable       Table,
            LayoutMetrics   Metrics,        // LayoutMetrics 
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs
            ushort          LookupFlags,    // Lookup flags for glyph lookups 
            int*            Advances,       // Glyph adv.widths 
            LayoutOffset*   Offsets,        // Glyph offsets
            int             FirstGlyph,     // where to apply lookup 
            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; //Always move to the next glyph, whether matched or not
 
            if (Format(Table) != 1) return false; //unknown format

            int glyphCount=GlyphInfo.Length;
 
            int mark1Glyph=FirstGlyph;
 
            //Lookup works with marks only 
            if ((GlyphInfo.GlyphFlags[mark1Glyph]&(ushort)GlyphFlags.GlyphTypeMask)!=(ushort)GlyphFlags.Mark) return false;
 
            int mark1CoverageIndex = Mark1Coverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[mark1Glyph]);
            if (mark1CoverageIndex==-1) return false;

            //Find preceeding mark according mark from specified class 
            int mark2Glyph = LayoutEngine.GetNextGlyphInLookup(Font,
                GlyphInfo, 
                FirstGlyph-1, 
                (ushort)(LookupFlags & 0xFF00), //Clear Ignore... flags
                LayoutEngine.LookBackward); 
            if (mark2Glyph<0) return false;

            int mark2CoverageIndex = Mark2Coverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[mark2Glyph]);
            if (mark2CoverageIndex==-1) return false; 

            ushort classCount = Mark1ClassCount(Table); 
            MarkArray mark1Array = Mark1Array(Table); 

            ushort mark1Class = mark1Array.Class(Table,(ushort)mark1CoverageIndex); 
            if (mark1Class>=classCount) return false; //Invalid mark class

            AnchorTable mark1Anchor = mark1Array.MarkAnchor(Table,(ushort)mark1CoverageIndex);
            if (mark1Anchor.IsNull()) 
            {
                return false; 
            } 

            AnchorTable mark2Anchor = Marks2(Table).Anchor(Table,(ushort)mark2CoverageIndex,classCount,mark1Class); 
            if (mark2Anchor.IsNull())
            {
                return false;
            } 

            Positioning.AlignAnchors(Font,Table,Metrics,GlyphInfo,Advances,Offsets, 
                mark2Glyph,mark1Glyph,mark2Anchor,mark1Anchor,false); 
            return true;
        } 

        public bool IsLookupCovered(
                        FontTable table,
                        uint[] glyphBits, 
                        ushort minGlyphId,
                        ushort maxGlyphId) 
        { 
            //
            return false; 
        }

        public CoverageTable GetPrimaryCoverage(FontTable table)
        { 
            return Mark1Coverage(table);
        } 
 
        public MarkToMarkPositioningSubtable(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 CursivePositioningSubtable
    { 
        private const ushort offsetFormat = 0;
        private const ushort offsetCoverage = 2;
        private const ushort offsetEntryExitCount = 4;
        private const ushort offsetEntryExitArray = 6; 
        private const ushort sizeEntryExitRecord = 4;
        private const ushort offsetEntryAnchor = 0; 
        private const ushort offsetExitAnchor = 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 EntryExitCount(FontTable Table)
        //{ 
        //    return Table.GetUShort(offsetEntryExitCount);
        //} 
 
        private AnchorTable EntryAnchor(FontTable Table, int Index)
        { 
            int anchorTableOffset = Table.GetUShort(offset +
                                                        offsetEntryExitArray +
                                                        sizeEntryExitRecord * Index +
                                                        offsetEntryAnchor); 
            if (anchorTableOffset == 0) return new AnchorTable(Table,0);
 
            return new AnchorTable(Table, offset + anchorTableOffset); 
        }
 
        private AnchorTable ExitAnchor(FontTable Table, int Index)
        {
            int anchorTableOffset = Table.GetUShort(offset +
                                                        offsetEntryExitArray + 
                                                        sizeEntryExitRecord * Index +
                                                        offsetExitAnchor); 
            if (anchorTableOffset == 0) return new AnchorTable(Table,0); 

            return new AnchorTable(Table, offset + anchorTableOffset); 
        }

        public unsafe bool Apply(
            IOpenTypeFont   Font, 
            FontTable       Table,
            LayoutMetrics   Metrics,        // LayoutMetrics 
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs 
            ushort          LookupFlags,    // Lookup flags for glyph lookups
            int*            Advances,       // Glyph adv.widths 
            LayoutOffset*   Offsets,        // Glyph offsets
            int             FirstGlyph,     // where to apply lookup
            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;

            if (Format(Table) != 1) return false; // Unknown format
 
            bool RTL = (LookupFlags & LayoutEngine.LookupFlagRightToLeft) != 0;
            ushort cursiveBit = (ushort)GlyphFlags.CursiveConnected; 
 
            //
 



            int glyphIndex, prevGlyphIndex, 
                coverageIndex, prevCoverageIndex;
 
            glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo, 
                                                               FirstGlyph,LookupFlags,
                                                               LayoutEngine.LookForward 
                                                           );

            //clear "CursiveConected" bit,
            //we will set it only if there is a connection to previous glyph 
            if (RTL)
            { 
                GlyphInfo.GlyphFlags[glyphIndex] &= (ushort)~cursiveBit; 
            }
 
            if ( glyphIndex >= AfterLastGlyph )
            {
                return false;
            } 

            prevGlyphIndex = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo, 
                                                               FirstGlyph-1,LookupFlags, 
                                                               LayoutEngine.LookBackward
                                                              ); 
            if ( prevGlyphIndex < 0 )
            {
                return false;
            } 

            CoverageTable coverage = Coverage(Table); 
 
            coverageIndex = coverage.GetGlyphIndex(Table,GlyphInfo.Glyphs[glyphIndex]);
            if (coverageIndex == -1) 
            {
                return false;
            }
 
            prevCoverageIndex = coverage.
                                   GetGlyphIndex(Table,GlyphInfo.Glyphs[prevGlyphIndex]); 
            if (prevCoverageIndex == -1) 
            {
                return false; 
            }

            AnchorTable prevExitAnchor, entryAnchor;
 
            prevExitAnchor = ExitAnchor(Table, prevCoverageIndex);
            if (prevExitAnchor.IsNull()) 
            { 
                return false;
            } 

            entryAnchor = EntryAnchor(Table,coverageIndex);
            if (entryAnchor.IsNull())
            { 
                return false;
            } 
 
            Positioning.AlignAnchors(Font, Table, Metrics,
                                     GlyphInfo, Advances, Offsets, 
                                     prevGlyphIndex, glyphIndex,
                                     prevExitAnchor, entryAnchor, true);

            if (RTL) 
            {
                UshortList glyphFlags = GlyphInfo.GlyphFlags; 
 
                int index;
 
                //set "cursive" bit for everything up to prevGlyphIndex
                for(index = glyphIndex; index>prevGlyphIndex; index--)
                {
                    glyphFlags[index] |= cursiveBit; 
                }
 
                //fix cursive dependencies 
                int yCorrection = Offsets[glyphIndex].dy;
                for(index = glyphIndex; 
                    (glyphFlags[index] & cursiveBit) != 0 ;
                    index--
                   )
                { 
                    Offsets[index].dy -= yCorrection;
                } 
                Invariant.Assert(glyphIndex>=0); //First glyph should not have bit set 
                Offsets[index].dy  -= yCorrection;
            } 

            return true;
        }
 
        public bool IsLookupCovered(
                        FontTable table, 
                        uint[] glyphBits, 
                        ushort minGlyphId,
                        ushort maxGlyphId) 
        {
            //
            return true;
        } 

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

        public CursivePositioningSubtable(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 LigatureAttachTable
    {
        private const int offsetAnchorArray = 2; 
        private const int sizeAnchorOffset = 2;
 
        public AnchorTable LigatureAnchor(FontTable Table, 
                                          ushort Component,
                                          ushort MarkClass) 
        {
            int anchorTableOffset = Table.GetUShort(offset + offsetAnchorArray +
                                                    (Component*classCount + MarkClass) *
                                                                      sizeAnchorOffset); 
            if (anchorTableOffset == 0)
            { 
                return new AnchorTable(Table, 0); 
            }
 
            return new AnchorTable(Table, offset + anchorTableOffset);
        }

        public LigatureAttachTable(int Offset,ushort ClassCount) 
        {
            offset = Offset; 
            classCount = ClassCount; 
        }
 
        private int offset;
        private int classCount;
    }
 
    /// 
    /// 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 MarkToLigaturePositioningSubtable
    {
        private const int offsetFormat = 0;
        private const int offsetMarkCoverage = 2; 
        private const int offsetLigatureCoverage = 4;
        private const int offsetClassCount = 6; 
        private const int offsetMarkArray = 8; 
        private const int offsetLigatureArray = 10;
        private const int offsetLigatureAttachArray = 2; 
        private const int sizeOffset = 2;

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

        private CoverageTable LigatureCoverage(FontTable Table) 
        {
            return new CoverageTable(offset + Table.GetUShort(offset + offsetLigatureCoverage)); 
        } 

        private ushort ClassCount(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetClassCount);
        }
 
        private MarkArray Marks(FontTable Table)
        { 
            return new MarkArray(offset + Table.GetUShort(offset + offsetMarkArray)); 
        }
 
        private LigatureAttachTable Ligatures(FontTable Table, int Index, ushort ClassCount)
        {
            int offsetLigatureArrayTable = offset + Table.GetUShort(offset + offsetLigatureArray);
            return new LigatureAttachTable(offsetLigatureArrayTable + 
                                           Table.GetUShort(offsetLigatureArrayTable +
                                                           offsetLigatureAttachArray + 
                                                           Index * sizeOffset), 
                                           ClassCount
                                          ); 
        }

        // Find base ligature and component corresponding to the mark
        private unsafe void FindBaseLigature ( 
            int             CharCount,
            UshortList      Charmap, 
            GlyphInfoList   GlyphInfo, 
            int             markGlyph,
            out ushort      component, 
            out int         ligatureGlyph
           )
        {
            int ligatureChar = 0; 
            ligatureGlyph = -1;
            component = 0; 
 
            bool FoundBase = false;
            for (int ch = GlyphInfo.FirstChars[markGlyph]; 
                        ch >= 0 && !FoundBase; ch--)
            {
                ushort glyph = Charmap[ch];
                if ((GlyphInfo.GlyphFlags[glyph] & (ushort)GlyphFlags.GlyphTypeMask) != 
                                                                    (ushort)GlyphFlags.Mark)
                { 
                    ligatureChar = ch; 
                    ligatureGlyph = glyph;
                    FoundBase = true; 
                }
            }
            if (!FoundBase) return;
 
            ushort comp = 0;
            for(ushort ch = GlyphInfo.FirstChars[ligatureGlyph]; 
                ch=0);
            Invariant.Assert(AfterLastGlyph<=GlyphInfo.Length); 

            NextGlyph = FirstGlyph+1; //Always move to the next glyph, whether matched or not 
 
            if (Format(Table) != 1) return false; //unknown format
 
            int glyphCount=GlyphInfo.Length;
            int markGlyph=FirstGlyph;

            //Lookup works with marks only 
            if ((GlyphInfo.GlyphFlags[markGlyph]&(ushort)GlyphFlags.GlyphTypeMask)!=(ushort)GlyphFlags.Mark) return false;
 
            int markCoverageIndex = MarkCoverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[markGlyph]); 
            if (markCoverageIndex==-1) return false;
 
            int baseGlyph;
            ushort component;

            FindBaseLigature(CharCount, Charmap,GlyphInfo,markGlyph, 
                                                out component, out baseGlyph);
            if (baseGlyph<0) return false; 
 
            int baseCoverageIndex = LigatureCoverage(Table).
                                        GetGlyphIndex(Table,GlyphInfo.Glyphs[baseGlyph]); 
            if (baseCoverageIndex == -1) return false;

            ushort classCount = ClassCount(Table);
            MarkArray marks = Marks(Table); 

            ushort markClass = marks.Class(Table,(ushort)markCoverageIndex); 
            if (markClass>=classCount) return false; //Invalid mark class 

            AnchorTable baseAnchor = Ligatures(Table,baseCoverageIndex, classCount). 
                                            LigatureAnchor(Table,component,markClass);
            if (baseAnchor.IsNull())
            {
                return false; 
            }
 
            AnchorTable markAnchor = marks.MarkAnchor(Table,(ushort)markCoverageIndex); 
            if (markAnchor.IsNull())
            { 
                return false;
            }

            Positioning.AlignAnchors(Font,Table,Metrics,GlyphInfo,Advances,Offsets, 
                baseGlyph,markGlyph,baseAnchor,markAnchor,false);
 
            return true; 
        }
 
        public bool IsLookupCovered(
                        FontTable table,
                        uint[] glyphBits,
                        ushort minGlyphId, 
                        ushort maxGlyphId)
        { 
            // 
            return false;
        } 

        public CoverageTable GetPrimaryCoverage(FontTable table)
        {
            return MarkCoverage(table); 
        }
 
        public MarkToLigaturePositioningSubtable(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:      Positioning.cs
// 
//  Contents:  OpentTypeLayout positioning 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
{ 
    //
 
 

 



 

 
 

    ///  
    /// Critical - Everything in this class is considered critical
    ///            because they either operate on raw font table bits or unsafe pointers.
    /// 
    [SecurityCritical(SecurityCriticalScope.Everything)] 
    internal static class Positioning
    { 
        public static int DesignToPixels(ushort DesignUnitsPerEm, ushort PixelsPerEm, int Value) 
        {
            //Result requested in design units 
            if (DesignUnitsPerEm==0) return Value;

            int  rounding = ((int)DesignUnitsPerEm)/2;;
 
            if (Value >= 0)
            { 
                // Half of Units per Em 
                rounding = ((int)DesignUnitsPerEm)/2;
            } 
            else
            {
                // -(Half of Units per Em). +1 to ensure rounding
                rounding = -((int)DesignUnitsPerEm >> 1)+1; 
            }
 
            return (Value*(int)PixelsPerEm + rounding)/DesignUnitsPerEm; 
        }
 

        /// 
        ///  Align to anchors between two glyphs (e.g. mark and base)
        ///  by changing adv.width and offsets for both of them 
        /// 
        ///  
        ///  
        /// 
        ///  
        /// 
        /// 
        /// 
        ///  
        /// 
        ///  
        ///  
        /// 
        public static unsafe void AlignAnchors( 
                                        IOpenTypeFont   Font,
                                        FontTable          Table,
                                        LayoutMetrics   Metrics,
                                        GlyphInfoList   GlyphInfo, 
                                        int*            Advances,
                                        LayoutOffset*   Offsets, 
                                        int             StaticGlyph, 
                                        int             MobileGlyph,
                                        AnchorTable     StaticAnchor, 
                                        AnchorTable     MobileAnchor,
                                        bool            UseAdvances
                                      )
        { 
            Invariant.Assert(StaticGlyph>=0 && StaticGlyph=0 && MobileGlyph 
    /// 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 DeviceTable 
    {
        private const int offsetStartSize = 0;
        private const int offsetEndSize = 2;
        private const int offsetDeltaFormat = 4; 
        private const int offsetDeltaValueArray = 6;
        private const int sizeDeltaValue = 2; 
 
        private ushort StartSize(FontTable Table)
        { 
            return Table.GetUShort(offset + offsetStartSize);
        }

        private ushort EndSize(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetEndSize); 
        } 

        private ushort DeltaFormat(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetDeltaFormat);
        }
 
        private ushort DeltaValue(FontTable Table, ushort Index)
        { 
            return Table.GetUShort( offset + offsetDeltaValueArray + 
                                             Index * sizeDeltaValue);
        } 

        public int Value(FontTable Table, ushort PixelsPerEm)
        {
            if (IsNull()) return 0; 

            ushort startSize = StartSize(Table); 
            ushort endSize   = EndSize(Table); 

            if (PixelsPerEmendSize) return 0; 

            ushort sizeIndex = (ushort)(PixelsPerEm-startSize);
            ushort valueIndex, shiftUp, shiftDown;
 
            switch (DeltaFormat(Table))
            { 
                case 1: 
                    valueIndex = (ushort)(sizeIndex>>3);
                    shiftUp    = (ushort)(16 + 2*(sizeIndex&0x0007)); 
                    shiftDown  = 30;
                    break;

                case 2: 
                    valueIndex = (ushort)(sizeIndex>>2);
                    shiftUp    = (ushort)(16 + 4*(sizeIndex&0x0003)); 
                    shiftDown  = 28; 
                    break;
 
                case 3:
                    valueIndex = (ushort)(sizeIndex>>1);
                    shiftUp    = (ushort)(16 + 8*(sizeIndex&0x0001));
                    shiftDown  = 24; 
                    break;
 
                default: 
                    return 0; //Unknown format
            } 

            int delta = DeltaValue(Table,valueIndex);
            delta <<= shiftUp;      //clear leading bits
            delta >>= shiftDown;    //extend sign and clear trailing bits 

            return delta; 
        } 

        public DeviceTable(int Offset) { offset = Offset; } 
        bool IsNull() { return (offset==0); }
        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 ValueRecordTable
    {
        const ushort XPlacmentFlag = 0x0001;
        const ushort YPlacmentFlag = 0x0002; 
        const ushort XAdvanceFlag   = 0x0004;
        const ushort YAdvanceFlag  = 0x0008; 
        const ushort XPlacementDeviceFlag = 0x0010; 
        const ushort YPlacementDeviceFlag = 0x0020;
        const ushort XAdvanceDeviceFlag  = 0x0040; 
        const ushort YAdvanceDeviceFlag  = 0x0080;

        private static ushort[] BitCount =
                    new ushort[16] { 0, 2, 2, 4,  2, 4, 4, 6,  2, 4, 4, 6,  4, 6, 6, 8 }; 

        public static ushort Size(ushort Format) 
        { 
            return (ushort)(BitCount[Format&0x000F]+BitCount[(Format>>4)&0x000F]);
        } 

        public void AdjustPos(  FontTable Table,
                                LayoutMetrics Metrics,
                                ref LayoutOffset GlyphOffset, 
                                ref int    GlyphAdvance
                             ) 
        { 
            int curOffset=offset;
 
            if ((format&XPlacmentFlag)!=0)
            {
                GlyphOffset.dx += Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth,
                                                                Table.GetShort(curOffset)); 
                curOffset+=2;
            } 
 
            if ((format&YPlacmentFlag)!=0)
            { 
                GlyphOffset.dy += Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmHeight,
                                                                Table.GetShort(curOffset));

                curOffset+=2; 
            }
 
            if ((format&XAdvanceFlag)!=0) 
            {
                    GlyphAdvance += Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth, 
                                                                    Table.GetShort(curOffset));
                curOffset+=2;
            }
 
            if ((format&YAdvanceFlag)!=0)
            { 
                    GlyphAdvance += Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmHeight, 
                        Table.GetShort(curOffset));
                curOffset+=2; 
            }

            if ((format&XPlacementDeviceFlag)!=0)
            { 
                int deviceTableOffset = Table.GetOffset(curOffset);
                if (deviceTableOffset != FontTable.NullOffset) 
                { 
                    DeviceTable deviceTable  = new DeviceTable(baseTableOffset+deviceTableOffset);
                    GlyphOffset.dx += deviceTable.Value(Table,Metrics.PixelsEmWidth); 
                }

                curOffset+=2;
            } 

            if ((format&YPlacementDeviceFlag)!=0) 
            { 
                int deviceTableOffset = Table.GetOffset(curOffset);
                if (deviceTableOffset != FontTable.NullOffset) 
                {
                    DeviceTable deviceTable  = new DeviceTable(baseTableOffset+deviceTableOffset);
                    GlyphOffset.dy += deviceTable.Value(Table,Metrics.PixelsEmHeight);
                } 

                curOffset+=2; 
            } 

            if ((format&XAdvanceDeviceFlag)!=0) 
            {
                if (Metrics.Direction==TextFlowDirection.LTR || Metrics.Direction==TextFlowDirection.RTL)
                {
                    int deviceTableOffset = Table.GetOffset(curOffset); 
                    if (deviceTableOffset != FontTable.NullOffset)
                    { 
                        DeviceTable deviceTable  = new DeviceTable(baseTableOffset+deviceTableOffset); 
                        GlyphAdvance += deviceTable.Value(Table,Metrics.PixelsEmWidth);
                    } 
                }

                curOffset+=2;
            } 

            if ((format&YAdvanceDeviceFlag)!=0) 
            { 
                if (Metrics.Direction==TextFlowDirection.TTB || Metrics.Direction==TextFlowDirection.BTT)
                { 
                    int deviceTableOffset = Table.GetOffset(curOffset);
                    if (deviceTableOffset != FontTable.NullOffset)
                    {
                        DeviceTable deviceTable  = new DeviceTable(baseTableOffset+deviceTableOffset); 
                        GlyphAdvance += deviceTable.Value(Table,Metrics.PixelsEmHeight);
                    } 
                } 

                curOffset+=2; 
            }
        }

        public ValueRecordTable(int Offset, int BaseTableOffset, ushort Format) 
        {
            offset = Offset; 
            baseTableOffset = BaseTableOffset; 
            format=Format;
        } 

        private ushort format;
        private int baseTableOffset;
        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 AnchorTable
    { 
        private const int offsetFormat = 0;
        private const int offsetXCoordinate = 2; 
        private const int offsetYCoordinate = 4; 
        private const int offsetFormat2AnchorPoint = 6;
        private const int offsetFormat3XDeviceTable = 6; 
        private const int offsetFormat3YDeviceTable = 8;

        private short XCoordinate(FontTable Table)
        { 
            return Table.GetShort(offset + offsetXCoordinate);
        } 
 
        private short YCoordinate(FontTable Table)
        { 
            return Table.GetShort(offset + offsetYCoordinate);
        }

        private ushort Format2AnchorPoint(FontTable Table) 
        {
            Invariant.Assert(format==2); 
            return Table.GetUShort(offset + offsetFormat2AnchorPoint); 
        }
 
        private DeviceTable Format3XDeviceTable(FontTable Table)
        {
            Invariant.Assert(format==3);
            int DeviceOffset = Table.GetUShort(offset + offsetFormat3XDeviceTable); 

            if (DeviceOffset!=0) 
            { 
                return new DeviceTable(offset + DeviceOffset);
            } 
            else
            {
                return new DeviceTable(0);
            } 
        }
 
        private DeviceTable Format3YDeviceTable(FontTable Table) 
        {
            Invariant.Assert(format==3); 

            int DeviceOffset = Table.GetUShort(offset + offsetFormat3YDeviceTable);

            if (DeviceOffset!=0) 
            {
                return new DeviceTable(offset + DeviceOffset); 
            } 
            else
            { 
                return new DeviceTable(0);
            }
        }
 
        public bool NeedContourPoint(FontTable Table)
        { 
            return (format==2); 
        }
 
        public ushort ContourPointIndex(FontTable Table)
        {
            Invariant.Assert(NeedContourPoint(Table));
            return Format2AnchorPoint(Table); 
        }
 
        public LayoutOffset AnchorCoordinates( 
                                    FontTable       Table,
                                    LayoutMetrics   Metrics, 
                                    LayoutOffset    ContourPoint
                                )
        {
            LayoutOffset Point = new LayoutOffset(); 

            switch (format) 
            { 
                case 1: //Simple coordinates
                        Point.dx = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth,XCoordinate(Table)); 
                        Point.dy = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmHeight,YCoordinate(Table));
                        break;

                case 2: //Coordinates + anchor point 
                        if (ContourPoint.dx==int.MinValue)
                        { 
                            Point.dx = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth,XCoordinate(Table)); 
                            Point.dy = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmHeight,YCoordinate(Table));
                        } 
                        else
                        {
                            Point.dx = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth,ContourPoint.dx);
                            Point.dy = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth,ContourPoint.dy); 
                        }
                        break; 
 
                case 3: //Coordinates + Device table
                        Point.dx = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmWidth,XCoordinate(Table))+ 
                                        Format3XDeviceTable(Table).Value(Table,Metrics.PixelsEmWidth);
                        Point.dy = Positioning.DesignToPixels(Metrics.DesignEmHeight,Metrics.PixelsEmHeight,YCoordinate(Table))+
                                        Format3YDeviceTable(Table).Value(Table,Metrics.PixelsEmHeight);
                        break; 

                default: //Unknown format 
                    Point.dx = 0; 
                    Point.dx = 0;
                    break; 
            }

            return Point;
        } 

 
        public AnchorTable(FontTable Table, int Offset) 
        {
            offset = Offset; 
            if (offset != 0)
                format = Table.GetUShort(offset + offsetFormat);
            else
                format = 0; 
        }
 
        public bool IsNull() { return (offset==0); } 
        private int offset;
        private ushort format; 
    }

    /// 
    /// 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 SinglePositioningSubtable
    { 
        private const int offsetFormat = 0;
        private const int offsetCoverage = 2;
        private const int offsetValueFormat = 4;
        private const int offsetFormat1Value = 6; 
        private const int offsetFormat2ValueCount = 6;
        private const int offsetFormat2ValueArray = 8; 
 
        private ushort Format(FontTable Table)
        { 
            return Table.GetUShort(offset + offsetFormat);
        }

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

        private ushort ValueFormat(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetValueFormat);
        }
 
        private ValueRecordTable Format1ValueRecord(FontTable Table)
        { 
            Invariant.Assert(Format(Table)==1); 

            return new ValueRecordTable(offset + offsetFormat1Value, 
                                        offset,
                                        ValueFormat(Table));
        }
 
        private ValueRecordTable Format2ValueRecord(FontTable Table, ushort Index)
        { 
            Invariant.Assert(Format(Table)==2); 

            return new ValueRecordTable(offset + 
                                            offsetFormat2ValueArray +
                                            Index * ValueRecordTable.Size(ValueFormat(Table)),
                                        offset,
                                        ValueFormat(Table)); 
        }
 
        public unsafe bool Apply( 
            FontTable               Table,
            LayoutMetrics           Metrics,        // LayoutMetrics 
            GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs
            int*                    Advances,       // Glyph adv.widths
            LayoutOffset*           Offsets,        // Glyph offsets
            int                     FirstGlyph,     // where to apply lookup 
            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;
 
            int glyphCount=GlyphInfo.Length;
            ushort glyphId = GlyphInfo.Glyphs[FirstGlyph]; 
 
            int coverageIndex = Coverage(Table).GetGlyphIndex(Table,glyphId);
            if (coverageIndex == -1) return false; 

            ValueRecordTable valueRecord;

            switch (Format(Table)) 
            {
                case 1: 
                    valueRecord = Format1ValueRecord(Table); 
                    break;
                case 2: 
                    valueRecord = Format2ValueRecord(Table,(ushort)coverageIndex);
                    break;
                default:
                    return false; 
            }
 
            valueRecord.AdjustPos(Table, Metrics, ref Offsets[FirstGlyph], ref Advances[FirstGlyph]); 

            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 SinglePositioningSubtable(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 PairPositioningSubtable
    { 
        private const int offsetFormat = 0;
        private const int offsetCoverage = 2; 
        private const int offsetValueFormat1 = 4; 
        private const int offsetValueFormat2 = 6;
        private const int offsetFormat1PairSetCount = 8; 
        private const int offsetFormat1PairSetArray = 10;
        private const int sizeFormat1PairSetOffset = 2;
        private const int offsetFormat2ClassDef1 = 8;
        private const int offsetFormat2ClassDef2 = 10; 
        private const int offsetFormat2Class1Count = 12;
        private const int offsetFormat2Class2Count = 14; 
        private const int offsetFormat2ValueRecordArray = 16; 

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

        private ushort SecondValueFormat(FontTable Table) 
        { 
            return Table.GetUShort(offset + offsetValueFormat2);
        } 

        // Not used. This value should be equal to glyph count in coverage table
        // Keeping it for future reference
        //private ushort Format1PairSetCount(FontTable Table) 
        //{
        //    Debug.Assert(Format(Table)==1); 
        //    return Table.GetUShort(offset + offsetFormat1PairSetCount); 
        //}
 
        private PairSetTable Format1PairSet(FontTable Table, ushort Index)
        {
            Invariant.Assert(Format(Table)==1);
            return new PairSetTable(offset + Table.GetUShort(offset + 
                                                             offsetFormat1PairSetArray +
                                                             Index * sizeFormat1PairSetOffset), 
                                    FirstValueFormat(Table), 
                                    SecondValueFormat(Table));
        } 

        private ClassDefTable Format2Class1Table(FontTable Table)
        {
            Invariant.Assert(Format(Table)==2); 
            return new ClassDefTable(offset+Table.GetUShort(offset + offsetFormat2ClassDef1));
        } 
 
        private ClassDefTable Format2Class2Table(FontTable Table)
        { 
            Invariant.Assert(Format(Table)==2);
            return new ClassDefTable(offset+Table.GetUShort(offset + offsetFormat2ClassDef2));
        }
 
        private ushort Format2Class1Count(FontTable Table)
        { 
            Invariant.Assert(Format(Table)==2); 
            return Table.GetUShort(offset + offsetFormat2Class1Count);
        } 

        private ushort Format2Class2Count(FontTable Table)
        {
            Invariant.Assert(Format(Table)==2); 
            return Table.GetUShort(offset + offsetFormat2Class2Count);
        } 
 
        private ValueRecordTable Format2FirstValueRecord(FontTable Table,
                                             ushort Class2Count, 
                                             ushort Class1Index,
                                             ushort Class2Index
                                            )
        { 
            Invariant.Assert(Format(Table)==2);
 
            ushort firstValueFormat  = FirstValueFormat(Table), 
                   secondValueFormat = SecondValueFormat(Table);
            int    recordSize = ValueRecordTable.Size(firstValueFormat) + 
                                ValueRecordTable.Size(secondValueFormat);

            return new ValueRecordTable(offset + offsetFormat2ValueRecordArray +
                                            (Class1Index*Class2Count+Class2Index)*recordSize, 
                                        offset,
                                        firstValueFormat); 
        } 

        private ValueRecordTable Format2SecondValueRecord(FontTable Table, 
                                              ushort Class2Count,
                                              ushort Class1Index,
                                              ushort Class2Index
                                             ) 
        {
            Invariant.Assert(Format(Table)==2); 
 
            ushort firstValueFormat   = FirstValueFormat(Table),
                   secondValueFormat = SecondValueFormat(Table); 
            int secondRecordOffset = ValueRecordTable.Size(firstValueFormat),
                recordSize = secondRecordOffset + ValueRecordTable.Size(secondValueFormat);

            return new ValueRecordTable(offset + 
                                           offsetFormat2ValueRecordArray +
                                           (Class1Index*Class2Count+Class2Index)*recordSize + 
                                           secondRecordOffset, 
                                        offset,
                                        secondValueFormat 
                                       );
        }

#region Pair positioing child 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 PairSetTable
        {
            private const int offsetPairValueCount = 0; 
            private const int offsetPairValueArray = 2;
            private const int offsetPairValueSecondGlyph = 0; 
            private const int offsetPairValueValue1 = 2; 

            public ushort PairValueCount(FontTable Table) 
            {
                return Table.GetUShort(offset + offsetPairValueCount);
            }
 
            public ushort PairValueGlyph(FontTable Table, ushort Index)
            { 
                return Table.GetUShort( offset + offsetPairValueArray + 
                    Index*pairValueRecordSize +
                    offsetPairValueSecondGlyph); 
            }

            public ValueRecordTable FirstValueRecord(FontTable Table, ushort Index, ushort Format)
            { 
                return new ValueRecordTable(offset + offsetPairValueArray +
                    Index*pairValueRecordSize + 
                    offsetPairValueValue1, 
                    offset,
                    Format); 
            }

            public ValueRecordTable SecondValueRecord(FontTable Table, ushort Index, ushort Format)
            { 
                return new ValueRecordTable(offset + offsetPairValueArray +
                    Index*pairValueRecordSize + 
                    secondValueRecordOffset, 
                    offset,
                    Format); 
            }

            //Search for second glyph in pair. returns -1 if not found
            public int FindPairValue(FontTable Table, ushort Glyph) 
            {
                //PERF: binary search 
                ushort pairCount = PairValueCount(Table); 
                for(ushort  i=0; i=0); 
            Invariant.Assert(AfterLastGlyph<=GlyphInfo.Length); 

            NextGlyph = FirstGlyph+1; //Always move to the next glyph, whether matched or not 

            int glyphCount=GlyphInfo.Length;
            ushort firstGlyphId = GlyphInfo.Glyphs[FirstGlyph];
 
            int secondGlyph = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo,FirstGlyph+1,LookupFlags,LayoutEngine.LookForward);
            if (secondGlyph>=AfterLastGlyph) return false; 
 
            ushort secondGlyphId = GlyphInfo.Glyphs[secondGlyph];
 
            ValueRecordTable firstValueRecord, secondValueRecord;

            switch (Format(Table))
            { 
                case 1:
                { 
                    int coverageIndex = Coverage(Table).GetGlyphIndex(Table,firstGlyphId); 
                    if (coverageIndex==-1) return false;
 
                    PairSetTable pairSet = Format1PairSet(Table,(ushort)coverageIndex);

                    int pairValueIndex = pairSet.FindPairValue(Table, secondGlyphId);
                    if (pairValueIndex == -1) return false; 

                    firstValueRecord  = pairSet.FirstValueRecord(Table,(ushort)pairValueIndex,FirstValueFormat(Table)); 
                    secondValueRecord = pairSet.SecondValueRecord(Table,(ushort)pairValueIndex,SecondValueFormat(Table)); 

                    break; 
                }
                case 2:
                {
                    int coverageIndex = Coverage(Table).GetGlyphIndex(Table,firstGlyphId); 
                    if (coverageIndex == -1) return false;
 
                    ushort firstClassIndex = Format2Class1Table(Table).GetClass(Table,firstGlyphId); 
                    if (firstClassIndex >= Format2Class1Count(Table)) return false; //this is invalid font;
                    ushort secondClassIndex = Format2Class2Table(Table).GetClass(Table,secondGlyphId); 
                    if (secondClassIndex >= Format2Class2Count(Table)) return false; //this is invalid font;

                    ushort class2Count = Format2Class2Count(Table);
                    firstValueRecord = Format2FirstValueRecord(Table, 
                                                               class2Count,
                                                               firstClassIndex, 
                                                               secondClassIndex 
                                                              );
                    secondValueRecord = Format2SecondValueRecord(Table, 
                                                                 class2Count,
                                                                 firstClassIndex,
                                                                 secondClassIndex
                                                                ); 
                    break;
                } 
                default: 
                    return false;
            } 

            //Now adjust positions
            firstValueRecord.AdjustPos (Table, Metrics, ref Offsets[FirstGlyph],  ref Advances[FirstGlyph]);
            secondValueRecord.AdjustPos(Table, Metrics, ref Offsets[secondGlyph], ref Advances[secondGlyph]); 

            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 PairPositioningSubtable(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 MarkArray
    {
        private const int offsetClassArray = 2;
        private const int sizeClassRecord = 4; 
        private const int offsetClassRecordClass = 0;
        private const int offsetClassRecordAnchor = 2; 
 
        public ushort Class(FontTable Table, ushort Index)
        { 
            return Table.GetUShort(offset + offsetClassArray +
                                            Index*sizeClassRecord +
                                            offsetClassRecordClass);
        } 

        public AnchorTable MarkAnchor(FontTable Table, ushort Index) 
        { 
            int anchorTableOffset = Table.GetUShort(offset + offsetClassArray +
                                                    Index*sizeClassRecord+ 
                                                    offsetClassRecordAnchor
                                                   );
            if (anchorTableOffset == 0)
            { 
                return new AnchorTable(Table, 0);
            } 
 
            return new AnchorTable(Table,offset + anchorTableOffset);
        } 

        public MarkArray(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 MarkToBasePositioningSubtable
    {
        private const int offsetFormat = 0; 
        private const int offsetCoverage = 2;
        private const int offsetBaseCoverage = 4; 
        private const int offsetClassCount = 6; 
        private const int offsetMarkArray = 8;
        private const int offsetBaseArray = 10; 

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

        private CoverageTable BaseCoverage(FontTable Table)
        { 
            return new CoverageTable(offset + Table.GetUShort(offset +
                                                                  offsetBaseCoverage)); 
        } 

        private ushort ClassCount(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetClassCount);
        }
 
        private MarkArray Marks(FontTable Table)
        { 
            return new MarkArray(offset + Table.GetUShort(offset + offsetMarkArray)); 
        }
 
        private BaseArray Bases(FontTable Table)
        {
            return new BaseArray(offset + Table.GetUShort(offset + offsetBaseArray));
        } 

#region Mark to base positioning child 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 BaseArray
        { 
            private const int offsetAnchorArray = 2;
            private const int sizeAnchorOffset = 2; 
 
            public AnchorTable BaseAnchor(FontTable Table, ushort BaseIndex,
                ushort MarkClassCount, 
                ushort MarkClass)
            {
                int anchorTableOffset = Table.GetUShort(offset + offsetAnchorArray +
                                                        (BaseIndex*MarkClassCount + MarkClass) * 
                                                        sizeAnchorOffset
                                                       ); 
                if (anchorTableOffset == 0) 
                {
                    return new AnchorTable(Table, 0); 
                }

                return new AnchorTable(Table, offset + anchorTableOffset);
            } 

            public BaseArray(int Offset)  { offset = Offset; } 
            private int offset; 
        }
#endregion 

        public unsafe bool Apply(
            IOpenTypeFont   Font,
            FontTable       Table, 
            LayoutMetrics   Metrics,        // LayoutMetrics
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs 
            ushort          LookupFlags,    // Lookup flags for glyph lookups 
            int*            Advances,       // Glyph adv.widths
            LayoutOffset*   Offsets,        // Glyph offsets 
            int             FirstGlyph,     // where to apply lookup
            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; //Always move to the next glyph, whether matched or not 

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

            int glyphCount=GlyphInfo.Length; 

            int markGlyph=FirstGlyph; 
 
            //Lookup works with marks only
            if ((GlyphInfo.GlyphFlags[markGlyph]&(ushort)GlyphFlags.GlyphTypeMask)!=(ushort)GlyphFlags.Mark) return false; 

            int markCoverageIndex = MarkCoverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[markGlyph]);
            if (markCoverageIndex==-1) return false;
 
            //Find preceeding base (precisely, not mark ). Uses special lookup flag
            int baseGlyph = LayoutEngine.GetNextGlyphInLookup(Font, 
                                                              GlyphInfo, 
                                                              FirstGlyph - 1,
                                                              LayoutEngine.LookupFlagFindBase, 
                                                              LayoutEngine.LookBackward);
            if (baseGlyph<0) return false;

            int baseCoverageIndex = BaseCoverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[baseGlyph]); 
            if (baseCoverageIndex == -1) return false;
 
            ushort classCount = ClassCount(Table); 
            MarkArray marks = Marks(Table);
 
            ushort markClass = marks.Class(Table,(ushort)markCoverageIndex);
            if (markClass>=classCount) return false; //Invalid mark class

            AnchorTable markAnchor = marks.MarkAnchor(Table,(ushort)markCoverageIndex); 
            if (markAnchor.IsNull())
            { 
                return false; 
            }
 
            AnchorTable baseAnchor = Bases(Table).BaseAnchor(Table,(ushort)baseCoverageIndex,classCount,markClass);
            if (baseAnchor.IsNull())
            {
                return false; 
            }
 
            Positioning.AlignAnchors(Font,Table,Metrics,GlyphInfo,Advances,Offsets, 
                                        baseGlyph,markGlyph,baseAnchor,markAnchor,false);
            return true; 
        }

        public bool IsLookupCovered(
                        FontTable table, 
                        uint[] glyphBits,
                        ushort minGlyphId, 
                        ushort maxGlyphId) 
        {
            // 
            return false;
        }

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

        public MarkToBasePositioningSubtable(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 MarkToMarkPositioningSubtable 
    {
        private const int offsetFormat = 0;
        private const int offsetCoverage = 2;
        private const int offsetMark2Coverage = 4; 
        private const int offsetClassCount = 6;
        private const int offsetMark1Array = 8; 
        private const int offsetMark2Array = 10; 

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

        private ushort Mark1ClassCount(FontTable Table) 
        { 
            return Table.GetUShort(offset + offsetClassCount);
        } 

        private MarkArray Mark1Array(FontTable Table)
        {
            return new MarkArray(offset + Table.GetUShort(offset + offsetMark1Array)); 
        }
 
        private Mark2Array Marks2(FontTable Table) 
        {
            return new Mark2Array(offset + Table.GetUShort(offset + offsetMark2Array)); 
        }

#region Mark to mark positioning child 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 Mark2Array 
        {
            private const int offsetCount = 0;
            private const int offsetAnchors = 2;
            private const int sizeAnchorOffset = 2; 

            public AnchorTable Anchor(FontTable Table, 
                ushort Mark2Index, 
                ushort Mark1ClassCount,
                ushort Mark1Class) 
            {
                int anchorTableOffset = Table.GetUShort(offset + offsetAnchors +
                                                        (Mark2Index*Mark1ClassCount+Mark1Class) *
                                                        sizeAnchorOffset 
                                                       );
                if (anchorTableOffset == 0) 
                { 
                    return new AnchorTable(Table, 0);
                } 

                return new AnchorTable(Table, offset + anchorTableOffset);
            }
#endregion 

            public Mark2Array(int Offset)  { offset = Offset; } 
            private int offset; 
        }
 
        public unsafe bool Apply(
            IOpenTypeFont   Font,
            FontTable       Table,
            LayoutMetrics   Metrics,        // LayoutMetrics 
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs
            ushort          LookupFlags,    // Lookup flags for glyph lookups 
            int*            Advances,       // Glyph adv.widths 
            LayoutOffset*   Offsets,        // Glyph offsets
            int             FirstGlyph,     // where to apply lookup 
            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; //Always move to the next glyph, whether matched or not
 
            if (Format(Table) != 1) return false; //unknown format

            int glyphCount=GlyphInfo.Length;
 
            int mark1Glyph=FirstGlyph;
 
            //Lookup works with marks only 
            if ((GlyphInfo.GlyphFlags[mark1Glyph]&(ushort)GlyphFlags.GlyphTypeMask)!=(ushort)GlyphFlags.Mark) return false;
 
            int mark1CoverageIndex = Mark1Coverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[mark1Glyph]);
            if (mark1CoverageIndex==-1) return false;

            //Find preceeding mark according mark from specified class 
            int mark2Glyph = LayoutEngine.GetNextGlyphInLookup(Font,
                GlyphInfo, 
                FirstGlyph-1, 
                (ushort)(LookupFlags & 0xFF00), //Clear Ignore... flags
                LayoutEngine.LookBackward); 
            if (mark2Glyph<0) return false;

            int mark2CoverageIndex = Mark2Coverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[mark2Glyph]);
            if (mark2CoverageIndex==-1) return false; 

            ushort classCount = Mark1ClassCount(Table); 
            MarkArray mark1Array = Mark1Array(Table); 

            ushort mark1Class = mark1Array.Class(Table,(ushort)mark1CoverageIndex); 
            if (mark1Class>=classCount) return false; //Invalid mark class

            AnchorTable mark1Anchor = mark1Array.MarkAnchor(Table,(ushort)mark1CoverageIndex);
            if (mark1Anchor.IsNull()) 
            {
                return false; 
            } 

            AnchorTable mark2Anchor = Marks2(Table).Anchor(Table,(ushort)mark2CoverageIndex,classCount,mark1Class); 
            if (mark2Anchor.IsNull())
            {
                return false;
            } 

            Positioning.AlignAnchors(Font,Table,Metrics,GlyphInfo,Advances,Offsets, 
                mark2Glyph,mark1Glyph,mark2Anchor,mark1Anchor,false); 
            return true;
        } 

        public bool IsLookupCovered(
                        FontTable table,
                        uint[] glyphBits, 
                        ushort minGlyphId,
                        ushort maxGlyphId) 
        { 
            //
            return false; 
        }

        public CoverageTable GetPrimaryCoverage(FontTable table)
        { 
            return Mark1Coverage(table);
        } 
 
        public MarkToMarkPositioningSubtable(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 CursivePositioningSubtable
    { 
        private const ushort offsetFormat = 0;
        private const ushort offsetCoverage = 2;
        private const ushort offsetEntryExitCount = 4;
        private const ushort offsetEntryExitArray = 6; 
        private const ushort sizeEntryExitRecord = 4;
        private const ushort offsetEntryAnchor = 0; 
        private const ushort offsetExitAnchor = 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 EntryExitCount(FontTable Table)
        //{ 
        //    return Table.GetUShort(offsetEntryExitCount);
        //} 
 
        private AnchorTable EntryAnchor(FontTable Table, int Index)
        { 
            int anchorTableOffset = Table.GetUShort(offset +
                                                        offsetEntryExitArray +
                                                        sizeEntryExitRecord * Index +
                                                        offsetEntryAnchor); 
            if (anchorTableOffset == 0) return new AnchorTable(Table,0);
 
            return new AnchorTable(Table, offset + anchorTableOffset); 
        }
 
        private AnchorTable ExitAnchor(FontTable Table, int Index)
        {
            int anchorTableOffset = Table.GetUShort(offset +
                                                        offsetEntryExitArray + 
                                                        sizeEntryExitRecord * Index +
                                                        offsetExitAnchor); 
            if (anchorTableOffset == 0) return new AnchorTable(Table,0); 

            return new AnchorTable(Table, offset + anchorTableOffset); 
        }

        public unsafe bool Apply(
            IOpenTypeFont   Font, 
            FontTable       Table,
            LayoutMetrics   Metrics,        // LayoutMetrics 
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs 
            ushort          LookupFlags,    // Lookup flags for glyph lookups
            int*            Advances,       // Glyph adv.widths 
            LayoutOffset*   Offsets,        // Glyph offsets
            int             FirstGlyph,     // where to apply lookup
            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;

            if (Format(Table) != 1) return false; // Unknown format
 
            bool RTL = (LookupFlags & LayoutEngine.LookupFlagRightToLeft) != 0;
            ushort cursiveBit = (ushort)GlyphFlags.CursiveConnected; 
 
            //
 



            int glyphIndex, prevGlyphIndex, 
                coverageIndex, prevCoverageIndex;
 
            glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo, 
                                                               FirstGlyph,LookupFlags,
                                                               LayoutEngine.LookForward 
                                                           );

            //clear "CursiveConected" bit,
            //we will set it only if there is a connection to previous glyph 
            if (RTL)
            { 
                GlyphInfo.GlyphFlags[glyphIndex] &= (ushort)~cursiveBit; 
            }
 
            if ( glyphIndex >= AfterLastGlyph )
            {
                return false;
            } 

            prevGlyphIndex = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo, 
                                                               FirstGlyph-1,LookupFlags, 
                                                               LayoutEngine.LookBackward
                                                              ); 
            if ( prevGlyphIndex < 0 )
            {
                return false;
            } 

            CoverageTable coverage = Coverage(Table); 
 
            coverageIndex = coverage.GetGlyphIndex(Table,GlyphInfo.Glyphs[glyphIndex]);
            if (coverageIndex == -1) 
            {
                return false;
            }
 
            prevCoverageIndex = coverage.
                                   GetGlyphIndex(Table,GlyphInfo.Glyphs[prevGlyphIndex]); 
            if (prevCoverageIndex == -1) 
            {
                return false; 
            }

            AnchorTable prevExitAnchor, entryAnchor;
 
            prevExitAnchor = ExitAnchor(Table, prevCoverageIndex);
            if (prevExitAnchor.IsNull()) 
            { 
                return false;
            } 

            entryAnchor = EntryAnchor(Table,coverageIndex);
            if (entryAnchor.IsNull())
            { 
                return false;
            } 
 
            Positioning.AlignAnchors(Font, Table, Metrics,
                                     GlyphInfo, Advances, Offsets, 
                                     prevGlyphIndex, glyphIndex,
                                     prevExitAnchor, entryAnchor, true);

            if (RTL) 
            {
                UshortList glyphFlags = GlyphInfo.GlyphFlags; 
 
                int index;
 
                //set "cursive" bit for everything up to prevGlyphIndex
                for(index = glyphIndex; index>prevGlyphIndex; index--)
                {
                    glyphFlags[index] |= cursiveBit; 
                }
 
                //fix cursive dependencies 
                int yCorrection = Offsets[glyphIndex].dy;
                for(index = glyphIndex; 
                    (glyphFlags[index] & cursiveBit) != 0 ;
                    index--
                   )
                { 
                    Offsets[index].dy -= yCorrection;
                } 
                Invariant.Assert(glyphIndex>=0); //First glyph should not have bit set 
                Offsets[index].dy  -= yCorrection;
            } 

            return true;
        }
 
        public bool IsLookupCovered(
                        FontTable table, 
                        uint[] glyphBits, 
                        ushort minGlyphId,
                        ushort maxGlyphId) 
        {
            //
            return true;
        } 

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

        public CursivePositioningSubtable(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 LigatureAttachTable
    {
        private const int offsetAnchorArray = 2; 
        private const int sizeAnchorOffset = 2;
 
        public AnchorTable LigatureAnchor(FontTable Table, 
                                          ushort Component,
                                          ushort MarkClass) 
        {
            int anchorTableOffset = Table.GetUShort(offset + offsetAnchorArray +
                                                    (Component*classCount + MarkClass) *
                                                                      sizeAnchorOffset); 
            if (anchorTableOffset == 0)
            { 
                return new AnchorTable(Table, 0); 
            }
 
            return new AnchorTable(Table, offset + anchorTableOffset);
        }

        public LigatureAttachTable(int Offset,ushort ClassCount) 
        {
            offset = Offset; 
            classCount = ClassCount; 
        }
 
        private int offset;
        private int classCount;
    }
 
    /// 
    /// 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 MarkToLigaturePositioningSubtable
    {
        private const int offsetFormat = 0;
        private const int offsetMarkCoverage = 2; 
        private const int offsetLigatureCoverage = 4;
        private const int offsetClassCount = 6; 
        private const int offsetMarkArray = 8; 
        private const int offsetLigatureArray = 10;
        private const int offsetLigatureAttachArray = 2; 
        private const int sizeOffset = 2;

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

        private CoverageTable LigatureCoverage(FontTable Table) 
        {
            return new CoverageTable(offset + Table.GetUShort(offset + offsetLigatureCoverage)); 
        } 

        private ushort ClassCount(FontTable Table) 
        {
            return Table.GetUShort(offset + offsetClassCount);
        }
 
        private MarkArray Marks(FontTable Table)
        { 
            return new MarkArray(offset + Table.GetUShort(offset + offsetMarkArray)); 
        }
 
        private LigatureAttachTable Ligatures(FontTable Table, int Index, ushort ClassCount)
        {
            int offsetLigatureArrayTable = offset + Table.GetUShort(offset + offsetLigatureArray);
            return new LigatureAttachTable(offsetLigatureArrayTable + 
                                           Table.GetUShort(offsetLigatureArrayTable +
                                                           offsetLigatureAttachArray + 
                                                           Index * sizeOffset), 
                                           ClassCount
                                          ); 
        }

        // Find base ligature and component corresponding to the mark
        private unsafe void FindBaseLigature ( 
            int             CharCount,
            UshortList      Charmap, 
            GlyphInfoList   GlyphInfo, 
            int             markGlyph,
            out ushort      component, 
            out int         ligatureGlyph
           )
        {
            int ligatureChar = 0; 
            ligatureGlyph = -1;
            component = 0; 
 
            bool FoundBase = false;
            for (int ch = GlyphInfo.FirstChars[markGlyph]; 
                        ch >= 0 && !FoundBase; ch--)
            {
                ushort glyph = Charmap[ch];
                if ((GlyphInfo.GlyphFlags[glyph] & (ushort)GlyphFlags.GlyphTypeMask) != 
                                                                    (ushort)GlyphFlags.Mark)
                { 
                    ligatureChar = ch; 
                    ligatureGlyph = glyph;
                    FoundBase = true; 
                }
            }
            if (!FoundBase) return;
 
            ushort comp = 0;
            for(ushort ch = GlyphInfo.FirstChars[ligatureGlyph]; 
                ch=0);
            Invariant.Assert(AfterLastGlyph<=GlyphInfo.Length); 

            NextGlyph = FirstGlyph+1; //Always move to the next glyph, whether matched or not 
 
            if (Format(Table) != 1) return false; //unknown format
 
            int glyphCount=GlyphInfo.Length;
            int markGlyph=FirstGlyph;

            //Lookup works with marks only 
            if ((GlyphInfo.GlyphFlags[markGlyph]&(ushort)GlyphFlags.GlyphTypeMask)!=(ushort)GlyphFlags.Mark) return false;
 
            int markCoverageIndex = MarkCoverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[markGlyph]); 
            if (markCoverageIndex==-1) return false;
 
            int baseGlyph;
            ushort component;

            FindBaseLigature(CharCount, Charmap,GlyphInfo,markGlyph, 
                                                out component, out baseGlyph);
            if (baseGlyph<0) return false; 
 
            int baseCoverageIndex = LigatureCoverage(Table).
                                        GetGlyphIndex(Table,GlyphInfo.Glyphs[baseGlyph]); 
            if (baseCoverageIndex == -1) return false;

            ushort classCount = ClassCount(Table);
            MarkArray marks = Marks(Table); 

            ushort markClass = marks.Class(Table,(ushort)markCoverageIndex); 
            if (markClass>=classCount) return false; //Invalid mark class 

            AnchorTable baseAnchor = Ligatures(Table,baseCoverageIndex, classCount). 
                                            LigatureAnchor(Table,component,markClass);
            if (baseAnchor.IsNull())
            {
                return false; 
            }
 
            AnchorTable markAnchor = marks.MarkAnchor(Table,(ushort)markCoverageIndex); 
            if (markAnchor.IsNull())
            { 
                return false;
            }

            Positioning.AlignAnchors(Font,Table,Metrics,GlyphInfo,Advances,Offsets, 
                baseGlyph,markGlyph,baseAnchor,markAnchor,false);
 
            return true; 
        }
 
        public bool IsLookupCovered(
                        FontTable table,
                        uint[] glyphBits,
                        ushort minGlyphId, 
                        ushort maxGlyphId)
        { 
            // 
            return false;
        } 

        public CoverageTable GetPrimaryCoverage(FontTable table)
        {
            return MarkCoverage(table); 
        }
 
        public MarkToLigaturePositioningSubtable(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