Skip to content

Commit f63a9d1

Browse files
authored
Merge pull request #1843 from wash2/fix-tiny-skia-quad
fix: quad rendering including border only inside of the bounds
2 parents c7332c1 + 2f886b0 commit f63a9d1

1 file changed

Lines changed: 126 additions & 18 deletions

File tree

tiny_skia/src/backend.rs

Lines changed: 126 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)