public static bool ApplyLookupList( FontMetrics fontMetrics, GSubTable table, Tag feature, LookupFlags lookupFlags, SequenceLookupRecord[] records, GlyphSubstitutionCollection collection, ushort index, int count) { bool hasChanged = false; SkippingGlyphIterator iterator = new(fontMetrics, collection, index, lookupFlags); int currentCount = collection.Count; foreach (SequenceLookupRecord lookupRecord in records) { ushort sequenceIndex = lookupRecord.SequenceIndex; ushort lookupIndex = lookupRecord.LookupListIndex; iterator.Index = index; iterator.Increment(sequenceIndex); GSub.LookupTable lookup = table.LookupList.LookupTables[lookupIndex]; hasChanged |= lookup.TrySubstitution(fontMetrics, table, collection, feature, iterator.Index, count - (iterator.Index - index)); // Account for substitutions changing the length of the collection. if (collection.Count != currentCount) { count -= currentCount - collection.Count; currentCount = collection.Count; } } return(hasChanged); }
public override bool TrySubstitution( FontMetrics fontMetrics, GSubTable table, GlyphSubstitutionCollection collection, Tag feature, ushort index, int count) => false;
public bool TrySubstitution( FontMetrics fontMetrics, GSubTable table, GlyphSubstitutionCollection collection, Tag feature, ushort index, int count) { foreach (LookupSubTable subTable in this.LookupSubTables) { if (subTable.TrySubstitution(fontMetrics, table, collection, feature, index, count)) { // A lookup is finished for a glyph after the client locates the target // glyph or glyph context and performs a substitution, if specified. return(true); } } return(false); }
public void ApplySubstitution(FontMetrics fontMetrics, GlyphSubstitutionCollection collection, KerningMode kerningMode) { for (ushort i = 0; i < collection.Count; i++) { // Choose a shaper based on the script. // This determines which features to apply to which glyphs. ScriptClass current = CodePoint.GetScriptClass(collection.GetGlyphShapingData(i).CodePoint); BaseShaper shaper = ShaperFactory.Create(current, kerningMode); ushort index = i; ushort count = 1; while (i < collection.Count - 1) { // We want to assign the same feature lookups to individual sections of the text rather // than the text as a whole to ensure that different language shapers do not interfere // with each other when the text contains multiple languages. GlyphShapingData nextData = collection.GetGlyphShapingData(i + 1); ScriptClass next = CodePoint.GetScriptClass(nextData.CodePoint); if (next is not ScriptClass.Common and not ScriptClass.Unknown and not ScriptClass.Inherited && next != current) { break; } i++; count++; } // Assign Substitution features to each glyph. shaper.AssignFeatures(collection, index, count); IEnumerable <Tag> stageFeatures = shaper.GetShapingStageFeatures(); int currentCount = collection.Count; SkippingGlyphIterator iterator = new(fontMetrics, collection, index, default); foreach (Tag stageFeature in stageFeatures) { List <(Tag Feature, ushort Index, LookupTable LookupTable)> lookups = this.GetFeatureLookups(in stageFeature, current); if (lookups.Count == 0) { continue; } // Apply features in order. foreach ((Tag Feature, ushort Index, LookupTable LookupTable)featureLookup in lookups) { Tag feature = featureLookup.Feature; iterator.Reset(index, featureLookup.LookupTable.LookupFlags); while (iterator.Index < index + count) { List <TagEntry> glyphFeatures = collection.GetGlyphShapingData(iterator.Index).Features; if (!HasFeature(glyphFeatures, in feature)) { iterator.Next(); continue; } featureLookup.LookupTable.TrySubstitution(fontMetrics, this, collection, featureLookup.Feature, iterator.Index, count - (iterator.Index - index)); iterator.Next(); // Account for substitutions changing the length of the collection. if (collection.Count != currentCount) { count = (ushort)(count - (currentCount - collection.Count)); currentCount = collection.Count; } } } } } }