# Do the three engines agree on text geometry? Partly, and the part they disagree on is sharply localized. Every other corpus this project checks the engine against is text-free by construction (`crates/harness/src/cases.rs`'s module doc) and the held-out WPT filter (`oracle/suites/normal-flow-pages.mjs`) rejects any page with a text node, so until now nothing had measured whether Chromium, Firefox and WebKit place glyphs closely enough for the geometry vote (`docs/geometry-verification.md`) to run at all. This is that measurement. It builds no layout code. **The short answer.** Line breaking and element geometry are votable; the text fragment rect is not. All three engines broke every line at the same place in both fonts, and the element boxes of a text-bearing page agree at 1/60 px 99–100% of the time. But the rect a text node's own line fragment occupies disagrees systematically: Firefox makes it 1 px taller than the other two almost always, and in the proportional font the three engines never once agreed on a line's width. Loosening the tolerance does not rescue it — the differences are whole-pixel-scale, not sub-pixel. ```mermaid flowchart TD probe["textProbe:
pinned font, 3 engines"] --> lines{"same number
of line fragments?"} lines -- "yes, 100% of the time
in both fonts" --> boxes{"element boxes
within 1/60 px?"} boxes -- "yes, 99-100%" --> ok["element geometry of a
text-bearing page: votable"] boxes --> frag{"text fragment rect
within 1/60 px?"} frag -- "x: yes in Ahem, 81.7% in Lato
width: 96.6% in Ahem, 0% in Lato" --> horiz["horizontal: font-dependent"] frag -- "y and height: 4-9%" --> vert["vertical: no, in either font"] ``` ## What was measured - **Probe**: `docs/dump-format.md` → "Text probe". One request renders a document with a pinned font embedded as a `data:` URL and returns, per engine, the ordinary element dump plus every text node's `Range.getClientRects()` — one rect per line fragment. An engine whose page fell back to a system font fails the request rather than being measured, so no figure here is contaminated by font substitution. - **Cases**: `crates/harness/src/text_cases.rs`, ten categories (`TextCategory::ALL`), each run in both fonts with byte-identical markup. The run below is `enumerated()` plus 60 seeded-random cases at seed `0x7e47`, so 70 cases per font. - **Quantities**: each element's bounding box and per-fragment rects, voted by `crates/harness/src/compare.rs` `vote()`; each text node's fragment count and per-fragment x, y, width and height, voted by `crates/harness/src/trace.rs` `vote_text()`. Both use `Consensus` at `dump::TOLERANCE_PX` = 1/60 px. - **Binary**: `crates/harness/src/bin/text_metrics.rs`. Raw responses are kept under `corpus/text-metrics//.json` (gitignored) so a rerun on other engine versions can be diffed against this one. A text node that produced no line box in any engine — the contents of every `