LibWeb: Add "position: sticky" support

Sticky positioning is implemented by modifying the algorithm for
assigning and refreshing scroll frames. Now, elements with
"position: sticky" are assigned their own scroll frame, and their
position is refreshed independently from regular scroll boxes.
Refreshing the scroll offsets for sticky boxes does not require display
list invalidation.

A separate hash map is used for the scroll frames of sticky boxes. This
is necessary because a single paintable box can have two scroll frames
if it 1) has "position: sticky" and 2) contains scrollable overflow.
This commit is contained in:
Aliaksandr Kalenik
2024-08-24 19:20:31 +02:00
committed by Alexander Kalenik
parent 866608532a
commit 30b636e90b
20 changed files with 705 additions and 2 deletions

View File

@@ -243,6 +243,11 @@ bool PaintableBox::is_scrollable(ScrollDirection direction) const
return overflow == CSS::Overflow::Scroll;
}
bool PaintableBox::is_scrollable() const
{
return is_scrollable(ScrollDirection::Horizontal) || is_scrollable(ScrollDirection::Vertical);
}
static constexpr CSSPixels scrollbar_thumb_thickness = 8;
Optional<CSSPixelRect> PaintableBox::scroll_thumb_rect(ScrollDirection direction) const
@@ -1111,4 +1116,25 @@ RefPtr<ScrollFrame const> PaintableBox::nearest_scroll_frame() const
return nullptr;
}
CSSPixelRect PaintableBox::padding_box_rect_relative_to_nearest_scrollable_ancestor() const
{
auto result = absolute_padding_box_rect();
auto const* nearest_scrollable_ancestor = this->nearest_scrollable_ancestor();
if (nearest_scrollable_ancestor) {
result.set_location(result.location() - nearest_scrollable_ancestor->absolute_rect().top_left());
}
return result;
}
PaintableBox const* PaintableBox::nearest_scrollable_ancestor() const
{
auto const* paintable = this->containing_block();
while (paintable) {
if (paintable->is_scrollable())
return paintable;
paintable = paintable->containing_block();
}
return nullptr;
}
}