mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-11 13:36:13 +03:00
LibWeb: Generate parsing code for CSS math functions
This commit is contained in:
parent
780998b3d5
commit
618c0402a7
Notes:
sideshowbarker
2024-07-17 08:36:27 +09:00
Author: https://github.com/AtkinsSJ Commit: https://github.com/SerenityOS/serenity/commit/618c0402a7 Pull-request: https://github.com/SerenityOS/serenity/pull/19996
@ -18,6 +18,15 @@ function (generate_css_implementation)
|
||||
arguments -j "${LIBWEB_INPUT_FOLDER}/CSS/Enums.json"
|
||||
)
|
||||
|
||||
invoke_generator(
|
||||
"MathFunctions.cpp"
|
||||
Lagom::GenerateCSSMathFunctions
|
||||
"${LIBWEB_INPUT_FOLDER}/CSS/MathFunctions.json"
|
||||
"CSS/MathFunctions.h"
|
||||
"CSS/MathFunctions.cpp"
|
||||
arguments -j "${LIBWEB_INPUT_FOLDER}/CSS/MathFunctions.json"
|
||||
)
|
||||
|
||||
invoke_generator(
|
||||
"MediaFeatureID.cpp"
|
||||
Lagom::GenerateCSSMediaFeatureID
|
||||
|
@ -2,6 +2,7 @@ set(SOURCES "") # avoid pulling SOURCES from parent scope
|
||||
|
||||
lagom_tool(GenerateCSSEasingFunctions SOURCES GenerateCSSEasingFunctions.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateCSSEnums SOURCES GenerateCSSEnums.cpp LIBS LibMain)
|
||||
lagom_tool(GenerateCSSMathFunctions SOURCES GenerateCSSMathFunctions.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)
|
||||
|
@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Sam Atkins <atkinssj@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "GeneratorUtil.h"
|
||||
#include <AK/SourceGenerator.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibMain/Main.h>
|
||||
|
||||
ErrorOr<void> generate_header_file(JsonObject& functions_data, Core::File& file);
|
||||
ErrorOr<void> generate_implementation_file(JsonObject& functions_data, Core::File& file);
|
||||
|
||||
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
{
|
||||
StringView generated_header_path;
|
||||
StringView generated_implementation_path;
|
||||
StringView identifiers_json_path;
|
||||
|
||||
Core::ArgsParser args_parser;
|
||||
args_parser.add_option(generated_header_path, "Path to the MathFunctions header file to generate", "generated-header-path", 'h', "generated-header-path");
|
||||
args_parser.add_option(generated_implementation_path, "Path to the MathFunctions implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
|
||||
args_parser.add_option(identifiers_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(identifiers_json_path));
|
||||
VERIFY(json.is_object());
|
||||
auto math_functions_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(math_functions_data, *generated_header_file));
|
||||
TRY(generate_implementation_file(math_functions_data, *generated_implementation_file));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ErrorOr<void> generate_header_file(JsonObject& functions_data, Core::File& file)
|
||||
{
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
|
||||
TRY(generator.try_append(R"~~~(
|
||||
// This file is generated by GenerateCSSMathFunctions.cpp
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
enum class MathFunction {
|
||||
)~~~"));
|
||||
|
||||
TRY(functions_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@,"sv));
|
||||
return {};
|
||||
}));
|
||||
|
||||
TRY(generator.try_append(R"~~~(
|
||||
};
|
||||
|
||||
}
|
||||
)~~~"));
|
||||
|
||||
TRY(file.write_until_depleted(generator.as_string_view().bytes()));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<String> generate_calculation_type_check(StringView calculation_variable_name, StringView parameter_types)
|
||||
{
|
||||
StringBuilder builder;
|
||||
auto allowed_types = parameter_types.split_view('|');
|
||||
bool first_type_check = true;
|
||||
for (auto const& allowed_type_name : allowed_types) {
|
||||
if (!first_type_check)
|
||||
TRY(builder.try_append(" || "sv));
|
||||
first_type_check = false;
|
||||
|
||||
if (allowed_type_name == "<angle>"sv) {
|
||||
TRY(builder.try_appendff("{}.{}", calculation_variable_name, "matches_angle()"sv));
|
||||
} else if (allowed_type_name == "<dimension>"sv) {
|
||||
TRY(builder.try_appendff("{}.{}", calculation_variable_name, "matches_dimension()"sv));
|
||||
} else if (allowed_type_name == "<flex>"sv) {
|
||||
TRY(builder.try_appendff("{}.{}", calculation_variable_name, "matches_flex()"sv));
|
||||
} else if (allowed_type_name == "<frequency>"sv) {
|
||||
TRY(builder.try_appendff("{}.{}", calculation_variable_name, "matches_frequency()"sv));
|
||||
} else if (allowed_type_name == "<length>"sv) {
|
||||
TRY(builder.try_appendff("{}.{}", calculation_variable_name, "matches_length()"sv));
|
||||
} else if (allowed_type_name == "<number>"sv) {
|
||||
TRY(builder.try_appendff("{}.{}", calculation_variable_name, "matches_number()"sv));
|
||||
} else if (allowed_type_name == "<percentage>"sv) {
|
||||
TRY(builder.try_appendff("{}.{}", calculation_variable_name, "matches_percentage()"sv));
|
||||
} else if (allowed_type_name == "<resolution>"sv) {
|
||||
TRY(builder.try_appendff("{}.{}", calculation_variable_name, "matches_resolution()"sv));
|
||||
} else if (allowed_type_name == "<time>"sv) {
|
||||
TRY(builder.try_appendff("{}.{}", calculation_variable_name, "matches_time()"sv));
|
||||
} else {
|
||||
dbgln("I don't know what '{}' is!", allowed_type_name);
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
ErrorOr<void> generate_implementation_file(JsonObject& functions_data, Core::File& file)
|
||||
{
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
|
||||
TRY(generator.try_append(R"~~~(
|
||||
// This file is generated by GenerateCSSMathFunctions.cpp
|
||||
|
||||
#include <AK/Debug.h>
|
||||
#include <LibWeb/CSS/MathFunctions.h>
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/Enums.h>
|
||||
#include <LibWeb/CSS/StyleValues/CalculatedStyleValue.h>
|
||||
|
||||
namespace Web::CSS::Parser {
|
||||
|
||||
static Optional<RoundingStrategy> parse_rounding_strategy(Vector<ComponentValue> const& tokens)
|
||||
{
|
||||
auto stream = TokenStream { tokens };
|
||||
stream.skip_whitespace();
|
||||
if (!stream.has_next_token())
|
||||
return {};
|
||||
|
||||
auto& ident = stream.next_token();
|
||||
if (!ident.is(Token::Type::Ident))
|
||||
return {};
|
||||
|
||||
stream.skip_whitespace();
|
||||
if (stream.has_next_token())
|
||||
return {};
|
||||
|
||||
auto maybe_identifier = value_id_from_string(ident.token().ident());
|
||||
if (!maybe_identifier.has_value())
|
||||
return {};
|
||||
|
||||
return value_id_to_rounding_strategy(maybe_identifier.value());
|
||||
}
|
||||
|
||||
ErrorOr<OwnPtr<CalculationNode>> Parser::parse_math_function(PropertyID property_id, Function const& function)
|
||||
{
|
||||
TokenStream stream { function.values() };
|
||||
auto arguments = parse_a_comma_separated_list_of_component_values(stream);
|
||||
)~~~"));
|
||||
|
||||
TRY(functions_data.try_for_each_member([&](auto& name, JsonValue const& value) -> ErrorOr<void> {
|
||||
auto& function_data = value.as_object();
|
||||
auto& parameters = function_data.get_array("parameters"sv).value();
|
||||
|
||||
auto function_generator = TRY(generator.fork());
|
||||
TRY(function_generator.set("name:lowercase", TRY(String::from_deprecated_string(name))));
|
||||
TRY(function_generator.set("name:titlecase", TRY(title_casify(name))));
|
||||
TRY(function_generator.try_appendln(" if (function.name().equals_ignoring_ascii_case(\"@name:lowercase@\"sv)) {"));
|
||||
if (function_data.get_bool("is-variadic"sv).value_or(false)) {
|
||||
// Variadic function
|
||||
TRY(function_generator.try_append(R"~~~(
|
||||
CSSNumericType determined_argument_type;
|
||||
Vector<NonnullOwnPtr<CalculationNode>> parsed_arguments;
|
||||
TRY(parsed_arguments.try_ensure_capacity(arguments.size()));
|
||||
|
||||
for (auto& argument : arguments) {
|
||||
auto calculation_node = TRY(parse_a_calculation(argument));
|
||||
if (!calculation_node) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "@name:lowercase@() argument #{} is not a valid calculation", parsed_arguments.size());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto maybe_argument_type = calculation_node->determine_type(m_context.current_property_id());
|
||||
if (!maybe_argument_type.has_value()) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "@name:lowercase@() argument #{} couldn't determine its type", parsed_arguments.size());
|
||||
return nullptr;
|
||||
}
|
||||
auto argument_type = maybe_argument_type.release_value();
|
||||
|
||||
)~~~"));
|
||||
// Generate some type checks
|
||||
VERIFY(parameters.size() == 1);
|
||||
auto& parameter_data = parameters[0].as_object();
|
||||
auto parameter_type_string = parameter_data.get_deprecated_string("type"sv).value();
|
||||
TRY(function_generator.set("type_check", TRY(generate_calculation_type_check("argument_type"sv, parameter_type_string))));
|
||||
TRY(function_generator.try_append(R"~~~(
|
||||
if (!(@type_check@)) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "@name:lowercase@() argument #{} type ({}) is not an accepted type", parsed_arguments.size(), MUST(argument_type.dump()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (parsed_arguments.is_empty()) {
|
||||
determined_argument_type = move(argument_type);
|
||||
} else {
|
||||
if (determined_argument_type != argument_type) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "@name:lowercase@() argument #{} type ({}) doesn't match type of previous arguments ({})", parsed_arguments.size(), MUST(argument_type.dump()), MUST(determined_argument_type.dump()));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TRY(parsed_arguments.try_append(calculation_node.release_nonnull()));
|
||||
}
|
||||
|
||||
return @name:titlecase@CalculationNode::create(move(parsed_arguments));
|
||||
}
|
||||
)~~~"));
|
||||
|
||||
} else {
|
||||
// Function with specified parameters.
|
||||
size_t min_argument_count = 0;
|
||||
size_t max_argument_count = parameters.size();
|
||||
parameters.for_each([&](JsonValue const& parameter_value) {
|
||||
auto& parameter = parameter_value.as_object();
|
||||
if (parameter.get_bool("required"sv) == true)
|
||||
min_argument_count++;
|
||||
});
|
||||
TRY(function_generator.set("min_argument_count", TRY(String::number(min_argument_count))));
|
||||
TRY(function_generator.set("max_argument_count", TRY(String::number(max_argument_count))));
|
||||
|
||||
TRY(function_generator.try_append(R"~~~(
|
||||
if (arguments.size() < @min_argument_count@ || arguments.size() > @max_argument_count@) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "@name:lowercase@() has wrong number of arguments {}, expected between @min_argument_count@ and @max_argument_count@ inclusive", arguments.size());
|
||||
return nullptr;
|
||||
}
|
||||
size_t argument_index = 0;
|
||||
[[maybe_unused]] CSSNumericType previous_argument_type;
|
||||
)~~~"));
|
||||
|
||||
size_t parameter_index = 0;
|
||||
StringView previous_parameter_type_string;
|
||||
TRY(parameters.try_for_each([&](JsonValue const& parameter_value) -> ErrorOr<void> {
|
||||
auto& parameter = parameter_value.as_object();
|
||||
auto parameter_type_string = parameter.get_deprecated_string("type"sv).value();
|
||||
auto parameter_required = parameter.get_bool("required"sv).value();
|
||||
|
||||
auto parameter_generator = TRY(function_generator.fork());
|
||||
TRY(parameter_generator.set("parameter_name", TRY(String::from_deprecated_string(parameter.get_deprecated_string("name"sv).value()))));
|
||||
TRY(parameter_generator.set("parameter_index", TRY(String::number(parameter_index))));
|
||||
|
||||
bool parameter_is_calculation;
|
||||
if (parameter_type_string == "<rounding-strategy>") {
|
||||
parameter_is_calculation = false;
|
||||
TRY(parameter_generator.set("parameter_type", TRY("RoundingStrategy"_string)));
|
||||
TRY(parameter_generator.set("parse_function", TRY("parse_rounding_strategy(arguments[argument_index])"_string)));
|
||||
TRY(parameter_generator.set("check_function", TRY(".has_value()"_string)));
|
||||
TRY(parameter_generator.set("release_function", TRY(".release_value()"_string)));
|
||||
if (auto default_value = parameter.get_deprecated_string("default"sv); default_value.has_value()) {
|
||||
TRY(parameter_generator.set("parameter_default", TRY(String::formatted(" = RoundingStrategy::{}", TRY(title_casify(default_value.value()))))));
|
||||
} else {
|
||||
TRY(parameter_generator.set("parameter_default", ""_short_string));
|
||||
}
|
||||
} else {
|
||||
// NOTE: This assumes everything not handled above is a calculation node of some kind.
|
||||
parameter_is_calculation = true;
|
||||
TRY(parameter_generator.set("parameter_type", TRY("OwnPtr<CalculationNode>"_string)));
|
||||
TRY(parameter_generator.set("parse_function", TRY("TRY(parse_a_calculation(arguments[argument_index]))"_string)));
|
||||
TRY(parameter_generator.set("check_function", TRY(" != nullptr"_string)));
|
||||
TRY(parameter_generator.set("release_function", TRY(".release_nonnull()"_string)));
|
||||
|
||||
// NOTE: We have exactly one default value in the data right now, and it's a `<calc-constant>`,
|
||||
// so that's all we handle.
|
||||
if (auto default_value = parameter.get_deprecated_string("default"sv); default_value.has_value()) {
|
||||
TRY(parameter_generator.set("parameter_default", TRY(String::formatted(" = TRY(ConstantCalculationNode::create(CalculationNode::constant_type_from_string(\"{}\"sv).value()))", TRY(String::from_deprecated_string(default_value.value()))))));
|
||||
} else {
|
||||
TRY(parameter_generator.set("parameter_default", ""_short_string));
|
||||
}
|
||||
}
|
||||
|
||||
TRY(parameter_generator.try_append(R"~~~(
|
||||
@parameter_type@ parameter_@parameter_index@@parameter_default@;
|
||||
)~~~"));
|
||||
|
||||
if (parameter_required) {
|
||||
TRY(parameter_generator.try_append(R"~~~(
|
||||
if (argument_index >= arguments.size()) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "@name:lowercase@() missing required argument '@parameter_name@'");
|
||||
return nullptr;
|
||||
} else {
|
||||
)~~~"));
|
||||
} else {
|
||||
TRY(parameter_generator.try_append(R"~~~(
|
||||
if (argument_index < arguments.size()) {
|
||||
)~~~"));
|
||||
}
|
||||
|
||||
TRY(parameter_generator.try_append(R"~~~(
|
||||
auto maybe_parsed_argument_@parameter_index@ = @parse_function@;
|
||||
if (maybe_parsed_argument_@parameter_index@@check_function@) {
|
||||
parameter_@parameter_index@ = maybe_parsed_argument_@parameter_index@@release_function@;
|
||||
argument_index++;
|
||||
)~~~"));
|
||||
if (parameter_required) {
|
||||
TRY(parameter_generator.try_append(R"~~~(
|
||||
} else {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "@name:lowercase@() required argument '@parameter_name@' failed to parse");
|
||||
return nullptr;
|
||||
)~~~"));
|
||||
}
|
||||
TRY(parameter_generator.try_append(R"~~~(
|
||||
}
|
||||
}
|
||||
)~~~"));
|
||||
|
||||
if (parameter_is_calculation) {
|
||||
auto parameter_type_variable = TRY(String::formatted("argument_type_{}", parameter_index));
|
||||
TRY(parameter_generator.set("type_check", TRY(generate_calculation_type_check(parameter_type_variable, parameter_type_string))));
|
||||
TRY(parameter_generator.try_append(R"~~~(
|
||||
auto maybe_argument_type_@parameter_index@ = parameter_@parameter_index@->determine_type(property_id);
|
||||
if (!maybe_argument_type_@parameter_index@.has_value()) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "@name:lowercase@() argument '@parameter_name@' couldn't determine its type");
|
||||
return nullptr;
|
||||
}
|
||||
auto argument_type_@parameter_index@ = maybe_argument_type_@parameter_index@.release_value();
|
||||
|
||||
if (!(@type_check@)) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "@name:lowercase@() argument '@parameter_name@' type ({}) is not an accepted type", MUST(argument_type_@parameter_index@.dump()));
|
||||
return nullptr;
|
||||
}
|
||||
)~~~"));
|
||||
|
||||
// NOTE: In all current cases, the parameters that take the same types must resolve to the same CSSNumericType.
|
||||
// This is a bit of a hack, but serves our needs for now.
|
||||
if (previous_parameter_type_string == parameter_type_string) {
|
||||
TRY(parameter_generator.try_append(R"~~~(
|
||||
if (argument_type_@parameter_index@ != previous_argument_type) {
|
||||
dbgln_if(CSS_PARSER_DEBUG, "@name:lowercase@() argument '@parameter_name@' type ({}) doesn't match type of previous arguments ({})", MUST(argument_type_@parameter_index@.dump()), MUST(previous_argument_type.dump()));
|
||||
return nullptr;
|
||||
}
|
||||
)~~~"));
|
||||
}
|
||||
TRY(parameter_generator.try_append(R"~~~(
|
||||
previous_argument_type = argument_type_@parameter_index@;
|
||||
)~~~"));
|
||||
}
|
||||
|
||||
parameter_index++;
|
||||
previous_parameter_type_string = parameter_type_string;
|
||||
return {};
|
||||
}));
|
||||
|
||||
// Generate the call to the constructor
|
||||
TRY(function_generator.try_append(" return @name:titlecase@CalculationNode::create("sv));
|
||||
parameter_index = 0;
|
||||
TRY(parameters.try_for_each([&](JsonValue const& parameter_value) -> ErrorOr<void> {
|
||||
auto& parameter = parameter_value.as_object();
|
||||
auto parameter_type_string = parameter.get_deprecated_string("type"sv).value();
|
||||
|
||||
auto parameter_generator = TRY(function_generator.fork());
|
||||
TRY(parameter_generator.set("parameter_index"sv, TRY(String::number(parameter_index))));
|
||||
|
||||
if (parameter_type_string == "<rounding-strategy>"sv) {
|
||||
TRY(parameter_generator.set("release_value"sv, ""_short_string));
|
||||
} else {
|
||||
// NOTE: This assumes everything not handled above is a calculation node of some kind.
|
||||
TRY(parameter_generator.set("release_value"sv, TRY(".release_nonnull()"_string)));
|
||||
}
|
||||
|
||||
if (parameter_index == 0) {
|
||||
TRY(parameter_generator.try_append("parameter_@parameter_index@@release_value@"sv));
|
||||
} else {
|
||||
TRY(parameter_generator.try_append(", parameter_@parameter_index@@release_value@"sv));
|
||||
}
|
||||
parameter_index++;
|
||||
return {};
|
||||
}));
|
||||
TRY(function_generator.try_append(R"~~~();
|
||||
}
|
||||
)~~~"));
|
||||
}
|
||||
return {};
|
||||
}));
|
||||
|
||||
TRY(generator.try_append(R"~~~(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
)~~~"));
|
||||
|
||||
TRY(file.write_until_depleted(generator.as_string_view().bytes()));
|
||||
return {};
|
||||
}
|
@ -615,6 +615,7 @@ set(GENERATED_SOURCES
|
||||
CSS/DefaultStyleSheetSource.cpp
|
||||
CSS/EasingFunctions.cpp
|
||||
CSS/Enums.cpp
|
||||
CSS/MathFunctions.cpp
|
||||
CSS/MediaFeatureID.cpp
|
||||
CSS/PropertyID.cpp
|
||||
CSS/QuirksModeStyleSheetSource.cpp
|
||||
|
232
Userland/Libraries/LibWeb/CSS/MathFunctions.json
Normal file
232
Userland/Libraries/LibWeb/CSS/MathFunctions.json
Normal file
@ -0,0 +1,232 @@
|
||||
{
|
||||
"abs": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"acos": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"asin": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"atan": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"atan2": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "y",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "x",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"clamp": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "min",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "central",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "max",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"cos": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>|<angle>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"exp": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"hypot": {
|
||||
"is-variadic": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"log": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "base",
|
||||
"type": "<number>",
|
||||
"required": false,
|
||||
"default": "e"
|
||||
}
|
||||
]
|
||||
},
|
||||
"max": {
|
||||
"is-variadic": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"min": {
|
||||
"is-variadic": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"mod": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "divisor",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"pow": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "exponent",
|
||||
"type": "<number>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"rem": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "divisor",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"round": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "strategy",
|
||||
"type": "<rounding-strategy>",
|
||||
"required": false,
|
||||
"default": "nearest"
|
||||
},
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "interval",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"sign": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>|<dimension>|<percentage>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"sin": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>|<angle>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"sqrt": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"tan": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "<number>|<angle>",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -290,6 +290,8 @@ private:
|
||||
ErrorOr<RefPtr<StyleValue>> parse_builtin_value(ComponentValue const&);
|
||||
ErrorOr<RefPtr<StyleValue>> parse_dynamic_value(ComponentValue const&);
|
||||
ErrorOr<RefPtr<CalculatedStyleValue>> parse_calculated_value(Vector<ComponentValue> const&);
|
||||
// NOTE: Implemented in generated code. (GenerateCSSMathFunctions.cpp)
|
||||
ErrorOr<OwnPtr<CalculationNode>> parse_math_function(PropertyID, Function const&);
|
||||
ErrorOr<OwnPtr<CalculationNode>> parse_a_calc_function_node(Function const&);
|
||||
ErrorOr<OwnPtr<CalculationNode>> parse_min_function(Function const&);
|
||||
ErrorOr<OwnPtr<CalculationNode>> parse_max_function(Function const&);
|
||||
|
Loading…
Reference in New Issue
Block a user