public bool IsLookupCovered( FontTable table, uint[] glyphBits, ushort minGlyphId, ushort maxGlyphId) { if (!Coverage(table).IsAnyGlyphCovered(table, glyphBits, minGlyphId, maxGlyphId ) ) { return(false); } ushort ligatureSetCount = LigatureSetCount(table); for (ushort setIndex = 0; setIndex < ligatureSetCount; setIndex++) { LigatureSetTable ligatureSet = LigatureSet(table, setIndex); ushort ligaCount = ligatureSet.LigatureCount(table); for (ushort liga = 0; liga < ligaCount; liga++) { LigatureTable ligature = ligatureSet.Ligature(table, liga); ushort compCount = ligature.ComponentCount(table); bool ligatureIsComplex = true; for (ushort compIndex = 1; compIndex < compCount; compIndex++) { ushort glyphId = ligature.Component(table, compIndex); if (glyphId > maxGlyphId || glyphId < minGlyphId || (glyphBits[glyphId >> 5] & (1 << (glyphId % 32))) == 0 ) { ligatureIsComplex = false; break; } } if (ligatureIsComplex) { return(true); } } } return(false); }
public 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); }