Skip to content

windows-canvas optimized rendering and text layout - #4756

Merged
Kenny Kerr (kennykerr) merged 5 commits into
masterfrom
canvas-invalidation-text
Jul 29, 2026
Merged

windows-canvas optimized rendering and text layout#4756
Kenny Kerr (kennykerr) merged 5 commits into
masterfrom
canvas-invalidation-text

Conversation

@kennykerr

@kennykerr Kenny Kerr (kennykerr) commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Adds demand-driven and state-driven controls to windows-reactor, plus a TextLayout API and invalidate / text layout samples. This makes it far simpler to produce efficient text rendering and demand-driven canvas rendering in general.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the windows-reactor + windows-canvas integration to support demand-driven rendering (size-driven and state-driven invalidation) and adds a higher-level TextLayout API for measured/hit-tested text that can be shaped once and reused.

Changes:

  • Add demand-driven canvas and state-driven canvas_invalidated (via Invalidator) to windows-reactor’s canvas bridge.
  • Add TextLayout + WordWrapping to windows-canvas, plus DrawingSession::draw_text_layout.
  • Update docs, tests, and samples to demonstrate demand-driven rendering + text layout + invalidation patterns.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
docs/crates/windows-reactor.md Documents new demand-driven rendering APIs and recommended patterns.
docs/crates/windows-canvas.md Adds docs for demand-driven rendering, TextLayout, wrapping, and sample references.
crates/tools/bindings/src/canvas.txt Extends bindgen filter to include DirectWrite layout APIs and constants.
crates/tests/libs/canvas/src/lib.rs Adds Rect::offset tests and new TextLayout behavior tests.
crates/samples/canvas/samples/src/lib.rs Switches sample harness default to demand-driven canvas; adds run_animated.
crates/samples/canvas/samples/examples/transform.rs Uses run_animated since it animates each frame.
crates/samples/canvas/samples/examples/text_layout.rs New example demonstrating TextLayout measurement + demand-driven repaint.
crates/samples/canvas/samples/examples/invalidate.rs New example demonstrating explicit invalidation-driven repaint.
crates/samples/canvas/hit_test/src/main.rs Converts hit-test sample to invalidate-on-pointer events instead of per-frame redraw.
crates/samples/canvas/editor/src/main.rs Converts editor sample to invalidate-on-state-change rendering.
crates/libs/reactor/src/lib.rs Re-exports canvas, canvas_invalidated, and Invalidator under the canvas feature.
crates/libs/reactor/src/canvas_bridge.rs Implements demand-vs-continuous render modes and the Invalidator hook/API.
crates/libs/canvas/src/types.rs Adds Rect::offset.
crates/libs/canvas/src/text.rs Adds WordWrapping, TextLayout, metrics/hit-test APIs.
crates/libs/canvas/src/session.rs Adds DrawingSession::draw_text_layout.
crates/libs/canvas/src/bindings.rs Generated bindings updated for DirectWrite layout + metrics/hit-test structs/methods.

Comment thread crates/libs/canvas/src/text.rs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 40 out of 40 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (6)

crates/libs/canvas/src/text.rs:241

  • hit_test_point discards the HRESULT from IDWriteTextLayout::HitTestPoint. On failure (e.g., invalid input), the returned HitTest will be based on default/undefined metrics. Returning Result<HitTest> (or validating inputs / asserting success) would prevent silent incorrect results.
        unsafe {
            _ = self
                .raw
                .HitTestPoint(point.x, point.y, &mut trailing, &mut inside, &mut m);
        }

crates/libs/canvas/src/text.rs:262

  • caret_bounds discards the HRESULT from IDWriteTextLayout::HitTestTextPosition. This can fail for out-of-range UTF-16 positions; returning a Rect anyway can silently produce incorrect caret geometry. Consider returning Result<Rect> (or explicitly clamping/validating position).
        unsafe {
            _ = self
                .raw
                .HitTestTextPosition(position, trailing, &mut x, &mut y, &mut m);
        }

crates/libs/reactor/src/canvas_bridge.rs:401

  • CanvasImageSource::draw now takes a callback returning Result<()>, but the doc example above still uses a closure returning () and calls unwrap() inside it. Please update the example to return Ok(()) and use ? for fallible brush creation so the docs match the API contract.
    pub fn draw(
        &self,
        clear: ColorF,
        f: impl FnOnce(&DrawingSession<'_>) -> Result<()>,
    ) -> Result<bool> {

crates/libs/reactor/src/canvas_bridge.rs:92

  • The example for animated_canvas no longer matches the function signature: the draw closure now returns Result<()>, so the snippet should return Ok(()) (and ideally use ? for fallible resource creation).

This issue also appears on line 397 of the same file.

/// animated_canvas(|ctx| {
///     ctx.clear(ColorF::CORNFLOWER_BLUE);
///     ctx.fill_ellipse(&ellipse, &brush);
/// })
/// ```

crates/libs/canvas/src/text.rs:219

  • TextLayout::metrics ignores the HRESULT from IDWriteTextLayout::GetMetrics. If the call fails, this returns default/garbage metrics with no signal to the caller. Since this is a new public API, consider making it fallible (e.g. metrics(&self) -> Result<TextMetrics>) or at least asserting/handling failure explicitly.

This issue also appears in the following locations of the same file:

  • line 237
  • line 258
    pub fn metrics(&self) -> TextMetrics {
        let mut m = DWRITE_TEXT_METRICS::default();
        unsafe { _ = self.raw.GetMetrics(&mut m) };
        TextMetrics {

crates/samples/canvas/text_layout/src/main.rs:49

  • The on-screen readout reports the TextLayout metrics as "px", but the TextMetrics values are in device-independent pixels (DIPs). The unit label should match the actual units to avoid confusion.

@kennykerr
Kenny Kerr (kennykerr) merged commit acb5a1a into master Jul 29, 2026
36 checks passed
@kennykerr
Kenny Kerr (kennykerr) deleted the canvas-invalidation-text branch July 29, 2026 10:51
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.

2 participants