Measure text with real font metrics, supplied by the caller - #23
Merged
Conversation
A template names typefaces and carries none; the PDF it travelled in carries them. So the font set is an argument and not a dependency: Face is two methods, Typeface is a family's four faces, and FontSet is an ordered map with FontFinder.find over it (fonts.js:90-155), pass for pass, including the ordered alternation its strip pattern really is. text.go grows the branch it had been written around. addString with a face is text.js:175-206 — advances in thousandths of an em scaled by the written size, a line height from the face's own vertical metrics and a first line that is that height less the gap. compute is untouched: it is the same function in both regimes, which is why real metrics reach the layout without moving the line breaking or the arithmetic above it. The stack under it is FontInfo and FontSelector folded together, with the replacement that decides everything: when the typeface is not found the WHOLE of xfaFont goes, size included, so a draw asking for Wingdings at 14pt is measured at ten points. A rich text's spans push their own font, inheriting each of the five values they leave falsy. leafsize.go resolves a leaf's <font> the way layoutNode does — its own, else the nearest above it in the template (html_utils.js:232-241) — and reads <para lineHeight>, which nothing could read before. Place is unchanged and passes no fonts, so v0.18.0's numbers stand; PlaceWithFonts is the new door. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A control run before anything was measured: PlaceWithFonts(form, nil) must reproduce v0.18.0 across the corpus, and it did not. Seven forms differed, all on letterSpacing="-0.002em" — 24 draws of ca-cra t1206 and t1207 — because this package reads a length strictly, following pdfium, and a strict reading of a relative unit stopped the leaf, its row and every sibling below it. Four forms lost their whole table. pdf.js reads every length with getMeasurement (utils.js:78-102), which drops a unit it does not know and keeps the number, and that function is now ported properly: unanchored, so it finds a number wherever it first appears, and with a default for a string holding none. styleMeasure is it with a default of nought, so the CSS reader is the same code. A FONT's two lengths take the lenient path; x, y, w and h stay strict. With that, all 560 forms are byte-identical to v0.18.0 with no fonts. The tests found one more: stripQuotes on a string of a single quote is "" in JavaScript and a panic in Go. 100% of statements, with XFACORPUS unset. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tannevaled
added a commit
that referenced
this pull request
Sep 5, 2026
…red (#24) Two measurements this repository could not make, and one number it published that a sharper instrument contradicts. THE SHEET. Every judge here compares a box — its x, and the sheet it landed on with its y — and none of them compares the sheet itself. v0.18.0 moved 378 leaves onto correctly oriented sheets and not one figure in corpus_test.go changed by a unit, because a leaf at the same (sheet, x, y) on a 612x792 sheet and on a 792x612 one counted as agreement. TestSheetsAgainstPdfium asks both halves. The SIZE is the weak one: 528 of the 559 forms give every page area of a form the same medium, so a sheet opened on the wrong page area is still the right size. Over the corpus the size agrees on 3 035 of 3 035 sheets, the largest disagreement in either dimension being 0.0000 pt — and v0.18.0's reported residue of "7 sheets whose size disagrees" was 7 FORMS tying at the fourth decimal, 1008.0 against 1008.0001, not a disagreement about paper at all. Which PAGE AREA a sheet was opened on has no such blind spot, and it finds ten sheets on three forms: us-uscis__g-1055 6, i-956g 3, i-956 1 — the three forms #21 and #23 left open, counted for the first time. placer.sheetAreas records it here and the probe reads it from GetPage(i)'s form node there, so it is known even on the 91 sheets of g-1055 whose page area draws no furniture. Neither side reads it off the geometry being judged. THE LINE COUNT. doc.go's "same line count as pdfium 25.9% / 82.5%" was not a line count: it was (our height less pdfium's) over OUR line height, bucketed. The proxy flatters, because a leaf that disagrees on the number of lines AND on how tall a line is can come to the same height. pdfium's probe now reports its own line count per leaf, and the answer is 23.2% and 76.3%. 1 002 leaves the proxy scored as agreeing take a different number of lines — fw9's Page4.Col2.F among them, four lines of 9 pt here against pdfium's three of 12. Where the counts do agree the whole residue is the FIRST line: 5 372 of 5 373. Our height for every line after the first is pdfium's to a hundredth of a point on 1 177 of 1 178. pdfium makes the first line the font size; pdf.js makes it the face's line height less its gap, and this follows pdf.js — so that one is a disagreement with pdfium and not a defect against the reference. Nothing in the measurement is changed for it. The layout does not move: all 560 forms are byte-identical before and after. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.
Text measured with real font metrics, with the fonts supplied by the caller.
xfakeeps its zero dependencies. A template names typefaces and carries none;the PDF it travelled in carries them; this package reads neither. So the font
set is an argument:
Faceis two methods — an advance in thousandths of an em, and theface's vertical metrics.
Typefaceis one family's four faces.FontSetis an ordered map of families with pdf.js'sFontFinder.findported over it (
fonts.js:90-155), pass for pass, including the orderedalternation its strip pattern really is:
bolditalicbeforebold,itlast, and a scanner rather than a chain of replacements.
PlaceWithFonts(form, set)is the new door.Placepasses none.No font file is read here.
tools/fontdump, outside the module, wiresgo-opentype/opentype to
Facein about thirty lines.text.gogrows the branch it had been written around:addStringwith a faceis
text.js:175-206.computeis untouched — it is the same function in bothregimes.
Measured, and the font set is named
Fifteen families from
/System/Library/Fonts/Supplemental: Arial, Times NewRoman and Courier New in four faces each, plus Verdana, Tahoma, Georgia, Arial
Narrow, Arial Black and Wingdings. Arial stands in for Helvetica, Myriad Pro,
HelveticaNeueLT Std and Helvetica LT Std. 211 683 of the corpus's 214 011
typeface references reach a family (98.9%).
The unit is a LINE, because pdfium measures with its own files and no
implementation reproduces another's advances in points.
The ten left are the nine pdfium also puts off the paper and
g-1055's oneunpaired leaf.
29 forms improve and one is worse:
us-irs__f6252, by one leaf, where a12 pt heading in HelveticaNeueLT Std wraps for pdfium and not for our Arial
stand-in — and where the old height agreed by accident. Named in the comment.
The control caught a defect before any number was believed
PlaceWithFonts(form, nil)must reproduce v0.18.0 exactly. Seven formsdiffered, on
letterSpacing="-0.002em": this package reads a length strictlyand a strict reading stopped four forms' whole tables. pdf.js reads every
length with
getMeasurement, which drops a unit it does not know; thatfunction is now ported properly and a FONT's two lengths take it. All 560 forms
are byte-identical to v0.18.0 with no fonts.
Gate: 100% of statements with
XFACORPUSunset,go vet,gofmt -lempty,-race, thirteen cross-compile targets,CGO_ENABLED=0,GOWORK=off, Go1.27.1 via
GOTOOLCHAIN. The corpus suite passes with the environment set.Refs #7.
🤖 Generated with Claude Code