From 4902306346164c87c342c50f6ac3d09373112e13 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Mon, 15 Jun 2026 18:19:29 -0500 Subject: [PATCH 1/2] Implement Border dashed-stroke geometry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wires up the five MAUI dashed-stroke properties that PR #273 deferred: - StrokeDashPattern - StrokeDashOffset - StrokeLineCap - StrokeLineJoin - StrokeMiterLimit Approach: keep the existing Modifier.Border() solid fast path for the common case, but switch to a Modifier.DrawBehind() + native Android.Graphics.Paint + DashPathEffect path whenever any of the five knobs diverges from defaults. Compose's Stroke ctor + dashPathEffect are stripped by the inline-class JVM mangling, so going down to the native canvas via the directly-bound AndroidCanvas_androidKt.getNativeCanvas is the smallest path. New plumbing: - [ComposeBridge] for DrawModifierKt.drawBehind + Modifier.DrawBehind extension. - Hand-written DrawScope JNI helpers (DrawScopeGetSize, DrawScopeGetNativeCanvas, UnpackSizeWidth/Height) that walk DrawScope -> DrawContext -> ICanvas -> Android.Graphics.Canvas. - New JCW Platform/BorderStrokeDrawCallback (registered net/compose/maui/BorderStrokeDrawCallback) implementing IFunction1 with a cached Paint and per-instance mutable state. Walks the IBorderStroke shape switch — RoundRectangle uniform/per-corner, Ellipse, Rectangle fallback — and insets by strokeWidth/2 to match Modifier.border centring. - InternalsVisibleTo for Microsoft.AndroidX.Compose.Maui so the JCW can call internal ComposeBridges helpers. - ColorMapping.ToArgb helper for native Paint colour. BorderHandler: - 5 new mappers funneling into a single _strokeGeometryVersion MutableState slot. - One readonly _strokeDrawCallback per handler instance to keep JCW identity stable across recompositions. - HasCustomStrokeGeometry() discriminator picks the DrawBehind path only when needed; otherwise we stay on Modifier.Border() (no regression for the solid case). Coverage: BorderHandler 35/40 (88%) -> 40/40 (100%). docs/maui-coverage.md regenerated. Sample: extended VisualsPage with five dashed/cap/join variants. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/maui-coverage.md | 31 +-- .../Pages/VisualsPage.xaml | 67 +++++ .../ColorMapping.cs | 15 ++ .../Handlers/BorderHandler.cs | 144 ++++++++++- .../Platform/BorderStrokeDrawCallback.cs | 241 ++++++++++++++++++ .../AssemblyInfo.cs | 10 + .../ComposeBridges.cs | 101 ++++++++ .../ModifierExtensions.cs | 31 +++ .../PublicAPI.Unshipped.txt | 1 + 9 files changed, 609 insertions(+), 32 deletions(-) create mode 100644 src/Microsoft.AndroidX.Compose.Maui/Platform/BorderStrokeDrawCallback.cs create mode 100644 src/Microsoft.AndroidX.Compose/AssemblyInfo.cs diff --git a/docs/maui-coverage.md b/docs/maui-coverage.md index 24d3799e..0c2c643d 100644 --- a/docs/maui-coverage.md +++ b/docs/maui-coverage.md @@ -1,6 +1,6 @@ # .NET MAUI ⇄ Microsoft.AndroidX.Compose.Maui backend coverage -Generated by `scripts/maui-coverage.cs` on 2026-06-12 22:58 UTC. +Generated by `scripts/maui-coverage.cs` on 2026-06-15 23:18 UTC. Pinned MAUI version: **10.0.20** (from `Directory.Build.targets`). @@ -15,14 +15,14 @@ collected transitively across base mappers (`ViewHandler.ViewMapper`, - **Stock MAUI handlers in scope**: 43 - **Handlers we override**: 24 (**55.8%**) -- **Property-mapper keys covered**: 883 / 1224 (**72.1%**) +- **Property-mapper keys covered**: 888 / 1224 (**72.5%**) ### Per-category coverage | Category | Handlers | Keys | | --- | --- | --- | | **Pages / Navigation** | 1/4 (25%) | 33/130 (25%) | -| **Containers** | 5/5 (100%) | 166/174 (95%) | +| **Containers** | 5/5 (100%) | 171/174 (98%) | | **Leaves** | 18/18 (100%) | 684/695 (98%) | | **Menus / Toolbar** | 0/7 (0%) | 0/1 (0%) | | **Shapes** | 0/1 (0%) | 0/41 (0%) | @@ -39,7 +39,7 @@ Sorted by category. ✅ = fully covered (100%), 🟡 = partial, ❌ = not implem | ❌ | `NavigationViewHandler` | Pages / Navigation | `NavigationPage` | — | 0 / 31 (0%) | | ✅ | `PageHandler` | Pages / Navigation | `Page` | `PageHandler` | 33 / 33 (100%) | | ❌ | `TabbedViewHandler` | Pages / Navigation | `TabbedPage` | — | 0 / 31 (0%) | -| 🟡 | `BorderHandler` | Containers | `Border` | `BorderHandler` | 35 / 40 (88%) | +| ✅ | `BorderHandler` | Containers | `Border` | `BorderHandler` | 40 / 40 (100%) | | ✅ | `ContentViewHandler` | Containers | `ContentView`, `IContentView` | `ContentViewHandler` | 32 / 32 (100%) | | ✅ | `LayoutHandler` | Containers | `Layout` | `LayoutHandler` | 32 / 32 (100%) | | 🟡 | `RefreshViewHandler` | Containers | `RefreshView` | `RefreshViewHandler` | 34 / 35 (97%) | @@ -112,7 +112,6 @@ Most often this is a non-trivial property we haven't wired up yet (`CharacterSpacing`, `Font`, `Padding` on `Button`; `CornerRadius`, dashed stroke patterns on `Border`). -- **`BorderHandler`** (88%) — missing: `StrokeDashOffset`, `StrokeDashPattern`, `StrokeLineCap`, `StrokeLineJoin`, `StrokeMiterLimit` - **`RadioButtonHandler`** (92%) — missing: `CornerRadius`, `StrokeColor`, `StrokeThickness` - **`ScrollViewHandler`** (94%) — missing: `HorizontalScrollBarVisibility`, `VerticalScrollBarVisibility` - **`ImageHandler`** (97%) — missing: `IsAnimationPlaying` @@ -299,17 +298,9 @@ _No Compose backend handler. Stock MAUI handler keeps the AppCompat backend._ -### 🟡 `BorderHandler` — `Border` +### ✅ `BorderHandler` — `Border` -Backed by `BorderHandler`. **35 / 40 keys (88%)**. - -Missing keys: - -- [ ] `StrokeDashOffset` -- [ ] `StrokeDashPattern` -- [ ] `StrokeLineCap` -- [ ] `StrokeLineJoin` -- [ ] `StrokeMiterLimit` +Backed by `BorderHandler`. **40 / 40 keys (100%)**. Extra keys we map (no stock counterpart): @@ -346,11 +337,11 @@ Extra keys we map (no stock counterpart): - [x] `Shadow` - [x] `Shape` - [x] `Stroke` -- [ ] `StrokeDashOffset` -- [ ] `StrokeDashPattern` -- [ ] `StrokeLineCap` -- [ ] `StrokeLineJoin` -- [ ] `StrokeMiterLimit` +- [x] `StrokeDashOffset` +- [x] `StrokeDashPattern` +- [x] `StrokeLineCap` +- [x] `StrokeLineJoin` +- [x] `StrokeMiterLimit` - [x] `StrokeThickness` - [x] `ToolTip` - [x] `Toolbar` diff --git a/src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/VisualsPage.xaml b/src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/VisualsPage.xaml index a78c4f05..d677b4d6 100644 --- a/src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/VisualsPage.xaml +++ b/src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/VisualsPage.xaml @@ -56,6 +56,73 @@ TextColor="#003E37" /> + +