From 46fc5a7992001ca8de6966d182ab9dba33d6742e Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 10 May 2023 17:48:21 -0400 Subject: fix: quad rendering including border only inside of the bounds --- tiny_skia/src/backend.rs | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) (limited to 'tiny_skia') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index d481bacd..58721a80 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -157,6 +157,7 @@ impl Backend { border_width, border_color, } => { + // XXX border seems to be contained by the bounds of the primitive in wgpu and for damage regions, so we do the same here let physical_bounds = (*bounds + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { @@ -172,7 +173,26 @@ impl Backend { ) .post_scale(scale_factor, scale_factor); - let path = rounded_rectangle(*bounds, *border_radius); + // Make sure the border radius is not larger than the bounds + let border_width = border_width + .min(bounds.width / 2.0) + .min(bounds.height / 2.0); + + // Offset the fill by the border width + let path_bounds = Rectangle { + x: bounds.x + border_width, + y: bounds.y + border_width, + width: bounds.width - 2.0 * border_width, + height: bounds.height - 2.0 * border_width, + }; + // fill border radius is the border radius minus the border width + let mut fill_border_radius = *border_radius; + for radius in &mut fill_border_radius { + *radius = (*radius - border_width / 2.0) + .min(path_bounds.width / 2.0) + .min(path_bounds.height / 2.0); + } + let path = rounded_rectangle(path_bounds, fill_border_radius); pixels.fill_path( &path, @@ -192,9 +212,27 @@ impl Backend { clip_mask, ); - if *border_width > 0.0 { + // border path is offset by half the border width + let path_bounds = Rectangle { + x: bounds.x + border_width / 2.0, + y: bounds.y + border_width / 2.0, + width: bounds.width - border_width, + height: bounds.height - border_width, + }; + + let mut border_radius = *border_radius; + for radius in &mut border_radius { + *radius = radius + .min(path_bounds.width / 2.0) + .min(path_bounds.height / 2.0); + } + + let border_radius_path = + rounded_rectangle(path_bounds, border_radius); + + if border_width > 0.0 { pixels.stroke_path( - &path, + &border_radius_path, &tiny_skia::Paint { shader: tiny_skia::Shader::SolidColor(into_color( *border_color, @@ -203,7 +241,7 @@ impl Backend { ..tiny_skia::Paint::default() }, &tiny_skia::Stroke { - width: *border_width, + width: border_width, ..tiny_skia::Stroke::default() }, transform, -- cgit From 5ee26cc8ec1a49c78d1f3f99ebf6696f827ea5d1 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 11 May 2023 12:25:43 -0400 Subject: fix: don't offset fill of quad --- tiny_skia/src/backend.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'tiny_skia') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 58721a80..583b8dac 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -178,21 +178,13 @@ impl Backend { .min(bounds.width / 2.0) .min(bounds.height / 2.0); - // Offset the fill by the border width - let path_bounds = Rectangle { - x: bounds.x + border_width, - y: bounds.y + border_width, - width: bounds.width - 2.0 * border_width, - height: bounds.height - 2.0 * border_width, - }; - // fill border radius is the border radius minus the border width let mut fill_border_radius = *border_radius; for radius in &mut fill_border_radius { - *radius = (*radius - border_width / 2.0) - .min(path_bounds.width / 2.0) - .min(path_bounds.height / 2.0); + *radius = (*radius) + .min(bounds.width / 2.0) + .min(bounds.height / 2.0); } - let path = rounded_rectangle(path_bounds, fill_border_radius); + let path = rounded_rectangle(*bounds, fill_border_radius); pixels.fill_path( &path, -- cgit From 102c78abd8085d06b72da8edfa83a15ff9df89f2 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 11 May 2023 19:21:36 -0400 Subject: fix: tiny-skia quad handle case where border_radius < border_width / 2.0 --- tiny_skia/src/backend.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 7 deletions(-) (limited to 'tiny_skia') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 583b8dac..d0d24b23 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,3 +1,5 @@ +use tiny_skia::{Mask, Pixmap, PixmapPaint}; + use crate::core::text; use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector}; use crate::graphics::backend; @@ -212,17 +214,29 @@ impl Backend { height: bounds.height - border_width, }; + // Make sure the border radius is correct let mut border_radius = *border_radius; - for radius in &mut border_radius { - *radius = radius - .min(path_bounds.width / 2.0) - .min(path_bounds.height / 2.0); + let mut border_radius_gt_half_border_width = + [true, true, true, true]; + for (i, radius) in &mut border_radius.iter_mut().enumerate() { + *radius = if *radius == 0.0 { + // Path should handle this fine + 0.0 + } else if *radius > border_width / 2.0 { + *radius - border_width / 2.0 + } else { + border_radius_gt_half_border_width[i] = false; + 0.0 + } + .min(path_bounds.width / 2.0) + .min(path_bounds.height / 2.0); } - let border_radius_path = - rounded_rectangle(path_bounds, border_radius); + // Stroking a path works well in this case. + if border_radius_gt_half_border_width.iter().all(|b| *b) { + let border_radius_path = + rounded_rectangle(path_bounds, border_radius); - if border_width > 0.0 { pixels.stroke_path( &border_radius_path, &tiny_skia::Paint { @@ -239,6 +253,68 @@ impl Backend { transform, clip_mask, ); + } else { + // Draw corners that have to small border radii as having no border radius, + // but mask them with the rounded rectangle with the correct border radius. + + let mut temp_pixmap = + Pixmap::new(bounds.width as u32, bounds.height as u32) + .unwrap(); + + let mut quad_mask = + Mask::new(bounds.width as u32, bounds.height as u32) + .unwrap(); + + let zero_bounds = Rectangle { + x: 0.0, + y: 0.0, + width: bounds.width, + height: bounds.height, + }; + let path = + rounded_rectangle(zero_bounds, fill_border_radius); + + quad_mask.fill_path( + &path, + tiny_skia::FillRule::EvenOdd, + true, + transform, + ); + let path_bounds = Rectangle { + x: border_width / 2.0, + y: border_width / 2.0, + width: bounds.width - border_width, + height: bounds.height - border_width, + }; + + let border_radius_path = + rounded_rectangle(path_bounds, border_radius); + + temp_pixmap.stroke_path( + &border_radius_path, + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor(into_color( + *border_color, + )), + anti_alias: true, + ..tiny_skia::Paint::default() + }, + &tiny_skia::Stroke { + width: border_width, + ..tiny_skia::Stroke::default() + }, + transform, + Some(&quad_mask), + ); + + pixels.draw_pixmap( + bounds.x as i32, + bounds.y as i32, + temp_pixmap.as_ref(), + &PixmapPaint::default(), + transform, + clip_mask, + ); } } Primitive::Text { -- cgit From bf7d636ebf90b6eba3ab6e4c718439e382ce9ec0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 27 Jun 2023 22:05:49 +0200 Subject: Draw border path for `quad` only if it has a border in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 214 ++++++++++++++++++++++++----------------------- 1 file changed, 109 insertions(+), 105 deletions(-) (limited to 'tiny_skia') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index d0d24b23..86eccdda 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -159,7 +159,6 @@ impl Backend { border_width, border_color, } => { - // XXX border seems to be contained by the bounds of the primitive in wgpu and for damage regions, so we do the same here let physical_bounds = (*bounds + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { @@ -206,115 +205,120 @@ impl Backend { clip_mask, ); - // border path is offset by half the border width - let path_bounds = Rectangle { - x: bounds.x + border_width / 2.0, - y: bounds.y + border_width / 2.0, - width: bounds.width - border_width, - height: bounds.height - border_width, - }; - - // Make sure the border radius is correct - let mut border_radius = *border_radius; - let mut border_radius_gt_half_border_width = - [true, true, true, true]; - for (i, radius) in &mut border_radius.iter_mut().enumerate() { - *radius = if *radius == 0.0 { - // Path should handle this fine - 0.0 - } else if *radius > border_width / 2.0 { - *radius - border_width / 2.0 - } else { - border_radius_gt_half_border_width[i] = false; - 0.0 - } - .min(path_bounds.width / 2.0) - .min(path_bounds.height / 2.0); - } - - // Stroking a path works well in this case. - if border_radius_gt_half_border_width.iter().all(|b| *b) { - let border_radius_path = - rounded_rectangle(path_bounds, border_radius); - - pixels.stroke_path( - &border_radius_path, - &tiny_skia::Paint { - shader: tiny_skia::Shader::SolidColor(into_color( - *border_color, - )), - anti_alias: true, - ..tiny_skia::Paint::default() - }, - &tiny_skia::Stroke { - width: border_width, - ..tiny_skia::Stroke::default() - }, - transform, - clip_mask, - ); - } else { - // Draw corners that have to small border radii as having no border radius, - // but mask them with the rounded rectangle with the correct border radius. - - let mut temp_pixmap = - Pixmap::new(bounds.width as u32, bounds.height as u32) - .unwrap(); - - let mut quad_mask = - Mask::new(bounds.width as u32, bounds.height as u32) - .unwrap(); - - let zero_bounds = Rectangle { - x: 0.0, - y: 0.0, - width: bounds.width, - height: bounds.height, - }; - let path = - rounded_rectangle(zero_bounds, fill_border_radius); - - quad_mask.fill_path( - &path, - tiny_skia::FillRule::EvenOdd, - true, - transform, - ); - let path_bounds = Rectangle { - x: border_width / 2.0, - y: border_width / 2.0, + if border_width > 0.0 { + // Border path is offset by half the border width + let border_bounds = Rectangle { + x: bounds.x + border_width / 2.0, + y: bounds.y + border_width / 2.0, width: bounds.width - border_width, height: bounds.height - border_width, }; - let border_radius_path = - rounded_rectangle(path_bounds, border_radius); - - temp_pixmap.stroke_path( - &border_radius_path, - &tiny_skia::Paint { - shader: tiny_skia::Shader::SolidColor(into_color( - *border_color, - )), - anti_alias: true, - ..tiny_skia::Paint::default() - }, - &tiny_skia::Stroke { - width: border_width, - ..tiny_skia::Stroke::default() - }, - transform, - Some(&quad_mask), - ); + // Make sure the border radius is correct + let mut border_radius = *border_radius; + let mut is_simple_border = true; + + for radius in &mut border_radius { + *radius = if *radius == 0.0 { + // Path should handle this fine + 0.0 + } else if *radius > border_width / 2.0 { + *radius - border_width / 2.0 + } else { + is_simple_border = false; + 0.0 + } + .min(border_bounds.width / 2.0) + .min(border_bounds.height / 2.0); + } - pixels.draw_pixmap( - bounds.x as i32, - bounds.y as i32, - temp_pixmap.as_ref(), - &PixmapPaint::default(), - transform, - clip_mask, - ); + // Stroking a path works well in this case + if is_simple_border { + let border_path = + rounded_rectangle(border_bounds, border_radius); + + pixels.stroke_path( + &border_path, + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor( + into_color(*border_color), + ), + anti_alias: true, + ..tiny_skia::Paint::default() + }, + &tiny_skia::Stroke { + width: border_width, + ..tiny_skia::Stroke::default() + }, + transform, + clip_mask, + ); + } else { + // Draw corners that have too small border radii as having no border radius, + // but mask them with the rounded rectangle with the correct border radius. + let mut temp_pixmap = Pixmap::new( + bounds.width as u32, + bounds.height as u32, + ) + .unwrap(); + + let mut quad_mask = Mask::new( + bounds.width as u32, + bounds.height as u32, + ) + .unwrap(); + + let zero_bounds = Rectangle { + x: 0.0, + y: 0.0, + width: bounds.width, + height: bounds.height, + }; + let path = + rounded_rectangle(zero_bounds, fill_border_radius); + + quad_mask.fill_path( + &path, + tiny_skia::FillRule::EvenOdd, + true, + transform, + ); + let path_bounds = Rectangle { + x: border_width / 2.0, + y: border_width / 2.0, + width: bounds.width - border_width, + height: bounds.height - border_width, + }; + + let border_radius_path = + rounded_rectangle(path_bounds, border_radius); + + temp_pixmap.stroke_path( + &border_radius_path, + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor( + into_color(*border_color), + ), + anti_alias: true, + ..tiny_skia::Paint::default() + }, + &tiny_skia::Stroke { + width: border_width, + ..tiny_skia::Stroke::default() + }, + transform, + Some(&quad_mask), + ); + + pixels.draw_pixmap( + bounds.x as i32, + bounds.y as i32, + temp_pixmap.as_ref(), + &PixmapPaint::default(), + transform, + clip_mask, + ); + } } } Primitive::Text { -- cgit From 2f886b0e4e1927ead031b1256026d53f48d5f8eb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 27 Jun 2023 22:06:32 +0200 Subject: Fix import consistency in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'tiny_skia') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 86eccdda..87738174 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,5 +1,3 @@ -use tiny_skia::{Mask, Pixmap, PixmapPaint}; - use crate::core::text; use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector}; use crate::graphics::backend; @@ -256,13 +254,13 @@ impl Backend { } else { // Draw corners that have too small border radii as having no border radius, // but mask them with the rounded rectangle with the correct border radius. - let mut temp_pixmap = Pixmap::new( + let mut temp_pixmap = tiny_skia::Pixmap::new( bounds.width as u32, bounds.height as u32, ) .unwrap(); - let mut quad_mask = Mask::new( + let mut quad_mask = tiny_skia::Mask::new( bounds.width as u32, bounds.height as u32, ) @@ -314,7 +312,7 @@ impl Backend { bounds.x as i32, bounds.y as i32, temp_pixmap.as_ref(), - &PixmapPaint::default(), + &tiny_skia::PixmapPaint::default(), transform, clip_mask, ); -- cgit