Chromium vs WebKit Glyph Rasterization in Map Labels
Feed two engines the same style, the same camera, the same tiles and the same font file, and their labels still differ — not randomly, but by a consistent offset along every glyph edge in the frame. Teams meet this as a mysterious 2% diff that a looser threshold seems to almost fix, and the almost is the problem: the tolerance needed to absorb it is large enough to hide a dropped label. This page explains where the difference comes from, which layer of it a flag can remove, and what the remainder means for how the two engines are compared.
This is a task within Cross-Browser Baseline Matrix, under CI/CD & Visual Testing Operations. The environment pinning it assumes is built in Containerized Rendering Environments for Map Tests.
Prerequisites
Where the difference comes from
Text becomes pixels in three stages, and the engines agree on only the first.
Shaping turns a string and a font into positioned glyph outlines, applying kerning, ligatures and script rules. Both engines implement the same specifications here, and given the same font they produce the same outlines in the same places. This is why a label never lands on a different feature or in a different order between engines.
Hinting adjusts those outlines so their stems and baselines land on pixel boundaries. Each engine ships its own hinting implementation, with its own default level, and the adjustments differ by fractions of a pixel per glyph. Because the adjustment is a function of the outline and the grid, it is consistent — the same glyph at the same size gets the same treatment every time on that engine, and a different one on the other.
Rasterisation converts the hinted outline into coverage values. The engines use different anti-aliasing filters, so even identical outlines produce slightly different edge pixels.
The systematic nature of all this is what makes it resistant to thresholds. Random noise averages out and stays small; a consistent per-glyph offset applied to every label in a dense frame accumulates into a large, structured delta that is indistinguishable in magnitude from a real cartographic fault.
What configuration can and cannot remove
Disabling hinting removes the largest single contributor, and Chromium exposes flags for it:
--font-render-hinting=none
--disable-lcd-text
--disable-font-subpixel-positioning
Two things about this are commonly misunderstood. First, disabling hinting does not make WebKit match Chromium — it changes what Chromium draws, so both engines’ baselines move and the gap narrows rather than closing. Second, WebKit does not expose an equivalent switch, so the two engines end up at different points on the same axis rather than at the same point.
What remains after the flags is the anti-aliasing filter and subpixel positioning, neither of which is configurable. That residue is the reason the matrix has an engine axis at all.
What the per-engine baseline is left holding
The practical rule that follows is worth stating plainly: compare each engine against its own golden, and never compare the engines against each other except as a diagnostic. A pairwise engine diff is a useful measurement when investigating — it tells you how far apart the two are and whether a change moved them closer or further — and it is not a gate, because there is no threshold at which “these two engines agree” is a meaningful assertion.
That also settles a question that comes up early: whether to run fewer engines to avoid the multiplication. The answer is that the engine axis should contain exactly the engines the product ships to and someone can name a bug in. Running an engine because it is available adds a full set of baselines, a full set of re-blesses and a full share of review load, in exchange for coverage of a rendering path nobody uses.
Verification
Confirm the procedure worked before wiring it into a blocking gate:
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The engines differ across the whole frame, not just labels | Something other than text is diverging — usually the GL backend, since only Chromium accepts the software-rasteriser flags | Check the fill and line region classes; a divergence there is an environment problem, not a text one |
| The gap between engines varies between runs | A font is being resolved differently on one of them, so shaping is producing different outlines rather than hinting adjusting the same ones | Verify the exact font files are present in both images; a fallback changes label metrics, not just their edges |
| Disabling hinting made the diff worse | The baselines were blessed with hinting on, so the flag change moved the reference engine away from its own golden | Re-bless both engines after the flag change; it is an environment change and needs the same treatment as any other |
Frequently asked questions
Can one engine's baseline ever be reused for another?
Only for scenes containing no vector text and no vector geometry — a pure raster tile view, typically. That case is worth measuring for, because it collapses three cells into one, and the procedure is the hash-agreement audit described in Maintaining Per-Engine Baselines for Leaflet and OpenLayers. Adding a single label to a collapsed scene invalidates the collapse.
Does the same reasoning apply to Firefox?
Yes, with a third set of values. Firefox has its own text stack and its own compositor rounding, so it sits at a third point rather than near either of the others. Nothing about the analysis changes; the practical difference is that its divergence from Chromium is often larger than WebKit’s, which surprises teams who expect the two non-Chromium engines to cluster.
Should hinting be disabled at all, then?
Usually yes, for a reason unrelated to cross-engine comparison: it removes a source of within-engine variation across host font configurations, which makes each engine’s own baseline more portable between machines. Treat it as an environment-determinism measure that happens to narrow the cross-engine gap, rather than as a cross-engine fix.
How large a divergence is normal between Chromium and WebKit?
On a label-dense frame at high zoom, one to three percent of pixels changed is typical with hinting disabled and the same fonts in place. Much more than that usually means a font difference rather than a rasterisation one; much less usually means the frame does not contain enough text for the measurement to say anything.
Related
- Up to Cross-Browser Baseline Matrix, and the section CI/CD & Visual Testing Operations.
- Chromium vs WebKit vs Firefox MapLibre Rendering Divergence — the wider engine comparison this drills into.
- Pinning Fonts and GPU Backend in a Playwright Docker Image — making the font stack identical before comparing anything.
- Per-Region Tolerance Classes for Map Interfaces — scoring label pixels separately from fill pixels.