.ai import: a compound path's plain subpath keeps its fill

In a compound clipping path whose subpaths paint differently, the fill
of a subpath that does not clip was read apart with the clipping
subpaths' fills. Only the clipping subpaths' fills are read apart now,
and a subpath that does not clip keeps its fill, as before.
This commit is contained in:
dotCooCoo
2026-11-08 11:22:37 +07:00
committed by bflatastic
parent b33cdfd14f
commit 589fd863c4
2 changed files with 21 additions and 2 deletions
+6 -2
View File
@@ -150,10 +150,14 @@ impl<'a> Reader<'a> {
// A group in a compound path (`*u u … U *U`) only holds its paths.
let mut kids = ungrouped(kids);
// A compound clipping path keeps its subpaths' fill when they all paint alike. When they paint
// differently, the fills of the filled ones are a compound path of their own, under what it clips.
// differently, the fills of the filled clipping ones are a compound path of their own, under what it clips.
let look = |n: &Node| (n.appearance.clone(), n.opacity, n.blend);
if clipping && kids.windows(2).any(|w| look(&w[0]) != look(&w[1])) {
let fills: Vec<Node> = kids.iter_mut().filter_map(|k| self.fill_apart(k)).collect();
let fills: Vec<Node> = kids
.iter_mut()
.filter(|k| matches!(k.kind, NodeKind::Path { clipping: true, .. }))
.filter_map(|k| self.fill_apart(k))
.collect();
painted = self.compound(fills, &gs);
}
let Some(n) = self.compound(kids, &gs) else {
+15
View File
@@ -1293,6 +1293,21 @@ fn compound_paths_and_clipping() {
assert!(filled.iter().all(|p| matches!(p.kind, NodeKind::Path { clipping: false, .. })), "{filled:?}");
assert_eq!((fill(&children[1]).color(), children[1].appearance.stroke().is_none()), (blue, true));
assert_eq!(fill(&children[2]).color(), Some(Color::rgb(1.0, 0.0, 0.0)));
// A subpath that doesn't clip keeps its fill; only the clipping subpath's fill is read apart.
let green = Some(Color::rgb(0.0, 1.0, 0.0));
let plain = format!(
"0 Ae\nq\n{RED}{}f\n*u\n0 0 1 0 0 0 1 Xa\n{}f\n0 1 0 0 0 1 0 Xa\n{}h\nW\nf\n*U\nQ\n",
rect_path(0.0, 0.0, 30.0, 30.0),
rect_path(5.0, 5.0, 25.0, 25.0),
rect_path(10.0, 10.0, 20.0, 20.0)
);
let doc = read_ok(&layer(&plain)).doc;
let NodeKind::Group { children, clip: true } = &art(&doc)[0].kind else { panic!("a clipping group") };
let NodeKind::Compound { children: subpaths, .. } = &children[0].kind else { panic!("{:?}", children[0].kind) };
let kinds: Vec<_> = subpaths.iter().map(|c| (matches!(c.kind, NodeKind::Path { clipping: true, .. }), fill(c).color())).collect();
assert_eq!(kinds, [(false, blue), (true, None)]);
let NodeKind::Compound { children: apart, .. } = &children[1].kind else { panic!("{:?}", children[1].kind) };
assert_eq!((apart.len(), fill(&children[1]).color()), (1, green), "only the clipping subpath's fill: {apart:?}");
// A tag after the compound clipping path is its own.
let doc = read_ok(&layer(&mixed.replace("*U\n", "*U\n/edge (clip) XT\n"))).doc;
let NodeKind::Group { children, .. } = &art(&doc)[0].kind else { panic!("a clipping group") };