You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add Microsoft Visio (.vsdx) document rendering support - #42
Adds Microsoft Visio (.vsdx) rendering support as a new DemaConsulting.CanvasNet.Vsdx NuGet package, following the same architecture pattern as the existing Pdf/Pptx/Svg/Charts packages: an OPC-package-aware VsdxDocument that opens a .vsdx, resolves pages/shapes (including Master/instance cell-merge inheritance, groups, connectors, geometry, themes, arrowheads, and text layout), and renders each page to a Canvas/raster surface.
Implementation proceeded across 9 original milestones (parsing, geometry, styling/theme resolution, groups, connectors/arrowheads, text layout/rendering, system integration) followed by 3 additional real-world-corpus bug-fix milestones (10, 11, 12) driven by visual comparison against Microsoft Visio (COM)-rendered ground truth for a 12-file, 16-page corpus of real-world .vsdx/.vsd-derived fixtures (from the Apache POI test-data corpus, Apache-licensed, plus permissively-licensed fixtures from dave-howard/vsdx and jgreywolf/vsdx-js). These bug-fix rounds fixed: spurious stencil/master text leakage, missing connector lines (1-D transform-cell merge), group/container fill transparency, real elliptical-arc geometry (previously skipped), a 2-D group-child transform-cell merge gap (causing fused ellipses, boundary zigzags, text overflow, and header mispositioning), and several arrowhead/text-suppression edge cases.
A small number of edge-case limitations were investigated exhaustively and found to have no safe narrow fix (would regress other correctly-rendered shapes in the corpus); these are documented as known limitations rather than silently left as bugs:
FillPattern=0 inconsistently suppressing fill in a few shapes (extension of the existing neutral-theme-fallback limitation).
One unsupported gradient FillPattern value ("36") affecting a single rack-diagram frame.
Minor UML class-compartment text/border padding on one diagram family.
Prior to opening this PR: a code review of the 3 bug-fix milestones found and the branch-level fix for one weak test assertion (commit dda2c46); a formal review was run against all 7 .reviewmark.yaml review-sets affected by this branch (Purpose, Decomposition, CanvasNetVsdx-Architecture, CanvasNetVsdx-Design, CanvasNetVsdx-Verification, CanvasNetVsdx-AllRequirements, CanvasNetVsdx-VsdxDocument), which found documentation/traceability gaps (User Guide section, orphaned requirement links, missing Acceptance Criteria section, design-intro structural drift, stale claims) in 6 of 7 sets; all findings were fixed (commit 957c740) and a recheck confirmed all 7 review-sets now Pass.
Type of Change
Bug fix (non-breaking change which fixes an issue)
New feature (non-breaking change which adds functionality)
Breaking change (fix or feature that would cause existing functionality to not work as expected)
Documentation update
Code quality improvement
Related Issues
Closes #
Pre-Submission Checklist
Build and Test
Code builds successfully and all tests pass: pwsh ./build.ps1 — 11,205 passed, 0 failed, 0 skipped
Code produces zero warnings
Code Quality
New code has appropriate XML documentation comments
Static analyzer warnings have been addressed
Quality Checks
All linters pass: pwsh ./lint.ps1 — exit code 0 (YAML, cspell/markdown, ReqStream/ReviewMark/VersionMark/SysML2 Tools, dotnet format all clean)
Testing
Added unit tests for new functionality
Updated existing tests if behavior changed
All tests follow the AAA (Arrange, Act, Assert) pattern
Test coverage is maintained or improved
Documentation
Updated README.md (if applicable)
Updated docs/ documentation (if applicable)
Added code examples for new features (if applicable)
Updated requirements.yaml (if applicable)
Additional Notes
31 commits across 12 milestones; all code review / formal review evidence is saved under .agent-logs/ (not committed as part of the diff's source, repo convention) for traceability of the process.
Visual validation corpus and Visio-COM reference renders used during development were scratch tooling outside the repo and are not part of this change.
Known, documented limitations (see docs/verification/canvas-net-vsdx/vsdx-document.md and docs/design/canvas-net-vsdx/vsdx-document.md): FillPattern=0 fill-suppression edge cases, one unsupported gradient fill pattern, and minor UML text/border padding — none affect the majority of real-world .vsdx files tested and are flagged for potential future follow-up.
Lays the documentation groundwork for a new DemaConsulting.CanvasNet.Vsdx
NuGet package providing Microsoft Visio (.vsdx) diagram-rendering support,
following the software-items.md standard:
- docs/design/canvas-net-vsdx.md + canvas-net-vsdx/vsdx-document.md: system
and unit design docs, describing the complete final feature set (shipped
as a single PR) with an ordered 9-milestone internal implementation plan.
- docs/sysml2/model/canvas-net-vsdx.sysml + subfolder: SysML2 architecture
model, wired into docs/sysml2/views/design-views.sysml.
- docs/reqstream/canvas-net-vsdx.yaml + subfolder: requirement entries
(CanvasNetVsdx-* / CanvasNetVsdx-VsdxDocument-* IDs) covering package
parsing, geometry/transform, master/stencil inheritance, style
resolution, text, connectors, color/theme, and the public Render API;
wired into root requirements.yaml.
- docs/verification/canvas-net-vsdx.md + subfolder: TODO verification
stubs, to be completed once the test suite exists.
- docs/design/introduction.md and .reviewmark.yaml updated to reference
the new system.
A research pass (not committed - see session artifacts) grounded this
design in real sample .vsdx files from the permissively-licensed
dave-howard/vsdx (BSD-3-Clause) and jgreywolf/vsdx-js (MIT) repositories;
14 of those sample files are staged for the later test-suite milestone at
test/DemaConsulting.CanvasNet.Vsdx.Tests.Fixtures-STAGING/.
No C# source/project files yet - implementation follows in subsequent
local commits per the phase plan in docs/design/canvas-net-vsdx.md.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Creates the empty, compiling project skeletons for the new
DemaConsulting.CanvasNet.Vsdx system, per Milestone 1 ("Project
scaffolding") of docs/design/canvas-net-vsdx.md's Implementation
Phase Plan.
- src/DemaConsulting.CanvasNet.Vsdx/DemaConsulting.CanvasNet.Vsdx.csproj:
new library project mirroring the sibling Pptx/Pdf/Charts csproj
conventions (net8.0/net9.0/net10.0, analyzers, SBOM, ApiMark,
SourceLink), referencing only the core DemaConsulting.CanvasNet
project (no Charts/Svg/Pdf dependency, per the design doc). Uses the
newest package versions currently in use anywhere in the repo
(DemaConsulting.ApiMark.MSBuild 0.5.4, SonarAnalyzer.CSharp
10.35.0.4138, Microsoft.CodeAnalysis.NetAnalyzers 10.0.401,
Microsoft.Sbom.Targets 4.1.13, Microsoft.SourceLink.GitHub
10.0.401).
- src/DemaConsulting.CanvasNet.Vsdx/NamespaceDoc.cs: forward-looking
namespace XML doc describing the final VsdxDocument feature set
(OPC package layer, page/master/style model, geometry+transform,
master/stencil inheritance, text, connector/glue-point routing,
color/theme resolution, public Render API), with a remarks note
that implementation is in progress and detailed scope will be
filled in on VsdxDocument as milestones land.
- src/DemaConsulting.CanvasNet.Vsdx/VsdxDocument.cs: an empty, public
sealed partial class VsdxDocument with only a one-line summary -
partial so later milestones can add VsdxDocument.*.cs files
(mirroring PptxDocument's own partial-class-per-concern
convention) without touching this file.
- test/DemaConsulting.CanvasNet.Vsdx.Tests/
DemaConsulting.CanvasNet.Vsdx.Tests.csproj: new xunit v3 test
project mirroring the sibling *.Tests.csproj conventions,
referencing only the new Vsdx project. The shared TestSupport
synthetic-font-helper link is intentionally omitted - this
milestone has no text-rendering code yet; a later milestone can
add it.
- test/DemaConsulting.CanvasNet.Vsdx.Tests/VsdxDocumentTests.cs: one
trivial smoke test confirming VsdxDocument exists and is
referenceable.
- CanvasNet.slnx: wires both new projects into the existing /src/
and /test/ solution folders, positioned immediately after their
Pptx counterparts (matching the existing, non-alphabetical but
consistent ordering).
Deferred to later milestones per the phase plan: OPC package
parsing/Open(...), page enumeration, shape/geometry model,
master/stencil inheritance, style resolution, text rendering,
connector/glue-point routing, theme/color resolution, the public
Render API, and promoting
test/DemaConsulting.CanvasNet.Vsdx.Tests.Fixtures-STAGING/ into this
test project (left untouched here).
Verified: dotnet build CanvasNet.slnx (0 warnings, 0 errors across
all three target frameworks); dotnet test on the new
DemaConsulting.CanvasNet.Vsdx.Tests project (3/3 passed - net8.0,
net9.0, net10.0); fix.ps1 run (no changes needed beyond what was
already formatted); dotnet format --verify-no-changes clean. lint.ps1
still reports pre-existing, out-of-scope cspell findings in
docs/design/introduction.md, docs/design/canvas-net-vsdx.md, and
test/DemaConsulting.CanvasNet.Vsdx.Tests.Fixtures-STAGING/ from the
prior commit; none are introduced by this change.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds missing technical terms (Visio, slnx, jgreywolfvsdxjs, Greywolf,
Lucidchart, basicshapes, diagramwithstyles, flowchartshapes) to existing
cspell:ignore comments, surfaced by lint.ps1 after the design-doc and
fixture-staging commits. Full lint.ps1 now passes clean.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implements the OPC/ZIP package layer and page index resolution for
DemaConsulting.CanvasNet.Vsdx, mirroring the proven PptxDocument precedent:
- VsdxDocument.Open(Stream) / Open(string path): opens a .vsdx as a
read-only ZIP archive with bounded buffering (MaxPackageBytes).
- VsdxDocument.Package.cs: generic OPC mechanics - [Content_Types].xml
parsing, relationship parsing/caching (_rels/.rels and part-level
.rels), "../"-relative target resolution, ResolveRelationshipByType /
TryResolveRelationshipByType, XXE-hardened XML loading.
- VsdxDocument.Pages.cs: resolves visio/document.xml (required) and
visio/pages/pages.xml (required) via relationship type; resolves
visio/masters/masters.xml and visio/theme/theme1.xml if present but
does not require them (confirmed optional via real fixture evidence
and the design doc's own exception contract); parses each <Page>'s
Name/NameU, PageWidth/PageHeight cells (inches -> EMU, ignoring any
U= formatting-hint attribute).
- VsdxPageInfo: readonly record struct (Name, WidthEmu, HeightEmu)
mirroring PptxSlideSize's shape/unit convention.
- PageCount property and GetPageSize(int) method exposed on
VsdxDocument, with idempotent Dispose().
- Exception contract mirrors Pptx exactly: ArgumentNullException/
ArgumentException for null/empty stream or path; InvalidDataException
for corrupt ZIP or a missing/empty required part. No new custom
exception type was needed.
- Full Milestone-2 test suite in VsdxDocumentTests.cs covering all
forward-declared reqstream test names, the full negative/validation
matrix, and real-fixture sanity checks (including a loop over all 14
staged sample files from the Fixtures-STAGING folder, wired into the
test project via a Link-based fixture include).
Deferred to later milestones (3+): shape/geometry parsing, masters/
styles/theme content, text, connectors, and rendering. Page-content
parts (visio/pages/pageN.xml) are intentionally not resolved yet.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… style resolution
Implements the internal per-shape resolution model for .vsdx diagrams:
- Shape tree parsing: generic Cell/Section cell-bag model for <Shapes>/<Shape>
XML (VsdxCell, VsdxCellBag, VsdxShapeNode), forward-compatible with future
group/nested-shape composition (Milestone 6).
- Master/Stencil resolution: visio/masters/masters.xml + per-master
masterN.xml parsing, with cell and geometry-row override-merge (including
the geometry-row-delete pattern) when a page shape references Master="N".
- StyleSheet chain resolution from visio/document.xml's <StyleSheets>,
including built-in style IDs, with a shape's direct cell overrides taking
final precedence.
- Geometry row parsing (MoveTo/LineTo/RelMoveTo/RelLineTo); other row types
(ArcTo, RelCubBezTo, Ellipse, etc.) are skipped gracefully per the design
doc's Risk Control Measures section, not thrown.
- 2-D and 1-D shape-local-to-page-coordinate affine transform, verified
against the format reference's worked rotation example with exact
expected-coordinate assertions.
- FillPattern 0/1 solid-or-none color/fill resolution with literal-RGB
fallback; Themed colors get a tolerant neutral-gray fallback pending full
theme/built-in-palette support.
- Reuses existing core Path/PathBuilder/Vector2/Rgba32 primitives from
DemaConsulting.CanvasNet; no parallel geometry/paint types invented.
New files: VsdxCell.cs, VsdxCellBag.cs, VsdxGeometry.cs, VsdxShapeTransform.cs,
VsdxResolvedPaint.cs, VsdxColorPalette.cs, VsdxUnsupportedFeatureException.cs,
VsdxShapeNode.cs, VsdxDocument.Shapes.cs, VsdxDocument.Masters.cs,
VsdxDocument.CellMerge.cs, VsdxDocument.Geometry.cs, VsdxDocument.Transform.cs,
VsdxDocument.Styles.cs, VsdxDocument.Paint.cs, plus VsdxTestPackages.cs and
five new test classes (Geometry/Transform/MasterInheritance/
StyleResolution/FixtureShapeResolution).
Deferred to later milestones: text (M4), connectors/glue-points (M5),
recursive group/nested-shape composition (M6), Themed/full built-in color
palette (M6), public Render API / pixel painting onto Surface (M7).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implements Milestone 4 ("Text rendering") of the Vsdx 9-milestone plan:
- Parse each shape's <Text> element (character data interleaved with
<cp IX="..."> / <pp IX="..."> run and paragraph markers) into an
ordered sequence of raw text runs (VsdxDocument.Text.cs,
VsdxTextRun.cs).
- Resolve character properties (font family/size/color/bold/italic) via
Section N="Character" cells and paragraph properties (alignment,
spacing) via Section N="Paragraph" cells, through the same TextStyle
StyleSheet chain-walking pattern already used for LineStyle/FillStyle
in Milestone 3 (instance -> Master -> Stencil -> built-in defaults),
plus direct per-shape text-section overrides
(VsdxDocument.TextStyle.cs, VsdxDocument.CellMerge.cs,
VsdxDocument.Styles.cs).
- Text-box positioning: implicit default equal to the shape's own
geometry bounding box in shape-local coordinates, with support for
explicit TxtPinX/TxtPinY/TxtWidth/TxtHeight/TxtAngle override cells
(VsdxDocument.TextBox.cs, VsdxTextBoxTransform.cs).
- Word-wrap/line-breaking and horizontal/vertical alignment within the
resolved text box, mirroring the Pptx text-layout tokenize/pack/
position pipeline, and glyph-ink path resolution via the shared
TrueTypeFont/SystemFontCatalog primitives
(VsdxDocument.TextLayout.cs, VsdxTextLayout.cs). A standalone glyph
painter (VsdxDocument.TextRender.cs) is included but intentionally
left unwired from any public API.
- VsdxShapeNode now carries resolved text runs, text-box transform, and
text layout alongside the existing geometry/paint data.
Adds VsdxTextParsingTests, VsdxTextStyleTests,
VsdxTextBoxPositioningTests, VsdxTextLayoutTests, VsdxTextRenderTests,
and VsdxFixtureTextResolutionTests (real-fixture coverage), growing the
Vsdx test suite from 201 to 297 passing tests.
Deferred to later milestones: connectors/glue-points and group/nested-
shape recursive composition (Milestone 5/6), themes (Milestone 6), and
the public Render API / pixel painting to a Surface (Milestone 7).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implements connector endpoint resolution and arrowhead rendering support
for DemaConsulting.CanvasNet.Vsdx, per the 9-milestone VSDX plan.
- Parse <Connects> sections per page into VsdxConnect records (connector
shape ID, endpoint, target shape ID, target cell, connection-point
index), associating connector shapes with their glued targets for
future use (e.g. hit-testing). Dangling/unresolved targets are
tolerated, not thrown.
- Endpoint-resolution strategy CONFIRMED against real fixture evidence:
trust the pre-baked BeginX/BeginY/EndX/EndY V= cell values already
resolved by Milestone 3's 1-D transform path, rather than dynamically
re-solving glue-point geometry. Verified across three real connector
fixtures (davehoward-test4-connectors.vsdx, jgreywolfvsdxjs-connectors.vsdx,
jgreywolfvsdxjs-diagramwithstyles.vsdx): every connector's Begin/End
cells carry a literal numeric V even when F= is a formula such as
_WALKGLUE(...) or PAR(PNT(...)), matching the format reference's
guidance that Visio bakes current glue coordinates at save time.
- Resolve BeginArrow/EndArrow/BeginArrowSize/EndArrowSize cells through
the existing StyleSheet-chain-then-direct-override precedence
(reusing the line-cell resolver), producing a VsdxArrowhead
descriptor (style + size) per endpoint. Implemented a conservative
style subset (None/OpenArrow/Arrow/Stealth/Circle/Diamond) with
graceful degrade-to-None for any unrecognized or non-numeric index,
never throwing. A real fixture (BeginArrow=13) exercises this
degrade path directly.
- New resolved-connector model types: VsdxConnect, VsdxConnectEndpoint,
VsdxConnectorEndpoints, VsdxArrowhead, VsdxArrowheadStyle. Wired into
VsdxShapeNode (Connects, ConnectorEndpoints) and VsdxResolvedPaint
(BeginArrowhead, EndArrowhead). Still no pixel painting to Surface.
- Added VsdxDocument.Connects.cs and VsdxDocument.Arrowheads.cs
following the existing partial-class-per-concern convention.
- Tests: VsdxConnectsParsingTests, VsdxGluePointResolutionTests,
VsdxArrowheadResolutionTests, VsdxConnectorFixtureTests (+20 tests;
297 -> 357 aggregated across net8.0/net9.0/net10.0, all green).
- Updated docs/reqstream/canvas-net-vsdx/vsdx-document.yaml wording for
ArrowheadRendering to reflect degrade-never-throw behavior.
Deferred to later milestones: group/nested-shape recursion and
theme/built-in-palette resolution (Milestone 6); public Render API and
pixel painting of resolved connectors/arrowheads to Surface
(Milestone 7).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…form composition
- Add VsdxTheme / VsdxDocument.Theme.cs: lazy, non-throwing parsing of visio/theme/themeN.xml
color scheme (12 RGBA slots), with graceful fallback when no theme part is present.
- Wire THEMEVAL(slot)-style cell formulas into the existing color resolution pipeline
(VsdxColorPalette.cs, VsdxDocument.Paint.cs, VsdxDocument.Styles.cs) alongside the
existing explicit RGB and FillPattern 0/1 paths.
- Add VsdxDocument.Groups.cs: recursive <Shapes> group/nested-shape resolver that composes
each child shape's local transform with its parent group's transform to arbitrary nesting
depth, with a depth-budget and resolved-shape-count guard throwing InvalidDataException on
pathological/cyclic structures.
- Extend VsdxShapeNode with a Parent reference to support the composed shape tree; rewire
VsdxDocument.Shapes.cs to use the new recursive resolver.
- Add VsdxThemeResolutionTests.cs and VsdxGroupResolutionTests.cs, grounded in real fixtures
(jgreywolfvsdxjs-* for theme parts, davehoward-test10-nested-shapes.vsdx and
davehoward-test3-house.vsdx for group nesting / Master-driven group children), plus
synthetic tests for the no-theme fallback, canonical theme-slot resolution, and the
depth/count budget exception paths that are unreachable via any real fixture.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implement VsdxDocument.Render(...) public API: page-indexed rendering to
a Surface via width/height and DPI overloads, with VsdxRenderOptions for
background color control (default opaque white). Walk the resolved
shape tree (including nested groups from Milestone 6) in document
order, accumulating page-to-pixel coordinate transforms via the new
VsdxShapeTransform.ToPageMatrix(), and dispatch each shape to geometry
fill/stroke painting (Milestone 3), text layout painting via
PaintTextLayout (Milestone 4, now wired in for the first time), and
connector line + arrowhead painting (Milestone 5) using the new
VsdxArrowheadGeometry local-space arrowhead builder.
Add end-to-end rendering regression tests covering shape-only, text,
connector, and group fixtures, plus synthetic unit tests for argument
validation, background defaults, DPI consistency, document-order
z-ordering, lazy shape-tree caching, and arrowhead painting. Link test
coverage to the pre-registered reqstream requirement IDs for the public
render API.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the 14 .vsdx fixtures, README.md, and the two LICENSE files out of
the test/DemaConsulting.CanvasNet.Vsdx.Tests.Fixtures-STAGING staging
folder into an in-project test/DemaConsulting.CanvasNet.Vsdx.Tests/VsdxFixtures
folder, mirroring the sibling Pptx package's PptxFixtures convention
exactly. Update the Vsdx test project's .csproj to use the same bare
<None Include="VsdxFixtures\**"> item form as Pptx, remove the
Staging Note section from the moved README.md, and update
.reviewmark.yaml's stale STAGING path reference on the
CanvasNetVsdx-VsdxDocument review-set. The STAGING folder is deleted
entirely now that all fixture-dependent tests pass from the new
location (confirmed: AppContext.BaseDirectory-based fixture resolution
required no code changes).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… and coverage gap tests
Reqstream traceability backfill (docs/reqstream/canvas-net-vsdx.yaml and
docs/reqstream/canvas-net-vsdx/vsdx-document.yaml): fix the drifted
tests: entries so every requirement ID references a real,
namespace-qualified, currently-passing test method name. Correct
requirement text for FillPatternDeferral (CanvasNetVsdx-ColorFill /
CanvasNetVsdx-VsdxDocument-FillPatternDeferral): the originally-planned
behavior (throw VsdxUnsupportedFeatureException on unsupported fill
patterns) was never implemented; the actual, already-approved behavior
is graceful degradation to solid fill, and the requirement text/title
now describe that - no new exception type was implemented (that would
be scope creep).
Two additional drift corrections discovered while writing this
milestone's own test coverage (documentation-only, no production code
changed, analogous to and consistent with the plan-authorized
FillPatternDeferral fix):
- GeometryUnrecognizedRowSkip: EllipticalArcTo/NURBSTo were claimed to
convert to approximating Bezier path segments; they are actually
skipped like any other unrecognized geometry row.
- ColorTableResolution: a document-level Colors/FaceNames table was
claimed to be parsed and resolved against; no such element is parsed
anywhere in VsdxDocument's source.
Both docs/design/canvas-net-vsdx.md and
docs/design/canvas-net-vsdx/vsdx-document.md are corrected to match,
each with a 'Correction note (Milestone 8)' annotation.
Verification documentation: replace the TODO stubs in
docs/verification/canvas-net-vsdx.md (system-level, 25 scenario
subsections) and docs/verification/canvas-net-vsdx/vsdx-document.md
(unit-level, 35 requirement-keyed subsections) with real test-strategy,
coverage-summary, and traceability content, mirroring the Pptx
sibling's structure and level of detail.
New test/DemaConsulting.CanvasNet.Vsdx.Tests/VsdxSystemIntegrationTests.cs:
25 test methods (24 Fact + 1 Theory over all 14 real fixtures), one per
system-level requirement, mirroring PptxSystemIntegrationTests.cs's
pattern, including a true end-to-end render-every-page-of-a-real-fixture
scenario.
Close the 5 concrete coverage gaps identified in the plan:
- Master-resolution caching (VsdxMasterInheritanceTests.cs)
- EllipticalArcTo/NURBSTo geometry rows skip tolerantly
(VsdxGeometryTests.cs)
- Geometry-row replace-by-IX merge semantics
(VsdxMasterInheritanceTests.cs)
- StyleSheet ID-0 ('No Style') chain termination
(VsdxStyleResolutionTests.cs)
- Color-table resolution: built-in palette index and direct hex literal
(new VsdxColorPaletteTests.cs)
Narrow, documented source change: VsdxDocument.Masters.cs's
ResolveMasterShape changed from private to internal (zero behavior
change) solely to allow the new caching-coverage test to call it
directly and assert the parsed master content tree is reused by
reference across repeated resolutions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Removed stale STAGING fixture-path reference in the vsdx-document.sysml
comment (pre-dated Milestone 1; test fixtures were promoted out of staging
in Milestone 8).
- Reconciled docs/sysml2/model/canvas-net-vsdx.sysml and its vsdx-document
subfolder descriptive text with the Milestone 8 design-doc corrections:
no document-level <Colors>/<FaceNames> table is parsed (only the built-in
palette, literal hex, and the Themed sentinel), EllipticalArcTo/NURBSTo/
InfiniteLine rows are tolerantly skipped rather than resolved into Path
segments, and no Drawing.Gradient type is referenced (every non-solid
FillPattern degrades to solid fill).
- Refreshed the vsdx-document.sysml sourceRef/testRef comments from a stale
pre-implementation planning-skeleton file list to the actual, current
source/test file layout.
- Refreshed the CanvasNetVsdx-VsdxDocument .reviewmark.yaml path comments
from '(planned; not yet created)' to match the completed implementation.
- Added a DemaConsulting.CanvasNet.Vsdx Features bullet and Installation
section to README.md, mirroring the existing Svg/Pdf/Charts/Pptx entries
(previously absent despite the package being fully implemented).
Full-repo validation: pwsh ./build.ps1 (11,127/11,127 tests passing across
net8.0/net9.0/net10.0) and pwsh ./lint.ps1 (markdownlint-cli2, cspell,
yamllint, dotnet format, reqstream, versionmark, reviewmark, sysml2tools)
both exit 0. dotnet reviewmark --enforce passes with no required-review
violations; the Vsdx-document review set's remaining coverage-warning gap
(*.Tests.csproj project file) is a pre-existing, repo-wide pattern shared
by every sibling test project, not a Vsdx-specific gap, and is left
untouched per scope discipline. An independent code-review pass over the
full src/DemaConsulting.CanvasNet.Vsdx and
test/DemaConsulting.CanvasNet.Vsdx.Tests diff (range 1b97b3e..HEAD) found
no defects: exception contracts, geometry/transform math, Master/StyleSheet
resolution, group-recursion budgets, resource disposal, thread-safety, and
public-API XML-doc coverage were all confirmed consistent with the
documented design.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…NonPrinting self-paint
Fixes two distinct root causes of spurious/duplicate text confirmed against
the apache/poi test-data corpus's real-world fixtures, verified visually
against Visio COM reference PNGs via the external smoke-test harness:
- VsdxDocument.Shapes.cs: ParseShapeElements now excludes a group child
<Shape Del="1"> stub (shape-level deletion, distinct from the already-
handled row-level geometry Del marker) from the resolved shape tree.
Confirmed, via a controlled git-stash A/B pixel diff, to eliminate
60973.vsdx's duplicate "OOB: N/A"/"[B] Lo1: N/A"/"TS: N/A" placeholder
text.
- VsdxDocument.Render.cs: RenderShapeRecursive now skips a shape's own
self-paint (fill/stroke/text/arrowheads) when its effective NonPrinting
cell resolves true, while still recursing into its children. Confirmed
to eliminate 44501b.vsdx's spurious "Activity" heading.
Adds VsdxDocument_GroupChildDeletedStub_ExcludedFromResolvedShapeTree to
VsdxGroupResolutionTests.cs covering the Del-stub exclusion with a small
synthetic fixture (the NonPrinting-suppression test rides along with
Bug #2's commit in VsdxRenderFixtureTests.cs, since both new tests were
appended as one contiguous diff hunk).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…orm-cell merge fix for missing connector lines
Fixes 60973.vsdx's missing connector-line defect, confirmed via the
external smoke-test harness against the Visio COM reference PNG. This
required two complementary changes beyond the plan report's original
stroke-width-only diagnosis, discovered via root-cause iteration after
the stroke-width floor alone did not resolve the visual discrepancy:
- VsdxDocument.Render.cs: PaintShapeGeometry's PaintStroke call now
applies a MinStrokeWidthPixels = 1f floor to the resolved stroke width,
so a sub-pixel LineWeight (confirmed ~0.5px at 150 DPI on this
fixture's connectors) still rasterizes a visible hairline instead of
vanishing.
- VsdxDocument.CellMerge.cs: discovered during deeper root-cause
investigation that the generic Master-wins merge rule was also
collapsing connector shape 802's resolved position to its Master's
own small, unrelated template-local corner, because its own correct,
baked PinX/PinY/LocPinX/LocPinY cells were marked F="Inh". Adds
TransformCellNames/PreferInstanceTransformCells so an instance's own
cell for the nine transform cells (PinX/PinY/Width/Height/LocPinX/
LocPinY/Angle/FlipX/FlipY) always wins over the Master's same-named
cell, even when marked Inh - narrowly scoped to exactly these cells,
since every other (genuinely shared) style cell keeps the original
Master-wins-over-Inh rule.
Adds MasterInheritance_InstanceInhMarkedTransformCell_PreferredOverMasterValue
and MasterInheritance_InstanceInhMarkedNonTransformCell_StillDefersToMasterValue
to VsdxMasterInheritanceTests.cs, and Render_SubPixelLineWeight_StillPaintsVisibleHairlineStroke
plus Render_NonPrintingShape_SkipsOwnFillButStillRendersChildren (Bug #1(b)'s
own test, appended in the same diff hunk) to VsdxRenderFixtureTests.cs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nsparency cells
Fixes 60973.vsdx's "Virtual Devices" container rendering fully opaque and
obscuring its own children, confirmed via the external smoke-test harness
against the Visio COM reference PNG.
VsdxDocument.Paint.cs's ResolvePaint now resolves FillForegndTrans/
LineColorTrans through the same FillStyle/LineStyle StyleSheet chain
already used for FillForegnd/LineColor, and a new ApplyTransparency
helper modulates the resolved FillColor/StrokeColor's alpha channel by
the parsed 0..1 transparency fraction. Confirmed via direct pixel
sampling: the container's resolved fill (127,127,127,153) blends to
(178,178,178) over white, matching the rasterizer's own alpha
compositing and the reference PNG's lighter, mostly-see-through frame.
Adds StyleResolution_FillForegndTrans_ReducesResolvedFillAlpha and
StyleResolution_LineColorTrans_ReducesResolvedStrokeAlpha to
VsdxStyleResolutionTests.cs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ty fixes
Updates the companion design/requirements/verification artifacts for this
milestone's 3 code fixes plus one doc-only note, per the originating plan
report's companion-artifact table:
- docs/design/canvas-net-vsdx/vsdx-document.md: documents the shape-level
Del="1" exclusion, the NonPrinting self-paint suppression, the stroke
hairline floor, the *Trans alpha resolution, and the CellMerge.cs
transform-cell-preference refinement discovered during this milestone's
own Bug #2 root-cause investigation (a deviation beyond the plan
report's original stroke-width-only diagnosis).
- docs/design/canvas-net-vsdx.md: records test.vsdx's header-bar/star as
a confirmed real-world sample of the already-documented Themed
neutral-fallback limitation - a documentation-only addition, no code
change, per the plan report's own non-bug determination.
- docs/reqstream/canvas-net-vsdx/vsdx-document.yaml: adds requirement
entries for deleted-shape exclusion, NonPrinting suppression, the
minimum visible stroke width, transparency honoring, and extends the
existing CellMerge requirement for the transform-cell exception.
- docs/verification/canvas-net-vsdx/vsdx-document.md: adds verification
entries for all 5 new/extended behaviors, tracing to their new unit
tests and to the external smoke-test visual-comparison evidence.
- .cspell.yaml: adds 'unconsulted', a genuine technical term (following
this file's own existing un-prefixed-word precedent) needed by the new
design/reqstream/verification prose and VsdxDocument.Paint.cs's own
ApplyTransparency remarks.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… 1-D shapes (Finding #3)
Scope the PreferInstanceTransformCells exception in VsdxDocument.CellMerge.cs to
1-D (connector) shapes only, reusing the existing BeginX/EndX detection
convention from VsdxDocument.Groups.cs, rather than applying it to every
shape type including 2-D shapes where the Master's own value can be
legitimately inherited.
- Updated the existing 1-D test fixture
(MasterInheritance_InstanceInhMarkedTransformCell_PreferredOverMasterValue)
to include BeginX/BeginY/EndX/EndY cells so it still exercises the
narrowed 1-D-only code path correctly.
- Added MasterInheritance_2DShapeInhMarkedTransformCell_DefersToMasterValue
proving a legitimate 2-D Master-inheritance-of-position scenario still
resolves correctly post-guard.
- Restored 2 assertions silently dropped from
MasterInheritance_InstanceGeometryRowWithoutDel_ReplacesMasterRowAtMatchingIndex
in a prior milestone 10 commit (Finding #4).
- Re-verified via smoke-test harness that 60973.vsdx's connector lines
(Bug #2 fix) are unaffected by the narrowing.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
)
Independently re-verified quality's claimed github260.vsdx visual
regression (a LineColorTrans="1" shape allegedly losing a border shown by
the Visio reference) by pixel-scanning the actual Visio-reference PNG at
the shape's own bounding box: no border/stroke ring exists in the
reference at all - it is a pure, borderless fill. The current invisible
rendering of that shape is caused by an unrelated, already-documented
NURBS-skip geometry limitation (confirmed via raw XML inspection and via
'git show f9c46f9 --stat', which touched only Paint.cs), not by the Bug #3
transparency fix.
No code change was made to VsdxDocument.Paint.cs. Added
StyleResolution_LineColorTrans_FullyTransparent_HasNoVisibleStroke and
StyleResolution_FillForegndTrans_FullyTransparent_HasNoVisibleFill to lock
in the existing, re-verified-correct V="1" (fully transparent) behavior.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- docs/design/canvas-net-vsdx/vsdx-document.md: document the 1-D-only
scoping of the CellMerge transform-cell exception (Finding #3), add the
Finding #1 re-verification note to the transparency resolution
narrative, and clarify the Del="1" stub-exclusion fix addresses the
stale-stub clutter text only, not the AIRttt/AIRuuu defect (Finding #2).
- docs/design/canvas-net-vsdx.md: cite github260.vsdx's circle as a second
confirmed instance of the NURBS-skip limitation, and add a new, named
deferred-limitation bullet documenting the AIRttt/AIRuuu defect as a
distinct, pre-existing, out-of-scope issue (Finding #2).
- docs/reqstream/canvas-net-vsdx/vsdx-document.yaml: update the CellMerge
entry's title/justification/tests for the 1-D-only scope, update the
TransparencyResolution entry's justification/tests with the Finding #1
re-verification evidence, and clarify the DeletedShapeExclusion entry's
justification to distinguish the Del="1" fix from the AIRttt/AIRuuu
defect.
- docs/verification/canvas-net-vsdx/vsdx-document.md: mirror the same
scope corrections and new test-scenario names in the verification
narrative for CellMerge, DeletedShapeExclusion, and
TransparencyResolution.
- .cspell.yaml: add genuine proper nouns/fixture identifiers surfaced by
the above documentation (AIRttt, AIRuuu, Lucidchart, lucidchart,
borderless) so `lint.ps1` passes cleanly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
, #3-frame contribution)
Fixes MergeGeometryRows (VsdxDocument.CellMerge.cs) to merge a matched instance/Master geometry
row cell-by-cell instead of whole-row replacement, so an instance row overriding only a subset
of its own cells still inherits the Master row's other, un-overridden cell values rather than
collapsing them to CLR defaults.
Adds MasterInheritance_GeometryRowPartialOverride_MergesCellByCellNotWholesale regression test.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…: Finding #1)
Adds EllipticalArcTo (general ellipse/arc) and ArcTo (circular, bow-height-derived) geometry-row
conversion to VsdxDocument.Geometry.cs's ResolveGeometry, producing an ArcTo path command that
reaches the row's own destination point instead of tolerantly skipping the row. A zero-bow ArcTo
row (A=0) degrades to a plain LineTo rather than throwing or producing a degenerate zero-radius
arc.
Adds Geometry_EllipticalArcToRow_ConvertsToArcReachingDestination,
Geometry_ArcToRow_ConvertsToArcWithBowDerivedRadius, and
Geometry_ArcToRow_ZeroBow_DegradesToLineTo, replacing the now-outdated
Geometry_EllipticalArcToAndNurbsToRows_AreSkippedWithoutThrowing test.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds HideText cell resolution (VsdxDocument.Paint.cs) and consults it in VsdxDocument.Render.cs
to skip only a shape's own text-run paint when HideText resolves truthy, leaving its own
fill/stroke/arrowheads and its children's painting unaffected - distinct from the broader
NonPrinting suppression which also skips fill/stroke.
Adds Render_ShapeWithHideTextCell_SuppressesOwnTextButNotFillOrStroke regression test.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…l sub-symptom)
Adds a <fld> (Field reference) element case to BuildRawRuns (VsdxDocument.Text.cs) so a field's
own nested, save-time-cached text content is parsed as a literal run instead of being silently
dropped; a <fld> interleaved between plain text segments merges into the surrounding run exactly
like a plain XText node would.
Adds TextParsing_FldElement_NestedTextContentParsedAsLiteralRun and
TextParsing_FldElementInterleavedWithText_MergesIntoSurroundingRun regression tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Maps confirmed-in-use arrowhead index 254 to a new hollow/unfilled-triangle VsdxArrowheadStyle
(VsdxArrowhead.cs, VsdxArrowheadGeometry.cs, VsdxDocument.Arrowheads.cs), found via a full-
document scan of the poi-fixtures corpus, and adds coverage for index 4 (existing solid-arrow
style family). Index 254 previously silently degraded to the unrecognized-index plain-line-end
fallback.
Adds ArrowheadResolution_EndArrowIndex4_ResolvesToArrowStyle and
ArrowheadResolution_EndArrowIndex254_ResolvesToHollowTriangleStyle regression tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…aster merge
Milestone 11 quality-retry (retry 1): fixes a confirmed geometry-row
cell-merge regression that fused/mis-sized ellipses in 60489.vsdx (Shape
114/122) and produced a floating, mispositioned, wrong-colored triangle in
44501e.vsdx (Shape 64, Master 28). Root cause: MergeGeometryRow applied the
generic "instance literal wins, else Master's cell" rule to geometry-row
coordinate cells, but these are almost always cached as F="Inh"
(formula-derived from Width/Height), so the generic rule treated them as
absent and substituted the Master's own differently-scaled cached value.
Fix: generalize PreferInstanceTransformCells to PreferInstanceCells(merged,
instanceCells, names), add an ArrowCellNames array (BeginArrow/EndArrow/
BeginArrowSize/EndArrowSize) applied through the existing 1-D-only gate
alongside TransformCellNames, and have MergeGeometryRow unconditionally
overlay the instance row's own present cells (literal or Inh) over the
generic merge result, preserving Master fallback only for cells genuinely
absent from the instance row.
While adding regression coverage for the ArrowCellNames extension, a new
test caught that PreferInstanceCells's original design (swapping which
VsdxCell wins, preserving its Formula) silently failed to affect arrowhead
resolution at all when overlaying an Inh-marked cell: ResolveLineCellValue/
ResolveFillCellValue (VsdxDocument.Paint.cs) use TryGetLiteral, which treats
any Inh-marked cell as "defer to the StyleSheet chain" rather than an
override. Fixed by writing the overlaid cell back as a literal
(Formula: null) - confirmed safe for TransformCellNames too, since its
consumer never inspects Formula.
Investigated the related arrowhead-rendering quality finding (44501e.vsdx
page 1) against the real fixture: the floating triangle is the same
geometry-row regression (fixed above); the separate "dash stub" artifacts
are a pre-existing, deliberate architecture boundary (arrowhead-decoration
painting is gated on 1-D ConnectorEndpoints; the dash-producing shapes are
ordinary 2-D Shape-typed icons) - an accepted, out-of-scope limitation, not
force-fixed.
Added regression tests:
- MasterInheritance_GeometryRowAllCellsInhButInstanceSizeDiffers_InstanceCoordinatesWin
- MasterInheritance_GeometryRowCellGenuinelyAbsentOnInstance_StillFallsThroughToMaster
- ArrowheadResolution_InstanceInhMarkedArrowCell_PreferredOverMasterValue
- ArrowheadResolution_2DShapeInhMarkedArrowCell_DefersToMasterValue
Verified via the external smoke-test harness: 60489.vsdx page 0 now renders
two distinct, correctly-sized ellipses; 44501e.vsdx page 1 no longer shows
the floating triangle and continues to render the EndArrow=254 hollow
triangle correctly; no regressions in 44501d.vsdx, 44501a.vsdx, 60973.vsdx
(pages 0-3), test.vsdx, and github260.vsdx.
dotnet build CanvasNet.slnx: 0 warnings, 0 errors.
Vsdx test project: 657/657 passed.
Full solution: 11193/11193 passed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ry 1)
Updates the reqstream YAML, design docs, and verification doc to match the
actual, evidence-based outcome of this quality-retry cycle rather than the
plan's hypothesis:
- GeometryRowMerge: corrected wording to the verified unconditional-overlay
rule; cites both the 60489.vsdx ellipse and 44501e.vsdx Shape-64 triangle
evidence; lists the 2 new geometry regression tests.
- CellMerge: documents the ArrowCellNames generalization and the
literalization fix discovered via testing; lists the 2 new arrow
regression tests.
- ArrowheadRendering: documents the investigation's conclusion - the
floating triangle is fixed via the geometry-row fix; the dash-stub
artifacts are characterized as an accepted, pre-existing, out-of-scope
1-D-only rendering-architecture limitation, not a regression and not
force-fixed. No requirement scope change.
docs/design/canvas-net-vsdx.md gains a new "Milestone 11's quality-retry
cycle (retry 1)" list entry; docs/design/canvas-net-vsdx/vsdx-document.md
corrects the geometry-row-merge cell-by-cell description and documents the
fix's rationale; docs/verification/canvas-net-vsdx/vsdx-document.md adds
matching verification notes with before/after visual-confirmation evidence
for GeometryRowMerge, CellMerge, and ArrowheadRendering.
pwsh ./fix.ps1 and pwsh ./lint.ps1 both ran clean after these changes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MergeCells now applies the TransformCellNames (PinX/PinY/Width/Height/
LocPinX/LocPinY/Angle/FlipX/FlipY) instance-wins overlay when the merged
shape is a Group child (isGroupChild: parent is not null), independent of
the existing 1-D-only test. This fixes a stale Master template-default
transform cell incorrectly winning over a resized Group child instance's
own correct, F="Inh"-marked value.
Confirmed via the external smoke-test harness against the real-world
corpus: Test_Visio-Some_Random_Text.vsdx's "View" table shape no longer
over-wraps its text (TxtWidth no longer falls back to a stale Master
Width), test.vsdx's header bar now sits flush at the top of its group,
and 44501e.vsdx's "-has" connector label now resolves to its own correct
external position. The top-level (non-group-child) 2-D shape exclusion
is untouched and remains locked by
MasterInheritance_2DShapeInhMarkedTransformCell_DefersToMasterValue.
Adds synthetic-fixture tests:
- MasterInheritance_2DGroupChildInhMarkedTransformCell_PrefersInstanceValue
- TextBox_GroupChildInhMarkedWidthDiffersFromMaster_TxtWidthReflectsInstanceWidth
- TextLayout_CorrectedGroupChildWidth_FitsOneLineWhereStaleMasterWidthOverWrapped
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
docs/design/canvas-net-vsdx.md: revise the Milestone 11 "2-D shape
transform-cell-merge exclusion" deferred-limitation bullet to record it
is now fixed for the group-child case, while 60973.vsdx's rack-frame
remains invisible for a separate, already-documented Themed-color/
gradient-fill reason, not a transform-cell problem. Adds a new bullet
extending the Milestone 4 neutral-theme-fallback deferral with this
milestone's exhaustive cross-fixture Themed-color investigation
(test_text_extraction.vsdx/60489.vsdx needing unfilled vs. 60973.vsdx
needing filled with real theme colors; no safe discriminator found).
Documents Finding #5 (UML class-name text crowding the compartment's own
top border in 44501d.vsdx/44501e.vsdx) as deferred/unresolved with
precise follow-up scope.
docs/verification/canvas-net-vsdx/vsdx-document.md and
docs/reqstream/canvas-net-vsdx/vsdx-document.yaml: update the
CanvasNetVsdx-VsdxDocument-CellMerge requirement/verification entry to
describe the group-child transform-cell carve-out, list the new tests,
and record the real-world-corpus confirmation evidence.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Code review flagged that Render_ShapeWithHideTextCell_SuppressesOwnTextButNotFillOrStroke
only sampled a single interior pixel, which would still pass even if the
HideText suppression were removed entirely. Now scans every pixel in the
shape's full rendered bounds and asserts each matches the pure fill color,
proving no glyph ink was painted anywhere.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Addresses all Critical/High/Medium findings (and one trivial Low) from the
7 formal-review reports run against the Vsdx work on this branch. No C#
production source behavior changes; one new unit test added to close a
coverage gap, plus a cspell-ignore fix in an existing test file.
Purpose review (F9, High):
- Add a full `VsdxDocument` User Guide API Reference section and a new
`Example 16` to docs/user_guide/introduction.md, mirroring the existing
PdfDocument section structure/tone.
Decomposition review (DES-01/DES-02):
- Reword the self-contradictory ChartModel unit-count sentence in
docs/design/introduction.md (two units, not "a single unit... and a
ChartRenderer unit").
- Add the missing CanvasNetVsdxView.svg diagram embed to
docs/design/canvas-net-vsdx/vsdx-document.md.
CanvasNetVsdx-Architecture review (DES-02, High):
- Add CanvasNetVsdx to docs/design/introduction.md's Software Structure and
Folder Layout sections.
- Document 6 existing unit tests (geometry, group-resolution, style,
render) as system-level Test Scenario coverage for the Milestone 10/11
capabilities in docs/verification/canvas-net-vsdx.md, since they already
exercise the full public API end-to-end.
CanvasNetVsdx-Design review:
- Link the 6 orphaned Milestone 10/11 unit requirements under their system
parent requirements in docs/reqstream/canvas-net-vsdx.yaml (arc-geometry
resolution, deleted-shape exclusion, transparency resolution,
non-printing suppression, minimum stroke width, hide-text suppression).
- Fix the broken MasterShapeInheritance -> CellMerge cross-references and
the stale "unimplemented"/planning-skeleton header comment in
docs/reqstream/canvas-net-vsdx/vsdx-document.yaml.
CanvasNetVsdx-Verification review:
- Add the missing Acceptance Criteria section to
docs/verification/canvas-net-vsdx/vsdx-document.md.
- Add CanvasNetVsdx to docs/verification/introduction.md's Scope section.
- Correct the stale "EllipticalArcTo is never converted" claim in
docs/verification/canvas-net-vsdx.md (Milestone 11 implemented real
elliptical-arc geometry resolution).
CanvasNetVsdx-AllRequirements review:
- Covered by the same reqstream/vsdx-document.yaml fixes above.
CanvasNetVsdx-VsdxDocument review (F-1 Medium, F-2/F-3 Low):
- Update docs/design/canvas-net-vsdx/vsdx-document.md's Key Methods entry
for ResolveEffectiveShape/CellMerge to describe the Milestone 12
isGroupChild carve-out, and the Data Model section to describe the
Milestone 11 arrowhead-index 4/254 recognition.
- Add a regression test
(ArrowheadResolution_2DGroupChildInhMarkedArrowCell_DefersToMasterValue)
proving the isGroupChild carve-out is deliberately scoped away from
ArrowCellNames, closing the F-3 coverage gap.
Verified clean with `pwsh ./lint.ps1` (markdownlint, cspell, yamllint,
reqstream, versionmark, reviewmark, sysml2tools) and a full
`pwsh ./build.ps1` run (11,205 tests passed, 0 failed, 0 skipped).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nvariant scale, TxtAngle text rotation, exception accessibility, stale docs, and ApiMark bump
Addresses all 8 GitHub Copilot automated review findings on PR #42:
1. VsdxDocument.Paint.cs: ResolvePaint no longer derives shape-wide HasFill/HasLine
from only geometry section 0's NoFill/NoLine; shape-wide flags now come purely
from FillPattern/LinePattern, with per-section suppression handled exclusively
by PaintShapeGeometry's existing per-section check. Regression test added.
2. VsdxDocument.Render.cs: AverageScale now computes the lengths of the transformed
basis vectors instead of the raw matrix diagonal, making it rotation-invariant.
Regression test compares stroke thickness of a rotated vs unrotated line.
3. VsdxDocument.Render.cs/TextLayout.cs/VsdxTextBoxTransform.cs: TxtAngle is now
composed into a dedicated text-to-pixel transform (ResolveTextToPixelTransform)
applied at paint time, rotating the text box about its own pin - a contained,
low-risk fix (approach a). Added a direct unit test of the composed transform.
4. VsdxUnsupportedFeatureException.cs: made public (was internal) to match its own
documented "callers can distinguish unsupported features" contract and the
sibling PptxUnsupportedFeatureException's public convention. Confirmed via
repo-wide search it has zero throw-sites today; kept (not removed) since
existing approved docs already describe it as intentional future scaffolding.
5. docs/sysml2/model/canvas-net-vsdx.sysml: corrected stale row-support list -
EllipticalArcTo/ArcTo are implemented (Milestone 11, resolved into real ArcTo
path commands); only NURBSTo/InfiniteLine/RelCubBezTo/SplineStart/SplineKnot/
PolylineTo/Ellipse remain genuinely skipped/deferred.
6. docs/sysml2/model/canvas-net-vsdx/vsdx-document.sysml: corrected stale claim
that Foreign shapes and non-solid FillPattern values throw
VsdxUnsupportedFeatureException - non-solid fills degrade to solid, and
Foreign shapes have no distinct Type-based handling at all.
7. VsdxDocument.cs: rewrote the class's stale Milestone-2-era XML remarks (which
claimed no shape/geometry/style/text/connector parsing existed) to accurately
describe current capabilities, mirroring PptxDocument's remarks style/tone.
Also corrected a stale "deferred to Milestone 7" remark on VsdxTextLayout.
8. VsdxTextStyleTests.cs: strengthened the VerticalAlign/margin test, which
previously only asserted TextLayout was non-null, to assert the resolved
glyph's actual X/Y origin differs measurably between the StyleSheet-inherited
default and a shape's own overriding VerticalAlign/LeftMargin cells.
Also bumps DemaConsulting.ApiMark.MSBuild to 0.5.7 across every package in the
repo (previously an inconsistent mix of 0.5.1/0.5.4/0.5.4 on Vsdx) - 0.5.7 picks
up fixes for cref link resolution and type-only cref rendering between 0.5.4 and
0.5.7 that are directly relevant to this repo's heavy XML-doc <see cref> usage.
Full solution build and all 11214 tests pass; lint.ps1 exits 0.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
An explicit empty <Text/> (or a text element containing only markers) produces a raw run list with Count == 0, so this condition treats the element as absent and copies the master's text. That can reintroduce master/stencil labels on instances that intentionally suppress their inherited text. Preserve whether the <Text> element exists and only use the master fallback when it is actually absent.
A positive but very large PageWidth/PageHeight value can make the EMU conversion overflow here, causing OverflowException instead of the documented InvalidDataException for malformed page dimensions/package data. Catch the overflow (or validate the scaled value before casting) and preserve the public error contract.
Update outdated namespace implementation status documentation
This namespace documentation still says implementation is in progress, but this PR wires the complete public VsdxDocument/Render implementation and documents it as delivered. Leaving this text in the generated API documentation gives consumers an incorrect status and should be replaced with a current description of the supported behavior and known gaps.
The class summary says this text painter is not wired into any public API, but RenderShapeRecursive now calls PaintTextLayout at VsdxDocument.Render.cs:218-219. This stale statement contradicts the shipped behavior and should be updated so the XML documentation does not describe an obsolete milestone state.
Correct EffectiveCells documentation for descendant shapes
ResolveShapeRecursive assigns EffectiveCells for every descendant, not just page-level shapes; the nested-shape test explicitly asserts this for children. The “only ... top-level shapes” qualifier is incorrect and should be removed so the model documentation matches the resolved tree.
This provenance section lists 14 fixtures from only the BSD-3-Clause and MIT sources, but the PR description says the validation corpus is a 12-file/16-page Apache POI-derived corpus plus these permissively licensed fixtures. Please reconcile the README, fixture set, and PR description so the shipped third-party artifacts have an accurate provenance and count.
…mal-review recheck doc gaps)
Addresses all 7 findings from GitHub Copilot's automated review round 2 on
PR #42 (after commit f6e3cf0 fixed the first 8), plus 2 additional
doc-propagation gaps found by a formal-review recheck of that same commit.
1. (High) VsdxDocument.Shapes.cs: ParseShapeElement/ParseShapeElements now
enforce the same MaxGroupNestingDepth/MaxResolvedShapeCount budget during
the parse pass itself (not only during ResolveShapeRecursive), so a
deeply nested or very wide untrusted page/master can no longer exhaust
the call stack or memory before either safety budget is reached. Added
direct ParseShapeElement unit tests (bypassing the resolver entirely) for
both the depth and count budgets.
2. (Medium) VsdxDocument.Groups.cs / VsdxTextRun.cs / VsdxDocument.Text.cs:
added VsdxRawText.HasElement so an explicit, empty <Text/> element is
distinguished from a genuinely absent one; the Master-text fallback now
checks HasElement instead of Runs.Count, so an instance's intentional
empty <Text/> no longer reintroduces the Master's text. Added regression
tests for both the empty-and-present and absent cases.
3. (Medium) VsdxDocument.Pages.cs: ParseSizeCellEmu now catches the EMU
conversion's OverflowException for a pathologically large page
dimension and re-throws the documented InvalidDataException, preserving
the public error contract. Added a regression test with a 1e300-inch
PageWidth asserting InvalidDataException (not OverflowException).
4. (Low) NamespaceDoc.cs: replaced the stale "implementation is in
progress" remarks with an accurate description of the shipped
VsdxDocument/Render functionality and its known limitations (FillPattern
edge cases, one unsupported gradient pattern, minor UML text padding).
5. (Low) VsdxDocument.TextRender.cs: corrected the class summary - the text
painter is wired into RenderShapeRecursive via PaintTextLayout, not
"not yet wired into any public API".
6. (Low) VsdxShapeNode.cs: removed the incorrect "only for page-level
shapes" qualifier from the EffectiveCells doc - ResolveShapeRecursive
assigns it for every descendant shape too.
7. (Low) VsdxFixtures/README.md: confirmed the existing 14-file
davehoward-*/jgreywolfvsdxjs-* provenance list/count is accurate, and
added a clarifying note that the separate Apache-POI-derived
12-file/16-page corpus and smoke-test scratch tooling mentioned in the
PR description were never checked into this repository.
8. Removed the stale "VsdxUnsupportedFeatureException is thrown for
Foreign shapes / non-solid FillPattern" claim from VsdxDocument.cs's own
class remarks, docs/design/canvas-net-vsdx.md, and
docs/design/introduction.md, matching the wording already corrected in
docs/sysml2/model/canvas-net-vsdx/vsdx-document.sysml by commit f6e3cf0:
neither case is distinctly branched on or throws today.
9. Documented the TxtAngle/text-box-rotation fix
(ResolveTextToPixelTransform) from f6e3cf0: added a Key Methods entry in
docs/design/canvas-net-vsdx/vsdx-document.md, a new requirement
(CanvasNetVsdx-VsdxDocument-TextBoxRotationRendering) in
docs/reqstream/canvas-net-vsdx/vsdx-document.yaml, and a matching
verification section in docs/verification/canvas-net-vsdx/vsdx-document.md.
pwsh ./build.ps1: Build succeeded, 0 warnings, 0 errors; 11229/11229 tests
passed across all target frameworks.
pwsh ./lint.ps1: exit code 0.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Addressed the 6 "Previously missed" findings from the latest review (commit 29c9605):
Preserve intentionally empty shape text (VsdxDocument.Groups.cs) — added a HasElement flag to distinguish an explicit empty <Text/> from a genuinely absent one; only the latter now falls back to the master's text. Regression test added.
Prevent page dimension conversion overflow (VsdxDocument.Pages.cs) — EMU conversion now validates the scaled value before casting and throws the documented InvalidDataException instead of an unhandled OverflowException. Regression test added.
Outdated namespace implementation status (NamespaceDoc.cs) — rewritten to describe current shipped capabilities and known limitations instead of "implementation in progress".
Stale text painter wiring doc (VsdxDocument.TextRender.cs) — corrected to reflect that PaintTextLayout is wired into RenderShapeRecursive.
EffectiveCells documentation for descendant shapes (VsdxShapeNode.cs) — removed the incorrect "top-level shapes only" qualifier; it's assigned for every descendant.
Fixture provenance/corpus counts (VsdxFixtures/README.md) — clarified that only the BSD-3-Clause/MIT-licensed fixtures are committed to this directory, and added a disclaimer distinguishing the committed fixture set from the separate (non-committed) Apache-POI-derived visual-validation corpus used during development.
…x-Render
The CanvasNetVsdx-VsdxDocument-TextBoxRotationRendering unit requirement
added for the TxtAngle text-box rotation fix (PR #42 round 1) was never
added as a child of its system-level parent, causing reqstream --enforce
to report it as orphaned (unreachable from any system/quality-tagged
requirement).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
x includes the first-line indent because it is initialized to IndFirst, but PositionLines uses LineWidthInches for centering and then adds each glyph's XInLineInches, which already includes that indent. A centered first line is therefore shifted by half the indent. Keep the indent out of the stored natural line width (or otherwise apply it in only one place).
Preserve theme formulas when resolving character colors
ResolveCharacterCell returns only the color value, so this 2-argument overload cannot inspect the cell's formula or the document theme. A text cell such as Color="Themed" with F="THEMEVAL(\"accent1\")" consequently always resolves to the neutral gray fallback, while fill/line colors use the theme-aware overload. Preserve the resolved character cell's formula and pass it together with GetTheme() here.
This field's XML documentation still says the masters part is not parsed and is reserved for a later milestone, but ResolveMasterShape now consumes _mastersPartPath to parse and cache master content during GetPageShapes. Update the comment so maintainers and generated internal API docs describe the current master-resolution behavior.
This XML summary is stale: MasterShapeId is actively used by ResolveShapeRecursive to correlate each group child with its master's child before merging and resolving it. Saying it is not resolved misleads maintainers about the behavior delivered in this PR; please describe the correlation instead.
The TextRuns summary still says this is populated only for top-level shapes, but ResolveShapeRecursive assigns TextRuns, TextBox, and TextLayout for every nested child as well. This contradicts the shipped nested-group text behavior and can cause callers/tests to incorrectly assume child text is unavailable; remove the top-level-only qualification.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request
Description
Adds Microsoft Visio (
.vsdx) rendering support as a newDemaConsulting.CanvasNet.VsdxNuGet package, following the same architecture pattern as the existingPdf/Pptx/Svg/Chartspackages: an OPC-package-awareVsdxDocumentthat opens a.vsdx, resolves pages/shapes (including Master/instance cell-merge inheritance, groups, connectors, geometry, themes, arrowheads, and text layout), and renders each page to aCanvas/raster surface.Implementation proceeded across 9 original milestones (parsing, geometry, styling/theme resolution, groups, connectors/arrowheads, text layout/rendering, system integration) followed by 3 additional real-world-corpus bug-fix milestones (10, 11, 12) driven by visual comparison against Microsoft Visio (COM)-rendered ground truth for a 12-file, 16-page corpus of real-world
.vsdx/.vsd-derived fixtures (from the Apache POI test-data corpus, Apache-licensed, plus permissively-licensed fixtures fromdave-howard/vsdxandjgreywolf/vsdx-js). These bug-fix rounds fixed: spurious stencil/master text leakage, missing connector lines (1-D transform-cell merge), group/container fill transparency, real elliptical-arc geometry (previously skipped), a 2-D group-child transform-cell merge gap (causing fused ellipses, boundary zigzags, text overflow, and header mispositioning), and several arrowhead/text-suppression edge cases.A small number of edge-case limitations were investigated exhaustively and found to have no safe narrow fix (would regress other correctly-rendered shapes in the corpus); these are documented as known limitations rather than silently left as bugs:
FillPattern=0inconsistently suppressing fill in a few shapes (extension of the existing neutral-theme-fallback limitation).FillPatternvalue ("36") affecting a single rack-diagram frame.Prior to opening this PR: a code review of the 3 bug-fix milestones found and the branch-level fix for one weak test assertion (
commit dda2c46); a formal review was run against all 7.reviewmark.yamlreview-sets affected by this branch (Purpose,Decomposition,CanvasNetVsdx-Architecture,CanvasNetVsdx-Design,CanvasNetVsdx-Verification,CanvasNetVsdx-AllRequirements,CanvasNetVsdx-VsdxDocument), which found documentation/traceability gaps (User Guide section, orphaned requirement links, missing Acceptance Criteria section, design-intro structural drift, stale claims) in 6 of 7 sets; all findings were fixed (commit 957c740) and a recheck confirmed all 7 review-sets now Pass.Type of Change
Related Issues
Closes #
Pre-Submission Checklist
Build and Test
pwsh ./build.ps1— 11,205 passed, 0 failed, 0 skippedCode Quality
Quality Checks
pwsh ./lint.ps1— exit code 0 (YAML, cspell/markdown, ReqStream/ReviewMark/VersionMark/SysML2 Tools, dotnet format all clean)Testing
Documentation
Additional Notes
.agent-logs/(not committed as part of the diff's source, repo convention) for traceability of the process.docs/verification/canvas-net-vsdx/vsdx-document.mdanddocs/design/canvas-net-vsdx/vsdx-document.md):FillPattern=0fill-suppression edge cases, one unsupported gradient fill pattern, and minor UML text/border padding — none affect the majority of real-world.vsdxfiles tested and are flagged for potential future follow-up.