From da5d4e9f6a64fcfa86c9f3cc00f83942810d00b9 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Thu, 27 Feb 2025 16:56:43 +0100 Subject: [PATCH] LibWeb: Assign sticky insets to Layout::InlineNode Before this change we were ignoring boxes with `display: inline` while assigning sticky insets. This was not correct because inline boxes are allowed to have sticky positioning. Fixes: https://github.com/LadybirdBrowser/ladybird/issues/3718 https://github.com/LadybirdBrowser/ladybird/issues/3507 https://github.com/LadybirdBrowser/ladybird/issues/3133 --- Libraries/LibWeb/Layout/LayoutState.cpp | 56 ++++++++++--------- Libraries/LibWeb/Layout/LayoutState.h | 1 + .../display-inline-with-position-sticky.html | 50 +++++++++++++++++ 3 files changed, 81 insertions(+), 26 deletions(-) create mode 100644 Tests/LibWeb/Crash/Layout/display-inline-with-position-sticky.html diff --git a/Libraries/LibWeb/Layout/LayoutState.cpp b/Libraries/LibWeb/Layout/LayoutState.cpp index ddcc6cd0389..8c3e3e18475 100644 --- a/Libraries/LibWeb/Layout/LayoutState.cpp +++ b/Libraries/LibWeb/Layout/LayoutState.cpp @@ -445,38 +445,42 @@ void LayoutState::commit(Box& root) 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& node = used_values.node(); + for (auto& paintable : node.paintables()) { + Painting::PaintableBox* paintable_box = nullptr; + if (is(paintable)) + paintable_box = &static_cast(paintable); - auto& paintable_box = const_cast(*box.paintable_box()); + if (!paintable_box) + continue; - 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. + if (node.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 sticky_insets = make(); + auto const& inset = node.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(); - } + 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, scrollport_size.height()); + if (!inset.top().is_auto()) { + sticky_insets->top = inset.top().to_px(node, scrollport_size.height()); + } + if (!inset.right().is_auto()) { + sticky_insets->right = inset.right().to_px(node, scrollport_size.width()); + } + if (!inset.bottom().is_auto()) { + sticky_insets->bottom = inset.bottom().to_px(node, scrollport_size.height()); + } + if (!inset.left().is_auto()) { + sticky_insets->left = inset.left().to_px(node, scrollport_size.width()); + } + paintable_box->set_sticky_insets(move(sticky_insets)); } - if (!inset.right().is_auto()) { - sticky_insets->right = inset.right().to_px(box, scrollport_size.width()); - } - if (!inset.bottom().is_auto()) { - sticky_insets->bottom = inset.bottom().to_px(box, scrollport_size.height()); - } - if (!inset.left().is_auto()) { - sticky_insets->left = inset.left().to_px(box, scrollport_size.width()); - } - paintable_box.set_sticky_insets(move(sticky_insets)); } } } diff --git a/Libraries/LibWeb/Layout/LayoutState.h b/Libraries/LibWeb/Layout/LayoutState.h index 7f969cbf669..748c8e1a61f 100644 --- a/Libraries/LibWeb/Layout/LayoutState.h +++ b/Libraries/LibWeb/Layout/LayoutState.h @@ -73,6 +73,7 @@ struct LayoutState { struct UsedValues { NodeWithStyle const& node() const { return *m_node; } + NodeWithStyle& node() { return const_cast(*m_node); } void set_node(NodeWithStyle&, UsedValues const* containing_block_used_values); UsedValues const* containing_block_used_values() const { return m_containing_block_used_values; } diff --git a/Tests/LibWeb/Crash/Layout/display-inline-with-position-sticky.html b/Tests/LibWeb/Crash/Layout/display-inline-with-position-sticky.html new file mode 100644 index 00000000000..bc50f65dc82 --- /dev/null +++ b/Tests/LibWeb/Crash/Layout/display-inline-with-position-sticky.html @@ -0,0 +1,50 @@ + + + + + + + +
+

+ This is an example of an inline box with position: sticky. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum euismod, nulla id consequat facilisis, + libero risus placerat lacus, sed fermentum nisl nunc non sapien. Vivamus scelerisque feugiat dui, ac + venenatis ligula ultricies vel. Duis id nunc in felis feugiat cursus. Pellentesque habitant morbi tristique + senectus et netus et malesuada fames ac turpis egestas. + Curabitur at felis ac massa aliquet dictum. Ut auctor ligula non ante interdum, a euismod dui tristique. Nam + consequat, massa ut ultrices fermentum, lacus libero vulputate nulla, sit amet vehicula erat odio a metus. + Nulla vitae lectus sed erat scelerisque sodales. +

+

+ This is an example of an inline box with position: sticky. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum euismod, nulla id consequat facilisis, + libero risus placerat lacus, sed fermentum nisl nunc non sapien. Vivamus scelerisque feugiat dui, ac + venenatis ligula ultricies vel. Duis id nunc in felis feugiat cursus. Pellentesque habitant morbi tristique + senectus et netus et malesuada fames ac turpis egestas. + Curabitur at felis ac massa aliquet dictum. Ut auctor ligula non ante interdum, a euismod dui tristique. Nam + consequat, massa ut ultrices fermentum, lacus libero vulputate nulla, sit amet vehicula erat odio a metus. + Nulla vitae lectus sed erat scelerisque sodales. +

+
+ + +