From 415ea4ec0cdb2848beb5c0c213f8f70fcfa2ecb7 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Mon, 2 Sep 2024 20:46:41 +0200 Subject: [PATCH] LibWeb: Resolve "position: sticky" insets relative to scrollport Reading of https://drafts.csswg.org/css-position revealed I was wrong assuming sticky insets need to be resolved relative to containing block. --- ...sticky-box-with-percentage-insets-ref.html | 28 ++++++++++++++++++ .../sticky-box-with-percentage-insets.html | 29 +++++++++++++++++++ .../Libraries/LibWeb/Layout/LayoutState.cpp | 27 ++++++++++++++--- 3 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 Tests/LibWeb/Ref/reference/sticky-box-with-percentage-insets-ref.html create mode 100644 Tests/LibWeb/Ref/sticky-box-with-percentage-insets.html diff --git a/Tests/LibWeb/Ref/reference/sticky-box-with-percentage-insets-ref.html b/Tests/LibWeb/Ref/reference/sticky-box-with-percentage-insets-ref.html new file mode 100644 index 00000000000..725c217f396 --- /dev/null +++ b/Tests/LibWeb/Ref/reference/sticky-box-with-percentage-insets-ref.html @@ -0,0 +1,28 @@ + +
+
I'm sticky
+
diff --git a/Tests/LibWeb/Ref/sticky-box-with-percentage-insets.html b/Tests/LibWeb/Ref/sticky-box-with-percentage-insets.html new file mode 100644 index 00000000000..36f3ebccdf7 --- /dev/null +++ b/Tests/LibWeb/Ref/sticky-box-with-percentage-insets.html @@ -0,0 +1,29 @@ + + +
+
I'm sticky
+
diff --git a/Userland/Libraries/LibWeb/Layout/LayoutState.cpp b/Userland/Libraries/LibWeb/Layout/LayoutState.cpp index 7dd63dd875a..9f55d639aa3 100644 --- a/Userland/Libraries/LibWeb/Layout/LayoutState.cpp +++ b/Userland/Libraries/LibWeb/Layout/LayoutState.cpp @@ -376,21 +376,40 @@ void LayoutState::commit(Box& root) auto& paintable_box = const_cast(*box.paintable_box()); if (!paintable_box.scroll_offset().is_zero()) paintable_box.set_scroll_offset(paintable_box.scroll_offset()); + } + + for (auto& it : used_values_per_layout_node) { + auto& used_values = *it.value; + if (!used_values.node().is_box()) + continue; + auto const& box = static_cast(used_values.node()); + + auto& paintable_box = const_cast(*box.paintable_box()); if (box.is_sticky_position()) { + // https://drafts.csswg.org/css-position/#insets + // For sticky positioned boxes, the inset is instead relative to the relevant scrollport’s size. Negative values are allowed. + auto sticky_insets = make(); auto const& inset = box.computed_values().inset(); + + auto const* nearest_scrollable_ancestor = paintable_box.nearest_scrollable_ancestor(); + CSSPixelSize scrollport_size; + if (nearest_scrollable_ancestor) { + scrollport_size = nearest_scrollable_ancestor->absolute_rect().size(); + } + if (!inset.top().is_auto()) { - sticky_insets->top = inset.top().to_px(box, used_values.containing_block_used_values()->content_height()); + sticky_insets->top = inset.top().to_px(box, scrollport_size.height()); } if (!inset.right().is_auto()) { - sticky_insets->right = inset.right().to_px(box, used_values.containing_block_used_values()->content_width()); + sticky_insets->right = inset.right().to_px(box, scrollport_size.width()); } if (!inset.bottom().is_auto()) { - sticky_insets->bottom = inset.bottom().to_px(box, used_values.containing_block_used_values()->content_height()); + sticky_insets->bottom = inset.bottom().to_px(box, scrollport_size.height()); } if (!inset.left().is_auto()) { - sticky_insets->left = inset.left().to_px(box, used_values.containing_block_used_values()->content_width()); + sticky_insets->left = inset.left().to_px(box, scrollport_size.width()); } paintable_box.set_sticky_insets(move(sticky_insets)); }