Browse Source

LibWeb: Parse transition style values

Matthew Olsson 1 year ago
parent
commit
5dce559ed8

+ 1 - 0
Userland/Libraries/LibWeb/CMakeLists.txt

@@ -126,6 +126,7 @@ set(SOURCES
     CSS/StyleValues/ShorthandStyleValue.cpp
     CSS/StyleValues/StyleValueList.cpp
     CSS/StyleValues/TransformationStyleValue.cpp
+    CSS/StyleValues/TransitionStyleValue.cpp
     CSS/StyleValues/UnresolvedStyleValue.cpp
     CSS/Supports.cpp
     CSS/SyntaxHighlighter/SyntaxHighlighter.cpp

+ 77 - 1
Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp

@@ -6,6 +6,7 @@
  * Copyright (c) 2022, MacDue <macdue@dueutil.tech>
  * Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
  * Copyright (c) 2024, Tommy van der Vorst <tommy@pixelspark.nl>
+ * Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -73,6 +74,7 @@
 #include <LibWeb/CSS/StyleValues/StyleValueList.h>
 #include <LibWeb/CSS/StyleValues/TimeStyleValue.h>
 #include <LibWeb/CSS/StyleValues/TransformationStyleValue.h>
+#include <LibWeb/CSS/StyleValues/TransitionStyleValue.h>
 #include <LibWeb/CSS/StyleValues/URLStyleValue.h>
 #include <LibWeb/CSS/StyleValues/UnresolvedStyleValue.h>
 #include <LibWeb/CSS/StyleValues/UnsetStyleValue.h>
@@ -5334,6 +5336,76 @@ RefPtr<StyleValue> Parser::parse_transform_origin_value(TokenStream<ComponentVal
     return nullptr;
 }
 
+RefPtr<StyleValue> Parser::parse_transition_value(TokenStream<ComponentValue>& tokens)
+{
+    if (contains_single_none_ident(tokens)) {
+        tokens.next_token(); // none
+        return IdentifierStyleValue::create(ValueID::None);
+    }
+
+    Vector<TransitionStyleValue::Transition> transitions;
+    auto transaction = tokens.begin_transaction();
+
+    while (tokens.has_next_token()) {
+        TransitionStyleValue::Transition transition;
+        auto time_value_count = 0;
+
+        while (tokens.has_next_token() && !tokens.peek_token().is(Token::Type::Comma)) {
+            if (auto time = parse_time(tokens); time.has_value()) {
+                switch (time_value_count) {
+                case 0:
+                    transition.duration = time.release_value().value();
+                    break;
+                case 1:
+                    transition.delay = time.release_value().value();
+                    break;
+                default:
+                    dbgln_if(CSS_PARSER_DEBUG, "Transition property has more than two time values");
+                    return {};
+                }
+                time_value_count++;
+                continue;
+            }
+
+            if (tokens.peek_token().is(Token::Type::Ident)) {
+                if (transition.property_name) {
+                    dbgln_if(CSS_PARSER_DEBUG, "Transition property has multiple property identifiers");
+                    return {};
+                }
+
+                auto ident = tokens.next_token().token().ident();
+                if (auto property = property_id_from_string(ident); property.has_value())
+                    transition.property_name = CustomIdentStyleValue::create(ident);
+            }
+
+            if (auto easing = parse_easing_value(tokens)) {
+                if (transition.easing) {
+                    dbgln_if(CSS_PARSER_DEBUG, "Transition property has multiple easing values");
+                    return {};
+                }
+
+                transition.easing = easing->as_easing();
+            }
+        }
+
+        if (!transition.property_name)
+            transition.property_name = CustomIdentStyleValue::create("all"_fly_string);
+
+        if (!transition.easing)
+            transition.easing = EasingStyleValue::create(EasingFunction::Ease, {});
+
+        transitions.append(move(transition));
+
+        if (!tokens.peek_token().is(Token::Type::Comma))
+            break;
+
+        tokens.next_token();
+    }
+
+    transaction.commit();
+    return TransitionStyleValue::create(move(transitions));
+}
+
 RefPtr<StyleValue> Parser::parse_as_css_value(PropertyID property_id)
 {
     auto component_values = parse_a_list_of_component_values(m_token_stream);
@@ -6262,7 +6334,11 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue>> Parser::parse_css_value(Property
     case PropertyID::TransformOrigin:
         if (auto parsed_value = parse_transform_origin_value(tokens); parsed_value && !tokens.has_next_token())
             return parsed_value.release_nonnull();
-        return ParseError ::SyntaxError;
+        return ParseError::SyntaxError;
+    case PropertyID::Transition:
+        if (auto parsed_value = parse_transition_value(tokens); parsed_value && !tokens.has_next_token())
+            return parsed_value.release_nonnull();
+        return ParseError::SyntaxError;
     default:
         break;
     }

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

@@ -271,6 +271,7 @@ private:
     RefPtr<StyleValue> parse_easing_value(TokenStream<ComponentValue>&);
     RefPtr<StyleValue> parse_transform_value(TokenStream<ComponentValue>&);
     RefPtr<StyleValue> parse_transform_origin_value(TokenStream<ComponentValue>&);
+    RefPtr<StyleValue> parse_transition_value(TokenStream<ComponentValue>&);
     RefPtr<StyleValue> parse_grid_track_size_list(TokenStream<ComponentValue>&, bool allow_separate_line_name_blocks = false);
     RefPtr<StyleValue> parse_grid_auto_track_sizes(TokenStream<ComponentValue>&);
     RefPtr<GridAutoFlowStyleValue> parse_grid_auto_flow_value(TokenStream<ComponentValue>&);

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

@@ -52,6 +52,7 @@
 #include <LibWeb/CSS/StyleValues/StyleValueList.h>
 #include <LibWeb/CSS/StyleValues/TimeStyleValue.h>
 #include <LibWeb/CSS/StyleValues/TransformationStyleValue.h>
+#include <LibWeb/CSS/StyleValues/TransitionStyleValue.h>
 #include <LibWeb/CSS/StyleValues/URLStyleValue.h>
 #include <LibWeb/CSS/StyleValues/UnresolvedStyleValue.h>
 #include <LibWeb/CSS/StyleValues/UnsetStyleValue.h>

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

@@ -123,6 +123,7 @@ using StyleValueVector = Vector<ValueComparingNonnullRefPtr<StyleValue const>>;
     __ENUMERATE_STYLE_VALUE_TYPE(String, string)                           \
     __ENUMERATE_STYLE_VALUE_TYPE(Time, time)                               \
     __ENUMERATE_STYLE_VALUE_TYPE(Transformation, transformation)           \
+    __ENUMERATE_STYLE_VALUE_TYPE(Transition, transition)                   \
     __ENUMERATE_STYLE_VALUE_TYPE(Unresolved, unresolved)                   \
     __ENUMERATE_STYLE_VALUE_TYPE(Unset, unset)                             \
     __ENUMERATE_STYLE_VALUE_TYPE(URL, url)                                 \

+ 39 - 0
Userland/Libraries/LibWeb/CSS/StyleValues/TransitionStyleValue.cpp

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibWeb/CSS/PropertyID.h>
+#include <LibWeb/CSS/StyleValues/TransitionStyleValue.h>
+
+namespace Web::CSS {
+
+String TransitionStyleValue::to_string() const
+{
+    StringBuilder builder;
+    bool first = true;
+    for (auto const& transition : m_transitions) {
+        if (!first)
+            builder.append(", "sv);
+        first = false;
+        builder.appendff("{} {} {} {}", transition.property_name->to_string(), transition.duration, transition.easing->to_string(), transition.delay);
+    }
+
+    return MUST(builder.to_string());
+}
+
+bool TransitionStyleValue::properties_equal(TransitionStyleValue const& other) const
+{
+    if (m_transitions.size() != other.m_transitions.size())
+        return false;
+
+    for (size_t i = 0; i < m_transitions.size(); i++) {
+        if (m_transitions[i] != other.m_transitions[i])
+            return false;
+    }
+
+    return true;
+}
+
+}

+ 50 - 0
Userland/Libraries/LibWeb/CSS/StyleValues/TransitionStyleValue.h

@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibWeb/CSS/StyleValue.h>
+#include <LibWeb/CSS/StyleValues/CustomIdentStyleValue.h>
+#include <LibWeb/CSS/StyleValues/EasingStyleValue.h>
+#include <LibWeb/CSS/Time.h>
+
+namespace Web::CSS {
+
+class TransitionStyleValue final : public StyleValueWithDefaultOperators<TransitionStyleValue> {
+public:
+    struct Transition {
+        ValueComparingRefPtr<CustomIdentStyleValue> property_name;
+        CSS::Time duration { CSS::Time::make_seconds(0.0) };
+        CSS::Time delay { CSS::Time::make_seconds(0.0) };
+        ValueComparingRefPtr<EasingStyleValue> easing;
+
+        bool operator==(Transition const&) const = default;
+    };
+
+    static ValueComparingNonnullRefPtr<TransitionStyleValue> create(Vector<Transition> transitions)
+    {
+        return adopt_ref(*new (nothrow) TransitionStyleValue(move(transitions)));
+    }
+
+    virtual ~TransitionStyleValue() override = default;
+
+    auto const& transitions() const { return m_transitions; }
+
+    virtual String to_string() const override;
+
+    bool properties_equal(TransitionStyleValue const& other) const;
+
+private:
+    explicit TransitionStyleValue(Vector<Transition> transitions)
+        : StyleValueWithDefaultOperators(Type::Transition)
+        , m_transitions(move(transitions))
+    {
+    }
+
+    Vector<Transition> m_transitions;
+};
+
+}

+ 1 - 0
Userland/Libraries/LibWeb/Forward.h

@@ -191,6 +191,7 @@ class TimePercentage;
 class TimeStyleValue;
 class Transformation;
 class TransformationStyleValue;
+class TransitionStyleValue;
 class URLStyleValue;
 class UnresolvedStyleValue;
 class UnsetStyleValue;