Status: Reference (current as of 2026-08-18)
When Donner's rendering of a resvg-test-suite case is correct but the upstream golden is not the right thing to compare against, the test pins Params::WithGoldenOverride("donner/svg/renderer/testdata/golden/resvg-<name>.png") so it compares against a Donner-blessed golden instead. This doc is the catalog of every such override and the reason it exists.
There are two distinct reasons an override is justified:
Custom goldens live in donner/svg/renderer/testdata/golden/resvg-<test-name>.png, named with the new (post-Great-Rename) test stem. The rationale for each is the .withReason("…") argument chained onto the override in resvg_test_suite.cc — grep the test name there to find it inline.
Naming note: these used the old a-* / e-* convention before the suite upgrade (0022). The four originally documented here mapped forward as: a-filter-013/a-filter-015 → drop-shadow-function-mm-values/drop-shadow-function-em-values (now parked, see below); e-marker-045/e-marker-051 (closed-shape / cusp marker direction) were superseded upstream and retired — the surviving marker override is orient=auto-on-M-C-C-4.
Filter Effects 1 specifies that a missing or non-filter URL disables the complete filter chain, leaving the object unfiltered (published definition, editor's draft). Two historical PNGs encode different behavior:
Both files are reference-disagreement skips against those PNGs. Independently authored pixel tests in FilterReferenceStages_tests.cc require unchanged visible leaf and group geometry for missing and non-filter references, including functions on both sides of a bad URL. No replacement golden or enlarged tolerance is used. Empty valid filters are covered separately and remain transparent.
filters/filter/complex-order-and-xlink-href.svg filters a rect through a filter that inherits its blur and height through xlink:href and sets its own x, so the filter region cuts the blur's input at its left and bottom edges. The vendored reference now is resvg v0.49.0's 300x300 rendering; the snapshot's reference had been flattened onto white (see third_party/resvg-test-suite/BUILD.bazel). Against it, Donner's region geometry and its free blur edges match. The remaining pixels (1,275 on TinySkia; Geode adds 3 frame-corner pixels) lie within 5 px of the two clipped edges: resvg approximates the blur with five box passes over a region-sized buffer, and each pass drops what spreads past the buffer, so the first row and column inside read alpha 84. Donner keeps that spill and reads 143, close to the 144 of a single Gaussian of the clipped input. The row is a reference-disagreement skip; a raised pixel budget would keep the rest of the case compared, but needs a maintainer decision. RendererRegressionTests.FilterHrefRegionClipMatchesClippedSourceBlurredWithRoom requires the clipped render to equal the visible part of the rect blurred with room around it.
| Category | Test | Reason (withReason) |
|---|---|---|
| filters/feSpotLight | complex-transform | resvg bug: SpotLight Y |
| filters/feImage | svg | We render higher quality |
| filters/feSpecularLighting | with-fePointLight | resvg golden |
| painting/context | with-pattern-objectBoundingBox-in-use | resvg golden bakes fractional-tile rounding |
| painting/marker | orient=auto-on-M-C-C-4 | Pre-existing rendering diff (stroke/AA), not cusp-related |
| painting/marker | with-an-image-child | We (correctly) render the image child |
| painting/paint-order | on-tspan | Preserve cross-span kerning across a paint-only tspan boundary |
| text/font-size | named-value | Donner uses CSS Fonts Level 4 |
| text/font-size | named-value-without-a-parent | Donner uses CSS Fonts Level 4 |
named-value{,-without-a-parent} reflect CSS Fonts Level 4's revised handling of named font sizes (xx-small … xx-large), which differs from resvg's older table.
with-pattern-objectBoundingBox-in-use runs against a committed Donner render (resvg-with-pattern-objectBoundingBox-in-use.png), shared by both backends (TinyGolden and GeodeGolden pass at the default budget). Evidence that resvg's golden is the artifact: resvg rasterizes pattern tiles at a rounded integer pixel size, and this test's context bounding box yields a fractional 56.57px on-screen tile that resvg draws as 57px, stretching the tile period by ~0.8%. Donner repeats the tile at the exact period. A numeric grid fit confirms it: Donner's render fits an ideal diamond grid anchored at the computed context box (31.82, -116.67), 226.27² with score 1.0, while resvg's golden fits no ideal grid (best score 0.899 — its grid drifts, consistent with per-tile rounding). The integer-tile pattern goldens in the same category (with-pattern-in-use, with-pattern-and-transform-in-use, with-pattern-on-marker, whose tiles land on exact pixel sizes) match Donner exactly, isolating the discrepancy to the fractional-tile case. Revisit if resvg regenerates goldens without the rounding.
CSS Images permits an implementation-selected edge-preserving algorithm for crisp-edges; deprecated optimizeSpeed maps to that value. An alternate nearest sampling grid does not establish that the upstream reference violates the specification.
| Category | Test | Reason |
|---|---|---|
| painting/image-rendering | on-feImage | Nearest sampling at destination pixel centers |
The project reference retains all vendored reference pixels outside the image primitive. Inside, the decoded 64 x 64 RGBA source is sampled with source_index = floor((destination_index + 0.5) * 64 / destination_extent). The default filter region expands the (40, 40, 120, 120) object box by 10% on each side, producing (70, 70, 360, 360) after the 500 / 200 viewport scale. All 129,600 image-region pixels follow this independent geometric construction. The separate optimizeSpeed fixture compares against its resvg v0.49.0 rendering, which TinySkia matches. Geode stays disabled for it: at 3.75 device pixels per texel, every second texel boundary falls on a pixel center, and Geode's interpolated texture coordinate lands just below it where tiny-skia's float inverse transform lands on it, so Geode picks the previous texel. All 564 differing pixels are inside the image; this is a sampling-position rounding difference, not missing SVG support.
These render correctly but differ from resvg because Donner's text stack (and the simple-vs-text-full split) shapes/composes differently. The golden is whichever Donner backend the test runs under.
| Category | Test | Reason |
|---|---|---|
| text/text | complex-graphemes-and-coordinates-list | Simple text can't compose combining marks |
| text/text | compound-emojis-and-coordinates-list | Emoji bitmap scaling differs from the golden |
| text/text | rotate-on-Arabic | Arabic shaping requires text-full |
| text/text | x-and-y-with-multiple-values-and-arabic-text | Arabic shaping; vertical-axis AA diff not the focus |
The text/textPath family carries the bulk of the overrides: sub-pixel character advance and anti-aliasing differences along curved baselines, which differ between the simple and text-full backends. All are .withReason("Minor char") unless noted.
| Category | Test | Reason |
|---|---|---|
| text/textPath | dy-with-tiny-coordinates | AA + minor char advance diffs (text vs text-full) |
| text/textPath | m-L-Z-path | Minor char |
| text/textPath | mixed-children-1 | AA diffs |
| text/textPath | nested | Minor char |
| text/textPath | path-with-ClosePath | Minor char |
| text/textPath | simple-case | Minor char |
| text/textPath | startOffset=-100 | Minor char |
| text/textPath | startOffset=10percent | Minor char |
| text/textPath | startOffset=30 | Minor char |
| text/textPath | startOffset=5mm | Minor char |
| text/textPath | tspan-with-absolute-position | Minor char |
| text/textPath | tspan-with-relative-position | Minor char |
| text/textPath | two-paths | Minor char |
| text/textPath | very-long-text | AA diffs |
| text/textPath | with-baseline-shift | Minor char |
| text/textPath | with-coordinates-on-text | Minor char |
| text/textPath | with-coordinates-on-textPath | Minor char |
| text/textPath | with-rotate | Minor char |
| text/textPath | with-text-anchor | (no reason string) |
| text/textPath | with-transform-on-a-referenced-path | Minor char |
| text/textPath | with-transform-outside-a-referenced-path | Minor char |
| text/textPath | with-underline | Minor char |
| text/text-decoration | indirect | (no reason string) |
Two entries (textPath/with-text-anchor, text-decoration/indirect) carry no withReason. They should either get one or migrate to a per-test threshold; the "Minor char" cluster is the precedent. Tracked in 0021.
resvg-drop-shadow-function-mm-values.png and resvg-drop-shadow-function-em-values.png are the migrated successors of the old a-filter-013 / a-filter-015 drop-shadow blur-halo cases: Donner's three-pass box-blur approximation (correct per CSS Filter Effects L1 §8 / SVG §15.9) produces a different halo shape than resvg's blur, so a Donner golden is required.
They are currently unreferenced. The filters/filter-functions category is active, with 26 of 43 files comparing on both backends and 17 explicit Triage: skips. No project-owned oracle has been accepted for the two unit-based drop-shadow cases yet. Keep both files until normative specification/browser triage decides whether each mismatch is a Donner defect, a vendored-oracle difference, or a justified project golden. Do not delete them as "orphans".
Three goldens added by #515 were never referenced by any override and were removed as dead data (recoverable from git history if a real override need surfaces):
The corresponding text/font-size tests pass against the upstream golden — only named-value{,-without-a-parent} need an override. After this cleanup the golden/ dir holds exactly 39 resvg-*.png: 37 active + the 2 parked drop-shadow goldens above.