diff --git a/packages/extraterm-font-ligatures/src/processors/6-3.ts b/packages/extraterm-font-ligatures/src/processors/6-3.ts index 347358ad..893aa546 100644 --- a/packages/extraterm-font-ligatures/src/processors/6-3.ts +++ b/packages/extraterm-font-ligatures/src/processors/6-3.ts @@ -1,6 +1,5 @@ -import { ChainingContextualSubstitutionTable, Lookup } from '../tables.js'; +import { ChainingContextualSubstitutionTable, CoverageTable, Lookup } from '../tables.js'; import { LookupTree, LookupTreeEntry } from '../types.js'; - import { listGlyphsByIndex } from './coverage.js'; import { processInputPosition, processLookaheadPosition, processBacktrackPosition, getInputTree, EntryMeta } from './helper.js'; @@ -40,16 +39,18 @@ export function buildTree(table: ChainingContextualSubstitutionTable.Format3, lo ); } - for (const coverage of table.lookaheadCoverage) { + if (table.lookaheadCoverage.length > 0) { + const glyphsByIndex = coverageTablesToGlyphsByIndex(table.lookaheadCoverage); currentEntries = processLookaheadPosition( - listGlyphsByIndex(coverage).map(glyph => glyph.glyphId), + glyphsByIndex, currentEntries ); } - for (const coverage of table.backtrackCoverage) { + if (table.backtrackCoverage.length > 0) { + const glyphsByIndex = coverageTablesToGlyphsByIndex(table.backtrackCoverage); currentEntries = processBacktrackPosition( - listGlyphsByIndex(coverage).map(glyph => glyph.glyphId), + glyphsByIndex, currentEntries ); } @@ -69,6 +70,13 @@ export function buildTree(table: ChainingContextualSubstitutionTable.Format3, lo }; } } - return result; } + +function coverageTablesToGlyphsByIndex(tables: CoverageTable[]): (number | [number, number])[] { + let glyphsByIndex: (number | [number, number])[] = []; + for (const coverage of tables) { + glyphsByIndex = glyphsByIndex.concat(listGlyphsByIndex(coverage).map(glyph => glyph.glyphId)); + } + return glyphsByIndex; +} diff --git a/packages/extraterm-font-ligatures/src/processors/coverage.ts b/packages/extraterm-font-ligatures/src/processors/coverage.ts index 5d8606c6..ffc7d054 100644 --- a/packages/extraterm-font-ligatures/src/processors/coverage.ts +++ b/packages/extraterm-font-ligatures/src/processors/coverage.ts @@ -25,7 +25,12 @@ export default function getCoverageGlyphIndex(table: CoverageTable, glyphId: num } } -export function listGlyphsByIndex(table: CoverageTable): { glyphId: number | [number, number]; index: number; }[] { +export interface GlyphIdIndex { + glyphId: number | [number, number]; + index: number; +} + +export function listGlyphsByIndex(table: CoverageTable): GlyphIdIndex[] { switch (table.format) { case 1: return table.glyphs.map((glyphId, index) => ({ glyphId, index })); diff --git a/packages/extraterm-font-ligatures/src/processors/helper.ts b/packages/extraterm-font-ligatures/src/processors/helper.ts index 0e6dbc6f..da65c4ac 100644 --- a/packages/extraterm-font-ligatures/src/processors/helper.ts +++ b/packages/extraterm-font-ligatures/src/processors/helper.ts @@ -21,7 +21,7 @@ export function processInputPosition( individual: new Map(), range: [] }; - for (const glyph of glyphs) { + for (const glyph of dedupGlyphs(glyphs)) { nextEntries.push(...getInputTree( currentEntry.entry.forward, lookupRecords, @@ -44,7 +44,7 @@ export function processLookaheadPosition( ): EntryMeta[] { const nextEntries: EntryMeta[] = []; for (const currentEntry of currentEntries) { - for (const glyph of glyphs) { + for (const glyph of dedupGlyphs(glyphs)) { const entry: LookupTreeEntry = {}; if (!currentEntry.entry.forward) { currentEntry.entry.forward = { @@ -76,8 +76,9 @@ export function processBacktrackPosition( currentEntries: EntryMeta[] ): EntryMeta[] { const nextEntries: EntryMeta[] = []; + for (const currentEntry of currentEntries) { - for (const glyph of glyphs) { + for (const glyph of dedupGlyphs(glyphs)) { const entry: LookupTreeEntry = {}; if (!currentEntry.entry.reverse) { currentEntry.entry.reverse = { @@ -100,10 +101,42 @@ export function processBacktrackPosition( } } } - return nextEntries; } +function dedupGlyphs(glyphs: (number | [number, number])[]): (number | [number, number])[] { + if (glyphs.length < 2) { + return glyphs; + } + + const result: (number | [number, number])[] = []; + const singleGlyphs = new Set(); + const pairGlyphs = new Set<[number, number]>(); + + for (const glyph of glyphs) { + if (Array.isArray(glyph)) { + let found = false; + for (const pair of pairGlyphs) { + if (pair[0] === glyph[0] && pair[1] === glyph[1]) { + found = true; + break; + } + } + if (!found) { + result.push(glyph); + pairGlyphs.add(glyph); + } + + } else { + if (!singleGlyphs.has(glyph)) { + result.push(glyph); + singleGlyphs.add(glyph); + } + } + } + return result; +} + export function getInputTree(tree: LookupTree, substitutions: SubstitutionLookupRecord[], lookups: Lookup[], inputIndex: number, glyphId: number | [number, number]): { entry: LookupTreeEntry; substitution: number | null; }[] { const result: { entry: LookupTreeEntry; substitution: number | null; }[] = []; if (!Array.isArray(glyphId)) {