summaryrefslogtreecommitdiffstats
path: root/tiny_skia/src/backend.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tiny_skia/src/backend.rs')
-rw-r--r--tiny_skia/src/backend.rs190
1 files changed, 148 insertions, 42 deletions
diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs
index 9d0fc527..e0134220 100644
--- a/tiny_skia/src/backend.rs
+++ b/tiny_skia/src/backend.rs
@@ -2,7 +2,8 @@ use crate::core::text;
use crate::core::Gradient;
use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector};
use crate::graphics::backend;
-use crate::graphics::{Primitive, Viewport};
+use crate::graphics::{Damage, Viewport};
+use crate::primitive::{self, Primitive};
use crate::Settings;
use std::borrow::Cow;
@@ -174,7 +175,18 @@ 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);
+
+ let mut fill_border_radius = *border_radius;
+ for radius in &mut fill_border_radius {
+ *radius = (*radius)
+ .min(bounds.width / 2.0)
+ .min(bounds.height / 2.0);
+ }
+ let path = rounded_rectangle(*bounds, fill_border_radius);
pixels.fill_path(
&path,
@@ -236,23 +248,120 @@ impl Backend {
clip_mask,
);
- if *border_width > 0.0 {
- pixels.stroke_path(
- &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,
- );
+ 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,
+ };
+
+ // 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);
+ }
+
+ // 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 = tiny_skia::Pixmap::new(
+ bounds.width as u32,
+ bounds.height as u32,
+ )
+ .unwrap();
+
+ let mut quad_mask = tiny_skia::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(),
+ &tiny_skia::PixmapPaint::default(),
+ transform,
+ clip_mask,
+ );
+ }
}
}
Primitive::Text {
@@ -311,6 +420,13 @@ impl Backend {
self.raster_pipeline
.draw(handle, *bounds, pixels, transform, clip_mask);
}
+ #[cfg(not(feature = "image"))]
+ Primitive::Image { .. } => {
+ log::warn!(
+ "Unsupported primitive in `iced_tiny_skia`: {:?}",
+ primitive
+ );
+ }
#[cfg(feature = "svg")]
Primitive::Svg {
handle,
@@ -334,12 +450,19 @@ impl Backend {
clip_mask,
);
}
- Primitive::Fill {
+ #[cfg(not(feature = "svg"))]
+ Primitive::Svg { .. } => {
+ log::warn!(
+ "Unsupported primitive in `iced_tiny_skia`: {:?}",
+ primitive
+ );
+ }
+ Primitive::Custom(primitive::Custom::Fill {
path,
paint,
rule,
transform,
- } => {
+ }) => {
let bounds = path.bounds();
let physical_bounds = (Rectangle {
@@ -367,12 +490,12 @@ impl Backend {
clip_mask,
);
}
- Primitive::Stroke {
+ Primitive::Custom(primitive::Custom::Stroke {
path,
paint,
stroke,
transform,
- } => {
+ }) => {
let bounds = path.bounds();
let physical_bounds = (Rectangle {
@@ -472,21 +595,6 @@ impl Backend {
translation,
);
}
- Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => {
- // Not supported!
- // TODO: Draw a placeholder (?)
- log::warn!(
- "Unsupported primitive in `iced_tiny_skia`: {:?}",
- primitive
- );
- }
- _ => {
- // Not supported!
- log::warn!(
- "Unsupported primitive in `iced_tiny_skia`: {:?}",
- primitive
- );
- }
}
}
}
@@ -659,9 +767,7 @@ fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) {
}
impl iced_graphics::Backend for Backend {
- fn trim_measurements(&mut self) {
- self.text_pipeline.trim_measurement_cache();
- }
+ type Primitive = primitive::Custom;
}
impl backend::Text for Backend {
@@ -685,7 +791,7 @@ impl backend::Text for Backend {
font: Font,
bounds: Size,
shaping: text::Shaping,
- ) -> (f32, f32) {
+ ) -> Size {
self.text_pipeline.measure(
contents,
size,