internal static bool ApplyLookup( IOpenTypeFont Font, // Font access interface OpenTypeTags TableTag, // Layout table tag (GSUB or GPOS) FontTable Table, // Layout table (GSUB or GPOS) LayoutMetrics Metrics, // LayoutMetrics LookupTable Lookup, // List definition structure 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 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 ) { Debug.Assert(TableTag==OpenTypeTags.GSUB || TableTag==OpenTypeTags.GPOS); Debug.Assert(FirstGlyph<AfterLastGlyph); Debug.Assert(AfterLastGlyph<=GlyphInfo.Length); ushort lookupType = Lookup.LookupType(); ushort lookupFlags = Lookup.LookupFlags(); ushort subtableCount = Lookup.SubTableCount(); bool match=false; NextGlyph=FirstGlyph+1; //Just to avoid compiler error // Find first glyph if (!IsLookupReversal(TableTag,lookupType)) { FirstGlyph=LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo,FirstGlyph, lookupFlags,LayoutEngine.LookForward); } else { AfterLastGlyph = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo,AfterLastGlyph-1, lookupFlags,LayoutEngine.LookBackward) + 1; } if (FirstGlyph>=AfterLastGlyph) return match; ushort originalLookupType = lookupType; // We need it to recover, if extension lookup updated lookupFormat for(ushort subtableIndex=0; !match && subtableIndex < subtableCount; subtableIndex++) { lookupType = originalLookupType; int subtableOffset = Lookup.SubtableOffset(Table, subtableIndex); 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 singleSub = new SingleSubstitutionSubtable(subtableOffset); match = singleSub.Apply( Table, GlyphInfo, FirstGlyph, out NextGlyph ); break; case 2: //MultipleSubst MultipleSubstitutionSubtable multipleSub = new MultipleSubstitutionSubtable(subtableOffset); match = multipleSub.Apply( Font, Table, CharCount, Charmap, GlyphInfo, lookupFlags, FirstGlyph, AfterLastGlyph, out NextGlyph ); break; case 3: //AlternateSubst AlternateSubstitutionSubtable alternateSub = new AlternateSubstitutionSubtable(subtableOffset); match = alternateSub.Apply( Table, GlyphInfo, Parameter, FirstGlyph, out NextGlyph ); break; case 4: //Ligature subst LigatureSubstitutionSubtable ligaSub = new LigatureSubstitutionSubtable(subtableOffset); match = ligaSub.Apply( Font, Table, CharCount, Charmap, GlyphInfo, lookupFlags, FirstGlyph, AfterLastGlyph, out NextGlyph ); break; case 5: //ContextualSubst ContextSubtable contextSub = new ContextSubtable(subtableOffset); match = contextSub.Apply( Font, TableTag, Table, Metrics, CharCount, Charmap, GlyphInfo, Advances, Offsets, lookupFlags, FirstGlyph, AfterLastGlyph, Parameter, nestingLevel, out NextGlyph ); break; case 6: //ChainingSubst ChainingSubtable chainingSub = new ChainingSubtable(subtableOffset); match = chainingSub.Apply( Font, TableTag, Table, Metrics, CharCount, Charmap, GlyphInfo, Advances, Offsets, lookupFlags, FirstGlyph, AfterLastGlyph, Parameter, nestingLevel, out NextGlyph ); break; case 7: //Extension lookup // Ext.Lookup processed earlier. It can't contain another ext.lookups in it. // Just skip it (do nothing); NextGlyph = FirstGlyph + 1; break; case 8: //ReverseCahiningSubst ReverseChainingSubtable reverseChainingSub = new ReverseChainingSubtable(subtableOffset); match = reverseChainingSub.Apply( Font, TableTag, Table, Metrics, CharCount, Charmap, GlyphInfo, Advances, Offsets, lookupFlags, FirstGlyph, AfterLastGlyph, Parameter, out NextGlyph ); break; default: // Unknown format NextGlyph = FirstGlyph+1; break; } if (match) { if (!IsLookupReversal(TableTag,lookupType)) { UpdateGlyphFlags(Font,GlyphInfo,FirstGlyph,NextGlyph,true,GlyphFlags.Substituted); } else { UpdateGlyphFlags(Font,GlyphInfo,NextGlyph,AfterLastGlyph,true,GlyphFlags.Substituted); } } 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); match = singlePos.Apply(Table, Metrics, GlyphInfo, Advances, Offsets, FirstGlyph, AfterLastGlyph, out NextGlyph ); break; case 2: //PairPos PairPositioningSubtable pairPos = new PairPositioningSubtable(subtableOffset); match = pairPos.Apply( Font, Table, Metrics, // LayoutMetrics GlyphInfo, // List of GlyphInfo structs lookupFlags, // Lookup flags for glyph lookups Advances, // Glyph adv.widths Offsets, // Glyph offsets FirstGlyph, // where to apply lookup AfterLastGlyph, // how long is a context we can use out NextGlyph // Next glyph to process ); break; case 3: // CursivePos // Under construction CursivePositioningSubtable cursivePositioningSubtable = new CursivePositioningSubtable(subtableOffset); cursivePositioningSubtable.Apply( Font, Table, Metrics, // LayoutMetrics GlyphInfo, // List of GlyphInfo structs lookupFlags, // Lookup flags for glyph lookups Advances, // Glyph adv.widths Offsets, // Glyph offsets FirstGlyph, // where to apply lookup AfterLastGlyph, // how long is a context we can use out NextGlyph // Next glyph to process ); break; case 4: //MarkToBasePos MarkToBasePositioningSubtable markToBasePos = new MarkToBasePositioningSubtable(subtableOffset); match = markToBasePos.Apply(Font, Table, Metrics, // LayoutMetrics GlyphInfo, // List of GlyphInfo structs lookupFlags, // Lookup flags for glyph lookups Advances, // Glyph adv.widths Offsets, // Glyph offsets FirstGlyph, // where to apply lookup AfterLastGlyph, // how long is a context we can use out NextGlyph // Next glyph to process ); break; case 5: //MarkToLigaturePos // Under construction MarkToLigaturePositioningSubtable markToLigaPos = new MarkToLigaturePositioningSubtable(subtableOffset); match = markToLigaPos.Apply( Font, Table, Metrics, // LayoutMetrics GlyphInfo, // List of GlyphInfo structs lookupFlags, // Lookup flags for glyph lookups CharCount, // Characters count (i.e. Charmap.Length); Charmap, // Char to glyph mapping Advances, // Glyph adv.widths Offsets, // Glyph offsets FirstGlyph, // where to apply lookup AfterLastGlyph, // how long is a context we can use out NextGlyph // Next glyph to process ); break; case 6: //MarkToMarkPos MarkToMarkPositioningSubtable markToMarkPos = new MarkToMarkPositioningSubtable(subtableOffset); match = markToMarkPos.Apply( Font, Table, Metrics, // LayoutMetrics GlyphInfo, // List of GlyphInfo structs lookupFlags, // Lookup flags for glyph lookups Advances, // Glyph adv.widths Offsets, // Glyph offsets FirstGlyph, // where to apply lookup AfterLastGlyph, // how long is a context we can use out NextGlyph // Next glyph to process ); break; case 7: // Contextual ContextSubtable contextSub = new ContextSubtable(subtableOffset); match = contextSub.Apply( Font, TableTag, Table, Metrics, CharCount, Charmap, GlyphInfo, Advances, Offsets, lookupFlags, FirstGlyph, AfterLastGlyph, Parameter, nestingLevel, out NextGlyph ); break; case 8: // Chaining ChainingSubtable chainingSub = new ChainingSubtable(subtableOffset); match = chainingSub.Apply( Font, TableTag, Table, Metrics, CharCount, Charmap, GlyphInfo, Advances, Offsets, lookupFlags, FirstGlyph, AfterLastGlyph, Parameter, nestingLevel, out NextGlyph ); break; case 9: //Extension lookup // Ext.Lookup processed earlier. It can't contain another ext.lookups in it. // Just skip it (do nothing); NextGlyph = FirstGlyph + 1; break; default: // Unknown format NextGlyph = FirstGlyph + 1; break; } if (match) { UpdateGlyphFlags(Font,GlyphInfo,FirstGlyph,NextGlyph,false,GlyphFlags.Positioned); } break; } default: Debug.Assert(false,"Unknown OpenType layout table!"); break; } } return match; }