mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-14 14:41:52 +00:00
Merge pull request #7517 from jayzed80/fix/offset-path-clip-silhouette-7289
Appearance: a group's own fills and strokes follow a clip group's clipping path, not the art it hides (#7289)
This commit is contained in:
@@ -661,8 +661,9 @@ pub fn has_container_appearance(n: &Node) -> bool {
|
||||
/// The regions a group's or layer's own fills and strokes paint, in document space, each with its
|
||||
/// fill rule: every visible member path and compound path, type as its glyph outlines and live
|
||||
/// objects evaluated; a compound shape as its area, with the symbol instances among its members
|
||||
/// as their symbols' art from `doc`; the members of a clip group or clipping layer without its
|
||||
/// clipping path. Images, other symbol instances and guides add nothing. A Repeat counts the
|
||||
/// as their symbols' art from `doc`; a clip group or clipping layer (`n` itself or one among its
|
||||
/// members) as the region its clipping path clips to ([`crate::clip::clip_outline`]), so members
|
||||
/// it hides add nothing. Images, other symbol instances and guides add nothing. A Repeat counts the
|
||||
/// Repeats in the art of `doc`'s symbols that its instances show toward its instance budget.
|
||||
pub fn member_shapes(doc: Option<&Document>, n: &Node) -> Vec<(PathData, FillRule)> {
|
||||
fn push(doc: Option<&Document>, n: &Node, out: &mut Vec<(PathData, FillRule)>) {
|
||||
@@ -690,8 +691,14 @@ pub fn member_shapes(doc: Option<&Document>, n: &Node) -> Vec<(PathData, FillRul
|
||||
}
|
||||
}
|
||||
fn members(doc: Option<&Document>, n: &Node, out: &mut Vec<(PathData, FillRule)>) {
|
||||
let clip = usize::from(n.clips());
|
||||
for c in n.children().into_iter().flatten().skip(clip) {
|
||||
// A clip group shows its members only inside its clipping path: its outline is that
|
||||
// region, not the clipped members' own shapes, which may reach far outside it (#7289).
|
||||
if n.clips() {
|
||||
let clip = n.children().and_then(|ch| ch.first());
|
||||
out.extend(clip.and_then(|c| crate::clip::clip_outline(c)).map(|(bp, rule)| (PathData::from_bezpath(&bp), rule)));
|
||||
return;
|
||||
}
|
||||
for c in n.children().into_iter().flatten() {
|
||||
push(doc, c, out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1757,3 +1757,38 @@ fn a_sublayers_ruler_guide_in_a_hidden_or_locked_group_stays_hidden_or_locked()
|
||||
assert_eq!(guides, [(NodeId(20), !hidden, locked)], "hidden {hidden}, locked {locked}");
|
||||
}
|
||||
}
|
||||
|
||||
/// A group's own Fill + Offset Path below its contents follows the outline of a clip group among
|
||||
/// its members, its clipping path, not the clipped art it hides outside that path (#7289).
|
||||
#[test]
|
||||
fn a_groups_own_fill_follows_a_clip_groups_clipping_path_not_its_hidden_art() {
|
||||
let mut clip = square_at_100();
|
||||
clip.id = NodeId(2);
|
||||
if let NodeKind::Path { clipping, .. } = &mut clip.kind {
|
||||
*clipping = true;
|
||||
}
|
||||
// The clipped art reaches 100 pt past the clipping path on either side.
|
||||
let hidden = Node::path(NodeId(3), shapes::rectangle(Rect::new(0.0, 100.0, 300.0, 200.0)), black());
|
||||
let clipped = Node::new(NodeId(5), NodeKind::Group { children: vec![Arc::new(clip), Arc::new(hidden)], clip: true });
|
||||
let mut g = Node::group(NodeId(10), vec![Arc::new(clipped.clone())]);
|
||||
let mut fill = vectorcraft_doc::FillLayer::new(Paint::solid(Color::rgb(1.0, 0.0, 0.0)));
|
||||
fill.effects.push(offset_10());
|
||||
g.appearance.items = vec![AppearanceItem::Fill(fill)];
|
||||
g.appearance.set_contents_at(1);
|
||||
let near = |a: Rect, b: Rect| (a.x0 - b.x0).abs() < 0.5 && (a.y0 - b.y0).abs() < 0.5 && (a.x1 - b.x1).abs() < 0.5 && (a.y1 - b.y1).abs() < 0.5;
|
||||
let expected = Rect::new(90.0, 90.0, 210.0, 210.0);
|
||||
|
||||
let art = evaluate_container(None, &g).unwrap();
|
||||
let ch = art.children().unwrap();
|
||||
assert_eq!(ch.len(), 2, "the fill's art below the clip group");
|
||||
assert_eq!(ch[0].id, NodeId(10));
|
||||
let b = drawn_bounds(&ch[0]).unwrap();
|
||||
assert!(near(b, expected), "the offset fill hugs the clipping path: {b:?}");
|
||||
|
||||
// The clip group itself with that fill: the same outline.
|
||||
let mut own = clipped;
|
||||
own.appearance = g.appearance.clone();
|
||||
assert_eq!(member_shapes(None, &own).len(), 1);
|
||||
let b = member_shapes(None, &own)[0].0.bounds().unwrap();
|
||||
assert!(near(b, Rect::new(100.0, 100.0, 200.0, 200.0)), "the clipping path's region: {b:?}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user