feat(svm): clip the drawing to what the metafile clips it to - #787
Merged
Conversation
This was referenced Aug 30, 2026
andiwand
force-pushed
the
feat/svm-bitmaps
branch
from
August 30, 2026 09:45
b7d7c6f to
746d43a
Compare
`CLIPREGION` and the two actions that intersect a region into it were skipped like any unimplemented action, so anything a metafile drew outside its own clip was shown in full. Every metafile a document carries sets one: 1124 of the 1125 harvested from the fixtures intersect a rectangle, 50 intersect a region. An svg `clip-path` names one shape and `ISECT…` intersects, so two clips become two groups, one inside the other. The state's clip is therefore a stack of shapes: `ensure_clip` keeps the groups the next drawing action still wants, closes the ones it does not and opens what is missing, which also makes a `POP` that restores the clip nothing special. A region streams as a band list - a union of rectangles - and from version 2 also as the poly-polygon those were rasterised from, which is the better outline where it is there. Both go into one `<path>`: disjoint bands make union and even-odd the same thing, and a poly-polygon wants even-odd anyway. Two details worth naming: vcl does not re-scale a clip when the map mode changes (`SetMapMode`: "clip regions are not re-scaled"), so the shape is transformed once, where the action sets it; and a file that sets its drawing area and then intersects the region of the same rectangle gets one group, not two. `MOVECLIPREGION` stays unimplemented - it occurs nowhere in the corpus and would have to move path data that is already written out. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CmCr22NW6wPQKiQidk96bq
The clip comments that told the story rather than the point, and `get_rectangle_polygon`, which said what its own name does. The `clip-rule` comment now says why `evenodd` is right for both shapes a region arrives as: holes where the file kept the poly-polygon, and a union where it only kept bands, which never overlap. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XQpLmJpJ87qbKoG8B7kbLY
andiwand
force-pushed
the
feat/svm-clipping
branch
from
August 30, 2026 10:00
0cfb5fd to
b6a19a3
Compare
`REGION_NULL` was a `bool null` beside the bands, which put "do not clip" and "clip everything away" one flag apart while they mean the opposite - and a null region whose flag goes unread yields empty path data, so it clips everything. `std::optional` makes the unwrap the only way in. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XQpLmJpJ87qbKoG8B7kbLY
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
🤖 Generated with Claude Code
Stage 5 of #772, stacked on #786 → #785 → #784 → #779 — review those first;
this branch's base is
feat/svm-bitmaps.Clipping was the largest gap left by occurrence: of 1125 metafiles harvested
from the fixtures, 1124 intersect a clip rectangle and 50 intersect a
region. All of it was skipped, so anything a metafile drew outside its own clip
was shown in full.
Intersecting clips are nested groups
An svg
clip-pathnames one shape, andISECT…intersects, so two clipsbecome two groups, one inside the other. The state's clip is therefore a stack
of shapes rather than one:
ensure_clipkeeps the groups the next drawingaction still wants, closes the ones it does not, and opens what is missing.
That also makes a
POPrestoring the clip nothing special — the next actioncloses what it has to, and the document's last groups close before
</svg>.Reading a region
A region streams as a band list (
RegionBand::load) — a union of rectangles —and, from version 2, as the poly-polygon those bands were rasterised from. The
polygons are the better outline where they are there. Both end up in one
<path>withclip-rule="evenodd": bands are disjoint, so union and even-oddagree, and a poly-polygon wants even-odd anyway.
Two details worth naming:
SetMapMode'sown comment says "clip regions are not re-scaled" — so the shape is
transformed once, where the action sets it.
rectangle. That is one group, not two; intersecting a clip with the shape
it already has is skipped.
MOVECLIPREGIONstays unimplemented: it occurs nowhere in the corpus and wouldhave to move path data that is already written out.
Verification
4 new tests (29 in the svm suite): a clip wraps what follows, two clips nest,
a pop closes the group its push drew in, and the same clip twice is one group.
Rendered every changed page against the reference with
compare-html --driver chrome: 1388 matched, 15 differ, and every one of those differs by 0.001% to0.03% of its pixels — the antialiased edge where a clip now trims a hairline
at the drawing's border. Cropping the largest of them side by side shows two
identical charts. No text changed anywhere.
Reference output regenerated (19 private, 4 public) and the pin advanced in
this branch.