mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 09:00:22 +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:
parent
401544f68f
commit
dd073b2711
Notes:
sideshowbarker
2024-07-17 01:13:25 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/dd073b2711 Pull-request: https://github.com/SerenityOS/serenity/pull/19845 Reviewed-by: https://github.com/AtkinsSJ
13 changed files with 471 additions and 5 deletions
|
@ -1,5 +1,14 @@
|
|||
function (generate_css_implementation)
|
||||
set(LIBWEB_INPUT_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
invoke_generator(
|
||||
"EasingFunctions.cpp"
|
||||
Lagom::GenerateCSSEasingFunctions
|
||||
"${LIBWEB_INPUT_FOLDER}/CSS/EasingFunctions.json"
|
||||
"CSS/EasingFunctions.h"
|
||||
"CSS/EasingFunctions.cpp"
|
||||
arguments -j "${LIBWEB_INPUT_FOLDER}/CSS/EasingFunctions.json"
|
||||
)
|
||||
|
||||
invoke_generator(
|
||||
"Enums.cpp"
|
||||
Lagom::GenerateCSSEnums
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
set(SOURCES "") # avoid pulling SOURCES from parent scope
|
||||
|
||||
lagom_tool(GenerateCSSEnums SOURCES GenerateCSSEnums.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateCSSMediaFeatureID SOURCES GenerateCSSMediaFeatureID.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateCSSPropertyID SOURCES GenerateCSSPropertyID.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateCSSTransformFunctions SOURCES GenerateCSSTransformFunctions.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateCSSValueID SOURCES GenerateCSSValueID.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateCSSEasingFunctions SOURCES GenerateCSSEasingFunctions.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateCSSEnums SOURCES GenerateCSSEnums.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateCSSMediaFeatureID SOURCES GenerateCSSMediaFeatureID.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateCSSPropertyID SOURCES GenerateCSSPropertyID.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateCSSTransformFunctions SOURCES GenerateCSSTransformFunctions.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateCSSValueID SOURCES GenerateCSSValueID.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateWindowOrWorkerInterfaces SOURCES GenerateWindowOrWorkerInterfaces.cpp LIBS LibMain LibIDL)
|
||||
lagom_tool(GenerateAriaRoles SOURCES GenerateAriaRoles.cpp LIBS LibMain)
|
||||
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2023, Sam Atkins <atkinssj@serenityos.org>
|
||||
* Copyright (c) 2023, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "GeneratorUtil.h"
|
||||
#include <AK/GenericLexer.h>
|
||||
#include <AK/SourceGenerator.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibMain/Main.h>
|
||||
|
||||
ErrorOr<void> generate_header_file(JsonObject&, Core::File&);
|
||||
ErrorOr<void> generate_implementation_file(JsonObject&, Core::File&);
|
||||
|
||||
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
{
|
||||
StringView generated_header_path;
|
||||
StringView generated_implementation_path;
|
||||
StringView functions_json_path;
|
||||
|
||||
Core::ArgsParser args_parser;
|
||||
args_parser.add_option(generated_header_path, "Path to the EasingFunctions header file to generate", "generated-header-path", 'h', "generated-header-path");
|
||||
args_parser.add_option(generated_implementation_path, "Path to the EasingFunctions implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
|
||||
args_parser.add_option(functions_json_path, "Path to the JSON file to read from", "json-path", 'j', "json-path");
|
||||
args_parser.parse(arguments);
|
||||
|
||||
auto json = TRY(read_entire_file_as_json(functions_json_path));
|
||||
VERIFY(json.is_object());
|
||||
auto easing_data = json.as_object();
|
||||
|
||||
auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write));
|
||||
auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write));
|
||||
|
||||
TRY(generate_header_file(easing_data, *generated_header_file));
|
||||
TRY(generate_implementation_file(easing_data, *generated_implementation_file));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ErrorOr<void> generate_header_file(JsonObject& easing_data, Core::File& file)
|
||||
{
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
|
||||
TRY(generator.try_append(R"~~~(
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Vector.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
)~~~"));
|
||||
|
||||
TRY(generator.try_appendln("enum class EasingFunction {"));
|
||||
TRY(easing_data.try_for_each_member([&](auto& name, auto&) -> ErrorOr<void> {
|
||||
auto member_generator = TRY(generator.fork());
|
||||
TRY(member_generator.set("name:titlecase", TRY(title_casify(name))));
|
||||
TRY(member_generator.try_appendln(" @name:titlecase@,"));
|
||||
return {};
|
||||
}));
|
||||
TRY(generator.try_appendln("};"));
|
||||
|
||||
TRY(generator.try_appendln("Optional<EasingFunction> easing_function_from_string(StringView);"));
|
||||
TRY(generator.try_appendln("StringView to_string(EasingFunction);"));
|
||||
|
||||
TRY(generator.try_append(R"~~~(
|
||||
enum class EasingFunctionParameterType {
|
||||
Integer,
|
||||
Number,
|
||||
NumberZeroToOne,
|
||||
StepPosition,
|
||||
};
|
||||
|
||||
struct EasingFunctionParameter {
|
||||
EasingFunctionParameterType type;
|
||||
bool is_optional { false };
|
||||
};
|
||||
|
||||
struct EasingFunctionMetadata {
|
||||
Vector<EasingFunctionParameter> parameters;
|
||||
};
|
||||
EasingFunctionMetadata easing_function_metadata(EasingFunction);
|
||||
)~~~"));
|
||||
|
||||
TRY(generator.try_appendln("\n}"));
|
||||
|
||||
TRY(file.write_until_depleted(generator.as_string_view().bytes()));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> generate_implementation_file(JsonObject& easing_data, Core::File& file)
|
||||
{
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
|
||||
TRY(generator.try_append(R"~~~(
|
||||
#include <LibWeb/CSS/EasingFunctions.h>
|
||||
#include <AK/Assertions.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
)~~~"));
|
||||
|
||||
TRY(generator.try_append(R"~~~(
|
||||
Optional<EasingFunction> easing_function_from_string(StringView name)
|
||||
{
|
||||
)~~~"));
|
||||
TRY(easing_data.try_for_each_member([&](auto& name, auto&) -> ErrorOr<void> {
|
||||
auto member_generator = TRY(generator.fork());
|
||||
TRY(member_generator.set("name", TRY(String::from_deprecated_string(name))));
|
||||
TRY(member_generator.set("name:titlecase", TRY(title_casify(name))));
|
||||
TRY(member_generator.try_append(R"~~~(
|
||||
if (name.equals_ignoring_ascii_case("@name@"sv))
|
||||
return EasingFunction::@name:titlecase@;
|
||||
)~~~"));
|
||||
return {};
|
||||
}));
|
||||
TRY(generator.try_append(R"~~~(
|
||||
return {};
|
||||
}
|
||||
)~~~"));
|
||||
|
||||
TRY(generator.try_append(R"~~~(
|
||||
StringView to_string(EasingFunction easing_function)
|
||||
{
|
||||
switch (easing_function) {
|
||||
)~~~"));
|
||||
TRY(easing_data.try_for_each_member([&](auto& name, auto&) -> ErrorOr<void> {
|
||||
auto member_generator = TRY(generator.fork());
|
||||
TRY(member_generator.set("name", TRY(String::from_deprecated_string(name))));
|
||||
TRY(member_generator.set("name:titlecase", TRY(title_casify(name))));
|
||||
TRY(member_generator.try_append(R"~~~(
|
||||
case EasingFunction::@name:titlecase@:
|
||||
return "@name@"sv;
|
||||
)~~~"));
|
||||
return {};
|
||||
}));
|
||||
TRY(generator.try_append(R"~~~(
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
)~~~"));
|
||||
|
||||
TRY(generator.try_append(R"~~~(
|
||||
EasingFunctionMetadata easing_function_metadata(EasingFunction easing_function)
|
||||
{
|
||||
switch (easing_function) {
|
||||
)~~~"));
|
||||
TRY(easing_data.try_for_each_member([&](auto& name, auto& value) -> ErrorOr<void> {
|
||||
VERIFY(value.is_object());
|
||||
|
||||
auto member_generator = TRY(generator.fork());
|
||||
TRY(member_generator.set("name:titlecase", TRY(title_casify(name))));
|
||||
TRY(member_generator.try_append(R"~~~(
|
||||
case EasingFunction::@name:titlecase@:
|
||||
return EasingFunctionMetadata {
|
||||
.parameters = {)~~~"));
|
||||
|
||||
if (auto parameters = value.as_object().get_array("parameters"sv); parameters.has_value()) {
|
||||
bool first = true;
|
||||
// parameters: [ "<foo>", "<foo [0, 1]>" ]
|
||||
TRY(parameters.value().try_for_each([&](JsonValue const& value) -> ErrorOr<void> {
|
||||
GenericLexer lexer { value.as_string() };
|
||||
VERIFY(lexer.consume_specific('<'));
|
||||
auto parameter_type_name = lexer.consume_until([](char ch) { return ch == ' ' || ch == '>'; });
|
||||
auto has_bounds = false;
|
||||
auto is_optional = false;
|
||||
if (lexer.consume_specific(" [")) {
|
||||
has_bounds = true;
|
||||
auto contents = lexer.consume_until(']');
|
||||
VERIFY(contents == "0, 1"sv);
|
||||
VERIFY(lexer.consume_specific(']'));
|
||||
}
|
||||
VERIFY(lexer.consume_specific('>'));
|
||||
if (lexer.consume_specific('?'))
|
||||
is_optional = true;
|
||||
|
||||
StringView parameter_type = ""sv;
|
||||
if (parameter_type_name == "number"sv)
|
||||
parameter_type = has_bounds ? "NumberZeroToOne"sv : "Number"sv;
|
||||
else if (parameter_type_name == "integer"sv)
|
||||
parameter_type = "Integer"sv;
|
||||
else if (parameter_type_name == "step-position"sv)
|
||||
parameter_type = "StepPosition"sv;
|
||||
else
|
||||
VERIFY_NOT_REACHED();
|
||||
|
||||
TRY(member_generator.try_append(first ? " "sv : ", "sv));
|
||||
first = false;
|
||||
|
||||
TRY(member_generator.try_append(TRY(String::formatted(
|
||||
"{{ EasingFunctionParameterType::{}, {} }}",
|
||||
parameter_type,
|
||||
is_optional ? "true"sv : "false"sv))));
|
||||
return {};
|
||||
}));
|
||||
}
|
||||
|
||||
TRY(member_generator.try_append(R"~~~( }
|
||||
};
|
||||
)~~~"));
|
||||
return {};
|
||||
}));
|
||||
TRY(generator.try_append(R"~~~(
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
)~~~"));
|
||||
|
||||
TRY(generator.try_appendln("\n}"));
|
||||
|
||||
TRY(file.write_until_depleted(generator.as_string_view().bytes()));
|
||||
return {};
|
||||
}
|
|
@ -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
|
||||
|
|
23
Userland/Libraries/LibWeb/CSS/EasingFunctions.json
Normal file
23
Userland/Libraries/LibWeb/CSS/EasingFunctions.json
Normal 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>?"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -166,6 +166,10 @@
|
|||
"invert",
|
||||
"inverted",
|
||||
"italic",
|
||||
"jump-both",
|
||||
"jump-end",
|
||||
"jump-none",
|
||||
"jump-start",
|
||||
"justify",
|
||||
"landscape",
|
||||
"large",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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()); }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
47
Userland/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.h
Normal file
47
Userland/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
|
@ -98,6 +98,7 @@ class ContentStyleValue;
|
|||
class CustomIdentStyleValue;
|
||||
class Display;
|
||||
class DisplayStyleValue;
|
||||
class EasingStyleValue;
|
||||
class EdgeStyleValue;
|
||||
class ElementInlineCSSStyleDeclaration;
|
||||
class ExplicitGridTrack;
|
||||
|
|
Loading…
Reference in a new issue