@@ -174,7 +174,18 @@ impl Backend {
174174 )
175175 . post_scale ( scale_factor, scale_factor) ;
176176
177- let path = rounded_rectangle ( * bounds, * border_radius) ;
177+ // Make sure the border radius is not larger than the bounds
178+ let border_width = border_width
179+ . min ( bounds. width / 2.0 )
180+ . min ( bounds. height / 2.0 ) ;
181+
182+ let mut fill_border_radius = * border_radius;
183+ for radius in & mut fill_border_radius {
184+ * radius = ( * radius)
185+ . min ( bounds. width / 2.0 )
186+ . min ( bounds. height / 2.0 ) ;
187+ }
188+ let path = rounded_rectangle ( * bounds, fill_border_radius) ;
178189
179190 pixels. fill_path (
180191 & path,
@@ -236,23 +247,120 @@ impl Backend {
236247 clip_mask,
237248 ) ;
238249
239- if * border_width > 0.0 {
240- pixels. stroke_path (
241- & path,
242- & tiny_skia:: Paint {
243- shader : tiny_skia:: Shader :: SolidColor ( into_color (
244- * border_color,
245- ) ) ,
246- anti_alias : true ,
247- ..tiny_skia:: Paint :: default ( )
248- } ,
249- & tiny_skia:: Stroke {
250- width : * border_width,
251- ..tiny_skia:: Stroke :: default ( )
252- } ,
253- transform,
254- clip_mask,
255- ) ;
250+ if border_width > 0.0 {
251+ // Border path is offset by half the border width
252+ let border_bounds = Rectangle {
253+ x : bounds. x + border_width / 2.0 ,
254+ y : bounds. y + border_width / 2.0 ,
255+ width : bounds. width - border_width,
256+ height : bounds. height - border_width,
257+ } ;
258+
259+ // Make sure the border radius is correct
260+ let mut border_radius = * border_radius;
261+ let mut is_simple_border = true ;
262+
263+ for radius in & mut border_radius {
264+ * radius = if * radius == 0.0 {
265+ // Path should handle this fine
266+ 0.0
267+ } else if * radius > border_width / 2.0 {
268+ * radius - border_width / 2.0
269+ } else {
270+ is_simple_border = false ;
271+ 0.0
272+ }
273+ . min ( border_bounds. width / 2.0 )
274+ . min ( border_bounds. height / 2.0 ) ;
275+ }
276+
277+ // Stroking a path works well in this case
278+ if is_simple_border {
279+ let border_path =
280+ rounded_rectangle ( border_bounds, border_radius) ;
281+
282+ pixels. stroke_path (
283+ & border_path,
284+ & tiny_skia:: Paint {
285+ shader : tiny_skia:: Shader :: SolidColor (
286+ into_color ( * border_color) ,
287+ ) ,
288+ anti_alias : true ,
289+ ..tiny_skia:: Paint :: default ( )
290+ } ,
291+ & tiny_skia:: Stroke {
292+ width : border_width,
293+ ..tiny_skia:: Stroke :: default ( )
294+ } ,
295+ transform,
296+ clip_mask,
297+ ) ;
298+ } else {
299+ // Draw corners that have too small border radii as having no border radius,
300+ // but mask them with the rounded rectangle with the correct border radius.
301+ let mut temp_pixmap = tiny_skia:: Pixmap :: new (
302+ bounds. width as u32 ,
303+ bounds. height as u32 ,
304+ )
305+ . unwrap ( ) ;
306+
307+ let mut quad_mask = tiny_skia:: Mask :: new (
308+ bounds. width as u32 ,
309+ bounds. height as u32 ,
310+ )
311+ . unwrap ( ) ;
312+
313+ let zero_bounds = Rectangle {
314+ x : 0.0 ,
315+ y : 0.0 ,
316+ width : bounds. width ,
317+ height : bounds. height ,
318+ } ;
319+ let path =
320+ rounded_rectangle ( zero_bounds, fill_border_radius) ;
321+
322+ quad_mask. fill_path (
323+ & path,
324+ tiny_skia:: FillRule :: EvenOdd ,
325+ true ,
326+ transform,
327+ ) ;
328+ let path_bounds = Rectangle {
329+ x : border_width / 2.0 ,
330+ y : border_width / 2.0 ,
331+ width : bounds. width - border_width,
332+ height : bounds. height - border_width,
333+ } ;
334+
335+ let border_radius_path =
336+ rounded_rectangle ( path_bounds, border_radius) ;
337+
338+ temp_pixmap. stroke_path (
339+ & border_radius_path,
340+ & tiny_skia:: Paint {
341+ shader : tiny_skia:: Shader :: SolidColor (
342+ into_color ( * border_color) ,
343+ ) ,
344+ anti_alias : true ,
345+ ..tiny_skia:: Paint :: default ( )
346+ } ,
347+ & tiny_skia:: Stroke {
348+ width : border_width,
349+ ..tiny_skia:: Stroke :: default ( )
350+ } ,
351+ transform,
352+ Some ( & quad_mask) ,
353+ ) ;
354+
355+ pixels. draw_pixmap (
356+ bounds. x as i32 ,
357+ bounds. y as i32 ,
358+ temp_pixmap. as_ref ( ) ,
359+ & tiny_skia:: PixmapPaint :: default ( ) ,
360+ transform,
361+ clip_mask,
362+ ) ;
363+ }
256364 }
257365 }
258366 Primitive :: Text {
0 commit comments