0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-20 13:42:59 -05:00

🐛 Open paths should always be rendered with center alignment

This commit is contained in:
Alejandro Alonso 2025-01-07 12:56:20 +01:00
parent de0eee13af
commit 98806defbf
3 changed files with 37 additions and 15 deletions

View file

@ -73,6 +73,7 @@ impl TryFrom<RawPathData> for Segment {
pub struct Path {
segments: Vec<Segment>,
skia_path: skia::Path,
open: bool,
}
fn starts_and_ends_at_same_point(path: &skia::Path) -> bool {
@ -91,6 +92,7 @@ impl TryFrom<Vec<RawPathData>> for Path {
type Error = String;
fn try_from(value: Vec<RawPathData>) -> Result<Self, Self::Error> {
let mut open = true;
let segments = value
.into_iter()
.map(|raw| Segment::try_from(raw))
@ -110,17 +112,20 @@ impl TryFrom<Vec<RawPathData>> 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
}
}

View file

@ -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

View file

@ -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