From c19358e1576514c6006756cff31190ae2488c5c0 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 13 Oct 2021 21:41:35 +0200 Subject: [PATCH] LibWeb: Move FFC layout algorithm step 2 into a separate function Determining the available main and cross space is now done by a separate function. The signature is a little bit hairy since this function computes some things that are used by subsequent algorithm steps. Factoring can definitely be improved further. --- .../LibWeb/Layout/FlexFormattingContext.cpp | 132 ++++++++++-------- .../LibWeb/Layout/FlexFormattingContext.h | 6 + 2 files changed, 77 insertions(+), 61 deletions(-) diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp index 2c4120c6ee..383c6602ee 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp @@ -72,8 +72,6 @@ void FlexFormattingContext::run(Box& flex_container, LayoutMode) bool is_row = is_row_layout(); - // Determine main/cross direction - auto main_size_is_infinite = false; auto layout_for_maximum_main_size = [&](Box& box) { bool main_constrained = false; if (is_row) { @@ -107,19 +105,7 @@ void FlexFormattingContext::run(Box& flex_container, LayoutMode) return BlockFormattingContext::compute_theoretical_height(box); } }; - auto containing_block_effective_main_size = [&is_row, &main_size_is_infinite](Box& box) { - if (is_row) { - if (box.containing_block()->has_definite_width()) - return box.containing_block()->width(); - main_size_is_infinite = true; - return NumericLimits::max(); - } else { - if (box.containing_block()->has_definite_height()) - return box.containing_block()->height(); - main_size_is_infinite = true; - return NumericLimits::max(); - } - }; + auto calculate_hypothetical_cross_size = [&is_row, this](Box& box) { bool cross_constrained = false; if (is_row) { @@ -158,56 +144,16 @@ void FlexFormattingContext::run(Box& flex_container, LayoutMode) generate_anonymous_flex_items(flex_container, flex_items); // 2. Determine the available main and cross space for the flex items - float main_available_size = 0; - [[maybe_unused]] float cross_available_size = 0; - [[maybe_unused]] float main_max_size = NumericLimits::max(); - [[maybe_unused]] float main_min_size = 0; + float main_max_size = NumericLimits::max(); + float main_min_size = 0; float cross_max_size = NumericLimits::max(); float cross_min_size = 0; - bool main_is_constrained = false; bool cross_is_constrained = false; - - if (has_definite_main_size(flex_container)) { - main_is_constrained = true; - main_available_size = specified_main_size(flex_container); - } else { - if (has_main_max_size(flex_container)) { - main_max_size = specified_main_max_size(flex_container); - main_available_size = main_max_size; - main_is_constrained = true; - } - if (has_main_min_size(flex_container)) { - main_min_size = specified_main_min_size(flex_container); - main_is_constrained = true; - } - - if (!main_is_constrained) { - auto available_main_size = containing_block_effective_main_size(flex_container); - main_available_size = available_main_size - sum_of_margin_padding_border_in_main_axis(flex_container); - if (flex_container.computed_values().flex_wrap() == CSS::FlexWrap::Wrap || flex_container.computed_values().flex_wrap() == CSS::FlexWrap::WrapReverse) { - main_available_size = specified_main_size(*flex_container.containing_block()); - main_is_constrained = true; - } - } - } - - if (has_definite_cross_size(flex_container)) { - cross_available_size = specified_cross_size(flex_container); - } else { - if (has_cross_max_size(flex_container)) { - cross_max_size = specified_cross_max_size(flex_container); - cross_is_constrained = true; - } - if (has_cross_min_size(flex_container)) { - cross_min_size = specified_cross_min_size(flex_container); - cross_is_constrained = true; - } - - // FIXME: Is this right? Probably not. - if (!cross_is_constrained) - cross_available_size = cross_max_size; - } + bool main_size_is_infinite = false; + auto available_space = determine_available_main_and_cross_space(flex_container, main_size_is_infinite, main_is_constrained, cross_is_constrained, main_min_size, main_max_size, cross_min_size, cross_max_size); + auto main_available_size = available_space.main; + [[maybe_unused]] auto cross_available_size = available_space.cross; // 3. Determine the flex base size and hypothetical main size of each item for (auto& flex_item : flex_items) { @@ -898,4 +844,68 @@ float FlexFormattingContext::sum_of_margin_padding_border_in_main_axis(Box const } } +// https://www.w3.org/TR/css-flexbox-1/#algo-available +FlexFormattingContext::AvailableSpace FlexFormattingContext::determine_available_main_and_cross_space(const Box& flex_container, bool& main_size_is_infinite, bool& main_is_constrained, bool& cross_is_constrained, float& main_min_size, float& main_max_size, float& cross_min_size, float& cross_max_size) const +{ + auto containing_block_effective_main_size = [&](Box const& box) { + if (is_row_layout()) { + if (box.containing_block()->has_definite_width()) + return box.containing_block()->width(); + main_size_is_infinite = true; + return NumericLimits::max(); + } else { + if (box.containing_block()->has_definite_height()) + return box.containing_block()->height(); + main_size_is_infinite = true; + return NumericLimits::max(); + } + }; + + float main_available_space = 0; + float cross_available_space = 0; + + if (has_definite_main_size(flex_container)) { + main_is_constrained = true; + main_available_space = specified_main_size(flex_container); + } else { + if (has_main_max_size(flex_container)) { + main_max_size = specified_main_max_size(flex_container); + main_available_space = main_max_size; + main_is_constrained = true; + } + if (has_main_min_size(flex_container)) { + main_min_size = specified_main_min_size(flex_container); + main_is_constrained = true; + } + + if (!main_is_constrained) { + auto available_main_size = containing_block_effective_main_size(flex_container); + main_available_space = available_main_size - sum_of_margin_padding_border_in_main_axis(flex_container); + if (flex_container.computed_values().flex_wrap() == CSS::FlexWrap::Wrap || flex_container.computed_values().flex_wrap() == CSS::FlexWrap::WrapReverse) { + main_available_space = specified_main_size(*flex_container.containing_block()); + main_is_constrained = true; + } + } + } + + if (has_definite_cross_size(flex_container)) { + cross_available_space = specified_cross_size(flex_container); + } else { + if (has_cross_max_size(flex_container)) { + cross_max_size = specified_cross_max_size(flex_container); + cross_is_constrained = true; + } + if (has_cross_min_size(flex_container)) { + cross_min_size = specified_cross_min_size(flex_container); + cross_is_constrained = true; + } + + // FIXME: Is this right? Probably not. + if (!cross_is_constrained) + cross_available_space = cross_max_size; + } + + return AvailableSpace { .main = main_available_space, .cross = cross_available_space }; +} + } diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h index cc58b21e97..9a4a864d3f 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h @@ -50,6 +50,12 @@ private: void generate_anonymous_flex_items(Box& flex_container, Vector&); + struct AvailableSpace { + float main { 0 }; + float cross { 0 }; + }; + AvailableSpace determine_available_main_and_cross_space(Box const& flex_container, bool& main_size_is_infinite, bool& main_is_constrained, bool& cross_is_constrained, float& main_min_size, float& main_max_size, float& cross_min_size, float& cross_max_size) const; + bool is_row_layout() const { return m_flex_direction == CSS::FlexDirection::Row || m_flex_direction == CSS::FlexDirection::RowReverse; } CSS::FlexDirection m_flex_direction {};