Merge pull request #7114 from dotCooCoo/feat/group-effect-after-members

Effects: a group's geometry effects reshape what its members draw
This commit is contained in:
BFlat
2026-11-13 23:03:46 +07:00
committed by GitHub
10 changed files with 496 additions and 36 deletions
+14 -5
View File
@@ -535,9 +535,9 @@ fn expanded_art_keeps_the_random_transforms_the_canvas_drew() {
}
/// The reply lists each object whose appearance expanded once, by the id it has in the document,
/// starting with the selected object. In "group copies" the two copies of the square share an id
/// until Expand Appearance gives them ids of their own, and the reply names the group, then each
/// copy by its new id.
/// starting with the selected object. In "group copies" the group's art holds the square with its
/// stroke's effect applied, so the reply names the group alone; the two copies of the square share
/// ids until Expand Appearance gives every object in them an id of its own.
#[test]
fn the_reply_names_each_expanded_copy_by_its_own_id() {
for case in RANDOM_CASES {
@@ -551,8 +551,17 @@ fn the_reply_names_each_expanded_copy_by_its_own_id() {
assert!(ids.iter().all(|&i| s.doc().unwrap().doc.node(NodeId(i)).is_some()), "{case}: {ids:?}");
if case == "group copies" {
let art = node(&s, id);
let copies: Vec<u64> = art.children().unwrap()[0].children().unwrap().iter().map(|c| c.id.0).collect();
assert_eq!(ids, [vec![id.0], copies].concat(), "{case}");
assert_eq!(ids, [id.0], "{case}");
let copies = art.children().unwrap();
assert_eq!(copies.len(), 2, "{case}");
let mut seen = std::collections::HashSet::new();
let mut repeated = vec![];
art.walk(&mut |n| {
if !seen.insert(n.id) {
repeated.push(n.id);
}
});
assert!(repeated.is_empty(), "{case}: {repeated:?}");
}
}
}
+19
View File
@@ -257,6 +257,25 @@ fn shadows_under_a_groups_or_an_objects_transform_expand_appearance_as_the_canva
}
}
/// A group's Transform effect runs after its member's own Offset Path in Expand Appearance as on
/// the canvas: the 100 pt square offset to 120 pt and scaled by half expands 60 pt wide.
#[test]
fn a_groups_effects_after_its_members_own_expand_as_the_canvas_draws_them() {
let mut s = session();
run(&mut s, "shape.rectangle", json!({"x": 50, "y": 50, "width": 100, "height": 100}));
run(&mut s, "effect.apply", json!({"effect": "path.offsetPath", "params": {"offset": 10}}));
run(&mut s, "object.group", json!({}));
run(&mut s, "effect.apply", json!({"effect": "distort.transform", "params": {"scaleH": 50, "scaleV": 50}}));
let before = render(&s);
run(&mut s, "effect.expandAppearance", json!({}));
let after = render(&s);
let diff = differing(&before, &after, 64);
assert_eq!(diff, 0, "{diff} pixels differ");
let doc = &s.doc().unwrap().doc;
let w = doc.node(doc.layers[0].id).and_then(|l| l.geometric_bounds()).unwrap().width();
assert!((w - 60.0).abs() < 1e-6, "{w}");
}
#[test]
fn a_placed_gradient_moved_by_a_warp_expands_as_the_canvas_draws_it() {
// The object's own effect, and the fill's (the first appearance item).