.ai import: a one-paint style's gradient paints the side its flag names

A gradient instance in a one-paint style marked both the fill and the
stroke as not read, so a style with a solid fill and a stroke gradient
was left out even when its `Xd` turns on only the fill. The instance's
flag (`1 Bb` for the stroke) now says which side the gradient paints, as
the object reader reads it; a gradient outside an instance still marks
both.
This commit is contained in:
dotCooCoo
2026-11-12 21:36:18 -08:00
parent a1f6eaed77
commit ecb994540c
2 changed files with 15 additions and 3 deletions
+11 -2
View File
@@ -780,6 +780,8 @@ struct OnePaint {
fill_unread: bool,
/// Its last stroke paint is a pattern (`P`) or may be a gradient (`Bg`).
stroke_unread: bool,
/// Inside a gradient instance (`flag Bb` … `BB`): whether it paints the stroke (flag 1).
instance: Option<bool>,
}
impl OnePaint {
@@ -788,8 +790,15 @@ impl OnePaint {
"Xd" => self.xd |= vals.iter().filter_map(V::num).count() >= 2,
"p" => self.fill_unread = true,
"P" => self.stroke_unread = true,
// Read as either one's, since its operands don't say which it paints.
"Bg" => (self.fill_unread, self.stroke_unread) = (true, true),
// The flag of the instance it is in says which one it paints, as an object's does
// (`Instance::begin` in `paint.rs`); outside one it is read as either one's.
"Bb" => self.instance = Some(vals.iter().filter_map(V::num).next_back() == Some(1.0)),
"BB" => self.instance = None,
"Bg" => match self.instance {
Some(true) => self.stroke_unread = true,
Some(false) => self.fill_unread = true,
None => (self.fill_unread, self.stroke_unread) = (true, true),
},
// A color replaces what came before it; one that isn't read leaves none.
"Xa" | "k" | "g" | "x" | "Xx" | "Xk" | "Xs" | "Xz" | "xa" | "xx" | "xk" | "xs" | "xz" => {
(self.fill_unread, self.paint.fill) = (false, None);
+4 -1
View File
@@ -1541,6 +1541,9 @@ fn a_style_of_one_paint_reads_as_the_fill_and_stroke_its_xd_turns_on() {
}
let solid_stroke = one("(Dots) 0 0 1 1 0 0 0 0 0 [1 0 0 1 0 0] P\n0 1 1 0 K\n1 0 Xd\n");
assert!(matches!(solid_stroke, Some(Ok(i)) if matches!(i.as_slice(), [StyleItem::Stroke { .. }])));
// A gradient instance's flag says which one it paints: a stroke gradient leaves a solid fill read.
let fill_and_stroke_gradient = one("0 0 1 0 k\n1 Bb\n2 (Ramp) 0 0 90 1 1 0 0 1 0 0 1 Bg\n0 BB\n0 1 Xd\n");
assert!(matches!(fill_and_stroke_gradient, Some(Ok(i)) if matches!(i.as_slice(), [StyleItem::Fill(_)])));
// Not read: no `Xd`, a gradient or pattern fill, a pattern stroke, a gradient stroke after a solid one, a paint
// turned on with no color.
for paint in [
@@ -1548,7 +1551,7 @@ fn a_style_of_one_paint_reads_as_the_fill_and_stroke_its_xd_turns_on() {
"0 Bb\n2 (Sky) 0 0 0 100 1 0 0 1 0 0 Bg\n0 BB\n0 1 Xd\n".to_string(),
"(Dots) 0 0 1 1 0 0 0 0 0 [1 0 0 1 0 0] p\n0 1 Xd\n".to_string(),
"(Dots) 0 0 1 1 0 0 0 0 0 [1 0 0 1 0 0] P\n1 0 Xd\n".to_string(),
"0 R\n0 1 1 0 K\nBb\n0 0 0 0 Bh\n2 (Ramp) 0 0 90 1 1 0 0 1 0 0 1 Bg\n0 BB\n2 w\n1 0 Xd\n".to_string(),
"0 R\n0 1 1 0 K\n1 Bb\n0 0 0 0 Bh\n2 (Ramp) 0 0 90 1 1 0 0 1 0 0 1 Bg\n0 BB\n2 w\n1 0 Xd\n".to_string(),
"0 0 1 0 k\n1 1 Xd\n".to_string(),
] {
assert_eq!(one(&paint), Some(Err(())), "{paint}");