Skip to content

feat(svm): clip the drawing to what the metafile clips it to - #787

Merged
andiwand merged 3 commits into
mainfrom
feat/svm-clipping
Aug 30, 2026
Merged

feat(svm): clip the drawing to what the metafile clips it to#787
andiwand merged 3 commits into
mainfrom
feat/svm-clipping

Conversation

@andiwand

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Stage 5 of #772, stacked on #786#785#784#779review 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-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 rather than one: ensure_clip keeps the groups the next drawing
action still wants, closes the ones it does not, and opens what is missing.
That also makes a POP restoring the clip nothing special — the next action
closes 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> with clip-rule="evenodd": bands are disjoint, so union and even-odd
agree, and a poly-polygon wants even-odd anyway.

Two details worth naming:

  • vcl does not re-scale a clip when the map mode changesSetMapMode's
    own comment says "clip regions are not re-scaled" — so the shape is
    transformed once, where the action sets it.
  • A file sets its drawing area and then intersects the region of the same
    rectangle.
    That is one group, not two; intersecting a clip with the shape
    it already has is skipped.

MOVECLIPREGION stays unimplemented: it occurs nowhere in the corpus and would
have 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% to
0.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.

andiwand and others added 2 commits August 30, 2026 11:55
`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
`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
@andiwand
andiwand merged commit 10eabc1 into main Aug 30, 2026
29 checks passed
@andiwand
andiwand deleted the feat/svm-clipping branch August 30, 2026 17:41
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.

1 participant