.ai import: a hidden clipping path's fill leaves with it

The fill read apart from a clipping path that was read on %_ lines, and
the copies of its subpaths, are recorded as read on those lines too, so
the copy of a look's art that is removed takes them along. The file
format notes list a compound clipping path whose subpaths paint
differently among the exceptions to a clipping path keeping its fill.
This commit is contained in:
dotCooCoo
2026-11-08 11:22:37 +07:00
committed by bflatastic
parent 589fd863c4
commit bbf4834f12
3 changed files with 32 additions and 0 deletions
@@ -336,6 +336,11 @@ impl<'a> Reader<'a> {
*clipping = false;
}
let mut fill = Node::new(self.doc.alloc_id(), kind);
// The copies of a path read on `%_` lines are on those lines too, as `add` records them.
let hidden = self.hidden_ids.contains(&n.id);
if hidden {
self.hidden_ids.insert(fill.id);
}
// A compound clipping path's subpaths: copies with ids of their own, linked to the same swatches, that don't clip.
for c in fill.children_mut().into_iter().flatten() {
let mut copy = self.doc.reid(c);
@@ -343,6 +348,9 @@ impl<'a> Reader<'a> {
if let NodeKind::Path { clipping, .. } = &mut copy.kind {
*clipping = false;
}
if hidden {
self.hidden_ids.insert(copy.id);
}
*c = Arc::new(copy);
}
(fill.opacity, fill.blend, fill.isolate, fill.knockout, fill.knockout_shape, fill.visible, fill.locked) =
+22
View File
@@ -375,6 +375,28 @@ fn a_drawn_look_keeps_its_objects_tags() {
assert_eq!(tags(&a[0]), ("https://example.com/n".to_string(), vec![tag("own", "L"), tag("sku", "N-1")]));
}
/// A clipping subpath on `%_` lines in a drawn look leaves with the fill read apart from it.
#[test]
fn a_hidden_clipping_paths_fill_leaves_the_look_with_it() {
let (a, b, c) = (rect_path(0.0, 0.0, 30.0, 30.0), rect_path(5.0, 5.0, 25.0, 25.0), rect_path(0.0, 0.0, 10.0, 10.0));
let two = rect_path(8.0, 8.0, 20.0, 20.0);
let second: String = format!("0 0 1 0 0 0 1 Xa\n{two}h\nW\nf\n").lines().map(|l| format!("%_{l}\n")).collect();
let hidden_clip = format!("*u\n{RED}{a}h\nW\nf\n{second}*U\n");
let body = format!("0 Ae\nu\nu\n{hidden_clip}{b}f\nU\nU\n0 0 Xd\n6 () XW\n%_{}n\n1 (Gone style) XW\n", c.replace('\n', "\n%_"));
let doc = read_ok(&layer(&body)).doc;
let mut leaves = vec![];
doc.layers.iter().for_each(|l| {
l.walk(&mut |n| {
if let NodeKind::Path { clipping, .. } = &n.kind {
leaves.push((*clipping, fill(n).color()));
}
})
});
// The first subpath, its fill and the look's plain path stay; the second subpath and its fill leave.
let (red, blue) = (Some(Color::rgb(1.0, 0.0, 0.0)), Some(Color::rgb(0.0, 0.0, 1.0)));
assert_eq!(leaves, [(true, None), (false, red), (false, blue)]);
}
/// Tags in a brush's art don't keep it from being read, and stay out of the art: it isn't an object
/// of the document.
#[test]
File diff suppressed because one or more lines are too long