Skip to content

Selection: clicks in a clip group follow the region its clipping path's effects give it - #7582

Merged
bflatastic merged 9 commits into
storytold:mainfrom
dotCooCoo:fix/clip-effects-hit-test
Nov 14, 2026
Merged

bflatastic merged 9 commits into
storytold:mainfrom
dotCooCoo:fix/clip-effects-hit-test

Conversation

@dotCooCoo

@dotCooCoo dotCooCoo commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

What and why

Follows #7476 (merged), which makes a clipping path's geometry effects shape the clip on the canvas.

With #7476, a clip group whose clipping path has a Transform effect draws its art where the effect moved the clip, but clicks, hovers and marquees still tested the plain clipping path. A click on the visible art selected nothing, and a click where the clipping path used to be selected art that is not drawn there. This changes which objects a click or marquee selects in such clip groups; clip groups without geometry effects on their clipping path behave as before.

  • The engine registers the effect-shaped region with the doc crate through the new hit::set_clip_region, as it does for image paint and live art. It gives a region only when the clipping path holds a visible geometry effect; otherwise the plain shapes count, and type used as a clipping path still counts by its frame.

  • Clicks, objects_at (Select Behind), the hidden art of a selected object, the Unlock submenu's list and marquees inside a clip group or a clipping layer use that region. Each container around a selected object tests its clipping path the way a click reaching it does.

  • Outline view and layers with Preview off draw no effects, so they keep the plain shapes. The Selection, Direct Selection and Enclosing Lasso marquees pass the view's outline state through the new hit::marquee_in_view; hit::enclosure_candidates takes an outline argument for the same reason. hit::marquee uses the effect-shaped region, and hit::marquee_in keeps the plain shapes, as the Color Theme Picker clips by them.

  • A marquee touches the clipping path itself by its own anchors and outline, as a click on its outline finds it, and also on the edge of the region, so a marquee around a clipping path that an effect moved into large art still selects it.

  • The region is kept per thread until the clipping path or the live inputs change. A clip group's reach takes in the region's box, so culling does not skip art the region moved past the plain clipping path. Up to 4,096 boxes are kept; when they are full, a new box replaces only as many others as it needs room for.

  • A geometry effect on a hidden member of a group used as a clipping path leaves clicks alone: the group clips by its visible members, so type in it still counts by its frame (effects::reshaped_clip_outline, which clip_outline also uses).

  • Direct Selection on a dynamic symbol's instance picks and outlines the art in the region its clipping paths' effects give it. Below a layer whose Preview is off, in the art or around the instance, it uses the plain clipping paths, and when the effects leave no region the outline is empty (hit::symbol_part_outline_in_view).

The progress line in docs/target-app-parity.md is next to #7476's. #7476's line in the same list now also says that when a clipping path has a fill or stroke of its own, the geometry effects of those fills and strokes apply after the group's geometry effects.

Not yet: an object's own geometry effects still do not move where clicks find it (paths, compound paths, groups and layers).

How it was tested

New tests, each shown failing with the matching part of the change disabled:

  • doc hit::tests: every_clip_test_follows_the_moved_region (hidden art of a selection, a clip group inside a group, locked objects, and a clipping layer above a sublayer with Preview off), hovers_past_more_clip_groups_than_the_boxes_kept_evaluate_few_again, clicks_in_a_clip_group_evaluate_its_clipping_paths_region_once_until_it_changes, a_marquee_touches_a_moved_clipping_path_on_its_region (including a Direct Selection marquee over the clipping path's own anchors), a_clipping_layer_with_preview_off_counts_its_plain_clipping_path and hovers_past_many_clip_groups_evaluate_each_clipping_path_once.
  • tools: select::tests::outline_view_marquees_measure_a_clip_group_by_its_plain_clipping_path, direct::tests::outline_view_marquees_measure_clipped_art_by_the_plain_clipping_path and addons::enclosing_lasso::tests::outline_view_loops_measure_clipped_art_by_the_plain_clipping_path.
  • engine tests::clip::clicks_follow_the_region_a_clipping_paths_effects_give_it (a Transform effect, clicks, objects_at and marquees, in a clip group and a clipping sublayer), and a new case in text_on_top_clips_by_its_glyphs: with a drop shadow, a click in the letter's counter still hits the art.

Commands, on #7476's earlier head a9fbb7aa50 plus this commit:

  • cargo fmt --all -- --check
  • cargo clippy -p vectorcraft-doc -p vectorcraft-tools -p vectorcraft-engine --all-targets -- -D warnings
  • cargo test -p vectorcraft-doc -p vectorcraft-tools -p vectorcraft-engine: 26 test binaries, 8,827 passed, 0 failed, 4 ignored

After rebasing onto #7476's current head fb8cf27b9a, which changes effects::clip_outline:

  • cargo test -p vectorcraft-doc -p vectorcraft-tools -p vectorcraft-engine --lib: 8,161 passed, 0 failed, 3 ignored
  • cargo clippy -p vectorcraft-engine --all-targets -- -D warnings

The later commits add hit::tests::a_symbol_part_follows_the_region_its_clipping_layers_effects_give_it and a hidden-member case, each shown failing first. On d8a25c4e9b (with main at 460d211995 merged in):

  • cargo fmt --all -- --check and cargo check --workspace --tests
  • cargo clippy -p vectorcraft-doc -p vectorcraft-tools -p vectorcraft-effects -p vectorcraft-engine -p vectorcraft-render --all-targets -- -D warnings
  • cargo test -p vectorcraft-doc --lib hit: 63 passed; cargo test -p vectorcraft-tools --lib: 1,028 passed, 1 ignored; cargo test -p vectorcraft-engine --lib clip: 192 passed; cargo test -p vectorcraft-effects --lib clip: 27 passed

Checklist

  • cargo xtask ci passes (fmt, clippy, tests, assets, brands, layers, wasm).
  • No panics in shipped code: no unwrap(), expect(), panic!, unreachable!, todo! or
    unimplemented! outside tests, and no unchecked indexing on data from files, parameters or
    messages. Errors are returned as Result and shown to the user
    (why and how).
  • Clean-room: nothing copied from Adobe products or GPL/AGPL code (AGENTS.md).
  • Every new asset has a row in ASSETS.md.

…'s effects give it

The canvas clips a clip group by its clipping path with the path's live
geometry effects applied, but clicks, hovers and marquees still tested
the plain clipping path. A click where a Transform effect had moved the
clip selected nothing, and a click on the clipping path's own place
selected art that was not drawn there.

- The engine registers the effect-shaped region with the doc crate
  (`hit::set_clip_region`), as it does for image paint and live art. It
  gives a region only when the clipping path holds a visible geometry
  effect; otherwise clicks keep the plain shapes, and type keeps
  counting by its frame.
- Clicks, `objects_at`, the hidden art of a selected object, the Unlock
  submenu's list and marquees inside a clip group or a clipping layer
  use that region. Outline view and layers with Preview off draw no
  effects and keep the plain shapes; the Selection, Direct Selection
  and Enclosing Lasso marquees pass the view's outline state
  (`hit::marquee_in_view`). Each container around a selected object
  tests its clipping path in the outline state a click has there.
- A marquee touches the clipping path itself by its own geometry, as a
  click on its outline finds it, and also on the edge of the region, so
  a marquee around a clipping path that an effect moved into large art
  still selects it. `hit::marquee_in` keeps the plain shapes for the
  Color Theme Picker, which clips by them.
- The region is kept per thread until the clipping path or the live
  inputs change. A clip group's reach takes in the region's box, so
  culling does not skip art the region moved past the plain clipping
  path. Up to 4096 boxes are kept; when they are full, a new box
  replaces only as many others as it needs room for.

Docs: docs/target-app-parity.md.
@coderabbitai

coderabbitai Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 6 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 107078a and cf8b88b.

Files selected for processing: 15

  • crates/doc/src/hit.rs
  • crates/doc/src/hit/tests.rs
  • crates/doc/src/node/ops.rs
  • crates/effects/src/clip.rs
  • crates/effects/src/lib.rs
  • crates/engine/src/session/documents.rs
  • crates/engine/src/tests/clip.rs
  • crates/tools/src/addons/enclosing_lasso.rs
  • crates/tools/src/addons/enclosing_lasso/tests.rs
  • crates/tools/src/direct.rs
  • crates/tools/src/direct/tests.rs
  • crates/tools/src/lib.rs
  • crates/tools/src/select.rs
  • crates/tools/src/select/tests.rs
  • docs/target-app-parity.md
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

… after the group's

The geometry effects of a clipping path's own fills and strokes stay live when the clipping path has a fill or stroke, so they reshape it after the geometry effects of the clip group and of the groups around it.
…s alone

A clipping path that is a group clips by its visible members only. A
geometry effect on a hidden member made clicks inside the clip group
count the group's type by its glyph outlines, where they count it by its
frame when nothing has an effect.

Clicks now ask `effects::reshaped_clip_outline`, which gives a region
only when an object the clipping path clips by has a geometry effect.
`clip_outline` uses the same function.
…ive it

Direct Selection on a dynamic symbol's instance picked an object in the
region its clipping path's effects give it, but cut the object's outline
to the plain clipping path, so the outline came out empty or cut short.
In a layer of the art whose Preview is off, it tested the effect-shaped
region and the fills, where the canvas draws the plain clipping path and
outlines.

- `hit::symbol_part_outline` cuts to the bounds of the effect-shaped
  region. The new `hit::symbol_part_outline_in_view` takes the view's
  outline state, and the Direct Selection overlay passes it.
- `hit::symbol_part_at` tests art in a layer whose Preview is off in
  outline.
Direct Selection on a dynamic symbol's instance below a layer whose
Preview is off tested and outlined the art in Preview, where the canvas
draws it in outline with the plain clipping paths. When a clipping
path's effects left no region, a selected object in its clip group kept
an outline cut to the plain clipping path.

- `hit::symbol_part_at` and `hit::symbol_part_outline_in_view` count the
  layers around the instance, the isolated container and the layers
  around it apart, as clicks outside symbols do.
  `symbol_part_outline_in_view` takes the click options in place of the
  outline flag.
- The outline of an object is empty when the effects of a clipping path
  around it leave no region.
@bflatastic
bflatastic merged commit a92993d into storytold:main Nov 14, 2026
7 checks passed
@bflatastic

Copy link
Copy Markdown
Member

Merged, thanks @dotCooCoo! It passed its CI checks.

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