mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 12:05:15 +00:00
LibGfx: Add Rect::unite()
The existing `::unite_horizontally()` and `::unite_vertically()` tests did not properly test the edge cases where left/top in the Rect were updated, so they get re-arranged a bit.
This commit is contained in:
parent
c0e861e2fa
commit
7eb4f3da37
Notes:
github-actions[bot]
2025-01-23 08:34:31 +00:00
Author: https://github.com/gmta Commit: https://github.com/LadybirdBrowser/ladybird/commit/7eb4f3da37c Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3276 Reviewed-by: https://github.com/kalenikaliaksandr ✅
7 changed files with 51 additions and 38 deletions
|
@ -835,6 +835,18 @@ public:
|
|||
return { { point.x() - size.width() / 2, point.y() - size.height() / 2 }, size };
|
||||
}
|
||||
|
||||
void unite(Rect<T> const& other)
|
||||
{
|
||||
if (is_empty()) {
|
||||
*this = other;
|
||||
return;
|
||||
}
|
||||
if (other.is_empty())
|
||||
return;
|
||||
unite_horizontally(other);
|
||||
unite_vertically(other);
|
||||
}
|
||||
|
||||
void unite_horizontally(Rect<T> const& other)
|
||||
{
|
||||
auto new_left = min(left(), other.left());
|
||||
|
@ -853,15 +865,8 @@ public:
|
|||
|
||||
[[nodiscard]] Rect<T> united(Rect<T> const& other) const
|
||||
{
|
||||
if (is_empty())
|
||||
return other;
|
||||
if (other.is_empty())
|
||||
return *this;
|
||||
Rect<T> rect;
|
||||
rect.set_left(min(left(), other.left()));
|
||||
rect.set_top(min(top(), other.top()));
|
||||
rect.set_right(max(right(), other.right()));
|
||||
rect.set_bottom(max(bottom(), other.bottom()));
|
||||
Rect<T> rect = *this;
|
||||
rect.unite(other);
|
||||
return rect;
|
||||
}
|
||||
|
||||
|
|
|
@ -927,7 +927,7 @@ GC::Ref<Geometry::DOMRect> Element::get_bounding_client_rect() const
|
|||
auto const& rect = list->item(i);
|
||||
if (rect->width() == 0 || rect->height() == 0)
|
||||
continue;
|
||||
bounding_rect = bounding_rect.united({ rect->x(), rect->y(), rect->width(), rect->height() });
|
||||
bounding_rect.unite({ rect->x(), rect->y(), rect->width(), rect->height() });
|
||||
}
|
||||
return Geometry::DOMRect::create(realm(), bounding_rect.to_type<float>());
|
||||
}
|
||||
|
|
|
@ -1243,7 +1243,7 @@ GC::Ref<Geometry::DOMRect> Range::get_bounding_client_rect()
|
|||
auto const& rect = list->item(i);
|
||||
if (rect->width() == 0 || rect->height() == 0)
|
||||
continue;
|
||||
bounding_rect = bounding_rect.united({ rect->x(), rect->y(), rect->width(), rect->height() });
|
||||
bounding_rect.unite({ rect->x(), rect->y(), rect->width(), rect->height() });
|
||||
}
|
||||
return Geometry::DOMRect::create(realm(), bounding_rect.to_type<float>());
|
||||
}
|
||||
|
|
|
@ -89,9 +89,8 @@ static CSSPixelRect measure_scrollable_overflow(Box const& box)
|
|||
|
||||
// - All line boxes directly contained by the scroll container.
|
||||
if (is<Painting::PaintableWithLines>(box.first_paintable())) {
|
||||
for (auto const& fragment : static_cast<Painting::PaintableWithLines const&>(*box.first_paintable()).fragments()) {
|
||||
scrollable_overflow_rect = scrollable_overflow_rect.united(fragment.absolute_rect());
|
||||
}
|
||||
for (auto const& fragment : static_cast<Painting::PaintableWithLines const&>(*box.first_paintable()).fragments())
|
||||
scrollable_overflow_rect.unite(fragment.absolute_rect());
|
||||
}
|
||||
|
||||
auto content_overflow_rect = scrollable_overflow_rect;
|
||||
|
@ -117,8 +116,8 @@ static CSSPixelRect measure_scrollable_overflow(Box const& box)
|
|||
if (child_border_box.bottom() < 0 || child_border_box.right() < 0)
|
||||
return TraversalDecision::Continue;
|
||||
|
||||
scrollable_overflow_rect = scrollable_overflow_rect.united(child_border_box);
|
||||
content_overflow_rect = content_overflow_rect.united(child_border_box);
|
||||
scrollable_overflow_rect.unite(child_border_box);
|
||||
content_overflow_rect.unite(child_border_box);
|
||||
|
||||
// - The scrollable overflow areas of all of the above boxes
|
||||
// (including zero-area boxes and accounting for transforms as described above),
|
||||
|
|
|
@ -271,15 +271,11 @@ void paint_background(PaintContext& context, PaintableBox const& paintable_box,
|
|||
// However, we must first figure out the real coverage area, taking repeat etc into account.
|
||||
|
||||
// FIXME: This could be written in a far more efficient way.
|
||||
auto fill_rect = Optional<DevicePixelRect> {};
|
||||
DevicePixelRect fill_rect;
|
||||
for_each_image_device_rect([&](auto const& image_device_rect) {
|
||||
if (!fill_rect.has_value()) {
|
||||
fill_rect = image_device_rect;
|
||||
} else {
|
||||
fill_rect = fill_rect->united(image_device_rect);
|
||||
}
|
||||
fill_rect.unite(image_device_rect);
|
||||
});
|
||||
display_list_recorder.fill_rect(fill_rect->to_type<int>(), color.value());
|
||||
display_list_recorder.fill_rect(fill_rect.to_type<int>(), color.value());
|
||||
} else if (is<CSS::ImageStyleValue>(image) && repeat_x && repeat_y && !repeat_x_has_gap && !repeat_y_has_gap) {
|
||||
// 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.
|
||||
|
|
|
@ -209,7 +209,7 @@ CSSPixelRect PaintableBox::compute_absolute_paint_rect() const
|
|||
continue;
|
||||
auto inflate = shadow.spread_distance + shadow.blur_radius;
|
||||
auto shadow_rect = rect.inflated(inflate, inflate, inflate, inflate).translated(shadow.offset_x, shadow.offset_y);
|
||||
rect = rect.united(shadow_rect);
|
||||
rect.unite(shadow_rect);
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
|
|
|
@ -57,28 +57,41 @@ TEST_CASE(rect_closest_to)
|
|||
EXPECT_EQ(screen_rect.side(closest), Gfx::IntRect::Side::Top);
|
||||
}
|
||||
|
||||
TEST_CASE(rect_unite)
|
||||
{
|
||||
Gfx::IntRect rect_a { 10, 10, 100, 100 };
|
||||
Gfx::IntRect rect_b { 50, 50, 60, 70 };
|
||||
|
||||
rect_a.unite(rect_b);
|
||||
|
||||
EXPECT_EQ(rect_a.left(), 10);
|
||||
EXPECT_EQ(rect_a.right(), 110);
|
||||
EXPECT_EQ(rect_a.top(), 10);
|
||||
EXPECT_EQ(rect_a.bottom(), 120);
|
||||
}
|
||||
|
||||
TEST_CASE(rect_unite_horizontally)
|
||||
{
|
||||
Gfx::IntRect rect { 10, 10, 100, 100 };
|
||||
Gfx::IntRect huge_rect { 0, 0, 1000, 1000 };
|
||||
Gfx::IntRect rect_a { 10, 10, 1000, 100 };
|
||||
Gfx::IntRect rect_b { 0, 0, 100, 1000 };
|
||||
|
||||
rect.unite_horizontally(huge_rect);
|
||||
rect_a.unite_horizontally(rect_b);
|
||||
|
||||
EXPECT_EQ(rect.left(), 0);
|
||||
EXPECT_EQ(rect.right(), 1000);
|
||||
EXPECT_EQ(rect.top(), 10);
|
||||
EXPECT_EQ(rect.bottom(), 110);
|
||||
EXPECT_EQ(rect_a.left(), 0);
|
||||
EXPECT_EQ(rect_a.right(), 1010);
|
||||
EXPECT_EQ(rect_a.top(), 10);
|
||||
EXPECT_EQ(rect_a.bottom(), 110);
|
||||
}
|
||||
|
||||
TEST_CASE(rect_unite_vertically)
|
||||
{
|
||||
Gfx::IntRect rect { 10, 10, 100, 100 };
|
||||
Gfx::IntRect huge_rect { 0, 0, 1000, 1000 };
|
||||
Gfx::IntRect rect_a { 10, 10, 1000, 1000 };
|
||||
Gfx::IntRect rect_b { 0, 0, 100, 100 };
|
||||
|
||||
rect.unite_vertically(huge_rect);
|
||||
rect_a.unite_vertically(rect_b);
|
||||
|
||||
EXPECT_EQ(rect.top(), 0);
|
||||
EXPECT_EQ(rect.bottom(), 1000);
|
||||
EXPECT_EQ(rect.left(), 10);
|
||||
EXPECT_EQ(rect.right(), 110);
|
||||
EXPECT_EQ(rect_a.top(), 0);
|
||||
EXPECT_EQ(rect_a.bottom(), 1010);
|
||||
EXPECT_EQ(rect_a.left(), 10);
|
||||
EXPECT_EQ(rect_a.right(), 1010);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue