diff --git a/.cspell.yaml b/.cspell.yaml index 8896c91b..582c19f0 100644 --- a/.cspell.yaml +++ b/.cspell.yaml @@ -19,6 +19,7 @@ words: - Antlr - antlr - Blockquotes + - CanvasNet - Postconditions - buildmark - buildtransitive diff --git a/.fileassert.yaml b/.fileassert.yaml index 95374418..d77040b4 100644 --- a/.fileassert.yaml +++ b/.fileassert.yaml @@ -12,10 +12,12 @@ tests: # --- PACKAGE --- # The Tool package previously ballooned to ~435 MB because native SkiaSharp runtime - # assets shipped with their debug symbols (.pdb) alongside the binaries. These tests - # just guard against that regression: the packed size stays under budget, the tool's - # main assembly and README are present, and no .pdb files leak into the native - # runtimes folder. + # assets shipped with their debug symbols (.pdb) alongside the binaries. Since the + # CanvasNet migration replaced SkiaSharp with a pure-managed renderer, the tool no + # longer ships any native runtime assets at all. These tests guard against a + # regression back to native assets: the packed size stays under a much smaller + # budget, the tool's main assembly and README are present, and no "runtimes" folder + # (native or otherwise) exists in the package. - name: Package_ToolSizeWithinLimit description: "Tool package stays within its size budget" @@ -23,10 +25,10 @@ tests: files: - pattern: "artifacts/packages/DemaConsulting.SysML2Tools.Tool.*.nupkg" count: 1 - max-size: 73400320 # 70 MiB + max-size: 10485760 # 10 MiB - name: Package_ToolContentsValid - description: "Tool package contains its main assembly and README, with no stray native symbol files" + description: "Tool package contains its main assembly and README, with no native runtime assets" tags: [package] files: - pattern: "artifacts/packages/DemaConsulting.SysML2Tools.Tool.*.nupkg" @@ -37,9 +39,9 @@ tests: - pattern: "tools/net10.0/any/DemaConsulting.SysML2Tools.dll" min: 1 max: 1 - # Native SkiaSharp runtime assets must not ship with .pdb symbol files - - # this is what caused the historical ~435 MB package-size bloat. - - pattern: "tools/net10.0/any/runtimes/**/*.pdb" + # The tool is now a pure-managed package (post-CanvasNet migration): + # no "runtimes" folder of any kind - native or otherwise - should ship. + - pattern: "tools/net10.0/any/runtimes/**" max: 0 # --- BUILD NOTES --- diff --git a/AGENTS.md b/AGENTS.md index 65ce15ff..b635b9b2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,7 +8,7 @@ suitable for architecture documentation, CI/CD pipelines, and AI-assisted modeling workflows. - **languages**: C# -- **technologies**: .NET, ANTLR4, SkiaSharp +- **technologies**: .NET, ANTLR4, CanvasNet # Project Structure diff --git a/README.md b/README.md index 93657eea..1d799558 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ documentation, CI/CD pipelines, and AI-assisted modeling workflows. engine with orthogonal specialization and membership edges, depth-coded fill colors, compartments, and configurable depth limiting - **SVG Output**: Zero external dependencies -- **PNG Output**: Pixel-identical across Windows, Linux, and macOS via SkiaSharp and an +- **PNG Output**: Pixel-identical across Windows, Linux, and macOS via CanvasNet and an embedded Noto Sans font - **NuGet Library**: Publishable packages with a stable public API — use the parser, semantic model, or layout engine independently of the CLI tool diff --git a/ROADMAP.md b/ROADMAP.md index 7ba6f4e0..ef0a8574 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -101,7 +101,7 @@ runs 9 tests following the `SysML2Tools_{Capability}SelfTest` naming convention: lint, SVG render, PNG render, dynamic-view SVG/PNG render, dynamic-view filtered render, and export — but every render test (SVG, PNG, and dynamic-view) exercises only the **General View** (`SelfTestModel`'s `GeneralView`). Add one SVG+PNG-validating test per remaining view kind so -SkiaSharp native assets and each view's layout strategy are exercised on every OS: +the rendering pipeline and each view's layout strategy are exercised on every OS: | Test | Proves | |---|---| @@ -126,17 +126,15 @@ size bloat and verifying the main assembly/README are present with no stray nati open: 1. **Tool smoke test:** install the packed tool from a local feed into a clean directory → run - `--version`, render a sample to **both SVG and PNG** (PNG proves SkiaSharp natives resolve), - and `--licenses`. + `--version`, render a sample to **both SVG and PNG** (PNG exercises the managed CanvasNet + renderer), and `--licenses`. 2. **Library-consumer smoke test:** a throwaway project referencing each library package from the - local feed → restore → exercise parse→layout→render-to-SVG-in-memory and render-to-PNG (again - proving SkiaSharp natives for `.Png` consumers). + local feed → restore → exercise parse→layout→render-to-SVG-in-memory and render-to-PNG. ### Licensing, docs, gallery, publish - **Licensing/attribution:** `--licenses` output covering Noto Sans (SIL OFL 1.1) and other OTS; - per-package README notes incl. the SkiaSharp native-assets requirement for - `DemaConsulting.SysML2Tools.Png` consumers. + per-package README notes. - **Documentation:** README and User Guide state that the Geometry View is not yet supported. Finalise the layout-algorithm reference in `docs/` and wire it into CI (`build.yaml`, `.fileassert.yaml`, `.reviewmark.yaml`). diff --git a/docs/design/introduction.md b/docs/design/introduction.md index f11eba25..30cd5152 100644 --- a/docs/design/introduction.md +++ b/docs/design/introduction.md @@ -274,14 +274,15 @@ Review-sets: defined in `.reviewmark.yaml` | Language / runtime | C# / .NET 8+ | MIT | | Parser generator | ANTLR4 (`Antlr4.Runtime.Standard`) | BSD-3-Clause | | SysML v2 grammar | `antlr/grammars-v4` (official OMG KEBNF) | MIT | -| PNG rendering | SkiaSharp | MIT | +| PNG rendering | CanvasNet | MIT | | Embedded font | Noto Sans | SIL OFL 1.1 | | Test results output | `DemaConsulting.TestResults` | — | | Unit testing | xUnit v3 | Apache 2.0 | -No ImageSharp dependency. The off-the-shelf `DemaConsulting.Rendering.Skia` PNG renderer uses -SkiaSharp, chosen over ImageSharp to avoid the Six Labors Split License, which would impose -licensing obligations on library consumers embedding the renderer in commercial products. +No ImageSharp dependency. The off-the-shelf `DemaConsulting.Rendering.CanvasNet` PNG renderer uses +CanvasNet, a pure-managed rendering library, chosen over ImageSharp to avoid the Six Labors Split +License, which would impose licensing obligations on library consumers embedding the renderer in +commercial products. ## Architectural Decisions @@ -293,10 +294,10 @@ in native graphics binaries. The `IRenderer` interface is the extension point. any user files are parsed. Single-file input is the degenerate case of a multi-file workspace; there is no single-file mode. -**SkiaSharp over ImageSharp.** SkiaSharp is MIT-licensed. ImageSharp v2+ uses the +**CanvasNet over ImageSharp.** CanvasNet is MIT-licensed. ImageSharp v2+ uses the Six Labors Split License which imposes obligations on commercial library consumers. -SkiaSharp's native asset requirement is transparent for tool consumers (handled by -NuGet at publish time) and is a known, documented constraint for library consumers. +CanvasNet is a pure-managed library with no native asset requirement, so this +constraint no longer applies to tool or library consumers. **Embedded Noto Sans font.** Ensures pixel-identical PNG output across all platforms. Noto Sans is licensed SIL OFL 1.1 which explicitly permits embedding in software. @@ -351,10 +352,9 @@ tests the integrated tool, not just unit-level components. SARIF output can be added as a formatting option on the existing infrastructure without any breaking changes. -**SkiaSharp native assets for library consumers.** Consumers referencing the off-the-shelf -`DemaConsulting.Rendering.Skia` PNG renderer must ensure the appropriate -`SkiaSharp.NativeAssets.*` package is included in their publish output. This must -be documented clearly in the package README. +**Pure-managed rendering — no native assets required.** Consumers referencing the +off-the-shelf `DemaConsulting.Rendering.CanvasNet` PNG renderer have no native asset +package to add: CanvasNet is a pure-managed .NET library with no P/Invoke dependency. **Noto Sans SIL OFL attribution.** OFL requires the copyright notice and license text to be included in distributions. Must appear in NuGet package notices and the diff --git a/docs/design/sysml2-tools-core/rendering.md b/docs/design/sysml2-tools-core/rendering.md index ede583ff..e82c8692 100644 --- a/docs/design/sysml2-tools-core/rendering.md +++ b/docs/design/sysml2-tools-core/rendering.md @@ -4,7 +4,7 @@ The Rendering subsystem wires together the rendering pipeline for SysML2 Tools. It bridges the Layout subsystem (which produces a `LayoutTree`) and the off-the-shelf renderer packages -(`DemaConsulting.Rendering.Svg` and `DemaConsulting.Rendering.Skia`) using the contracts that +(`DemaConsulting.Rendering.Svg` and `DemaConsulting.Rendering.CanvasNet`) using the contracts that both sides must satisfy. The SysML-agnostic rendering contracts — `IRenderer` (low-level render interface), `Theme` @@ -179,7 +179,7 @@ flowchart TD `DemaConsulting.SysML2Tools.Semantic`; the `using` directive `using DemaConsulting.SysML2Tools.Semantic;` is required in `ILayoutStrategy.cs` and `DiagramRenderer.cs`. - The `IRenderer` implementations come from the off-the-shelf `DemaConsulting.Rendering.Svg` and - `DemaConsulting.Rendering.Skia` packages, referenced by the Tool via ``. + `DemaConsulting.Rendering.CanvasNet` packages, referenced by the Tool via ``. ### Requirements Traceability diff --git a/docs/design/sysml2-tools-tool/render.md b/docs/design/sysml2-tools-tool/render.md index 2453983d..daf99752 100644 --- a/docs/design/sysml2-tools-tool/render.md +++ b/docs/design/sysml2-tools-tool/render.md @@ -143,7 +143,7 @@ future-locale story, which applies identically here. qualified view names, and `SynthesizeDynamicView` used by `TryProcessDynamicView` to build the ad-hoc view node for `--view-type`/`--view-target`/`--filter` - `SvgRenderer` (in `DemaConsulting.Rendering.Svg`) — produces SVG output -- `PngRenderer` (in `DemaConsulting.Rendering.Skia`) — produces PNG output +- `PngRenderer` (in `DemaConsulting.Rendering.CanvasNet`) — produces PNG output - `Themes.Light` (in `DemaConsulting.Rendering.Abstractions`) — default theme - `Context`/`RenderCommandOptions`/`RenderArgumentParser` (in `DemaConsulting.SysML2Tools.Cli` and `DemaConsulting.SysML2Tools.Render`) — reads arguments; writes output diff --git a/docs/design/sysml2-tools-tool/self-test/validation.md b/docs/design/sysml2-tools-tool/self-test/validation.md index bf07a7b5..e73dd339 100644 --- a/docs/design/sysml2-tools-tool/self-test/validation.md +++ b/docs/design/sysml2-tools-tool/self-test/validation.md @@ -76,15 +76,12 @@ with `WorkspaceLoader.LoadAsync`, calls `DiagramRenderer.RenderWorkspace` with `outputs.Count > 0 && outputs[0].Data.Length > 0`. Records pass or fail. Any exception is caught and recorded via `HandleTestException`. -**RunRenderPngSelfTestAsync**: Verifies that `SelfTestModel` renders to a non-empty PNG stream, -or skips gracefully when SkiaSharp is unavailable. +**RunRenderPngSelfTestAsync**: Verifies that `SelfTestModel` renders to a non-empty PNG stream. - *Parameters*: `Context context`, `DemaConsulting.TestResults.TestResults testResults`. - *Returns*: `Task`. -Calls `NativeLibrary.TryLoad("libSkiaSharp", ...)` first. If the library is absent, records -the test as `Passed` with a skip message and returns early. Otherwise frees the handle, writes -`SelfTestModel` to a temp file, loads the workspace, calls `DiagramRenderer.RenderWorkspace` +Writes `SelfTestModel` to a temp file, loads the workspace, calls `DiagramRenderer.RenderWorkspace` with `new PngRenderer()`, and asserts non-empty output. Records pass or fail. Any exception is caught and recorded via `HandleTestException`. @@ -105,9 +102,7 @@ distinct failure message when `diagnostic` is non-null or workspace loading fail exception is caught and recorded via `HandleTestException`. **RunRenderDynamicViewPngSelfTestAsync**: Mirrors -`RunRenderDynamicViewSvgSelfTestAsync` but with the PNG renderer, skipping gracefully (same -`NativeLibrary.TryLoad("libSkiaSharp", ...)` guard) when the native SkiaSharp library is -unavailable. +`RunRenderDynamicViewSvgSelfTestAsync` but with the PNG renderer. - *Parameters*: `Context context`, `DemaConsulting.TestResults.TestResults testResults`. - *Returns*: `Task`. diff --git a/docs/gallery/png/AvionicsBrowserView.png b/docs/gallery/png/AvionicsBrowserView.png index 628a415a..5f94e9ca 100644 Binary files a/docs/gallery/png/AvionicsBrowserView.png and b/docs/gallery/png/AvionicsBrowserView.png differ diff --git a/docs/gallery/png/BatterySubsystemView.png b/docs/gallery/png/BatterySubsystemView.png index b05e4c22..39861c3c 100644 Binary files a/docs/gallery/png/BatterySubsystemView.png and b/docs/gallery/png/BatterySubsystemView.png differ diff --git a/docs/gallery/png/CarLineageGridView.png b/docs/gallery/png/CarLineageGridView.png index 3cbf8098..934c01ca 100644 Binary files a/docs/gallery/png/CarLineageGridView.png and b/docs/gallery/png/CarLineageGridView.png differ diff --git a/docs/gallery/png/ComputerSystemInterconnectionView.png b/docs/gallery/png/ComputerSystemInterconnectionView.png index 731945dc..f8067213 100644 Binary files a/docs/gallery/png/ComputerSystemInterconnectionView.png and b/docs/gallery/png/ComputerSystemInterconnectionView.png differ diff --git a/docs/gallery/png/CoreLinkInterconnectionView.png b/docs/gallery/png/CoreLinkInterconnectionView.png index a3c18e94..19016c04 100644 Binary files a/docs/gallery/png/CoreLinkInterconnectionView.png and b/docs/gallery/png/CoreLinkInterconnectionView.png differ diff --git a/docs/gallery/png/DroneGeneralView.png b/docs/gallery/png/DroneGeneralView.png index 91303fd3..2928780b 100644 Binary files a/docs/gallery/png/DroneGeneralView.png and b/docs/gallery/png/DroneGeneralView.png differ diff --git a/docs/gallery/png/ElevatorStateTransitionView.png b/docs/gallery/png/ElevatorStateTransitionView.png index 3ce280fd..b0f927ee 100644 Binary files a/docs/gallery/png/ElevatorStateTransitionView.png and b/docs/gallery/png/ElevatorStateTransitionView.png differ diff --git a/docs/gallery/png/GroundSegmentDirectChildrenView.png b/docs/gallery/png/GroundSegmentDirectChildrenView.png index 069d11b3..cdff7a5c 100644 Binary files a/docs/gallery/png/GroundSegmentDirectChildrenView.png and b/docs/gallery/png/GroundSegmentDirectChildrenView.png differ diff --git a/docs/gallery/png/GroundSegmentRecursiveView.png b/docs/gallery/png/GroundSegmentRecursiveView.png index c464183b..1b907605 100644 Binary files a/docs/gallery/png/GroundSegmentRecursiveView.png and b/docs/gallery/png/GroundSegmentRecursiveView.png differ diff --git a/docs/gallery/png/MissionControlGeneralView.png b/docs/gallery/png/MissionControlGeneralView.png index 20b658d3..4856f080 100644 Binary files a/docs/gallery/png/MissionControlGeneralView.png and b/docs/gallery/png/MissionControlGeneralView.png differ diff --git a/docs/gallery/png/MotorRigInterconnectionView.png b/docs/gallery/png/MotorRigInterconnectionView.png index 94fa2036..77fb1e69 100644 Binary files a/docs/gallery/png/MotorRigInterconnectionView.png and b/docs/gallery/png/MotorRigInterconnectionView.png differ diff --git a/docs/gallery/png/OAuthSequenceView.png b/docs/gallery/png/OAuthSequenceView.png index 555c85a3..36db9349 100644 Binary files a/docs/gallery/png/OAuthSequenceView.png and b/docs/gallery/png/OAuthSequenceView.png differ diff --git a/docs/gallery/png/OperatorConsoleDeepView.png b/docs/gallery/png/OperatorConsoleDeepView.png index 40845bc9..3579e87a 100644 Binary files a/docs/gallery/png/OperatorConsoleDeepView.png and b/docs/gallery/png/OperatorConsoleDeepView.png differ diff --git a/docs/gallery/png/OperatorConsoleExactView.png b/docs/gallery/png/OperatorConsoleExactView.png index 81761a70..320c7b46 100644 Binary files a/docs/gallery/png/OperatorConsoleExactView.png and b/docs/gallery/png/OperatorConsoleExactView.png differ diff --git a/docs/gallery/png/PipelineActionFlowView.png b/docs/gallery/png/PipelineActionFlowView.png index 8caaf805..ee851c5a 100644 Binary files a/docs/gallery/png/PipelineActionFlowView.png and b/docs/gallery/png/PipelineActionFlowView.png differ diff --git a/docs/gallery/png/TaxonomyMatrixView.png b/docs/gallery/png/TaxonomyMatrixView.png index 6238513f..31012b5b 100644 Binary files a/docs/gallery/png/TaxonomyMatrixView.png and b/docs/gallery/png/TaxonomyMatrixView.png differ diff --git a/docs/gallery/png/TokenExchangeSequenceView.png b/docs/gallery/png/TokenExchangeSequenceView.png index 44b83b9d..116dc176 100644 Binary files a/docs/gallery/png/TokenExchangeSequenceView.png and b/docs/gallery/png/TokenExchangeSequenceView.png differ diff --git a/docs/gallery/png/WorkstationInterconnectionView.png b/docs/gallery/png/WorkstationInterconnectionView.png index 9f435646..9b35aced 100644 Binary files a/docs/gallery/png/WorkstationInterconnectionView.png and b/docs/gallery/png/WorkstationInterconnectionView.png differ diff --git a/docs/gallery/svg/MotorRigInterconnectionView.svg b/docs/gallery/svg/MotorRigInterconnectionView.svg index 69494805..8fa8e434 100644 --- a/docs/gallery/svg/MotorRigInterconnectionView.svg +++ b/docs/gallery/svg/MotorRigInterconnectionView.svg @@ -1,4 +1,4 @@ - + @@ -30,28 +30,28 @@ - + «part def» MotorRig - + «part» controller : Controller - + «part» motor : Motor - - power - - powerIn - - - encoderOut - - encoderFeedback - - - thermalOut - - thermalSense - + + power + + powerIn + + + encoderOut + + encoderFeedback + + + thermalOut + + thermalSense + diff --git a/docs/reqstream/ots/dema-rendering.yaml b/docs/reqstream/ots/dema-rendering.yaml index e0eb39cb..287b5334 100644 --- a/docs/reqstream/ots/dema-rendering.yaml +++ b/docs/reqstream/ots/dema-rendering.yaml @@ -3,7 +3,7 @@ # # Requirements for the DemaConsulting.Rendering package family (DemaConsulting.Rendering, # DemaConsulting.Rendering.Abstractions, DemaConsulting.Rendering.Layout, -# DemaConsulting.Rendering.Svg, DemaConsulting.Rendering.Skia) that SysML2Tools consumes for +# DemaConsulting.Rendering.Svg, DemaConsulting.Rendering.CanvasNet) that SysML2Tools consumes for # SysML-agnostic layout and rendering. Each requirement is verified indirectly through SysML2Tools # tests that drive the package family end-to-end. @@ -91,7 +91,7 @@ sections: title: >- DemaConsulting.Rendering shall render a laid-out layout tree to a valid PNG image. justification: | - SysML2Tools produces raster output through the package's Skia-based PngRenderer. The + SysML2Tools produces raster output through the package's CanvasNet-based PngRenderer. The renderer must turn a LayoutTree into a valid PNG image, evidenced by PNG bytes produced from an empty tree and from full workspace renders. tags: [ots] diff --git a/docs/reqstream/sysml2-tools-tool/self-test/validation.yaml b/docs/reqstream/sysml2-tools-tool/self-test/validation.yaml index eb027721..3cfab5a4 100644 --- a/docs/reqstream/sysml2-tools-tool/self-test/validation.yaml +++ b/docs/reqstream/sysml2-tools-tool/self-test/validation.yaml @@ -81,13 +81,11 @@ sections: title: >- The Validation class shall include a PNG render self-test that loads the built-in self-test model and verifies that at least one non-empty PNG stream - is produced, skipping gracefully when the SkiaSharp native library is absent. + is produced. justification: | - A PNG render self-test confirms SkiaSharp integration is operational. Skipping - when the native library is absent prevents false failures in environments that - only support SVG output. + A PNG render self-test confirms CanvasNet PNG rendering integration is operational. tests: - - Validation_RunRenderPngSelfTest_SkiaSharpAvailable_Passes + - Validation_RunRenderPngSelfTest_ValidModel_Passes - id: SysML2Tools-Tool-Validation-RenderDynamicViewSelfTests title: >- @@ -96,9 +94,9 @@ sections: SysML2Tools_RenderDynamicViewFilteredSelfTest — that synthesize and render a dynamic view (via DiagramRenderer.SynthesizeDynamicView) targeting the built-in self-test model's package with no view def present, verifying: at least one non-empty SVG stream - is produced (Svg); at least one non-empty PNG stream is produced, skipping gracefully - when SkiaSharp is absent (Png, mirroring the existing PNG self-test's skip behavior); - and that applying a --filter expression which matches nothing produces a strictly + is produced (Svg); at least one non-empty PNG stream is produced (Png, mirroring + the existing PNG self-test); and that applying a --filter expression which matches + nothing produces a strictly smaller rendered SVG than the unfiltered equivalent (Filtered), confirming the filter genuinely narrows output rather than being merely accepted. justification: | @@ -110,7 +108,7 @@ sections: not just accepted and ignored. tests: - Validation_RunRenderDynamicViewSvgSelfTest_ValidModel_Passes - - Validation_RunRenderDynamicViewPngSelfTest_SkiaSharpAvailable_Passes + - Validation_RunRenderDynamicViewPngSelfTest_ValidModel_Passes - Validation_RunRenderDynamicViewFilteredSelfTest_ValidModel_Passes - id: SysML2Tools-Tool-Validation-PassedSummary diff --git a/docs/user_guide/introduction.md b/docs/user_guide/introduction.md index 335bf1be..fdf5aa7c 100644 --- a/docs/user_guide/introduction.md +++ b/docs/user_guide/introduction.md @@ -403,7 +403,7 @@ sysml2tools render model.sysml --output out --walk-depth 3 | Extension | Format | Notes | | --- | --- | --- | | `.svg` | SVG | Zero external dependencies | -| `.png` | PNG | SkiaSharp (MIT); pixel-identical across platforms | +| `.png` | PNG | CanvasNet (MIT); pixel-identical across platforms | PNG output uses an embedded Noto Sans font to guarantee pixel-identical output across Windows, Linux, and macOS. diff --git a/docs/verification/ots/dema-rendering.md b/docs/verification/ots/dema-rendering.md index fe1ddea3..b4423e33 100644 --- a/docs/verification/ots/dema-rendering.md +++ b/docs/verification/ots/dema-rendering.md @@ -16,7 +16,7 @@ SysML2Tools: - `DemaConsulting.Rendering.Layout` — the `LayeredLayoutAlgorithm`, `LayoutEngine`, containment layout, and connector routing. - `DemaConsulting.Rendering.Svg` — the `SvgRenderer`. -- `DemaConsulting.Rendering.Skia` — the Skia-based `PngRenderer` (and JPEG/WebP renderers). +- `DemaConsulting.Rendering.CanvasNet` — the CanvasNet-based `PngRenderer` (and `JpegRenderer`). SysML2Tools relies on the family to lay a graph of sized nodes and directed edges out into placed boxes and routed orthogonal connectors, honor the requested layout direction (including a @@ -141,7 +141,7 @@ package's `SvgRenderer`. #### PngRenderer_Render_EmptyTree_WritesPngBytes -**Scenario**: The package's Skia-based `PngRenderer` renders an empty `LayoutTree`. +**Scenario**: The package's CanvasNet-based `PngRenderer` renders an empty `LayoutTree`. **Expected**: Valid PNG image bytes are written to the output stream. diff --git a/docs/verification/sysml2-tools-core/rendering.md b/docs/verification/sysml2-tools-core/rendering.md index 9e1af3c9..d40e680e 100644 --- a/docs/verification/sysml2-tools-core/rendering.md +++ b/docs/verification/sysml2-tools-core/rendering.md @@ -59,7 +59,7 @@ that the Phase 4 implementation produces a valid SVG document for the trivial ca **PngRenderer_Render_EmptyTree_WritesPngBytes**: A `PngRenderer` instance is constructed and `Render` is called with an empty `LayoutTree`, default `RenderOptions`, and a `MemoryStream`; the first four bytes of the output are asserted to equal the PNG magic -number `0x89 0x50 0x4E 0x47`. This confirms that Phase 4 SkiaSharp encoding produces +number `0x89 0x50 0x4E 0x47`. This confirms that Phase 4 CanvasNet encoding produces valid PNG output for the minimal canvas case. **DiagramRenderer_RenderWorkspace_NoViews_ReturnsEmptyList**: A `DiagramRenderer` instance diff --git a/docs/verification/sysml2-tools-tool/self-test/validation.md b/docs/verification/sysml2-tools-tool/self-test/validation.md index 48531eeb..cfbf1206 100644 --- a/docs/verification/sysml2-tools-tool/self-test/validation.md +++ b/docs/verification/sysml2-tools-tool/self-test/validation.md @@ -63,11 +63,10 @@ a silent context; the log output contains `"✓ SysML2Tools_RenderSvgSelfTest"`, that the SVG render pipeline produces output for the built-in model. This scenario is tested by `Validation_RunRenderSvgSelfTest_ValidModel_Passes`. -**Validation_RunRenderPngSelfTest_SkiaSharpAvailable_Passes**: When SkiaSharp is available, -the full validation suite is run; the log output contains -`"✓ SysML2Tools_RenderPngSelfTest"`. When SkiaSharp is absent, the suite is run without a -log and exit code is 0 (the test skips internally). This scenario is tested by -`Validation_RunRenderPngSelfTest_SkiaSharpAvailable_Passes`. +**Validation_RunRenderPngSelfTest_ValidModel_Passes**: The full validation suite is run with +a silent context; the log output contains +`"✓ SysML2Tools_RenderPngSelfTest"`. This scenario is tested by +`Validation_RunRenderPngSelfTest_ValidModel_Passes`. **Validation_RunRenderDynamicViewSvgSelfTest_ValidModel_Passes**: The full validation suite is run with a silent context; the log output contains @@ -75,12 +74,10 @@ run with a silent context; the log output contains `DiagramRenderer.SynthesizeDynamicView` (with no `view def` in the model) renders successfully. This scenario is tested by `Validation_RunRenderDynamicViewSvgSelfTest_ValidModel_Passes`. -**Validation_RunRenderDynamicViewPngSelfTest_SkiaSharpAvailable_Passes**: When SkiaSharp is -available, the full validation suite is run; the log output contains -`"✓ SysML2Tools_RenderDynamicViewPngSelfTest"`. When SkiaSharp is absent, the suite is run -without a log and exit code is 0 (the test skips internally, mirroring the existing PNG -self-test's skip behavior). This scenario is tested by -`Validation_RunRenderDynamicViewPngSelfTest_SkiaSharpAvailable_Passes`. +**Validation_RunRenderDynamicViewPngSelfTest_ValidModel_Passes**: The full validation suite is +run with a silent context; the log output contains +`"✓ SysML2Tools_RenderDynamicViewPngSelfTest"`. This scenario is tested by +`Validation_RunRenderDynamicViewPngSelfTest_ValidModel_Passes`. **Validation_RunRenderDynamicViewFilteredSelfTest_ValidModel_Passes**: The full validation suite is run with a silent context; the log output contains diff --git a/src/DemaConsulting.SysML2Tools.Core/DemaConsulting.SysML2Tools.Core.csproj b/src/DemaConsulting.SysML2Tools.Core/DemaConsulting.SysML2Tools.Core.csproj index dfeea85d..9cdd8bcd 100644 --- a/src/DemaConsulting.SysML2Tools.Core/DemaConsulting.SysML2Tools.Core.csproj +++ b/src/DemaConsulting.SysML2Tools.Core/DemaConsulting.SysML2Tools.Core.csproj @@ -53,7 +53,7 @@ - + diff --git a/src/DemaConsulting.SysML2Tools.Core/Rendering/NamespaceDoc.cs b/src/DemaConsulting.SysML2Tools.Core/Rendering/NamespaceDoc.cs index dfe216cc..26a35486 100644 --- a/src/DemaConsulting.SysML2Tools.Core/Rendering/NamespaceDoc.cs +++ b/src/DemaConsulting.SysML2Tools.Core/Rendering/NamespaceDoc.cs @@ -28,7 +28,7 @@ namespace DemaConsulting.SysML2Tools.Rendering; /// output format you need: /// /// dotnet add package DemaConsulting.Rendering.Svg # for SvgRenderer -/// dotnet add package DemaConsulting.Rendering.Skia # for PngRenderer +/// dotnet add package DemaConsulting.Rendering.CanvasNet # for PngRenderer /// /// /// diff --git a/src/DemaConsulting.SysML2Tools.Tool/DemaConsulting.SysML2Tools.Tool.csproj b/src/DemaConsulting.SysML2Tools.Tool/DemaConsulting.SysML2Tools.Tool.csproj index 7d09c92c..8d1b9ac8 100644 --- a/src/DemaConsulting.SysML2Tools.Tool/DemaConsulting.SysML2Tools.Tool.csproj +++ b/src/DemaConsulting.SysML2Tools.Tool/DemaConsulting.SysML2Tools.Tool.csproj @@ -52,17 +52,6 @@ - - - ;win-x64;win-x86;win-arm64;linux-x64;linux-arm64;linux-musl-x64;linux-musl-arm64;osx; - - @@ -96,23 +85,10 @@ - - - - - - - + - - - + + @@ -120,41 +96,4 @@ - - - - - - - - - - - diff --git a/src/DemaConsulting.SysML2Tools.Tool/Render/RenderCommand.cs b/src/DemaConsulting.SysML2Tools.Tool/Render/RenderCommand.cs index 26ac8efc..72cb26cd 100644 --- a/src/DemaConsulting.SysML2Tools.Tool/Render/RenderCommand.cs +++ b/src/DemaConsulting.SysML2Tools.Tool/Render/RenderCommand.cs @@ -3,7 +3,7 @@ // using DemaConsulting.Rendering.Abstractions; -using DemaConsulting.Rendering.Skia; +using DemaConsulting.Rendering.CanvasNet; using DemaConsulting.Rendering.Svg; using DemaConsulting.SysML2Tools.Cli; using DemaConsulting.SysML2Tools.Io; diff --git a/src/DemaConsulting.SysML2Tools.Tool/SelfTest/Validation.cs b/src/DemaConsulting.SysML2Tools.Tool/SelfTest/Validation.cs index da0886eb..9bf7a389 100644 --- a/src/DemaConsulting.SysML2Tools.Tool/SelfTest/Validation.cs +++ b/src/DemaConsulting.SysML2Tools.Tool/SelfTest/Validation.cs @@ -21,7 +21,7 @@ using System.Runtime.InteropServices; using DemaConsulting.Rendering.Abstractions; -using DemaConsulting.Rendering.Skia; +using DemaConsulting.Rendering.CanvasNet; using DemaConsulting.Rendering.Svg; using DemaConsulting.SysML2Tools.Cli; using DemaConsulting.SysML2Tools.Parser; @@ -382,7 +382,6 @@ private static async Task RunRenderSvgSelfTestAsync(Context context, DemaConsult /// /// Runs a PNG render self-test against the built-in . - /// Skips gracefully when the SkiaSharp native library is unavailable. /// /// The context for output. /// The test results collection. @@ -393,19 +392,6 @@ private static async Task RunRenderPngSelfTestAsync(Context context, DemaConsult try { - // Check whether the SkiaSharp native library is loadable before attempting PNG rendering. - // If the native runtime is absent the test is skipped (recorded as Passed) so that - // environments without the SkiaSharp native assets do not fail the suite. - if (!NativeLibrary.TryLoad("libSkiaSharp", out var nativeHandle)) - { - test.Outcome = DemaConsulting.TestResults.TestOutcome.Passed; - context.WriteLine($"↷ SysML2Tools_RenderPngSelfTest - Skipped (SkiaSharp unavailable)"); - FinalizeTestResult(test, startTime, testResults); - return; - } - - NativeLibrary.Free(nativeHandle); - using var tempDir = new TemporaryDirectory(); var modelFile = PathHelpers.SafePathCombine(tempDir.DirectoryPath, "self-test.sysml"); @@ -529,8 +515,7 @@ private static async Task RunRenderDynamicViewSvgSelfTestAsync(Context context, /// /// Runs a dynamic (ad-hoc) view PNG render self-test, mirroring - /// but with the PNG renderer. Skips - /// gracefully when the SkiaSharp native library is unavailable. + /// but with the PNG renderer. /// /// The context for output. /// The test results collection. @@ -541,17 +526,6 @@ private static async Task RunRenderDynamicViewPngSelfTestAsync(Context context, try { - // Check whether the SkiaSharp native library is loadable before attempting PNG rendering. - if (!NativeLibrary.TryLoad("libSkiaSharp", out var nativeHandle)) - { - test.Outcome = DemaConsulting.TestResults.TestOutcome.Passed; - context.WriteLine($"↷ SysML2Tools_RenderDynamicViewPngSelfTest - Skipped (SkiaSharp unavailable)"); - FinalizeTestResult(test, startTime, testResults); - return; - } - - NativeLibrary.Free(nativeHandle); - using var tempDir = new TemporaryDirectory(); var modelFile = PathHelpers.SafePathCombine(tempDir.DirectoryPath, "self-test.sysml"); diff --git a/test/DemaConsulting.SysML2Tools.Tests/DemaConsulting.SysML2Tools.Tests.csproj b/test/DemaConsulting.SysML2Tools.Tests/DemaConsulting.SysML2Tools.Tests.csproj index 46349603..bdd84788 100644 --- a/test/DemaConsulting.SysML2Tools.Tests/DemaConsulting.SysML2Tools.Tests.csproj +++ b/test/DemaConsulting.SysML2Tools.Tests/DemaConsulting.SysML2Tools.Tests.csproj @@ -63,19 +63,8 @@ - - - - - - - - - + + diff --git a/test/DemaConsulting.SysML2Tools.Tests/Rendering/RenderIntegrationTests.cs b/test/DemaConsulting.SysML2Tools.Tests/Rendering/RenderIntegrationTests.cs index bb5649ac..32ff8d11 100644 --- a/test/DemaConsulting.SysML2Tools.Tests/Rendering/RenderIntegrationTests.cs +++ b/test/DemaConsulting.SysML2Tools.Tests/Rendering/RenderIntegrationTests.cs @@ -3,7 +3,7 @@ // using DemaConsulting.Rendering.Abstractions; -using DemaConsulting.Rendering.Skia; +using DemaConsulting.Rendering.CanvasNet; using DemaConsulting.Rendering.Svg; using DemaConsulting.SysML2Tools.Rendering; using DemaConsulting.SysML2Tools.Semantic; diff --git a/test/DemaConsulting.SysML2Tools.Tests/Rendering/RenderingTests.cs b/test/DemaConsulting.SysML2Tools.Tests/Rendering/RenderingTests.cs index e7f9ba88..5f0f133c 100644 --- a/test/DemaConsulting.SysML2Tools.Tests/Rendering/RenderingTests.cs +++ b/test/DemaConsulting.SysML2Tools.Tests/Rendering/RenderingTests.cs @@ -4,7 +4,7 @@ using DemaConsulting.Rendering; using DemaConsulting.Rendering.Abstractions; -using DemaConsulting.Rendering.Skia; +using DemaConsulting.Rendering.CanvasNet; using DemaConsulting.Rendering.Svg; using DemaConsulting.SysML2Tools.Rendering; using DemaConsulting.SysML2Tools.Semantic; diff --git a/test/DemaConsulting.SysML2Tools.Tool.Tests/Render/RenderSubsystemTests.cs b/test/DemaConsulting.SysML2Tools.Tool.Tests/Render/RenderSubsystemTests.cs index 8af0dfd6..603a9043 100644 --- a/test/DemaConsulting.SysML2Tools.Tool.Tests/Render/RenderSubsystemTests.cs +++ b/test/DemaConsulting.SysML2Tools.Tool.Tests/Render/RenderSubsystemTests.cs @@ -148,17 +148,6 @@ public async Task RenderSubsystem_FormatSvg_UsesSvgRenderer() [Fact] public async Task RenderSubsystem_FormatPng_UsesPngRenderer() { - // Guard: check if SkiaSharp native library is loadable without triggering type - // initializers. Return early when the library is absent so no TypeInitializationException - // propagates through xUnit's cleanup infrastructure. - if (!System.Runtime.InteropServices.NativeLibrary.TryLoad("libSkiaSharp", out var nativeHandle)) - { - // SkiaSharp native runtime unavailable in this build environment; skip rendering. - return; - } - - System.Runtime.InteropServices.NativeLibrary.Free(nativeHandle); - // Arrange: write a SysML model with a view definition; create temp output dir var tempDir = Path.Combine(Path.GetTempPath(), $"render_png_{Guid.NewGuid():N}"); Directory.CreateDirectory(tempDir); diff --git a/test/DemaConsulting.SysML2Tools.Tool.Tests/SelfTest/ValidationTests.cs b/test/DemaConsulting.SysML2Tools.Tool.Tests/SelfTest/ValidationTests.cs index b640e71a..540525e8 100644 --- a/test/DemaConsulting.SysML2Tools.Tool.Tests/SelfTest/ValidationTests.cs +++ b/test/DemaConsulting.SysML2Tools.Tool.Tests/SelfTest/ValidationTests.cs @@ -275,25 +275,11 @@ public async Task Validation_RunExportSelfTest_ValidModel_Passes() } /// - /// Test that the PNG render self-test passes (or is skipped) when SkiaSharp is available. + /// Test that the PNG render self-test passes for the built-in self-test model. /// [Fact] - public async Task Validation_RunRenderPngSelfTest_SkiaSharpAvailable_Passes() + public async Task Validation_RunRenderPngSelfTest_ValidModel_Passes() { - // Guard: check if SkiaSharp native library is loadable without triggering type - // initializers. If unavailable, the self-test skips internally and we only check - // that the suite still exits cleanly. - if (!System.Runtime.InteropServices.NativeLibrary.TryLoad("libSkiaSharp", out var nativeHandle)) - { - // SkiaSharp unavailable — just verify the suite exits cleanly (skip is recorded as pass) - using var context = Context.Create(["--silent"]); - await Validation.RunAsync(context); - Assert.Equal(0, context.ExitCode); - return; - } - - System.Runtime.InteropServices.NativeLibrary.Free(nativeHandle); - // Arrange: capture validation output via log file var logFile = Path.Combine(Path.GetTempPath(), $"validation_test_{Guid.NewGuid()}.log"); try @@ -347,26 +333,12 @@ public async Task Validation_RunRenderDynamicViewSvgSelfTest_ValidModel_Passes() } /// - /// Test that the dynamic-view PNG render self-test passes (or is skipped) when SkiaSharp - /// is available. + /// Test that the dynamic-view PNG render self-test passes for the built-in self-test + /// model. /// [Fact] - public async Task Validation_RunRenderDynamicViewPngSelfTest_SkiaSharpAvailable_Passes() + public async Task Validation_RunRenderDynamicViewPngSelfTest_ValidModel_Passes() { - // Guard: check if SkiaSharp native library is loadable without triggering type - // initializers. If unavailable, the self-test skips internally and we only check - // that the suite still exits cleanly. - if (!System.Runtime.InteropServices.NativeLibrary.TryLoad("libSkiaSharp", out var nativeHandle)) - { - // SkiaSharp unavailable — just verify the suite exits cleanly (skip is recorded as pass) - using var context = Context.Create(["--silent"]); - await Validation.RunAsync(context); - Assert.Equal(0, context.ExitCode); - return; - } - - System.Runtime.InteropServices.NativeLibrary.Free(nativeHandle); - // Arrange: capture validation output via log file var logFile = Path.Combine(Path.GetTempPath(), $"validation_test_{Guid.NewGuid()}.log"); try