Repository navigation
Conversation
With enableRenderingOptimization, renderDisplayObjectOptimized restored the context right after drawing the object that owns the clipPath, so the clip of a Group never reached its children. Keep the clip in renderState.restoreStack until the walk leaves the subtree, as renderDisplayObject does, and restore the cached context state with it so cached styles do not go stale. Closes antvis#1915
🦋 Changeset detectedLatest commit: fe81add The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
@shkomg Will there be a noticeable drop in rendering performance? |
|
Thanks for asking. The change only adds work for objects that have a clipPath: objects without one take exactly the same path as before (no extra save/restore, and the subtree check only runs while a clip is active). For each clip it keeps one I measured it on the canvas renderer with
So within about 2%, which is near the timer's resolution. In the clipped scenes the base build also skips the clip and draws more pixels, so those two rows are not a perfectly like-for-like comparison. Happy to share the benchmark page or run another scene you care about. |
…dering compareDocumentPosition walked both nodes to the root and scanned siblings when leaving a clipped subtree, which grows with many sibling clipped groups. parent.contains(object) walks up to the clip owner only and gives the same answer here, since an object is never its own pushed clip parent.
🤔 This is a ...
🔗 Related issue link
Closes #1915
💡 Background and solution
With
enableRenderingOptimization: true, the canvas renderer ignored aclipPathset on aGroupfor the group's children.renderDisplayObjectOptimizedcalledcontext.restore()right after drawing the object that owns the clip, so the clip was already gone when the children were drawn.The optimized path now keeps the clip on
renderState.restoreStackuntil the walk leaves that subtree, likerenderDisplayObjectdoes. Sincerestore()also reverts the styles and transform set inside the clip, the cached context state is saved with the clip and put back on restore, andprevObjectis reset so the next object applies its transform and styles again. Objects without a clip get no extrasave()/restore().This also makes the existing
2d-clipPathdemo render the same with the option on and off. Added thebugfix-issue_1915demo, a unit test (__tests__/unit/plugins/canvas-rendering-optimization-clip.spec.ts) and a patch changeset.Tested: the new unit test fails without the change and passes with it (it also covers 1,000 sibling clipped groups followed by an unclipped sibling), the full jest unit suite passes (283 tests), and eslint and prettier are clean; the visual integration tests were not run locally.
The video shows the
bugfix-issue_1915demo with the option on: the red rect stays inside the clip outline, also after toggling the option and moving the rect.antv-g.mp4
Performance
Cost with
enableRenderingOptimization: an object with no clip on the stack adds onerestoreStack.lengthcheck. A clipped object adds onesave(), kept until the walk leaves its subtree and then undone with onerestore(), plus a copy of the small style cache; the check for the next objects isparent.contains(object), which walks up from the object to the clip owner only and allocates nothing.Measured on an Apple M4 Max (macOS 26.6.2, chrome-headless-shell 156, 1000x800, DPR 1): per frame one fill change,
canvas.render()and a 1x1getImageDatato force rasterization; 60 warm-up and 300 measured frames, median of 3 runs, ms per frame,master-> this PR, p95 in brackets.The clipped scenes are not like for like:
masterdrops the group clip for children and draws them unclipped, so these numbers show the fix adds no frame time, not that it makes rendering faster.📝 Changelog
clipPathon aGroupnot clipping its children whenenableRenderingOptimizationis enabled.enableRenderingOptimization时Group上的clipPath对子元素不生效的问题。☑️ Self Check before Merge
Fix written with Claude Code; video is an automated browser run of this branch recorded by User Stories Bot.