diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 79c0f6ccc4c..c711d3b3e32 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/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 diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 3a157e3cbe1..683313108bb 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -6,6 +6,7 @@ * Copyright (c) 2022, MacDue * Copyright (c) 2024, Shannon Booth * Copyright (c) 2024, Tommy van der Vorst + * Copyright (c) 2024, Matthew Olsson * * SPDX-License-Identifier: BSD-2-Clause */ @@ -73,6 +74,7 @@ #include #include #include +#include #include #include #include @@ -5334,6 +5336,76 @@ RefPtr Parser::parse_transform_origin_value(TokenStream Parser::parse_transition_value(TokenStream& tokens) +{ + if (contains_single_none_ident(tokens)) { + tokens.next_token(); // none + return IdentifierStyleValue::create(ValueID::None); + } + + Vector 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 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> 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; } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index 90a85f06250..3f322adb42b 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -271,6 +271,7 @@ private: RefPtr parse_easing_value(TokenStream&); RefPtr parse_transform_value(TokenStream&); RefPtr parse_transform_origin_value(TokenStream&); + RefPtr parse_transition_value(TokenStream&); RefPtr parse_grid_track_size_list(TokenStream&, bool allow_separate_line_name_blocks = false); RefPtr parse_grid_auto_track_sizes(TokenStream&); RefPtr parse_grid_auto_flow_value(TokenStream&); diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp index 8ff0ce9f87a..e70338ed97e 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index addd269ff10..a5421aaaa6c 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -123,6 +123,7 @@ using StyleValueVector = Vector>; __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) \ diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/TransitionStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/TransitionStyleValue.cpp new file mode 100644 index 00000000000..d67e50088fd --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/TransitionStyleValue.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024, Matthew Olsson . + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +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; +} + +} diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/TransitionStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/TransitionStyleValue.h new file mode 100644 index 00000000000..7ea806e253f --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/TransitionStyleValue.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, Matthew Olsson . + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Web::CSS { + +class TransitionStyleValue final : public StyleValueWithDefaultOperators { +public: + struct Transition { + ValueComparingRefPtr property_name; + CSS::Time duration { CSS::Time::make_seconds(0.0) }; + CSS::Time delay { CSS::Time::make_seconds(0.0) }; + ValueComparingRefPtr easing; + + bool operator==(Transition const&) const = default; + }; + + static ValueComparingNonnullRefPtr create(Vector 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 transitions) + : StyleValueWithDefaultOperators(Type::Transition) + , m_transitions(move(transitions)) + { + } + + Vector m_transitions; +}; + +} diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 949ce7733ad..7500d06640f 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/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;