public bool Apply(
                            FontTable          Table,
                            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs
                            int             FirstGlyph,     // where to apply it
                            out int         NextGlyph       // Next glyph to process
                         )
        {
            Invariant.Assert(FirstGlyph >= 0);
        
            NextGlyph = FirstGlyph + 1; //In case we don't match;
                
            ushort GlyphId = GlyphInfo.Glyphs[FirstGlyph];
            int CoverageIndex = Coverage(Table).GetGlyphIndex(Table,GlyphId);
            if (CoverageIndex == -1) return false;
            
            switch(Format(Table))
            {
                case 1:
                    GlyphInfo.Glyphs[FirstGlyph] = (ushort)(GlyphId + Format1DeltaGlyphId(Table));
                    GlyphInfo.GlyphFlags[FirstGlyph] = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                    NextGlyph = FirstGlyph + 1;
                    return true;

                case 2:
                    GlyphInfo.Glyphs[FirstGlyph] = Format2SubstituteGlyphId(Table,(ushort)CoverageIndex);
                    GlyphInfo.GlyphFlags[FirstGlyph] = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                    NextGlyph = FirstGlyph + 1;
                    return true;

                default:
                    NextGlyph = FirstGlyph+1;
                    return false;
            }
        }
Beispiel #2
0
        public bool Apply(
                            FontTable          Table,
                            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs
                            int             FirstGlyph,     // where to apply it
                            out int         NextGlyph       // Next glyph to process
                         )
        {
            Invariant.Assert(FirstGlyph >= 0);
        
            NextGlyph = FirstGlyph + 1; //In case we don't match;
                
            ushort GlyphId = GlyphInfo.Glyphs[FirstGlyph];
            int CoverageIndex = Coverage(Table).GetGlyphIndex(Table,GlyphId);
            if (CoverageIndex == -1) return false;
            
            switch(Format(Table))
            {
                case 1:
                    GlyphInfo.Glyphs[FirstGlyph] = (ushort)(GlyphId + Format1DeltaGlyphId(Table));
                    GlyphInfo.GlyphFlags[FirstGlyph] = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                    NextGlyph = FirstGlyph + 1;
                    return true;

                case 2:
                    GlyphInfo.Glyphs[FirstGlyph] = Format2SubstituteGlyphId(Table,(ushort)CoverageIndex);
                    GlyphInfo.GlyphFlags[FirstGlyph] = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                    NextGlyph = FirstGlyph + 1;
                    return true;

                default:
                    NextGlyph = FirstGlyph+1;
                    return false;
            }
        }
        public unsafe bool Apply(
            FontTable       Table,
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo
            uint            FeatureParam,   // For this lookup - index of glyph alternate
            int             FirstGlyph,     // where to apply it
            out int         NextGlyph       // Next glyph to process
            )
        {
            NextGlyph = FirstGlyph + 1; // always move one glyph forward, 
                                        // doesn't matter whether we matched context
                                        
            if (Format(Table) != 1) return false; //Unknown format
            
            int oldGlyphCount=GlyphInfo.Length;
            
            int coverageIndex = Coverage(Table).
                                    GetGlyphIndex(Table,GlyphInfo.Glyphs[FirstGlyph]);
            if (coverageIndex==-1) return false;
            
            AlternateSetTable alternateSet = AlternateSet(Table,coverageIndex);
            
            ushort alternateGlyph = alternateSet.Alternate(Table, FeatureParam);

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

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

        private AlternateSetTable AlternateSet(FontTable Table, int index)
        {
            return(new AlternateSetTable(offset +
                                         Table.GetUShort(offset +
                                                         offsetAlternateSets +
                                                         index * sizeAlternateSetOffset)
                                         ));
        }
Beispiel #5
0
        // Not used. This value should be equal to glyph count in Coverage.
        // Keeping it for future reference
        //private ushort SequenceCount(FontTable Table)
        //{
        //    return Table.GetUShort(offset + offsetSequenceCount);
        //}

        private MultipleSubstitutionSequenceTable Sequence(FontTable Table, int Index)
        {
            return(new MultipleSubstitutionSequenceTable(
                       offset +
                       Table.GetUShort(offset +
                                       offsetSequenceArray +
                                       Index * sizeSequenceOffset)
                       ));
        }
Beispiel #6
0
 public bool IsLookupCovered(
     FontTable table,
     uint[] glyphBits,
     ushort minGlyphId,
     ushort maxGlyphId)
 {
     return(Coverage(table).IsAnyGlyphCovered(table,
                                              glyphBits,
                                              minGlyphId,
                                              maxGlyphId
                                              ));
 }
Beispiel #7
0
        public bool IsLookupCovered(
            FontTable table,
            uint[] glyphBits,
            ushort minGlyphId,
            ushort maxGlyphId)
        {
            if (!Coverage(table).IsAnyGlyphCovered(table,
                                                   glyphBits,
                                                   minGlyphId,
                                                   maxGlyphId
                                                   )
                )
            {
                return(false);
            }

            ushort ligatureSetCount = LigatureSetCount(table);

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

                for (ushort liga = 0; liga < ligaCount; liga++)
                {
                    LigatureTable ligature  = ligatureSet.Ligature(table, liga);
                    ushort        compCount = ligature.ComponentCount(table);

                    bool ligatureIsComplex = true;

                    for (ushort compIndex = 1; compIndex < compCount; compIndex++)
                    {
                        ushort glyphId = ligature.Component(table, compIndex);

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

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

            return(false);
        }
        private static bool AppendCoverageGlyphRecords(
            FontTable table,
            ushort lookupIndex,
            CoverageTable coverage,
            GlyphLookupRecord[] records,
            ref int recordCount,
            ref int maxLookupGlyph
            )
        {
            switch (coverage.Format(table))
            {
            case 1:
                ushort glyphCount = coverage.Format1GlyphCount(table);

                for (ushort i = 0; i < glyphCount; i++)
                {
                    ushort glyph = coverage.Format1Glyph(table, i);

                    if (!AppendGlyphRecord(glyph, lookupIndex, records, ref recordCount, ref maxLookupGlyph))
                    {
                        // We've failed to add another record.
                        return(false);
                    }
                }

                break;

            case 2:

                ushort rangeCount = coverage.Format2RangeCount(table);

                for (ushort i = 0; i < rangeCount; i++)
                {
                    ushort firstGlyph = coverage.Format2RangeStartGlyph(table, i);
                    ushort lastGlyph  = coverage.Format2RangeEndGlyph(table, i);

                    for (int glyph = firstGlyph; glyph <= lastGlyph; glyph++)
                    {
                        if (!AppendGlyphRecord((ushort)glyph, lookupIndex, records, ref recordCount, ref maxLookupGlyph))
                        {
                            // We've failed to add another record.
                            return(false);
                        }
                    }
                }

                break;
            }

            return(true);
        }
Beispiel #9
0
            public ushort Alternate(FontTable Table, uint FeatureParam)
            {
                Invariant.Assert(FeatureParam > 0); // Parameter 0 means feautre is disabled.
                //Should be filtered out in GetNextEnabledGlyphRange

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

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

                return(Table.GetUShort(offset + offsetGlyphs + (ushort)index * sizeGlyph));
            }
Beispiel #10
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="Font">Font</param>
        /// <param name="ScriptTag">Script to search in</param>
        /// <param name="LangSysTag">LangGys to search for</param>
        /// <returns>TagInfoFlags, if script not present == None</returns>
        internal static TagInfoFlags FindLangSys(
            IOpenTypeFont Font,
            uint ScriptTag,
            uint LangSysTag
            )
        {
            TagInfoFlags flags = TagInfoFlags.None;

            try
            {
                FontTable gsubTable = Font.GetFontTable(OpenTypeTags.GSUB);
                if (gsubTable.IsPresent)
                {
                    GSUBHeader  gsubHeader = new GSUBHeader(0);
                    ScriptTable gsubScript = gsubHeader.GetScriptList(gsubTable).FindScript(gsubTable, ScriptTag);
                    if (!gsubScript.IsNull && !gsubScript.FindLangSys(gsubTable, LangSysTag).IsNull)
                    {
                        flags |= TagInfoFlags.Substitution;
                    }
                }
            }
            catch (FileFormatException)
            {
                return(TagInfoFlags.None);
            }

            try
            {
                FontTable gposTable = Font.GetFontTable(OpenTypeTags.GPOS);
                if (gposTable.IsPresent)
                {
                    GPOSHeader  gposHeader = new GPOSHeader(0);
                    ScriptTable gposScript = gposHeader.GetScriptList(gposTable).FindScript(gposTable, ScriptTag);
                    if (!gposScript.IsNull && !gposScript.FindLangSys(gposTable, LangSysTag).IsNull)
                    {
                        flags |= TagInfoFlags.Positioning;
                    }
                }
            }
            catch (FileFormatException)
            {
                return(TagInfoFlags.None);
            }

            return(flags);
        }
Beispiel #11
0
 public ushort ComponentCount(FontTable Table)
 {
     return Table.GetUShort(offset + offsetComponentCount);
 }
Beispiel #12
0
 private LigatureSetTable LigatureSet(FontTable Table, ushort Index)
 {
     return new LigatureSetTable(offset+Table.GetUShort(offset+
                                                        offsetLigatureSetArray + 
                                                        Index * sizeLigatureSet));
 }
Beispiel #13
0
 public LigatureTable Ligature(FontTable Table, ushort Index)
 {
     return new LigatureTable(offset + Table.GetUShort(offset + 
         offsetLigatureArray + 
         Index * sizeLigatureOffset));
 }
Beispiel #14
0
 public ushort ComponentCount(FontTable Table)
 {
     return(Table.GetUShort(offset + offsetComponentCount));
 }
Beispiel #15
0
        /// <summary>
        /// Position glyphs according to features defined in the font.
        /// </summary>
        /// <param name="Font">In: Font access interface</param>
        /// <param name="workspace">In: Workspace for layout engine</param>
        /// <param name="ScriptTag">In: Script tag</param>
        /// <param name="LangSysTag">In: LangSys tag</param>
        /// <param name="Metrics">In: LayoutMetrics</param>
        /// <param name="FeatureSet">In: List of features to apply</param>
        /// <param name="featureCount">In: Actual number of features in <paramref name="FeatureSet"/></param>
        /// <param name="featureSetOffset">In: offset of input characters inside FeatureSet</param>
        /// <param name="CharCount">In: Characters count (i.e. <paramref name="Charmap"/>.Length);</param>
        /// <param name="Charmap">In: Char to glyph mapping</param>
        /// <param name="Glyphs">In/out: List of GlyphInfo structs</param>
        /// <param name="Advances">In/out: Glyphs adv.widths</param>
        /// <param name="Offsets">In/out: Glyph offsets</param>
        /// <returns>Substitution result</returns>
        internal static OpenTypeLayoutResult PositionGlyphs(
            IOpenTypeFont Font,
            OpenTypeLayoutWorkspace workspace,
            uint ScriptTag,
            uint LangSysTag,
            LayoutMetrics Metrics,
            Feature[]               FeatureSet,
            int featureCount,
            int featureSetOffset,
            int CharCount,
            UshortList Charmap,
            GlyphInfoList Glyphs,
            int *Advances,
            LayoutOffset *Offsets
            )
        {
            try
            {
                FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS);
                if (!GposTable.IsPresent)
                {
                    return(OpenTypeLayoutResult.ScriptNotFound);
                }

                GPOSHeader GposHeader = new GPOSHeader(0);
                ScriptList ScriptList = GposHeader.GetScriptList(GposTable);

                ScriptTable Script = ScriptList.FindScript(GposTable, ScriptTag);
                if (Script.IsNull)
                {
                    return(OpenTypeLayoutResult.ScriptNotFound);
                }

                LangSysTable LangSys = Script.FindLangSys(GposTable, LangSysTag);
                if (LangSys.IsNull)
                {
                    return(OpenTypeLayoutResult.LangSysNotFound);
                }

                FeatureList FeatureList = GposHeader.GetFeatureList(GposTable);
                LookupList  LookupList  = GposHeader.GetLookupList(GposTable);

                LayoutEngine.ApplyFeatures(
                    Font,
                    workspace,
                    OpenTypeTags.GPOS,
                    GposTable,
                    Metrics,
                    LangSys,
                    FeatureList,
                    LookupList,
                    FeatureSet,
                    featureCount,
                    featureSetOffset,
                    CharCount,
                    Charmap,
                    Glyphs,
                    Advances,
                    Offsets
                    );
            }
            catch (FileFormatException)
            {
                return(OpenTypeLayoutResult.BadFontTable);
            }

            return(OpenTypeLayoutResult.Success);
        }
Beispiel #16
0
 // Not used. This value should be equal to glyph count in Coverage.
 // Keeping it for future reference
 //private ushort SequenceCount(FontTable Table)
 //{
 //    return Table.GetUShort(offset + offsetSequenceCount);
 //}
 
 private MultipleSubstitutionSequenceTable Sequence(FontTable Table, int Index)
 {
     return new MultipleSubstitutionSequenceTable(
                                 offset + 
                                 Table.GetUShort(offset +
                                                 offsetSequenceArray +
                                                 Index * sizeSequenceOffset)
                                );
 }
Beispiel #17
0
 // Not used. This value should be equal to glyph count in Coverage.
 // Keeping it for future reference
 //private ushort Foramt2GlyphCount(FontTable Table)
 //{
 //    Debug.Assert(Format(Table)==2);
 //    return Table.GetUShort(offset + offsetFormat2GlyphCount);
 //}       
 private ushort Format2SubstituteGlyphId(FontTable Table,ushort Index)
 {
     Invariant.Assert(Format(Table)==2);
     return Table.GetUShort(offset + offsetFormat2SubstitutehArray + 
                                     Index * sizeFormat2SubstituteSize);
 }
Beispiel #18
0
 private CoverageTable Coverage(FontTable Table)
 {
     return(new CoverageTable(offset + Table.GetUShort(offset + offsetCoverage)));
 }
Beispiel #19
0
 public LigatureTable Ligature(FontTable Table, ushort Index)
 {
     return(new LigatureTable(offset + Table.GetUShort(offset +
                                                       offsetLigatureArray +
                                                       Index * sizeLigatureOffset)));
 }
Beispiel #20
0
        public unsafe bool Apply(
            IOpenTypeFont Font,
            FontTable Table,
            int CharCount,
            UshortList Charmap,             // Character to glyph map
            GlyphInfoList GlyphInfo,        // List of GlyphInfo
            ushort LookupFlags,             // Lookup flags for glyph lookups
            int FirstGlyph,                 // where to apply it
            int AfterLastGlyph,             // how long is a context we can use
            out int NextGlyph               // Next glyph to process
            )
        {
            NextGlyph = FirstGlyph + 1; // in case we don't match

            if (Format(Table) != 1)
            {
                return(false);                    //unknown format
            }
            int oldGlyphCount = GlyphInfo.Length;

            ushort glyphId       = GlyphInfo.Glyphs[FirstGlyph];
            int    coverageIndex = Coverage(Table).GetGlyphIndex(Table, glyphId);

            if (coverageIndex == -1)
            {
                return(false);
            }

            MultipleSubstitutionSequenceTable sequence = Sequence(Table, coverageIndex);

            ushort sequenceLength = sequence.GlyphCount(Table);
            int    lengthDelta    = sequenceLength - 1;

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

                if (lengthDelta > 0)
                {
                    GlyphInfo.Insert(FirstGlyph, lengthDelta);
                }

                //put glyphs in place
                for (ushort gl = 0; gl < sequenceLength; gl++)
                {
                    GlyphInfo.Glyphs[FirstGlyph + gl]     = sequence.Glyph(Table, gl);
                    GlyphInfo.GlyphFlags[FirstGlyph + gl] =
                        (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                    GlyphInfo.FirstChars[FirstGlyph + gl]     = firstChar;
                    GlyphInfo.LigatureCounts[FirstGlyph + gl] = ligatureCount;
                }
            }

            // Fix char mapping - very simple for now.
            // Works only for arabic base+mark -> base and marks decomposition
            // Needs work for full mapping
            for (int ch = 0; ch < CharCount; ch++)
            {
                if (Charmap[ch] > FirstGlyph)
                {
                    Charmap[ch] = (ushort)(Charmap[ch] + lengthDelta);
                }
            }

            NextGlyph = FirstGlyph + lengthDelta + 1;

            return(true);
        }
Beispiel #21
0
 public ushort Format(FontTable Table)
 {
     return(Table.GetUShort(offset + offsetFormat));
 }
Beispiel #22
0
 // Not used. This value should be equal to glyph count in Coverage.
 // Keeping it for future reference
 //private ushort Foramt2GlyphCount(FontTable Table)
 //{
 //    Debug.Assert(Format(Table)==2);
 //    return Table.GetUShort(offset + offsetFormat2GlyphCount);
 //}
 private ushort Format2SubstituteGlyphId(FontTable Table, ushort Index)
 {
     Invariant.Assert(Format(Table) == 2);
     return(Table.GetUShort(offset + offsetFormat2SubstitutehArray +
                            Index * sizeFormat2SubstituteSize));
 }
Beispiel #23
0
 public ushort LigatureGlyph(FontTable Table)
 {
     return(Table.GetUShort(offset + offsetLigatureGlyph));
 }
Beispiel #24
0
 public ushort Glyph(FontTable Table, ushort index)
 {
     return(Table.GetUShort(offset + offsetGlyphArray + index * sizeGlyphId));
 }
Beispiel #25
0
        public unsafe bool Apply(
                            IOpenTypeFont   Font,
                            FontTable       Table,
                            int             CharCount,
                            UshortList      Charmap,        // Character to glyph map
                            GlyphInfoList   GlyphInfo,      // List of GlyphInfo
                            ushort          LookupFlags,    // Lookup flags for glyph lookups
                            int             FirstGlyph,     // where to apply it
                            int             AfterLastGlyph, // how long is a context we can use
                            out int         NextGlyph       // Next glyph to process
                          )
        {
            Invariant.Assert(FirstGlyph>=0);
            Invariant.Assert(AfterLastGlyph<=GlyphInfo.Length);

            NextGlyph = FirstGlyph + 1; //In case we don't match;
            
            if (Format(Table) != 1) return false; // Unknown format
                
            int glyphCount=GlyphInfo.Length;
            ushort glyphId = GlyphInfo.Glyphs[FirstGlyph];
            int CoverageIndex = Coverage(Table).GetGlyphIndex(Table,glyphId);
            if (CoverageIndex==-1) return false;

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

            LigatureSetTable ligatureSet = LigatureSet(Table,(ushort)CoverageIndex);
            ushort ligaCount = ligatureSet.LigatureCount(Table);
            for(ushort liga=0; liga<ligaCount; liga++)
            {
                LigatureTable ligature = ligatureSet.Ligature(Table,liga);
                compCount = ligature.ComponentCount(Table);
                if (compCount == 0)
                {
                    throw new FileFormatException();
                }
                
                curGlyph=FirstGlyph;
                ushort comp=1;
                for(comp=1;comp<compCount;comp++)
                {
                    curGlyph = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo,curGlyph+1,LookupFlags,LayoutEngine.LookForward);
                    if (curGlyph>=AfterLastGlyph) break;
                    
                    if (GlyphInfo.Glyphs[curGlyph]!=ligature.Component(Table,comp)) break;
                }
                
                if (comp==compCount) //liga matched
                {
                    match=true;
                    ligatureGlyph = ligature.LigatureGlyph(Table);
                    break; //Liga found
                }
            }
            //If no ligature found, match will remain false after last iteration
            
            if (match) 
            {
                //Fix character and glyph Mapping
            
                //PERF: localize ligature character range
                    
                //Calculate Ligature CharCount
                int totalLigaCharCount=0;
                int firstLigaChar=int.MaxValue;
                curGlyph=FirstGlyph;
                for(ushort comp=0;comp<compCount;comp++)
                {
                    Invariant.Assert(curGlyph<AfterLastGlyph);
                    
                    int curFirstChar = GlyphInfo.FirstChars[curGlyph];
                    int curLigaCount = GlyphInfo.LigatureCounts[curGlyph];
                    
                    totalLigaCharCount += curLigaCount;
                    if (curFirstChar<firstLigaChar) firstLigaChar=curFirstChar;
                    
                    curGlyph = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo,curGlyph+1,LookupFlags,LayoutEngine.LookForward);
                }
                    
                curGlyph=FirstGlyph;
                int prevGlyph=FirstGlyph;
                ushort shift=0;
                for(ushort comp=1;comp<=compCount;comp++)
                {
                    prevGlyph=curGlyph;
                    
                    if (comp<compCount)
                    {
                        curGlyph = LayoutEngine.
                                        GetNextGlyphInLookup(Font,GlyphInfo,
                                                             curGlyph+1,
                                                             LookupFlags,
                                                             LayoutEngine.LookForward);
                    }
                    else curGlyph = GlyphInfo.Length; // to the end from last component
                    
                    // Set charmap for ligature component
                    for(int curChar=0; curChar<CharCount; curChar++)
                    {
                        if (Charmap[curChar]==prevGlyph)
                        {
                            Charmap[curChar] = (ushort)FirstGlyph;
                        }
                    }

                    //Shift glyphInfo
                    if (shift>0)
                    {
                        for(int glyph=prevGlyph+1; glyph<curGlyph; glyph++)
                        {
                            GlyphInfo.Glyphs[glyph-shift]         = GlyphInfo.Glyphs[glyph];
                            GlyphInfo.GlyphFlags[glyph-shift]     = GlyphInfo.GlyphFlags[glyph];
                            GlyphInfo.FirstChars[glyph-shift]     = GlyphInfo.FirstChars[glyph];
                            GlyphInfo.LigatureCounts[glyph-shift] = GlyphInfo.LigatureCounts[glyph];
                        }
                    
                        if (curGlyph-prevGlyph>1) //do fixing only if have glyphs in between
                        {
                            for(int curChar=0; curChar<CharCount; curChar++)
                            {
                                ushort curCharmap = Charmap[curChar];
                                if (curCharmap>prevGlyph && curCharmap<curGlyph)
                                {
                                    Charmap[curChar] -= shift;
                                }
                            }
                        }
                    }
                                        
                    ++shift;
                }
                
                //Place new glyph into position of first ligature glyph
                GlyphInfo.Glyphs[FirstGlyph]         = ligatureGlyph;
                GlyphInfo.GlyphFlags[FirstGlyph]     = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                GlyphInfo.FirstChars[FirstGlyph]     = (ushort)firstLigaChar;
                GlyphInfo.LigatureCounts[FirstGlyph] = (ushort)totalLigaCharCount;
                
                //remove empty space
                if (compCount > 1)
                {
                    GlyphInfo.Remove(GlyphInfo.Length-compCount+1,compCount-1);
                }
                
                NextGlyph=prevGlyph-(compCount-1)+1;
            }
            
            return match;
        }
Beispiel #26
0
 public ushort GlyphCount(FontTable Table)
 {
     return(Table.GetUShort(offset + offsetGlyphCount));
 }
Beispiel #27
0
 public ushort Glyph(FontTable Table, ushort index)
 {
     return Table.GetUShort(offset + offsetGlyphArray + index * sizeGlyphId);
 }
Beispiel #28
0
        public unsafe bool Apply(
            FontTable       Table,
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo
            uint            FeatureParam,   // For this lookup - index of glyph alternate
            int             FirstGlyph,     // where to apply it
            out int         NextGlyph       // Next glyph to process
            )
        {
            NextGlyph = FirstGlyph + 1; // always move one glyph forward, 
                                        // doesn't matter whether we matched context
                                        
            if (Format(Table) != 1) return false; //Unknown format
            
            int oldGlyphCount=GlyphInfo.Length;
            
            int coverageIndex = Coverage(Table).
                                    GetGlyphIndex(Table,GlyphInfo.Glyphs[FirstGlyph]);
            if (coverageIndex==-1) return false;
            
            AlternateSetTable alternateSet = AlternateSet(Table,coverageIndex);
            
            ushort alternateGlyph = alternateSet.Alternate(Table, FeatureParam);

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

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

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

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

            if (CoverageIndex == -1)
            {
                return(false);
            }

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

            LigatureSetTable ligatureSet = LigatureSet(Table, (ushort)CoverageIndex);
            ushort           ligaCount   = ligatureSet.LigatureCount(Table);

            for (ushort liga = 0; liga < ligaCount; liga++)
            {
                LigatureTable ligature = ligatureSet.Ligature(Table, liga);
                compCount = ligature.ComponentCount(Table);
                if (compCount == 0)
                {
                    throw new FileFormatException();
                }

                curGlyph = FirstGlyph;
                ushort comp = 1;
                for (comp = 1; comp < compCount; comp++)
                {
                    curGlyph = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo, curGlyph + 1, LookupFlags, LayoutEngine.LookForward);
                    if (curGlyph >= AfterLastGlyph)
                    {
                        break;
                    }

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

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

            if (match)
            {
                //Fix character and glyph Mapping

                //PERF: localize ligature character range

                //Calculate Ligature CharCount
                int totalLigaCharCount = 0;
                int firstLigaChar      = int.MaxValue;
                curGlyph = FirstGlyph;
                for (ushort comp = 0; comp < compCount; comp++)
                {
                    Invariant.Assert(curGlyph < AfterLastGlyph);

                    int curFirstChar = GlyphInfo.FirstChars[curGlyph];
                    int curLigaCount = GlyphInfo.LigatureCounts[curGlyph];

                    totalLigaCharCount += curLigaCount;
                    if (curFirstChar < firstLigaChar)
                    {
                        firstLigaChar = curFirstChar;
                    }

                    curGlyph = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo, curGlyph + 1, LookupFlags, LayoutEngine.LookForward);
                }

                curGlyph = FirstGlyph;
                int    prevGlyph = FirstGlyph;
                ushort shift     = 0;
                for (ushort comp = 1; comp <= compCount; comp++)
                {
                    prevGlyph = curGlyph;

                    if (comp < compCount)
                    {
                        curGlyph = LayoutEngine.
                                   GetNextGlyphInLookup(Font, GlyphInfo,
                                                        curGlyph + 1,
                                                        LookupFlags,
                                                        LayoutEngine.LookForward);
                    }
                    else
                    {
                        curGlyph = GlyphInfo.Length;  // to the end from last component
                    }
                    // Set charmap for ligature component
                    for (int curChar = 0; curChar < CharCount; curChar++)
                    {
                        if (Charmap[curChar] == prevGlyph)
                        {
                            Charmap[curChar] = (ushort)FirstGlyph;
                        }
                    }

                    //Shift glyphInfo
                    if (shift > 0)
                    {
                        for (int glyph = prevGlyph + 1; glyph < curGlyph; glyph++)
                        {
                            GlyphInfo.Glyphs[glyph - shift]         = GlyphInfo.Glyphs[glyph];
                            GlyphInfo.GlyphFlags[glyph - shift]     = GlyphInfo.GlyphFlags[glyph];
                            GlyphInfo.FirstChars[glyph - shift]     = GlyphInfo.FirstChars[glyph];
                            GlyphInfo.LigatureCounts[glyph - shift] = GlyphInfo.LigatureCounts[glyph];
                        }

                        if (curGlyph - prevGlyph > 1) //do fixing only if have glyphs in between
                        {
                            for (int curChar = 0; curChar < CharCount; curChar++)
                            {
                                ushort curCharmap = Charmap[curChar];
                                if (curCharmap > prevGlyph && curCharmap < curGlyph)
                                {
                                    Charmap[curChar] -= shift;
                                }
                            }
                        }
                    }

                    ++shift;
                }

                //Place new glyph into position of first ligature glyph
                GlyphInfo.Glyphs[FirstGlyph]         = ligatureGlyph;
                GlyphInfo.GlyphFlags[FirstGlyph]     = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                GlyphInfo.FirstChars[FirstGlyph]     = (ushort)firstLigaChar;
                GlyphInfo.LigatureCounts[FirstGlyph] = (ushort)totalLigaCharCount;

                //remove empty space
                if (compCount > 1)
                {
                    GlyphInfo.Remove(GlyphInfo.Length - compCount + 1, compCount - 1);
                }

                NextGlyph = prevGlyph - (compCount - 1) + 1;
            }

            return(match);
        }
Beispiel #31
0
 public ushort GlyphCount(FontTable Table)
 {
     return Table.GetUShort(offset + offsetGlyphCount);
 }
Beispiel #32
0
 private short Format1DeltaGlyphId(FontTable Table)
 {
     Invariant.Assert(Format(Table) == 1);
     return(Table.GetShort(offset + offsetFormat1DeltaGlyphId));
 }
Beispiel #33
0
 public bool IsLookupCovered(
                 FontTable table, 
                 uint[] glyphBits, 
                 ushort minGlyphId, 
                 ushort maxGlyphId)
 {
     return Coverage(table).IsAnyGlyphCovered(table,
                                              glyphBits,
                                              minGlyphId,
                                              maxGlyphId
                                             );
 }
Beispiel #34
0
 public CoverageTable GetPrimaryCoverage(FontTable table)
 {
     return(Coverage(table));
 }
Beispiel #35
0
/* This is unused code, but will be used later so it is just commented out for now.
 *
 *      /// <summary>
 *      /// Enumerates scripts in a font
 *      /// </summary>
 *      internal static OpenTypeLayoutResult GetScriptList (
 *          IOpenTypeFont       Font,     // In: Font access interface
 *          out TagInfo[]       Scripts   // Out: Array of scripts supported
 *          )
 *      {
 *          ushort i;
 *          ushort GposNewTags;
 *
 *          Scripts=null; // Assignment required, because of out attribute.
 *                        // This value should be owerwritten later.
 *
 *          try
 *          {
 *              FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB);
 *              FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS);
 *
 *              GSUBHeader GsubHeader = new GSUBHeader(0);
 *              GPOSHeader GposHeader = new GPOSHeader(0);
 *
 *              ScriptList GsubScriptList;
 *              ScriptList GposScriptList;
 *              ushort GsubScriptCount;
 *              ushort GposScriptCount;
 *
 *              if (GsubTable.IsNotPresent && GposTable.IsNotPresent)
 *              {
 *                  Scripts = Array.Empty<TagInfo>();
 *                  return OpenTypeLayoutResult.Success;
 *              }
 *
 *              if (GsubTable.IsPresent)
 *              {
 *                  GsubScriptList  = GsubHeader.GetScriptList(GsubTable);
 *                  GsubScriptCount = GsubScriptList.GetScriptCount(GsubTable);
 *              }
 *              else
 *              {
 *                  GsubScriptList = new ScriptList(FontTable.InvalidOffset);
 *                  GsubScriptCount = 0;
 *              }
 *
 *              if (GposTable.IsPresent)
 *              {
 *                  GposScriptList  = GposHeader.GetScriptList(GposTable);
 *                  GposScriptCount = GposScriptList.GetScriptCount(GposTable);
 *              }
 *              else
 *              {
 *                  GposScriptList = new ScriptList(FontTable.InvalidOffset);
 *                  GposScriptCount = 0;
 *              }
 *
 *              //This is true in most cases that there is no new tags in GPOS.
 *              //So, we allocate this array then check GPOS for new tags
 *              Scripts = new TagInfo[GsubScriptCount];
 *
 *              for(i=0; i<GsubScriptCount; i++)
 *              {
 *                  Scripts[i].Tag      = GsubScriptList.GetScriptTag(GsubTable,i);
 *                  Scripts[i].TagFlags = TagInfoFlags.Substitution;
 *              }
 *
 *              //Check GPOS for tags that is not in GSUB
 *              GposNewTags=0;
 *
 *              for(i=0;i<GposScriptCount;i++)
 *              {
 *                  uint GposTag = GsubScriptList.GetScriptTag(GposTable,i);
 *                  if (TagInfo.IsNewTag(Scripts,GposTag)) GposNewTags++;
 *              }
 *
 *              //append new tags to ScriptTags if any exists
 *              if (GposNewTags>0)
 *              {
 *                  int CurrentScriptIndex=GposScriptCount;
 *
 *                  //Allocate new array to fit all tags
 *                  TagInfo[] tmp = Scripts;
 *                  Scripts = new TagInfo[GsubScriptCount+GposNewTags];
 *                  Array.Copy(tmp,0,Scripts,0,tmp.Length);
 *
 *                  for(i=0;i<GposScriptCount;i++)
 *                  {
 *                      uint GposTag = GsubScriptList.GetScriptTag(GposTable,i);
 *                      if (TagInfo.IsNewTag(Scripts,GposTag))
 *                      {
 *                          Scripts[CurrentScriptIndex].Tag=GposTag;
 *                          Scripts[CurrentScriptIndex].TagFlags
 *                              = TagInfoFlags.Positioning;
 ++CurrentScriptIndex;
 *                      }
 *                      else
 *                      {
 *                          int ScriptIndex = TagInfo.GetTagIndex(Scripts,GposTag);
 *                          Scripts[ScriptIndex].TagFlags |= TagInfoFlags.Positioning;
 *                      }
 *                  }
 *
 *                  Debug.Assert(CurrentScriptIndex==Scripts.Length);
 *              }
 *          }
 *          catch (FileFormatException)
 *          {
 *              return OpenTypeLayoutResult.BadFontTable;
 *          }
 *
 *          return OpenTypeLayoutResult.Success;
 *      }
 *
 *
 *      ///<summary>
 *      /// Enumerates language systems for script
 *      /// </summary>
 *      internal static OpenTypeLayoutResult  GetLangSysList (
 *          IOpenTypeFont   Font,       // In: Font access interface
 *          uint            ScriptTag,  // In: Script tag
 *          out TagInfo[]   LangSystems // Out: Array of LangSystems for Script
 *          )
 *      {
 *          ushort i;
 *          ushort GposNewTags;
 *
 *          LangSystems=null; // Assignment required, because of out attribute.
 *                            // This value should be owerwritten later.
 *
 *          try
 *          {
 *              FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB);
 *              FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS);
 *
 *              GSUBHeader GsubHeader = new GSUBHeader(0);
 *              GPOSHeader GposHeader = new GPOSHeader(0);
 *
 *              ScriptList GsubScriptList;
 *              ScriptList GposScriptList;
 *              ScriptTable GsubScript;
 *              ScriptTable GposScript;
 *              ushort GsubLangSysCount;
 *              ushort GposLangSysCount;
 *
 *              if (GsubTable.IsNotPresent && GposTable.IsNotPresent)
 *              {
 *                  return OpenTypeLayoutResult.ScriptNotFound;
 *              }
 *
 *              if (GsubTable.IsPresent)
 *              {
 *                  GsubScriptList = GsubHeader.GetScriptList(GsubTable);
 *                  GsubScript = GsubScriptList.FindScript(GsubTable,ScriptTag);
 *              }
 *              else
 *              {
 *                  GsubScript = new ScriptTable(FontTable.InvalidOffset);
 *              }
 *
 *              if (GposTable.IsPresent)
 *              {
 *                  GposScriptList  = GposHeader.GetScriptList(GposTable);
 *                  GposScript = GposScriptList.FindScript(GposTable,ScriptTag);
 *              }
 *              else
 *              {
 *                  GposScript = new ScriptTable(FontTable.InvalidOffset);
 *              }
 *
 *              if (GsubScript.IsNull && GposScript.IsNull)
 *              {
 *                  return OpenTypeLayoutResult.ScriptNotFound;
 *              }
 *
 *              if (!GsubScript.IsNull)
 *              {
 *                  GsubLangSysCount = GsubScript.GetLangSysCount(GsubTable);
 *              }
 *              else
 *              {
 *                  GsubLangSysCount = 0;
 *              }
 *
 *              if (!GposScript.IsNull)
 *              {
 *                  GposLangSysCount = GposScript.GetLangSysCount(GposTable);
 *              }
 *              else
 *              {
 *                  GposLangSysCount = 0;
 *              }
 *
 *              //This is true in most cases that there is no new tags in GPOS.
 *              //So, we allocate this array then check GPOS for new tags
 *              ushort CurrentLangSysIndex;
 *
 *              if (GsubScript.IsDefaultLangSysExists(GsubTable))
 *              {
 *                  LangSystems = new TagInfo[GsubLangSysCount+1];
 *                  LangSystems[0].Tag      = (uint)OpenTypeTags.dflt;
 *                  LangSystems[0].TagFlags = TagInfoFlags.Substitution;
 *                  CurrentLangSysIndex = 1;
 *              }
 *              else
 *              {
 *                  LangSystems = new TagInfo[GsubLangSysCount];
 *                  CurrentLangSysIndex = 0;
 *              }
 *
 *              for(i=0; i<GsubLangSysCount; i++)
 *              {
 *                  LangSystems[CurrentLangSysIndex].Tag = GsubScript.GetLangSysTag(GsubTable,i);
 *                  LangSystems[CurrentLangSysIndex].TagFlags = TagInfoFlags.Substitution;
 ++CurrentLangSysIndex;
 *              }
 *
 *              //Check GPOS for tags that is not in GSUB
 *              GposNewTags=0;
 *
 *              if (!GposScript.IsNull)
 *              {
 *                  if (GposScript.IsDefaultLangSysExists(GposTable) &&
 *                      TagInfo.IsNewTag(LangSystems,(uint)OpenTypeTags.dflt))
 *                  {
 ++GposNewTags;
 *                  }
 *
 *                  for(i=0;i<GposLangSysCount;i++)
 *                  {
 *                      uint GposTag = GsubScript.GetLangSysTag(GposTable,i);
 *                      if (TagInfo.IsNewTag(LangSystems,GposTag))
 *                      {
 ++GposNewTags;
 *                      }
 *                  }
 *              }
 *
 *              Debug.Assert(CurrentLangSysIndex==LangSystems.Length);
 *
 *              //append new tags to ScriptTags if any exists
 *              if (GposNewTags>0)
 *              {
 *                  //Allocate new array to fit all tags
 *                  TagInfo[] tmp = LangSystems;
 *                  LangSystems = new TagInfo[GsubLangSysCount+GposNewTags];
 *                  Array.Copy(tmp,0,LangSystems,0,tmp.Length);
 *
 *                  if (GposScript.IsDefaultLangSysExists(GposTable))
 *                  {
 *                      if (TagInfo.IsNewTag(LangSystems,(uint)OpenTypeTags.dflt))
 *                      {
 *                          LangSystems[CurrentLangSysIndex].Tag = (uint)OpenTypeTags.dflt;
 *                          LangSystems[CurrentLangSysIndex].TagFlags = TagInfoFlags.Positioning;
 ++CurrentLangSysIndex;
 *                      }
 *                      else
 *                      {
 *                          int LangSysIndex = TagInfo.GetTagIndex(LangSystems,(uint)OpenTypeTags.dflt);
 *                          LangSystems[LangSysIndex].TagFlags |= TagInfoFlags.Positioning;
 *                      }
 *                  }
 *
 *                  for(i=0;i<GposLangSysCount;i++)
 *                  {
 *                      uint GposTag = GposScript.GetLangSysTag(GposTable,i);
 *
 *                      if (TagInfo.IsNewTag(LangSystems,GposTag))
 *                      {
 *                          LangSystems[CurrentLangSysIndex].Tag = GposTag;
 *                          LangSystems[CurrentLangSysIndex].TagFlags = TagInfoFlags.Positioning;
 ++CurrentLangSysIndex;
 *                      }
 *                      else
 *                      {
 *                          int LangSysIndex = TagInfo.GetTagIndex(LangSystems,GposTag);
 *                          LangSystems[LangSysIndex].TagFlags |= TagInfoFlags.Positioning;
 *                      }
 *                  }
 *
 *                  Debug.Assert(CurrentLangSysIndex==LangSystems.Length);
 *              }
 *          }
 *          catch (FileFormatException)
 *          {
 *              return OpenTypeLayoutResult.BadFontTable;
 *          }
 *
 *          return OpenTypeLayoutResult.Success;
 *      }
 *
 *
 *      /// <summary>
 *      /// Enumerates features in a language system
 *      /// </summary>
 *      internal static OpenTypeLayoutResult  GetFeatureList (
 *          IOpenTypeFont   Font,           // In: Font access interface
 *          uint            ScriptTag,      // In: Script tag
 *          uint            LangSysTag,     // In: LangSys tag
 *          out TagInfo[]   Features        // Out: Array of features
 *          )
 *      {
 *          ushort i;
 *          ushort GposNewTags;
 *
 *          Features=null; // Assignment required, because of out attribute.
 *                         // This value should be owerwritten later.
 *
 *          try
 *          {
 *              FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB);
 *              FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS);
 *
 *              GSUBHeader GsubHeader = new GSUBHeader(0);
 *              GPOSHeader GposHeader = new GPOSHeader(0);
 *
 *              ScriptList GsubScriptList;
 *              ScriptList GposScriptList;
 *              ScriptTable GsubScript;
 *              ScriptTable GposScript;
 *              LangSysTable GsubLangSys;
 *              LangSysTable GposLangSys;
 *              ushort GsubFeatureCount;
 *              ushort GposFeatureCount;
 *              FeatureList GsubFeatureList;
 *              FeatureList GposFeatureList;
 *
 *
 *              if (GsubTable.IsNotPresent && GposTable.IsNotPresent)
 *              {
 *                  return OpenTypeLayoutResult.ScriptNotFound;
 *              }
 *
 *              if (GsubTable.IsPresent)
 *              {
 *                  GsubScriptList  = GsubHeader.GetScriptList(GsubTable);
 *                  GsubScript      = GsubScriptList.FindScript(GsubTable,ScriptTag);
 *                  GsubLangSys     = GsubScript.FindLangSys(GsubTable,LangSysTag);
 *                  GsubFeatureList = GsubHeader.GetFeatureList(GsubTable);
 *              }
 *              else
 *              {
 *                  GsubScript = new ScriptTable(FontTable.InvalidOffset);
 *                  GsubLangSys = new LangSysTable(FontTable.InvalidOffset);
 *                  GsubFeatureList = new FeatureList(FontTable.InvalidOffset);
 *              }
 *
 *              if (GposTable.IsPresent)
 *              {
 *                  GposScriptList  = GposHeader.GetScriptList(GposTable);
 *                  GposScript      = GposScriptList.FindScript(GposTable,ScriptTag);
 *                  GposLangSys     = GposScript.FindLangSys(GposTable,LangSysTag);
 *                  GposFeatureList = GposHeader.GetFeatureList(GposTable);
 *              }
 *              else
 *              {
 *                  GposScript = new ScriptTable(FontTable.InvalidOffset);
 *                  GposLangSys = new LangSysTable(FontTable.InvalidOffset);
 *                  GposFeatureList = new FeatureList(FontTable.InvalidOffset);
 *              }
 *
 *              if (GsubScript.IsNull && GposScript.IsNull)
 *              {
 *                  return OpenTypeLayoutResult.ScriptNotFound;
 *              }
 *
 *              if (GsubLangSys.IsNull && GposLangSys.IsNull)
 *              {
 *                  return OpenTypeLayoutResult.LangSysNotFound;
 *              }
 *
 *              if (!GsubLangSys.IsNull)
 *              {
 *                  GsubFeatureCount = GsubLangSys.FeatureCount(GsubTable);
 *              }
 *              else
 *              {
 *                  GsubFeatureCount = 0;
 *              }
 *
 *              if (!GposLangSys.IsNull)
 *              {
 *                  GposFeatureCount = GposLangSys.FeatureCount(GposTable);
 *              }
 *              else
 *              {
 *                  GposFeatureCount = 0;
 *              }
 *
 *              Features = new TagInfo[GsubFeatureCount];
 *              int CurrentFeatureIndex = 0;
 *
 *              for(i=0; i<GsubFeatureCount; i++)
 *              {
 *                  ushort FeatureIndex = GsubLangSys.GetFeatureIndex(GsubTable,i);
 *                  Features[CurrentFeatureIndex].Tag = GsubFeatureList.FeatureTag(GsubTable,FeatureIndex);
 *                  Features[CurrentFeatureIndex].TagFlags = TagInfoFlags.Substitution;
 ++CurrentFeatureIndex;
 *              }
 *
 *              Debug.Assert(CurrentFeatureIndex==Features.Length);
 *
 *              //Check GPOS for tags that is not in GSUB
 *              GposNewTags=0;
 *              if (!GposLangSys.IsNull)
 *              {
 *                  for(i=0;i<GposFeatureCount;i++)
 *                  {
 *                      ushort FeatureIndex = GposLangSys.GetFeatureIndex(GposTable,i);
 *                      uint GposTag = GposFeatureList.FeatureTag(GposTable,FeatureIndex);
 *                      if (TagInfo.IsNewTag(Features,GposTag))
 *                      {
 ++GposNewTags;
 *                      }
 *                  }
 *              }
 *
 *              //append new tags to ScriptTags if any exists
 *              if (GposNewTags>0)
 *              {
 *                  //Allocate new array to fit all tags
 *                  TagInfo[] tmp = Features;
 *                  Features = new TagInfo[GsubFeatureCount+GposNewTags];
 *                  Array.Copy(tmp,0,Features,0,tmp.Length);
 *
 *                  for(i=0;i<GposFeatureCount;i++)
 *                  {
 *                      ushort FeatureIndex = GposLangSys.GetFeatureIndex(GposTable,i);
 *                      uint GposTag = GposFeatureList.FeatureTag(GposTable,FeatureIndex);
 *
 *                      if (TagInfo.IsNewTag(Features,GposTag))
 *                      {
 *                          Features[CurrentFeatureIndex].Tag = GposTag;
 *                          Features[CurrentFeatureIndex].TagFlags = TagInfoFlags.Positioning;
 ++CurrentFeatureIndex;
 *                      }
 *                      else
 *                      {
 *                          int Index = TagInfo.GetTagIndex(Features,GposTag);
 *                          Features[Index].TagFlags |= TagInfoFlags.Positioning;
 *                      }
 *                  }
 *
 *                  Debug.Assert(CurrentFeatureIndex==Features.Length);
 *              }
 *
 *
 *          }
 *          catch (FileFormatException)
 *          {
 *              return OpenTypeLayoutResult.BadFontTable;
 *          }
 *
 *          return OpenTypeLayoutResult.Success;
 *      }
 */

        /// <summary>
        /// Substitutes glyphs according to features defined in the font.
        /// </summary>
        /// <param name="Font">In: Font access interface</param>
        /// <param name="workspace">In: Workspace for layout engine</param>
        /// <param name="ScriptTag">In: Script tag</param>
        /// <param name="LangSysTag">In: LangSys tag</param>
        /// <param name="FeatureSet">In: List of features to apply</param>
        /// <param name="featureCount">In: Actual number of features in <paramref name="FeatureSet"/></param>
        /// <param name="featureSetOffset">In: offset of input characters inside FeatureSet</param>
        /// <param name="CharCount">In: Characters count (i.e. <paramref name="Charmap"/>.Length);</param>
        /// <param name="Charmap">In/out: Char to glyph mapping</param>
        /// <param name="Glyphs">In/out: List of GlyphInfo structs</param>
        /// <returns>Substitution result</returns>
        internal static OpenTypeLayoutResult SubstituteGlyphs(
            IOpenTypeFont Font,                     // In: Font access interface
            OpenTypeLayoutWorkspace workspace,      // In: Workspace for layout engine
            uint ScriptTag,                         // In: Script tag
            uint LangSysTag,                        // In: LangSys tag
            Feature[]               FeatureSet,     // In: List of features to apply
            int featureCount,                       // In: Actual number of features in FeatureSet
            int featureSetOffset,
            int CharCount,                          // In: Characters count (i.e. Charmap.Length);
            UshortList Charmap,                     // In/out: Char to glyph mapping
            GlyphInfoList Glyphs                    // In/out: List of GlyphInfo structs
            )
        {
            try
            {
                FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB);
                if (!GsubTable.IsPresent)
                {
                    return(OpenTypeLayoutResult.ScriptNotFound);
                }

                GSUBHeader GsubHeader = new GSUBHeader(0);
                ScriptList ScriptList = GsubHeader.GetScriptList(GsubTable);

                ScriptTable Script = ScriptList.FindScript(GsubTable, ScriptTag);
                if (Script.IsNull)
                {
                    return(OpenTypeLayoutResult.ScriptNotFound);
                }

                LangSysTable LangSys = Script.FindLangSys(GsubTable, LangSysTag);
                if (LangSys.IsNull)
                {
                    return(OpenTypeLayoutResult.LangSysNotFound);
                }

                FeatureList FeatureList = GsubHeader.GetFeatureList(GsubTable);
                LookupList  LookupList  = GsubHeader.GetLookupList(GsubTable);

                LayoutEngine.ApplyFeatures(
                    Font,
                    workspace,
                    OpenTypeTags.GSUB,
                    GsubTable,
                    new LayoutMetrics(), //it is not needed for substitution
                    LangSys,
                    FeatureList,
                    LookupList,
                    FeatureSet,
                    featureCount,
                    featureSetOffset,
                    CharCount,
                    Charmap,
                    Glyphs,
                    null,
                    null
                    );
            }
            catch (FileFormatException)
            {
                return(OpenTypeLayoutResult.BadFontTable);
            }

            return(OpenTypeLayoutResult.Success);
        }
Beispiel #36
0
 public ushort LigatureCount(FontTable Table)
 {
     return(Table.GetUShort(offset + offsetLigatureCount));
 }
Beispiel #37
0
 private ushort LigatureSetCount(FontTable Table)
 {
     return Table.GetUShort(offset + offsetLigatureSetCount);
 }
Beispiel #38
0
        public unsafe bool Apply( 
            IOpenTypeFont           Font,           // Font access interface 
            OpenTypeTags            TableTag,       // Layout table tag (GSUB or GPOS)
            FontTable               Table,          // Layout table (GSUB or GPOS) 
            LayoutMetrics           Metrics,        // LayoutMetrics
            int                     CharCount,      // Characters count (i.e. Charmap.Length);
            UshortList              Charmap,        // Char to glyph mapping
            GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs 
            int*                    Advances,       // Glyph adv.widths
            LayoutOffset*           Offsets,        // Glyph offsets 
            ushort                  LookupFlags,    // Lookup table flags 
            int                     FirstGlyph,     // where to apply it
            int                     AfterLastGlyph, // how long is a context we can use 
            uint                    Parameter,      // lookup parameter
            int                     nestingLevel,   // Contextual lookup nesting level
            out int                 NextGlyph       // out: next glyph index
            ) 
        {
            Invariant.Assert(Format(Table)==2); 
 
            NextGlyph = FirstGlyph + 1; //in case we don't match
 
            int glyphCount = GlyphInfo.Length;

            int     glyphIndex = FirstGlyph;
            ushort  glyphId = GlyphInfo.Glyphs[glyphIndex]; 

            if (Coverage(Table).GetGlyphIndex(Table,glyphId) < 0) return false; 
 
            ClassDefTable inputClassDef = InputClassDef(Table),
                          backtrackClassDef =  BacktrackClassDef(Table), 
                          lookaheadClassDef = LookaheadClassDef(Table);

            ushort GlyphClass = inputClassDef.GetClass(Table,glyphId);
            if (GlyphClass >= ClassSetCount(Table)) return false; //!!! Bad font table 

            SubClassSet subClassSet = ClassSet(Table,GlyphClass); 
            if (subClassSet.IsNull) return false;   // There are no rules for this class 

            ushort ruleCount = subClassSet.RuleCount(Table); 

            bool match = false;
            for(ushort i=0; !match && i<ruleCount; i++)
            { 
                match = subClassSet.Rule(Table,i).Apply(Font, TableTag, Table, Metrics,
                                                        inputClassDef,backtrackClassDef,lookaheadClassDef, 
                                                        CharCount, Charmap, 
                                                        GlyphInfo, Advances, Offsets,
                                                        LookupFlags, FirstGlyph, AfterLastGlyph, 
                                                        Parameter,
                                                        nestingLevel,
                                                        out NextGlyph
                                                       ); 
            }
 
            return match; 
        }
Beispiel #39
0
 public ushort LigatureCount(FontTable Table)
 {
     return Table.GetUShort(offset + offsetLigatureCount);
 }
Beispiel #40
0
 public bool IsLookupCovered(
                 FontTable table,
                 uint[] glyphBits,
                 ushort minGlyphId, 
                 ushort maxGlyphId)
 { 
     return true; 
 }
Beispiel #41
0
 public ushort LigatureGlyph(FontTable Table)
 {
     return Table.GetUShort(offset + offsetLigatureGlyph);
 }
Beispiel #42
0
 public CoverageTable BacktrackCoverage(FontTable Table, ushort Index) 
 {
     return new CoverageTable(offset +
                                 Table.GetUShort(offset+
                                                 offsetBacktrackGlyphCount + 
                                                 sizeGlyphCount +
                                                 Index*sizeCoverageOffset) 
                             ); 
 }
Beispiel #43
0
 public ushort Component(FontTable Table, ushort Index)
 {
     //LigaTable includes comps from 1 to N. So, (Index-1)
     return Table.GetUShort(offset + offsetComponentArray +
         (Index-1) * sizeComponent);
 }
Beispiel #44
0
 public CoverageTable LookaheadCoverage(FontTable Table, ushort Index)
 { 
     return new CoverageTable(offset +
                                 Table.GetUShort(offset+ 
                                                 offsetLookaheadGlyphCount + 
                                                 sizeGlyphCount +
                                                 Index*sizeCoverageOffset) 
                             );
 }
Beispiel #45
0
        public bool IsLookupCovered(
                        FontTable table, 
                        uint[] glyphBits, 
                        ushort minGlyphId, 
                        ushort maxGlyphId)
        {
            if (!Coverage(table).IsAnyGlyphCovered(table,
                                                     glyphBits,
                                                     minGlyphId,
                                                     maxGlyphId
                                                    )
               ) return false;

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

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

        }
Beispiel #46
0
 public ContextualLookupRecords ContextualLookups(FontTable Table) 
 {
     int recordCountOffset = offset + offsetLookaheadGlyphCount + sizeGlyphCount + 
                             LookaheadGlyphCount(Table) * sizeCoverageOffset; 
     return new ContextualLookupRecords(recordCountOffset+sizeGlyphCount,
                                         Table.GetUShort(recordCountOffset)); 
 }
Beispiel #47
0
 private short Format1DeltaGlyphId(FontTable Table)
 {
     Invariant.Assert(Format(Table)==1);
     return Table.GetShort(offset + offsetFormat1DeltaGlyphId);
 }
Beispiel #48
0
        public CoverageChainingSubtable(FontTable Table, int Offset)
        { 
            offset = Offset;
            offsetInputGlyphCount = offsetBacktrackGlyphCount + sizeGlyphCount + 
                                      Table.GetUShort(offset+offsetBacktrackGlyphCount) * 
                                                                    sizeCoverageOffset;
 
            offsetLookaheadGlyphCount = offsetInputGlyphCount + sizeGlyphCount +
                                          Table.GetUShort(offset+offsetInputGlyphCount) *
                                                                   sizeCoverageOffset;
        } 
Beispiel #49
0
        public unsafe bool Apply(
            IOpenTypeFont   Font,
            FontTable       Table,
            int             CharCount,
            UshortList      Charmap,        // Character to glyph map
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo
            ushort          LookupFlags,    // Lookup flags for glyph lookups
            int             FirstGlyph,     // where to apply it
            int             AfterLastGlyph, // how long is a context we can use
            out int         NextGlyph       // Next glyph to process
            )
         {
            NextGlyph = FirstGlyph + 1; // in case we don't match
            
            if (Format(Table) != 1) return false; //unknown format
            
            int oldGlyphCount=GlyphInfo.Length;
            
            ushort glyphId = GlyphInfo.Glyphs[FirstGlyph];
            int coverageIndex = Coverage(Table).GetGlyphIndex(Table,glyphId);
            if (coverageIndex==-1) return false;
            
            MultipleSubstitutionSequenceTable sequence = Sequence(Table,coverageIndex);

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

                if (lengthDelta > 0)
                {
                    GlyphInfo.Insert(FirstGlyph,lengthDelta);
                }
                
                //put glyphs in place
                for(ushort gl=0; gl<sequenceLength; gl++)
                {
                    GlyphInfo.Glyphs[FirstGlyph + gl] = sequence.Glyph(Table,gl);
                    GlyphInfo.GlyphFlags[FirstGlyph + gl] =
                                (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                    GlyphInfo.FirstChars[FirstGlyph + gl] = firstChar;
                    GlyphInfo.LigatureCounts[FirstGlyph + gl] = ligatureCount;
                }
            }
            
            //Fix char mapping - very simple for now. 
            // Works only for arabic base+mark -> base and marks decomposition
            //
            for(int ch=0;ch<CharCount;ch++)
            {
                if (Charmap[ch]>FirstGlyph) Charmap[ch] = (ushort)(Charmap[ch]+lengthDelta);
            }
            
            NextGlyph = FirstGlyph + lengthDelta + 1;
            
            return true;
         }
Beispiel #50
0
        public unsafe bool Apply( 
            IOpenTypeFont           Font,           // Font access interface 
            OpenTypeTags            TableTag,       // Layout table tag (GSUB or GPOS)
            FontTable               Table,          // Layout table (GSUB or GPOS) 
            LayoutMetrics           Metrics,        // LayoutMetrics
            int                     CharCount,      // Characters count (i.e. Charmap.Length);
            UshortList              Charmap,        // Char to glyph mapping
            GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs 
            int*                    Advances,       // Glyph adv.widths
            LayoutOffset*           Offsets,        // Glyph offsets 
            ushort                  LookupFlags,    // Lookup table flags 
            int                     FirstGlyph,     // where to apply it
            int                     AfterLastGlyph, // how long is a context we can use 
            uint                    Parameter,      // lookup parameter
            int                     nestingLevel,   // Contextual lookup nesting level
            out int                 NextGlyph       // out: next glyph index
            ) 
        {
            Invariant.Assert(Format(Table)==3); 
 
            NextGlyph = FirstGlyph + 1; //in case we don't match
 
            int glyphCount = GlyphInfo.Length;
            int glyphIndex;

            ushort backtrackGlyphCount = BacktrackGlyphCount(Table); 
            ushort inputGlyphCount     = InputGlyphCount(Table);
            ushort lookaheadGlyphCount = LookaheadGlyphCount(Table); 
 
            if (FirstGlyph < backtrackGlyphCount ||
                (FirstGlyph + inputGlyphCount) > AfterLastGlyph) 
            {
                return false;
            }
 
            bool match = true;
 
            //Check backtrack sequence 
            glyphIndex = FirstGlyph;
            for(ushort backtrackIndex = 0; 
                backtrackIndex < backtrackGlyphCount && match;
                backtrackIndex++)
            {
                 glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo, 
                                                                glyphIndex-1,
                                                                LookupFlags, 
                                                                LayoutEngine.LookBackward 
                                                               );
 
                if (glyphIndex<0 ||
                    BacktrackCoverage(Table,backtrackIndex)
                            .GetGlyphIndex(Table,GlyphInfo.Glyphs[glyphIndex])<0)
                { 
                    match=false;
                } 
            } 

            if (!match) return false; 

            glyphIndex = FirstGlyph;
            for(ushort inputIndex = 0;
                inputIndex < inputGlyphCount && match; 
                inputIndex++)
            { 
                if (glyphIndex>=AfterLastGlyph || 
                    InputCoverage(Table,inputIndex)
                    .GetGlyphIndex(Table,GlyphInfo.Glyphs[glyphIndex])<0) 
                {
                    match=false;
                }
                else 
                {
                    glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo, 
                        glyphIndex + 1, 
                        LookupFlags,
                        LayoutEngine.LookForward 
                        );
                }
            }
 
            if (!match) return false;
 
            int afterInputGlyph = glyphIndex; // remember where we were after input seqence 

            for(ushort lookaheadIndex = 0; 
                lookaheadIndex < lookaheadGlyphCount && match;
                lookaheadIndex++)
            {
                if (glyphIndex>=GlyphInfo.Length || 
                    LookaheadCoverage(Table,lookaheadIndex)
                    .GetGlyphIndex(Table,GlyphInfo.Glyphs[glyphIndex])<0) 
                { 
                    match=false;
                } 
                else
                {
                    glyphIndex = LayoutEngine.
                                    GetNextGlyphInLookup(Font, GlyphInfo, 
                                                         glyphIndex + 1,
                                                         LookupFlags, 
                                                         LayoutEngine.LookForward); 
                }
            } 

            if (match)
            {
                ContextualLookups(Table).ApplyContextualLookups( 
                                                Font,
                                                TableTag, 
                                                Table, 
                                                Metrics,
                                                CharCount, 
                                                Charmap,
                                                GlyphInfo,
                                                Advances,
                                                Offsets, 
                                                LookupFlags,
                                                FirstGlyph, 
                                                afterInputGlyph, //As AfterLastGlyph 
                                                Parameter,
                                                nestingLevel, 
                                                out NextGlyph
                                            );
            }
 
            return match;
        } 
Beispiel #51
0
 private CoverageTable Coverage(FontTable Table)
 {
     return new CoverageTable(offset + Table.GetUShort(offset + offsetCoverage));
 }
Beispiel #52
0
 private LigatureSetTable LigatureSet(FontTable Table, ushort Index)
 {
     return(new LigatureSetTable(offset + Table.GetUShort(offset +
                                                          offsetLigatureSetArray +
                                                          Index * sizeLigatureSet)));
 }
Beispiel #53
0
 // Not used. This value should be equal to glyph count in Coverage.
 // Keeping it for future reference
 //private ushort AlternateSetCount(FontTable Table)
 //{
 //    return Table.GetUShort(offset + offsetAlternateSetCount);
 //}
 
 private AlternateSetTable AlternateSet(FontTable Table, int index)
 {
     return new AlternateSetTable(offset + 
                                  Table.GetUShort(offset + 
                                                  offsetAlternateSets +
                                                  index * sizeAlternateSetOffset)
                                 );
 }
        private static void ComputeTableCache(
            IOpenTypeFont font,
            OpenTypeTags tableTag,
            int maxCacheSize,
            ref int cacheSize,
            ref GlyphLookupRecord[] records,
            ref int recordCount,
            ref int glyphCount,
            ref int lastLookupAdded
            )
        {
            FontTable table = font.GetFontTable(tableTag);

            if (!table.IsPresent)
            {
                return;
            }

            FeatureList featureList;
            LookupList  lookupList;

            Debug.Assert(tableTag == OpenTypeTags.GSUB || tableTag == OpenTypeTags.GPOS);

            switch (tableTag)
            {
            case OpenTypeTags.GSUB:
            {
                GSUBHeader header = new GSUBHeader();
                featureList = header.GetFeatureList(table);
                lookupList  = header.GetLookupList(table);
                break;
            }

            case OpenTypeTags.GPOS:
            {
                GPOSHeader header = new GPOSHeader();
                featureList = header.GetFeatureList(table);
                lookupList  = header.GetLookupList(table);
                break;
            }

            default:
            {
                Debug.Assert(false);
                featureList = new FeatureList(0);
                lookupList  = new LookupList(0);
                break;
            }
            }

            // Estimate number of records that can fit into cache using ratio of approximately
            // 4 bytes of cache per actual record. Most of fonts will fit into this value, except
            // some tiny caches and big EA font that can have ratio of around 5 (theoretical maximum is 8).
            //
            // If actual ratio for particluar font will be larger than 4, we will remove records
            // from the end to fit into cache.
            //
            // If ratio is less than 4 we actually can fit more lookups, but for the speed and because most fonts
            // will fit into cache completely anyway we do not do anything about this here.
            int maxRecordCount = maxCacheSize / 4;

            // For now, we will just allocate array of maximum size.
            // Given heuristics above, it wont be greater than max cache size.
            //
            records = new GlyphLookupRecord[maxRecordCount];

            //
            // Now iterate through lookups and subtables, filling in lookup-glyph pairs list
            //
            int lookupCount = lookupList.LookupCount(table);
            int recordCountAfterLastLookup = 0;

            //
            // Not all lookups can be invoked from feature directly,
            // they are actions from contextual lookups.
            // We are not interested in those, because they will
            // never work from high level, so do not bother adding them to the cache.
            //
            // Filling array of lookup usage bits, to skip those not mapped to any lookup
            //
            BitArray lookupUsage = new BitArray(lookupCount);

            for (ushort feature = 0; feature < featureList.FeatureCount(table); feature++)
            {
                FeatureTable featureTable = featureList.FeatureTable(table, feature);

                for (ushort lookup = 0; lookup < featureTable.LookupCount(table); lookup++)
                {
                    ushort lookupIndex = featureTable.LookupIndex(table, lookup);

                    if (lookupIndex >= lookupCount)
                    {
                        // This must be an invalid font. Just igonoring this lookup here.
                        continue;
                    }

                    lookupUsage[lookupIndex] = true;
                }
            }
            // Done with lookup usage bits

            for (ushort lookupIndex = 0; lookupIndex < lookupCount; lookupIndex++)
            {
                if (!lookupUsage[lookupIndex])
                {
                    continue;
                }

                int  firstLookupRecord = recordCount;
                int  maxLookupGlyph    = -1;
                bool cacheIsFull       = false;

                LookupTable lookup        = lookupList.Lookup(table, lookupIndex);
                ushort      lookupType    = lookup.LookupType();
                ushort      subtableCount = lookup.SubTableCount();

                for (ushort subtableIndex = 0; subtableIndex < subtableCount; subtableIndex++)
                {
                    int subtableOffset = lookup.SubtableOffset(table, subtableIndex);

                    CoverageTable coverage = GetSubtablePrincipalCoverage(table, tableTag, lookupType, subtableOffset);

                    if (coverage.IsInvalid)
                    {
                        continue;
                    }

                    cacheIsFull = !AppendCoverageGlyphRecords(table, lookupIndex, coverage, records, ref recordCount, ref maxLookupGlyph);

                    if (cacheIsFull)
                    {
                        break;
                    }
                }

                if (cacheIsFull)
                {
                    break;
                }

                lastLookupAdded            = lookupIndex;
                recordCountAfterLastLookup = recordCount;
            }

            // We may hit storage overflow in the middle of lookup. Throw this partial lookup away
            recordCount = recordCountAfterLastLookup;

            if (lastLookupAdded == -1)
            {
                // We did not succeed adding even single lookup.
                return;
            }

            // We now have glyph records for (may be not all) lookups in the table.
            // Cache structures should be sorted by glyph, then by lookup index.
            Array.Sort(records, 0, recordCount);

            cacheSize  = -1;
            glyphCount = -1;

            // It may happen, that records do not fit into cache, even using our heuristics.
            // We will remove lookups one by one from the end until it fits.
            while (recordCount > 0)
            {
                CalculateCacheSize(records, recordCount, out cacheSize, out glyphCount);

                if (cacheSize <= maxCacheSize)
                {
                    // Fine, we now fit into max cache size
                    break;
                }
                else
                {
                    // Find last lookup index
                    int lastLookup = -1;
                    for (int i = 0; i < recordCount; i++)
                    {
                        int lookup = records[i].Lookup;

                        if (lastLookup < lookup)
                        {
                            lastLookup = lookup;
                        }
                    }

                    Debug.Assert(lastLookup >= 0); // There are lookups, so there was an index

                    // Remove it
                    int currentRecord = 0;
                    for (int i = 0; i < recordCount; i++)
                    {
                        if (records[i].Lookup == lastLookup)
                        {
                            continue;
                        }

                        if (currentRecord == i)
                        {
                            continue;
                        }

                        records[currentRecord] = records[i];
                        currentRecord++;
                    }

                    recordCount = currentRecord;

                    // Do not forget update lastLookupAdded variable
                    lastLookupAdded = lastLookup - 1;
                }
            }

            if (recordCount == 0)
            {
                // We can't fit even single lookup into the cache
                return;
            }

            Debug.Assert(cacheSize > 0);  // We've calcucalted them at least ones, and
            Debug.Assert(glyphCount > 0); // if there is no records, we already should've exited
        }
Beispiel #55
0
            public ushort Alternate(FontTable Table, uint FeatureParam)
            {
                Invariant.Assert(FeatureParam > 0); // Parameter 0 means feautre is disabled.
                                                //Should be filtered out in GetNextEnabledGlyphRange

                // Off by one - alternate number 1 is stored under index 0
                uint index = FeatureParam - 1;
                
                if (index >= GlyphCount(Table)) 
                {
                    return AlternateSubstitutionSubtable.InvalidAlternateGlyph;
                }
                
                return Table.GetUShort(offset + offsetGlyphs + (ushort)index*sizeGlyph);
            }
        private static CoverageTable GetSubtablePrincipalCoverage(
            FontTable table,
            OpenTypeTags tableTag,
            ushort lookupType,
            int subtableOffset
            )
        {
            Debug.Assert(tableTag == OpenTypeTags.GSUB || tableTag == OpenTypeTags.GPOS);

            CoverageTable coverage = CoverageTable.InvalidCoverage;

            switch (tableTag)
            {
            case OpenTypeTags.GSUB:
                if (lookupType == 7)
                {
                    ExtensionLookupTable extension =
                        new ExtensionLookupTable(subtableOffset);

                    lookupType     = extension.LookupType(table);
                    subtableOffset = extension.LookupSubtableOffset(table);
                }

                switch (lookupType)
                {
                case 1:         //SingleSubst
                    SingleSubstitutionSubtable singleSubst =
                        new SingleSubstitutionSubtable(subtableOffset);

                    return(singleSubst.GetPrimaryCoverage(table));

                case 2:         //MultipleSubst
                    MultipleSubstitutionSubtable multipleSub =
                        new MultipleSubstitutionSubtable(subtableOffset);
                    return(multipleSub.GetPrimaryCoverage(table));

                case 3:         //AlternateSubst
                    AlternateSubstitutionSubtable alternateSub =
                        new AlternateSubstitutionSubtable(subtableOffset);
                    return(alternateSub.GetPrimaryCoverage(table));

                case 4:         //Ligature subst
                    LigatureSubstitutionSubtable ligaSub =
                        new LigatureSubstitutionSubtable(subtableOffset);
                    return(ligaSub.GetPrimaryCoverage(table));

                case 5:         //ContextualSubst
                    ContextSubtable contextSub =
                        new ContextSubtable(subtableOffset);
                    return(contextSub.GetPrimaryCoverage(table));

                case 6:         //ChainingSubst
                    ChainingSubtable chainingSub =
                        new ChainingSubtable(subtableOffset);
                    return(chainingSub.GetPrimaryCoverage(table));

                case 7:         //Extension lookup
                    // Ext.Lookup processed earlier. It can't contain another ext.lookups in it
                    break;

                case 8:         //ReverseCahiningSubst
                    ReverseChainingSubtable reverseChainingSub =
                        new ReverseChainingSubtable(subtableOffset);
                    return(reverseChainingSub.GetPrimaryCoverage(table));
                }

                break;

            case OpenTypeTags.GPOS:
                if (lookupType == 9)
                {
                    ExtensionLookupTable extension =
                        new ExtensionLookupTable(subtableOffset);

                    lookupType     = extension.LookupType(table);
                    subtableOffset = extension.LookupSubtableOffset(table);
                }

                switch (lookupType)
                {
                case 1:         //SinglePos
                    SinglePositioningSubtable singlePos =
                        new SinglePositioningSubtable(subtableOffset);
                    return(singlePos.GetPrimaryCoverage(table));

                case 2:         //PairPos
                    PairPositioningSubtable pairPos =
                        new PairPositioningSubtable(subtableOffset);
                    return(pairPos.GetPrimaryCoverage(table));

                case 3:         // CursivePos
                    CursivePositioningSubtable cursivePos =
                        new CursivePositioningSubtable(subtableOffset);
                    return(cursivePos.GetPrimaryCoverage(table));

                case 4:         //MarkToBasePos
                    MarkToBasePositioningSubtable markToBasePos =
                        new MarkToBasePositioningSubtable(subtableOffset);
                    return(markToBasePos.GetPrimaryCoverage(table));

                case 5:         //MarkToLigaturePos
                    // Under construction
                    MarkToLigaturePositioningSubtable markToLigaPos =
                        new MarkToLigaturePositioningSubtable(subtableOffset);
                    return(markToLigaPos.GetPrimaryCoverage(table));

                case 6:         //MarkToMarkPos
                    MarkToMarkPositioningSubtable markToMarkPos =
                        new MarkToMarkPositioningSubtable(subtableOffset);
                    return(markToMarkPos.GetPrimaryCoverage(table));

                case 7:         // Contextual
                    ContextSubtable contextPos =
                        new ContextSubtable(subtableOffset);
                    return(contextPos.GetPrimaryCoverage(table));

                case 8:         // Chaining
                    ChainingSubtable chainingPos =
                        new ChainingSubtable(subtableOffset);
                    return(chainingPos.GetPrimaryCoverage(table));

                case 9:         //Extension lookup
                    // Ext.Lookup processed earlier. It can't contain another ext.lookups in it
                    break;
                }

                break;
            }

            return(CoverageTable.InvalidCoverage);
        }
Beispiel #57
0
 private ushort LigatureSetCount(FontTable Table)
 {
     return(Table.GetUShort(offset + offsetLigatureSetCount));
 }
Beispiel #58
0
        ///<summary>
        /// Internal method to test layout tables if they are uitable for fast path.
        /// Returns list of script-langauge pairs that are not optimizable.
        ///</summary>
        internal static OpenTypeLayoutResult GetComplexLanguageList(
            IOpenTypeFont Font,                 //In: Font access interface
            uint[]              featureList,    //In: Feature to look in
            uint[]              glyphBits,
            ushort minGlyphId,
            ushort maxGlyphId,
            out WritingSystem[] complexLanguages
            // Out: List of script/langauge pair
            //      that are not optimizable
            )
        {
            try
            {
                WritingSystem[] gsubComplexLanguages      = null;
                WritingSystem[] gposComplexLanguages      = null;
                int             gsubComplexLanguagesCount = 0;
                int             gposComplexLanguagesCount = 0;

                FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB);
                FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS);

                if (GsubTable.IsPresent)
                {
                    LayoutEngine.GetComplexLanguageList(
                        OpenTypeTags.GSUB,
                        GsubTable,
                        featureList,
                        glyphBits,
                        minGlyphId,
                        maxGlyphId,
                        out gsubComplexLanguages,
                        out gsubComplexLanguagesCount
                        );
                }

                if (GposTable.IsPresent)
                {
                    LayoutEngine.GetComplexLanguageList(
                        OpenTypeTags.GPOS,
                        GposTable,
                        featureList,
                        glyphBits,
                        minGlyphId,
                        maxGlyphId,
                        out gposComplexLanguages,
                        out gposComplexLanguagesCount
                        );
                }

                if (gsubComplexLanguages == null && gposComplexLanguages == null)
                {
                    complexLanguages = null;
                    return(OpenTypeLayoutResult.Success);
                }

                // Both tables have complex scrips, merge results

                // Count gpos unique Languages
                // and pack them at the same time
                // so we do not research them again.
                int gposNewLanguages = 0, i, j;

                for (i = 0; i < gposComplexLanguagesCount; i++)
                {
                    bool foundInGsub = false;

                    for (j = 0; j < gsubComplexLanguagesCount; j++)
                    {
                        if (gsubComplexLanguages[j].scriptTag == gposComplexLanguages[i].scriptTag &&
                            gsubComplexLanguages[j].langSysTag == gposComplexLanguages[i].langSysTag
                            )
                        {
                            foundInGsub = true;
                            break;
                        }
                        ;
                    }

                    if (!foundInGsub)
                    {
                        if (gposNewLanguages < i)
                        {
                            gposComplexLanguages[gposNewLanguages] = gposComplexLanguages[i];
                        }

                        gposNewLanguages++;
                    }
                }

                //realloc array for merged results, merge both arrays
                complexLanguages = new WritingSystem[gsubComplexLanguagesCount + gposNewLanguages];

                for (i = 0; i < gsubComplexLanguagesCount; i++)
                {
                    complexLanguages[i] = gsubComplexLanguages[i];
                }

                for (i = 0; i < gposNewLanguages; i++)
                {
                    complexLanguages[gsubComplexLanguagesCount + i] = gposComplexLanguages[i];
                }

                return(OpenTypeLayoutResult.Success);
            }
            catch (FileFormatException)
            {
                complexLanguages = null;
                return(OpenTypeLayoutResult.BadFontTable);
            }
        }
Beispiel #59
0
 public CoverageTable GetPrimaryCoverage(FontTable table)
 {
     return Coverage(table);
 }
Beispiel #60
0
 public ushort Component(FontTable Table, ushort Index)
 {
     //LigaTable includes comps from 1 to N. So, (Index-1)
     return(Table.GetUShort(offset + offsetComponentArray +
                            (Index - 1) * sizeComponent));
 }