Skip to content

Add gradient brush ABI support (LinearGradientBrush/RadialGradientBrush) - #7

Merged
Marc-André Moreau (mamoreau-devolutions) merged 2 commits into
masterfrom
copilot/expand-avalonia-api-coverage
Sep 12, 2026
Merged

Add gradient brush ABI support (LinearGradientBrush/RadialGradientBrush)#7
Marc-André Moreau (mamoreau-devolutions) merged 2 commits into
masterfrom
copilot/expand-avalonia-api-coverage

Conversation

@mamoreau-devolutions

Copy link
Copy Markdown
Contributor

Summary

Expands Avalonia API coverage in Rustolonia with gradient brush support (LinearGradientBrush/RadialGradientBrush), following the existing "sibling interface + QueryInterface" versioning pattern.

What changed

  • New additive COM interfaces IAvnGradientBrush / IAvnLinearGradientBrush / IAvnRadialGradientBrush. IAvnBrush v1 (solid-color only) is untouched.
  • IAvnControlFactory gains create_linear_gradient_brush / create_radial_gradient_brush, which required bumping its deterministic IID from ABI version 13 → 14.
  • Full stack implemented:
    • C# IR (ProjectionIr v16→17) + generator emits the new interfaces, native header, and factory methods.
    • Rust avalonia-sys exposes the raw vtables/structs.
    • Rust avalonia adds safe LinearGradientBrush, RadialGradientBrush, Paint, GradientStop, SpreadMethod, RelativePoint, RelativeScalar types.
  • Scope decision: existing chrome properties (Background/BorderBrush/Foreground) remain solid-brush-only — reading a gradient-backed brush off them still returns AVN_E_NONSOLIDBRUSH. Wiring gradients into control properties is left for a future wave.
  • Fixed hardcoded factory ABI version (13→14) expectations across the C# (ClrTypeExtractorTests.cs) and Rust (brush_abi.rs, control_abi.rs, definitions_abi.rs, wave_a_abi.rswave_k_abi.rs) ABI test suites.
  • Added new tests: rust/avalonia-sys/tests/gradient_brush_abi.rs (interface shapes/IIDs/vtable slots) and rust/avalonia/tests/gradient_brush_round_trip.rs (safe-API value semantics).
  • Documentation: rust/MARSHALLING.md (new "Gradient brushes" section), rust/README.md, rust/COMPATIBILITY.md (IR v17 + gradient-wave ABI notes). rust/release-manifest.json bumped to IR v17.

Testing

  • cargo test -p avalonia-sys --locked: 77/77 passing (excludes pre-existing host-binary-dependent nativeaot_fixture tests, unrelated/environment-gated).
  • cargo test -p avalonia --locked: all passing.
  • cargo test -p avalonia-bindgen --locked: 50/50 passing.
  • dotnet test tests\Avalonia.Projection.Ir.Tests\Avalonia.Projection.Ir.Tests.csproj -c Release: 129/129 passing.
  • dotnet build host\Avalonia.Host.csproj -c Release: succeeded, 0 errors.

Introduces IAvnGradientBrush/IAvnLinearGradientBrush/IAvnRadialGradientBrush as
new sibling COM interfaces alongside the existing solid-only IAvnBrush (v1
unchanged). IAvnControlFactory gains create_linear_gradient_brush and
create_radial_gradient_brush, requiring its IID to move from ABI version
13 to 14.

- C# IR/generator layer emits the new interfaces, native header, and
  factory methods (IR schema bumped to v17).
- Rust avalonia-sys exposes the raw vtables/structs; avalonia adds safe
  LinearGradientBrush/RadialGradientBrush/Paint/GradientStop/SpreadMethod/
  RelativePoint/RelativeScalar types.
- Existing chrome properties (Background/BorderBrush/Foreground) remain
  solid-brush-only by design; reading a gradient there still returns
  AVN_E_NONSOLIDBRUSH.
- Updates hardcoded factory ABI version expectations (13->14) across the
  C# and Rust ABI test suites, and adds new tests covering the gradient
  interfaces' shapes/IIDs and safe-API value semantics.
- Documents the new capability in MARSHALLING.md/README.md/COMPATIBILITY.md
  and bumps release-manifest.json's projectionIr schema to 17.
…lid-only

A rubber-duck review of PR #7 caught a real regression: the generator's
FromBrush/ToBrush helpers (used by every existing Background/BorderBrush/
Foreground getter and setter) special-cased gradient brushes, silently
routing them through the solid-only IAvnBrush property path instead of
throwing AVN_E_NONSOLIDBRUSH as documented and originally tested.

This contradicted the PR's own stated scope decision (existing chrome
properties stay solid-brush-only in this wave) and broke
BrushMemberComTests.A_non_solid_brush_fails_explicitly_instead_of_picking_a_nearest_colour.

Fix: remove the gradient special-casing from ComSourceEmitter's emitted
FromBrush/ToBrush methods, restoring the solid-only behavior for existing
properties. Gradient objects still separately implement IAvnBrush at the
class level (AvnLinearGradientBrush/AvnRadialGradientBrush), where GetColor
correctly returns AVN_E_NONSOLIDBRUSH by design - that path was already
correct and is unchanged.

No ABI/IID/header changes result from this fix (regenerated header/IR/
Rust bindings are byte-identical); only IAvnBrush.g.cs's static helper
methods changed. Verified: Avalonia.Host.Tests 375/375 pass (was 374/375),
Avalonia.Projection.Ir.Tests 129/129 pass, and the full non-host-dependent
Rust test suite passes.
@mamoreau-devolutions
Marc-André Moreau (mamoreau-devolutions) deleted the copilot/expand-avalonia-api-coverage branch September 12, 2026 14:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant