Skip to content
Permalink
Browse files
[@Property] Allow CSS-wide keywords in registered custom properties
https://bugs.webkit.org/show_bug.cgi?id=249305
<rdar://problem/103357146>

Reviewed by Alan Baradlay.

CSS-wide keywords (initial, inherit, unset, revert, revert-layer) should be allowed whatever the syntax is.

* LayoutTests/css-custom-properties-api/inline-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/register-property-syntax-parsing-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/registered-property-cssom-expected.txt:
* Source/WebCore/css/CSSCustomPropertyValue.cpp:
(WebCore::CSSCustomPropertyValue::containsCSSWideKeyword const):

Find if this value contains a CSS-wide keyword, including the "*" case where we just have tokens.

* Source/WebCore/css/CSSCustomPropertyValue.h:
* Source/WebCore/css/DOMCSSRegisterCustomProperty.cpp:
(WebCore::DOMCSSRegisterCustomProperty::registerProperty):

CSS-wide keywords are not allowed as the initial value though.

* Source/WebCore/css/parser/CSSParserTokenRange.h:
(WebCore::CSSParserTokenRange::consumeAll):

Add a helper to avoid silly consume loops.

* Source/WebCore/css/parser/CSSPropertyParser.cpp:
(WebCore::CSSPropertyParser::consumeCustomPropertyValueWithSyntax):
(WebCore::CSSPropertyParser::collectParsedCustomPropertyValueDependencies):
(WebCore::CSSPropertyParser::parseTypedCustomPropertyValue):

Canonical link: https://commits.webkit.org/257873@main
  • Loading branch information
anttijk committed Dec 14, 2022
1 parent f0ad494 commit b957d5f5e295f6a8c8557b75c73ac2ab424f6b6d
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 28 deletions.
@@ -6,10 +6,10 @@ PASS CSS.registerProperty
PASS Formerly valid values are still readable from inline styles but are computed as the unset value
PASS Values not matching the registered type can't be set
PASS Values can be removed from inline styles
FAIL Stylesheets can be modified by CSSOM assert_equals: expected "0px" but got "20px"
FAIL Valid values can be set on inline styles assert_equals: expected "inherit" but got "30em"
FAIL Var values are accepted assert_equals: expected "calc(var(--b) + 10px)" but got "30em"
FAIL Var values are accepted without validation assert_equals: expected "calc(var(--b) + 15px)" but got "30em"
FAIL Var values are accepted without validation, even when it is obvious they will not parse assert_equals: expected "calc(var(--b) 15px)" but got "30em"
FAIL Var values are accepted without validation, even when it is obvious they will not parse (typed) assert_equals: expected "calc(var(--registered) 15px)" but got "30em"
PASS Stylesheets can be modified by CSSOM
PASS Valid values can be set on inline styles
FAIL Var values are accepted assert_equals: expected "calc(var(--b) + 10px)" but got "inherit"
FAIL Var values are accepted without validation assert_equals: expected "calc(var(--b) + 15px)" but got "inherit"
FAIL Var values are accepted without validation, even when it is obvious they will not parse assert_equals: expected "calc(var(--b) 15px)" but got "inherit"
FAIL Var values are accepted without validation, even when it is obvious they will not parse (typed) assert_equals: expected "calc(var(--registered) 15px)" but got "inherit"

@@ -119,11 +119,11 @@ PASS syntax:'<length>|INHERIT', initialValue:'10px' is invalid
PASS syntax:'<percentage>|unsEt', initialValue:'2%' is invalid
PASS syntax:'<color>|REVert', initialValue:'red' is invalid
PASS syntax:'<integer>|deFAUlt', initialValue:'1' is invalid
FAIL syntax:'*', initialValue:'initial' is invalid assert_throws_dom: function "() => CSS.registerProperty({name: name, syntax: syntax, initialValue: initialValue, inherits: false})" did not throw
FAIL syntax:'*', initialValue:'inherit' is invalid assert_throws_dom: function "() => CSS.registerProperty({name: name, syntax: syntax, initialValue: initialValue, inherits: false})" did not throw
FAIL syntax:'*', initialValue:'unset' is invalid assert_throws_dom: function "() => CSS.registerProperty({name: name, syntax: syntax, initialValue: initialValue, inherits: false})" did not throw
FAIL syntax:'*', initialValue:'revert' is invalid assert_throws_dom: function "() => CSS.registerProperty({name: name, syntax: syntax, initialValue: initialValue, inherits: false})" did not throw
FAIL syntax:'*', initialValue:'revert-layer' is invalid assert_throws_dom: function "() => CSS.registerProperty({name: name, syntax: syntax, initialValue: initialValue, inherits: false})" did not throw
PASS syntax:'*', initialValue:'initial' is invalid
PASS syntax:'*', initialValue:'inherit' is invalid
PASS syntax:'*', initialValue:'unset' is invalid
PASS syntax:'*', initialValue:'revert' is invalid
PASS syntax:'*', initialValue:'revert-layer' is invalid
FAIL syntax:'*', initialValue:'default' is invalid assert_throws_dom: function "() => CSS.registerProperty({name: name, syntax: syntax, initialValue: initialValue, inherits: false})" did not throw
PASS syntax:'<custom-ident>', initialValue:'initial' is invalid
PASS syntax:'<custom-ident>', initialValue:'inherit' is invalid
@@ -5,5 +5,5 @@ FAIL Formerly valid values are still readable from inline styles but are compute
FAIL Values not matching the registered type can still be set assert_equals: expected "hi" but got ""
PASS Values can be removed from inline styles
FAIL Stylesheets can be modified by CSSOM assert_equals: expected "0px" but got "10px"
FAIL Valid values can be set on inline styles assert_equals: expected "inherit" but got "pink"
PASS Valid values can be set on inline styles

@@ -127,4 +127,18 @@ Vector<CSSParserToken> CSSCustomPropertyValue::tokens() const
return result;
}

bool CSSCustomPropertyValue::containsCSSWideKeyword() const
{
return WTF::switchOn(m_value, [&](const CSSValueID& valueID) {
return WebCore::isCSSWideKeyword(valueID);
}, [&](const Ref<CSSVariableData>& value) {
auto range = CSSParserTokenRange { value->tokens() };
range.consumeWhitespace();
auto token = range.consumeIncludingWhitespace();
return range.atEnd() && token.type() == IdentToken && WebCore::isCSSWideKeyword(token.id());
}, [&](auto&) {
return false;
});
}

}
@@ -97,6 +97,7 @@ class CSSCustomPropertyValue final : public CSSValue {
bool isResolved() const { return !std::holds_alternative<Ref<CSSVariableReferenceValue>>(m_value); }
bool isUnset() const { return std::holds_alternative<CSSValueID>(m_value) && std::get<CSSValueID>(m_value) == CSSValueUnset; }
bool isInvalid() const { return std::holds_alternative<CSSValueID>(m_value) && std::get<CSSValueID>(m_value) == CSSValueInvalid; }
bool containsCSSWideKeyword() const;

const VariantValue& value() const { return m_value; }

@@ -74,6 +74,9 @@ ExceptionOr<void> DOMCSSRegisterCustomProperty::registerProperty(Document& docum

if (!initialValue || !initialValue->isResolved())
return Exception { SyntaxError, "The given initial value does not parse for the given syntax."_s };

if (initialValue->containsCSSWideKeyword())
return Exception { SyntaxError, "The intitial value cannot be a CSS-wide keyword."_s };
}

CSSRegisteredCustomProperty property { AtomString { descriptor.name }, *syntax, descriptor.inherits, WTFMove(initialValue) };
@@ -87,6 +87,8 @@ class CSSParserTokenRange {
++m_first;
}

CSSParserTokenRange consumeAll() { return { std::exchange(m_first, m_last), m_last }; }

String serialize() const;

const CSSParserToken* begin() const { return m_first; }
@@ -224,7 +224,7 @@ bool CSSPropertyParser::parseValue(CSSPropertyID propertyID, bool important, con
return parseSuccess;
}

static RefPtr<CSSValue> maybeConsumeCSSWideKeyword(CSSParserTokenRange& range)
static RefPtr<CSSPrimitiveValue> maybeConsumeCSSWideKeyword(CSSParserTokenRange& range)
{
CSSParserTokenRange rangeCopy = range;
CSSValueID valueID = rangeCopy.consumeIncludingWhitespace().id();
@@ -330,8 +330,6 @@ std::pair<RefPtr<CSSValue>, CSSCustomPropertySyntax::Type> CSSPropertyParser::co
{
ASSERT(!syntax.isUniversal());

m_range.consumeWhitespace();

auto rangeCopy = m_range;

auto consumeSingleValue = [&](auto& range, auto& component) -> RefPtr<CSSValue> {
@@ -410,17 +408,23 @@ bool CSSPropertyParser::canParseTypedCustomPropertyValue(const CSSCustomProperty
if (syntax.isUniversal())
return true;

m_range.consumeWhitespace();

if (maybeConsumeCSSWideKeyword(m_range))
return true;

auto [value, syntaxType] = consumeCustomPropertyValueWithSyntax(syntax);
return value && m_range.atEnd();
return value;
}

void CSSPropertyParser::collectParsedCustomPropertyValueDependencies(const CSSCustomPropertySyntax& syntax, bool isInitial, HashSet<CSSPropertyID>& dependencies)
{
if (syntax.isUniversal())
return;

auto [value, syntaxType] = consumeCustomPropertyValueWithSyntax(syntax);
m_range.consumeWhitespace();

auto [value, syntaxType] = consumeCustomPropertyValueWithSyntax(syntax);
if (!value)
return;

@@ -431,12 +435,13 @@ void CSSPropertyParser::collectParsedCustomPropertyValueDependencies(const CSSCu

RefPtr<CSSCustomPropertyValue> CSSPropertyParser::parseTypedCustomPropertyValue(const AtomString& name, const CSSCustomPropertySyntax& syntax, Style::BuilderState& builderState)
{
if (syntax.isUniversal()) {
auto propertyValue = CSSCustomPropertyValue::createSyntaxAll(name, CSSVariableData::create(m_range));
while (!m_range.atEnd())
m_range.consume();
return propertyValue;
}
if (syntax.isUniversal())
return CSSCustomPropertyValue::createSyntaxAll(name, CSSVariableData::create(m_range.consumeAll()));

m_range.consumeWhitespace();

if (auto value = maybeConsumeCSSWideKeyword(m_range))
return CSSCustomPropertyValue::createWithID(name, value->valueID());

auto [value, syntaxType] = consumeCustomPropertyValueWithSyntax(syntax);
if (!value)
@@ -4306,11 +4306,7 @@ static RefPtr<CSSValue> consumeCustomPaint(CSSParserTokenRange& args)
if (!args.atEnd())
args.consume();

auto argumentList = CSSVariableData::create(args);

while (!args.atEnd())
args.consume();

auto argumentList = CSSVariableData::create(args.consumeAll());
return CSSPaintImageValue::create(name, WTFMove(argumentList));
}
#endif

0 comments on commit b957d5f

Please sign in to comment.