1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 19:37:36 +00:00

LibWeb: Cache pointer to UsedValues for each FlexItem

This avoids expensive repeated LayoutState hash lookups.
This commit is contained in:
Andreas Kling 2024-01-23 21:11:02 +01:00
parent 4e6de47f93
commit 7fedf806c2
2 changed files with 74 additions and 74 deletions

View file

@ -73,8 +73,8 @@ void FlexFormattingContext::run(Box const& run_box, LayoutMode, AvailableSpace c
// 3. If a single-line flex container has a definite cross size, // 3. If a single-line flex container has a definite cross size,
// the automatic preferred outer cross size of any stretched flex items is the flex containers inner cross size // the automatic preferred outer cross size of any stretched flex items is the flex containers inner cross size
// (clamped to the flex items min and max cross size) and is considered definite. // (clamped to the flex items min and max cross size) and is considered definite.
if (is_single_line() && has_definite_cross_size(flex_container())) { if (is_single_line() && has_definite_cross_size(m_flex_container_state)) {
auto flex_container_inner_cross_size = inner_cross_size(flex_container()); auto flex_container_inner_cross_size = inner_cross_size(m_flex_container_state);
for (auto& item : m_flex_items) { for (auto& item : m_flex_items) {
if (!flex_item_is_stretched(item)) if (!flex_item_is_stretched(item))
continue; continue;
@ -180,8 +180,7 @@ void FlexFormattingContext::run(Box const& run_box, LayoutMode, AvailableSpace c
// AD-HOC: Finally, layout the inside of all flex items. // AD-HOC: Finally, layout the inside of all flex items.
copy_dimensions_from_flex_items_to_boxes(); copy_dimensions_from_flex_items_to_boxes();
for (auto& item : m_flex_items) { for (auto& item : m_flex_items) {
auto& box_state = m_state.get(item.box); if (auto independent_formatting_context = layout_inside(item.box, LayoutMode::Normal, item.used_values.available_inner_space_or_constraints_from(m_available_space_for_items->space)))
if (auto independent_formatting_context = layout_inside(item.box, LayoutMode::Normal, box_state.available_inner_space_or_constraints_from(m_available_space_for_items->space)))
independent_formatting_context->parent_context_did_dimension_child_root_box(); independent_formatting_context->parent_context_did_dimension_child_root_box();
compute_inset(item.box); compute_inset(item.box);
@ -268,7 +267,7 @@ void FlexFormattingContext::generate_anonymous_flex_items()
return IterationDecision::Continue; return IterationDecision::Continue;
child_box.set_flex_item(true); child_box.set_flex_item(true);
FlexItem item = { child_box }; FlexItem item = { child_box, m_state.get_mutable(child_box) };
populate_specified_margins(item, m_flex_direction); populate_specified_margins(item, m_flex_direction);
auto& order_bucket = order_item_bucket.ensure(child_box.computed_values().order()); auto& order_bucket = order_item_bucket.ensure(child_box.computed_values().order());
@ -302,22 +301,19 @@ void FlexFormattingContext::generate_anonymous_flex_items()
} }
} }
bool FlexFormattingContext::has_definite_main_size(Box const& box) const bool FlexFormattingContext::has_definite_main_size(LayoutState::UsedValues const& used_values) const
{ {
auto const& used_values = m_state.get(box);
return is_row_layout() ? used_values.has_definite_width() : used_values.has_definite_height(); return is_row_layout() ? used_values.has_definite_width() : used_values.has_definite_height();
} }
CSSPixels FlexFormattingContext::inner_main_size(Box const& box) const CSSPixels FlexFormattingContext::inner_main_size(LayoutState::UsedValues const& used_values) const
{ {
auto const& box_state = m_state.get(box); return is_row_layout() ? used_values.content_width() : used_values.content_height();
return is_row_layout() ? box_state.content_width() : box_state.content_height();
} }
CSSPixels FlexFormattingContext::inner_cross_size(Box const& box) const CSSPixels FlexFormattingContext::inner_cross_size(LayoutState::UsedValues const& used_values) const
{ {
auto const& box_state = m_state.get(box); return is_row_layout() ? used_values.content_height() : used_values.content_width();
return is_row_layout() ? box_state.content_height() : box_state.content_width();
} }
bool FlexFormattingContext::has_main_min_size(Box const& box) const bool FlexFormattingContext::has_main_min_size(Box const& box) const
@ -332,9 +328,8 @@ bool FlexFormattingContext::has_cross_min_size(Box const& box) const
return !value.is_auto(); return !value.is_auto();
} }
bool FlexFormattingContext::has_definite_cross_size(Box const& box) const bool FlexFormattingContext::has_definite_cross_size(LayoutState::UsedValues const& used_values) const
{ {
auto const& used_values = m_state.get(box);
return is_row_layout() ? used_values.has_definite_height() : used_values.has_definite_width(); return is_row_layout() ? used_values.has_definite_height() : used_values.has_definite_width();
} }
@ -465,7 +460,7 @@ CSS::FlexBasis FlexFormattingContext::used_flex_basis_for_item(FlexItem const& i
// the used value for flex-basis is content. // the used value for flex-basis is content.
if (flex_basis.has<CSS::Size>() if (flex_basis.has<CSS::Size>()
&& flex_basis.get<CSS::Size>().is_percentage() && flex_basis.get<CSS::Size>().is_percentage()
&& !has_definite_main_size(flex_container())) { && !has_definite_main_size(m_flex_container_state)) {
flex_basis = CSS::FlexBasisContent {}; flex_basis = CSS::FlexBasisContent {};
} }
@ -553,11 +548,11 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size(
// - a definite cross size, // - a definite cross size,
if (item.box->has_preferred_aspect_ratio() if (item.box->has_preferred_aspect_ratio()
&& item.used_flex_basis->has<CSS::FlexBasisContent>() && item.used_flex_basis->has<CSS::FlexBasisContent>()
&& has_definite_cross_size(item.box)) { && has_definite_cross_size(item)) {
// flex_base_size is calculated from definite cross size and intrinsic aspect ratio // flex_base_size is calculated from definite cross size and intrinsic aspect ratio
return adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints( return adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(
item.box, item.box,
calculate_main_size_from_cross_size_and_aspect_ratio(inner_cross_size(item.box), item.box->preferred_aspect_ratio().value()), calculate_main_size_from_cross_size_and_aspect_ratio(inner_cross_size(item), item.box->preferred_aspect_ratio().value()),
computed_cross_min_size(item.box), computed_cross_min_size(item.box),
computed_cross_max_size(item.box)); computed_cross_max_size(item.box));
} }
@ -590,8 +585,8 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size(
// The flex base size is the items resulting main size. // The flex base size is the items resulting main size.
// NOTE: If the flex item has a definite main size, just use that as the flex base size. // NOTE: If the flex item has a definite main size, just use that as the flex base size.
if (has_definite_main_size(child_box)) if (has_definite_main_size(item))
return inner_main_size(child_box); return inner_main_size(item);
// NOTE: There's a fundamental problem with many CSS specifications in that they neglect to mention // NOTE: There's a fundamental problem with many CSS specifications in that they neglect to mention
// which width to provide when calculating the intrinsic height of a box in various situations. // which width to provide when calculating the intrinsic height of a box in various situations.
@ -632,9 +627,9 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size(
// The spec just barely hand-waves about this, but it seems to *roughly* match what other engines do. // The spec just barely hand-waves about this, but it seems to *roughly* match what other engines do.
// See "Note" section here: https://drafts.csswg.org/css-flexbox-1/#definite-sizes // See "Note" section here: https://drafts.csswg.org/css-flexbox-1/#definite-sizes
if (is_row_layout()) if (is_row_layout())
m_state.get_mutable(item.box).set_temporary_content_width(item.hypothetical_main_size); item.used_values.set_temporary_content_width(item.hypothetical_main_size);
else else
m_state.get_mutable(item.box).set_temporary_content_height(item.hypothetical_main_size); item.used_values.set_temporary_content_height(item.hypothetical_main_size);
} }
// https://drafts.csswg.org/css-flexbox-1/#min-size-auto // https://drafts.csswg.org/css-flexbox-1/#min-size-auto
@ -653,7 +648,7 @@ Optional<CSSPixels> FlexFormattingContext::specified_size_suggestion(FlexItem co
{ {
// If the items preferred main size is definite and not automatic, // If the items preferred main size is definite and not automatic,
// then the specified size suggestion is that size. It is otherwise undefined. // then the specified size suggestion is that size. It is otherwise undefined.
if (has_definite_main_size(item.box) && !should_treat_main_size_as_auto(item.box)) { if (has_definite_main_size(item) && !should_treat_main_size_as_auto(item.box)) {
// NOTE: We use get_pixel_{width,height} to ensure that CSS box-sizing is respected. // NOTE: We use get_pixel_{width,height} to ensure that CSS box-sizing is respected.
return is_row_layout() ? get_pixel_width(item.box, computed_main_size(item.box)) : get_pixel_height(item.box, computed_main_size(item.box)); return is_row_layout() ? get_pixel_width(item.box, computed_main_size(item.box)) : get_pixel_height(item.box, computed_main_size(item.box));
} }
@ -678,11 +673,11 @@ Optional<CSSPixels> FlexFormattingContext::transferred_size_suggestion(FlexItem
// If the item has a preferred aspect ratio and its preferred cross size is definite, // If the item has a preferred aspect ratio and its preferred cross size is definite,
// then the transferred size suggestion is that size // then the transferred size suggestion is that size
// (clamped by its minimum and maximum cross sizes if they are definite), converted through the aspect ratio. // (clamped by its minimum and maximum cross sizes if they are definite), converted through the aspect ratio.
if (item.box->has_preferred_aspect_ratio() && has_definite_cross_size(item.box)) { if (item.box->has_preferred_aspect_ratio() && has_definite_cross_size(item)) {
auto aspect_ratio = item.box->preferred_aspect_ratio().value(); auto aspect_ratio = item.box->preferred_aspect_ratio().value();
return adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints( return adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(
item.box, item.box,
calculate_main_size_from_cross_size_and_aspect_ratio(inner_cross_size(item.box), aspect_ratio), calculate_main_size_from_cross_size_and_aspect_ratio(inner_cross_size(item), aspect_ratio),
computed_cross_min_size(item.box), computed_cross_min_size(item.box),
computed_cross_max_size(item.box)); computed_cross_max_size(item.box));
} }
@ -774,7 +769,7 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
if (m_available_space_for_items->main.is_intrinsic_sizing_constraint()) if (m_available_space_for_items->main.is_intrinsic_sizing_constraint())
available_main_size = m_available_space_for_items->main; available_main_size = m_available_space_for_items->main;
else else
available_main_size = AvailableSize::make_definite(inner_main_size(flex_container())); available_main_size = AvailableSize::make_definite(inner_main_size(m_flex_container_state));
// 1. Determine the used flex factor. // 1. Determine the used flex factor.
@ -1008,14 +1003,14 @@ void FlexFormattingContext::determine_hypothetical_cross_size_of_item(FlexItem&
auto clamp_max = (!should_treat_cross_max_size_as_none(item.box) && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : CSSPixels::max(); auto clamp_max = (!should_treat_cross_max_size_as_none(item.box) && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : CSSPixels::max();
// If we have a definite cross size, this is easy! No need to perform layout, we can just use it as-is. // 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)) { if (has_definite_cross_size(item)) {
// To avoid subtracting padding and border twice for `box-sizing: border-box` only min and max clamp should happen on a second pass // To avoid subtracting padding and border twice for `box-sizing: border-box` only min and max clamp should happen on a second pass
if (resolve_percentage_min_max_sizes) { if (resolve_percentage_min_max_sizes) {
item.hypothetical_cross_size = css_clamp(item.hypothetical_cross_size, clamp_min, clamp_max); item.hypothetical_cross_size = css_clamp(item.hypothetical_cross_size, clamp_min, clamp_max);
return; return;
} }
item.hypothetical_cross_size = css_clamp(inner_cross_size(item.box), clamp_min, clamp_max); item.hypothetical_cross_size = css_clamp(inner_cross_size(item), clamp_min, clamp_max);
return; return;
} }
@ -1085,8 +1080,8 @@ void FlexFormattingContext::determine_hypothetical_cross_size_of_item(FlexItem&
void FlexFormattingContext::calculate_cross_size_of_each_flex_line() void FlexFormattingContext::calculate_cross_size_of_each_flex_line()
{ {
// If the flex container is single-line and has a definite cross size, the cross size of the flex line is the flex containers inner cross size. // If the flex container is single-line and has a definite cross size, the cross size of the flex line is the flex containers inner cross size.
if (is_single_line() && has_definite_cross_size(flex_container())) { if (is_single_line() && has_definite_cross_size(m_flex_container_state)) {
m_flex_lines[0].cross_size = inner_cross_size(flex_container()); m_flex_lines[0].cross_size = inner_cross_size(m_flex_container_state);
return; return;
} }
@ -1207,30 +1202,30 @@ void FlexFormattingContext::distribute_any_remaining_free_space()
case CSS::JustifyContent::Normal: case CSS::JustifyContent::Normal:
case CSS::JustifyContent::FlexStart: case CSS::JustifyContent::FlexStart:
if (is_direction_reverse()) { if (is_direction_reverse()) {
initial_offset = inner_main_size(flex_container()); initial_offset = inner_main_size(m_flex_container_state);
} else { } else {
initial_offset = 0; initial_offset = 0;
} }
break; break;
case CSS::JustifyContent::End: case CSS::JustifyContent::End:
initial_offset = inner_main_size(flex_container()); initial_offset = inner_main_size(m_flex_container_state);
break; break;
case CSS::JustifyContent::FlexEnd: case CSS::JustifyContent::FlexEnd:
if (is_direction_reverse()) { if (is_direction_reverse()) {
initial_offset = 0; initial_offset = 0;
} else { } else {
initial_offset = inner_main_size(flex_container()); initial_offset = inner_main_size(m_flex_container_state);
} }
break; break;
case CSS::JustifyContent::Center: case CSS::JustifyContent::Center:
initial_offset = (inner_main_size(flex_container()) - used_main_space) / 2; initial_offset = (inner_main_size(m_flex_container_state) - used_main_space) / 2;
if (is_direction_reverse()) { if (is_direction_reverse()) {
initial_offset = inner_main_size(flex_container()) - initial_offset; initial_offset = inner_main_size(m_flex_container_state) - initial_offset;
} }
break; break;
case CSS::JustifyContent::SpaceBetween: case CSS::JustifyContent::SpaceBetween:
if (is_direction_reverse()) { if (is_direction_reverse()) {
initial_offset = inner_main_size(flex_container()); initial_offset = inner_main_size(m_flex_container_state);
} else { } else {
initial_offset = 0; initial_offset = 0;
} }
@ -1241,7 +1236,7 @@ void FlexFormattingContext::distribute_any_remaining_free_space()
if (flex_line.remaining_free_space.has_value()) if (flex_line.remaining_free_space.has_value())
space_between_items = flex_line.remaining_free_space.value() / number_of_items; space_between_items = flex_line.remaining_free_space.value() / number_of_items;
if (is_direction_reverse()) { if (is_direction_reverse()) {
initial_offset = inner_main_size(flex_container()) - space_between_items / 2; initial_offset = inner_main_size(m_flex_container_state) - space_between_items / 2;
} else { } else {
initial_offset = space_between_items / 2; initial_offset = space_between_items / 2;
} }
@ -1250,7 +1245,7 @@ void FlexFormattingContext::distribute_any_remaining_free_space()
if (flex_line.remaining_free_space.has_value()) if (flex_line.remaining_free_space.has_value())
space_between_items = flex_line.remaining_free_space.value() / (number_of_items + 1); space_between_items = flex_line.remaining_free_space.value() / (number_of_items + 1);
if (is_direction_reverse()) { if (is_direction_reverse()) {
initial_offset = inner_main_size(flex_container()) - space_between_items; initial_offset = inner_main_size(m_flex_container_state) - space_between_items;
} else { } else {
initial_offset = space_between_items; initial_offset = space_between_items;
} }
@ -1411,9 +1406,9 @@ void FlexFormattingContext::align_all_flex_items_along_the_cross_axis()
void FlexFormattingContext::determine_flex_container_used_cross_size() void FlexFormattingContext::determine_flex_container_used_cross_size()
{ {
CSSPixels cross_size = 0; CSSPixels cross_size = 0;
if (has_definite_cross_size(flex_container())) { if (has_definite_cross_size(m_flex_container_state)) {
// Flex container has definite cross size: easy-peasy. // Flex container has definite cross size: easy-peasy.
cross_size = inner_cross_size(flex_container()); cross_size = inner_cross_size(m_flex_container_state);
} else { } else {
// Flex container has indefinite cross size. // Flex container has indefinite cross size.
auto cross_size_value = is_row_layout() ? flex_container().computed_values().height() : flex_container().computed_values().width(); auto cross_size_value = is_row_layout() ? flex_container().computed_values().height() : flex_container().computed_values().width();
@ -1430,7 +1425,7 @@ void FlexFormattingContext::determine_flex_container_used_cross_size()
} }
} else { } else {
// Otherwise, resolve the indefinite size at this point. // Otherwise, resolve the indefinite size at this point.
cross_size = cross_size_value.to_px(flex_container(), inner_cross_size(*flex_container().containing_block())); cross_size = cross_size_value.to_px(flex_container(), inner_cross_size(m_state.get(*flex_container().containing_block())));
} }
} }
@ -1454,7 +1449,7 @@ void FlexFormattingContext::align_all_flex_lines()
// FIXME: Support reverse // FIXME: Support reverse
CSSPixels cross_size_of_flex_container = inner_cross_size(flex_container()); CSSPixels cross_size_of_flex_container = inner_cross_size(m_flex_container_state);
if (is_single_line()) { if (is_single_line()) {
// For single-line flex containers, we only need to center the line along the cross axis. // For single-line flex containers, we only need to center the line along the cross axis.
@ -1546,22 +1541,21 @@ void FlexFormattingContext::copy_dimensions_from_flex_items_to_boxes()
{ {
for (auto& item : m_flex_items) { for (auto& item : m_flex_items) {
auto const& box = item.box; auto const& box = item.box;
auto& box_state = m_state.get_mutable(box);
box_state.padding_left = box->computed_values().padding().left().to_px(box, m_flex_container_state.content_width()); item.used_values.padding_left = box->computed_values().padding().left().to_px(box, m_flex_container_state.content_width());
box_state.padding_right = box->computed_values().padding().right().to_px(box, m_flex_container_state.content_width()); item.used_values.padding_right = box->computed_values().padding().right().to_px(box, m_flex_container_state.content_width());
box_state.padding_top = box->computed_values().padding().top().to_px(box, m_flex_container_state.content_width()); item.used_values.padding_top = box->computed_values().padding().top().to_px(box, m_flex_container_state.content_width());
box_state.padding_bottom = box->computed_values().padding().bottom().to_px(box, m_flex_container_state.content_width()); item.used_values.padding_bottom = box->computed_values().padding().bottom().to_px(box, m_flex_container_state.content_width());
box_state.margin_left = box->computed_values().margin().left().to_px(box, m_flex_container_state.content_width()); item.used_values.margin_left = box->computed_values().margin().left().to_px(box, m_flex_container_state.content_width());
box_state.margin_right = box->computed_values().margin().right().to_px(box, m_flex_container_state.content_width()); item.used_values.margin_right = box->computed_values().margin().right().to_px(box, m_flex_container_state.content_width());
box_state.margin_top = box->computed_values().margin().top().to_px(box, m_flex_container_state.content_width()); item.used_values.margin_top = box->computed_values().margin().top().to_px(box, m_flex_container_state.content_width());
box_state.margin_bottom = box->computed_values().margin().bottom().to_px(box, m_flex_container_state.content_width()); item.used_values.margin_bottom = box->computed_values().margin().bottom().to_px(box, m_flex_container_state.content_width());
box_state.border_left = box->computed_values().border_left().width; item.used_values.border_left = box->computed_values().border_left().width;
box_state.border_right = box->computed_values().border_right().width; item.used_values.border_right = box->computed_values().border_right().width;
box_state.border_top = box->computed_values().border_top().width; item.used_values.border_top = box->computed_values().border_top().width;
box_state.border_bottom = box->computed_values().border_bottom().width; item.used_values.border_bottom = box->computed_values().border_bottom().width;
set_main_size(box, item.main_size.value()); set_main_size(box, item.main_size.value());
set_cross_size(box, item.cross_size.value()); set_cross_size(box, item.cross_size.value());
@ -1912,7 +1906,7 @@ CSSPixels FlexFormattingContext::calculate_min_content_main_size(FlexItem const&
if (is_row_layout()) { if (is_row_layout()) {
return calculate_min_content_width(item.box); return calculate_min_content_width(item.box);
} }
auto available_space = m_state.get(item.box).available_inner_space_or_constraints_from(m_available_space_for_items->space); auto available_space = item.used_values.available_inner_space_or_constraints_from(m_available_space_for_items->space);
if (available_space.width.is_indefinite()) { if (available_space.width.is_indefinite()) {
available_space.width = AvailableSize::make_definite(calculate_width_to_use_when_determining_intrinsic_height_of_item(item)); available_space.width = AvailableSize::make_definite(calculate_width_to_use_when_determining_intrinsic_height_of_item(item));
} }
@ -1924,7 +1918,7 @@ CSSPixels FlexFormattingContext::calculate_max_content_main_size(FlexItem const&
if (is_row_layout()) { if (is_row_layout()) {
return calculate_max_content_width(item.box); return calculate_max_content_width(item.box);
} }
auto available_space = m_state.get(item.box).available_inner_space_or_constraints_from(m_available_space_for_items->space); auto available_space = item.used_values.available_inner_space_or_constraints_from(m_available_space_for_items->space);
if (available_space.width.is_indefinite()) { if (available_space.width.is_indefinite()) {
available_space.width = AvailableSize::make_definite(calculate_width_to_use_when_determining_intrinsic_height_of_item(item)); available_space.width = AvailableSize::make_definite(calculate_width_to_use_when_determining_intrinsic_height_of_item(item));
} }
@ -1948,7 +1942,7 @@ CSSPixels FlexFormattingContext::calculate_fit_content_cross_size(FlexItem const
CSSPixels FlexFormattingContext::calculate_min_content_cross_size(FlexItem const& item) const CSSPixels FlexFormattingContext::calculate_min_content_cross_size(FlexItem const& item) const
{ {
if (is_row_layout()) { if (is_row_layout()) {
auto available_space = m_state.get(item.box).available_inner_space_or_constraints_from(m_available_space_for_items->space); auto available_space = item.used_values.available_inner_space_or_constraints_from(m_available_space_for_items->space);
if (available_space.width.is_indefinite()) { if (available_space.width.is_indefinite()) {
available_space.width = AvailableSize::make_definite(calculate_width_to_use_when_determining_intrinsic_height_of_item(item)); available_space.width = AvailableSize::make_definite(calculate_width_to_use_when_determining_intrinsic_height_of_item(item));
} }
@ -1960,7 +1954,7 @@ CSSPixels FlexFormattingContext::calculate_min_content_cross_size(FlexItem const
CSSPixels FlexFormattingContext::calculate_max_content_cross_size(FlexItem const& item) const CSSPixels FlexFormattingContext::calculate_max_content_cross_size(FlexItem const& item) const
{ {
if (is_row_layout()) { if (is_row_layout()) {
auto available_space = m_state.get(item.box).available_inner_space_or_constraints_from(m_available_space_for_items->space); auto available_space = item.used_values.available_inner_space_or_constraints_from(m_available_space_for_items->space);
if (available_space.width.is_indefinite()) { if (available_space.width.is_indefinite()) {
available_space.width = AvailableSize::make_definite(calculate_width_to_use_when_determining_intrinsic_height_of_item(item)); available_space.width = AvailableSize::make_definite(calculate_width_to_use_when_determining_intrinsic_height_of_item(item));
} }
@ -2044,7 +2038,7 @@ void FlexFormattingContext::resolve_cross_axis_auto_margins()
void FlexFormattingContext::handle_align_content_stretch() void FlexFormattingContext::handle_align_content_stretch()
{ {
// If the flex container has a definite cross size, // If the flex container has a definite cross size,
if (!has_definite_cross_size(flex_container())) if (!has_definite_cross_size(m_flex_container_state))
return; return;
// align-content is stretch, // align-content is stretch,
@ -2059,12 +2053,12 @@ void FlexFormattingContext::handle_align_content_stretch()
// CSS-FLEXBOX-2: Account for gap between flex lines. // CSS-FLEXBOX-2: Account for gap between flex lines.
sum_of_flex_line_cross_sizes += cross_gap() * (m_flex_lines.size() - 1); sum_of_flex_line_cross_sizes += cross_gap() * (m_flex_lines.size() - 1);
if (sum_of_flex_line_cross_sizes >= inner_cross_size(flex_container())) if (sum_of_flex_line_cross_sizes >= inner_cross_size(m_flex_container_state))
return; return;
// increase the cross size of each flex line by equal amounts // increase the cross size of each flex line by equal amounts
// such that the sum of their cross sizes exactly equals the flex containers inner cross size. // such that the sum of their cross sizes exactly equals the flex containers inner cross size.
CSSPixels remainder = inner_cross_size(flex_container()) - sum_of_flex_line_cross_sizes; CSSPixels remainder = inner_cross_size(m_flex_container_state) - sum_of_flex_line_cross_sizes;
CSSPixels extra_per_line = remainder / m_flex_lines.size(); CSSPixels extra_per_line = remainder / m_flex_lines.size();
for (auto& line : m_flex_lines) for (auto& line : m_flex_lines)
@ -2077,7 +2071,7 @@ CSSPixelPoint FlexFormattingContext::calculate_static_position(Box const& box) c
// The cross-axis edges of the static-position rectangle of an absolutely-positioned child // The cross-axis edges of the static-position rectangle of an absolutely-positioned child
// of a flex container are the content edges of the flex container. // of a flex container are the content edges of the flex container.
CSSPixels cross_offset = 0; CSSPixels cross_offset = 0;
CSSPixels half_line_size = inner_cross_size(flex_container()) / 2; CSSPixels half_line_size = inner_cross_size(m_flex_container_state) / 2;
auto const& box_state = m_state.get(box); auto const& box_state = m_state.get(box);
CSSPixels cross_margin_before = is_row_layout() ? box_state.margin_top : box_state.margin_left; CSSPixels cross_margin_before = is_row_layout() ? box_state.margin_top : box_state.margin_left;
@ -2102,16 +2096,16 @@ CSSPixelPoint FlexFormattingContext::calculate_static_position(Box const& box) c
case CSS::AlignItems::End: case CSS::AlignItems::End:
case CSS::AlignItems::SelfEnd: case CSS::AlignItems::SelfEnd:
case CSS::AlignItems::FlexEnd: case CSS::AlignItems::FlexEnd:
cross_offset = half_line_size - inner_cross_size(box) - cross_margin_after - cross_border_after - cross_padding_after; cross_offset = half_line_size - inner_cross_size(box_state) - cross_margin_after - cross_border_after - cross_padding_after;
break; break;
case CSS::AlignItems::Center: case CSS::AlignItems::Center:
cross_offset = -((inner_cross_size(box) + cross_border_before + cross_border_after) / 2); cross_offset = -((inner_cross_size(box_state) + cross_border_before + cross_border_after) / 2);
break; break;
default: default:
break; break;
} }
cross_offset += inner_cross_size(flex_container()) / 2; cross_offset += inner_cross_size(m_flex_container_state) / 2;
// The main-axis edges of the static-position rectangle are where the margin edges of the child // The main-axis edges of the static-position rectangle are where the margin edges of the child
// would be positioned if it were the sole flex item in the flex container, // would be positioned if it were the sole flex item in the flex container,
@ -2140,12 +2134,12 @@ CSSPixelPoint FlexFormattingContext::calculate_static_position(Box const& box) c
case CSS::JustifyContent::SpaceAround: case CSS::JustifyContent::SpaceAround:
case CSS::JustifyContent::SpaceEvenly: case CSS::JustifyContent::SpaceEvenly:
pack_from_end = false; pack_from_end = false;
main_offset = (inner_main_size(flex_container()) - inner_main_size(box) - main_border_before - main_border_after) / 2; main_offset = (inner_main_size(m_flex_container_state) - inner_main_size(box_state) - main_border_before - main_border_after) / 2;
break; break;
} }
if (pack_from_end) if (pack_from_end)
main_offset += inner_main_size(flex_container()) - inner_main_size(box) - main_border_before - main_border_after; main_offset += inner_main_size(m_flex_container_state) - inner_main_size(box_state) - main_border_before - main_border_after;
auto static_position_offset = is_row_layout() ? CSSPixelPoint { main_offset, cross_offset } : CSSPixelPoint { cross_offset, main_offset }; auto static_position_offset = is_row_layout() ? CSSPixelPoint { main_offset, cross_offset } : CSSPixelPoint { cross_offset, main_offset };
@ -2180,14 +2174,14 @@ CSSPixels FlexFormattingContext::main_gap() const
{ {
auto const& computed_values = flex_container().computed_values(); auto const& computed_values = flex_container().computed_values();
auto gap = is_row_layout() ? computed_values.column_gap() : computed_values.row_gap(); auto gap = is_row_layout() ? computed_values.column_gap() : computed_values.row_gap();
return gap.to_px(flex_container(), inner_main_size(flex_container())); return gap.to_px(flex_container(), inner_main_size(m_flex_container_state));
} }
CSSPixels FlexFormattingContext::cross_gap() const CSSPixels FlexFormattingContext::cross_gap() const
{ {
auto const& computed_values = flex_container().computed_values(); auto const& computed_values = flex_container().computed_values();
auto gap = is_row_layout() ? computed_values.row_gap() : computed_values.column_gap(); auto gap = is_row_layout() ? computed_values.row_gap() : computed_values.column_gap();
return gap.to_px(flex_container(), inner_cross_size(flex_container())); return gap.to_px(flex_container(), inner_cross_size(m_flex_container_state));
} }
} }

View file

@ -53,6 +53,7 @@ private:
struct FlexItem { struct FlexItem {
JS::NonnullGCPtr<Box> box; JS::NonnullGCPtr<Box> box;
LayoutState::UsedValues& used_values;
Optional<CSS::FlexBasis> used_flex_basis {}; Optional<CSS::FlexBasis> used_flex_basis {};
bool used_flex_basis_is_definite { false }; bool used_flex_basis_is_definite { false };
CSSPixels flex_base_size { 0 }; CSSPixels flex_base_size { 0 };
@ -117,10 +118,15 @@ private:
CSSPixels main_gap() const; CSSPixels main_gap() const;
CSSPixels cross_gap() const; CSSPixels cross_gap() const;
bool has_definite_main_size(Box const&) const; [[nodiscard]] bool has_definite_main_size(LayoutState::UsedValues const&) const;
bool has_definite_cross_size(Box const&) const; [[nodiscard]] bool has_definite_cross_size(LayoutState::UsedValues const&) const;
CSSPixels inner_main_size(Box const&) const; [[nodiscard]] bool has_definite_main_size(FlexItem const& item) const { return has_definite_main_size(item.used_values); }
CSSPixels inner_cross_size(Box const&) const; [[nodiscard]] bool has_definite_cross_size(FlexItem const& item) const { return has_definite_cross_size(item.used_values); }
[[nodiscard]] CSSPixels inner_main_size(LayoutState::UsedValues const&) const;
[[nodiscard]] CSSPixels inner_cross_size(LayoutState::UsedValues const&) const;
[[nodiscard]] CSSPixels inner_main_size(FlexItem const& item) const { return inner_main_size(item.used_values); }
[[nodiscard]] CSSPixels inner_cross_size(FlexItem const& item) const { return inner_cross_size(item.used_values); }
bool has_main_min_size(Box const&) const; bool has_main_min_size(Box const&) const;
bool has_cross_min_size(Box const&) const; bool has_cross_min_size(Box const&) const;
CSSPixels specified_main_max_size(Box const&) const; CSSPixels specified_main_max_size(Box const&) const;