Skip to content

Commit 102c78a

Browse files
committed
fix: tiny-skia quad handle case where border_radius < border_width / 2.0
1 parent 5ee26cc commit 102c78a

1 file changed

Lines changed: 83 additions & 7 deletions

File tree

tiny_skia/src/backend.rs

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use tiny_skia::{Mask, Pixmap, PixmapPaint};
2+
13
use crate::core::text;
24
use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector};
35
use crate::graphics::backend;
@@ -212,17 +214,29 @@ impl Backend {
212214
height: bounds.height - border_width,
213215
};
214216

217+
// Make sure the border radius is correct
215218
let mut border_radius = *border_radius;
216-
for radius in &mut border_radius {
217-
*radius = radius
218-
.min(path_bounds.width / 2.0)
219-
.min(path_bounds.height / 2.0);
219+
let mut border_radius_gt_half_border_width =
220+
[true, true, true, true];
221+
for (i, radius) in &mut border_radius.iter_mut().enumerate() {
222+
*radius = if *radius == 0.0 {
223+
// Path should handle this fine
224+
0.0
225+
} else if *radius > border_width / 2.0 {
226+
*radius - border_width / 2.0
227+
} else {
228+
border_radius_gt_half_border_width[i] = false;
229+
0.0
230+
}
231+
.min(path_bounds.width / 2.0)
232+
.min(path_bounds.height / 2.0);
220233
}
221234

222-
let border_radius_path =
223-
rounded_rectangle(path_bounds, border_radius);
235+
// Stroking a path works well in this case.
236+
if border_radius_gt_half_border_width.iter().all(|b| *b) {
237+
let border_radius_path =
238+
rounded_rectangle(path_bounds, border_radius);
224239

225-
if border_width > 0.0 {
226240
pixels.stroke_path(
227241
&border_radius_path,
228242
&tiny_skia::Paint {
@@ -239,6 +253,68 @@ impl Backend {
239253
transform,
240254
clip_mask,
241255
);
256+
} else {
257+
// Draw corners that have to small border radii as having no border radius,
258+
// but mask them with the rounded rectangle with the correct border radius.
259+
260+
let mut temp_pixmap =
261+
Pixmap::new(bounds.width as u32, bounds.height as u32)
262+
.unwrap();
263+
264+
let mut quad_mask =
265+
Mask::new(bounds.width as u32, bounds.height as u32)
266+
.unwrap();
267+
268+
let zero_bounds = Rectangle {
269+
x: 0.0,
270+
y: 0.0,
271+
width: bounds.width,
272+
height: bounds.height,
273+
};
274+
let path =
275+
rounded_rectangle(zero_bounds, fill_border_radius);
276+
277+
quad_mask.fill_path(
278+
&path,
279+
tiny_skia::FillRule::EvenOdd,
280+
true,
281+
transform,
282+
);
283+
let path_bounds = Rectangle {
284+
x: border_width / 2.0,
285+
y: border_width / 2.0,
286+
width: bounds.width - border_width,
287+
height: bounds.height - border_width,
288+
};
289+
290+
let border_radius_path =
291+
rounded_rectangle(path_bounds, border_radius);
292+
293+
temp_pixmap.stroke_path(
294+
&border_radius_path,
295+
&tiny_skia::Paint {
296+
shader: tiny_skia::Shader::SolidColor(into_color(
297+
*border_color,
298+
)),
299+
anti_alias: true,
300+
..tiny_skia::Paint::default()
301+
},
302+
&tiny_skia::Stroke {
303+
width: border_width,
304+
..tiny_skia::Stroke::default()
305+
},
306+
transform,
307+
Some(&quad_mask),
308+
);
309+
310+
pixels.draw_pixmap(
311+
bounds.x as i32,
312+
bounds.y as i32,
313+
temp_pixmap.as_ref(),
314+
&PixmapPaint::default(),
315+
transform,
316+
clip_mask,
317+
);
242318
}
243319
}
244320
Primitive::Text {

0 commit comments

Comments
 (0)