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; }
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); }
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; }
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); }