Merge pull request #1426 from storytold/q/1410-ai-compound-paint
Fix #1410: an .ai compound path takes its last path's paint, and paths grouped in it stay its paths
This commit is contained in:
commit
487cc29b57
|
|
@ -702,13 +702,17 @@ impl<'a> Reader<'a> {
|
|||
"*U" => self.close(what, |k| matches!(k, Kind::Compound))?,
|
||||
_ => self.close(what, |k| matches!(k, Kind::Clip))?,
|
||||
};
|
||||
let Frame { kind, children: mut kids, gs, clips, hidden: opened_hidden, .. } = f;
|
||||
let Frame { kind, children: kids, gs, clips, hidden: opened_hidden, .. } = f;
|
||||
// A compound path of clipping paths clips its clipping group.
|
||||
let clipping = matches!(kind, Kind::Compound) && !clips.is_empty();
|
||||
let node = match kind {
|
||||
Kind::Compound => {
|
||||
let Some(first) = kids.first() else { return Ok(()) };
|
||||
let (appearance, opacity, blend, rule) = (first.appearance.clone(), first.opacity, first.blend, path_rule(first));
|
||||
// A group in a compound path (`*u u … U *U`) only holds its paths.
|
||||
let mut kids = ungrouped(kids);
|
||||
// The compound path's paint is its last path's (a gradient's instance wraps only
|
||||
// that one); the last painted one, should the last have none.
|
||||
let Some(shown) = kids.iter().rev().find(|k| !k.appearance.items.is_empty()).or(kids.last()) else { return Ok(()) };
|
||||
let (appearance, opacity, blend, rule) = (shown.appearance.clone(), shown.opacity, shown.blend, path_rule(shown));
|
||||
for k in &mut kids {
|
||||
k.opacity = 1.0;
|
||||
k.blend = BlendMode::Normal;
|
||||
|
|
@ -1716,6 +1720,18 @@ fn close(bp: &mut BezPath) {
|
|||
}
|
||||
|
||||
/// The fill rule of a path or compound node.
|
||||
/// `kids` with the members of each plain group among them in the group's place, at any depth.
|
||||
fn ungrouped(kids: Vec<Node>) -> Vec<Node> {
|
||||
let mut out = Vec::with_capacity(kids.len());
|
||||
for k in kids {
|
||||
match k.kind {
|
||||
NodeKind::Group { children, clip: false } => out.extend(ungrouped(children.into_iter().map(Arc::unwrap_or_clone).collect())),
|
||||
_ => out.push(k),
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn path_rule(n: &Node) -> FillRule {
|
||||
match &n.kind {
|
||||
NodeKind::Path { rule, .. } | NodeKind::Compound { rule, .. } => *rule,
|
||||
|
|
|
|||
|
|
@ -244,6 +244,25 @@ fn compound_paths_and_clipping() {
|
|||
assert!(*clip && matches!(children[0].kind, NodeKind::Path { clipping: true, .. }));
|
||||
}
|
||||
|
||||
/// #1410: a compound path shows its last path's paint, and paths grouped in it stay its paths.
|
||||
#[test]
|
||||
fn compound_path_takes_its_last_paths_paint() {
|
||||
let paths = format!("0 g\n{}f\n{RED}{}f\n", rect_path(0.0, 0.0, 30.0, 30.0), rect_path(10.0, 10.0, 20.0, 20.0));
|
||||
let bodies = [
|
||||
format!("0 Ae\n*u\n{paths}*U\n"),
|
||||
// The paths in a group.
|
||||
format!("0 Ae\n*u\n0 Ae\nu\n{paths}U\n*U\n"),
|
||||
// The last path unpainted.
|
||||
format!("*u\n{paths}{}n\n*U\n", rect_path(1.0, 1.0, 2.0, 2.0)),
|
||||
];
|
||||
for body in bodies {
|
||||
let a = art(&read_ok(&layer(&body)).doc);
|
||||
let NodeKind::Compound { children, .. } = &a[0].kind else { panic!("{:?}", a[0].kind) };
|
||||
assert!(children.len() >= 2 && children.iter().all(|c| matches!(c.kind, NodeKind::Path { .. })), "{body}");
|
||||
assert_eq!(fill(&a[0]).color(), Some(Color::rgb(1.0, 0.0, 0.0)), "{body}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transparency_of_objects_and_groups() {
|
||||
let art_ = format!(
|
||||
|
|
|
|||
Loading…
Reference in New Issue