mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-01 13:49:16 +00:00
LibWeb: Do not deform bitmaps partially outside the img-box
Instead of trying to manually determine which parts of a bitmap fall within the box of the `<img>` element, just draw the whole bitmap and let Skia clip the draw-area to the correct rectangle. This fixes a bug where the entire bitmap was squashed into the rectangle of the image box instead of being clipped. With this change, image rendering is now correct enough to import some of the WPT tests for object-fit and object-position. To get some good coverage I have imported all tests for the `<img>` tag. I also wanted to import a subset of the tests for the `<object>` tag, since those are passing as well now. Unfortunately, they are flaky for unknown reasons. This is the second attempt at this bugfix. The prior one wase055927ead
and broke image rendering whenever the page was scrolled. It has subsequently been reverted in16b14273d1
. Hopefully this time it is not horribly broken.
This commit is contained in:
parent
5d3b45127e
commit
d76f841994
Notes:
github-actions[bot]
2025-03-10 16:15:05 +00:00
Author: https://github.com/InvalidUsernameException
Commit: d76f841994
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3854
36 changed files with 1758 additions and 24 deletions
|
@ -79,7 +79,6 @@ void ImagePaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
|
||||
auto scale_x = 0.0f;
|
||||
auto scale_y = 0.0f;
|
||||
Gfx::IntRect bitmap_intersect = bitmap_rect;
|
||||
|
||||
// https://drafts.csswg.org/css-images/#the-object-fit
|
||||
auto object_fit = m_is_svg_image ? CSS::ObjectFit::Contain : computed_values().object_fit();
|
||||
|
@ -109,11 +108,9 @@ void ImagePaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
if (bitmap_aspect_ratio >= image_aspect_ratio) {
|
||||
scale_x = (float)image_rect.width() / bitmap_rect.width();
|
||||
scale_y = scale_x;
|
||||
bitmap_intersect.set_height(bitmap_rect.width() * image_aspect_ratio);
|
||||
} else {
|
||||
scale_x = (float)image_rect.height() / bitmap_rect.height();
|
||||
scale_y = scale_x;
|
||||
bitmap_intersect.set_width(bitmap_rect.height() / image_aspect_ratio);
|
||||
}
|
||||
break;
|
||||
case CSS::ObjectFit::ScaleDown:
|
||||
|
@ -121,7 +118,6 @@ void ImagePaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
case CSS::ObjectFit::None:
|
||||
scale_x = 1;
|
||||
scale_y = 1;
|
||||
bitmap_intersect.set_size(image_rect.size().to_type<int>());
|
||||
}
|
||||
|
||||
auto scaled_bitmap_width = CSSPixels::nearest_value_for(bitmap_rect.width() * scale_x);
|
||||
|
@ -130,31 +126,22 @@ void ImagePaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
auto residual_horizontal = image_rect.width() - scaled_bitmap_width;
|
||||
auto residual_vertical = image_rect.height() - scaled_bitmap_height;
|
||||
|
||||
bitmap_intersect.set_x((bitmap_rect.width() - bitmap_intersect.width()) / 2);
|
||||
bitmap_intersect.set_y((bitmap_rect.height() - bitmap_intersect.height()) / 2);
|
||||
|
||||
// https://drafts.csswg.org/css-images/#the-object-position
|
||||
auto const& object_position = computed_values().object_position();
|
||||
|
||||
auto offset_x = CSSPixels::from_raw(0);
|
||||
if (object_position.edge_x == CSS::PositionEdge::Left) {
|
||||
offset_x = object_position.offset_x.to_px(layout_node(), residual_horizontal);
|
||||
bitmap_intersect.set_x(0);
|
||||
} else if (object_position.edge_x == CSS::PositionEdge::Right) {
|
||||
offset_x = residual_horizontal - object_position.offset_x.to_px(layout_node(), residual_horizontal);
|
||||
}
|
||||
if (image_rect.width() < scaled_bitmap_width)
|
||||
bitmap_intersect.set_x(-(offset_x / scale_x));
|
||||
|
||||
auto offset_y = CSSPixels::from_raw(0);
|
||||
if (object_position.edge_y == CSS::PositionEdge::Top) {
|
||||
offset_y = object_position.offset_y.to_px(layout_node(), residual_vertical);
|
||||
bitmap_intersect.set_y(0);
|
||||
} else if (object_position.edge_y == CSS::PositionEdge::Bottom) {
|
||||
offset_y = residual_vertical - object_position.offset_y.to_px(layout_node(), residual_vertical);
|
||||
}
|
||||
if (image_rect.height() < scaled_bitmap_height)
|
||||
bitmap_intersect.set_y(-(offset_y / scale_y));
|
||||
|
||||
Gfx::IntRect draw_rect = {
|
||||
image_int_rect_device_pixels.x() + context.rounded_device_pixels(offset_x).value(),
|
||||
|
@ -163,7 +150,7 @@ void ImagePaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
context.rounded_device_pixels(scaled_bitmap_height).value()
|
||||
};
|
||||
|
||||
context.display_list_recorder().draw_scaled_immutable_bitmap(draw_rect.intersected(image_int_rect_device_pixels), *bitmap, bitmap_rect.intersected(bitmap_intersect), scaling_mode);
|
||||
context.display_list_recorder().draw_scaled_immutable_bitmap(draw_rect, image_int_rect_device_pixels, *bitmap, scaling_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue