LibWeb: Don't crash with near-zero background sizes

This commit is contained in:
Gingeh 2025-07-01 14:21:12 +10:00 committed by Sam Atkins
commit fa410a67d9
Notes: github-actions[bot] 2025-07-02 10:46:43 +00:00
4 changed files with 25 additions and 0 deletions

View file

@ -268,6 +268,12 @@ void paint_background(PaintContext& context, PaintableBox const& paintable_box,
while (image_x < css_clip_rect.right()) { while (image_x < css_clip_rect.right()) {
image_rect.set_x(image_x); image_rect.set_x(image_x);
auto image_device_rect = context.rounded_device_rect(image_rect); auto image_device_rect = context.rounded_device_rect(image_rect);
// If the image's dimensions were rounded to zero then they need to be restored to avoid a crash.
// There's no need to check that !image_rect.is_empty() because empty images are discarded in resolve_background_layers.
if (image_device_rect.width() == 0)
image_device_rect.set_width(1);
if (image_device_rect.height() == 0)
image_device_rect.set_height(1);
callback(image_device_rect); callback(image_device_rect);
if (!repeat_x) if (!repeat_x)
break; break;
@ -299,6 +305,13 @@ void paint_background(PaintContext& context, PaintableBox const& paintable_box,
// Use a dedicated painting command for repeated images instead of recording a separate command for each instance // Use a dedicated painting command for repeated images instead of recording a separate command for each instance
// of a repeated background, so the painter has the opportunity to optimize the painting of repeated images. // of a repeated background, so the painter has the opportunity to optimize the painting of repeated images.
auto dest_rect = context.rounded_device_rect(image_rect); auto dest_rect = context.rounded_device_rect(image_rect);
// If the image's dimensions were rounded to zero then they need to be restored to avoid a crash.
// There's no need to check that !image_rect.is_empty() because empty images are discarded in resolve_background_layers.
if (dest_rect.width() == 0)
dest_rect.set_width(1);
if (dest_rect.height() == 0)
dest_rect.set_height(1);
auto const* bitmap = static_cast<CSS::ImageStyleValue const&>(image).current_frame_bitmap(dest_rect); auto const* bitmap = static_cast<CSS::ImageStyleValue const&>(image).current_frame_bitmap(dest_rect);
auto scaling_mode = to_gfx_scaling_mode(image_rendering, bitmap->rect(), dest_rect.to_type<int>()); auto scaling_mode = to_gfx_scaling_mode(image_rendering, bitmap->rect(), dest_rect.to_type<int>());
context.display_list_recorder().draw_repeated_immutable_bitmap(dest_rect.to_type<int>(), clip_rect.to_type<int>(), *bitmap, scaling_mode, { .x = repeat_x, .y = repeat_y }); context.display_list_recorder().draw_repeated_immutable_bitmap(dest_rect.to_type<int>(), clip_rect.to_type<int>(), *bitmap, scaling_mode, { .x = repeat_x, .y = repeat_y });

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50">
<rect fill="green" width="50" height="50"/>
</svg>

After

Width:  |  Height:  |  Size: 116 B

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<div style="width: 100px; height: 100px; background: green"></div>

View file

@ -0,0 +1,7 @@
<!DOCTYPE html>
<link rel="match" href="../expected/background-size-near-zero-svg-ref.html">
<div style="background-image: url(../data/50x50-green.svg);
width: 100px; height: 100px; background-size: 0.2px 0.2px">
</div>
<!-- FIXME: Workaround to ensure CSS background-image is loaded before taking screenshot: https://github.com/LadybirdBrowser/ladybird/issues/3448 -->
<img style="display: none" src="../data/50x50-green.svg">