Skip to content

MarkdownRenderer structure step 2b: public SVG host API for resvg - #106

Merged
zhuowcui merged 1 commit into
codex/markdown-renderer-1-0from
codex/markdown-renderer-svg-host
Oct 28, 2026
Merged

zhuowcui merged 1 commit into
codex/markdown-renderer-1-0from
codex/markdown-renderer-svg-host

Conversation

@Xueyang-Song

Copy link
Copy Markdown
Collaborator

Step 2, part 2 of the MarkdownRenderer structure cleanup. It targets the #103 branch, not main.

The resvg pack plugged into the renderer through 13 internal types. They are now public API in MarkdownRenderer.Images, resvg uses only public API, and its internals grant is gone. Two grants remain (the performance harness and the sample), plus the TextMate grammar link; they come next.

The public SVG host API

Memory admission and render priority. These are optional capabilities of IMarkdownSvgRenderer; the views detect them.

Type Purpose
IMarkdownSvgAdmission TryOpenAsync opens a document if capacity allows, or reports how much it needs; WaitForCapacityAsync lets the view wait instead of failing the image.
IMarkdownSvgPreparationAdmission, IMarkdownSvgPreparationLease Reserve PrepareSource scratch memory from the same capacity.
IMarkdownSvgPrioritizedDocument A render that takes a demand, so queued work can move ahead.
MarkdownSvgRenderDemand An image's visibility, raised from overscan to visible as it scrolls into view. Providers read Priority and call RegisterPromotion; only the view creates and raises demands.
MarkdownSvgAdmissionResult, MarkdownSvgAdmissionStatus The outcome of TryOpenAsync.

The internal names said "host" (OpenForHostAsync, RenderForHostAsync, MarkdownSvgDemandTicket); the public names drop it. Each type has its own file.

Raster checks. MarkdownRasterImageInspection.Inspect(bytes) applies the renderer's own decode budget to encoded bytes without decoding them. It reports format, size, frames, decoded bytes, orientation and whether a static preview fits. resvg uses it before sending WebP and SVG-embedded rasters to its worker; before, it called the renderer's internal budget parser. MarkdownRasterFormat gains Ico, which the parser already recognized.

SVG source information. resvg reads an SVG's title, description and root size during its own validation pass. A test holds that single pass to at least 30% fewer allocations than separate passes. It now does this with the public MarkdownSvgSourceInfoReader and returns MarkdownSvgSourcePreparation.Admit(bytes, info). The view's own fallback uses the same collector, so there is still one implementation.

Decisions for review

  • Keep the single-pass SVG metadata behind a small XML-event reader instead of letting the view read every SVG again. The reader is a low-level API, but the alternatives were a second XML pass per SVG or a second copy of the title and geometry rules.
  • Inspection runs the orientation read too, so one call answers both questions resvg asks. For SVG-embedded images it is one extra bounded header scan per image.
  • New tests compare MarkdownRasterImageInspection field by field with the internal budget it wraps, and the reader with the view's own extraction.

Not covered

  • The opt-in layout-diagnostics build, which was already failing and is not part of CI, still stops in resvg. Its #if diagnostics blocks write worker events into the renderer's internal event source and read the renderer's SVG correlation ID. Step 4 replaces those blocks with a public tracing design. I updated the diagnostics-only tests to the new API, but they compile only in that build.

Verification

Check Result
MarkdownRenderer.slnx Release x64 0 warnings, 0 errors
JitHub.WinUI Release x64 with the security gate passes; 84/84 ReleaseSecurity tests
MarkdownRenderer.Tests 1,408 (+11 for the inspector and the source-info reader)
GitHub.Tests / Svg.Resvg.Tests 3,043 / 808
Math / Mermaid / Html / TextMate / Conformance 80 / 259 / 10 / 70 / 9
PublicApi.Tests / Sample.Automation.Tests / JitHub.WinUI.Tests Debug 16 / 4 / 3,126
NativeAOT project smokes: renderer, Mermaid, resvg (live worker isolation), Math, TextMate (win-x64) publish with 0 warnings and run
MarkdownRenderer package consumed by NativeAOT and trimmed single-file x86 and x64 run; ARM64 cross-published
Packed packages 8; size gates pass (936,012 bytes compressed, 2,301,440 managed)
--locked-mode restore every project except JitHub.Web, whose lock does not match this machine's SDK (10.0.14 vs 10.0.11), unchanged here
resvg worker identity, x86/x64/arm64 verified; committed binaries unchanged
Test-ProjectStructure.ps1, engineering and compliance script self-tests pass

Also not run: PixelTests, the external performance-gate subset, and Sandbox UI runs.

🤖 Generated with Claude Code

The resvg pack plugged into the renderer through internal types in three
groups. Each is now public API in MarkdownRenderer.Images, and resvg
uses only public API.

Memory admission and render priority. These are optional capabilities
an IMarkdownSvgRenderer can implement; the views detect them:
- IMarkdownSvgAdmission (TryOpenAsync, WaitForCapacityAsync), so the
  view waits for capacity instead of failing an image when the provider
  is full.
- IMarkdownSvgPreparationAdmission and IMarkdownSvgPreparationLease,
  for PrepareSource scratch memory from the same capacity.
- IMarkdownSvgPrioritizedDocument and MarkdownSvgRenderDemand, so
  queued renders move ahead when their image scrolls into view. Only
  Priority and RegisterPromotion are public; the view creates and raises
  demands.
- MarkdownSvgAdmissionResult and MarkdownSvgAdmissionStatus.
The internal names said "host" (OpenForHostAsync, MarkdownSvgDemandTicket
and so on); the public names drop it.

Raster checks. MarkdownRasterImageInspection.Inspect applies the
renderer's own decode budget to encoded bytes without decoding them.
resvg uses it before sending WebP and SVG-embedded rasters to its
worker, instead of calling the renderer's internal budget parser.
MarkdownRasterFormat gains Ico, which the parser already recognized.

SVG source information. resvg reads an SVG's title, description and
root size during its own validation pass, which a test holds to at
least 30% fewer allocations than separate passes. It now does that with
the public MarkdownSvgSourceInfoReader and hands the result over with
MarkdownSvgSourcePreparation.Admit(bytes, info). The view's own fallback
uses the same collector, so there is still one implementation.

The opt-in layout-diagnostics build, which was already failing and is
not part of CI, still stops in resvg: its #if diagnostics blocks write
worker events into the renderer's internal event source and read its
correlation ID. Step 4 replaces those blocks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zhuowcui
zhuowcui merged commit 1f0401f into codex/markdown-renderer-1-0 Oct 28, 2026
9 of 10 checks passed
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