Repository navigation
feat(core,fonts): font coverage — M4 4.2 - #33
Merged
Merged
Conversation
Shaping asks what a font did with a letter it has. This asks the question underneath it: has the font got the letter at all? A font with no shaping tables renders Arabic as disconnected letters; a font with no Arabic renders it as a row of empty boxes, and no shaping table would have saved it. "Install a font" is the wrong advice for the first and the only advice for the second, so they are separate modules reporting separate facts. A font is judged only over the characters it answers for. The Latin, the European digits and the ASCII punctuation of a mixed paragraph are drawn by the other font slot, so reporting an Arabic font for having no Q would be reporting a font for text it was never asked to draw — ADR 0004's first failure mode through a new door. Format characters are out because they are meaning rather than shape: no font draws U+0600 ARABIC NUMBER SIGN, and a check that said otherwise would report every font there is. Presentation forms are out because pre-shaped text is already a blocking defect with a repair of its own, and a second finding there would be the tool arguing with itself about one character. Missing characters come back named. charname.rs is the Arabic script's Unicode names, generated by scripts/make-char-names.py from the UCD Python itself ships — no network, no third-party module — and refreshed by make names. It answers None outside the four logical-order Arabic blocks rather than inventing a name, which is the refusal joining::JoiningType::Unstated already makes, and coverage::judges is built on it. The rest is not the domain's. ports::FontSource takes a family name and answers with bytes; mirsam-fonts implements it over the platform's font directories; mirsam-core still opens nothing and invariant 1 holds. The index reads each file's naming table alone rather than the file — 690 families in 118 ms on macOS instead of half a gigabyte of outlines — and a family nobody has is an answer, not an error. Two things real fonts taught that the specification did not. macOS states English family names in Mac Roman and keeps the Unicode records for the localisations, so refusing the legacy encoding leaves Helvetica.ttc naming itself nothing at all; Mac Roman agrees with ASCII below 0x80 and diverges above it, so an all-ASCII record is decoded exactly and anything else is left unread rather than guessed at. And a family is spread over files that all state the family name, so a document saying Arial means the regular face: taking the first match gives Arial Bold Italic.ttf, which on this machine has no Arabic while Arial.ttf has. bold.ttf joined the font fixtures so that regressing on that fails a committed test rather than a user's deck. Nothing in the audit path calls any of this yet. Turning a coverage report into a finding is 4.3's decision, and Coverage::covers_nothing is deliberately the only conclusion the evidence supports on its own. Validated beyond the fixtures against macOS: Helvetica and Comic Sans MS come back missing every Arabic letter of the text, Times New Roman and Geeza Pro come back complete, Mishafi shapes perfectly and lacks only Persian peh and Urdu tteh, and Arial resolves to Arial.ttf with complete coverage and four joins of five — ADR 0008's reh, still not a defect.
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.
Shaping asks what a font did with a letter it has. This asks the question underneath it: has the font got the letter at all?
A font with no shaping tables renders Arabic as disconnected letters; a font with no Arabic renders it as a row of empty boxes, and no shaping table would have saved it. "Install a font" is the wrong advice for the first and the only advice for the second, so they are separate modules reporting separate facts.
What a font is judged over
Only the characters it answers for. The Latin, the European digits and the ASCII punctuation of a mixed paragraph are drawn by the other font slot, so reporting an Arabic font for having no
Qwould be reporting a font for text it was never asked to draw — ADR 0004's first failure mode through a new door.Two exclusions inside that:
By name
charname.rsis the Arabic script's Unicode names, generated byscripts/make-char-names.pyfrom the UCD Python itself ships — no network, no third-party module — and refreshed bymake names. A finding readsU+067E ARABIC LETTER PEH, notU+067E. It answersNoneoutside the four logical-order Arabic blocks rather than inventing a name, which is the refusaljoining::JoiningType::Unstatedalready makes.The port and its adapter
ports::FontSourcetakes a family name and answers with bytes;mirsam-fontsimplements it over the platform's font directories.mirsam-corestill opens nothing and invariant 1 holds. The index reads each file's naming table alone rather than the file — 690 families in 118 ms on macOS instead of half a gigabyte of outlines — and a family nobody has is an answer, not an error.Two things real fonts taught that the specification did not
Helvetica.ttcnaming itself nothing at all. Mac Roman agrees with ASCII below 0x80 and diverges above it, so an all-ASCII record is decoded exactly and anything else is left unread rather than guessed at — a wrong name is worse than a missing one, because it resolves.Arialmeans the regular face. Taking the first match givesArial Bold Italic.ttf, which on this machine has no Arabic whileArial.ttfhas.bold.ttfjoined the font fixtures so that regressing on this fails a committed test rather than a user's deck.The boundary this does not cross
Nothing in the audit path calls any of this yet. Turning a coverage report into a finding is 4.3's decision, and
Coverage::covers_nothingis deliberately the only conclusion the evidence supports on its own.Validation
cargo testruns coverage against the hand-built fonts, which map U+0621..U+064A and nothing else, so every boundary the check draws shows up as a character the fixture has or has not got — and the four fonts agree about coverage exactly while disagreeing about shaping.mirsam-fontsresolves a family name to bytes and proves it got the right file by shaping through it.Beyond the fixtures, against macOS:
Arial.ttf, complete, four joins of five — ADR 0008's reh, still not a defectmake verifypasses.