Skip to content

Optimize clipped layers - #1158

Merged
LaurenzV merged 3 commits into
linebender:mainfrom
gorghoa:clip-path-layer-bounds
Oct 17, 2026
Merged

LaurenzV merged 3 commits into
linebender:mainfrom
gorghoa:clip-path-layer-bounds

Conversation

@gorghoa

@gorghoa gorghoa commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

Fix for #1146

A clipped group's layer was the size of its whole content, even when the clip path only lets a small part through. This shrinks the layer to the clip path bounds (+2 px for anti-aliasing).

It only applies to simple cases: a clip path made of paths only, no mask or filter, and no rotation or skew.

Adds 8 clip-path tests, with reference images rendered on main. In 2 of them, the moved layer origin changes the anti-aliasing of a few edge pixels (at most 28 pixels, at most 16/255 per channel). Those 2 references are updated in the fix commit. All existing tests still render exactly as before.

Written by an LLM (Claude opus 5.5), per the Linebender LLM policy.

gorghoa and others added 3 commits October 17, 2026 11:29
Groups whose content is much larger than their clip path, as produced
by illustration tools: clip via `use`, subpixel clip on content larger
than the canvas, clip partially outside the canvas or outside the
content, scaled and mirrored clip transforms, nested clipped groups and
`clipPathUnits=objectBoundingBox`.

Reference images rendered with the current renderer.
…-generated)

A clipped group gets a layer sized to its whole content, then the clip
mask is applied to that whole layer. When the clip path is much smaller
than the content (common in files exported from illustration tools,
which wrap shapes in <clipPath><use/></clipPath>), most of that work is
thrown away, and its cost grows with the layer area.

This shrinks the layer to the intersection with the clip path bounds
(expanded by 2px, like group layers), only for simple cases: clip paths
made of paths (possibly wrapped in plain groups, as <use> produces),
without nested clip path, mask, filter or text, and without rotation or
skew. Other cases keep the current behaviour.

On a synthetic file (100 groups whose content covers the canvas, each
clipped to a 40x40 square), rendering time drops from 0.96 s to 0.018 s
at 1000 px and from 31.7 s to 0.44 s at 4000 px.

Because the layer origin moves, floating-point rounding changes the
anti-aliasing of a few edge pixels inside the clipped content. Two of
the new clip-path tests are affected (28 and 5 pixels, by at most
16/255 per channel); their reference images are updated.

Disclosure: this change was written end to end by an LLM (Claude),
as an exploration. It is published as inspiration only, not as a
contribution, per the Linebender LLM contribution policy.
@LaurenzV
LaurenzV force-pushed the clip-path-layer-bounds branch from eb5a037 to a540913 Compare October 17, 2026 12:28
@LaurenzV

Copy link
Copy Markdown
Collaborator

Thank you, huge improvement! I applied two tweaks:

  • I removed the tests because I think they don't really cover anything new that isn't already covered by existing tests.
  • I've changed it so we instead just tweak the layer bounding box directly in usvg, instead of doing it in resvg. This way, other consumers can profit from this as well.

@LaurenzV LaurenzV changed the title Clip path layer bounds Optimize clipped layers Oct 17, 2026
@LaurenzV
LaurenzV merged commit 054ccf3 into linebender:main Oct 17, 2026
5 checks passed
@LaurenzV

Copy link
Copy Markdown
Collaborator

Ah sorry, I realized that the additional tests were requested by @RazrFalcon. But as mentioned we already have plenty of tests and there isn't much magic in this fix, so I think it should be fine.

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