From 213a548b1f0d6c8601e29add21d3de8ba0467bf4 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 14 Aug 2025 13:55:45 +0100 Subject: [PATCH] LibWeb/CSS: Implement CSSStyleValue.parse() and .parseAll() The "subdivide into iterations" part is left as a FIXME for now, until we have a way of knowing if a property is a list or not. The parse_a_css_style_value() helper has an unwieldy return type because of the requirement that it return either one value or a list of values, but sticking to the spec here seems worthwhile for now. --- Libraries/LibWeb/CSS/CSSStyleValue.cpp | 55 +++++++++++++++++++ Libraries/LibWeb/CSS/CSSStyleValue.h | 9 +++ Libraries/LibWeb/CSS/CSSStyleValue.idl | 4 +- .../normalize-ident.tentative.txt | 5 +- .../css-typed-om/stylevalue-objects/parse.txt | 12 ++-- .../stylevalue-objects/parseAll.txt | 11 ++-- .../cssKeywordValue.tentative.txt | 5 +- .../cssStyleValue-string.txt | 6 +- 8 files changed, 85 insertions(+), 22 deletions(-) diff --git a/Libraries/LibWeb/CSS/CSSStyleValue.cpp b/Libraries/LibWeb/CSS/CSSStyleValue.cpp index c96c0c6319d..e731b89d0f7 100644 --- a/Libraries/LibWeb/CSS/CSSStyleValue.cpp +++ b/Libraries/LibWeb/CSS/CSSStyleValue.cpp @@ -7,6 +7,8 @@ #include "CSSStyleValue.h" #include #include +#include +#include #include namespace Web::CSS { @@ -36,6 +38,59 @@ void CSSStyleValue::initialize(JS::Realm& realm) Base::initialize(realm); } +// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssstylevalue-parse +WebIDL::ExceptionOr> CSSStyleValue::parse(JS::VM& vm, String property, String css_text) +{ + // The parse(property, cssText) method, when invoked, must parse a CSSStyleValue with property property, cssText + // cssText, and parseMultiple set to false, and return the result. + auto result = parse_a_css_style_value(vm, property, css_text, ParseMultiple::No); + if (result.is_exception()) + return result.release_error(); + return result.value().get>(); +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssstylevalue-parseall +WebIDL::ExceptionOr>> CSSStyleValue::parse_all(JS::VM& vm, String property, String css_text) +{ + // The parseAll(property, cssText) method, when invoked, must parse a CSSStyleValue with property property, cssText + // cssText, and parseMultiple set to true, and return the result. + auto result = parse_a_css_style_value(vm, property, css_text, ParseMultiple::Yes); + if (result.is_exception()) + return result.release_error(); + return result.value().get>>(); +} + +// https://drafts.css-houdini.org/css-typed-om-1/#parse-a-cssstylevalue +WebIDL::ExceptionOr, GC::RootVector>>> CSSStyleValue::parse_a_css_style_value(JS::VM& vm, String property, String css_text, ParseMultiple parse_multiple) +{ + // 1. If property is not a custom property name string, set property to property ASCII lowercased. + if (!is_a_custom_property_name_string(property)) + property = property.to_ascii_lowercase(); + + // 2. If property is not a valid CSS property, throw a TypeError. + if (!is_a_valid_css_property(property)) + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("'{}' is not a valid CSS property", property)) }; + + // 3. Attempt to parse cssText according to property’s grammar. + // If this fails, throw a TypeError. + // Otherwise, let whole value be the parsed result. + auto property_id = property_id_from_string(property).release_value(); + auto whole_value = parse_css_value(Parser::ParsingParams {}, css_text, property_id); + if (!whole_value) + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Failed to parse '{}' as a value for '{}' property", css_text, property)) }; + + // FIXME: 4. Subdivide into iterations whole value, according to property, and let values be the result. + + // 5. For each value in values, replace it with the result of reifying value for property. + GC::RootVector> reified_values { vm.heap() }; + reified_values.append(whole_value->reify(*vm.current_realm(), property)); + + // 6. If parseMultiple is false, return values[0]. Otherwise, return values. + if (parse_multiple == ParseMultiple::No) + return reified_values.take_first(); + return reified_values; +} + // https://drafts.css-houdini.org/css-typed-om-1/#stylevalue-serialization String CSSStyleValue::to_string() const { diff --git a/Libraries/LibWeb/CSS/CSSStyleValue.h b/Libraries/LibWeb/CSS/CSSStyleValue.h index 730d9d3f467..74ad0d3113a 100644 --- a/Libraries/LibWeb/CSS/CSSStyleValue.h +++ b/Libraries/LibWeb/CSS/CSSStyleValue.h @@ -22,6 +22,9 @@ public: virtual void initialize(JS::Realm&) override; + static WebIDL::ExceptionOr> parse(JS::VM&, String property, String css_text); + static WebIDL::ExceptionOr>> parse_all(JS::VM&, String property, String css_text); + virtual String to_string() const; protected: @@ -30,6 +33,12 @@ protected: private: explicit CSSStyleValue(JS::Realm&, String associated_property, String constructed_from_string); + enum class ParseMultiple : u8 { + No, + Yes, + }; + static WebIDL::ExceptionOr, GC::RootVector>>> parse_a_css_style_value(JS::VM&, String property, String css_text, ParseMultiple); + // https://drafts.css-houdini.org/css-typed-om-1/#dom-cssstylevalue-associatedproperty-slot Optional m_associated_property; diff --git a/Libraries/LibWeb/CSS/CSSStyleValue.idl b/Libraries/LibWeb/CSS/CSSStyleValue.idl index b66fd270190..031f441c415 100644 --- a/Libraries/LibWeb/CSS/CSSStyleValue.idl +++ b/Libraries/LibWeb/CSS/CSSStyleValue.idl @@ -2,6 +2,6 @@ [Exposed=(Window, Worker, PaintWorklet, LayoutWorklet)] interface CSSStyleValue { stringifier; - [FIXME, Exposed=Window] static CSSStyleValue parse(USVString property, USVString cssText); - [FIXME, Exposed=Window] static sequence parseAll(USVString property, USVString cssText); + [Exposed=Window] static CSSStyleValue parse(USVString property, USVString cssText); + [Exposed=Window] static sequence parseAll(USVString property, USVString cssText); }; diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-normalization/normalize-ident.tentative.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-normalization/normalize-ident.tentative.txt index fe17efb70bd..0da1a2283b2 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-normalization/normalize-ident.tentative.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-normalization/normalize-ident.tentative.txt @@ -2,7 +2,6 @@ Harness status: OK Found 2 tests -1 Pass -1 Fail -Fail CSS identifiers are normalized from String to CSSKeywordValues +2 Pass +Pass CSS identifiers are normalized from String to CSSKeywordValues Pass CSS identifiers are normalized from CSSOM to CSSKeywordValues \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-objects/parse.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-objects/parse.txt index 095f9470d66..9be66ab27f0 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-objects/parse.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-objects/parse.txt @@ -2,9 +2,9 @@ Harness status: OK Found 5 tests -5 Fail -Fail CSSStyleValue.parse() with a valid property returns a CSSStyleValue -Fail CSSStyleValue.parse() is not case sensitive -Fail CSSStyleValue.parse() with a valid list-valued property returns a CSSStyleValue -Fail CSSStyleValue.parse() with a valid shorthand property returns a CSSStyleValue -Fail CSSStyleValue.parse() with a valid custom property returns a CSSStyleValue \ No newline at end of file +5 Pass +Pass CSSStyleValue.parse() with a valid property returns a CSSStyleValue +Pass CSSStyleValue.parse() is not case sensitive +Pass CSSStyleValue.parse() with a valid list-valued property returns a CSSStyleValue +Pass CSSStyleValue.parse() with a valid shorthand property returns a CSSStyleValue +Pass CSSStyleValue.parse() with a valid custom property returns a CSSStyleValue \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-objects/parseAll.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-objects/parseAll.txt index b10cd1abdcb..e445310911e 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-objects/parseAll.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-objects/parseAll.txt @@ -2,9 +2,10 @@ Harness status: OK Found 5 tests -5 Fail -Fail CSSStyleValue.parseAll() with a valid property returns a list with a single CSSStyleValue -Fail CSSStyleValue.parseAll() is not case sensitive +4 Pass +1 Fail +Pass CSSStyleValue.parseAll() with a valid property returns a list with a single CSSStyleValue +Pass CSSStyleValue.parseAll() is not case sensitive Fail CSSStyleValue.parseAll() with a valid list-valued property returns a list with a single CSSStyleValue -Fail CSSStyleValue.parseAll() with a valid shorthand property returns a CSSStyleValue -Fail CSSStyleValue.parseAll() with a valid custom property returns a list with a single CSSStyleValue \ No newline at end of file +Pass CSSStyleValue.parseAll() with a valid shorthand property returns a CSSStyleValue +Pass CSSStyleValue.parseAll() with a valid custom property returns a list with a single CSSStyleValue \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssKeywordValue.tentative.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssKeywordValue.tentative.txt index 21c33086202..1a93c705a32 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssKeywordValue.tentative.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssKeywordValue.tentative.txt @@ -2,9 +2,8 @@ Harness status: OK Found 4 tests -3 Pass -1 Fail +4 Pass Pass CSSKeywordValue constructed from IDL serializes correctly Pass CSSKeywordValue constructed from IDL serializes to escaped strings -Fail CSSKeywordValue from DOMString modified through "value" setter serializes correctly +Pass CSSKeywordValue from DOMString modified through "value" setter serializes correctly Pass CSSKeywordValue from CSSOM modified through "value" setter serializes correctly \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssStyleValue-string.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssStyleValue-string.txt index a569e307e63..63f0a39deb6 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssStyleValue-string.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssStyleValue-string.txt @@ -2,6 +2,6 @@ Harness status: OK Found 2 tests -2 Fail -Fail CSSStyleValue parsed from string serializes to given string -Fail Shorthand CSSStyleValue parsed from string serializes to given string \ No newline at end of file +2 Pass +Pass CSSStyleValue parsed from string serializes to given string +Pass Shorthand CSSStyleValue parsed from string serializes to given string \ No newline at end of file