From 98806defbfb736ec7147c70b3c7d5463a4d62e26 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 7 Jan 2025 12:56:20 +0100 Subject: [PATCH] :bug: Open paths should always be rendered with center alignment --- render-wasm/src/shapes/paths.rs | 9 +++++++++ render-wasm/src/shapes/renderable.rs | 28 ++++++++++++++++------------ render-wasm/src/shapes/strokes.rs | 15 ++++++++++++--- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/render-wasm/src/shapes/paths.rs b/render-wasm/src/shapes/paths.rs index f4528bc4a..1e77b9ccc 100644 --- a/render-wasm/src/shapes/paths.rs +++ b/render-wasm/src/shapes/paths.rs @@ -73,6 +73,7 @@ impl TryFrom for Segment { pub struct Path { segments: Vec, skia_path: skia::Path, + open: bool, } fn starts_and_ends_at_same_point(path: &skia::Path) -> bool { @@ -91,6 +92,7 @@ impl TryFrom> for Path { type Error = String; fn try_from(value: Vec) -> Result { + let mut open = true; let segments = value .into_iter() .map(|raw| Segment::try_from(raw)) @@ -110,17 +112,20 @@ impl TryFrom> for Path { } Segment::Close => { skia_path.close(); + open = false; } } } if !skia_path.is_last_contour_closed() && starts_and_ends_at_same_point(&skia_path) { skia_path.close(); + open = false; } Ok(Path { segments, skia_path, + open, }) } } @@ -129,4 +134,8 @@ impl Path { pub fn to_skia_path(&self) -> skia::Path { self.skia_path.snapshot() } + + pub fn is_open(&self) -> bool { + self.open + } } diff --git a/render-wasm/src/shapes/renderable.rs b/render-wasm/src/shapes/renderable.rs index 5f4ad4fc8..de752dba1 100644 --- a/render-wasm/src/shapes/renderable.rs +++ b/render-wasm/src/shapes/renderable.rs @@ -131,7 +131,7 @@ fn render_stroke( Kind::Rect(rect) => draw_stroke_on_rect(surface.canvas(), stroke, rect, &selrect), Kind::Circle(rect) => draw_stroke_on_circle(surface.canvas(), stroke, rect, &selrect), Kind::Path(path) => { - draw_stroke_on_path(surface.canvas(), stroke, path, &selrect, path_transform) + draw_stroke_on_path(surface.canvas(), stroke, path, &selrect, path_transform); } } } @@ -165,9 +165,10 @@ fn draw_stroke_on_path( let mut skia_path = path.to_skia_path(); skia_path.transform(path_transform.unwrap()); - let paint_stroke = stroke.to_stroked_paint(selrect); + let kind = stroke.render_kind(path.is_open()); + let paint_stroke = stroke.to_stroked_paint(kind.clone(), selrect); // Draw the different kind of strokes for a path requires different strategies: - match stroke.kind { + match kind { // For inner stroke we draw a center stroke (with double width) and clip to the original path (that way the extra outer stroke is removed) StrokeKind::InnerStroke => { canvas.clip_path(&skia_path, skia::ClipOp::Intersect, true); @@ -288,10 +289,11 @@ pub fn draw_image_stroke_in_container( Kind::Path(p) => { let mut path = p.to_skia_path(); path.transform(path_transform.unwrap()); - if stroke.kind == StrokeKind::InnerStroke { + let stroke_kind = stroke.render_kind(p.is_open()); + if stroke_kind == StrokeKind::InnerStroke { canvas.clip_path(&path, skia::ClipOp::Intersect, true); } - let paint = stroke.to_stroked_paint(&outer_rect); + let paint = stroke.to_stroked_paint(stroke_kind, &outer_rect); canvas.draw_path(&path, &paint); } } @@ -317,13 +319,15 @@ pub fn draw_image_stroke_in_container( canvas.draw_image_rect(image, None, dest_rect, &image_paint); // Clear outer stroke for paths if necessary. When adding an outer stroke we need to empty the stroke added too in the inner area. - if let (Kind::Path(p), StrokeKind::OuterStroke) = (kind, &stroke.kind) { - let mut path = p.to_skia_path(); - path.transform(path_transform.unwrap()); - let mut clear_paint = skia::Paint::default(); - clear_paint.set_blend_mode(skia::BlendMode::Clear); - clear_paint.set_anti_alias(true); - canvas.draw_path(&path, &clear_paint); + if let Kind::Path(p) = kind { + if stroke.render_kind(p.is_open()) == StrokeKind::OuterStroke { + let mut path = p.to_skia_path(); + path.transform(path_transform.unwrap()); + let mut clear_paint = skia::Paint::default(); + clear_paint.set_blend_mode(skia::BlendMode::Clear); + clear_paint.set_anti_alias(true); + canvas.draw_path(&path, &clear_paint); + } } // Restore canvas state diff --git a/render-wasm/src/shapes/strokes.rs b/render-wasm/src/shapes/strokes.rs index 2eec2293b..95f99a9f0 100644 --- a/render-wasm/src/shapes/strokes.rs +++ b/render-wasm/src/shapes/strokes.rs @@ -46,10 +46,19 @@ pub struct Stroke { pub style: StrokeStyle, pub cap_end: StrokeCap, pub cap_start: StrokeCap, - pub kind: StrokeKind, + kind: StrokeKind, } impl Stroke { + // Strokes for open shapes should be rendered as if they were centered. + pub fn render_kind(&self, is_open: bool) -> StrokeKind { + if is_open { + StrokeKind::CenterStroke + } else { + self.kind.clone() + } + } + pub fn new_center_stroke(width: f32, style: i32) -> Self { let transparent = skia::Color::from_argb(0, 0, 0, 0); Stroke { @@ -153,9 +162,9 @@ impl Stroke { paint } - pub fn to_stroked_paint(&self, rect: &math::Rect) -> skia::Paint { + pub fn to_stroked_paint(&self, kind: StrokeKind, rect: &math::Rect) -> skia::Paint { let mut paint = self.to_paint(rect); - match self.kind { + match kind { StrokeKind::InnerStroke => { paint.set_stroke_width(2. * self.width); paint