From 1a78edb8c90b151d6d6e63226ce63e759045eeb7 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Sat, 5 Oct 2024 22:18:53 +0200 Subject: [PATCH] LibWeb: Define static position calculation separately for each FC Static position of a box is defined by formatting context type it belongs to, so let's define this algorithm separately for each FC instead of assuming FormattingContext::calculate_static_position_rect() understands how to handle all of them. Also with this change calculate_static_position_rect() is no longer virtual function. --- .../LibWeb/Layout/BlockFormattingContext.cpp | 9 ++++ .../LibWeb/Layout/BlockFormattingContext.h | 1 + .../LibWeb/Layout/FlexFormattingContext.h | 2 +- .../LibWeb/Layout/FormattingContext.cpp | 47 ------------------- .../LibWeb/Layout/FormattingContext.h | 1 - .../LibWeb/Layout/GridFormattingContext.cpp | 12 +++++ .../LibWeb/Layout/GridFormattingContext.h | 1 + .../LibWeb/Layout/InlineFormattingContext.cpp | 38 +++++++++++++++ .../LibWeb/Layout/InlineFormattingContext.h | 1 + .../LibWeb/Layout/TableFormattingContext.cpp | 9 ++++ .../LibWeb/Layout/TableFormattingContext.h | 1 + 11 files changed, 73 insertions(+), 49 deletions(-) diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index 38f1638804c..4d9fa836a7c 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -1329,4 +1329,13 @@ CSSPixels BlockFormattingContext::greatest_child_width(Box const& box) const return max_width; } +StaticPositionRect BlockFormattingContext::calculate_static_position_rect(Box const& box) const +{ + StaticPositionRect static_position; + auto const& box_state = m_state.get(box); + auto offset_to_static_parent = content_box_rect_in_static_position_ancestor_coordinate_space(box, *box.containing_block()); + static_position.rect = { offset_to_static_parent.location().translated(0, box_state.vertical_offset_of_parent_block_container), { 0, 0 } }; + return static_position; +} + } diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h index 6d7301d003f..c5415155c7a 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h @@ -25,6 +25,7 @@ public: virtual void run(AvailableSpace const&) override; virtual CSSPixels automatic_content_width() const override; virtual CSSPixels automatic_content_height() const override; + StaticPositionRect calculate_static_position_rect(Box const&) const; auto const& left_side_floats() const { return m_left_floats; } auto const& right_side_floats() const { return m_right_floats; } diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h index 7ad776651d8..ef3cd331ef4 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h @@ -24,7 +24,7 @@ public: Box const& flex_container() const { return context_box(); } - virtual StaticPositionRect calculate_static_position_rect(Box const&) const override; + StaticPositionRect calculate_static_position_rect(Box const&) const; private: [[nodiscard]] bool should_treat_main_size_as_auto(Box const&) const; diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp index 65eee891d26..f241c725b4a 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -1174,53 +1174,6 @@ CSSPixelRect FormattingContext::content_box_rect_in_static_position_ancestor_coo VERIFY_NOT_REACHED(); } -// https://www.w3.org/TR/css-position-3/#staticpos-rect -StaticPositionRect FormattingContext::calculate_static_position_rect(Box const& box) const -{ - // NOTE: This is very ad-hoc. - // The purpose of this function is to calculate the approximate position that `box` - // would have had if it were position:static. - - CSSPixels x = 0; - CSSPixels y = 0; - - VERIFY(box.parent()); - if (box.parent()->children_are_inline()) { - // We're an abspos box with inline siblings. This is gonna get messy! - if (auto* sibling = box.previous_sibling()) { - // Hard case: there's a previous sibling. This means there's already inline content - // preceding the hypothetical static position of `box` within its containing block. - // If we had been position:static, that inline content would have been wrapped in - // anonymous block box, so now we get to imagine what the world might have looked like - // in that scenario.. - // Basically, we find its last associated line box fragment and place `box` under it. - // FIXME: I'm 100% sure this can be smarter, better and faster. - LineBoxFragment const* last_fragment = nullptr; - auto& cb_state = m_state.get(*sibling->containing_block()); - for (auto& line_box : cb_state.line_boxes) { - for (auto& fragment : line_box.fragments()) { - if (&fragment.layout_node() == sibling) - last_fragment = &fragment; - } - } - if (last_fragment) { - x = last_fragment->offset().x() + last_fragment->width(); - y = last_fragment->offset().y() + last_fragment->height(); - } - } else { - // Easy case: no previous sibling, we're at the top of the containing block. - } - } else { - auto const& box_state = m_state.get(box); - // We're among block siblings, Y can be calculated easily. - y = box_state.vertical_offset_of_parent_block_container; - } - auto offset_to_static_parent = content_box_rect_in_static_position_ancestor_coordinate_space(box, *box.containing_block()); - StaticPositionRect static_position_rect; - static_position_rect.rect = { offset_to_static_parent.location().translated(x, y), { 0, 0 } }; - return static_position_rect; -} - void FormattingContext::layout_absolutely_positioned_element(Box const& box, AvailableSpace const& available_space) { if (box.is_svg_box()) { diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.h b/Userland/Libraries/LibWeb/Layout/FormattingContext.h index 66dfc846cd7..a2f8f6a819d 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.h @@ -107,7 +107,6 @@ public: [[nodiscard]] CSSPixels calculate_stretch_fit_width(Box const&, AvailableSize const&) const; [[nodiscard]] CSSPixels calculate_stretch_fit_height(Box const&, AvailableSize const&) const; - virtual StaticPositionRect calculate_static_position_rect(Box const&) const; bool can_skip_is_anonymous_text_run(Box&); void compute_inset(NodeWithStyleAndBoxModelMetrics const&); diff --git a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp index 2fe197d9a92..62c8fa78c0d 100644 --- a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp @@ -2508,6 +2508,18 @@ CSSPixels GridFormattingContext::calculate_minimum_contribution(GridItem const& return calculate_min_content_contribution(item, dimension); } +StaticPositionRect GridFormattingContext::calculate_static_position_rect(Box const& box) const +{ + // Result of this function is only used when containing block is not a grid container. + // If the containing block is a grid container then static position is a grid area rect and + // layout_absolutely_positioned_element() defined for GFC knows how to handle this case. + StaticPositionRect static_position; + auto const& box_state = m_state.get(box); + auto offset_to_static_parent = content_box_rect_in_static_position_ancestor_coordinate_space(box, *box.containing_block()); + static_position.rect = { offset_to_static_parent.location().translated(0, 0), { box_state.content_width(), box_state.content_height() } }; + return static_position; +} + } namespace AK { diff --git a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h index e2ba6b5f067..580be87ff11 100644 --- a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h @@ -109,6 +109,7 @@ public: virtual void run(AvailableSpace const& available_space) override; virtual CSSPixels automatic_content_width() const override; virtual CSSPixels automatic_content_height() const override; + StaticPositionRect calculate_static_position_rect(Box const&) const; Box const& grid_container() const { return context_box(); } diff --git a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp index b999e9b3288..a8e758d625e 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp @@ -463,4 +463,42 @@ void InlineFormattingContext::set_vertical_float_clearance(CSSPixels vertical_fl { m_vertical_float_clearance = vertical_float_clearance; } + +StaticPositionRect InlineFormattingContext::calculate_static_position_rect(Box const& box) const +{ + CSSPixels x = 0; + CSSPixels y = 0; + + VERIFY(box.parent()); + VERIFY(box.parent()->children_are_inline()); + // We're an abspos box with inline siblings. This is gonna get messy! + if (auto const* sibling = box.previous_sibling()) { + // Hard case: there's a previous sibling. This means there's already inline content + // preceding the hypothetical static position of `box` within its containing block. + // If we had been position:static, that inline content would have been wrapped in + // anonymous block box, so now we get to imagine what the world might have looked like + // in that scenario.. + // Basically, we find its last associated line box fragment and place `box` under it. + // FIXME: I'm 100% sure this can be smarter, better and faster. + LineBoxFragment const* last_fragment = nullptr; + auto const& cb_state = m_state.get(*sibling->containing_block()); + for (auto const& line_box : cb_state.line_boxes) { + for (auto const& fragment : line_box.fragments()) { + if (&fragment.layout_node() == sibling) + last_fragment = &fragment; + } + } + if (last_fragment) { + x = last_fragment->offset().x() + last_fragment->width(); + y = last_fragment->offset().y() + last_fragment->height(); + } + } else { + // Easy case: no previous sibling, we're at the top of the containing block. + } + auto offset_to_static_parent = content_box_rect_in_static_position_ancestor_coordinate_space(box, *box.containing_block()); + StaticPositionRect static_position_rect; + static_position_rect.rect = { offset_to_static_parent.location().translated(x, y), { 0, 0 } }; + return static_position_rect; +} + } diff --git a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.h b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.h index 13d95c4568a..4cd7f4fd882 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.h @@ -26,6 +26,7 @@ public: virtual void run(AvailableSpace const&) override; virtual CSSPixels automatic_content_height() const override; virtual CSSPixels automatic_content_width() const override; + StaticPositionRect calculate_static_position_rect(Box const&) const; void dimension_box_on_line(Box const&, LayoutMode); diff --git a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp index bc7d629d89a..57a93c1e69f 100644 --- a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp @@ -1849,6 +1849,15 @@ CSSPixels TableFormattingContext::border_spacing_vertical() const return computed_values.border_spacing_vertical().to_px(table_box()); } +StaticPositionRect TableFormattingContext::calculate_static_position_rect(Box const& box) const +{ + // FIXME: Implement static position calculation for table descendants instead of always returning a rectangle with zero position and size. + StaticPositionRect static_position; + auto offset_to_static_parent = content_box_rect_in_static_position_ancestor_coordinate_space(box, *box.containing_block()); + static_position.rect = { offset_to_static_parent.location(), { 0, 0 } }; + return static_position; +} + template<> Vector& TableFormattingContext::table_rows_or_columns() { diff --git a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h index dac2b4b2730..8145cd96cbc 100644 --- a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h @@ -28,6 +28,7 @@ public: virtual void run(AvailableSpace const&) override; virtual CSSPixels automatic_content_width() const override; virtual CSSPixels automatic_content_height() const override; + StaticPositionRect calculate_static_position_rect(Box const&) const; Box const& table_box() const { return context_box(); } TableWrapper const& table_wrapper() const