Skip to content

Add node-aware selective paint scenes - #698

Open
duz52 wants to merge 2 commits into
DioxusLabs:mainfrom
duz52:feat/node-aware-selective-paint
Open

Add node-aware selective paint scenes#698
duz52 wants to merge 2 commits into
DioxusLabs:mainfrom
duz52:feat/node-aware-selective-paint

Conversation

@duz52

@duz52 duz52 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add BlitzPaintScene, a node-aware extension of AnyRender's PaintScene.
  • Keep the existing paint_scene API through a forwarding PaintSceneAdapter that ignores node metadata.
  • Add paint_scene_with_nodes for node ownership scopes and selective paint traversal.
  • Identify paint ownership with a document-local NodeId plus document ID.

Motivation

Page-by-page output needs to retain Blitz's authoritative paint order while omitting DOM branches that cannot contribute to the current page. Painting the whole document first would require untangling a nested command and layer stream afterward.

This is deliberately coarse paint filtering, not fragmentation. Split content is placed and clipped separately. The node-aware scene only exposes DOM ownership around the commands Blitz already emits.

Design

BlitzPaintScene has PaintScene as a supertrait and adds three operations:

  • should_paint(PaintNode) selects paint traversal branches and independently painted inline owners.
  • begin_node(PaintNode) starts a contiguous ownership scope.
  • end_node(PaintNode) closes that scope.

Only the scene is threaded through the painter. There is no separate hooks argument, trait object, registry, plugin system, or intermediate scene representation.

PaintSceneAdapter forwards the complete RenderContext and PaintScene surface to an ordinary AnyRender backend and ignores the node-specific methods. The existing paint_scene entry point uses this adapter, preserving its current API and paint output.

PaintNode combines BaseDocument::id() with NodeId, so nodes in subdocuments remain unambiguous. Scopes are nested and balanced, but may repeat because one DOM node's commands are not necessarily contiguous in CSS paint order.

Ownership details

  • Glyphs, text decorations, and inline backgrounds use the inline brush's owning node.
  • Table-row backgrounds use the row node rather than the table root.
  • A body background propagated to the canvas remains owned by the body.
  • Subdocument nodes are disambiguated by document ID.
  • Custom-widget scene preparation honors paint selection.

Validation

Added integration coverage for:

  • exact paint-output equality between the ordinary adapter path and a node-aware scene;
  • element paint-branch exclusion;
  • balanced node scopes;
  • inline owner attribution and filtering;
  • propagated body-background ownership.

Commands run:

cargo check -p blitz-paint --all-features
cargo test -p blitz-paint --all-features
cargo test -p blitz-tests
RUSTDOCFLAGS='-D warnings' cargo doc -p blitz-paint --no-deps
cargo fmt --all -- --check
git diff --check

All passed.

Strict scoped Clippy also passed:

cargo clippy -p blitz-paint --all-features --no-deps -- -D warnings -A clippy::needless-borrow
cargo clippy -p blitz-tests --test paint_nodes --no-deps -- -D warnings -A clippy::needless-return -A clippy::needless-borrow

The allowances are limited to pre-existing warnings outside this change:

  • packages/blitz-paint/src/render/mask.rs: clippy::needless_borrow
  • packages/blitz-dom/src/mutator.rs: clippy::needless_return

WPT results

No changes in test results compared to main.

Generated by the WPT workflow.

@duz52 duz52 changed the title Add node-aware selective paint hooks Add node-aware selective paint scenes Aug 14, 2026
@duz52

duz52 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

@nicoburns Thanks — I reworked the PR around that shape.

There is now a BlitzPaintScene: PaintScene trait, so only the scene is passed through the paint traversal. A PaintSceneAdapter forwards the full RenderContext/PaintScene API to an ordinary backend and no-ops the node-specific methods, which lets the existing paint_scene API remain unchanged. Node-aware backends use paint_scene_with_nodes directly.

I removed the separate hooks object and the two-argument plumbing entirely. The ownership and filtering behavior is unchanged, and the full CI matrix is green.

It feels substantially cleaner now. Would appreciate another sanity check when you have a chance: #698

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