From 537256fae2df8df70d0b7df54ee4f3678edb8cf7 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Sun, 28 May 2023 19:31:26 +0300 Subject: [PATCH] LibWeb: Treat unresolvable percentages as auto to resolve sizes in GFC Fixes the bug that currently we always consider tracks with percentage size as ones with "fixed" length even when available size is not definite. With this change tracks with percentage size when available size is not definite will be considered as "intrinsic" sized. --- .../grid/unresolvable-percentage-track.txt | 10 +++ .../grid/unresolvable-percentage-track.html | 11 +++ .../Libraries/LibWeb/CSS/GridTrackSize.cpp | 27 +++++++ Userland/Libraries/LibWeb/CSS/GridTrackSize.h | 10 ++- .../LibWeb/Layout/GridFormattingContext.cpp | 71 +++++-------------- .../LibWeb/Layout/GridFormattingContext.h | 2 + 6 files changed, 73 insertions(+), 58 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/grid/unresolvable-percentage-track.txt create mode 100644 Tests/LibWeb/Layout/input/grid/unresolvable-percentage-track.html diff --git a/Tests/LibWeb/Layout/expected/grid/unresolvable-percentage-track.txt b/Tests/LibWeb/Layout/expected/grid/unresolvable-percentage-track.txt new file mode 100644 index 0000000000..ba09701e5c --- /dev/null +++ b/Tests/LibWeb/Layout/expected/grid/unresolvable-percentage-track.txt @@ -0,0 +1,10 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x600 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x17.46875 children: not-inline + Box at (8,8) content-size 784x17.46875 flex-container(row) [FFC] children: not-inline + Box at (8,8) content-size 36.84375x17.46875 flex-item [GFC] children: not-inline + BlockContainer
at (8,8) content-size 36.84375x17.46875 [BFC] children: inline + line 0 width: 36.84375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 5, rect: [8,8 36.84375x17.46875] + "hello" + TextNode <#text> diff --git a/Tests/LibWeb/Layout/input/grid/unresolvable-percentage-track.html b/Tests/LibWeb/Layout/input/grid/unresolvable-percentage-track.html new file mode 100644 index 0000000000..d09cd4eaea --- /dev/null +++ b/Tests/LibWeb/Layout/input/grid/unresolvable-percentage-track.html @@ -0,0 +1,11 @@ + +
hello
\ No newline at end of file diff --git a/Userland/Libraries/LibWeb/CSS/GridTrackSize.cpp b/Userland/Libraries/LibWeb/CSS/GridTrackSize.cpp index 7e7356c16b..939d476b95 100644 --- a/Userland/Libraries/LibWeb/CSS/GridTrackSize.cpp +++ b/Userland/Libraries/LibWeb/CSS/GridTrackSize.cpp @@ -36,6 +36,33 @@ GridSize::GridSize() GridSize::~GridSize() = default; +bool GridSize::is_auto(Layout::AvailableSize const& available_size) const +{ + if (m_type == Type::LengthPercentage) { + if (m_length_percentage.is_percentage()) + return !available_size.is_definite(); + return m_length_percentage.is_auto(); + } + + return false; +} + +bool GridSize::is_fixed(Layout::AvailableSize const& available_size) const +{ + if (m_type == Type::LengthPercentage) { + if (m_length_percentage.is_percentage()) + return available_size.is_definite(); + return !m_length_percentage.is_auto(); + } + + return false; +} + +bool GridSize::is_intrinsic(Layout::AvailableSize const& available_size) const +{ + return is_auto(available_size) || is_max_content() || is_min_content(); +} + GridSize GridSize::make_auto() { return GridSize(CSS::Length::make_auto()); diff --git a/Userland/Libraries/LibWeb/CSS/GridTrackSize.h b/Userland/Libraries/LibWeb/CSS/GridTrackSize.h index 19af23c36b..87206ec053 100644 --- a/Userland/Libraries/LibWeb/CSS/GridTrackSize.h +++ b/Userland/Libraries/LibWeb/CSS/GridTrackSize.h @@ -8,6 +8,7 @@ #include #include +#include namespace Web::CSS { @@ -30,8 +31,8 @@ public: Type type() const { return m_type; } - bool is_auto() const { return m_type == Type::LengthPercentage && m_length_percentage.is_auto(); } - bool is_length_percentage() const { return m_type == Type::LengthPercentage; } + bool is_auto(Layout::AvailableSize const&) const; + bool is_fixed(Layout::AvailableSize const&) const; bool is_flexible_length() const { return m_type == Type::FlexibleLength; } bool is_max_content() const { return m_type == Type::MaxContent; } bool is_min_content() const { return m_type == Type::MinContent; } @@ -42,10 +43,7 @@ public: // https://www.w3.org/TR/css-grid-2/#layout-algorithm // An intrinsic sizing function (min-content, max-content, auto, fit-content()). // FIXME: Add missing properties once implemented. - bool is_intrinsic_track_sizing() const - { - return is_auto() || is_max_content() || is_min_content(); - } + bool is_intrinsic(Layout::AvailableSize const&) const; bool is_definite() const { diff --git a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp index 609509a4e6..3bb0ad0b91 100644 --- a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp @@ -630,59 +630,23 @@ void GridFormattingContext::initialize_track_sizes(AvailableSpace const& availab auto& tracks_and_gaps = dimension == GridDimension::Column ? m_grid_columns_and_gaps : m_grid_rows_and_gaps; auto& available_size = dimension == GridDimension::Column ? available_space.width : available_space.height; - // For each track, if the track’s min track sizing function is: for (auto& track : tracks_and_gaps) { if (track.is_gap) continue; - switch (track.min_track_sizing_function.type()) { - // - A fixed sizing function - // Resolve to an absolute length and use that size as the track’s initial base size. - case CSS::GridSize::Type::LengthPercentage: { - if (!track.min_track_sizing_function.is_auto()) { - track.base_size = track.min_track_sizing_function.css_size().to_px(grid_container(), available_size.to_px()); - } - - break; - } - // - An intrinsic sizing function - // Use an initial base size of zero. - case CSS::GridSize::Type::FlexibleLength: - case CSS::GridSize::Type::MaxContent: - case CSS::GridSize::Type::MinContent: { + if (track.min_track_sizing_function.is_fixed(available_size)) { + track.base_size = track.min_track_sizing_function.css_size().to_px(grid_container(), available_size.to_px()); + } else if (track.min_track_sizing_function.is_intrinsic(available_size)) { track.base_size = 0; - break; - } - default: - VERIFY_NOT_REACHED(); } - // For each track, if the track’s max track sizing function is: - switch (track.max_track_sizing_function.type()) { - // - A fixed sizing function - // Resolve to an absolute length and use that size as the track’s initial growth limit. - case CSS::GridSize::Type::LengthPercentage: { - if (!track.max_track_sizing_function.is_auto()) { - track.growth_limit = track.max_track_sizing_function.css_size().to_px(grid_container(), available_size.to_px()); - } else { - track.growth_limit = INFINITY; - } - break; - } - // - A flexible sizing function - // Use an initial growth limit of infinity. - case CSS::GridSize::Type::FlexibleLength: { + if (track.max_track_sizing_function.is_fixed(available_size)) { + track.growth_limit = track.max_track_sizing_function.css_size().to_px(grid_container(), available_size.to_px()); + } else if (track.max_track_sizing_function.is_flexible_length()) { track.growth_limit = INFINITY; - break; - } - // - An intrinsic sizing function - // Use an initial growth limit of infinity. - case CSS::GridSize::Type::MaxContent: - case CSS::GridSize::Type::MinContent: { + } else if (track.max_track_sizing_function.is_intrinsic(available_size)) { track.growth_limit = INFINITY; - break; - } - default: + } else { VERIFY_NOT_REACHED(); } @@ -891,7 +855,7 @@ void GridFormattingContext::increase_sizes_to_accommodate_spanning_items_crossin // function by distributing extra space as needed to accommodate these items’ minimum contributions. Vector intrinsic_minimum_spanned_tracks; for (auto& track : spanned_tracks) { - if (track.min_track_sizing_function.is_intrinsic_track_sizing()) + if (track.min_track_sizing_function.is_intrinsic(available_size)) intrinsic_minimum_spanned_tracks.append(track); } auto item_size_contribution = [&] { @@ -929,7 +893,7 @@ void GridFormattingContext::increase_sizes_to_accommodate_spanning_items_crossin if (available_size.is_max_content()) { Vector max_content_minimum_tracks; for (auto& track : spanned_tracks) { - if (track.min_track_sizing_function.is_auto() || track.min_track_sizing_function.is_max_content()) { + if (track.min_track_sizing_function.is_auto(available_size) || track.min_track_sizing_function.is_max_content()) { max_content_minimum_tracks.append(track); } } @@ -951,7 +915,7 @@ void GridFormattingContext::increase_sizes_to_accommodate_spanning_items_crossin // 5. For intrinsic maximums: Next increase the growth limit of tracks with an intrinsic max track sizing Vector intrinsic_maximum_tracks; for (auto& track : spanned_tracks) { - if (track.max_track_sizing_function.is_intrinsic_track_sizing()) { + if (track.max_track_sizing_function.is_intrinsic(available_size)) { intrinsic_maximum_tracks.append(track); } } @@ -974,7 +938,7 @@ void GridFormattingContext::increase_sizes_to_accommodate_spanning_items_crossin // content contributions. Vector max_content_maximum_tracks; for (auto& track : spanned_tracks) { - if (track.max_track_sizing_function.is_max_content() || track.max_track_sizing_function.is_auto()) { + if (track.max_track_sizing_function.is_max_content() || track.max_track_sizing_function.is_auto(available_size)) { max_content_maximum_tracks.append(track); } } @@ -1183,19 +1147,19 @@ void GridFormattingContext::stretch_auto_tracks(AvailableSpace const& available_ // step instead. CSSPixels used_space = 0; for (auto& track : tracks_and_gaps) { - if (!track.max_track_sizing_function.is_auto()) + if (!track.max_track_sizing_function.is_auto(available_size)) used_space += track.base_size; } CSSPixels remaining_space = available_size.is_definite() ? available_size.to_px() - used_space : 0; auto count_of_auto_max_sizing_tracks = 0; for (auto& track : tracks_and_gaps) { - if (track.max_track_sizing_function.is_auto()) + if (track.max_track_sizing_function.is_auto(available_size)) count_of_auto_max_sizing_tracks++; } for (auto& track : tracks_and_gaps) { - if (track.max_track_sizing_function.is_auto()) + if (track.max_track_sizing_function.is_auto(available_size)) track.base_size = max(track.base_size, remaining_space / count_of_auto_max_sizing_tracks); } } @@ -1424,6 +1388,8 @@ void GridFormattingContext::resolve_grid_item_heights() void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const& available_space) { + m_available_space = available_space; + place_grid_items(available_space); initialize_grid_tracks_for_columns_and_rows(available_space); @@ -1812,7 +1778,8 @@ CSSPixels GridFormattingContext::automatic_minimum_size(GridItem const& item, Gr auto item_track_index = item.raw_position(dimension); // FIXME: Check all tracks spanned by an item - auto item_spans_auto_tracks = tracks[item_track_index].min_track_sizing_function.is_auto(); + AvailableSize const& available_size = dimension == GridDimension::Column ? m_available_space->width : m_available_space->height; + auto item_spans_auto_tracks = tracks[item_track_index].min_track_sizing_function.is_auto(available_size); if (item_spans_auto_tracks && !item.box().is_scroll_container()) { return item.add_border_box_sizes(content_based_minimum_size(item, dimension), dimension, m_state); } diff --git a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h index e9f50326e4..e8d351705a 100644 --- a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h @@ -201,6 +201,8 @@ private: Vector m_grid_items; Vector> m_boxes_to_place; + Optional m_available_space; + void determine_grid_container_height(); void determine_intrinsic_size_of_grid_container(AvailableSpace const& available_space);