mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-24 18:17:44 -06:00
#2305 fixed WinAnsi 0xAD in `crates/fonts`, and closed with two loose ends it named: the user-visible extraction path goes through hayro, not that table, so it still reported the invisible character; and the same Annex D.2 note makes 0xA0 the `space` glyph. This finishes both, and makes the two tables in the product agree about the same byte. WinAnsiEncoding gives codes 0xA0 and 0xAD the glyph names `space` and `hyphen` -- the names it also gives 0x20 and 0x2D -- and MacRomanEncoding gives 0xCA `space`. The tables called them `nbspace` and `sfthyphen`, whose Adobe Glyph List values U+00A0 and U+00AD are invisible formatting characters, so extraction hid ink the reader can see: "well-known" drawn with the 0xAD byte matched no search and no redaction pattern, and a non-breaking space did not match the space a reader typed. Evidence. Two sources transcribe the table the same way (an Annex D implementation's docs, and the WinAnsi.enc encoding vector R ships, which gives `/space` at octal 240 and `/hyphen` at 255), and a black-box check settles the rest: on a synthetic fixture pdftotext reads the base-encoded codes as `a-b a b`, and keeps U+00AD for a code an explicit `/Differences` names `sfthyphen`. We now do both. Over the 989-file pdf.js corpus the soft hyphens we extract fall from 117 to 13 and the non-breaking spaces from 30 to 26; everything left comes from `/ToUnicode` maps, which say what they mean and are not touched. Scope. The base table only, in the text direction only. - A `/Differences` entry naming `sfthyphen` or `nbspace` is a deliberate statement about one code and keeps its glyph list value, as pdftotext does. - Glyph lookup is untouched, so a font program's own `sfthyphen` program is still found first. In hayro that is why the alias sits in the Unicode path rather than in the generated encoding table: `code_to_ps_name` is shared with lookup. - Writing is unaffected: `encode` takes the lowest code showing a character, so ' ' and '-' still write 0x20 and 0x2D, and a caller holding a literal U+00A0 still writes 0xA0. Tests. `fonts` pins both tables and the whole decode/encode path including the `/Differences` case; `render` pins the extraction a reader actually gets, over WinAnsi, MacRoman and `/Differences`. Each was watched failing with each cell and each match arm reverted in turn, so no assertion is passing by accident. fonts 70, render 296+4, redact 49, a11y 43 and edit 156 are green, with fmt, clippy, `xtask layers` (37 crates) and `xtask assets` clean. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>