mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-28 05:07:35 +00:00
LibWeb/CSS: Parse initial value using syntax from @property
Now we pass all WPT tests in: `css/css-properties-values-api/at-property-cssom`. Note: Failing tests were false positives. Proper handling of inheriting values and detecting computational independence will be done in another PR.
This commit is contained in:
parent
31536c53a2
commit
190745fd58
Notes:
github-actions[bot]
2025-08-04 10:10:06 +00:00
Author: https://github.com/Norbiros
Commit: 190745fd58
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5638
Reviewed-by: https://github.com/AtkinsSJ ✅
5 changed files with 278 additions and 13 deletions
|
@ -30,6 +30,8 @@
|
|||
#include <LibWeb/CSS/FontFace.h>
|
||||
#include <LibWeb/CSS/Parser/ErrorReporter.h>
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/Parser/Syntax.h>
|
||||
#include <LibWeb/CSS/Parser/SyntaxParsing.h>
|
||||
#include <LibWeb/CSS/PropertyName.h>
|
||||
#include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/CustomIdentStyleValue.h>
|
||||
|
@ -747,12 +749,40 @@ GC::Ptr<CSSPropertyRule> Parser::convert_to_property_rule(AtRule const& rule)
|
|||
}
|
||||
});
|
||||
|
||||
// TODO: Parse the initial value using the syntax, if it's provided.
|
||||
|
||||
if (syntax_maybe.has_value() && inherits_maybe.has_value()) {
|
||||
return CSSPropertyRule::create(realm(), name, syntax_maybe.value(), inherits_maybe.value(), move(initial_value_maybe));
|
||||
// @property rules require a syntax and inherits descriptor; if either are missing, the entire rule is invalid and must be ignored.
|
||||
if (!syntax_maybe.has_value() || syntax_maybe->is_empty() || !inherits_maybe.has_value()) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
|
||||
auto parsing_params = CSS::Parser::ParsingParams { *document() };
|
||||
auto syntax_component_values = parse_component_values_list(parsing_params, syntax_maybe.value());
|
||||
auto maybe_syntax = parse_as_syntax(syntax_component_values);
|
||||
|
||||
// If the provided string is not a valid syntax string (if it returns failure when consume
|
||||
// a syntax definition is called on it), the descriptor is invalid and must be ignored.
|
||||
if (!maybe_syntax) {
|
||||
return {};
|
||||
}
|
||||
// The initial-value descriptor is optional only if the syntax is the universal syntax definition,
|
||||
// otherwise the descriptor is required; if it’s missing, the entire rule is invalid and must be ignored.
|
||||
if (!initial_value_maybe && maybe_syntax->type() != CSS::Parser::SyntaxNode::NodeType::Universal) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (initial_value_maybe) {
|
||||
initial_value_maybe = Web::CSS::Parser::parse_with_a_syntax(parsing_params, initial_value_maybe->tokenize(), *maybe_syntax);
|
||||
// Otherwise, if the value of the syntax descriptor is not the universal syntax definition,
|
||||
// the following conditions must be met for the @property rule to be valid:
|
||||
// - The initial-value descriptor must be present.
|
||||
// - The initial-value descriptor’s value must parse successfully according to the grammar specified by the syntax definition.
|
||||
// - FIXME: The initial-value must be computationally independent.
|
||||
|
||||
if (!initial_value_maybe || initial_value_maybe->is_guaranteed_invalid()) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return CSSPropertyRule::create(realm(), name, syntax_maybe.value(), inherits_maybe.value(), move(initial_value_maybe));
|
||||
}
|
||||
|
||||
GC::Ptr<CSSFontFaceRule> Parser::convert_to_font_face_rule(AtRule const& rule)
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 39 tests
|
||||
|
||||
39 Pass
|
||||
Pass Rule for --no-descriptors is invalid
|
||||
Pass Rule for --no-syntax is invalid
|
||||
Pass Rule for --no-inherits is invalid
|
||||
Pass Rule for --no-initial-color-value is invalid
|
||||
Pass Rule for --syntax-only is invalid
|
||||
Pass Rule for --inherits-only is invalid
|
||||
Pass Rule for --initial-value-only is invalid
|
||||
Pass Rule for --valid has expected cssText
|
||||
Pass Rule for --valid-reverse has expected cssText
|
||||
Pass Rule for --valid-universal has expected cssText
|
||||
Pass Rule for --valid-whitespace has expected cssText
|
||||
Pass Rule for --vALId has expected cssText
|
||||
Pass Rule for --no-initial-universal-value has expected cssText
|
||||
Pass Rule for --tab tab has expected cssText
|
||||
Pass CSSRule.type returns 0
|
||||
Pass Rule for --valid returns expected value for CSSPropertyRule.name
|
||||
Pass Rule for --valid-reverse returns expected value for CSSPropertyRule.name
|
||||
Pass Rule for --valid-universal returns expected value for CSSPropertyRule.name
|
||||
Pass Rule for --valid-whitespace returns expected value for CSSPropertyRule.name
|
||||
Pass Rule for --vALId returns expected value for CSSPropertyRule.name
|
||||
Pass Rule for --no-initial-universal-value returns expected value for CSSPropertyRule.name
|
||||
Pass Rule for --valid returns expected value for CSSPropertyRule.syntax
|
||||
Pass Rule for --valid-reverse returns expected value for CSSPropertyRule.syntax
|
||||
Pass Rule for --valid-universal returns expected value for CSSPropertyRule.syntax
|
||||
Pass Rule for --valid-whitespace returns expected value for CSSPropertyRule.syntax
|
||||
Pass Rule for --vALId returns expected value for CSSPropertyRule.syntax
|
||||
Pass Rule for --no-initial-universal-value returns expected value for CSSPropertyRule.syntax
|
||||
Pass Rule for --valid returns expected value for CSSPropertyRule.inherits
|
||||
Pass Rule for --valid-reverse returns expected value for CSSPropertyRule.inherits
|
||||
Pass Rule for --valid-universal returns expected value for CSSPropertyRule.inherits
|
||||
Pass Rule for --valid-whitespace returns expected value for CSSPropertyRule.inherits
|
||||
Pass Rule for --vALId returns expected value for CSSPropertyRule.inherits
|
||||
Pass Rule for --no-initial-universal-value returns expected value for CSSPropertyRule.inherits
|
||||
Pass Rule for --valid returns expected value for CSSPropertyRule.initialValue
|
||||
Pass Rule for --valid-reverse returns expected value for CSSPropertyRule.initialValue
|
||||
Pass Rule for --valid-universal returns expected value for CSSPropertyRule.initialValue
|
||||
Pass Rule for --valid-whitespace returns expected value for CSSPropertyRule.initialValue
|
||||
Pass Rule for --vALId returns expected value for CSSPropertyRule.initialValue
|
||||
Pass Rule for --no-initial-universal-value returns expected value for CSSPropertyRule.initialValue
|
|
@ -2,8 +2,8 @@ Harness status: OK
|
|||
|
||||
Found 139 tests
|
||||
|
||||
130 Pass
|
||||
9 Fail
|
||||
128 Pass
|
||||
11 Fail
|
||||
Pass CSS Values and Units Test: attr
|
||||
Fail CSS Values and Units Test: attr 1
|
||||
Pass CSS Values and Units Test: attr 2
|
||||
|
@ -54,12 +54,12 @@ Pass CSS Values and Units Test: attr 46
|
|||
Pass CSS Values and Units Test: attr 47
|
||||
Pass CSS Values and Units Test: attr 48
|
||||
Pass CSS Values and Units Test: attr 49
|
||||
Pass CSS Values and Units Test: attr 50
|
||||
Fail CSS Values and Units Test: attr 50
|
||||
Fail CSS Values and Units Test: attr 51
|
||||
Pass CSS Values and Units Test: attr 52
|
||||
Pass CSS Values and Units Test: attr 53
|
||||
Pass CSS Values and Units Test: attr 54
|
||||
Pass CSS Values and Units Test: attr 55
|
||||
Fail CSS Values and Units Test: attr 55
|
||||
Pass CSS Values and Units Test: attr 56
|
||||
Pass CSS Values and Units Test: attr 57
|
||||
Pass CSS Values and Units Test: attr 58
|
||||
|
|
|
@ -2,15 +2,15 @@ Harness status: OK
|
|||
|
||||
Found 30 tests
|
||||
|
||||
11 Pass
|
||||
19 Fail
|
||||
9 Pass
|
||||
21 Fail
|
||||
Pass `initial` as a value for an unregistered custom property
|
||||
Pass `inherit` as a value for an unregistered custom property
|
||||
Pass `unset` as a value for an unregistered custom property
|
||||
Fail `revert` as a value for an unregistered custom property
|
||||
Pass `revert-layer` as a value for an unregistered custom property
|
||||
Pass `initial` as a value for a non-inheriting registered custom property
|
||||
Pass `initial` as a value for an inheriting registered custom property
|
||||
Fail `initial` as a value for a non-inheriting registered custom property
|
||||
Fail `initial` as a value for an inheriting registered custom property
|
||||
Pass `inherit` as a value for a non-inheriting registered custom property
|
||||
Pass `inherit` as a value for an inheriting registered custom property
|
||||
Fail `unset` as a value for a non-inheriting registered custom property
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#cssom">
|
||||
<script src="../../resources/testharness.js"></script>
|
||||
<script src="../../resources/testharnessreport.js"></script>
|
||||
<style>
|
||||
@property --valid {
|
||||
syntax: "<color> | none";
|
||||
inherits: false;
|
||||
initial-value: red;
|
||||
}
|
||||
@property --valid-reverse {
|
||||
initial-value: 0px;
|
||||
inherits: true;
|
||||
syntax: "<length>";
|
||||
}
|
||||
@property --valid-universal {
|
||||
syntax: "*";
|
||||
inherits: false;
|
||||
}
|
||||
@property --valid-whitespace {
|
||||
syntax: " <color># ";
|
||||
inherits: false;
|
||||
initial-value: red, blue;
|
||||
}
|
||||
@property --vALId {
|
||||
syntax: "<color> | none";
|
||||
inherits: false;
|
||||
initial-value: red;
|
||||
}
|
||||
@property --no-descriptors {
|
||||
|
||||
}
|
||||
@property --no-syntax {
|
||||
inherits: false;
|
||||
initial-value: red;
|
||||
}
|
||||
@property --no-inherits {
|
||||
syntax: "<color> | none";
|
||||
initial-value: red;
|
||||
}
|
||||
@property --no-initial-color-value {
|
||||
syntax: "<color> | none";
|
||||
inherits: false;
|
||||
}
|
||||
@property --no-initial-universal-value {
|
||||
syntax: "*";
|
||||
inherits: false;
|
||||
}
|
||||
@property --syntax-only {
|
||||
syntax: "<color> | none";
|
||||
}
|
||||
@property --inherits-only {
|
||||
inherits: true;
|
||||
}
|
||||
@property --initial-value-only {
|
||||
initial-value: red;
|
||||
}
|
||||
/* U+0009 CHARACTER TABULATION */
|
||||
@property --tab\9 tab {
|
||||
syntax: "*";
|
||||
inherits: true;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
|
||||
function find_at_property_rule(name) {
|
||||
for (let rule of document.styleSheets[0].cssRules) {
|
||||
if (rule.constructor.name != "CSSPropertyRule")
|
||||
continue;
|
||||
if (rule.name == name)
|
||||
return rule;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function test_invalid(name) {
|
||||
test(() => {
|
||||
let rule = find_at_property_rule(name);
|
||||
assert_true(!rule);
|
||||
}, `Rule for ${name} is invalid`);
|
||||
}
|
||||
|
||||
function test_css_text(name, expected) {
|
||||
test(() => {
|
||||
let rule = find_at_property_rule(name);
|
||||
assert_true(!!rule);
|
||||
assert_equals(rule.cssText, expected);
|
||||
}, `Rule for ${name} has expected cssText`);
|
||||
}
|
||||
|
||||
function test_name(name) {
|
||||
test(() => {
|
||||
let rule = find_at_property_rule(name);
|
||||
assert_true(!!rule);
|
||||
assert_equals(rule.name, name);
|
||||
}, `Rule for ${name} returns expected value for CSSPropertyRule.name`);
|
||||
}
|
||||
|
||||
function test_syntax(name, expected) {
|
||||
test(() => {
|
||||
let rule = find_at_property_rule(name);
|
||||
assert_true(!!rule);
|
||||
assert_equals(rule.syntax, expected);
|
||||
}, `Rule for ${name} returns expected value for CSSPropertyRule.syntax`);
|
||||
}
|
||||
|
||||
function test_inherits(name, expected) {
|
||||
test(() => {
|
||||
let rule = find_at_property_rule(name);
|
||||
assert_true(!!rule);
|
||||
assert_equals(rule.inherits, expected);
|
||||
}, `Rule for ${name} returns expected value for CSSPropertyRule.inherits`);
|
||||
}
|
||||
|
||||
function test_initial_value(name, expected) {
|
||||
test(() => {
|
||||
let rule = find_at_property_rule(name);
|
||||
assert_true(!!rule);
|
||||
assert_equals(rule.initialValue, expected);
|
||||
}, `Rule for ${name} returns expected value for CSSPropertyRule.initialValue`);
|
||||
}
|
||||
|
||||
// Invalid @property rules.
|
||||
test_invalid('--no-descriptors');
|
||||
test_invalid('--no-syntax');
|
||||
test_invalid('--no-inherits');
|
||||
test_invalid('--no-initial-color-value');
|
||||
test_invalid('--syntax-only', '@property --syntax-only { syntax: "<color> | none"; }');
|
||||
test_invalid('--inherits-only', '@property --inherits-only { inherits: true; }');
|
||||
test_invalid('--initial-value-only', '@property --initial-value-only { initial-value: red; }');
|
||||
|
||||
// CSSPropertyRule.cssText
|
||||
|
||||
test_css_text('--valid', '@property --valid { syntax: "<color> | none"; inherits: false; initial-value: red; }');
|
||||
test_css_text('--valid-reverse', '@property --valid-reverse { syntax: "<length>"; inherits: true; initial-value: 0px; }');
|
||||
test_css_text('--valid-universal', '@property --valid-universal { syntax: "*"; inherits: false; }');
|
||||
test_css_text('--valid-whitespace', '@property --valid-whitespace { syntax: " <color># "; inherits: false; initial-value: red, blue; }');
|
||||
test_css_text('--vALId', '@property --vALId { syntax: "<color> | none"; inherits: false; initial-value: red; }');
|
||||
|
||||
test_css_text('--no-initial-universal-value', '@property --no-initial-universal-value { syntax: "*"; inherits: false; }');
|
||||
|
||||
test_css_text('--tab\ttab', '@property --tab\\9 tab { syntax: "*"; inherits: true; }');
|
||||
|
||||
// CSSRule.type
|
||||
|
||||
test(() => {
|
||||
let rule = find_at_property_rule('--valid');
|
||||
assert_equals(rule.type, 0);
|
||||
}, 'CSSRule.type returns 0');
|
||||
|
||||
// CSSPropertyRule.name
|
||||
|
||||
test_name('--valid');
|
||||
test_name('--valid-reverse');
|
||||
test_name('--valid-universal');
|
||||
test_name('--valid-whitespace');
|
||||
test_name('--vALId');
|
||||
|
||||
test_name('--no-initial-universal-value');
|
||||
|
||||
// CSSPropertyRule.syntax
|
||||
|
||||
test_syntax('--valid', '<color> | none');
|
||||
test_syntax('--valid-reverse', '<length>');
|
||||
test_syntax('--valid-universal', '*');
|
||||
test_syntax('--valid-whitespace', ' <color># ');
|
||||
test_syntax('--vALId', '<color> | none');
|
||||
|
||||
test_syntax('--no-initial-universal-value', '*');
|
||||
|
||||
// CSSPropertyRule.inherits
|
||||
|
||||
test_inherits('--valid', false);
|
||||
test_inherits('--valid-reverse', true);
|
||||
test_inherits('--valid-universal', false);
|
||||
test_inherits('--valid-whitespace', false);
|
||||
test_inherits('--vALId', false);
|
||||
|
||||
test_inherits('--no-initial-universal-value', false);
|
||||
|
||||
// CSSPropertyRule.initialValue
|
||||
|
||||
test_initial_value('--valid', 'red');
|
||||
test_initial_value('--valid-reverse', '0px');
|
||||
test_initial_value('--valid-universal', null);
|
||||
test_initial_value('--valid-whitespace', 'red, blue');
|
||||
test_initial_value('--vALId', 'red');
|
||||
|
||||
test_initial_value('--no-initial-universal-value', null);
|
||||
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue