diff options
author | 2023-05-11 19:21:36 -0400 | |
---|---|---|
committer | 2023-05-11 19:21:36 -0400 | |
commit | 102c78abd8085d06b72da8edfa83a15ff9df89f2 (patch) | |
tree | 1964719bec03029d0b00642d79875cfc8824bd44 /tiny_skia | |
parent | 5ee26cc8ec1a49c78d1f3f99ebf6696f827ea5d1 (diff) | |
download | iced-102c78abd8085d06b72da8edfa83a15ff9df89f2.tar.gz iced-102c78abd8085d06b72da8edfa83a15ff9df89f2.tar.bz2 iced-102c78abd8085d06b72da8edfa83a15ff9df89f2.zip |
fix: tiny-skia quad handle case where border_radius < border_width / 2.0
Diffstat (limited to 'tiny_skia')
-rw-r--r-- | tiny_skia/src/backend.rs | 90 |
1 files changed, 83 insertions, 7 deletions
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 { |