Let a composite font's identifiers reach its glyphs through the charset - #15
Merged
Conversation
tannevaled
force-pushed
the
bounded-clip
branch
from
August 27, 2026 08:11
adc1e9a to
a0f0cd7
Compare
tannevaled
force-pushed
the
cid-through-charset
branch
from
August 27, 2026 08:11
0628c9d to
2be4b38
Compare
tannevaled
force-pushed
the
bounded-clip
branch
from
August 27, 2026 08:58
a0f0cd7 to
307b75d
Compare
How an identifier reaches a glyph depends on which sort of program carries them. A TrueType-based one says so in a map of its own, and where it says nothing the identifier is the glyph number. A CFF one addressed by identifier says nothing of the kind: the mapping lives in the font program's own charset, and the map a document may supply is defined only for the other sort. This took the identifier for the glyph number in both cases. That is wrong in the worse of the two ways: past the end of the font it draws nothing, but inside it — which is the usual case — it draws a real glyph and the wrong one. Measured over 5 999 corpus files: of 85 CFF fonts addressed by identifier, 38 have a charset that is not the identity. Of the glyphs those fonts were asked for by the pages that use them, 11 148 came out the wrong glyph, 467 right and 17 blank. Ninety-six in every hundred, silently. Twenty-one of 3 040 sample pages change. Put beside macOS's own renderer, the worst of them goes from a page of scattered fragments to a page of text, and its distance from the reference falls from 0.0312 to 0.0196. An identifier the font does not name now draws nothing, rather than whichever glyph happens to carry that number. The test builds a font addressed by identifier whose one drawable glyph answers to identifier 100 and is glyph 1, so that a reader taking one for the other looks for glyph 100 in a font of two and draws nothing. It fails without the change and passes with it. Found by a licence-aware reading of the mature implementations, which this fleet had never done.
tannevaled
force-pushed
the
cid-through-charset
branch
from
August 27, 2026 08:59
2be4b38 to
5694778
Compare
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.
How an identifier reaches a glyph depends on which sort of program carries them.
This took the identifier for the glyph number in both cases — wrong in the worse of the two ways. Past the end of the font it draws nothing; inside it, which is the usual case, it draws a real glyph and the wrong one.
Measured over 5 999 corpus files
96 in every hundred, silently. The blank pages that first drew attention to this are the small half of the problem.
What it looks like
21 of 3 040 sample pages change. The worst goes from a page of scattered fragments to a page of text, and its distance from macOS's own rendering falls 0.0312 to 0.0196. Two of three spot-checked pages moved closer; the third by 0.0002 the wrong way, within the sparse-page blind spot of that metric.
An identifier the font does not name now draws nothing, rather than whichever glyph happens to carry that number.
The test
There was no scaffolding for this: the existing composite-font tests build TrueType-based fonts, where the defect is invisible. So the test builds a CID-keyed CFF whose one drawable glyph answers to identifier 100 and is glyph 1 — a reader taking one for the other looks for glyph 100 in a font of two and draws nothing.
It fails without the change and passes with it.
Needs
go-opentype/opentypev0.10.0, which exposes the charset (opentype#32, merged).Found by a licence-aware reading of the mature implementations — pdf.js, PDFBox, pdfcpu, qpdf, pypdf, all Apache/BSD, no code copied — which this fleet had never done.
Stacked on
bounded-clip. 100% statement coverage,go vetandgofmtclean, nine cross-compile targets.