M7: read each grouped form once and check PUA alternate meanings

Change:
- Leave a form found to be artwork, or refused for a reason in the form
  itself, out of later preparation passes, so a page with many logos or
  unsupported groups no longer reaches the 64-placement limit and prepares
  nothing. ungroup_ops now marks each refusal as intrinsic or contextual;
  contextual ones (translucency, the resources it would merge into, pattern
  placement, the decode budget) are re-evaluated where the form appears, so
  a form refused in one place is still prepared where a parent draws it.
- Refuse a page-level Do with an operand too many for that placement only:
  the form found by its first operand may not be the one drawn. Check a
  form's own operand counts before the nested walk, as an intrinsic refusal.
- Use the Windows PUA alternates only when every kept alternate whose code
  the PDF's map names a Thai character names that alternate's base
  character, so alternates in another order that the map reveals are refused.

Chores:
- Say that the font program confirms each recovered glyph's advance class,
  not its identity, and document the alternate check.

Validation: with and without craft-fonts, fonts 105 (+3 build-input), edit
468, engine 482 (+28 integration) and automation 50 + 352 passed; editor flows
248 passed. Formatting, strict Clippy, layers, assets and parity passed; the
wasm check was not run locally. Each new regression failed with its fix
reverted. Real-PDF edits on Royal Gazette 26288 kept their source fonts.
This commit is contained in:
xullul committed 2026-11-07 17:00:48 +07:00
1 parent 7634ac8064
commit a453112151
5 files changed
+176 -37

No files matched your search

+2 -1
View File
@@ -86,7 +86,8 @@ selects for Thai, not just a GPOS table); GSUB substitution is optional, as spec
[the OpenType Thai model](https://learn.microsoft.com/en-us/typography/script-development/thai).
Verified legacy Thai PUA fonts use positional substitutions instead of requiring GPOS; their
alternates are used only when each kept one has a mark's zero advance (or, for the two
consonant forms, an advance). A THSarabunPSK program with its own Thai mark
consonant forms, an advance) and, where the PDF's own map names its character, the character
that alternate stands for. A THSarabunPSK program with its own Thai mark
positioning, such as a complete face loaded with Load font, is shaped by that layout instead,
still in its own codes. One without it takes the legacy path only when every Thai glyph it keeps
is where the legacy glyph order puts it, and is otherwise shaped as an ordinary source font. A