diff --git a/render-wasm/src/shapes/paths.rs b/render-wasm/src/shapes/paths.rs index f4528bc4aa..1e77b9ccc2 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 5f4ad4fc8c..de752dba19 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 2eec2293b6..cf56a02f98 100644 --- a/render-wasm/src/shapes/strokes.rs +++ b/render-wasm/src/shapes/strokes.rs @@ -32,7 +32,7 @@ pub enum StrokeCap { // Square, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum StrokeKind { InnerStroke, OuterStroke, @@ -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 + } + } + pub fn new_center_stroke(width: f32, style: i32) -> Self { let transparent = skia::Color::from_argb(0, 0, 0, 0); Stroke { @@ -124,7 +133,12 @@ impl Stroke { let path_effect = match self.style { StrokeStyle::Dotted => { let mut circle_path = skia::Path::new(); - circle_path.add_circle((0.0, 0.0), self.width / 2.0, None); + let width = match self.kind { + StrokeKind::InnerStroke => self.width, + StrokeKind::CenterStroke => self.width / 2.0, + StrokeKind::OuterStroke => self.width, + }; + circle_path.add_circle((0.0, 0.0), width, None); let advance = self.width + 5.0; skia::PathEffect::path_1d( &circle_path, @@ -153,9 +167,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