Render: a dashed brush stroke keeps the layered path for object opacity

Follow-up to #3697 (CodeRabbit): a brush stroke is drawn as separate
pieces (draw_brush), so folding object opacity into its colour isn't exact.
A non-dashed brush stroke already counted as one paint before #3697; to
keep that change's scope, a dashed stroke counts as one paint only when it
has no brush. dashed_stroke_opacity_folds_into_its_colour checks that a
dashed brush stroke isn't folded; it fails without the change.
This commit is contained in:
Taha-Mahmoodi
2026-10-23 04:14:37 +07:00
committed by bflatastic
parent 0395729b31
commit 087e38aafc
2 changed files with 6 additions and 2 deletions
+3 -2
View File
@@ -2231,14 +2231,15 @@ fn single_plain_fill(n: &Node) -> bool {
/// Number of visible painted fill/stroke items (opacity folding is exact only for one). A dashed
/// stroke is one paint: its dashes are outlined into one path and filled once, so overlapping
/// dashes don't darken where they overlap.
/// dashes don't darken where they overlap. A dashed brush stroke isn't: its pieces are drawn one
/// by one.
fn painted_items(n: &Node) -> usize {
n.appearance
.items
.iter()
.filter(|i| match i {
AppearanceItem::Fill(f) => f.visible && !f.paint.is_none() && matches!(f.paint, vectorcraft_color::Paint::Solid { .. }),
AppearanceItem::Stroke(s) => s.visible && !s.paint.is_none() && s.width > 0.0 && matches!(s.paint, vectorcraft_color::Paint::Solid { .. }),
AppearanceItem::Stroke(s) => s.visible && !s.paint.is_none() && s.width > 0.0 && matches!(s.paint, vectorcraft_color::Paint::Solid { .. }) && (s.dash.is_none() || s.brush.is_none()),
})
.count()
.max(if n.appearance.items.iter().any(|i| matches!(i, AppearanceItem::Fill(f) if f.visible && !matches!(f.paint, vectorcraft_color::Paint::Solid { .. } | vectorcraft_color::Paint::None)) || matches!(i, AppearanceItem::Stroke(s) if s.visible && !matches!(s.paint, vectorcraft_color::Paint::Solid { .. } | vectorcraft_color::Paint::None))) { 2 } else { 0 })
+3
View File
@@ -980,6 +980,9 @@ fn dashed_stroke_opacity_folds_into_its_colour() {
};
let mut d = Document::new(100.0, 100.0);
assert_eq!(painted_items(&dashed(&mut d, 0.6, 1.0)), 1, "a dashed stroke takes the folded fast path");
let mut brushed = dashed(&mut d, 0.6, 1.0);
brushed.appearance.stroke_mut().unwrap().brush = Some("Calligraphic".into());
assert_ne!(painted_items(&brushed), 1, "a dashed brush stroke draws its pieces one by one: no folding");
let folded = render(&doc(0.6, 1.0));
let layered = render(&doc(1.0, 0.6));
assert_ne!(folded.pixel(20, 40), [255, 255, 255, 255], "the stroke is drawn");