diff --git a/Directory.Build.props b/Directory.Build.props index 88a66654cb..edc3a1b59f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,12 +1,12 @@  - 4.4.0 + 4.5.0 - 12.0.0.4 + 12.0.0.5 $(VersionSuffix) - 6.5.31.5 + 6.5.31.6 $(VersionSuffix) - 10.0.0 + 10.0.0.1 $(VersionSuffix) Wiesław Šoltés Wiesław Šoltés diff --git a/README.md b/README.md index 1d822ee9be..c1dfd0f140 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ and the `Svg.Skia` renderer will provide more complete rendering subsystem imple - `Svg.Custom` and `Svg.Skia` now include typed `pointer-events` handling plus geometry-aware topmost hit testing. - `Svg.Skia` now includes a shared interaction dispatcher, shared animation clock/controller, and host-driven animation playback APIs. - `Svg.Controls.Skia.Avalonia` and `Svg.Controls.Skia.Uno` now expose animation backend selection, playback rate, frame interval, and resolved-backend diagnostics. -- `SvgML.Avalonia`, `SvgML.Maui`, and `SvgML.Uno` now live in the same repository, so inline Avalonia, .NET MAUI, and Uno XAML-authored SVG trees build against the local `Svg.Skia` sources and ship from the same release pipeline. +- `SvgML.Avalonia`, `SvgML.Maui`, and `SvgML.Uno` now live in the same repository, so inline Avalonia, .NET MAUI, and Uno XAML-authored SVG trees, including native controls hosted through SVG `foreignObject`, build against the local `Svg.Skia` sources and ship from the same release pipeline. - Avalonia adds an optional `NativeComposition` animation backend with fallback to `RenderLoop` or `DispatcherTimer` when retained composition is unavailable. - `tests/Svg.Skia.Benchmarks` adds a local BenchmarkDotNet harness for the shared animation renderer, and `samples/TestApp` exposes backend and playback controls for manual verification. diff --git a/build/SvgML.Weaving.targets b/build/SvgML.Weaving.targets index 0836189945..2007912d1f 100644 --- a/build/SvgML.Weaving.targets +++ b/build/SvgML.Weaving.targets @@ -1,6 +1,6 @@ - + false false net10.0 diff --git a/plan/svgml-foreignobject-inline-controls-update.md b/plan/svgml-foreignobject-inline-controls-update.md new file mode 100644 index 0000000000..c350e6f19d --- /dev/null +++ b/plan/svgml-foreignobject-inline-controls-update.md @@ -0,0 +1,83 @@ +# SvgML `foreignObject` Inline Controls Update + +Update date: 2026-04-21 + +## Goal + +Use SVG `foreignObject` as the idiomatic SvgML host for native inline controls on Avalonia, Uno, and .NET MAUI. + +`InlineUIContainer` has been removed; `foreignObject` is the single native-control host element. + +This also covers non-inline SVG scene placement: a `foreignObject` with a native child can be authored anywhere a graphical SVG element is allowed, including directly under `svg` and inside transformed grouping containers. + +## SVG Basis + +- MDN describes `foreignObject` as the SVG element for including content from another namespace, most commonly HTML in browsers: https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/foreignObject +- SVG 1.1 defines `x`, `y`, `width`, and `height` as the rectangular region into which the foreign content is placed: https://www.w3.org/TR/SVG11/extend.html#ForeignObjectElement +- SVG 1.1 also specifies that `x`/`y` default to `0`, and zero `width` or `height` disables rendering. + +SvgML maps those rules onto native UI hosting: + +- non-inline `foreignObject` uses its SVG rectangular bounds +- inline `foreignObject` reserves text-flow space from explicit `width`/`height` or the measured native control size +- missing non-inline `width`/`height` are written from the native desired size when a child control exists + +## Architecture + +### Shared model + +`foreignObject` implements the hosted-control contract: + +- `HostedControl` returns the platform-native child +- `GetHostedControlSize()` returns explicit SVG size when set, otherwise native desired size +- a generated stable mapping id is emitted when the author did not set `id` + +When a `foreignObject` is authored inside SVG text, it serializes as a `tspan` placeholder with: + +- generated or explicit id for retained-scene mapping +- invisible placeholder glyph +- `font-size` from resolved slot height +- `textLength` from resolved slot width +- `lengthAdjust="spacingAndGlyphs"` + +This lets the SVG text engine reserve inline advance while the real native control is arranged by the platform overlay. + +### Scene graph + +`SvgForeignObject` is retained as a non-rendering scene node, but the scene compiler now assigns geometry bounds from `x`, `y`, `width`, and `height`. + +This is required for non-inline hosted controls because the native child is not serialized into the SVG document and therefore does not contribute child geometry. + +### Platform overlays + +All platforms now use one hosted-control layout contract: + +- enumerate hosted controls from the SvgML source tree +- detect inline placement by walking from the hosted element to an owning `text_base` +- compute inline slot positions from the source text tree +- use retained-scene `foreignObject` bounds for normal SVG-scene placement +- fall back to the source `foreignObject` slot (`x`, `y`, `width`, `height`) transformed through the element's total SVG transform when retained bounds are not available +- transform SVG picture-space bounds into platform control coordinates +- measure and arrange the native child in that slot + +Avalonia hosts controls as logical/visual children of the root `svg`. + +Uno hosts controls through retained popups positioned from the transformed SVG slot. + +MAUI hosts controls in an `AbsoluteLayout` overlay above the Skia drawing surface. + +## XML Namespaces + +SvgML assemblies expose the `SvgML` CLR namespace through `https://github.com/svgml` where the XAML stack supports public assembly-level XML namespace definitions. + +Avalonia also keeps the existing `https://github.com/avaloniaui` mapping so SvgML elements can be used unprefixed in Avalonia markup that already has Avalonia as the default namespace. + +Uno uses the WinUI/Uno-supported `using:SvgML` XAML namespace form because Uno's `XmlnsDefinitionAttribute` is not publicly usable by application/library code. + +## Samples + +The Avalonia, Uno, and MAUI demos now demonstrate both inline controls and scene controls using `foreignObject`. + +Scene controls show root-level placement and controls hosted inside translated SVG groups, with native buttons, text editors, sliders, and checkbox content arranged from SVG geometry. + +Uno sample markup relies on measured native size because Uno XAML does not currently convert literal `SvgUnit` values for `foreignObject` attributes. diff --git a/plan/svgml-inline-ui-controls-plan.md b/plan/svgml-inline-ui-controls-plan.md new file mode 100644 index 0000000000..5f7fbed36a --- /dev/null +++ b/plan/svgml-inline-ui-controls-plan.md @@ -0,0 +1,5 @@ +# SvgML Inline UI Controls Plan + +Superseded by `svgml-foreignobject-inline-controls-update.md`. + +The initial implementation plan used a custom `InlineUIContainer` element as the public inline native-control host. The current design removes that custom element and uses SVG `foreignObject` as the single idiomatic public API for Avalonia, Uno, and MAUI. diff --git a/samples/SvgML.Avalonia.Demo/MainWindow.axaml b/samples/SvgML.Avalonia.Demo/MainWindow.axaml index da18c1ce4b..d97bf5fede 100644 --- a/samples/SvgML.Avalonia.Demo/MainWindow.axaml +++ b/samples/SvgML.Avalonia.Demo/MainWindow.axaml @@ -2,9 +2,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="500" + mc:Ignorable="d" d:DesignWidth="960" d:DesignHeight="680" x:Class="SvgML.Avalonia.Demo.MainWindow" - Width="800" Height="500" + Width="960" Height="680" Title="SvgML.Avalonia Demo"> @@ -52,16 +52,169 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Release review + + Approve + +