Skip to content

Windows: real CSS-style box-shadow via DirectComposition (#210 follow-up) #230

Description

@proggeramlug

Context

#210 wired 4 of the 5 Windows styling stubs (decoration / opacity / border_color / border_width) at v0.5.347. The fifth — widget.shadow — remained Stub. Storage was already in place at crates/perry-ui-windows/src/widgets/mod.rs::SHADOW_PARAMS; what's missing is the rendering pass.

Why a separate issue

Real CSS box-shadow rendering on Win32 child controls (vs top-level windows) needs DirectComposition:

  • IDCompositionDevice / IDCompositionVisual / IDCompositionEffectGroup
  • IDCompositionDropShadowEffect (the named CSS-equivalent shape: color, blur, offset)
  • DXGI swap chain integration so DirectComposition can composite atop the GDI render

Or alternatively a custom alpha-blended WM_PAINT pass on the parent that draws N concentric translucent rectangles to approximate Gaussian blur. This is the classic GDI "fake shadow" — visible but not pixel-accurate.

Either path is multi-day work that didn't fit inside #210's scope. Decoration / opacity / border could land via small per-prop apply functions; shadow needs new infrastructure.

Acceptance criteria

  • widget.shadow row in the styling matrix flips from StubWired for Windows.
  • A widget calling widgetSetShadow(handle, r, g, b, a, blur, offsetX, offsetY) produces a visible drop shadow under the widget's bounds, matching the CSS box-shadow reference within reasonable approximation (color, offset, and at least 8-16px of blur radius).
  • Existing widgets with corner radius (which uses SetWindowRgn) still render correctly — the shadow path must compose with the rounded clip, not fight it.
  • docs/examples/ui/styling/visual_test.ts section 4 (Shadow) renders visible shadows on Windows.

Hints for the implementer

  • crates/perry-ui-macos/src/widgets/mod.rs::set_shadow is the reference (CALayer-based — sets setMasksToBounds: false + shadowOpacity / shadowRadius / shadowOffset). Behavior to match: opaque shadow color with alpha riding on shadowOpacity; positive offsetY = downward (HTML convention).
  • The SHADOW_PARAMS store already exists (mod.rs:798) with the full 7-tuple. The apply_corner_radius deferred-paint pattern at mod.rs:962 is the canonical "call from layout pipeline" hook — apply_shadow(handle) should slot in symmetrically.
  • DirectComposition requires Windows 8+ (matches Perry's minimum). The windows-rs crate already enables Win32_Graphics_DirectComposition would need to be added to crates/perry-ui-windows/Cargo.toml's windows features.
  • Two-stage strategy that keeps initial scope manageable: (1) GDI alpha-blend approximation first — visible shadow but not perfectly Gaussian; (2) DirectComposition upgrade later for true CSS parity. This issue could be split if the GDI step is enough for a v1.

Closes

When this lands: Windows reaches 43/43 Wired alongside every other Perry-supported platform. Combined with #210 (now closed except this row), the styling matrix is fully green for issue #185.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions