Skip to content

Commit 26b200c

Browse files
joshuamegnauth54hecrj
authored andcommitted
Fix Tiny Skia panic on infinite length quads
Fixes issue 2066. Iced may produce primitives with an infinite length or width. The WGPU renderer handles those somewhere along the pipeline. Tiny Skia's `PathBuilder::finish` returns `None` if non-normal floats are passed to the builder. This patch adds a check to prevent that. See: * https://github.com/RazrFalcon/tiny-skia/blob/master/path/src/path_builder.rs#L421 * https://github.com/RazrFalcon/tiny-skia/blob/master/path/src/rect.rs#L344
1 parent 66c8a80 commit 26b200c

1 file changed

Lines changed: 55 additions & 27 deletions

File tree

tiny_skia/src/backend.rs

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use tiny_skia::Size;
2-
31
use crate::core::{Background, Color, Gradient, Rectangle, Vector};
42
use crate::graphics::backend;
53
use crate::graphics::text;
@@ -155,6 +153,29 @@ impl Backend {
155153
border,
156154
shadow,
157155
} => {
156+
// Tiny Skia's `PathBuilder::finish` returns `None` on infinites and NaNs which causes iced to panic.
157+
// Certain widget combinations can lead to an infinite in either dimension hence the need for this check.
158+
// However, it's likely a misuse of iced's API so the check only applies on debug builds.
159+
// https://docs.rs/tiny-skia/latest/tiny_skia/struct.Rect.html#method.from_points
160+
#[cfg(debug_assertions)]
161+
let checked_bounds = Rectangle::new(
162+
bounds.position(),
163+
crate::core::Size {
164+
width: if bounds.width.is_normal() {
165+
bounds.width
166+
} else {
167+
clip_bounds.width
168+
},
169+
height: if bounds.height.is_normal() {
170+
bounds.height
171+
} else {
172+
clip_bounds.height
173+
},
174+
},
175+
);
176+
#[cfg(debug_assertions)]
177+
let bounds = &checked_bounds;
178+
158179
let physical_bounds = (*bounds + translation) * scale_factor;
159180

160181
if !clip_bounds.intersects(&physical_bounds) {
@@ -211,31 +232,34 @@ impl Backend {
211232
(x..x + width).map(move |x| (x as f32, y as f32))
212233
})
213234
.filter_map(|(x, y)| {
214-
Size::from_wh(half_width, half_height).map(|size| {
215-
let shadow_distance = rounded_box_sdf(
216-
Vector::new(
217-
x - physical_bounds.position().x
218-
- (shadow.offset.x * scale_factor)
219-
- half_width,
220-
y - physical_bounds.position().y
221-
- (shadow.offset.y * scale_factor)
222-
- half_height,
223-
),
224-
size,
225-
&radii,
226-
);
227-
let shadow_alpha = 1.0
228-
- smoothstep(
229-
-shadow.blur_radius * scale_factor,
230-
shadow.blur_radius * scale_factor,
231-
shadow_distance,
235+
tiny_skia::Size::from_wh(half_width, half_height)
236+
.map(|size| {
237+
let shadow_distance = rounded_box_sdf(
238+
Vector::new(
239+
x - physical_bounds.position().x
240+
- (shadow.offset.x
241+
* scale_factor)
242+
- half_width,
243+
y - physical_bounds.position().y
244+
- (shadow.offset.y
245+
* scale_factor)
246+
- half_height,
247+
),
248+
size,
249+
&radii,
232250
);
233-
234-
let mut color = into_color(shadow.color);
235-
color.apply_opacity(shadow_alpha);
236-
237-
color.to_color_u8().premultiply()
238-
})
251+
let shadow_alpha = 1.0
252+
- smoothstep(
253+
-shadow.blur_radius * scale_factor,
254+
shadow.blur_radius * scale_factor,
255+
shadow_distance,
256+
);
257+
258+
let mut color = into_color(shadow.color);
259+
color.apply_opacity(shadow_alpha);
260+
261+
color.to_color_u8().premultiply()
262+
})
239263
})
240264
.collect();
241265

@@ -947,7 +971,11 @@ fn smoothstep(a: f32, b: f32, x: f32) -> f32 {
947971
x * x * (3.0 - 2.0 * x)
948972
}
949973

950-
fn rounded_box_sdf(to_center: Vector, size: Size, radii: &[f32]) -> f32 {
974+
fn rounded_box_sdf(
975+
to_center: Vector,
976+
size: tiny_skia::Size,
977+
radii: &[f32],
978+
) -> f32 {
951979
let radius = match (to_center.x > 0.0, to_center.y > 0.0) {
952980
(true, true) => radii[2],
953981
(true, false) => radii[1],

0 commit comments

Comments
 (0)