Browse Source

LibWeb: Add support for parsing `grid-auto-flow` CSS property

Co-Authored-By: Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
Andreas Kling 1 năm trước cách đây
mục cha
commit
703c2bb06e

+ 1 - 0
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

+ 9 - 0
Userland/Libraries/LibWeb/CSS/ComputedValues.h

@@ -32,6 +32,11 @@ struct AspectRatio {
     Optional<Ratio> 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<CSS::VerticalAlign, CSS::LengthPercentage> 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<Vector<String>> 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; }
 

+ 56 - 0
Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp

@@ -53,6 +53,7 @@
 #include <LibWeb/CSS/StyleValues/FontStyleValue.h>
 #include <LibWeb/CSS/StyleValues/FrequencyStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridAreaShorthandStyleValue.h>
+#include <LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridTemplateAreaStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridTrackPlacementShorthandStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
@@ -5308,6 +5309,57 @@ RefPtr<StyleValue> Parser::parse_grid_track_size_list(Vector<ComponentValue> con
     return GridTrackSizeListStyleValue::create(CSS::GridTrackSizeList(track_list, line_names_list));
 }
 
+// https://www.w3.org/TR/css-grid-1/#grid-auto-flow-property
+RefPtr<GridAutoFlowStyleValue> Parser::parse_grid_auto_flow_value(Vector<ComponentValue> const& component_values)
+{
+    // [ row | column ] || dense
+    TokenStream<ComponentValue> tokens { component_values };
+    if (!tokens.has_next_token())
+        return nullptr;
+
+    auto parse_axis = [&]() -> Optional<GridAutoFlowStyleValue::Axis> {
+        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<GridAutoFlowStyleValue::Dense> {
+        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<GridAutoFlowStyleValue::Axis> axis;
+    Optional<GridAutoFlowStyleValue::Dense> 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<StyleValue> Parser::parse_grid_auto_track_sizes(Vector<ComponentValue> const& component_values)
 {
     // https://www.w3.org/TR/css-grid-2/#auto-tracks
@@ -5774,6 +5826,10 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue>> 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();

+ 1 - 0
Userland/Libraries/LibWeb/CSS/Parser/Parser.h

@@ -252,6 +252,7 @@ private:
     RefPtr<StyleValue> parse_transform_origin_value(Vector<ComponentValue> const&);
     RefPtr<StyleValue> parse_grid_track_size_list(Vector<ComponentValue> const&, bool allow_separate_line_name_blocks = false);
     RefPtr<StyleValue> parse_grid_auto_track_sizes(Vector<ComponentValue> const&);
+    [[nodiscard]] RefPtr<GridAutoFlowStyleValue> parse_grid_auto_flow_value(Vector<ComponentValue> const&);
     RefPtr<StyleValue> parse_grid_track_size_list_shorthand_value(Vector<ComponentValue> const&);
     RefPtr<StyleValue> parse_grid_track_placement(Vector<ComponentValue> const&);
     RefPtr<StyleValue> parse_grid_track_placement_shorthand_value(Vector<ComponentValue> const&);

+ 4 - 0
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",

+ 10 - 0
Userland/Libraries/LibWeb/CSS/StyleProperties.cpp

@@ -12,6 +12,7 @@
 #include <LibWeb/CSS/StyleValues/AngleStyleValue.h>
 #include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
 #include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
+#include <LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridTemplateAreaStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
@@ -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);

+ 1 - 0
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;

+ 7 - 0
Userland/Libraries/LibWeb/CSS/StyleValue.cpp

@@ -33,6 +33,7 @@
 #include <LibWeb/CSS/StyleValues/FontStyleValue.h>
 #include <LibWeb/CSS/StyleValues/FrequencyStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridAreaShorthandStyleValue.h>
+#include <LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridTemplateAreaStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridTrackPlacementShorthandStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
@@ -224,6 +225,12 @@ GridAreaShorthandStyleValue const& StyleValue::as_grid_area_shorthand() const
     return static_cast<GridAreaShorthandStyleValue const&>(*this);
 }
 
+GridAutoFlowStyleValue const& StyleValue::as_grid_auto_flow() const
+{
+    VERIFY(is_grid_auto_flow());
+    return static_cast<GridAutoFlowStyleValue const&>(*this);
+}
+
 GridTemplateAreaStyleValue const& StyleValue::as_grid_template_area() const
 {
     VERIFY(is_grid_template_area());

+ 4 - 0
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<GridTrackPlacementStyleValue&>(const_cast<StyleValue const&>(*this).as_grid_track_placement()); }
     GridTrackSizeListShorthandStyleValue& as_grid_track_size_list_shorthand() { return const_cast<GridTrackSizeListShorthandStyleValue&>(const_cast<StyleValue const&>(*this).as_grid_track_size_list_shorthand()); }
     GridTrackSizeListStyleValue& as_grid_track_size_list() { return const_cast<GridTrackSizeListStyleValue&>(const_cast<StyleValue const&>(*this).as_grid_track_size_list()); }
+    GridAutoFlowStyleValue& as_grid_auto_flow() { return const_cast<GridAutoFlowStyleValue&>(const_cast<StyleValue const&>(*this).as_grid_auto_flow()); }
     IdentifierStyleValue& as_identifier() { return const_cast<IdentifierStyleValue&>(const_cast<StyleValue const&>(*this).as_identifier()); }
     ImageStyleValue& as_image() { return const_cast<ImageStyleValue&>(const_cast<StyleValue const&>(*this).as_image()); }
     InheritStyleValue& as_inherit() { return const_cast<InheritStyleValue&>(const_cast<StyleValue const&>(*this).as_inherit()); }

+ 28 - 0
Userland/Libraries/LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.cpp

@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "GridAutoFlowStyleValue.h"
+
+namespace Web::CSS {
+
+ValueComparingNonnullRefPtr<GridAutoFlowStyleValue> GridAutoFlowStyleValue::create(Axis axis, Dense dense)
+{
+    return adopt_ref(*new GridAutoFlowStyleValue(axis, dense));
+}
+
+ErrorOr<String> 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();
+}
+
+}

+ 45 - 0
Userland/Libraries/LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.h

@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibWeb/CSS/StyleValue.h>
+
+namespace Web::CSS {
+
+class GridAutoFlowStyleValue final : public StyleValueWithDefaultOperators<GridAutoFlowStyleValue> {
+public:
+    enum Axis {
+        Row,
+        Column,
+    };
+    enum Dense {
+        No,
+        Yes,
+    };
+    static ValueComparingNonnullRefPtr<GridAutoFlowStyleValue> 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<String> 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 };
+};
+
+}

+ 1 - 0
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;

+ 1 - 0
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())