1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 08:47:44 +00:00

Meta/CodeGenerators+LibWeb: Implement parsing CSS easing functions

This only implements the parser bits, no functionality is implemented,
and no properties are parsed because of this.
This commit is contained in:
Ali Mohammad Pur 2023-07-06 02:29:36 +03:30 committed by Andreas Kling
parent 401544f68f
commit dd073b2711
13 changed files with 471 additions and 5 deletions

View file

@ -89,6 +89,7 @@ set(SOURCES
CSS/StyleValues/ConicGradientStyleValue.cpp
CSS/StyleValues/ContentStyleValue.cpp
CSS/StyleValues/DisplayStyleValue.cpp
CSS/StyleValues/EasingStyleValue.cpp
CSS/StyleValues/EdgeStyleValue.cpp
CSS/StyleValues/FilterValueListStyleValue.cpp
CSS/StyleValues/FlexFlowStyleValue.cpp
@ -612,6 +613,7 @@ generate_css_implementation()
set(GENERATED_SOURCES
ARIA/AriaRoles.cpp
CSS/DefaultStyleSheetSource.cpp
CSS/EasingFunctions.cpp
CSS/Enums.cpp
CSS/MediaFeatureID.cpp
CSS/PropertyID.cpp

View file

@ -0,0 +1,23 @@
{
"linear": {},
"ease": {},
"ease-in": {},
"ease-out": {},
"ease-in-out": {},
"cubic-bezier": {
"parameters": [
"<number [0, 1]>",
"<number>",
"<number [0, 1]>",
"<number>"
]
},
"step-start": {},
"step-end": {},
"steps": {
"parameters": [
"<integer>",
"<step-position>?"
]
}
}

View file

@ -166,6 +166,10 @@
"invert",
"inverted",
"italic",
"jump-both",
"jump-end",
"jump-none",
"jump-start",
"justify",
"landscape",
"large",

View file

@ -45,6 +45,7 @@
#include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
#include <LibWeb/CSS/StyleValues/CustomIdentStyleValue.h>
#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
#include <LibWeb/CSS/StyleValues/EasingStyleValue.h>
#include <LibWeb/CSS/StyleValues/EdgeStyleValue.h>
#include <LibWeb/CSS/StyleValues/FilterValueListStyleValue.h>
#include <LibWeb/CSS/StyleValues/FlexFlowStyleValue.h>
@ -7039,6 +7040,108 @@ ErrorOr<RefPtr<StyleValue>> Parser::parse_text_decoration_line_value(TokenStream
return StyleValueList::create(move(style_values), StyleValueList::Separator::Space);
}
ErrorOr<RefPtr<StyleValue>> Parser::parse_easing_value(TokenStream<ComponentValue>& tokens)
{
auto transaction = tokens.begin_transaction();
tokens.skip_whitespace();
auto const& part = tokens.next_token();
StringView name;
Optional<Vector<ComponentValue> const&> arguments;
if (part.is(Token::Type::Ident)) {
name = part.token().ident();
} else if (part.is_function()) {
name = part.function().name();
arguments = part.function().values();
} else {
return nullptr;
}
auto maybe_function = easing_function_from_string(name);
if (!maybe_function.has_value())
return nullptr;
auto function = maybe_function.release_value();
auto function_metadata = easing_function_metadata(function);
if (function_metadata.parameters.is_empty() && arguments.has_value()) {
dbgln_if(CSS_PARSER_DEBUG, "Too many arguments to {}. max: 0", name);
return nullptr;
}
StyleValueVector values;
size_t argument_index = 0;
if (arguments.has_value()) {
auto argument_tokens = TokenStream { *arguments };
auto arguments_values = parse_a_comma_separated_list_of_component_values(argument_tokens);
if (arguments_values.size() > function_metadata.parameters.size()) {
dbgln_if(CSS_PARSER_DEBUG, "Too many arguments to {}. max: {}", name, function_metadata.parameters.size());
return nullptr;
}
for (auto& argument_values : arguments_values) {
if (argument_values.size() != 1) {
dbgln_if(CSS_PARSER_DEBUG, "Too many values in argument to {}. max: 1", name);
return nullptr;
}
auto& value = argument_values[0];
switch (function_metadata.parameters[argument_index].type) {
case EasingFunctionParameterType::Number: {
if (value.is(Token::Type::Number))
values.append(TRY(NumberStyleValue::create(value.token().number().value())));
else
return nullptr;
break;
}
case EasingFunctionParameterType::NumberZeroToOne: {
if (value.is(Token::Type::Number) && value.token().number_value() >= 0 && value.token().number_value() <= 1)
values.append(TRY(NumberStyleValue::create(value.token().number().value())));
else
return nullptr;
break;
}
case EasingFunctionParameterType::Integer: {
if (value.is(Token::Type::Number) && value.token().number().is_integer())
values.append(TRY(IntegerStyleValue::create(value.token().number().integer_value())));
else
return nullptr;
break;
}
case EasingFunctionParameterType::StepPosition: {
if (!value.is(Token::Type::Ident))
return nullptr;
auto ident = TRY(parse_identifier_value(value));
if (!ident)
return nullptr;
switch (ident->to_identifier()) {
case ValueID::JumpStart:
case ValueID::JumpEnd:
case ValueID::JumpNone:
case ValueID::Start:
case ValueID::End:
TRY(values.try_append(*ident));
break;
default:
return nullptr;
}
}
}
++argument_index;
}
}
if (argument_index < function_metadata.parameters.size() && !function_metadata.parameters[argument_index].is_optional) {
dbgln_if(CSS_PARSER_DEBUG, "Required parameter at position {} is missing", argument_index);
return nullptr;
}
transaction.commit();
return EasingStyleValue::create(function, move(values));
}
ErrorOr<RefPtr<StyleValue>> Parser::parse_transform_value(Vector<ComponentValue> const& component_values)
{
StyleValueVector transformations;

View file

@ -352,6 +352,7 @@ private:
ErrorOr<RefPtr<StyleValue>> parse_single_shadow_value(TokenStream<ComponentValue>&, AllowInsetKeyword);
ErrorOr<RefPtr<StyleValue>> parse_text_decoration_value(Vector<ComponentValue> const&);
ErrorOr<RefPtr<StyleValue>> parse_text_decoration_line_value(TokenStream<ComponentValue>&);
ErrorOr<RefPtr<StyleValue>> parse_easing_value(TokenStream<ComponentValue>&);
ErrorOr<RefPtr<StyleValue>> parse_transform_value(Vector<ComponentValue> const&);
ErrorOr<RefPtr<StyleValue>> parse_transform_origin_value(Vector<ComponentValue> const&);
ErrorOr<RefPtr<StyleValue>> parse_grid_track_size_list(Vector<ComponentValue> const&, bool allow_separate_line_name_blocks = false);

View file

@ -25,6 +25,7 @@
#include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
#include <LibWeb/CSS/StyleValues/CustomIdentStyleValue.h>
#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
#include <LibWeb/CSS/StyleValues/EasingStyleValue.h>
#include <LibWeb/CSS/StyleValues/EdgeStyleValue.h>
#include <LibWeb/CSS/StyleValues/FilterValueListStyleValue.h>
#include <LibWeb/CSS/StyleValues/FlexFlowStyleValue.h>
@ -113,6 +114,12 @@ BorderRadiusStyleValue const& StyleValue::as_border_radius() const
return static_cast<BorderRadiusStyleValue const&>(*this);
}
EasingStyleValue const& StyleValue::as_easing() const
{
VERIFY(is_easing());
return static_cast<EasingStyleValue const&>(*this);
}
BorderRadiusShorthandStyleValue const& StyleValue::as_border_radius_shorthand() const
{
VERIFY(is_border_radius_shorthand());

View file

@ -101,6 +101,7 @@ public:
Content,
CustomIdent,
Display,
Easing,
Edge,
FilterValueList,
Flex,
@ -158,6 +159,7 @@ public:
bool is_content() const { return type() == Type::Content; }
bool is_custom_ident() const { return type() == Type::CustomIdent; }
bool is_display() const { return type() == Type::Display; }
bool is_easing() const { return type() == Type::Easing; }
bool is_edge() const { return type() == Type::Edge; }
bool is_filter_value_list() const { return type() == Type::FilterValueList; }
bool is_flex() const { return type() == Type::Flex; }
@ -214,6 +216,7 @@ public:
ContentStyleValue const& as_content() const;
CustomIdentStyleValue const& as_custom_ident() const;
DisplayStyleValue const& as_display() const;
EasingStyleValue const& as_easing() const;
EdgeStyleValue const& as_edge() const;
FilterValueListStyleValue const& as_filter_value_list() const;
FlexFlowStyleValue const& as_flex_flow() const;
@ -267,6 +270,7 @@ public:
ContentStyleValue& as_content() { return const_cast<ContentStyleValue&>(const_cast<StyleValue const&>(*this).as_content()); }
CustomIdentStyleValue& as_custom_ident() { return const_cast<CustomIdentStyleValue&>(const_cast<StyleValue const&>(*this).as_custom_ident()); }
DisplayStyleValue& as_display() { return const_cast<DisplayStyleValue&>(const_cast<StyleValue const&>(*this).as_display()); }
EasingStyleValue& as_easing() { return const_cast<EasingStyleValue&>(const_cast<StyleValue const&>(*this).as_easing()); }
EdgeStyleValue& as_edge() { return const_cast<EdgeStyleValue&>(const_cast<StyleValue const&>(*this).as_edge()); }
FilterValueListStyleValue& as_filter_value_list() { return const_cast<FilterValueListStyleValue&>(const_cast<StyleValue const&>(*this).as_filter_value_list()); }
FlexFlowStyleValue& as_flex_flow() { return const_cast<FlexFlowStyleValue&>(const_cast<StyleValue const&>(*this).as_flex_flow()); }

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech>
* Copyright (c) 2023, Ali Mohammad Pur <mpfard@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "EasingStyleValue.h"
#include <AK/StringBuilder.h>
namespace Web::CSS {
ErrorOr<String> EasingStyleValue::to_string() const
{
if (m_properties.easing_function == EasingFunction::StepStart)
return "steps(1, start)"_string;
if (m_properties.easing_function == EasingFunction::StepEnd)
return "steps(1, end)"_string;
StringBuilder builder;
TRY(builder.try_append(CSS::to_string(m_properties.easing_function)));
if (m_properties.values.is_empty())
return builder.to_string();
TRY(builder.try_append('('));
for (size_t i = 0; i < m_properties.values.size(); ++i) {
TRY(builder.try_append(TRY(m_properties.values[i]->to_string())));
if (i != m_properties.values.size() - 1)
TRY(builder.try_append(", "sv));
}
TRY(builder.try_append(')'));
return builder.to_string();
}
bool EasingStyleValue::Properties::operator==(Properties const& other) const
{
return easing_function == other.easing_function && values == other.values;
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech>
* Copyright (c) 2023, Ali Mohammad Pur <mpfard@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/CSS/EasingFunctions.h>
#include <LibWeb/CSS/StyleValue.h>
namespace Web::CSS {
class EasingStyleValue final : public StyleValueWithDefaultOperators<EasingStyleValue> {
public:
static ErrorOr<ValueComparingNonnullRefPtr<EasingStyleValue>> create(CSS::EasingFunction easing_function, StyleValueVector&& values)
{
return adopt_nonnull_ref_or_enomem(new (nothrow) EasingStyleValue(easing_function, move(values)));
}
virtual ~EasingStyleValue() override = default;
CSS::EasingFunction easing_function() const { return m_properties.easing_function; }
StyleValueVector values() const { return m_properties.values; }
virtual ErrorOr<String> to_string() const override;
bool properties_equal(EasingStyleValue const& other) const { return m_properties == other.m_properties; }
private:
EasingStyleValue(CSS::EasingFunction easing_function, StyleValueVector&& values)
: StyleValueWithDefaultOperators(Type::Easing)
, m_properties { .easing_function = easing_function, .values = move(values) }
{
}
struct Properties {
CSS::EasingFunction easing_function;
StyleValueVector values;
bool operator==(Properties const& other) const;
} m_properties;
};
}

View file

@ -98,6 +98,7 @@ class ContentStyleValue;
class CustomIdentStyleValue;
class Display;
class DisplayStyleValue;
class EasingStyleValue;
class EdgeStyleValue;
class ElementInlineCSSStyleDeclaration;
class ExplicitGridTrack;