Repository navigation
Continue after the glyphs a lookup matched or inserted - #398
Merged
blikblum merged 2 commits intoOct 18, 2026
Merged
Conversation
After a lookup applied, fontkit always moved on to the glyph after the one it started at. A multiple substitution was then applied to its own output, and a contextual lookup to glyphs inside its input sequence or inserted by its nested lookups, so fonts like Libre Barcode EAN13 Text ran out of memory (foliojs#383). After a deletion, the following glyph was skipped. Like HarfBuzz, continue after the inserted glyphs, at the glyph that followed a deleted one, and after the input sequence of a contextual lookup, adjusted for the glyphs its nested lookups inserted or deleted.
Likheet
force-pushed
the
fix/383-continue-after-substitution
branch
from
October 13, 2026 03:32
e1e3506 to
fa1cfa1
Compare
Member
|
Many thanks. Just did a small change |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #383.
After a lookup applies,
applyLookupsmoves on to the glyph after the one it started at. HarfBuzz continues after the glyphs the lookup consumed or produced instead, and the difference shows up in three places:sub a by b a;never finishes.applyLookupListresets to the start of the match, so the lookup is tried again on glyphs inside its input sequence and on glyphs its nested lookups inserted. In Libre Barcode EAN13 Text, lookup 82 rewrites a digitDfollowed by an EAN-8 tail aslt.below.quiet guard.normal.ean8 D, then matches thatDagain, until the heap runs out. Before that, lookup 15 also matches an EAN-8 rule inside the EAN-13 sequence it just matched.This continues after the inserted glyphs, at the glyph that followed a deleted one, and after the input sequence of a contextual lookup, moved by the glyphs its nested lookups insert or delete but never before the glyph a nested lookup applied to (as in HarfBuzz's
apply_lookup). Every step now either moves forward or removes glyphs, so a lookup always finishes.Tests:
test/shaping.js: a 1.3 KB font built with fontTools (the feature code is in the test) covers each case, with HarfBuzz's output as the expected results. Onmaster, two of the five run out of memory and the other three give different glyphs or advances.test/issues.js: the font from the issue (OFL, from google/fonts) with the codes from the report. EAN-8 matches HarfBuzz. For EAN-13, five glyphs still differ because of the backtrack order bug that Fix chaining context backtrack matching order #372 fixes; with Fix chaining context backtrack matching order #372 applied too, it matches HarfBuzz exactly.Other fonts run into this as well: with Noto Sans Kaithi (it ships with macOS), any consonant followed by U+110B1 KAITHI VOWEL SIGN I ran out of memory.
To make sure nothing else changes, I shaped about 11,400 strings (a multilingual sample plus random strings from each font's cmap) with 196 fonts that have GSUB or GPOS: the fonts in
test/data, the macOS system fonts, and Google Fonts that lean on contextual lookups (Fira Code, JetBrains Mono, Recursive, Noto Nastaliq Urdu, Scheherazade New, Noto Sans Myanmar, the other Libre Barcode families and more). Compared withmaster, the output changed for 6 strings, all of which ran out of memory before. One now matches HarfBuzz exactly and the other five are closer to it; what's left comes from #372's bug and from the USE shaper's reordering. No string that matched HarfBuzz before differs now.npm testpasses and the changed files are Prettier-clean.