From 9bc001f410005ca394de36452d7e53dbb529c1a4 Mon Sep 17 00:00:00 2001 From: martinfalisse Date: Mon, 16 Jan 2023 19:02:39 +0100 Subject: [PATCH] LibWeb: Parse `grid-area` CSS property --- .../Libraries/LibWeb/CSS/Parser/Parser.cpp | 80 +++++++++++++++++++ Userland/Libraries/LibWeb/CSS/Parser/Parser.h | 1 + Userland/Libraries/LibWeb/CSS/Properties.json | 16 ++++ .../CSS/ResolvedCSSStyleDeclaration.cpp | 28 +++++++ .../Libraries/LibWeb/CSS/StyleComputer.cpp | 16 ++++ .../Libraries/LibWeb/CSS/StyleProperties.cpp | 6 ++ .../Libraries/LibWeb/CSS/StyleProperties.h | 1 + Userland/Libraries/LibWeb/CSS/StyleValue.cpp | 31 +++++++ Userland/Libraries/LibWeb/CSS/StyleValue.h | 40 ++++++++++ Userland/Libraries/LibWeb/Forward.h | 1 + 10 files changed, 220 insertions(+) diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index ddac708bb7..bc6ac2cec3 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -6292,6 +6292,82 @@ RefPtr Parser::parse_grid_track_placement_shorthand_value(Vector Parser::parse_grid_area_shorthand_value(Vector const& component_values) +{ + auto tokens = TokenStream { component_values }; + Token current_token; + + auto parse_placement_tokens = [&](Vector& placement_tokens, bool check_for_delimiter = true) -> void { + current_token = tokens.next_token().token(); + while (true) { + if (check_for_delimiter && current_token.is(Token::Type::Delim) && current_token.delim() == "/"sv) + break; + placement_tokens.append(current_token); + tokens.skip_whitespace(); + if (!tokens.has_next_token()) + break; + current_token = tokens.next_token().token(); + } + }; + + Vector row_start_placement_tokens; + parse_placement_tokens(row_start_placement_tokens); + + Vector column_start_placement_tokens; + if (tokens.has_next_token()) + parse_placement_tokens(column_start_placement_tokens); + + Vector row_end_placement_tokens; + if (tokens.has_next_token()) + parse_placement_tokens(row_end_placement_tokens); + + Vector column_end_placement_tokens; + if (tokens.has_next_token()) + parse_placement_tokens(column_end_placement_tokens, false); + + // https://www.w3.org/TR/css-grid-2/#placement-shorthands + // The grid-area property is a shorthand for grid-row-start, grid-column-start, grid-row-end and + // grid-column-end. + auto row_start_style_value = parse_grid_track_placement(row_start_placement_tokens); + auto column_start_style_value = parse_grid_track_placement(column_start_placement_tokens); + auto row_end_style_value = parse_grid_track_placement(row_end_placement_tokens); + auto column_end_style_value = parse_grid_track_placement(column_end_placement_tokens); + + // If four values are specified, grid-row-start is set to the first value, grid-column-start + // is set to the second value, grid-row-end is set to the third value, and grid-column-end is set to the + // fourth value. + auto row_start = GridTrackPlacement::make_auto(); + auto column_start = GridTrackPlacement::make_auto(); + auto row_end = GridTrackPlacement::make_auto(); + auto column_end = GridTrackPlacement::make_auto(); + + if (row_start_style_value) + row_start = row_start_style_value.release_nonnull()->as_grid_track_placement().grid_track_placement(); + + // When grid-column-start is omitted, if grid-row-start is a , all four longhands are set to + // that value. Otherwise, it is set to auto. + if (column_start_style_value) + column_start = column_start_style_value.release_nonnull()->as_grid_track_placement().grid_track_placement(); + else + column_start = row_start; + + // When grid-row-end is omitted, if grid-row-start is a , grid-row-end is set to that + // ; otherwise, it is set to auto. + if (row_end_style_value) + row_end = row_end_style_value.release_nonnull()->as_grid_track_placement().grid_track_placement(); + else + row_end = column_start; + + // When grid-column-end is omitted, if grid-column-start is a , grid-column-end is set to + // that ; otherwise, it is set to auto. + if (column_end_style_value) + column_end = column_end_style_value.release_nonnull()->as_grid_track_placement().grid_track_placement(); + else + column_end = row_end; + + return GridAreaShorthandStyleValue::create(row_start, column_start, row_end, column_end); +} + RefPtr Parser::parse_grid_template_areas_value(Vector const& component_values) { Vector> grid_area_rows; @@ -6446,6 +6522,10 @@ Parser::ParseErrorOr> Parser::parse_css_value(Property if (auto parsed_value = parse_grid_track_placement_shorthand_value(component_values)) return parsed_value.release_nonnull(); return ParseError::SyntaxError; + case PropertyID::GridArea: + if (auto parsed_value = parse_grid_area_shorthand_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 fc46c0bf21..6d33d1d3e4 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -316,6 +316,7 @@ private: RefPtr parse_grid_track_placement(Vector const&); RefPtr parse_grid_track_placement_shorthand_value(Vector const&); RefPtr parse_grid_template_areas_value(Vector const&); + RefPtr parse_grid_area_shorthand_value(Vector const&); // calc() parsing, according to https://www.w3.org/TR/css-values-3/#calc-syntax OwnPtr parse_calc_sum(TokenStream&); diff --git a/Userland/Libraries/LibWeb/CSS/Properties.json b/Userland/Libraries/LibWeb/CSS/Properties.json index d59bf2b45c..fe6f69713b 100644 --- a/Userland/Libraries/LibWeb/CSS/Properties.json +++ b/Userland/Libraries/LibWeb/CSS/Properties.json @@ -740,6 +740,22 @@ "column-gap" ] }, + "grid-area": { + "inherited": false, + "initial": "auto", + "valid-identifiers": [ + "auto" + ], + "valid-types": [ + "string" + ], + "longhands": [ + "grid-column-end", + "grid-column-start", + "grid-row-end", + "grid-row-start" + ] + }, "grid-column": { "inherited": false, "initial": "auto", diff --git a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp index bd7ebfafe8..9e713e8871 100644 --- a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp +++ b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp @@ -332,6 +332,34 @@ RefPtr ResolvedCSSStyleDeclaration::style_value_for_property(Layout: return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().flex_wrap())); case CSS::PropertyID::Float: return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().float_())); + case CSS::PropertyID::GridArea: { + auto maybe_grid_row_start = property(CSS::PropertyID::GridRowStart); + auto maybe_grid_column_start = property(CSS::PropertyID::GridColumnStart); + auto maybe_grid_row_end = property(CSS::PropertyID::GridRowEnd); + auto maybe_grid_column_end = property(CSS::PropertyID::GridColumnEnd); + RefPtr grid_row_start, grid_column_start, grid_row_end, grid_column_end; + if (maybe_grid_row_start.has_value()) { + VERIFY(maybe_grid_row_start.value().value->is_grid_track_placement()); + grid_row_start = maybe_grid_row_start.value().value->as_grid_track_placement(); + } + if (maybe_grid_column_start.has_value()) { + VERIFY(maybe_grid_column_start.value().value->is_grid_track_placement()); + grid_column_start = maybe_grid_column_start.value().value->as_grid_track_placement(); + } + if (maybe_grid_row_end.has_value()) { + VERIFY(maybe_grid_row_end.value().value->is_grid_track_placement()); + grid_row_end = maybe_grid_row_end.value().value->as_grid_track_placement(); + } + if (maybe_grid_column_end.has_value()) { + VERIFY(maybe_grid_column_end.value().value->is_grid_track_placement()); + grid_column_end = maybe_grid_column_end.value().value->as_grid_track_placement(); + } + return GridAreaShorthandStyleValue::create( + grid_row_start.release_nonnull(), + grid_column_start.release_nonnull(), + grid_row_end.release_nonnull(), + grid_column_end.release_nonnull()); + } case CSS::PropertyID::GridColumn: { auto maybe_grid_column_end = property(CSS::PropertyID::GridColumnEnd); auto maybe_grid_column_start = property(CSS::PropertyID::GridColumnStart); diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp index 64c670b932..1b55d9089a 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -520,6 +520,22 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope return; } + if (property_id == CSS::PropertyID::GridArea) { + if (value.is_grid_area_shorthand()) { + auto const& shorthand = value.as_grid_area_shorthand(); + style.set_property(CSS::PropertyID::GridRowStart, shorthand.row_start()); + style.set_property(CSS::PropertyID::GridColumnStart, shorthand.column_start()); + style.set_property(CSS::PropertyID::GridRowEnd, shorthand.row_end()); + style.set_property(CSS::PropertyID::GridColumnEnd, shorthand.column_end()); + return; + } + style.set_property(CSS::PropertyID::GridRowStart, value); + style.set_property(CSS::PropertyID::GridColumnStart, value); + style.set_property(CSS::PropertyID::GridRowEnd, value); + style.set_property(CSS::PropertyID::GridColumnEnd, value); + return; + } + if (property_id == CSS::PropertyID::GridColumn) { if (value.is_grid_track_placement_shorthand()) { auto const& shorthand = value.as_grid_track_placement_shorthand(); diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index 4653601e82..d08b983af8 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -751,4 +751,10 @@ Vector> StyleProperties::grid_template_areas() const return value->as_grid_template_area().grid_template_area(); } +String StyleProperties::grid_area() const +{ + auto value = property(CSS::PropertyID::GridArea); + return value->as_string().to_string().release_value_but_fixme_should_propagate_errors(); +} + } diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index 3567e4fb90..572528a6dc 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -92,6 +92,7 @@ public: CSS::GridTrackPlacement grid_row_start() const; Optional border_collapse() const; Vector> grid_template_areas() const; + String grid_area() const; Vector transformations() const; CSS::TransformOrigin transform_origin() const; diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp index 27c9b10555..ae22e9574c 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp @@ -140,6 +140,12 @@ GridTrackPlacementShorthandStyleValue const& StyleValue::as_grid_track_placement return static_cast(*this); } +GridAreaShorthandStyleValue const& StyleValue::as_grid_area_shorthand() const +{ + VERIFY(is_grid_area_shorthand()); + return static_cast(*this); +} + GridTemplateAreaStyleValue const& StyleValue::as_grid_template_area() const { VERIFY(is_grid_template_area()); @@ -1427,6 +1433,31 @@ bool GridTrackPlacementShorthandStyleValue::equals(StyleValue const& other) cons && m_end->equals(typed_other.m_end); } +ErrorOr GridAreaShorthandStyleValue::to_string() const +{ + StringBuilder builder; + if (!m_row_start->as_grid_track_placement().grid_track_placement().is_auto()) + builder.appendff("{}", m_row_start->as_grid_track_placement().grid_track_placement().to_string().value()); + if (!m_column_start->as_grid_track_placement().grid_track_placement().is_auto()) + builder.appendff(" / {}", m_column_start->as_grid_track_placement().grid_track_placement().to_string().value()); + if (!m_row_end->as_grid_track_placement().grid_track_placement().is_auto()) + builder.appendff(" / {}", m_row_end->as_grid_track_placement().grid_track_placement().to_string().value()); + if (!m_column_end->as_grid_track_placement().grid_track_placement().is_auto()) + builder.appendff(" / {}", m_column_end->as_grid_track_placement().grid_track_placement().to_string().value()); + return builder.to_string(); +} + +bool GridAreaShorthandStyleValue::equals(StyleValue const& other) const +{ + if (type() != other.type()) + return false; + auto const& typed_other = other.as_grid_area_shorthand(); + return m_row_start->equals(typed_other.m_row_start) + && m_column_start->equals(typed_other.m_column_start) + && m_row_end->equals(typed_other.m_row_end) + && m_column_end->equals(typed_other.m_column_end); +} + ErrorOr GridTrackPlacementStyleValue::to_string() const { return m_grid_track_placement.to_string(); diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index 0bb1178e0d..693b6338fb 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -228,6 +228,7 @@ public: FlexFlow, Font, Frequency, + GridAreaShorthand, GridTemplateArea, GridTrackPlacement, GridTrackPlacementShorthand, @@ -276,6 +277,7 @@ public: bool is_flex_flow() const { return type() == Type::FlexFlow; } bool is_font() const { return type() == Type::Font; } bool is_frequency() const { return type() == Type::Frequency; } + bool is_grid_area_shorthand() const { return type() == Type::GridAreaShorthand; } bool is_grid_template_area() const { return type() == Type::GridTemplateArea; } bool is_grid_track_placement() const { return type() == Type::GridTrackPlacement; } bool is_grid_track_placement_shorthand() const { return type() == Type::GridTrackPlacementShorthand; } @@ -322,6 +324,7 @@ public: FlexStyleValue const& as_flex() const; FontStyleValue const& as_font() const; FrequencyStyleValue const& as_frequency() const; + GridAreaShorthandStyleValue const& as_grid_area_shorthand() const; GridTemplateAreaStyleValue const& as_grid_template_area() const; GridTrackPlacementShorthandStyleValue const& as_grid_track_placement_shorthand() const; GridTrackPlacementStyleValue const& as_grid_track_placement() const; @@ -366,6 +369,7 @@ public: FlexStyleValue& as_flex() { return const_cast(const_cast(*this).as_flex()); } FontStyleValue& as_font() { return const_cast(const_cast(*this).as_font()); } FrequencyStyleValue& as_frequency() { return const_cast(const_cast(*this).as_frequency()); } + GridAreaShorthandStyleValue& as_grid_area_shorthand() { return const_cast(const_cast(*this).as_grid_area_shorthand()); } GridTemplateAreaStyleValue& as_grid_template_area() { return const_cast(const_cast(*this).as_grid_template_area()); } GridTrackPlacementShorthandStyleValue& as_grid_track_placement_shorthand() { return const_cast(const_cast(*this).as_grid_track_placement_shorthand()); } GridTrackPlacementStyleValue& as_grid_track_placement() { return const_cast(const_cast(*this).as_grid_track_placement()); } @@ -1124,6 +1128,42 @@ private: NonnullRefPtr m_end; }; +class GridAreaShorthandStyleValue final : public StyleValue { +public: + static NonnullRefPtr create(NonnullRefPtr row_start, NonnullRefPtr column_start, NonnullRefPtr row_end, NonnullRefPtr column_end) + { + return adopt_ref(*new GridAreaShorthandStyleValue(row_start, column_start, row_end, column_end)); + } + static NonnullRefPtr create(GridTrackPlacement row_start, GridTrackPlacement column_start, GridTrackPlacement row_end, GridTrackPlacement column_end) + { + return adopt_ref(*new GridAreaShorthandStyleValue(GridTrackPlacementStyleValue::create(row_start), GridTrackPlacementStyleValue::create(column_start), GridTrackPlacementStyleValue::create(row_end), GridTrackPlacementStyleValue::create(column_end))); + } + virtual ~GridAreaShorthandStyleValue() override = default; + + NonnullRefPtr row_start() const { return m_row_start; } + NonnullRefPtr column_start() const { return m_column_start; } + NonnullRefPtr row_end() const { return m_row_end; } + NonnullRefPtr column_end() const { return m_column_end; } + + virtual ErrorOr to_string() const override; + virtual bool equals(StyleValue const& other) const override; + +private: + GridAreaShorthandStyleValue(NonnullRefPtr row_start, NonnullRefPtr column_start, NonnullRefPtr row_end, NonnullRefPtr column_end) + : StyleValue(Type::GridAreaShorthand) + , m_row_start(row_start) + , m_column_start(column_start) + , m_row_end(row_end) + , m_column_end(column_end) + { + } + + NonnullRefPtr m_row_start; + NonnullRefPtr m_column_start; + NonnullRefPtr m_row_end; + NonnullRefPtr m_column_end; +}; + class GridTrackSizeStyleValue final : public StyleValue { public: static NonnullRefPtr create(CSS::GridTrackSizeList grid_track_size_list); diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 311b61168c..e528172c86 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -62,6 +62,7 @@ class FontStyleValue; class Frequency; class FrequencyPercentage; class FrequencyStyleValue; +class GridAreaShorthandStyleValue; class GridMinMax; class GridRepeat; class GridSize;