Skip to content

Fix chaining context backtrack matching order#372

Open
lehni wants to merge 1 commit into
foliojs:masterfrom
lineto:fix/chain-context-backtrack-order
Open

Fix chaining context backtrack matching order#372
lehni wants to merge 1 commit into
foliojs:masterfrom
lineto:fix/chain-context-backtrack-order

Conversation

@lehni
Copy link
Copy Markdown

@lehni lehni commented May 20, 2026

The chaining-context lookup (GSUB type 6, formats 1–3) stores backtrack coverage/class/glyph arrays in reverse buffer order per the OpenType spec: backtrack[0] is the glyph immediately before the input, backtrack[1] is one further back, etc. The current matcher feeds the stored order directly to sequenceMatches(-N, …), which iterates forward — so it ends up comparing backtrack[0] against the position farthest from the input. When all backtrack positions accept the same coverage (the common case) the bug is invisible, but rules with distinct positions silently fail to fire.

The fix reverses the backtrack array before matching, in all three chain-context formats.

Test

Added a shaping test using Noto Sans Syriac Estrangela's calt chain rule where:

  • backtrack[0] accepts a mark glyph (uni0731/uni0734/uni0737)
  • backtrack[1] accepts a positional consonant (uni0712.Init/uni0712.Medi/uni071A.Medi)
  • input is uni0713.Fina, substituted to uni0713.FinaWide

Input ܒܱܓ (U+0712 U+0731 U+0713) joins to [uni0712.Init, uni0731, uni0713.Fina]. Per spec the rule fires and produces uni0713.FinaWide (matching HarfBuzz); without the fix fontkit leaves uni0713.Fina unsubstituted.

- Backtrack arrays are stored in reverse buffer order per OT spec
- Reverse before matching so backtrack[0] aligns with position before input
@lehni lehni force-pushed the fix/chain-context-backtrack-order branch 4 times, most recently from 22cd36c to 789c8bd Compare May 20, 2026 10:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant