1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-01 10:18:13 +00:00

LibWeb: Implement static position for abspos children of flex container

This commit is contained in:
Andreas Kling 2022-10-24 23:17:36 +02:00
parent bd592480e4
commit 3e10293047
2 changed files with 97 additions and 6 deletions

View file

@ -1138,7 +1138,7 @@ void FlexFormattingContext::determine_used_cross_size_of_each_flex_item()
// If a flex item has align-self: stretch, its computed cross size property is auto,
// and neither of its cross-axis margins are auto, the used outer cross size is the used cross size of its flex line,
// clamped according to the items used min and max cross sizes.
if (alignment_for_item(*flex_item) == CSS::AlignItems::Stretch
if (alignment_for_item(flex_item->box) == CSS::AlignItems::Stretch
&& is_cross_auto(flex_item->box)
&& !flex_item->margins.cross_before_is_auto
&& !flex_item->margins.cross_after_is_auto) {
@ -1290,9 +1290,9 @@ void FlexFormattingContext::dump_items() const
}
}
CSS::AlignItems FlexFormattingContext::alignment_for_item(FlexItem const& item) const
CSS::AlignItems FlexFormattingContext::alignment_for_item(Box const& box) const
{
switch (item.box.computed_values().align_self()) {
switch (box.computed_values().align_self()) {
case CSS::AlignSelf::Auto:
return flex_container().computed_values().align_items();
case CSS::AlignSelf::Normal:
@ -1326,7 +1326,7 @@ void FlexFormattingContext::align_all_flex_items_along_the_cross_axis()
for (auto& flex_line : m_flex_lines) {
for (auto* flex_item : flex_line.items) {
float half_line_size = flex_line.cross_size / 2.0f;
switch (alignment_for_item(*flex_item)) {
switch (alignment_for_item(flex_item->box)) {
case CSS::AlignItems::Baseline:
// FIXME: Implement this
// Fallthrough
@ -1797,7 +1797,7 @@ float FlexFormattingContext::calculate_max_content_cross_size(FlexItem const& it
// https://drafts.csswg.org/css-flexbox-1/#stretched
bool FlexFormattingContext::flex_item_is_stretched(FlexItem const& item) const
{
auto alignment = alignment_for_item(item);
auto alignment = alignment_for_item(item.box);
if (alignment != CSS::AlignItems::Stretch)
return false;
// If the cross size property of the flex item computes to auto, and neither of the cross-axis margins are auto, the flex item is stretched.
@ -1893,4 +1893,93 @@ void FlexFormattingContext::handle_align_content_stretch()
line.cross_size += extra_per_line;
}
// https://drafts.csswg.org/css-flexbox-1/#abspos-items
Gfx::FloatPoint FlexFormattingContext::calculate_static_position(Box const& box) const
{
// 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.
float cross_offset = 0;
float half_line_size = specified_cross_size(flex_container()) / 2;
auto const& box_state = m_state.get(box);
float cross_margin_before = is_row_layout() ? box_state.margin_top : box_state.margin_left;
float cross_margin_after = is_row_layout() ? box_state.margin_bottom : box_state.margin_right;
float cross_border_before = is_row_layout() ? box_state.border_top : box_state.border_left;
float cross_border_after = is_row_layout() ? box_state.border_bottom : box_state.border_right;
float cross_padding_before = is_row_layout() ? box_state.padding_top : box_state.padding_left;
float cross_padding_after = is_row_layout() ? box_state.padding_bottom : box_state.padding_right;
switch (alignment_for_item(box)) {
case CSS::AlignItems::Baseline:
// FIXME: Implement this
// Fallthrough
case CSS::AlignItems::FlexStart:
case CSS::AlignItems::Stretch:
cross_offset = 0 - half_line_size + cross_margin_before + cross_border_before + cross_padding_before;
break;
case CSS::AlignItems::FlexEnd:
cross_offset = half_line_size - specified_cross_size(box) - cross_margin_after - cross_border_after - cross_padding_after;
break;
case CSS::AlignItems::Center:
cross_offset = 0 - (specified_cross_size(box) / 2.0f);
break;
default:
break;
}
cross_offset += specified_cross_size(flex_container()) / 2.0f;
// 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,
// assuming both the child and the flex container were fixed-size boxes of their used size.
// (For this purpose, auto margins are treated as zero.
bool pack_from_end = true;
float main_offset = 0;
switch (flex_container().computed_values().justify_content()) {
case CSS::JustifyContent::FlexStart:
if (is_direction_reverse()) {
pack_from_end = false;
main_offset = specified_main_size(flex_container());
} else {
main_offset = 0;
}
break;
case CSS::JustifyContent::FlexEnd:
if (is_direction_reverse()) {
main_offset = 0;
} else {
pack_from_end = false;
main_offset = specified_main_size(flex_container());
}
break;
case CSS::JustifyContent::SpaceBetween:
main_offset = 0;
break;
case CSS::JustifyContent::Center:
case CSS::JustifyContent::SpaceAround:
main_offset = specified_main_size(flex_container()) / 2.0f - specified_main_size(box) / 2.0f;
break;
}
// NOTE: Next, we add the flex container's padding since abspos boxes are placed relative to the padding edge
// of their abspos containing block.
if (pack_from_end) {
main_offset += is_row_layout() ? m_flex_container_state.padding_left : m_flex_container_state.padding_top;
} else {
main_offset += is_row_layout() ? m_flex_container_state.padding_right : m_flex_container_state.padding_bottom;
}
if (!pack_from_end)
main_offset += specified_main_size(flex_container()) - specified_main_size(box);
auto static_position_offset = is_row_layout() ? Gfx::FloatPoint { main_offset, cross_offset } : Gfx::FloatPoint { cross_offset, main_offset };
auto absolute_position_of_flex_container = absolute_content_rect(flex_container(), m_state).location();
auto absolute_position_of_abspos_containing_block = absolute_content_rect(*box.containing_block(), m_state).location();
auto diff = absolute_position_of_flex_container - absolute_position_of_abspos_containing_block;
return static_position_offset + diff;
}
}