mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-19 07:33:20 +00:00
LibWeb/CSS: Promote <transform-list/function>
to parsable types
The `transform` property is now parsed based on its JSON data, and shouldn't behave any differently than before. This makes `<transform-list>` and `<transform-function>` work in the `syntax` descriptor for `@property`, and also means we know that `transform` can accept the `none` keyword. We get a few WPT passes out of that.
This commit is contained in:
parent
65ba5acf9d
commit
35fd3bda79
Notes:
github-actions[bot]
2025-10-14 12:43:05 +00:00
Author: https://github.com/AtkinsSJ
Commit: 35fd3bda79
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6466
8 changed files with 170 additions and 136 deletions
|
@ -484,7 +484,8 @@ private:
|
||||||
RefPtr<StyleValue const> parse_rotate_value(TokenStream<ComponentValue>&);
|
RefPtr<StyleValue const> parse_rotate_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<StyleValue const> parse_stroke_dasharray_value(TokenStream<ComponentValue>&);
|
RefPtr<StyleValue const> parse_stroke_dasharray_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<StyleValue const> parse_easing_value(TokenStream<ComponentValue>&);
|
RefPtr<StyleValue const> parse_easing_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<StyleValue const> parse_transform_value(TokenStream<ComponentValue>&);
|
RefPtr<StyleValue const> parse_transform_function_value(TokenStream<ComponentValue>&);
|
||||||
|
RefPtr<StyleValue const> parse_transform_list_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<StyleValue const> parse_transform_origin_value(TokenStream<ComponentValue>&);
|
RefPtr<StyleValue const> parse_transform_origin_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<StyleValue const> parse_transition_value(TokenStream<ComponentValue>&);
|
RefPtr<StyleValue const> parse_transition_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<StyleValue const> parse_transition_property_value(TokenStream<ComponentValue>&);
|
RefPtr<StyleValue const> parse_transition_property_value(TokenStream<ComponentValue>&);
|
||||||
|
|
|
@ -178,6 +178,10 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||||
return parsed.release_value();
|
return parsed.release_value();
|
||||||
if (auto parsed = parse_for_type(ValueType::String); parsed.has_value())
|
if (auto parsed = parse_for_type(ValueType::String); parsed.has_value())
|
||||||
return parsed.release_value();
|
return parsed.release_value();
|
||||||
|
if (auto parsed = parse_for_type(ValueType::TransformFunction); parsed.has_value())
|
||||||
|
return parsed.release_value();
|
||||||
|
if (auto parsed = parse_for_type(ValueType::TransformList); parsed.has_value())
|
||||||
|
return parsed.release_value();
|
||||||
if (auto parsed = parse_for_type(ValueType::Url); parsed.has_value())
|
if (auto parsed = parse_for_type(ValueType::Url); parsed.has_value())
|
||||||
return parsed.release_value();
|
return parsed.release_value();
|
||||||
|
|
||||||
|
@ -802,10 +806,6 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_css_value(Pr
|
||||||
if (auto parsed_value = parse_touch_action_value(tokens); parsed_value && !tokens.has_next_token())
|
if (auto parsed_value = parse_touch_action_value(tokens); parsed_value && !tokens.has_next_token())
|
||||||
return parsed_value.release_nonnull();
|
return parsed_value.release_nonnull();
|
||||||
return ParseError::SyntaxError;
|
return ParseError::SyntaxError;
|
||||||
case PropertyID::Transform:
|
|
||||||
if (auto parsed_value = parse_transform_value(tokens); parsed_value && !tokens.has_next_token())
|
|
||||||
return parsed_value.release_nonnull();
|
|
||||||
return ParseError::SyntaxError;
|
|
||||||
case PropertyID::TransformOrigin:
|
case PropertyID::TransformOrigin:
|
||||||
if (auto parsed_value = parse_transform_origin_value(tokens); parsed_value && !tokens.has_next_token())
|
if (auto parsed_value = parse_transform_origin_value(tokens); parsed_value && !tokens.has_next_token())
|
||||||
return parsed_value.release_nonnull();
|
return parsed_value.release_nonnull();
|
||||||
|
@ -4913,119 +4913,6 @@ RefPtr<StyleValue const> Parser::parse_touch_action_value(TokenStream<ComponentV
|
||||||
return StyleValueList::create(move(parsed_values), StyleValueList::Separator::Space);
|
return StyleValueList::create(move(parsed_values), StyleValueList::Separator::Space);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/css-transforms-1/#transform-property
|
|
||||||
RefPtr<StyleValue const> Parser::parse_transform_value(TokenStream<ComponentValue>& tokens)
|
|
||||||
{
|
|
||||||
// <transform> = none | <transform-list>
|
|
||||||
// <transform-list> = <transform-function>+
|
|
||||||
|
|
||||||
if (auto none = parse_all_as_single_keyword_value(tokens, Keyword::None))
|
|
||||||
return none;
|
|
||||||
|
|
||||||
StyleValueVector transformations;
|
|
||||||
auto transaction = tokens.begin_transaction();
|
|
||||||
while (tokens.has_next_token()) {
|
|
||||||
auto const& part = tokens.consume_a_token();
|
|
||||||
if (!part.is_function())
|
|
||||||
return nullptr;
|
|
||||||
auto maybe_function = transform_function_from_string(part.function().name);
|
|
||||||
if (!maybe_function.has_value())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
auto context_guard = push_temporary_value_parsing_context(FunctionContext { part.function().name });
|
|
||||||
|
|
||||||
auto function = maybe_function.release_value();
|
|
||||||
auto function_metadata = transform_function_metadata(function);
|
|
||||||
|
|
||||||
auto function_tokens = TokenStream { part.function().value };
|
|
||||||
auto arguments = parse_a_comma_separated_list_of_component_values(function_tokens);
|
|
||||||
|
|
||||||
if (arguments.size() > function_metadata.parameters.size()) {
|
|
||||||
ErrorReporter::the().report(InvalidValueError {
|
|
||||||
.value_type = "<transform-function>"_fly_string,
|
|
||||||
.value_string = part.function().original_source_text(),
|
|
||||||
.description = MUST(String::formatted("Too many arguments to {}. max: {}", part.function().name, function_metadata.parameters.size())),
|
|
||||||
});
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arguments.size() < function_metadata.parameters.size() && function_metadata.parameters[arguments.size()].required) {
|
|
||||||
ErrorReporter::the().report(InvalidValueError {
|
|
||||||
.value_type = "<transform-function>"_fly_string,
|
|
||||||
.value_string = part.function().original_source_text(),
|
|
||||||
.description = MUST(String::formatted("Required parameter at position {} is missing", arguments.size())),
|
|
||||||
});
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
StyleValueVector values;
|
|
||||||
for (auto argument_index = 0u; argument_index < arguments.size(); ++argument_index) {
|
|
||||||
TokenStream argument_tokens { arguments[argument_index] };
|
|
||||||
argument_tokens.discard_whitespace();
|
|
||||||
|
|
||||||
switch (function_metadata.parameters[argument_index].type) {
|
|
||||||
case TransformFunctionParameterType::Angle: {
|
|
||||||
// These are `<angle> | <zero>` in the spec, so we have to check for both kinds.
|
|
||||||
if (auto angle_value = parse_angle_value(argument_tokens)) {
|
|
||||||
values.append(angle_value.release_nonnull());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (argument_tokens.next_token().is(Token::Type::Number) && argument_tokens.next_token().token().number_value() == 0) {
|
|
||||||
argument_tokens.discard_a_token(); // 0
|
|
||||||
values.append(AngleStyleValue::create(Angle::make_degrees(0)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
case TransformFunctionParameterType::Length:
|
|
||||||
case TransformFunctionParameterType::LengthNone: {
|
|
||||||
if (auto length_value = parse_length_value(argument_tokens)) {
|
|
||||||
values.append(length_value.release_nonnull());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (function_metadata.parameters[argument_index].type == TransformFunctionParameterType::LengthNone
|
|
||||||
&& argument_tokens.next_token().is_ident("none"sv)) {
|
|
||||||
|
|
||||||
argument_tokens.discard_a_token(); // none
|
|
||||||
values.append(KeywordStyleValue::create(Keyword::None));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
case TransformFunctionParameterType::LengthPercentage: {
|
|
||||||
if (auto length_percentage_value = parse_length_percentage_value(argument_tokens)) {
|
|
||||||
values.append(length_percentage_value.release_nonnull());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
case TransformFunctionParameterType::Number: {
|
|
||||||
if (auto number_value = parse_number_value(argument_tokens)) {
|
|
||||||
values.append(number_value.release_nonnull());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
case TransformFunctionParameterType::NumberPercentage: {
|
|
||||||
if (auto number_percentage_value = parse_number_percentage_value(argument_tokens)) {
|
|
||||||
values.append(number_percentage_value.release_nonnull());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
argument_tokens.discard_whitespace();
|
|
||||||
if (argument_tokens.has_next_token())
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
transformations.append(TransformationStyleValue::create(PropertyID::Transform, function, move(values)));
|
|
||||||
}
|
|
||||||
transaction.commit();
|
|
||||||
return StyleValueList::create(move(transformations), StyleValueList::Separator::Space);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://www.w3.org/TR/css-transforms-1/#propdef-transform-origin
|
// https://www.w3.org/TR/css-transforms-1/#propdef-transform-origin
|
||||||
RefPtr<StyleValue const> Parser::parse_transform_origin_value(TokenStream<ComponentValue>& tokens)
|
RefPtr<StyleValue const> Parser::parse_transform_origin_value(TokenStream<ComponentValue>& tokens)
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
#include <LibWeb/CSS/StyleValues/StyleValueList.h>
|
#include <LibWeb/CSS/StyleValues/StyleValueList.h>
|
||||||
#include <LibWeb/CSS/StyleValues/SuperellipseStyleValue.h>
|
#include <LibWeb/CSS/StyleValues/SuperellipseStyleValue.h>
|
||||||
#include <LibWeb/CSS/StyleValues/TimeStyleValue.h>
|
#include <LibWeb/CSS/StyleValues/TimeStyleValue.h>
|
||||||
|
#include <LibWeb/CSS/StyleValues/TransformationStyleValue.h>
|
||||||
#include <LibWeb/CSS/StyleValues/URLStyleValue.h>
|
#include <LibWeb/CSS/StyleValues/URLStyleValue.h>
|
||||||
#include <LibWeb/CSS/StyleValues/UnicodeRangeStyleValue.h>
|
#include <LibWeb/CSS/StyleValues/UnicodeRangeStyleValue.h>
|
||||||
#include <LibWeb/CSS/StyleValues/UnresolvedStyleValue.h>
|
#include <LibWeb/CSS/StyleValues/UnresolvedStyleValue.h>
|
||||||
|
@ -4700,6 +4701,131 @@ NonnullRefPtr<StyleValue const> Parser::resolve_unresolved_style_value(DOM::Abst
|
||||||
return parsed_value.release_value();
|
return parsed_value.release_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/css-transforms-1/#typedef-transform-function
|
||||||
|
RefPtr<StyleValue const> Parser::parse_transform_function_value(TokenStream<ComponentValue>& tokens)
|
||||||
|
{
|
||||||
|
auto transaction = tokens.begin_transaction();
|
||||||
|
tokens.discard_whitespace();
|
||||||
|
auto const& part = tokens.consume_a_token();
|
||||||
|
if (!part.is_function())
|
||||||
|
return nullptr;
|
||||||
|
auto maybe_function = transform_function_from_string(part.function().name);
|
||||||
|
if (!maybe_function.has_value())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { part.function().name });
|
||||||
|
|
||||||
|
auto function = maybe_function.release_value();
|
||||||
|
auto function_metadata = transform_function_metadata(function);
|
||||||
|
|
||||||
|
auto function_tokens = TokenStream { part.function().value };
|
||||||
|
auto arguments = parse_a_comma_separated_list_of_component_values(function_tokens);
|
||||||
|
|
||||||
|
if (arguments.size() > function_metadata.parameters.size()) {
|
||||||
|
ErrorReporter::the().report(InvalidValueError {
|
||||||
|
.value_type = "<transform-function>"_fly_string,
|
||||||
|
.value_string = part.function().original_source_text(),
|
||||||
|
.description = MUST(String::formatted("Too many arguments to {}. max: {}", part.function().name, function_metadata.parameters.size())),
|
||||||
|
});
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments.size() < function_metadata.parameters.size() && function_metadata.parameters[arguments.size()].required) {
|
||||||
|
ErrorReporter::the().report(InvalidValueError {
|
||||||
|
.value_type = "<transform-function>"_fly_string,
|
||||||
|
.value_string = part.function().original_source_text(),
|
||||||
|
.description = MUST(String::formatted("Required parameter at position {} is missing", arguments.size())),
|
||||||
|
});
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
StyleValueVector values;
|
||||||
|
for (auto argument_index = 0u; argument_index < arguments.size(); ++argument_index) {
|
||||||
|
TokenStream argument_tokens { arguments[argument_index] };
|
||||||
|
argument_tokens.discard_whitespace();
|
||||||
|
|
||||||
|
switch (function_metadata.parameters[argument_index].type) {
|
||||||
|
case TransformFunctionParameterType::Angle: {
|
||||||
|
// These are `<angle> | <zero>` in the spec, so we have to check for both kinds.
|
||||||
|
if (auto angle_value = parse_angle_value(argument_tokens)) {
|
||||||
|
values.append(angle_value.release_nonnull());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (argument_tokens.next_token().is(Token::Type::Number) && argument_tokens.next_token().token().number_value() == 0) {
|
||||||
|
argument_tokens.discard_a_token(); // 0
|
||||||
|
values.append(AngleStyleValue::create(Angle::make_degrees(0)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
case TransformFunctionParameterType::Length:
|
||||||
|
case TransformFunctionParameterType::LengthNone: {
|
||||||
|
if (auto length_value = parse_length_value(argument_tokens)) {
|
||||||
|
values.append(length_value.release_nonnull());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (function_metadata.parameters[argument_index].type == TransformFunctionParameterType::LengthNone
|
||||||
|
&& argument_tokens.next_token().is_ident("none"sv)) {
|
||||||
|
|
||||||
|
argument_tokens.discard_a_token(); // none
|
||||||
|
values.append(KeywordStyleValue::create(Keyword::None));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
case TransformFunctionParameterType::LengthPercentage: {
|
||||||
|
if (auto length_percentage_value = parse_length_percentage_value(argument_tokens)) {
|
||||||
|
values.append(length_percentage_value.release_nonnull());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
case TransformFunctionParameterType::Number: {
|
||||||
|
if (auto number_value = parse_number_value(argument_tokens)) {
|
||||||
|
values.append(number_value.release_nonnull());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
case TransformFunctionParameterType::NumberPercentage: {
|
||||||
|
if (auto number_percentage_value = parse_number_percentage_value(argument_tokens)) {
|
||||||
|
values.append(number_percentage_value.release_nonnull());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argument_tokens.discard_whitespace();
|
||||||
|
if (argument_tokens.has_next_token())
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.commit();
|
||||||
|
return TransformationStyleValue::create(PropertyID::Transform, function, move(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/css-transforms-1/#typedef-transform-list
|
||||||
|
RefPtr<StyleValue const> Parser::parse_transform_list_value(TokenStream<ComponentValue>& tokens)
|
||||||
|
{
|
||||||
|
// <transform-list> = <transform-function>+
|
||||||
|
// https://www.w3.org/TR/css-transforms-1/#transform-property
|
||||||
|
StyleValueVector transformations;
|
||||||
|
auto transaction = tokens.begin_transaction();
|
||||||
|
while (tokens.has_next_token()) {
|
||||||
|
if (auto maybe_function = parse_transform_function_value(tokens)) {
|
||||||
|
transformations.append(maybe_function.release_nonnull());
|
||||||
|
tokens.discard_whitespace();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (transformations.is_empty())
|
||||||
|
return {};
|
||||||
|
transaction.commit();
|
||||||
|
return StyleValueList::create(move(transformations), StyleValueList::Separator::Space);
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<StyleValue const> Parser::parse_value(ValueType value_type, TokenStream<ComponentValue>& tokens)
|
RefPtr<StyleValue const> Parser::parse_value(ValueType value_type, TokenStream<ComponentValue>& tokens)
|
||||||
{
|
{
|
||||||
switch (value_type) {
|
switch (value_type) {
|
||||||
|
@ -4758,6 +4884,10 @@ RefPtr<StyleValue const> Parser::parse_value(ValueType value_type, TokenStream<C
|
||||||
return parse_string_value(tokens);
|
return parse_string_value(tokens);
|
||||||
case ValueType::Time:
|
case ValueType::Time:
|
||||||
return parse_time_value(tokens);
|
return parse_time_value(tokens);
|
||||||
|
case ValueType::TransformFunction:
|
||||||
|
return parse_transform_function_value(tokens);
|
||||||
|
case ValueType::TransformList:
|
||||||
|
return parse_transform_list_value(tokens);
|
||||||
case ValueType::Url:
|
case ValueType::Url:
|
||||||
return parse_url_value(tokens);
|
return parse_url_value(tokens);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3783,7 +3783,13 @@
|
||||||
"affects-layout": false,
|
"affects-layout": false,
|
||||||
"affects-stacking-context": true,
|
"affects-stacking-context": true,
|
||||||
"percentages-resolve-to": "length",
|
"percentages-resolve-to": "length",
|
||||||
"multiplicity": "list"
|
"multiplicity": "list",
|
||||||
|
"valid-types": [
|
||||||
|
"transform-list"
|
||||||
|
],
|
||||||
|
"valid-identifiers": [
|
||||||
|
"none"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"transform-box": {
|
"transform-box": {
|
||||||
"animation-type": "discrete",
|
"animation-type": "discrete",
|
||||||
|
|
|
@ -61,6 +61,10 @@ Optional<ValueType> value_type_from_string(StringView string)
|
||||||
return ValueType::String;
|
return ValueType::String;
|
||||||
if (string.equals_ignoring_ascii_case("time"sv))
|
if (string.equals_ignoring_ascii_case("time"sv))
|
||||||
return ValueType::Time;
|
return ValueType::Time;
|
||||||
|
if (string.equals_ignoring_ascii_case("transform-function"sv))
|
||||||
|
return ValueType::TransformFunction;
|
||||||
|
if (string.equals_ignoring_ascii_case("transform-list"sv))
|
||||||
|
return ValueType::TransformList;
|
||||||
if (string.equals_ignoring_ascii_case("url"sv))
|
if (string.equals_ignoring_ascii_case("url"sv))
|
||||||
return ValueType::Url;
|
return ValueType::Url;
|
||||||
return {};
|
return {};
|
||||||
|
@ -123,6 +127,10 @@ StringView value_type_to_string(ValueType value_type)
|
||||||
return "String"sv;
|
return "String"sv;
|
||||||
case Web::CSS::ValueType::Time:
|
case Web::CSS::ValueType::Time:
|
||||||
return "Time"sv;
|
return "Time"sv;
|
||||||
|
case Web::CSS::ValueType::TransformFunction:
|
||||||
|
return "TransformFunction"sv;
|
||||||
|
case Web::CSS::ValueType::TransformList:
|
||||||
|
return "TransformList"sv;
|
||||||
case Web::CSS::ValueType::Url:
|
case Web::CSS::ValueType::Url:
|
||||||
return "Url"sv;
|
return "Url"sv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,8 @@ enum class ValueType : u8 {
|
||||||
Resolution,
|
Resolution,
|
||||||
String,
|
String,
|
||||||
Time,
|
Time,
|
||||||
|
TransformFunction,
|
||||||
|
TransformList,
|
||||||
Url,
|
Url,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ Harness status: OK
|
||||||
|
|
||||||
Found 239 tests
|
Found 239 tests
|
||||||
|
|
||||||
177 Pass
|
189 Pass
|
||||||
62 Fail
|
50 Fail
|
||||||
Pass syntax:'*', initialValue:'a' is valid
|
Pass syntax:'*', initialValue:'a' is valid
|
||||||
Pass syntax:' * ', initialValue:'b' is valid
|
Pass syntax:' * ', initialValue:'b' is valid
|
||||||
Pass syntax:'<length>', initialValue:'2px' is valid
|
Pass syntax:'<length>', initialValue:'2px' is valid
|
||||||
|
@ -53,12 +53,12 @@ Pass syntax:'<time>', initialValue:'2s' is valid
|
||||||
Pass syntax:'<time>', initialValue:'calc(2s - 9ms)' is valid
|
Pass syntax:'<time>', initialValue:'calc(2s - 9ms)' is valid
|
||||||
Pass syntax:'<resolution>', initialValue:'10dpi' is valid
|
Pass syntax:'<resolution>', initialValue:'10dpi' is valid
|
||||||
Pass syntax:'<resolution>', initialValue:'3dPpX' is valid
|
Pass syntax:'<resolution>', initialValue:'3dPpX' is valid
|
||||||
Fail syntax:'<transform-function>', initialValue:'translateX(2px)' is valid
|
Pass syntax:'<transform-function>', initialValue:'translateX(2px)' is valid
|
||||||
Pass syntax:'<transform-function>|<integer>', initialValue:'5' is valid
|
Pass syntax:'<transform-function>|<integer>', initialValue:'5' is valid
|
||||||
Fail syntax:'<transform-function>|<integer>', initialValue:'scale(2)' is valid
|
Pass syntax:'<transform-function>|<integer>', initialValue:'scale(2)' is valid
|
||||||
Fail syntax:'<transform-function>+', initialValue:'translateX(2px) rotate(42deg)' is valid
|
Pass syntax:'<transform-function>+', initialValue:'translateX(2px) rotate(42deg)' is valid
|
||||||
Fail syntax:'<transform-list>', initialValue:'scale(2)' is valid
|
Pass syntax:'<transform-list>', initialValue:'scale(2)' is valid
|
||||||
Fail syntax:'<transform-list>', initialValue:'translateX(2px) rotate(20deg)' is valid
|
Pass syntax:'<transform-list>', initialValue:'translateX(2px) rotate(20deg)' is valid
|
||||||
Pass syntax:'<string>', initialValue:''foo bar'' is valid
|
Pass syntax:'<string>', initialValue:''foo bar'' is valid
|
||||||
Fail syntax:'<string>', initialValue:' 'foo bar' ' is valid
|
Fail syntax:'<string>', initialValue:' 'foo bar' ' is valid
|
||||||
Pass syntax:'<string>', initialValue:''foo bar' is valid
|
Pass syntax:'<string>', initialValue:''foo bar' is valid
|
||||||
|
@ -94,15 +94,15 @@ Pass syntax:'yellow', initialValue:'yellow' is valid
|
||||||
Fail syntax:'yellow | <color>+', initialValue:'yellow blue' is valid
|
Fail syntax:'yellow | <color>+', initialValue:'yellow blue' is valid
|
||||||
Pass syntax:'<color># | yellow', initialValue:'yellow, blue' is valid
|
Pass syntax:'<color># | yellow', initialValue:'yellow, blue' is valid
|
||||||
Fail syntax:'yellow | <color>#', initialValue:'yellow, blue' is valid
|
Fail syntax:'yellow | <color>#', initialValue:'yellow, blue' is valid
|
||||||
Fail syntax:'<transform-list> | <transform-function> ', initialValue:'scale(2) rotate(90deg)' is valid
|
Pass syntax:'<transform-list> | <transform-function> ', initialValue:'scale(2) rotate(90deg)' is valid
|
||||||
Fail syntax:'<transform-function> | <transform-list>', initialValue:'scale(2) rotate(90deg)' is valid
|
Fail syntax:'<transform-function> | <transform-list>', initialValue:'scale(2) rotate(90deg)' is valid
|
||||||
Fail syntax:'<transform-list> | <transform-function>+ ', initialValue:'scale(2) rotate(90deg)' is valid
|
Pass syntax:'<transform-list> | <transform-function>+ ', initialValue:'scale(2) rotate(90deg)' is valid
|
||||||
Fail syntax:'<transform-function>+ | <transform-list>', initialValue:'scale(2) rotate(90deg)' is valid
|
Pass syntax:'<transform-function>+ | <transform-list>', initialValue:'scale(2) rotate(90deg)' is valid
|
||||||
Fail syntax:'<transform-list> | <transform-function># ', initialValue:'scale(2) rotate(90deg)' is valid
|
Pass syntax:'<transform-list> | <transform-function># ', initialValue:'scale(2) rotate(90deg)' is valid
|
||||||
Fail syntax:'<transform-function># | <transform-list>', initialValue:'scale(2) rotate(90deg)' is valid
|
Pass syntax:'<transform-function># | <transform-list>', initialValue:'scale(2) rotate(90deg)' is valid
|
||||||
Fail syntax:'<transform-list> | <transform-function># ', initialValue:'scale(2), rotate(90deg)' is valid
|
Fail syntax:'<transform-list> | <transform-function># ', initialValue:'scale(2), rotate(90deg)' is valid
|
||||||
Fail syntax:'<transform-function># | <transform-list>', initialValue:'scale(2), rotate(90deg)' is valid
|
Pass syntax:'<transform-function># | <transform-list>', initialValue:'scale(2), rotate(90deg)' is valid
|
||||||
Fail syntax:'<transform-list>', initialValue:'scale(2) rotate(90deg) ' is valid
|
Pass syntax:'<transform-list>', initialValue:'scale(2) rotate(90deg) ' is valid
|
||||||
Pass syntax:'<integer>+ | <percentage>+ | <length>+ ', initialValue:'1' is valid
|
Pass syntax:'<integer>+ | <percentage>+ | <length>+ ', initialValue:'1' is valid
|
||||||
Pass syntax:'<integer>+ | <percentage>+ | <length>+ ', initialValue:'1 1' is valid
|
Pass syntax:'<integer>+ | <percentage>+ | <length>+ ', initialValue:'1 1' is valid
|
||||||
Pass syntax:'<integer>+ | <percentage>+ | <length>+ ', initialValue:'1%' is valid
|
Pass syntax:'<integer>+ | <percentage>+ | <length>+ ', initialValue:'1%' is valid
|
||||||
|
|
|
@ -2,14 +2,14 @@ Harness status: OK
|
||||||
|
|
||||||
Found 33 tests
|
Found 33 tests
|
||||||
|
|
||||||
27 Pass
|
28 Pass
|
||||||
6 Fail
|
5 Fail
|
||||||
Pass Can set 'transform' to CSS-wide keywords: initial
|
Pass Can set 'transform' to CSS-wide keywords: initial
|
||||||
Pass Can set 'transform' to CSS-wide keywords: inherit
|
Pass Can set 'transform' to CSS-wide keywords: inherit
|
||||||
Pass Can set 'transform' to CSS-wide keywords: unset
|
Pass Can set 'transform' to CSS-wide keywords: unset
|
||||||
Pass Can set 'transform' to CSS-wide keywords: revert
|
Pass Can set 'transform' to CSS-wide keywords: revert
|
||||||
Fail Can set 'transform' to var() references: var(--A)
|
Fail Can set 'transform' to var() references: var(--A)
|
||||||
Fail Can set 'transform' to the 'none' keyword: none
|
Pass Can set 'transform' to the 'none' keyword: none
|
||||||
Fail Can set 'transform' to a transform: translate(50%, 50%)
|
Fail Can set 'transform' to a transform: translate(50%, 50%)
|
||||||
Fail Can set 'transform' to a transform: perspective(10em)
|
Fail Can set 'transform' to a transform: perspective(10em)
|
||||||
Fail Can set 'transform' to a transform: translate3d(0px, 1px, 2px) translate(0px, 1px) rotate3d(1, 2, 3, 45deg) rotate(45deg) scale3d(1, 2, 3) scale(1, 2) skew(1deg, 1deg) skewX(1deg) skewY(45deg) perspective(1px) matrix3d(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) matrix(1, 2, 3, 4, 5, 6)
|
Fail Can set 'transform' to a transform: translate3d(0px, 1px, 2px) translate(0px, 1px) rotate3d(1, 2, 3, 45deg) rotate(45deg) scale3d(1, 2, 3) scale(1, 2) skew(1deg, 1deg) skewX(1deg) skewY(45deg) perspective(1px) matrix3d(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) matrix(1, 2, 3, 4, 5, 6)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue