|
|
Donner 0.8.0-pre
Embeddable browser-grade SVG2 engine
|
Status: Living catalog. The CPU-backend (RendererTinySkia) feature gaps and bugs are the active front, and lead this backlog. Geode runs the same resvg Params and thresholds as the CPU variants; backend-specific override tables are not part of the suite policy.
The triage backlog for 0022's Milestone 2 — working through the tests the suite upgrade pulled in and either fixing the underlying gap or recording why a Params::Skip(...) is the correct state. Each entry corresponds to one or more skips/threshold-overrides in resvg_test_suite.cc.
When a gap is fixed, delete its entry here and un-skip the tests in the same PR. Golden overrides (where Donner is right and resvg's golden is wrong) live in 0009, not here.
Conventions:
There are four supported ways the suite records a known gap. All of them must be expressed through the normal Params path close to the affected tests:
| State | Count | Meaning |
|---|---|---|
| Params::Skip("reason") | 234 | Not run. Feature gap or known bug. The bulk of this doc. |
| Params::RenderOnly("reason") | 72 | Rendered, not compared. Used for UB/deprecated cases where no-crash coverage is still useful. |
| Commented-out INSTANTIATE_TEST_SUITE_P | 1 block | filters/filter-functions — whole category dark on CI. See B2. |
| Params::WithThreshold(…, maxPx) / local max-pixel budget | 96 | Passes with an explicit threshold or pixel budget. Large non-text budgets remain suspect; see Masked bugs behind inflated CPU thresholds. |
| Geode-disabled local Params entries | 1 analytic-residual + ~9 CPU-only-feature | The analytic-coverage work closed the former ~16-gate cluster; remaining = 1 feGaussianBlur/complex-transform (#625) + paint-order/0-N-dash tests Geode doesn't implement yet. See Geode coverage (resolved). |
| Count | |
|---|---|
| Params::Skip(...) | 234 |
| Params::RenderOnly(...) | 72 (render-must-not-crash, no pixel compare) |
| WithThreshold / max-pixel overrides | 96 (~15 still over 1000 px -> masked-bug candidates) |
| Geode-disabled local Params entries | 1 analytic-residual + ~9 CPU-only-feature (down from 22; analytic dual-ray landed, see 0041) |
| Commented-out category blocks | 1 (filters/filter-functions) |
Landed 2026-05-25 from a parallel CPU-backend debugging sweep. IDs are burned (not reused).
Highest-value first. "Out of scope" rows are correct-as-skipped and listed at the bottom for completeness.
Recently fixed (PRs #608–#611, in review) — see Recently fixed. F2 (transform-origin regression), B1 (intrinsic sizing), B5 (feMorphology), B6 (feImage resampling) are resolved; their IDs are burned. The rows below are what's left.
| ID | Gap | Impact | Kind |
|---|---|---|---|
| B2 | filters/filter-functions disabled (CI "Data corrupted") | ~30 | CI gap — whole category dark |
| B3 | <image> embedded/data-URL sizing | 13 | Bug — one investigation |
| B4 | <use> → inline <svg> sizing | 5 | Bug (shares machinery with B3) |
| F12 | transform-origin on paint-servers / <image> / text | 2 left | on-text/on-image DONE; paint-servers (gradient/pattern) + on-text-path remain → #621, #624 |
| F3 | context-fill / context-stroke | 13 | Feature |
| F5 | full dominant-baseline keyword set | 14 | Feature |
| F4 | <switch> conditional processing | 12 (+systemLanguage 3) | Feature |
| F6 | full alignment-baseline keyword set | 10 | Feature |
| F7 | paint-order rendering | DONE (7/8) | Rendered on shapes + text; on-tspan residual → #624 |
| F9 | textLength + lengthAdjust stretch/compress | 8 | Feature |
| F10 | textPath SVG2 attributes (path/side/method/spacing) | 8 | Feature |
| F11 | BiDi / RTL text shaping | ~8 | Feature (needs text-full) |
| F8 | primitive subregion clipping (feBlend/feComposite/feFlood) | 5 | Feature |
| B7 | font substitution — missing bundled families (masked by fat thresholds) | ~9 | Triage: bundle fonts vs. document as known gap |
| — | masking edge cases (mask 8, clipPath 6) | ~14 | Mixed |
| — | uncertain Bug? entries (need triage) | ~12 | Needs investigation |
| F1 | enable-background + in=Background* | 23 | Out of scope (deprecated) |
| — | other deprecated/UB skips | ~30 | Out of scope |
Impact: ~30 tests — the entire filters/filter-functions/ block, commented out at resvg_test_suite.cc:1410.
Symptom: The INSTANTIATE_TEST_SUITE_P(FiltersFilterFunctions, …) block is commented out. The category produces "Data corrupted" parse errors on CI x86_64 runners but passes locally on aarch64. (Note: the harmless per-test "Data corrupted" log lines from UrlLoader font fallback are unrelated — this is a parse failure that fails the comparison.)
Root cause: unknown. Candidates: a resvg-test-suite data-integrity issue on CI, an x86_64-specific parser bug, or a runfiles/encoding difference between the runners. This is exactly the CI-vs-local gap the project's always-green-main policy calls out — the fix is to close the gap, not route around it.
Next step: reproduce on an x86_64 runner (or container). Capture the exact SVG that triggers "Data corrupted" and minimize it. These tests were enabled once in #515 before being disabled, so the rendering path works — this is an input/parse problem on one arch. Two custom goldens (drop-shadow-function-{mm,em}-values) are parked for re-enable; see 0009.
These tests pass, but only because maxMismatchedPixels was raised far above the suite default (100). pixelmatch already excludes anti-aliased pixels, so a multi-thousand-px diff on the CPU backend is a real rendering difference. Per CLAUDE.md §"Anti-Aliasing Is Never the Root Cause", "AA drift" is not a valid reason for these magnitudes. The full audit list lives in the test file. B6 (feImage resampling) is now fixed — see Recently fixed; the real cause was a bilinear-vs-bicubic kernel, not the suspected transform bug, and the 3 "transform" tests were never broken (their fat thresholds were over-inflation, now removed). The remaining structural cluster is below.
Impact: ~9 text/font-family/ tests at maxPx 600–5200 (serif 4200, sans-serif 1900, monospace 600, cursive 5000, fantasy 5200, bold-sans-serif 5200, source-sans-pro 1300, font-list 1300, fallback-2 1000), plus text/text/xml-lang=ja (19100, CJK) and structure/defs/ style-inheritance-on-text (6500).
Symptom: the diffs are whole-glyph — Donner substitutes a different font than the golden was rendered with (the suite's cursive/fantasy/CJK families aren't bundled), so every glyph outline differs. This is not a renderer bug; it's a font-availability gap currently silently absorbed by a fat threshold.
Next step (triage decision): either (a) bundle the missing families and tighten the thresholds to default, or (b) reclassify these as explicit Skip("font not bundled: <family>") so the gap is visible instead of hidden. Do not leave them as unexplained fat thresholds. Decide per-family; serif/sans-serif/monospace likely map to already-bundled Noto faces (real diff to chase), while cursive/fantasy are genuinely missing.
The remaining sub-1000-px CPU thresholds (feColorMatrix matrix/saturate variants, feDropShadow, text-decoration rotate-lists, pattern AA) are small enough to be plausible coverage-geometry differences; audit opportunistically but they are not promoted bugs.
B1 (intrinsic sizing + percent on non-square viewBox) is now fixed — see Recently fixed. It was three coupled causes, not just the suspected transformPosition→transformVector (also per-axis percent extent + <marker> % parsing).
Impact: 13 tests in structure/image/ (plus 2 external-URL Not impl, 4 UB RenderOnly).
Symptom: Embedded images (data URLs, embedded JPEG/GIF/SVG) render but at the wrong size; preserveAspectRatio modes (none/xMin/Mid/Max…-meet/slice) and the no-width/no-height/auto sizing cases disagree with the golden.
Root cause: needs investigation — <image> layout/sizing and preserveAspectRatio resolution for raster + nested-SVG content.
Next step: start with preserveAspectRatio=none, then walk the no-width/no-height/auto matrix and MIME-sniffing failures. Shares preserveAspectRatio math with B6 (fixed) and B4.
Impact: 5 tests in structure/use/.
Symptom: <use> of an inline <svg> with various width/height/viewBox combinations sizes the instance wrong.
Next step: likely shares machinery with B3's viewport sizing; investigate together if convenient.
B5 (feMorphology degenerate radius) is now fixed — see Recently fixed.
Impact: 13 tests in painting/context/. Parsed but not honored at render. Used by markers and <use> to inherit the referencing element's paint.
Impact: 12 tests in structure/switch/ (+1 in clipPath). Includes requiredFeatures / systemLanguage evaluation. Related: structure/systemLanguage (3), which F4 should subsume.
Impact: 14 tests in text/dominant-baseline/. Missing before-edge, after-edge, no-change, reset-size, use-script, etc.
Impact: 10 tests in text/alignment-baseline/. Full keyword set + tspan baseline alignment.
Impact: 8 tests in painting/paint-order/. The property name parses but render order (fill/stroke/markers) is not reordered. On shapes, text, and tspan.
Impact: 5 tests (filters/feBlend 2, filters/feComposite 3 incl. feFlood subregion). Filter primitives don't clip output to their x/y/width/height subregion. Overlaps B6 (fixed)'s subregion cases.
Impact: ~8 (text/textLength 4 + text/lengthAdjust 3 + text/text-decoration interaction). Text stretching/compressing to a target length (spacing and spacingAndGlyphs), including the Arabic cases.
Impact: 8 in text/textPath/: path attribute, side=right, method=stretch, spacing=auto, path+xlink:href combinations, filter on textPath, plus the deferred vertical/writing-mode=tb cases.
Impact: ~8 across text/direction (2), text/unicode-bidi (1), text/text/bidi-reordering, text/tspan/bidi-reordering, text/letter-spacing/mixed-scripts, text/textLength Arabic. Needs the BiDi algorithm + RTL shaping (text-full). Group as one workstream.
Impact: 7 tests in structure/transform-origin/ (on-gradient ×2, on-pattern ×2, on-image, on-text, on-text-path), kept skipped after the F2 regression fix.
Symptom: these were never green — they are a separate never-implemented gap, not the #514 regression. Gradients/patterns route their transform through getRawEntityFromParentTransform (SVGGradientElement.cc, SVGPatternElement.cc), which intentionally drops the transform-origin pivot; for <image>/text the layout computes the correct origin (verified) but it doesn't compose with the content-placement transform, so they render off-screen.
Next step: thread the resolved origin pivot through the paint-server and image/text content transforms (the shape path is now correct after #609 — mirror it).
| Category | Tests | Gap |
|---|---|---|
| structure/a | 3 | <a> hyperlink rendering |
| structure/svg | 2 | nested-svg overflow |
| structure/style | 1 | CSS @import / external CSS |
| structure/symbol | 1 | transform on <symbol> (SVG2) |
| painting/image-rendering | 2 | image-rendering (pixelated/crisp-edges) |
| masking/clipPath | 6 | clipPath with <text> children, <use> child, shorthand edge cases |
| masking/mask | 8 | mask-type, mask-units, color-interpolation, mask-on-self |
| text/font | 2 | font shorthand; canvas-size mismatch (test harness) |
| text/tspan | 3 | tspan interaction with clip-path/filter/mask |
| painting/stroke-dasharray | 4 | 0 n dash patterns with caps |
| painting/marker | 4 | multiple closepaths, rounded-rect corners, recursive-5 |
| text/writing-mode | ~6 | writing-mode=tb with dx/dy, vertical-lr/rl edge cases |
These have a question-mark reason in the file and need a root-cause pass to decide bug vs. out-of-scope:
| Category | Tests | Why |
|---|---|---|
| filters/enable-background | 21 | Category default Params::RenderOnly(...): deprecated in SVG 2 (→ <filter> chains / backdrop-filter). See unsupported_svg1_features.md. |
| filters/filter in=Background* | 2 | Same deprecation (BackgroundImage/BackgroundAlpha inputs). |
| text/tref | 9 (+1 display) | <tref> removed in SVG 2. |
| text/kerning | 2 | kerning attribute deprecated SVG 1.1. |
| text/glyph-orientation-* | 2 | deprecated SVG 1.1. |
| paint-servers/radialGradient | 2 | test-suite bugs (focal-point-correction, fr> default — SVG2 behavior changed). |
| painting/opacity/50percent | 1 | css-color-4 allows percentage; test predates it. |
| structure/style-attribute | 1 | <svg version="1.1"> disables geometry-in-style (SVG 1.1 behavior). |
| Other RenderOnly UB cases | 51 | Implementation-defined output; we verify no-crash only (per project policy, kept RenderOnly not Skip). |
Geode is part of the same resvg test matrix as the CPU variants. It should use the same ImageComparisonParams thresholds, render-only state, skips, and golden overrides as the other renderers. Backend support is recorded through normal Params feature requirements or local backend disables, never through side-table gates.
Policy:
The practical goal is fewer overrides over time. A large override map is a signal to either fix the feature, classify it as a clear unsupported/deprecated case, or write a focused non-resvg regression that exercises the root cause directly.
RESOLVED. Geode now uses official Slug analytic dual-ray coverage at 1 sample/pixel on every adapter (4× MSAA and the Intel-Arc alpha-coverage fallback deleted; Mac/Linux unified; GeodeTinyParity retired). See 0041 (as-built).
The earlier theory in this section — that ~16 Geode gates shared one "slug_fill edge-coverage quantization" root cause — was wrong, and is preserved here only as a caution: the analytic rewrite left those tests byte-identical, proving coverage was never the cause. They were three real, separate bugs plus two legitimate per-backend goldens, all now fixed/closed:
Lesson: a large diff amplified by a filter/matrix is not evidence of a coverage problem — inspect whether a coverage change actually moves it before attributing it. The only remaining Geode resvg gate is feGaussianBlur/complex-transform (genuine analytic-vs-finite-sample 1px blur edge) — #625.