diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index db29e53eb1..0aa8e0289e 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -99,6 +99,7 @@ set(SOURCES CSS/StyleValues/FlexStyleValue.cpp CSS/StyleValues/FontStyleValue.cpp CSS/StyleValues/GridAreaShorthandStyleValue.cpp + CSS/StyleValues/GridAutoFlowStyleValue.cpp CSS/StyleValues/GridTemplateAreaStyleValue.cpp CSS/StyleValues/GridTrackPlacementStyleValue.cpp CSS/StyleValues/GridTrackPlacementShorthandStyleValue.cpp diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index d83c1b3f7f..b5707d8c73 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -32,6 +32,11 @@ struct AspectRatio { Optional preferred_ratio; }; +struct GridAutoFlow { + bool row { true }; + bool dense { false }; +}; + class InitialValues { public: static AspectRatio aspect_ratio() { return AspectRatio { true, {} }; } @@ -101,6 +106,7 @@ public: static CSS::GridTrackPlacement grid_column_start() { return CSS::GridTrackPlacement::make_auto(); } static CSS::GridTrackPlacement grid_row_end() { return CSS::GridTrackPlacement::make_auto(); } static CSS::GridTrackPlacement grid_row_start() { return CSS::GridTrackPlacement::make_auto(); } + static CSS::GridAutoFlow grid_auto_flow() { return CSS::GridAutoFlow {}; } static CSS::Size column_gap() { return CSS::Size::make_auto(); } static CSS::Size row_gap() { return CSS::Size::make_auto(); } static CSS::BorderCollapse border_collapse() { return CSS::BorderCollapse::Separate; } @@ -276,6 +282,7 @@ public: Variant const& vertical_align() const { return m_noninherited.vertical_align; } CSS::GridTrackSizeList const& grid_auto_columns() const { return m_noninherited.grid_auto_columns; } CSS::GridTrackSizeList const& grid_auto_rows() const { return m_noninherited.grid_auto_rows; } + CSS::GridAutoFlow const& grid_auto_flow() const { return m_noninherited.grid_auto_flow; } CSS::GridTrackSizeList const& grid_template_columns() const { return m_noninherited.grid_template_columns; } CSS::GridTrackSizeList const& grid_template_rows() const { return m_noninherited.grid_template_rows; } CSS::GridTrackPlacement const& grid_column_end() const { return m_noninherited.grid_column_end; } @@ -436,6 +443,7 @@ protected: CSS::GridTrackSizeList grid_auto_rows; CSS::GridTrackSizeList grid_template_columns; CSS::GridTrackSizeList grid_template_rows; + CSS::GridAutoFlow grid_auto_flow { InitialValues::grid_auto_flow() }; CSS::GridTrackPlacement grid_column_end { InitialValues::grid_column_end() }; CSS::GridTrackPlacement grid_column_start { InitialValues::grid_column_start() }; CSS::GridTrackPlacement grid_row_end { InitialValues::grid_row_end() }; @@ -549,6 +557,7 @@ public: void set_row_gap(CSS::Size const& row_gap) { m_noninherited.row_gap = row_gap; } void set_border_collapse(CSS::BorderCollapse const& border_collapse) { m_inherited.border_collapse = border_collapse; } void set_grid_template_areas(Vector> const& grid_template_areas) { m_noninherited.grid_template_areas = grid_template_areas; } + void set_grid_auto_flow(CSS::GridAutoFlow grid_auto_flow) { m_noninherited.grid_auto_flow = grid_auto_flow; } void set_transition_delay(CSS::Time const& transition_delay) { m_noninherited.transition_delay = transition_delay; } void set_table_layout(CSS::TableLayout value) { m_noninherited.table_layout = value; } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 40e815eac4..e7229084e3 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -5308,6 +5309,57 @@ RefPtr Parser::parse_grid_track_size_list(Vector con return GridTrackSizeListStyleValue::create(CSS::GridTrackSizeList(track_list, line_names_list)); } +// https://www.w3.org/TR/css-grid-1/#grid-auto-flow-property +RefPtr Parser::parse_grid_auto_flow_value(Vector const& component_values) +{ + // [ row | column ] || dense + TokenStream tokens { component_values }; + if (!tokens.has_next_token()) + return nullptr; + + auto parse_axis = [&]() -> Optional { + auto transaction = tokens.begin_transaction(); + auto token = tokens.next_token(); + if (!token.is(Token::Type::Ident)) + return {}; + auto const& ident = token.token().ident(); + if (ident.equals_ignoring_ascii_case("row"sv)) { + transaction.commit(); + return GridAutoFlowStyleValue::Axis::Row; + } else if (ident.equals_ignoring_ascii_case("column"sv)) { + transaction.commit(); + return GridAutoFlowStyleValue::Axis::Column; + } + return {}; + }; + + auto parse_dense = [&]() -> Optional { + auto transaction = tokens.begin_transaction(); + auto token = tokens.next_token(); + if (!token.is(Token::Type::Ident)) + return {}; + auto const& ident = token.token().ident(); + if (ident.equals_ignoring_ascii_case("dense"sv)) { + transaction.commit(); + return GridAutoFlowStyleValue::Dense::Yes; + } + return {}; + }; + + Optional axis; + Optional dense; + if (axis = parse_axis(); axis.has_value()) { + dense = parse_dense(); + } else if (dense = parse_dense(); dense.has_value()) { + axis = parse_axis(); + } + + if (tokens.has_next_token()) + return nullptr; + + return GridAutoFlowStyleValue::create(axis.value_or(GridAutoFlowStyleValue::Axis::Row), dense.value_or(GridAutoFlowStyleValue::Dense::No)); +} + RefPtr Parser::parse_grid_auto_track_sizes(Vector const& component_values) { // https://www.w3.org/TR/css-grid-2/#auto-tracks @@ -5774,6 +5826,10 @@ Parser::ParseErrorOr> Parser::parse_css_value(Property if (auto parsed_value = parse_grid_area_shorthand_value(component_values)) return parsed_value.release_nonnull(); return ParseError::SyntaxError; + case PropertyID::GridAutoFlow: + if (auto parsed_value = parse_grid_auto_flow_value(component_values)) + return parsed_value.release_nonnull(); + return ParseError::SyntaxError; case PropertyID::GridTemplateAreas: if (auto parsed_value = parse_grid_template_areas_value(component_values)) return parsed_value.release_nonnull(); diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index 384f59df18..acaaaf73ed 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -252,6 +252,7 @@ private: RefPtr parse_transform_origin_value(Vector const&); RefPtr parse_grid_track_size_list(Vector const&, bool allow_separate_line_name_blocks = false); RefPtr parse_grid_auto_track_sizes(Vector const&); + [[nodiscard]] RefPtr parse_grid_auto_flow_value(Vector const&); RefPtr parse_grid_track_size_list_shorthand_value(Vector const&); RefPtr parse_grid_track_placement(Vector const&); RefPtr parse_grid_track_placement_shorthand_value(Vector const&); diff --git a/Userland/Libraries/LibWeb/CSS/Properties.json b/Userland/Libraries/LibWeb/CSS/Properties.json index 5a49a07224..866e3185b2 100644 --- a/Userland/Libraries/LibWeb/CSS/Properties.json +++ b/Userland/Libraries/LibWeb/CSS/Properties.json @@ -1129,6 +1129,10 @@ ], "percentages-resolve-to": "length" }, + "grid-auto-flow": { + "inherited": false, + "initial": "row" + }, "grid-auto-rows": { "inherited": false, "initial": "auto", diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index 015cdc7c3f..fd51ae1c5e 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -901,6 +902,15 @@ CSS::GridTrackSizeList StyleProperties::grid_template_rows() const return value->as_grid_track_size_list().grid_track_size_list(); } +CSS::GridAutoFlow StyleProperties::grid_auto_flow() const +{ + auto value = property(CSS::PropertyID::GridAutoFlow); + if (!value->is_grid_auto_flow()) + return CSS::GridAutoFlow {}; + auto& grid_auto_flow_value = value->as_grid_auto_flow(); + return CSS::GridAutoFlow { .row = grid_auto_flow_value.is_row(), .dense = grid_auto_flow_value.is_dense() }; +} + CSS::GridTrackPlacement StyleProperties::grid_column_end() const { auto value = property(CSS::PropertyID::GridColumnEnd); diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index f6f427ff87..2f7102634d 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -104,6 +104,7 @@ public: CSS::GridTrackSizeList grid_auto_rows() const; CSS::GridTrackSizeList grid_template_columns() const; CSS::GridTrackSizeList grid_template_rows() const; + [[nodiscard]] CSS::GridAutoFlow grid_auto_flow() const; CSS::GridTrackPlacement grid_column_end() const; CSS::GridTrackPlacement grid_column_start() const; CSS::GridTrackPlacement grid_row_end() const; diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp index f4f80dccb9..a9a6e24496 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -224,6 +225,12 @@ GridAreaShorthandStyleValue const& StyleValue::as_grid_area_shorthand() const return static_cast(*this); } +GridAutoFlowStyleValue const& StyleValue::as_grid_auto_flow() const +{ + VERIFY(is_grid_auto_flow()); + return static_cast(*this); +} + GridTemplateAreaStyleValue const& StyleValue::as_grid_template_area() const { VERIFY(is_grid_template_area()); diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index c921e8d1d2..957e37aeb2 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -109,6 +109,7 @@ public: Font, Frequency, GridAreaShorthand, + GridAutoFlow, GridTemplateArea, GridTrackPlacement, GridTrackPlacementShorthand, @@ -175,6 +176,7 @@ public: bool is_grid_track_placement_shorthand() const { return type() == Type::GridTrackPlacementShorthand; } bool is_grid_track_size_list() const { return type() == Type::GridTrackSizeList; } bool is_grid_track_size_list_shorthand() const { return type() == Type::GridTrackSizeListShorthand; } + bool is_grid_auto_flow() const { return type() == Type::GridAutoFlow; } bool is_identifier() const { return type() == Type::Identifier; } bool is_image() const { return type() == Type::Image; } bool is_inherit() const { return type() == Type::Inherit; } @@ -235,6 +237,7 @@ public: GridTrackPlacementStyleValue const& as_grid_track_placement() const; GridTrackSizeListShorthandStyleValue const& as_grid_track_size_list_shorthand() const; GridTrackSizeListStyleValue const& as_grid_track_size_list() const; + GridAutoFlowStyleValue const& as_grid_auto_flow() const; IdentifierStyleValue const& as_identifier() const; ImageStyleValue const& as_image() const; InheritStyleValue const& as_inherit() const; @@ -291,6 +294,7 @@ public: GridTrackPlacementStyleValue& as_grid_track_placement() { return const_cast(const_cast(*this).as_grid_track_placement()); } GridTrackSizeListShorthandStyleValue& as_grid_track_size_list_shorthand() { return const_cast(const_cast(*this).as_grid_track_size_list_shorthand()); } GridTrackSizeListStyleValue& as_grid_track_size_list() { return const_cast(const_cast(*this).as_grid_track_size_list()); } + GridAutoFlowStyleValue& as_grid_auto_flow() { return const_cast(const_cast(*this).as_grid_auto_flow()); } IdentifierStyleValue& as_identifier() { return const_cast(const_cast(*this).as_identifier()); } ImageStyleValue& as_image() { return const_cast(const_cast(*this).as_image()); } InheritStyleValue& as_inherit() { return const_cast(const_cast(*this).as_inherit()); } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.cpp new file mode 100644 index 0000000000..bd520623cb --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "GridAutoFlowStyleValue.h" + +namespace Web::CSS { + +ValueComparingNonnullRefPtr GridAutoFlowStyleValue::create(Axis axis, Dense dense) +{ + return adopt_ref(*new GridAutoFlowStyleValue(axis, dense)); +} + +ErrorOr GridAutoFlowStyleValue::to_string() const +{ + StringBuilder builder; + if (m_row) + builder.append("row"sv); + else + builder.append("column"sv); + if (m_dense) + builder.append(" dense"sv); + return builder.to_string(); +} + +} diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.h new file mode 100644 index 0000000000..ff41938991 --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::CSS { + +class GridAutoFlowStyleValue final : public StyleValueWithDefaultOperators { +public: + enum Axis { + Row, + Column, + }; + enum Dense { + No, + Yes, + }; + static ValueComparingNonnullRefPtr create(Axis, Dense); + virtual ~GridAutoFlowStyleValue() override = default; + + [[nodiscard]] bool is_row() const { return m_row; } + [[nodiscard]] bool is_column() const { return !m_row; } + [[nodiscard]] bool is_dense() const { return m_dense; } + + virtual ErrorOr to_string() const override; + bool properties_equal(GridAutoFlowStyleValue const& other) const { return m_row == other.m_row && m_dense == other.m_dense; } + +private: + explicit GridAutoFlowStyleValue(Axis axis, Dense dense) + : StyleValueWithDefaultOperators(Type::GridAutoFlow) + , m_row(axis == Axis::Row) + , m_dense(dense == Dense::Yes) + { + } + + bool m_row { false }; + bool m_dense { false }; +}; + +} diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index d0ccd64194..8dc33fe717 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -114,6 +114,7 @@ class FrequencyOrCalculated; class FrequencyPercentage; class FrequencyStyleValue; class GridAreaShorthandStyleValue; +class GridAutoFlowStyleValue; class GridMinMax; class GridRepeat; class GridSize; diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index 47080c5454..f51815860d 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -724,6 +724,7 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style) computed_values.set_grid_row_end(computed_style.grid_row_end()); computed_values.set_grid_row_start(computed_style.grid_row_start()); computed_values.set_grid_template_areas(computed_style.grid_template_areas()); + computed_values.set_grid_auto_flow(computed_style.grid_auto_flow()); auto fill = computed_style.property(CSS::PropertyID::Fill); if (fill->has_color())