Skip to content

Propagate root/body backgrounds to the canvas - #672

Open
nicoburns wants to merge 2 commits into
mainfrom
devin/1786315163-background-root
Open

Propagate root/body backgrounds to the canvas#672
nicoburns wants to merge 2 commits into
mainfrom
devin/1786315163-background-root

Conversation

@nicoburns

@nicoburns nicoburns commented Aug 9, 2026

Copy link
Copy Markdown
Member

Summary

Fixes the css/CSS2/backgrounds/background-root-* WPT tests (+30 net passes across css/CSS2, css/css-backgrounds, css/css-flexbox, css/css-grid, css/css-position).

Canvas background propagation (blitz-paint): the root element's background (or the <body>'s, when the root's is entirely transparent) now propagates to the canvas per CSS2 §14.2:

  • BlitzDomPainter resolves a canvas_bg_source_id and paints that element's background color and image layers over the whole canvas in paint_scene, before rendering the tree.
  • Image layers are positioned relative to the source element's background positioning area but tiled over a canvas-sized painting area, via a new painting_rect_override on ElementCx.
  • draw_background skips the source element so the propagated background isn't painted twice.

Root element margin (blitz-dom): resolve_layout now offsets the root element's box by its margin (taffy's compute_root_layout resolves the margin into the available size but leaves location at the origin). Required by most background-root-* tests, and also fixes root-box-001 and two margin-collapse tests.

Repeat over the painting area (blitz-paint): repeat/round/space tiles now cover the background painting area (clip box, or whole canvas for the canvas background) rather than just the positioning area:

let origin_rect = self.box_rect(layer.origin);
let painting_rect = self
    .painting_rect_override
    .unwrap_or_else(|| self.box_rect(layer.clip));
let extend_width = extend(bg_pos_x + (origin_rect.x0 - painting_rect.x0), bg_size.width);

This replaces the previous per-(clip, origin)-combination special cases with a general formula, and makes e.g. tiles visible beneath translucent borders (as in the background-repeat-space-8 reference).

Outset box-shadow clipping: an element whose background propagates to the canvas paints no background of its own, so its outset shadow is now always clipped out of its border box (previously an opaque background was assumed to cover it).

Test results

Before/after comparison over css/CSS2 css/css-backgrounds css/css-flexbox css/css-grid css/css-position: 30 tests fixed, 1 newly failing:

  • css/CSS2/backgrounds/background-position-002.xht — the test page now renders correctly (body background propagated to canvas), but its reference page renders wrong due to a pre-existing bug: an absolutely positioned height: 100% element resolves its height against the body instead of the initial containing block. Previously both pages were wrong in the same way, so the test "passed".

Still failing (pre-existing, separate issues): background-root-023 (fixed-position offset affected by sibling margin), background-root-101/102/103 (require script support).

Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/cd28e74e905344f3b4530021070cd6b1
Requested by: @nicoburns

WPT results

37 newly passing, 4 newly failing (net +33).

Full diff (41 changed tests)
- Pass => Fail css/CSS2/backgrounds/background-position-002.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-002.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-004.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-005.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-006.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-007.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-008.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-009.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-010.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-011.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-012a.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-012b.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-013a.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-013b.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-014a.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-014b.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-015.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-016.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-017.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-018.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-019.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-020.xht
+ Fail => Pass css/CSS2/backgrounds/background-root-024.xht
+ Fail => Pass css/CSS2/margin-padding-clear/margin-collapse-020.xht
+ Fail => Pass css/CSS2/margin-padding-clear/margin-collapse-021.xht
+ Fail => Pass css/CSS2/normal-flow/root-box-001.xht
+ Fail => Pass css/CSS2/tables/table-backgrounds-bs-cell-001.xht
+ Fail => Pass css/CSS2/tables/table-backgrounds-bs-table-001.xht
+ Fail => Pass css/compositing/root-element-background-transparency.html
+ Fail => Pass css/css-backgrounds/background-origin/origin-content-box.html
+ Fail => Pass css/css-backgrounds/background-origin/origin-content-box_with_radius.html
+ Fail => Pass css/css-backgrounds/background-position/background-position-right-in-body.html
+ Fail => Pass css/css-backgrounds/background-repeat/gradient-repeat-spaced-with-borders.html
+ Fail => Pass css/css-display/display-contents-root-background.html
- Pass => Fail css/css-image-animation/image-animation-body-background-no-propagation-paused.html
- Pass => Fail css/css-images/linear-gradient-body-sibling-index.html
- Pass => Fail css/css-transforms/perspective-split-by-zero-w.html
+ Fail => Pass css/css-transforms/transform-background-005.html
+ Fail => Pass css/css-transforms/transform-background-006.html
+ Fail => Pass css/css-transforms/transform-background-008.html
+ Fail => Pass css/css-transforms/transform-translate-background-001.html

Generated by the WPT workflow.

@nicoburns nicoburns self-assigned this Aug 9, 2026
@staging-devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@staging-devin-ai-integration

Copy link
Copy Markdown
Contributor

WPT regression sweep (all css/ suites, 36,601 tests)

Ran the in-repo WPT runner over all 90 css/ suites on this branch vs main (708eb61). Also ran cargo test --workspace on the branch: all green.

Net result: 36 FAIL→PASS, 4 PASS→FAIL, no new crashes.

Newly passing tests are exactly on-theme: all 22 css/CSS2/backgrounds/background-root-* reftests, root-box-001, margin-collapse-020/021, table background propagation, compositing/root-element-background-transparency, display-contents-root-background, background-origin/position tests, and 4 css-transforms/transform-background-* tests.

Of the 4 regressions, 1 is the known background-position-002.xht (broken reference due to pre-existing abspos height:100% bug). The other 3 are coincidental passes on main that the now-correct canvas background propagation exposes — in each case the ref renders more correctly on this branch and the failure is a pre-existing engine limitation:

Test Pre-existing limitation exposed
css-transforms/perspective-split-by-zero-w.html perspective plane with w<0 split not rendered; the ref's z-index:-1 red detector patch only becomes visible once body bg correctly paints in the canvas layer
css-images/linear-gradient-body-sibling-index.html sibling-index() in gradients unsupported (body bg was previously never painted at all: body height 0)
css-image-animation/image-animation-body-background-no-propagation-paused.html GIF animation unsupported (same vacuous-pass story on main)

Most interesting one — on main the ref's red "missing content" detector was hidden under the body background (wrong paint order); with propagation it correctly shows where the perspective plane isn't rendered:

perspective-split-by-zero-w: main (top) vs branch (bottom), test|ref

linear-gradient-body-sibling-index (branch ref now correctly paints the propagated gradient; test misses it for lack of sibling-index support)

linear-gradient-body-sibling-index montage

image-animation-body-background-no-propagation-paused (branch propagates bg to canvas; test shows GIF frame 1 since GIFs don't animate)

image-animation montage

@staging-devin-ai-integration
staging-devin-ai-integration Bot force-pushed the devin/1786315163-background-root branch 2 times, most recently from b72b836 to 6647af4 Compare August 13, 2026 18:32
@staging-devin-ai-integration
staging-devin-ai-integration Bot force-pushed the devin/1786315163-background-root branch from 6647af4 to 4ebb335 Compare August 13, 2026 19:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant