summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2022-10-24 23:17:36 +0200
committerAndreas Kling <kling@serenityos.org>2022-10-27 13:02:27 +0200
commit3e1029304795c435250722d975f672e31869c133 (patch)
treeef5df929443bc5a0e887b9e5be2a929208263d91 /Userland/Libraries
parentbd592480e467c9f06cc4abc4297af8a5ad977b95 (diff)
downloadserenity-3e1029304795c435250722d975f672e31869c133.zip
LibWeb: Implement static position for abspos children of flex container
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp99
-rw-r--r--Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h4
2 files changed, 97 insertions, 6 deletions
diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp
index bd577f727d..44d7ce7688 100644
--- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp
+++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp
@@ -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 itemโ€™s 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;
+}
+
}
diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h
index 0f54a66e9f..0fc842817e 100644
--- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h
+++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h
@@ -27,6 +27,8 @@ public:
virtual void determine_width_of_child(Box const&, AvailableSpace const&) override;
virtual void determine_height_of_child(Box const&, AvailableSpace const&) override;
+ virtual Gfx::FloatPoint calculate_static_position(Box const&) const override;
+
private:
void dump_items() const;
@@ -144,7 +146,7 @@ private:
void handle_align_content_stretch();
- CSS::AlignItems alignment_for_item(FlexItem const&) const;
+ CSS::AlignItems alignment_for_item(Box const&) const;
void determine_used_cross_size_of_each_flex_item();