|
1 | | -use tiny_skia::Size; |
2 | | - |
3 | 1 | use crate::core::{Background, Color, Gradient, Rectangle, Vector}; |
4 | 2 | use crate::graphics::backend; |
5 | 3 | use crate::graphics::text; |
@@ -155,6 +153,29 @@ impl Backend { |
155 | 153 | border, |
156 | 154 | shadow, |
157 | 155 | } => { |
| 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 | + |
158 | 179 | let physical_bounds = (*bounds + translation) * scale_factor; |
159 | 180 |
|
160 | 181 | if !clip_bounds.intersects(&physical_bounds) { |
@@ -211,31 +232,34 @@ impl Backend { |
211 | 232 | (x..x + width).map(move |x| (x as f32, y as f32)) |
212 | 233 | }) |
213 | 234 | .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, |
232 | 250 | ); |
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 | + }) |
239 | 263 | }) |
240 | 264 | .collect(); |
241 | 265 |
|
@@ -947,7 +971,11 @@ fn smoothstep(a: f32, b: f32, x: f32) -> f32 { |
947 | 971 | x * x * (3.0 - 2.0 * x) |
948 | 972 | } |
949 | 973 |
|
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 { |
951 | 979 | let radius = match (to_center.x > 0.0, to_center.y > 0.0) { |
952 | 980 | (true, true) => radii[2], |
953 | 981 | (true, false) => radii[1], |
|
0 commit comments