Update 'Solidify Stroke' to preserve the original fill (#3971)

* Update 'Solidify Stroke' to preserve the original fill

* Efficiency improvements
This commit is contained in:
Keavon Chambers 2026-03-28 18:11:26 -07:00 committed by GitHub
parent 50a618ad12
commit 71ff4c937f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 37 additions and 10 deletions

View File

@ -1110,14 +1110,19 @@ async fn offset_path(_: impl Ctx, content: Table<Vector>, distance: f64, join: S
#[node_macro::node(category("Vector: Modifier"), path(core_types::vector))]
async fn solidify_stroke(_: impl Ctx, content: Table<Vector>) -> Table<Vector> {
// TODO: Make this node support stroke align, which it currently ignores
content
.into_iter()
.map(|mut row| {
let vector = row.element;
.flat_map(|row| {
let mut vector = row.element;
let transform = row.transform;
let alpha_blending = row.alpha_blending;
let source_node_id = row.source_node_id;
let stroke = vector.style.stroke().clone().unwrap_or_default();
let bezpaths = vector.stroke_bezpath_iter();
let mut result = Vector::default();
let mut solidified_stroke = Vector::default();
// Taking the existing stroke data and passing it to kurbo::stroke to generate new fill paths.
let join = match stroke.join {
@ -1133,6 +1138,7 @@ async fn solidify_stroke(_: impl Ctx, content: Table<Vector>) -> Table<Vector> {
let dash_offset = stroke.dash_offset;
let dash_pattern = stroke.dash_lengths;
let miter_limit = stroke.join_miter_limit;
let paint_order = stroke.paint_order;
let stroke_style = kurbo::Stroke::new(stroke.weight)
.with_caps(cap)
@ -1153,17 +1159,38 @@ async fn solidify_stroke(_: impl Ctx, content: Table<Vector>) -> Table<Vector> {
solidified.apply_affine(Affine::new(stroke.transform.inverse().to_cols_array()));
}
result.append_bezpath(solidified);
solidified_stroke.append_bezpath(solidified);
}
// We set our fill to our stroke's color, then clear our stroke.
// We set the solidified stroke's fill to the stroke's color and without a stroke.
if let Some(stroke) = vector.style.stroke() {
result.style.set_fill(Fill::solid_or_none(stroke.color));
result.style.set_stroke(Stroke::default());
solidified_stroke.style.set_fill(Fill::solid_or_none(stroke.color));
}
row.element = result;
row
let stroke_row = TableRow {
element: solidified_stroke,
transform,
alpha_blending,
source_node_id,
};
// If the original vector has a fill, preserve it as a separate row with the stroke cleared.
let has_fill = !vector.style.fill().is_none();
let fill_row = has_fill.then(move || {
vector.style.clear_stroke();
TableRow {
element: vector,
transform,
alpha_blending,
source_node_id,
}
});
// Ordering based on the paint order. The first row in the table is rendered below the second.
match paint_order {
PaintOrder::StrokeAbove => fill_row.into_iter().chain(std::iter::once(stroke_row)).collect::<Vec<_>>(),
PaintOrder::StrokeBelow => std::iter::once(stroke_row).chain(fill_row).collect::<Vec<_>>(),
}
})
.collect()
}
@ -1208,7 +1235,7 @@ async fn path_is_closed(
) -> bool {
content
.iter()
.flat_map(|row| row.element.stroke_bezpath_iter().map(|bezpath| bezpath.elements().last() == Some(&kurbo::PathEl::ClosePath)))
.flat_map(|row| row.element.build_stroke_path_iter().map(|(_, closed)| closed))
.nth(index.max(0.) as usize)
.unwrap_or(false)
}