LibWeb/CSS: Support converting CSSKeywordValue to a StyleValue

Either KeywordStyleValue or CustomIdentStyleValue depending on whether
we recognize it as a CSS::Keyword.
This commit is contained in:
Sam Atkins 2025-10-02 15:03:49 +01:00 committed by Andreas Kling
parent 84f0f37a29
commit d855b3d90f
5 changed files with 103 additions and 65 deletions

View File

@ -7,7 +7,11 @@
#include "CSSKeywordValue.h"
#include <LibWeb/Bindings/CSSKeywordValuePrototype.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/CSS/Keyword.h>
#include <LibWeb/CSS/PropertyNameAndID.h>
#include <LibWeb/CSS/Serialize.h>
#include <LibWeb/CSS/StyleValues/CustomIdentStyleValue.h>
#include <LibWeb/CSS/StyleValues/KeywordStyleValue.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::CSS {
@ -63,6 +67,39 @@ WebIDL::ExceptionOr<String> CSSKeywordValue::to_string() const
return serialize_an_identifier(m_value);
}
// https://drafts.css-houdini.org/css-typed-om-1/#create-an-internal-representation
WebIDL::ExceptionOr<NonnullRefPtr<StyleValue const>> CSSKeywordValue::create_an_internal_representation(PropertyNameAndID const& property) const
{
// If value is a CSSStyleValue subclass,
// If value does not match the grammar of a list-valued property iteration of property, throw a TypeError.
bool const matches_grammar = [&] {
// https://drafts.css-houdini.org/css-typed-om-1/#cssstylevalue-match-a-grammar
// A CSSKeywordValue matches an <ident> specified in a grammar if its value internal slot matches the
// identifier.
// If case-folding rules are in effect normally for that <ident> (such as Auto matching the keyword auto
// specified in the grammar for width), they apply to this comparison as well.
if (property.is_custom_property()) {
// FIXME: If this is a registered custom property, check if that allows the keyword.
return true;
}
auto keyword = keyword_from_string(m_value);
return keyword.has_value() && property_accepts_keyword(property.id(), keyword.value());
}();
if (!matches_grammar) {
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Property '{}' does not accept the keyword '{}'", property.name(), m_value)) };
}
// If any component of propertys CSS grammar has a limited numeric range, and the corresponding part of value
// is a CSSUnitValue that is outside of that range, replace that value with the result of wrapping it in a
// fresh CSSMathSum whose values internal slot contains only that part of value.
// NB: Non-applicable.
// Return the value.
if (auto keyword = keyword_from_string(m_value); keyword.has_value())
return KeywordStyleValue::create(*keyword);
return CustomIdentStyleValue::create(m_value);
}
// https://drafts.css-houdini.org/css-typed-om-1/#rectify-a-keywordish-value
GC::Ref<CSSKeywordValue> rectify_a_keywordish_value(JS::Realm& realm, CSSKeywordish const& keywordish)
{

View File

@ -29,6 +29,7 @@ public:
WebIDL::ExceptionOr<void> set_value(FlyString value);
virtual WebIDL::ExceptionOr<String> to_string() const override;
virtual WebIDL::ExceptionOr<NonnullRefPtr<StyleValue const>> create_an_internal_representation(PropertyNameAndID const&) const override;
private:
explicit CSSKeywordValue(JS::Realm&, FlyString value);

View File

@ -2,49 +2,49 @@ Harness status: OK
Found 69 tests
28 Pass
41 Fail
64 Pass
5 Fail
Fail Can set 'cursor' to CSS-wide keywords: initial
Fail Can set 'cursor' to CSS-wide keywords: inherit
Fail Can set 'cursor' to CSS-wide keywords: unset
Fail Can set 'cursor' to CSS-wide keywords: revert
Fail Can set 'cursor' to var() references: var(--A)
Fail Can set 'cursor' to the 'auto' keyword: auto
Fail Can set 'cursor' to the 'default' keyword: default
Fail Can set 'cursor' to the 'none' keyword: none
Fail Can set 'cursor' to the 'context-menu' keyword: context-menu
Fail Can set 'cursor' to the 'help' keyword: help
Fail Can set 'cursor' to the 'pointer' keyword: pointer
Fail Can set 'cursor' to the 'progress' keyword: progress
Fail Can set 'cursor' to the 'wait' keyword: wait
Fail Can set 'cursor' to the 'cell' keyword: cell
Fail Can set 'cursor' to the 'crosshair' keyword: crosshair
Fail Can set 'cursor' to the 'text' keyword: text
Fail Can set 'cursor' to the 'vertical-text' keyword: vertical-text
Fail Can set 'cursor' to the 'alias' keyword: alias
Fail Can set 'cursor' to the 'copy' keyword: copy
Fail Can set 'cursor' to the 'move' keyword: move
Fail Can set 'cursor' to the 'no-drop' keyword: no-drop
Fail Can set 'cursor' to the 'not-allowed' keyword: not-allowed
Fail Can set 'cursor' to the 'grab' keyword: grab
Fail Can set 'cursor' to the 'grabbing' keyword: grabbing
Fail Can set 'cursor' to the 'e-resize' keyword: e-resize
Fail Can set 'cursor' to the 'n-resize' keyword: n-resize
Fail Can set 'cursor' to the 'ne-resize' keyword: ne-resize
Fail Can set 'cursor' to the 'nw-resize' keyword: nw-resize
Fail Can set 'cursor' to the 's-resize' keyword: s-resize
Fail Can set 'cursor' to the 'se-resize' keyword: se-resize
Fail Can set 'cursor' to the 'sw-resize' keyword: sw-resize
Fail Can set 'cursor' to the 'w-resize' keyword: w-resize
Fail Can set 'cursor' to the 'ew-resize' keyword: ew-resize
Fail Can set 'cursor' to the 'ns-resize' keyword: ns-resize
Fail Can set 'cursor' to the 'nesw-resize' keyword: nesw-resize
Fail Can set 'cursor' to the 'nwse-resize' keyword: nwse-resize
Fail Can set 'cursor' to the 'col-resize' keyword: col-resize
Fail Can set 'cursor' to the 'row-resize' keyword: row-resize
Fail Can set 'cursor' to the 'all-scroll' keyword: all-scroll
Fail Can set 'cursor' to the 'zoom-in' keyword: zoom-in
Fail Can set 'cursor' to the 'zoom-out' keyword: zoom-out
Pass Can set 'cursor' to the 'auto' keyword: auto
Pass Can set 'cursor' to the 'default' keyword: default
Pass Can set 'cursor' to the 'none' keyword: none
Pass Can set 'cursor' to the 'context-menu' keyword: context-menu
Pass Can set 'cursor' to the 'help' keyword: help
Pass Can set 'cursor' to the 'pointer' keyword: pointer
Pass Can set 'cursor' to the 'progress' keyword: progress
Pass Can set 'cursor' to the 'wait' keyword: wait
Pass Can set 'cursor' to the 'cell' keyword: cell
Pass Can set 'cursor' to the 'crosshair' keyword: crosshair
Pass Can set 'cursor' to the 'text' keyword: text
Pass Can set 'cursor' to the 'vertical-text' keyword: vertical-text
Pass Can set 'cursor' to the 'alias' keyword: alias
Pass Can set 'cursor' to the 'copy' keyword: copy
Pass Can set 'cursor' to the 'move' keyword: move
Pass Can set 'cursor' to the 'no-drop' keyword: no-drop
Pass Can set 'cursor' to the 'not-allowed' keyword: not-allowed
Pass Can set 'cursor' to the 'grab' keyword: grab
Pass Can set 'cursor' to the 'grabbing' keyword: grabbing
Pass Can set 'cursor' to the 'e-resize' keyword: e-resize
Pass Can set 'cursor' to the 'n-resize' keyword: n-resize
Pass Can set 'cursor' to the 'ne-resize' keyword: ne-resize
Pass Can set 'cursor' to the 'nw-resize' keyword: nw-resize
Pass Can set 'cursor' to the 's-resize' keyword: s-resize
Pass Can set 'cursor' to the 'se-resize' keyword: se-resize
Pass Can set 'cursor' to the 'sw-resize' keyword: sw-resize
Pass Can set 'cursor' to the 'w-resize' keyword: w-resize
Pass Can set 'cursor' to the 'ew-resize' keyword: ew-resize
Pass Can set 'cursor' to the 'ns-resize' keyword: ns-resize
Pass Can set 'cursor' to the 'nesw-resize' keyword: nesw-resize
Pass Can set 'cursor' to the 'nwse-resize' keyword: nwse-resize
Pass Can set 'cursor' to the 'col-resize' keyword: col-resize
Pass Can set 'cursor' to the 'row-resize' keyword: row-resize
Pass Can set 'cursor' to the 'all-scroll' keyword: all-scroll
Pass Can set 'cursor' to the 'zoom-in' keyword: zoom-in
Pass Can set 'cursor' to the 'zoom-out' keyword: zoom-out
Pass Setting 'cursor' to a length: 0px throws TypeError
Pass Setting 'cursor' to a length: -3.14em throws TypeError
Pass Setting 'cursor' to a length: 3.14cm throws TypeError

View File

@ -2,34 +2,34 @@ Harness status: OK
Found 56 tests
30 Pass
26 Fail
51 Pass
5 Fail
Fail Can set 'display' to CSS-wide keywords: initial
Fail Can set 'display' to CSS-wide keywords: inherit
Fail Can set 'display' to CSS-wide keywords: unset
Fail Can set 'display' to CSS-wide keywords: revert
Fail Can set 'display' to var() references: var(--A)
Fail Can set 'display' to the 'none' keyword: none
Fail Can set 'display' to the 'block' keyword: block
Fail Can set 'display' to the 'inline' keyword: inline
Fail Can set 'display' to the 'flow-root' keyword: flow-root
Fail Can set 'display' to the 'table' keyword: table
Fail Can set 'display' to the 'flex' keyword: flex
Fail Can set 'display' to the 'grid' keyword: grid
Fail Can set 'display' to the 'list-item' keyword: list-item
Fail Can set 'display' to the 'table-row-group' keyword: table-row-group
Fail Can set 'display' to the 'table-header-group' keyword: table-header-group
Fail Can set 'display' to the 'table-footer-group' keyword: table-footer-group
Fail Can set 'display' to the 'table-row' keyword: table-row
Fail Can set 'display' to the 'table-cell' keyword: table-cell
Fail Can set 'display' to the 'table-column-group' keyword: table-column-group
Fail Can set 'display' to the 'table-column' keyword: table-column
Fail Can set 'display' to the 'table-caption' keyword: table-caption
Fail Can set 'display' to the 'contents' keyword: contents
Fail Can set 'display' to the 'inline-block' keyword: inline-block
Fail Can set 'display' to the 'inline-table' keyword: inline-table
Fail Can set 'display' to the 'inline-flex' keyword: inline-flex
Fail Can set 'display' to the 'inline-grid' keyword: inline-grid
Pass Can set 'display' to the 'none' keyword: none
Pass Can set 'display' to the 'block' keyword: block
Pass Can set 'display' to the 'inline' keyword: inline
Pass Can set 'display' to the 'flow-root' keyword: flow-root
Pass Can set 'display' to the 'table' keyword: table
Pass Can set 'display' to the 'flex' keyword: flex
Pass Can set 'display' to the 'grid' keyword: grid
Pass Can set 'display' to the 'list-item' keyword: list-item
Pass Can set 'display' to the 'table-row-group' keyword: table-row-group
Pass Can set 'display' to the 'table-header-group' keyword: table-header-group
Pass Can set 'display' to the 'table-footer-group' keyword: table-footer-group
Pass Can set 'display' to the 'table-row' keyword: table-row
Pass Can set 'display' to the 'table-cell' keyword: table-cell
Pass Can set 'display' to the 'table-column-group' keyword: table-column-group
Pass Can set 'display' to the 'table-column' keyword: table-column
Pass Can set 'display' to the 'table-caption' keyword: table-caption
Pass Can set 'display' to the 'contents' keyword: contents
Pass Can set 'display' to the 'inline-block' keyword: inline-block
Pass Can set 'display' to the 'inline-table' keyword: inline-table
Pass Can set 'display' to the 'inline-flex' keyword: inline-flex
Pass Can set 'display' to the 'inline-grid' keyword: inline-grid
Pass Setting 'display' to a length: 0px throws TypeError
Pass Setting 'display' to a length: -3.14em throws TypeError
Pass Setting 'display' to a length: 3.14cm throws TypeError

View File

@ -2,14 +2,14 @@ Harness status: OK
Found 95 tests
54 Pass
41 Fail
56 Pass
39 Fail
Fail Can set 'width' to CSS-wide keywords: initial
Fail Can set 'width' to CSS-wide keywords: inherit
Fail Can set 'width' to CSS-wide keywords: unset
Fail Can set 'width' to CSS-wide keywords: revert
Fail Can set 'width' to var() references: var(--A)
Fail Can set 'width' to the 'auto' keyword: auto
Pass Can set 'width' to the 'auto' keyword: auto
Fail Can set 'width' to a percent: 0%
Fail Can set 'width' to a percent: -3.14%
Fail Can set 'width' to a percent: 3.14%
@ -72,7 +72,7 @@ Fail Can set 'max-width' to CSS-wide keywords: inherit
Fail Can set 'max-width' to CSS-wide keywords: unset
Fail Can set 'max-width' to CSS-wide keywords: revert
Fail Can set 'max-width' to var() references: var(--A)
Fail Can set 'max-width' to the 'none' keyword: none
Pass Can set 'max-width' to the 'none' keyword: none
Fail Can set 'max-width' to a percent: 0%
Fail Can set 'max-width' to a percent: -3.14%
Fail Can set 'max-width' to a percent: 3.14%