1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 06:07:34 +00:00

LibWeb: Improve FFC step 7 (hypothetical cross size)

- Avoid performing inside layout on definite-size flex items (since
  their computed size can be used as-is.)

- Use FormattingState::clone() to generate a throwaway layout instead of
  mutating the tree in-place.

- Update spec link & comments based on current CSSWG draft. The latest
  version is quite a bit clearer on how this should work.
This commit is contained in:
Andreas Kling 2022-02-27 13:39:38 +01:00
parent b904bff838
commit 1ce1af5d8b
2 changed files with 31 additions and 28 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org> * Copyright (c) 2021-2022, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org> * Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
@ -117,7 +117,7 @@ void FlexFormattingContext::run(Box const& run_box, LayoutMode)
// Cross Size Determination // Cross Size Determination
// 7. Determine the hypothetical cross size of each item // 7. Determine the hypothetical cross size of each item
for (auto& flex_item : m_flex_items) { for (auto& flex_item : m_flex_items) {
flex_item.hypothetical_cross_size = determine_hypothetical_cross_size_of_item(flex_item.box); determine_hypothetical_cross_size_of_item(flex_item);
} }
// 8. Calculate the cross size of each flex line. // 8. Calculate the cross size of each flex line.
@ -825,36 +825,39 @@ void FlexFormattingContext::resolve_flexible_lengths(float const main_available_
} }
} }
// https://www.w3.org/TR/css-flexbox-1/#algo-cross-item // https://drafts.csswg.org/css-flexbox-1/#algo-cross-item
float FlexFormattingContext::determine_hypothetical_cross_size_of_item(Box const& box) void FlexFormattingContext::determine_hypothetical_cross_size_of_item(FlexItem& item)
{ {
bool cross_constrained = false; // Determine the hypothetical cross size of each item by performing layout
if (is_row_layout()) { // as if it were an in-flow block-level box with the used main size
if (!is_undefined_or_auto(box.computed_values().height()) || !is_undefined_or_auto(box.computed_values().min_height())) { // and the given available space, treating auto as fit-content.
cross_constrained = true;
} // If we have a definite cross size, this is easy! No need to perform layout, we can just use it as-is.
if (has_definite_cross_size(item.box)) {
auto const& cross_value = is_row_layout() ? item.box.computed_values().height() : item.box.computed_values().width();
item.hypothetical_cross_size = cross_value->length().to_px(item.box);
return;
}
// For indefinite cross sizes, we perform a throwaway layout and then measure it.
auto throwaway_state = m_state;
auto& tmp_container_state = throwaway_state.get_mutable(flex_container());
tmp_container_state.content_width = is_row_layout() ? m_available_space->main : m_available_space->cross;
VERIFY(item.box.containing_block() == &flex_container());
if (auto independent_formatting_context = create_independent_formatting_context_if_needed(throwaway_state, item.box)) {
independent_formatting_context->run(item.box, LayoutMode::Default);
} else { } else {
if (!is_undefined_or_auto(box.computed_values().width()) || !is_undefined_or_auto(box.computed_values().min_width())) { // NOTE: Flex items should always create an independent formatting context!
cross_constrained = true; VERIFY_NOT_REACHED();
}
} }
if (!cross_constrained && box.children_are_inline()) { auto const& box_state = throwaway_state.get(item.box);
auto& block_container = verify_cast<BlockContainer>(box); if (is_row_layout()) {
BlockFormattingContext bfc(m_state, block_container, this); item.hypothetical_cross_size = BlockFormattingContext::compute_theoretical_height(throwaway_state, item.box);
bfc.run(box, LayoutMode::Default); } else {
InlineFormattingContext ifc(m_state, block_container, bfc); item.hypothetical_cross_size = box_state.content_width;
ifc.run(box, LayoutMode::OnlyRequiredLineBreaks);
auto const& box_state = m_state.get(box);
return is_row_layout() ? box_state.content_height : box_state.content_width;
} }
if (is_row_layout())
return BlockFormattingContext::compute_theoretical_height(m_state, box);
BlockFormattingContext context(m_state, verify_cast<BlockContainer>(box), this);
context.compute_width(box);
return m_state.get(box).content_width;
} }
// https://www.w3.org/TR/css-flexbox-1/#algo-cross-line // https://www.w3.org/TR/css-flexbox-1/#algo-cross-line

View file

@ -96,7 +96,7 @@ private:
void resolve_flexible_lengths(float main_available_size); void resolve_flexible_lengths(float main_available_size);
float determine_hypothetical_cross_size_of_item(Box const&); void determine_hypothetical_cross_size_of_item(FlexItem&);
void calculate_cross_size_of_each_flex_line(float cross_min_size, float cross_max_size); void calculate_cross_size_of_each_flex_line(float cross_min_size, float cross_max_size);