Skip to content

Add CanvasNet.Pptx Phases 1a-1d: OOXML package layer, presentation model, geometry/paint, and text layout/rendering - #33

Merged
Malcolmnixon merged 112 commits into
mainfrom
feature/pptx-document-support
Oct 7, 2026
Merged

Malcolmnixon merged 112 commits into
mainfrom
feature/pptx-document-support

Conversation

@Malcolmnixon

@Malcolmnixon Malcolmnixon commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Pull Request

Description

A new PowerPoint (.pptx) rendering feature, introducing the
DemaConsulting.CanvasNet.Pptx package, modeled on the existing
DemaConsulting.CanvasNet.Pdf package as a single Software Unit
(PptxDocument), plus a new, independently-distributed
DemaConsulting.CanvasNet.Charts package providing OOXML chart
model/rendering/parsing support consumed by the PPTX renderer. This PR
has grown across Phases 1a-1f plus several Phase 2 follow-ups and now
covers:

  • Phase 1a - OOXML package layer: zip container opening
    (System.IO.Compression.ZipArchive), [Content_Types].xml resolution,
    package/part relationship resolution (_rels/.rels, per-part .rels,
    relative ../ target traversal and root-escape rejection), hardened
    against malformed/oversized/case-mismatched input.
  • Phase 1b - Presentation/theme/slide-master/slide-layout/slide model
    and placeholder property inheritance (placeholder -> layout -> master ->
    theme).
  • Phase 1c - DrawingML shape geometry (<a:xfrm>, custom/preset
    geometry, group transforms) and paint (solid/gradient fills, outlines).
  • Phase 1d - Text body/paragraph/run parsing, inheritance
    (placeholder -> layout -> master <p:txStyles> -> theme), word-wrap /
    alignment / vertical-anchor / normAutofit layout, and glyph rendering
    reusing the core TrueTypeFont/SystemFontCatalog/PathFiller
    pipeline.
  • Phase 1e - Picture shape decoding/cropping/compositing, table
    structure/cell-rect/paint resolution, and recursive full shape-tree
    parsing (including nested groups).
  • Phase 1f - The public, per-slide Render API, dispatching a
    document-order walk of a slide's shape tree to the Phase 1c/1d/1e
    resolvers/painters.
  • Phase 2 follow-ups (this release, cumulative) - slide/layout/master
    <p:bg> background-fill resolution, <a:buChar>/<a:buAutoNum>
    bullet/numbering rendering, <p:cxnSp> connector-shape rendering,
    pattern fill (30 of 54 named preset patterns, including shape/table
    fills) and picture fill, and <p:graphicFrame> chart integration via
    the new DemaConsulting.CanvasNet.Charts package (bar/column/line/
    pie/doughnut/area chart types).

Still excluded: full text justification, spAutoFit shape-resize,
kerning, text-overflow clipping, nested tables, table auto-sizing/
banding, and radial/path gradients. Pattern and picture fills - including
slide/layout/master background fills (<p:bg>), not just shape/table
fills - are implemented. A corpus-driven hardening pass (mirroring the
PDF feature's own phased history) remains a possible future follow-up.

The DemaConsulting.CanvasNet.Pptx package depends on core
DemaConsulting.CanvasNet and the new DemaConsulting.CanvasNet.Charts
package (never on .Pdf or .Svg), consistent with existing precedent.

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
  • 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 - clean (markdownlint, cspell, yamllint, dotnet format, reqstream, versionmark, reviewmark, sysml2tools)

Testing

  • Added unit tests for new functionality (package-layer, presentation/theme/model, geometry/paint, text layout/rendering, pictures/tables/shape-tree, background fill, bullets, connectors, pattern/picture fill, and chart parsing/rendering/integration, plus system integration)
  • Updated existing tests if behavior changed (N/A - new packages)
  • All tests follow the AAA (Arrange, Act, Assert) pattern
  • Test coverage is maintained or improved

Documentation

  • Updated README.md (if applicable) - deferred; no end-user-visible feature yet
  • Updated docs/ documentation (design/verification/reqstream/sysml2 companion artifacts added/updated for the full scope landed in this PR)
  • Added code examples for new features (if applicable) - deferred until a later release
  • Updated requirements.yaml (if applicable)

Additional Notes

Remaining deferred items (full text justification, spAutoFit,
kerning, text-overflow clipping, nested tables, table auto-sizing/
banding, radial/path gradients, pattern/picture slide background fill)
and a possible future corpus-driven hardening pass are tracked
internally as potential follow-up work, not committed phases of this PR.

Copilot AI lite review requested due to automatic review settings October 2, 2026 22:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved moderate and critical findings remain in package validation, path handling, resource bounds, and test coverage.

Review effort: Lite
Findings: 2 High severity · 5 Medium severity · 1 Low severity

Open (8)
What changed in this PR

Adds the Phase 1a CanvasNet.Pptx OOXML package-layer scaffold.

Changes:

  • Adds ZIP, content-type, and relationship parsing.
  • Adds unit and integration tests.
  • Adds project wiring and requirements, design, verification, and SysML2 artifacts.
File Summary
test/​DemaConsulting.CanvasNet.Pptx.Tests/​PptxSystemIntegrationTests.cs System integration coverage
test/​DemaConsulting.CanvasNet.Pptx.Tests/​PptxDocumentTests.cs Package-layer unit tests
test/​DemaConsulting.CanvasNet.Pptx.Tests/​DemaConsulting.CanvasNet.Pptx.Tests.csproj Test project configuration
src/​DemaConsulting.CanvasNet.Pptx/​PptxDocument.Package.cs OOXML package parsing and relationship resolution
src/​DemaConsulting.CanvasNet.Pptx/​PptxDocument.cs Public document-opening and disposal API
src/​DemaConsulting.CanvasNet.Pptx/​NamespaceDoc.cs Namespace documentation
src/​DemaConsulting.CanvasNet.Pptx/​DemaConsulting.CanvasNet.Pptx.csproj Package configuration
requirements.yaml Requirements inclusion
docs/​verification/​canvas-net-pptx/​pptx-document.md Unit verification
docs/​verification/​canvas-net-pptx.md System verification
docs/​sysml2/​model/​canvas-net-pptx/​pptx-document.sysml Unit architecture model
docs/​sysml2/​model/​canvas-net-pptx.sysml System architecture model
docs/​reqstream/​canvas-net-pptx/​pptx-document.yaml Unit requirements
docs/​reqstream/​canvas-net-pptx/​platform-requirements.yaml Platform requirements
docs/​reqstream/​canvas-net-pptx.yaml System requirements
docs/​design/​introduction.md Design catalog update
docs/​design/​canvas-net-pptx/​pptx-document.md Unit design
docs/​design/​canvas-net-pptx.md System design
CanvasNet.slnx Solution project registration
.reviewmark.yaml Review configuration
.cspell.yaml Spelling configuration

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Package.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Package.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Package.cs
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Package.cs
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Package.cs
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Package.cs
Comment thread test/DemaConsulting.CanvasNet.Pptx.Tests/PptxSystemIntegrationTests.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/NamespaceDoc.cs Outdated
Copilot AI lite review requested due to automatic review settings October 2, 2026 22:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Package.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Presentation.cs
Comment thread docs/reqstream/canvas-net-pptx.yaml
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.cs
Copilot AI lite review requested due to automatic review settings October 2, 2026 23:05

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved package-validation, API correctness, documentation, and traceability issues remain.

Review effort: Lite
Findings: 5 High severity · 5 Medium severity · 2 Low severity

Open (12)
Resolved since last review (1)
Previously missed (1)

In code that hasn't changed since last review

Low severity Update dependency statement for Canvas.Rgba32 usage

docs/​design/​canvas-net-pptx/​pptx-document.md:15

This unit design still says the implementation uses only BCL types and no CanvasNet core type, but Phase 1b now parses theme colors into Canvas.Rgba32 and the project references the core package. Update this dependency statement so the design does not contradict the implementation and system design.

Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Package.cs Outdated
Copilot AI lite review requested due to automatic review settings October 3, 2026 18:28
@Malcolmnixon
Malcolmnixon force-pushed the feature/pptx-document-support branch from 97dd6e4 to 7c002dc Compare October 3, 2026 18:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Theme.cs
Copilot AI lite review requested due to automatic review settings October 3, 2026 19:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Presentation.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Geometry.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Paint.cs Outdated
Comment thread docs/design/introduction.md Outdated
Comment thread docs/verification/canvas-net-pptx.md Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/NamespaceDoc.cs Outdated
Copilot AI lite review requested due to automatic review settings October 3, 2026 23:55
@Malcolmnixon
Malcolmnixon force-pushed the feature/pptx-document-support branch from f9df468 to 29d9107 Compare October 3, 2026 23:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Geometry.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.cs
@Malcolmnixon Malcolmnixon changed the title Add CanvasNet.Pptx Phase 1a: OOXML package layer scaffold Add CanvasNet.Pptx Phases 1a-1d: OOXML package layer, presentation model, geometry/paint, and text layout/rendering Oct 4, 2026
Malcolmnixon pushed a commit that referenced this pull request Oct 4, 2026
Fixes accumulated GitHub Copilot PR-review findings against
PptxDocument.Package.cs:

- Switch OPC part-name lookup from OrdinalIgnoreCase to ordinal
  (case-sensitive) comparison per the OPC spec, and reject duplicate
  ZIP entry names instead of silently overwriting the earlier one.
- Bound XML parsing of [Content_Types].xml and relationship parts via
  XmlReaderSettings (DTD processing disabled, MaxCharactersInDocument
  capped) to prevent an XML-bomb/zip-bomb pattern from exhausting
  memory during Open.
- Validate [Content_Types].xml's root element/namespace before
  parsing Default/Override children; throw InvalidDataException for a
  malformed root instead of silently finding no entries.
- Require Default's Extension/ContentType and Override's
  PartName/ContentType attributes; throw InvalidDataException for any
  malformed element instead of silently discarding it.
- Validate relationship-part root element/namespace (package-level
  _rels/.rels and per-part .rels) and require each Relationship's
  Id/Type/Target attributes, throwing InvalidDataException for a bad
  root or a missing required attribute at both call sites.
- Update stale doc comments describing the old case-insensitive
  lookup behavior.
- Fix a test fixture relationship in PptxTextTests.cs that was
  missing a now-required Type attribute.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Malcolmnixon pushed a commit that referenced this pull request Oct 4, 2026
…review findings 7-8)

Fixes accumulated GitHub Copilot PR-review findings against
PptxDocument.Presentation.cs:

- ParseSlideIdList now validates each resolved <p:sldId> relationship
  Type ends with the OOXML slide-relationship suffix ("/slide"),
  throwing InvalidDataException if a slide ID is mistargeted at a
  theme or other arbitrary part instead of silently accepting it as a
  valid slide.
- GetSlideSizeInPixels now range-checks the rounded width/height
  against int.MinValue/int.MaxValue before casting, throwing
  InvalidDataException for an oversized EMU dimension/DPI combination
  instead of silently wrapping to a negative/invalid size.
- Updated doc comments to describe the new validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Malcolmnixon pushed a commit that referenced this pull request Oct 4, 2026
…lor attributes (PR #33 review findings 9-12)

Fixes accumulated GitHub Copilot PR-review findings against
PptxDocument.Geometry.cs, PptxDocument.Paint.cs, and
PptxDocument.Theme.cs:

- Added a shared ParseRequiredFloatAttribute helper using
  invariant-culture TryParse, and refactored ResolveShapeFrame's
  <a:off>/<a:ext> attribute parsing (ParseOff/ParseExt) to use it
  instead of a direct (float?) cast, so a non-numeric x/y/cx/cy
  attribute throws InvalidDataException rather than an unrelated raw
  FormatException.
- ParseOptionalPoint (group <a:chOff>/<a:chExt> parsing) now requires
  both attributes whenever the element itself is present, throwing
  InvalidDataException for a present-but-incomplete element instead
  of silently substituting a default - a present element with a
  missing required attribute is malformed input, not the "absent
  element" case the default is meant to cover.
- Gradient-stop <a:gs> pos parsing now uses invariant-culture TryParse
  and throws InvalidDataException for a non-numeric value instead of
  an unrelated raw FormatException.
- ParseSchemeColor now validates an OOXML color value is exactly six
  hex digits before calling Rgba32.Parse, throwing
  InvalidDataException for an eight-digit (AARRGGBB) value instead of
  silently misreading its leading byte as alpha.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Malcolmnixon pushed a commit that referenced this pull request Oct 4, 2026
…ntegration test to public API (finding 13)

Adds regression test coverage for review findings 1-12, and fixes
finding 13:

- PptxDocumentTests.cs: new tests covering case-sensitive/duplicate
  part names, bounded XML parsing, Content_Types/Relationships root
  and required-attribute validation, external-target-mode rejection,
  slide relationship type validation, slide-dimension overflow, and
  eight-digit theme color rejection.
- PptxGeometryTests.cs: new tests covering non-numeric <a:off>/<a:ext>
  attributes and present-but-incomplete <a:chOff>/<a:chExt>.
- PptxPaintTests.cs: new test covering a non-numeric gradient-stop pos
  attribute.
- PptxSystemIntegrationTests.cs: restructured the well-formed-package
  system test to assert only through PptxDocument's public API
  (SlideCount/SlideSize) instead of the internal
  ResolveRelationship/ResolvePart members, since a system-integration
  test exercising internal-only APIs contradicted this project's own
  verification-document claim that system tests exercise only
  consumer-visible behavior. The internal-API assertion this test
  previously made is already covered by the unit-test suite.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Malcolmnixon pushed a commit that referenced this pull request Oct 4, 2026
…se 1a-1d scope (PR #33 review findings 14, 16-18)

Fixes documentation staleness findings where internal artifacts still
described an earlier phase as "current" despite Phase 1c/1d having
landed:

- NamespaceDoc.cs: rewrote the summary/remarks to describe the actual
  current (Phase 1d) cumulative feature set - package layer,
  presentation/theme/master/layout/slide model, DrawingML shape
  geometry/paint, and text layout/rendering - instead of calling
  PptxDocument a "decode/rasterize-only codec" or freezing the
  description at Phase 1b.
- PptxDocument.Package.cs: fixed two stale doc-comment claims that no
  presentation-specific content is parsed anywhere in the class (see
  the companion code-change commit for the Package.cs diff itself -
  these comment fixes are included there).
- docs/design/canvas-net-pptx.md: removed a stale "(this release)"
  label from the Phase 1b paragraph.
- docs/design/introduction.md: rewrote the CanvasNetPptx system bullet
  to describe the full Phase 1a-1d cumulative scope and dependency
  list (Geometry/Drawing/Fonts), moving the "(the current release)"
  label to Phase 1d.
- docs/verification/canvas-net-pptx.md: fixed the stale first-scenario
  description (now references SlideCount/SlideSize instead of internal
  ResolveRelationship/ResolvePart), added the already-existing Phase
  1c/1d system-test scenarios, and rewrote the Acceptance Criteria
  paragraph to describe the complete current feature set instead of
  claiming geometry/paint/text rendering doesn't exist.
- docs/reqstream/canvas-net-pptx/pptx-document.yaml and
  docs/verification/canvas-net-pptx/pptx-document.md: linked all new
  regression tests added for findings 1-12 into their corresponding
  requirements' test lists (widening several requirement titles to
  describe the hardened/validated behavior), and added a new
  CanvasNetPptx-PptxDocument-CaseSensitivePartNames requirement to
  cover finding 1's case-sensitivity/duplicate-entry behavior, which
  no existing requirement described.
- docs/sysml2/model/canvas-net-pptx/pptx-document.sysml: fixed a
  matching stale "presentation-rendering codec" phrase describing
  rendering as a deferred "later phase" capability, now that it ships.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings October 4, 2026 01:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved critical and moderate correctness, security, and rendering issues remain.

Review effort: Lite
Findings: 1 High severity · 6 Medium severity

Open (7)
Resolved since last review (21)

And 1 more resolved.

Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.cs
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Paint.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Text.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.TextInheritance.cs
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.TextLayout.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.TextLayout.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.TextRender.cs
Implements Phase 1a of the multi-phase PowerPoint (.pptx) rendering
feature per .agent-logs/planning-pptx-phase1a-7f3a1c.md:

- New DemaConsulting.CanvasNet.Pptx project (net8.0/9.0/10.0),
  referencing only the core CanvasNet package, plus its
  DemaConsulting.CanvasNet.Pptx.Tests test project; both registered
  in CanvasNet.slnx.
- PptxDocument public API stub: Open(Stream), Open(string), Dispose().
- PptxDocument.Package.cs: internal OOXML package layer - opens a
  .pptx as a read-only ZipArchive, resolves [Content_Types].xml
  (default extension mappings and part-specific overrides), and
  resolves package-level (_rels/.rels) and per-part relationships,
  including relative-target (../) resolution and root-escape
  rejection. No presentation-specific content (ppt/presentation.xml,
  slides, layouts, masters, rendering) is parsed - deferred to later
  phases.
- Unit tests (PptxDocumentTests.cs) and system-integration tests
  (PptxSystemIntegrationTests.cs) using hand-authored, fully
  in-memory ZipArchive-over-MemoryStream fixtures.
- Companion artifacts: reqstream requirements (system, unit, and
  platform-requirements), design docs, verification docs, SysML2
  model files (no dependency edge to core yet, since no core symbol
  is used this phase), .reviewmark.yaml review-set blocks, and a new
  CanvasNetPptx paragraph in docs/design/introduction.md's Scope
  section.
- Added pptx/OOXML-related technical terms to .cspell.yaml.

Deviation from the task's literal file list: no
src/DemaConsulting.CanvasNet.Pptx/README.md was created, matching
the existing precedent that neither DemaConsulting.CanvasNet.Pdf nor
DemaConsulting.CanvasNet.Svg have a per-project README.md - the
repo-root README.md is already packed as the NuGet readme via each
csproj's existing relative-path "..\..\README.md" Pack entry.

Validated: fix.ps1, build.ps1 (full solution + 7347/7347 tests
passing, zero regressions), and lint.ps1 (yamllint, cspell,
markdownlint, reqstream, versionmark, reviewmark, sysml2tools,
dotnet format) all pass cleanly.
Malcolm Nixon and others added 11 commits October 6, 2026 02:14
Implements a format-agnostic OOXML c:chartSpace parser internal to
DemaConsulting.CanvasNet.Charts, consuming only System.Xml.Linq with no
OPC/ZIP/PresentationML/.Pptx dependency, reading only cached values
(c:numCache/c:strCache). Parses c:barChart (bar/col via c:barDir),
c:lineChart, c:pieChart, c:doughnutChart, and c:areaChart, including
series names, categories, values, chart title, legend presence/position,
and axis titles/range. Throws a new ChartUnsupportedFeatureException for
unsupported chart kinds (radar/scatter/bubble/stock/surface/3D/ofPie),
combo charts, and series with no cached values.

- src/DemaConsulting.CanvasNet.Charts/OpenXml/OpenXmlChartParser.cs
- src/DemaConsulting.CanvasNet.Charts/OpenXml/ChartUnsupportedFeatureException.cs
- src/DemaConsulting.CanvasNet.Charts/OpenXml/NamespaceDoc.cs
- test/DemaConsulting.CanvasNet.Charts.Tests/OpenXmlChartParserTests.cs (57 tests)
- test/DemaConsulting.CanvasNet.Charts.Tests/OpenXmlChartFixtures/README.md

Includes companion reqstream requirements, design docs, verification
docs, SysML2 model/view, .reviewmark.yaml review-set, README feature
note, and user guide API/example section. Adds openxml/textless/aiden/
misrouting/parameterless/Lbls to .cspell.yaml as genuine technical terms
introduced by this phase.

10359/10359 tests passing (up from 10188 baseline), 0 build warnings/
errors.
Resolve <p:graphicFrame> chart relationships, parse via OpenXmlChartParser,
and render via ChartRenderer onto the slide surface using the existing
picture-compositing pattern (transform/clip/z-order). Deferred chart-type
gaps in OpenXmlChartParser (ChartUnsupportedFeatureException) are wrapped
as PptxUnsupportedFeatureException at the Pptx integration boundary to
preserve the fail-closed convention and avoid leaking Charts-specific
exception types from PptxDocument's public API.

- Add one-directional project reference: Pptx -> Charts
- New PptxDocument.Charts.cs: chart part resolution + parse + exception wrap
- Thread chart-part resolution through ShapeTree/Slides/Layouts/Masters
- Render.cs: composite rendered chart onto slide surface like pictures
- Rewrite 3 existing corpus tests to expect successful chart rendering
- Add 2 new real fixtures: supported line chart, unsupported radar chart
- New PptxChartsTests.cs covering dispatch, exception wrapping, malformed
  <c:chart>, and synthetic end-to-end rendering
- Update companion docs/reqstream/verification/sysml2/reviewmark entries
  and .cspell.yaml for new genuine technical terms (texel, precomputes,
  uncontained, prst)

Tests: 10359 -> 10395 (all passing), 0 build warnings/errors.
Documentation/compliance finalization pass for the DemaConsulting.CanvasNet.Charts
feature (Phase 5 of 5, final phase). No chart code, test, or public API changes.

- requirements.yaml: add missing include for
  docs/reqstream/canvas-net-charts/chart-model/chart-renderer.yaml, fixing 15
  reqstream --lint "unknown child" errors.
- docs/design/introduction.md: rewrite the CanvasNetCharts bullet to present
  tense (Phase 4 PptxDocument integration is complete, not future) with an
  accurate deferred-chart-type clause (radar/scatter/bubble/stock/surface/3-D/
  "of pie"/combo deferred; bar/column/line/pie/doughnut/area supported); correct
  the stale CanvasNetPptx bullet claim that pattern/picture fills "remain
  explicitly deferred" (30 of 54 pattern presets are now supported, 24 remain
  deferred; picture fill is implemented).
- docs/design/canvas-net-charts.md,
  docs/design/canvas-net-charts/chart-model.md,
  docs/design/canvas-net-charts/open-xml-chart.md,
  docs/design/canvas-net-charts/open-xml-chart/open-xml-chart-parser.md:
  remove stale "Phase 3/Phase 4/future phase" framing, replacing with
  present-tense phrasing describing the completed CanvasNetPptx integration.
- docs/verification/canvas-net-charts.md: remove the "remains expected in a
  later phase" paragraph; cross-reference the existing PptxChartsTests.cs/
  fixture-corpus system-level tests in CanvasNetPptx's own verification doc.
- docs/sysml2/model/canvas-net-charts.sysml: correct a stale "As of this
  release (Phase 3)" qualifier on the CanvasNetCharts-must-never-reference-
  CanvasNetPptx constraint, which the design doc already documents as a
  permanent architectural rule, not phase-specific.
- .cspell.yaml: add gridline, gridlines, misrender (genuine Charts-related
  technical terms) plus horz, Horz, Dmnd, patt, pythonpptx, slidenum, xfrm,
  drawingml, Calibri, unoverridden, subtable (genuine pre-existing
  CanvasNetPptx technical terms/tool names needed for lint.ps1 to pass
  cleanly end-to-end).
- .reviewmark.yaml: shorten 5 over-120-char comment lines.
- docs/verification/canvas-net-charts/chart-model/chart-document.md,
  docs/verification/canvas-net-charts/chart-model/chart-renderer.md: rewrap
  heading lines for markdownlint MD013 compliance.
- docs/verification/canvas-net-pptx/pptx-document.md,
  test/DemaConsulting.CanvasNet.Pptx.Tests/PptxFixtures/README.md: shorten
  pre-existing over-120-char heading/table lines (introduced in Phase 4) also
  required for lint.ps1 to pass cleanly.
- README.md, docs/user_guide/introduction.md: add a brief mention of PPTX
  chart auto-rendering via PptxDocument.Render.

Verification performed:
- Confirmed the SysML2 Charts model (system/subsystem/unit level) is
  consistent; sysml2tools lint passes with no errors.
- Confirmed the existing user guide Chart/ChartBuilder/ChartRenderer content
  and Examples 14-15 already provide a realistic ChartBuilder + Render
  sample; no new user-guide file was warranted (no per-system file
  convention exists for Pdf/Svg/Pptx either).
- Confirmed deferred chart types and the ~24 deferred pattern-fill presets
  are both documented and discoverable from docs/design/introduction.md.

pwsh ./lint.ps1 passes cleanly (markdownlint-cli2, cspell, yamllint,
dotnet format, reqstream, versionmark, reviewmark, sysml2tools).
pwsh ./build.ps1 passes with 0 warnings, 0 errors, and the full 10395-test
suite passing (unchanged from baseline).
Clamp c:numCache/c:strCache's c:ptCount to 1,048,576 (Excel's own max
worksheet row count) before allocating the dense values/labels array.
A crafted or corrupted chart1.xml could previously declare an
arbitrarily large ptCount (e.g. 2000000000), driving an
attacker-controlled array allocation of up to ~16 GB per series and
crashing the host process with OutOfMemoryException instead of a
clean, fail-closed rejection.

Exceeding the cap now throws the existing
ChartUnsupportedFeatureException (feature token
charts-openxml-point-count-too-large), which PptxDocument already
wraps as PptxUnsupportedFeatureException.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Reject nested [/Pattern /Pattern] color space bases in
  ResolvePatternColorSpace by throwing UnsupportedImageFeatureException
  (feature pdf-colorspace-Pattern-nested) instead of letting it reach
  ComponentCount's documented-unreachable InvalidOperationException
  backstop.
- BuildShadingPattern now reads the shading dictionary's own /Domain
  entry (default [0, 1]) instead of always assuming the default,
  independently of the sampled /Function's own /Domain.
- ApplyTiffPredictor now validates decoded data length is an exact
  multiple of the row stride, mirroring ApplyPngPredictor's existing
  check, instead of silently truncating a partial trailing row.
- RenderTilingPatternCell now disposes tileSurface if cell execution or
  recoloring throws partway through, preventing a resource leak on the
  exception path.

Adds one regression test per fix in PdfDocumentTests.cs.
…erflow DoS

Both ParseShapeTree (parse-time) and RenderNode (render-time) recursed
into nested <p:grpSp> elements with no depth limit. A crafted .pptx with
deeply nested group shapes could trigger an uncatchable
StackOverflowException.

Adds MaxGroupShapeNestingDepth = 100, applied identically to both parse
and render paths, throwing InvalidDataException (matching the existing
PptxDocument size-cap convention) when exceeded.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
lint.ps1 was failing on 3 unrecognized words ('uncatchable' x2,
'nullably') introduced by the group-shape recursion-depth fix. Reworded
the comments instead of adding new entries to .cspell.yaml's protected
word list.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/DemaConsulting.CanvasNet.Charts/OpenXml/OpenXmlChartParser.cs
Comment thread src/DemaConsulting.CanvasNet.Charts/ChartRenderer.CategoryChart.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Tables.cs Outdated
Comment thread docs/design/canvas-net-charts/open-xml-chart.md Outdated
Comment thread docs/design/introduction.md Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/NamespaceDoc.cs
Malcolm Nixon and others added 3 commits October 6, 2026 16:52
… table fill transforms

- Enforce cumulative chart cache allocation budget in OpenXmlChartParser
- Prevent double-to-float overflow in category chart value mapping
- Apply transforms to all coordinate-dependent paints in table fills

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Update caller documentation for implemented PPTX chart integration
- Correct ChartRenderer dependency documentation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ment links

- Fix stale test method names referenced in pptx-document.yaml requirements
  (renamed tests were not updated in multiple requirement blocks)
- Wire 22 previously-orphaned Pptx requirements into existing parent
  children lists (Open, PlaceholderInheritance, ShapeGeometryAndPaint,
  TextLayoutAndRendering)
- Add 5 new top-level Pptx requirement blocks for Phase-2 follow-up
  features that had no existing thematic parent (SlideBackgroundFill,
  MasterLayoutShapeRendering, BulletsAndNumbering, ConnectorShapes,
  ChartGraphicFrames)
- Add CanvasNet-Canvas-PixelCompositing and CanvasNet-Lib-PixelCompositing
  to wire the orphaned Rgba32-CompositeOver requirement into root
  reachability
- Wire 3 orphaned Charts requirements (ChartUnsupportedFeatureException,
  RealFixtureEndToEnd, RenderRoundTrip) into existing/new parents

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/DemaConsulting.CanvasNet.Charts/ChartRenderer.CategoryChart.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Charts/ChartColorPalette.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Render.cs
Comment thread src/DemaConsulting.CanvasNet.Charts/NamespaceDoc.cs Outdated
Comment thread src/DemaConsulting.CanvasNet.Pptx/NamespaceDoc.cs Outdated
…urface disposal on failure, doc staleness

- Guard chart range-padding arithmetic against overflow for extreme finite values
- Wrap ChartColorPalette.Default backing array with Array.AsReadOnly
- Dispose PptxDocument render Surface on exception before rethrow
- Correct Charts NamespaceDoc: host-format chart integration is implemented
- Correct Pptx NamespaceDoc: pattern/picture background fills are implemented, no longer deferred
- Add regression test for extreme finite chart value ranges

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Unresolved moderate findings affect chart correctness, malformed-input handling, resource disposal, and stroke robustness.

Review effort: Lite
Findings: None

Resolved since last review (6)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Require chart namespace when classifying plot areas

src/​DemaConsulting.CanvasNet.Charts/​OpenXml/​OpenXmlChartParser.cs:287

ClassifyPlotArea matches chart kinds by LocalName alone, so a foreign-namespace element named barChart/radarChart is accepted as a c:* chart. If it carries c:ser children, malformed XML can be turned into a valid Chart instead of being rejected. Require e.Name.Namespace == ChartNs before applying these lookup tables.

ClassifyPlotArea matched chart-type elements by LocalName alone, so a
foreign-namespace element named e.g. barChart/radarChart could be accepted
as a c:* chart and, if it carried c:ser children, turn malformed XML into a
valid Chart instead of being rejected. Now requires e.Name.Namespace ==
ChartNs before applying the chart-type lookup tables.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Critical resource-lifetime defects and additional correctness and validation issues remain unresolved.

Review effort: Lite
Findings: 2 High severity

Open (2)
Previously missed (2)

In code that hasn't changed since last review

Medium severity Prevent overflow when mapping extreme chart values

src/​DemaConsulting.CanvasNet.Charts/​ChartRenderer.CategoryChart.cs:342

With mixed extreme finite values such as [-double.MaxValue, double.MaxValue], max - min becomes Infinity; mapping either endpoint then computes Infinity / Infinity, producing NaN coordinates and silently losing the plotted bars/points even though the render succeeds. The extreme-value test only checks the surface dimensions, so use a scaled/normalized difference when the range overflows and assert that the data remains visible.

Low severity Update verification inventory with new chart subsystems

docs/​verification/​introduction.md:48

The verification introduction still describes CanvasNetCharts as a single ChartModel subsystem containing only ChartDocument, but this PR adds ChartRenderer and the separate OpenXmlChart subsystem with OpenXmlChartParser. Update this top-level verification inventory so it does not omit the new units and subsystem.

Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Paint.cs
Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Render.cs Outdated
…w, verification doc staleness

- Dispose decoded picture surfaces after painting:
  - Render-time-only picture fills (backgrounds, shape/connector
    fills, and direct <p:pic> images) are tracked per Render() call
    and disposed once painting completes.
  - Table-cell picture fills, resolved once at parse time and cached
    inside a master/layout/slide's own shape tree, are instead owned
    by PptxDocument and disposed by Dispose().
  - Added regression tests proving repeated Render() calls on the
    same slide still paint correctly for both the render-time and
    cached picture-fill paths.
- Prevent overflow when mapping extreme chart values: ValueToPixel
  now uses a SafeRatio helper that falls back to a halved-operand
  subtraction when max - min overflows to Infinity, avoiding
  Infinity / Infinity = NaN. Strengthened the extreme-value test to
  assert data is still visibly plotted.
- Update verification inventory with new chart subsystems:
  docs/verification/introduction.md now lists ChartRenderer and the
  OpenXmlChart/OpenXmlChartParser subsystem alongside ChartDocument.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved critical and moderate findings remain, including concurrent render-state corruption and memory-safety issues.

Review effort: Lite
Findings: 1 High severity

Open (1)
Resolved since last review (2)
Previously missed (4)

In code that hasn't changed since last review

Medium severity Defensively copy the palette list in immutable options

src/​DemaConsulting.CanvasNet.Charts/​ChartRenderOptions.cs:88

Although the class is documented as an immutable options bag, this property stores the caller's IReadOnlyList reference directly. A caller can mutate the underlying list after options construction (or concurrently during rendering), changing palette resolution and potentially causing inconsistent results. Make a defensive immutable copy when the property is initialized.

Low severity Document CanvasNetPptx installation in the README

README.md:106

The README now documents installation for the new Charts package but omits DemaConsulting.CanvasNet.Pptx, even though this PR introduces that independently distributed public package and the root README is packed into it. Add a PPTX installation section alongside the existing SVG/PDF/Charts sections so users can discover how to consume the feature.

Low severity Add CanvasNetCharts to the system dependency summary

docs/​design/​introduction.md:120

This new system summary lists Canvas/Geometry/Drawing/Fonts/Codecs as CanvasNetPptx's dependencies but omits the newly introduced CanvasNetCharts dependency, even though embedded chart graphic frames now route through OpenXmlChartParser and ChartRenderer. Update the dependency summary so the design introduction does not contradict the package/model dependency graph.

Low severity Add CanvasNetPptx to the verification-system inventory

docs/​verification/​introduction.md:49

The verification-system inventory adds CanvasNetCharts but still omits the new CanvasNetPptx system, despite the PR adding docs/verification/canvas-net-pptx.md and its requirements. This makes the verification introduction incomplete and breaks the top-level navigation to the PPTX verification design.

Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Render.cs Outdated
…te immutability, doc gaps

- PptxDocument.Render.cs/Images.cs: replace the shared _currentRenderImages
  instance field with a call-local renderImages list threaded explicitly
  through Render/RenderNode/RenderShape/RenderPicture/RenderConnector and
  ResolveAndTrackPictureSurface. Two concurrent Render() calls on the same
  PptxDocument instance could previously race on the shared field, causing
  premature/duplicate disposal or leaked images; each call's own list is now
  fully isolated.
- ChartRenderOptions.cs: ColorPalette now defensively copies the caller's
  list/array in its init accessor, so mutating the original collection after
  constructing a ChartRenderOptions instance can no longer retroactively
  change palette resolution for that (documented-immutable) instance. Added
  ChartRenderOptionsTests.cs covering the defensive copy.
- README.md: documented the missing DemaConsulting.CanvasNet.Pptx package
  installation section.
- docs/design/introduction.md: added CanvasNetPptx's dependency on
  CanvasNetCharts to the system dependency summary.
- docs/verification/introduction.md: added the missing CanvasNetPptx system
  entry to the verification-system inventory.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved correctness, malformed-input handling, numerical robustness, performance, and concurrent-rendering findings remain.

Review effort: Lite
Findings: 1 High severity

Open (1)
Resolved since last review (1)
Previously missed (3)

In code that hasn't changed since last review

Medium severity Prevent mutation of ColorPalette through array casting

src/​DemaConsulting.CanvasNet.Charts/​ChartRenderOptions.cs:92

The defensive copy is stored as a raw array behind an IReadOnlyList interface. Consumers can cast options.ColorPalette back to Rgba32[] (or IList<Rgba32>) and mutate the supposedly immutable options instance, unlike the ReadOnlyCollection snapshots used by Chart and ChartSeries. Store a read-only wrapper around the copied array.

Medium severity Prevent pie total overflow from suppressing all wedges

src/​DemaConsulting.CanvasNet.Charts/​ChartRenderer.PieChart.cs:52

Summing valid finite pie values directly can overflow: two or more large positive double values (which ChartSeries accepts) make total become Infinity, so every share becomes zero and the renderer paints no wedges. Accumulate normalized values relative to the largest positive value, or otherwise use an overflow-safe summation, and use the same scale when calculating each share.

Medium severity Wrap chart model validation errors as InvalidDataException

src/​DemaConsulting.CanvasNet.Pptx/​PptxDocument.Charts.cs:81

Malformed chart data can still escape as ArgumentException here. OpenXmlChartParser.Parse delegates cache/count/range validation to Chart/ChartSeries/ChartAxis constructors, which throw ArgumentException, but this integration only translates ChartUnsupportedFeatureException; the Pptx requirement explicitly promises InvalidDataException for any malformed chart part. Catch the model-validation exception and wrap it as InvalidDataException while preserving the unsupported-feature wrapper.

Comment thread src/DemaConsulting.CanvasNet.Pptx/PptxDocument.Slides.cs
…, pie overflow, chart validation wrapping

- PptxDocument/PdfDocument: explicitly document that a single instance
  is not thread-safe, matching common .NET document/parser conventions
  (e.g. XDocument, Stream), instead of serializing every lazy cache
  behind a document-wide lock. Callers needing concurrent rendering
  should open one instance per thread or synchronize externally.
- ChartRenderOptions.ColorPalette: wrap the defensive copy in a
  ReadOnlyCollection<Rgba32> (matching Chart/ChartSeries' own pattern)
  so a caller casting the property back to Rgba32[]/IList<Rgba32>
  can no longer mutate the options instance.
- ChartRenderer.PieChart: normalize each value against the largest
  positive value before accumulating, so summing large-but-finite pie
  values can no longer overflow to Infinity and zero every wedge share.
- PptxDocument.Charts: catch ArgumentException thrown by Chart/
  ChartSeries/ChartAxis model-validation (via OpenXmlChartParser.Parse)
  and rewrap it as InvalidDataException, preserving the existing
  ChartUnsupportedFeatureException -> PptxUnsupportedFeatureException
  wrapping.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Unresolved moderate issues affect chart correctness, malformed-data handling, resource usage, and scope documentation.

Review effort: Lite
Findings: None

Resolved since last review (1)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Picture and pattern background support scope is inconsistent

src/​DemaConsulting.CanvasNet.Pptx/​PptxDocument.Render.cs:99

These render remarks say picture backgrounds are fully supported and covered pattern backgrounds are fully supported, but the PR description explicitly lists pattern/picture slide backgrounds as excluded. ResolveSlideBackgroundFill currently passes those fills through ResolveFill, so the implementation and stated scope disagree; please reconcile the behavior or the documented deferred boundary before release.

…R description exclusion claim

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Unresolved moderate findings affect chart validation and rendering, PPTX handling, resource cleanup, color resolution, and stroke robustness.

Review effort: Lite
Findings: None

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants