From 6354f950fd2036e63b25f945861dc95dd5b4f1b6 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Wed, 9 Aug 2023 15:04:48 +0200 Subject: [PATCH] LibWeb: Support "order" property for items in GridFormattingContext Closes https://github.com/SerenityOS/serenity/issues/20434 --- Tests/LibWeb/Layout/expected/grid/order.txt | 41 ++++++++ Tests/LibWeb/Layout/input/grid/order.html | 33 +++++++ .../LibWeb/Layout/GridFormattingContext.cpp | 93 +++++++++++-------- 3 files changed, 129 insertions(+), 38 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/grid/order.txt create mode 100644 Tests/LibWeb/Layout/input/grid/order.html diff --git a/Tests/LibWeb/Layout/expected/grid/order.txt b/Tests/LibWeb/Layout/expected/grid/order.txt new file mode 100644 index 0000000000..fa3e0afd6e --- /dev/null +++ b/Tests/LibWeb/Layout/expected/grid/order.txt @@ -0,0 +1,41 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (1,1) content-size 798x600 [BFC] children: not-inline + BlockContainer at (10,10) content-size 780x104 children: not-inline + Box at (11,11) content-size 778x102 [GFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (271.328125,12) content-size 100x100 [BFC] children: inline + line 0 width: 7.9375, height: 21.84375, bottom: 21.84375, baseline: 16.921875 + frag 0 from TextNode start: 0, length: 1, rect: [271.328125,12 7.9375x21.84375] + "1" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (530.65625,12) content-size 100x100 [BFC] children: inline + line 0 width: 11.015625, height: 21.84375, bottom: 21.84375, baseline: 16.921875 + frag 0 from TextNode start: 0, length: 1, rect: [530.65625,12 11.015625x21.84375] + "2" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (12,12) content-size 100x100 [BFC] children: inline + line 0 width: 11.375, height: 21.84375, bottom: 21.84375, baseline: 16.921875 + frag 0 from TextNode start: 0, length: 1, rect: [12,12 11.375x21.84375] + "3" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (10,114) content-size 780x0 children: inline + TextNode <#text> + +PaintableWithLines (Viewport<#document>) [0,0 800x600] overflow: [0,0 800x602] + PaintableWithLines (BlockContainer) [0,0 800x602] + PaintableWithLines (BlockContainer) [9,9 782x106] + PaintableBox (Box
.grid-container) [10,10 780x104] + PaintableWithLines (BlockContainer
.grid-item.item-1) [270.328125,11 102x102] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item.item-2) [529.65625,11 102x102] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item.item-3) [11,11 102x102] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [10,114 780x0] diff --git a/Tests/LibWeb/Layout/input/grid/order.html b/Tests/LibWeb/Layout/input/grid/order.html new file mode 100644 index 0000000000..42a6e8ef23 --- /dev/null +++ b/Tests/LibWeb/Layout/input/grid/order.html @@ -0,0 +1,33 @@ + +
+
1
+
2
+
3
+
diff --git a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp index 3a30c0cbc5..997b3d0e5d 100644 --- a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp @@ -1314,7 +1314,7 @@ void GridFormattingContext::place_grid_items(AvailableSpace const& available_spa // flex items), which are then assigned to predefined areas in the grid. They can be explicitly // placed using coordinates through the grid-placement properties or implicitly placed into // empty areas using auto-placement. - Vector> boxes_to_place; + HashMap>> order_item_bucket; grid_container().for_each_child_of_type([&](Box& child_box) { if (can_skip_is_anonymous_text_run(child_box)) return IterationDecision::Continue; @@ -1322,7 +1322,9 @@ void GridFormattingContext::place_grid_items(AvailableSpace const& available_spa if (child_box.is_out_of_flow(*this)) return IterationDecision::Continue; - boxes_to_place.append(child_box); + auto& order_bucket = order_item_bucket.ensure(child_box.computed_values().order()); + order_bucket.append(child_box); + return IterationDecision::Continue; }); @@ -1333,28 +1335,37 @@ void GridFormattingContext::place_grid_items(AvailableSpace const& available_spa // https://drafts.csswg.org/css-grid/#auto-placement-algo // 8.5. Grid Item Placement Algorithm + auto keys = order_item_bucket.keys(); + quick_sort(keys, [](auto& a, auto& b) { return a < b; }); + // FIXME: 0. Generate anonymous grid items // 1. Position anything that's not auto-positioned. - for (size_t i = 0; i < boxes_to_place.size(); i++) { - auto const& child_box = boxes_to_place[i]; - if (is_auto_positioned_row(child_box->computed_values().grid_row_start(), child_box->computed_values().grid_row_end()) - || is_auto_positioned_column(child_box->computed_values().grid_column_start(), child_box->computed_values().grid_column_end())) - continue; - place_item_with_row_and_column_position(child_box); - boxes_to_place.remove(i); - i--; + for (auto key : keys) { + auto& boxes_to_place = order_item_bucket.get(key).value(); + for (size_t i = 0; i < boxes_to_place.size(); i++) { + auto const& child_box = boxes_to_place[i]; + if (is_auto_positioned_row(child_box->computed_values().grid_row_start(), child_box->computed_values().grid_row_end()) + || is_auto_positioned_column(child_box->computed_values().grid_column_start(), child_box->computed_values().grid_column_end())) + continue; + place_item_with_row_and_column_position(child_box); + boxes_to_place.remove(i); + i--; + } } // 2. Process the items locked to a given row. // FIXME: Do "dense" packing - for (size_t i = 0; i < boxes_to_place.size(); i++) { - auto const& child_box = boxes_to_place[i]; - if (is_auto_positioned_row(child_box->computed_values().grid_row_start(), child_box->computed_values().grid_row_end())) - continue; - place_item_with_row_position(child_box); - boxes_to_place.remove(i); - i--; + for (auto key : keys) { + auto& boxes_to_place = order_item_bucket.get(key).value(); + for (size_t i = 0; i < boxes_to_place.size(); i++) { + auto const& child_box = boxes_to_place[i]; + if (is_auto_positioned_row(child_box->computed_values().grid_row_start(), child_box->computed_values().grid_row_end())) + continue; + place_item_with_row_position(child_box); + boxes_to_place.remove(i); + i--; + } } // 3. Determine the columns in the implicit grid. @@ -1373,15 +1384,18 @@ void GridFormattingContext::place_grid_items(AvailableSpace const& available_spa // 3.3. If the largest column span among all the items without a definite column position is larger // than the width of the implicit grid, add columns to the end of the implicit grid to accommodate // that column span. - for (auto const& child_box : boxes_to_place) { - int column_span = 1; - if (child_box->computed_values().grid_column_start().is_span()) - column_span = child_box->computed_values().grid_column_start().raw_value(); - else if (child_box->computed_values().grid_column_end().is_span()) - column_span = child_box->computed_values().grid_column_end().raw_value(); + for (auto key : keys) { + auto& boxes_to_place = order_item_bucket.get(key).value(); + for (auto const& child_box : boxes_to_place) { + int column_span = 1; + if (child_box->computed_values().grid_column_start().is_span()) + column_span = child_box->computed_values().grid_column_start().raw_value(); + else if (child_box->computed_values().grid_column_end().is_span()) + column_span = child_box->computed_values().grid_column_end().raw_value(); - if (column_span - 1 > m_occupation_grid.max_column_index()) - m_occupation_grid.set_max_column_index(column_span - 1); + if (column_span - 1 > m_occupation_grid.max_column_index()) + m_occupation_grid.set_max_column_index(column_span - 1); + } } // 4. Position the remaining grid items. @@ -1389,23 +1403,26 @@ void GridFormattingContext::place_grid_items(AvailableSpace const& available_spa // order: auto auto_placement_cursor_x = 0; auto auto_placement_cursor_y = 0; - for (size_t i = 0; i < boxes_to_place.size(); i++) { - auto const& child_box = boxes_to_place[i]; - // 4.1. For sparse packing: - // FIXME: no distinction made. See #4.2 + for (auto key : keys) { + auto& boxes_to_place = order_item_bucket.get(key).value(); + for (size_t i = 0; i < boxes_to_place.size(); i++) { + auto const& child_box = boxes_to_place[i]; + // 4.1. For sparse packing: + // FIXME: no distinction made. See #4.2 - // 4.1.1. If the item has a definite column position: - if (!is_auto_positioned_column(child_box->computed_values().grid_column_start(), child_box->computed_values().grid_column_end())) - place_item_with_column_position(child_box, auto_placement_cursor_x, auto_placement_cursor_y); + // 4.1.1. If the item has a definite column position: + if (!is_auto_positioned_column(child_box->computed_values().grid_column_start(), child_box->computed_values().grid_column_end())) + place_item_with_column_position(child_box, auto_placement_cursor_x, auto_placement_cursor_y); - // 4.1.2. If the item has an automatic grid position in both axes: - else - place_item_with_no_declared_position(child_box, auto_placement_cursor_x, auto_placement_cursor_y); + // 4.1.2. If the item has an automatic grid position in both axes: + else + place_item_with_no_declared_position(child_box, auto_placement_cursor_x, auto_placement_cursor_y); - boxes_to_place.remove(i); - i--; + boxes_to_place.remove(i); + i--; - // FIXME: 4.2. For dense packing: + // FIXME: 4.2. For dense packing: + } } // NOTE: When final implicit grid sizes are known, we can offset their positions so leftmost grid track has 0 index.