Title: [276488] trunk
Revision
276488
Author
[email protected]
Date
2021-04-22 22:25:40 -0700 (Thu, 22 Apr 2021)

Log Message

[css-counter-styles] Parse @counter-style descriptors
https://bugs.webkit.org/show_bug.cgi?id=224718

Patch by Tyler Wilcock <[email protected]> on 2021-04-22
Reviewed by Darin Adler.

LayoutTests/imported/w3c:

Parsing for all @counter-style descriptors is implemented with this
patch, so mark more tests passing.

You'll notice that some @counter-style descriptors implemented in this
patch did not gain any passing tests (e.g. `pad`, `negative`).  In all
of these cases, the expected results contain a <string> value, and we
fail only because we incorrectly don't serialize these <string> values
with quotes.  I have manually confirmed in all cases that these values
are properly parsed, so it's just the serialization that's incorrect.

These <string> values serialize without quotes because WebKit's representation
of custom identifiers is not a separate type, but instead overloaded onto the
CSS_STRING type.  This means that during serialization time, WebKit must guess
whether it is actually serializing a string (and include quotes if so), or if
it's serializing a custom ident (leaving off quotes if so).

Relevant code snippet:

https://github.com/WebKit/WebKit/blob/36caeec07975bd5f47db8ac6b749c2787230a461/Source/WebCore/css/CSSMarkup.cpp#L153#L161

Relevant changelog snippet from David Hyatt, 2016-12-07:

> We also overload CSS_STRING primitive value type and have it act as both a string
> and a custom identifier. This is lame, since the parser should have made two different
> types of objects instead, but since our parser doesn't do that yet, I added a serializeAsStringOrCustomIdent
> that preserves our old behavior of "quote the string only if needed." In this case what
> that really meant was "Try to guess that we were originally a custom ident and leave off
> quotes if so." This function will go away once we properly create CSSStringValues and
> CSSCustomIdentValues instead of turning the latter into strings.

* web-platform-tests/css/css-counter-styles/counter-style-fallback-expected.txt:
* web-platform-tests/css/css-counter-styles/counter-style-prefix-suffix-syntax-expected.txt:
* web-platform-tests/css/css-counter-styles/counter-style-range-syntax-expected.txt:
* web-platform-tests/css/css-counter-styles/counter-style-speak-as-syntax-expected.txt:
* web-platform-tests/css/css-counter-styles/counter-style-system-syntax-expected.txt:

Source/WebCore:

Implement parsing and CSSCounterStyleRule IDL interface for @counter-style descriptors.
See spec for full details on all descriptors:

https://drafts.csswg.org/css-counter-styles-3/#the-counter-style-rule

Test: webexposed/counter-style-image-symbols-not-exposed.html and WPTs

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::ComputedStyleExtractor::valueForPropertyInStyle):
Return `nullptr` for new @counter-style descriptor properties.

* css/CSSCounterStyleRule.cpp:
(WebCore::toCounterStyleSystemEnum):
(WebCore::symbolsValidForSystem):
(WebCore::StyleRuleCounterStyle::newValueInvalidOrEqual const):
(WebCore::CSSCounterStyleRule::cssText const):
(WebCore::CSSCounterStyleRule::setName):
(WebCore::CSSCounterStyleRule::setterInternal):
(WebCore::CSSCounterStyleRule::setSystem):
(WebCore::CSSCounterStyleRule::setNegative):
(WebCore::CSSCounterStyleRule::setPrefix):
(WebCore::CSSCounterStyleRule::setSuffix):
(WebCore::CSSCounterStyleRule::setRange):
(WebCore::CSSCounterStyleRule::setPad):
(WebCore::CSSCounterStyleRule::setFallback):
(WebCore::CSSCounterStyleRule::setSymbols):
(WebCore::CSSCounterStyleRule::setAdditiveSymbols):
(WebCore::CSSCounterStyleRule::setSpeakAs):
Implement setters and tangential functionality required by setters.

* css/CSSCounterStyleRule.h:
Replace FIXME with actual descriptor getter and setter
implementations.

* css/CSSProperties.json:
Add @counter-style descriptor properties.

* css/CSSValueKeywords.in:
Add new values required for `system` and `speak-as`
@counter-style descriptor properties.

* css/parser/CSSParserContext.cpp:
(WebCore::CSSParserContext::isPropertyRuntimeDisabled const):
Ensure new @counter-style descriptors are disabled at runtime based
on CSSParserContext state.

* css/parser/CSSPropertyParser.cpp:
(WebCore::consumeCounterStyleSystem):
(WebCore::consumeCounterStyleSymbol):
(WebCore::consumeCounterStyleNegative):
(WebCore::consumeCounterStyleRangeBound):
(WebCore::consumeCounterStyleRange):
(WebCore::consumeCounterStylePad):
(WebCore::consumeCounterStyleSymbols):
(WebCore::consumeCounterStyleAdditiveSymbols):
(WebCore::consumeCounterStyleSpeakAs):
(WebCore::CSSPropertyParser::parseCounterStyleDescriptor):
Parse @counter-style descriptors.

Tools:

* DumpRenderTree/TestOptions.cpp:
(WTR::TestOptions::defaults):
Fix typo (missing 's').  CSSCounterStyleAtRulesEnabled, not
CSSCounterStyleAtRuleEnabled.

LayoutTests:

Add test ensuring <image> @counter-style symbol values cannot be
parsed when the `counterStyleAtRuleImageSymbolsEnabled` feature flag
is disabled.

---

This test is skipped on Windows because I haven't been able to get the
required feature flags (CSSCounterStyleAtRulesEnabled and
CSSCounterStyleAtRuleImageSymbolsEnabled) to work properly for that
port.

The code hidden behind these flags is all in the CSS parser, which is not
unique to Windows, so I think we can be confident that if the test passes
on all other platforms, that the behavior is correct on Windows too.

One attempt at implementing the necessary Windows-specific flag functionality is here:

https://bugs.webkit.org/attachment.cgi?id=426371&action=""

Which failed to compile[1] with this error:

> C:\cygwin\home\buildbot\worker\Windows-EWS\build\Tools\DumpRenderTree\win\DumpRenderTree.cpp(834,51): error C2039: 'setCSSCounterStyleAtRulesEnabled': is not a member of 'IWebPreferencesPrivate7' [C:\cygwin\home\buildbot\worker\Windows-EWS\build\WebKitBuild\Release\Tools\DumpRenderTree\DumpRenderTreeLib.vcxproj]
> C:\cygwin\home\buildbot\worker\Windows-EWS\build\Tools\DumpRenderTree\win\DumpRenderTree.cpp(835,62): error C2039: 'setCSSCounterStyleAtRuleImageSymbolsEnabled': is not a member of 'IWebPreferencesPrivate7' [C:\cygwin\home\buildbot\worker\Windows-EWS\build\WebKitBuild\Release\Tools\DumpRenderTree\DumpRenderTreeLib.vcxproj]

Those methods are present in `IWebPreferencesPrivate7.idl`, and implemented similarly to other
flags in other places (e.g. win/WebPreferences.{h, cpp}, win/WebPreferenceKeysPrivate.h).
I can't reproduce this compilation error on my Windows machine.

I then tried removing the lines that caused the above compilation failure.
Those setters are called in DumpRenderTree::enableExperimentalFeatures, so in
lieu of enabling these flags there I could enable the flag I need via test header.

That patch is: https://bugs.webkit.org/attachment.cgi?id=426509&action=""

This results in successful compilation, but causes lots (all?) of the
layout tests to fail[2] with a stacktrace that looks like:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (276487 => 276488)


--- trunk/LayoutTests/ChangeLog	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/LayoutTests/ChangeLog	2021-04-23 05:25:40 UTC (rev 276488)
@@ -1,3 +1,63 @@
+2021-04-22  Tyler Wilcock  <[email protected]>
+
+        [css-counter-styles] Parse @counter-style descriptors
+        https://bugs.webkit.org/show_bug.cgi?id=224718
+
+        Reviewed by Darin Adler.
+
+        Add test ensuring <image> @counter-style symbol values cannot be
+        parsed when the `counterStyleAtRuleImageSymbolsEnabled` feature flag
+        is disabled.
+
+        ---
+
+        This test is skipped on Windows because I haven't been able to get the
+        required feature flags (CSSCounterStyleAtRulesEnabled and
+        CSSCounterStyleAtRuleImageSymbolsEnabled) to work properly for that
+        port.
+
+        The code hidden behind these flags is all in the CSS parser, which is not
+        unique to Windows, so I think we can be confident that if the test passes
+        on all other platforms, that the behavior is correct on Windows too.
+
+        One attempt at implementing the necessary Windows-specific flag functionality is here:
+
+        https://bugs.webkit.org/attachment.cgi?id=426371&action=""
+
+        Which failed to compile[1] with this error:
+
+        > C:\cygwin\home\buildbot\worker\Windows-EWS\build\Tools\DumpRenderTree\win\DumpRenderTree.cpp(834,51): error C2039: 'setCSSCounterStyleAtRulesEnabled': is not a member of 'IWebPreferencesPrivate7' [C:\cygwin\home\buildbot\worker\Windows-EWS\build\WebKitBuild\Release\Tools\DumpRenderTree\DumpRenderTreeLib.vcxproj]
+        > C:\cygwin\home\buildbot\worker\Windows-EWS\build\Tools\DumpRenderTree\win\DumpRenderTree.cpp(835,62): error C2039: 'setCSSCounterStyleAtRuleImageSymbolsEnabled': is not a member of 'IWebPreferencesPrivate7' [C:\cygwin\home\buildbot\worker\Windows-EWS\build\WebKitBuild\Release\Tools\DumpRenderTree\DumpRenderTreeLib.vcxproj]
+
+        Those methods are present in `IWebPreferencesPrivate7.idl`, and implemented similarly to other
+        flags in other places (e.g. win/WebPreferences.{h, cpp}, win/WebPreferenceKeysPrivate.h).
+        I can't reproduce this compilation error on my Windows machine.
+
+        I then tried removing the lines that caused the above compilation failure.
+        Those setters are called in DumpRenderTree::enableExperimentalFeatures, so in
+        lieu of enabling these flags there I could enable the flag I need via test header.
+
+        That patch is: https://bugs.webkit.org/attachment.cgi?id=426509&action=""
+
+        This results in successful compilation, but causes lots (all?) of the
+        layout tests to fail[2] with a stacktrace that looks like:
+
+00007ffc`3e9e3113 WebKit!WebPreferences::speechRecognitionEnabled(int * enabled = 0x00007ffc`3eae0f50)+0x29 [C:\cygwin\home\buildbot\worker\Windows-EWS\build\Source\WebKitLegacy\win\WebPreferences.cpp @ 2617]
+00007ffc`3e9e3cc0 DumpRenderTreeLib!resetWebPreferencesToConsistentValues(struct IWebPreferences * preferences = 0x00000205`e2f204b0)+0x63 [C:\cygwin\home\buildbot\worker\Windows-EWS\build\Tools\DumpRenderTree\win\DumpRenderTree.cpp @ 847]
+00007ffc`3e9e4171 DumpRenderTreeLib!resetWebViewToConsistentStateBeforeTesting(class WTR::TestOptions * options = 0x00000065`738fea60)+0x2e0 [C:\cygwin\home\buildbot\worker\Windows-EWS\build\Tools\DumpRenderTree\win\DumpRenderTree.cpp @ 1054]
+00007ffc`3e9e67d3 DumpRenderTreeLib!runTest(class std::basic_string<char,std::char_traits<char>,std::allocator<char> > * inputLine = <Value unavailable error>)+0x2f1 [C:\cygwin\home\buildbot\worker\Windows-EWS\build\Tools\DumpRenderTree\win\DumpRenderTree.cpp @ 1239]
+00007ff7`89952f30 DumpRenderTreeLib!main(int argc = <Value unavailable error>, char ** argv = <Value unavailable error>)+0x5d3 [C:\cygwin\home\buildbot\worker\Windows-EWS\build\Tools\DumpRenderTree\win\DumpRenderTree.cpp @ 1676]
+00007ff7`89953884 DumpRenderTree!main(int argc = 0n2, char ** argv = 0x00000205`e2e74b80)+0x880 [C:\cygwin\home\buildbot\worker\Windows-EWS\build\Tools\win\DLLLauncher\DLLLauncherMain.cpp @ 232]
+
+        I haven't done much digging into why this happens, and cannot reproduce it on my Windows machine.
+
+        [1]: https://ews-build.webkit.org/#/builders/10/builds/86747
+        [2]: https://ews-build.webkit.org/#/builders/10/builds/86897
+
+        * platform/win/TestExpectations: Skip newly added test on Windows.
+        * webexposed/counter-style-image-symbols-not-exposed-expected.txt: Added.
+        * webexposed/counter-style-image-symbols-not-exposed.html: Added.
+
 2021-04-22  Megan Gardner  <[email protected]>
 
         Sometimes appHighlights are not painted when created.

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (276487 => 276488)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-04-23 05:25:40 UTC (rev 276488)
@@ -1,3 +1,46 @@
+2021-04-22  Tyler Wilcock  <[email protected]>
+
+        [css-counter-styles] Parse @counter-style descriptors
+        https://bugs.webkit.org/show_bug.cgi?id=224718
+
+        Reviewed by Darin Adler.
+
+        Parsing for all @counter-style descriptors is implemented with this
+        patch, so mark more tests passing.
+
+        You'll notice that some @counter-style descriptors implemented in this
+        patch did not gain any passing tests (e.g. `pad`, `negative`).  In all
+        of these cases, the expected results contain a <string> value, and we
+        fail only because we incorrectly don't serialize these <string> values
+        with quotes.  I have manually confirmed in all cases that these values
+        are properly parsed, so it's just the serialization that's incorrect.
+
+        These <string> values serialize without quotes because WebKit's representation
+        of custom identifiers is not a separate type, but instead overloaded onto the
+        CSS_STRING type.  This means that during serialization time, WebKit must guess
+        whether it is actually serializing a string (and include quotes if so), or if
+        it's serializing a custom ident (leaving off quotes if so).
+
+        Relevant code snippet:
+
+        https://github.com/WebKit/WebKit/blob/36caeec07975bd5f47db8ac6b749c2787230a461/Source/WebCore/css/CSSMarkup.cpp#L153#L161
+
+        Relevant changelog snippet from David Hyatt, 2016-12-07:
+
+        > We also overload CSS_STRING primitive value type and have it act as both a string
+        > and a custom identifier. This is lame, since the parser should have made two different
+        > types of objects instead, but since our parser doesn't do that yet, I added a serializeAsStringOrCustomIdent
+        > that preserves our old behavior of "quote the string only if needed." In this case what
+        > that really meant was "Try to guess that we were originally a custom ident and leave off
+        > quotes if so." This function will go away once we properly create CSSStringValues and
+        > CSSCustomIdentValues instead of turning the latter into strings.
+
+        * web-platform-tests/css/css-counter-styles/counter-style-fallback-expected.txt:
+        * web-platform-tests/css/css-counter-styles/counter-style-prefix-suffix-syntax-expected.txt:
+        * web-platform-tests/css/css-counter-styles/counter-style-range-syntax-expected.txt:
+        * web-platform-tests/css/css-counter-styles/counter-style-speak-as-syntax-expected.txt:
+        * web-platform-tests/css/css-counter-styles/counter-style-system-syntax-expected.txt:
+
 2021-04-22  Antoine Quint  <[email protected]>
 
         Add discrete animation support for border-image-repeat

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-fallback-expected.txt (276487 => 276488)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-fallback-expected.txt	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-fallback-expected.txt	2021-04-23 05:25:40 UTC (rev 276488)
@@ -1,5 +1,5 @@
 
-FAIL @counter-style 'fallback: bar' is valid assert_not_equals: got disallowed value -1
+PASS @counter-style 'fallback: bar' is valid
 PASS @counter-style 'fallback: "bar"' is invalid
 PASS @counter-style 'fallback: none' is invalid
 PASS @counter-style 'fallback: initial' is invalid

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-prefix-suffix-syntax-expected.txt (276487 => 276488)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-prefix-suffix-syntax-expected.txt	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-prefix-suffix-syntax-expected.txt	2021-04-23 05:25:40 UTC (rev 276488)
@@ -7,8 +7,8 @@
 FAIL @counter-style 'suffix: "inherit"' is valid assert_not_equals: got disallowed value -1
 FAIL @counter-style 'prefix: "unset"' is valid assert_not_equals: got disallowed value -1
 FAIL @counter-style 'suffix: "unset"' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'prefix: custom-ident' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'suffix: custom-ident' is valid assert_not_equals: got disallowed value -1
+PASS @counter-style 'prefix: custom-ident' is valid
+PASS @counter-style 'suffix: custom-ident' is valid
 PASS @counter-style 'prefix: initial' is invalid
 PASS @counter-style 'suffix: initial' is invalid
 PASS @counter-style 'prefix: inherit' is invalid
@@ -15,12 +15,12 @@
 PASS @counter-style 'suffix: inherit' is invalid
 PASS @counter-style 'prefix: unset' is invalid
 PASS @counter-style 'suffix: unset' is invalid
-FAIL @counter-style 'prefix: url("https://example.com/foo.png")' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'suffix: url("https://example.com/foo.png")' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'prefix: url(https://example.com/foo.png)' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'suffix: url(https://example.com/foo.png)' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'prefix: linear-gradient(yellow, blue)' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'suffix: linear-gradient(yellow, blue)' is valid assert_not_equals: got disallowed value -1
+PASS @counter-style 'prefix: url("https://example.com/foo.png")' is valid
+PASS @counter-style 'suffix: url("https://example.com/foo.png")' is valid
+PASS @counter-style 'prefix: url(https://example.com/foo.png)' is valid
+PASS @counter-style 'suffix: url(https://example.com/foo.png)' is valid
+PASS @counter-style 'prefix: linear-gradient(yellow, blue)' is valid
+PASS @counter-style 'suffix: linear-gradient(yellow, blue)' is valid
 PASS @counter-style 'prefix: ' is invalid
 PASS @counter-style 'suffix: ' is invalid
 PASS @counter-style 'prefix: foo bar' is invalid

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-range-syntax-expected.txt (276487 => 276488)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-range-syntax-expected.txt	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-range-syntax-expected.txt	2021-04-23 05:25:40 UTC (rev 276488)
@@ -1,10 +1,10 @@
 
-FAIL @counter-style 'range: auto' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'range: infinite infinite' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'range: infinite 0' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'range: 0 infinite' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'range: infinite 0, 5 10, 100 infinite' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'range: infinite 10, 5 20, 15 infinite' is valid assert_not_equals: got disallowed value -1
+PASS @counter-style 'range: auto' is valid
+PASS @counter-style 'range: infinite infinite' is valid
+PASS @counter-style 'range: infinite 0' is valid
+PASS @counter-style 'range: 0 infinite' is valid
+PASS @counter-style 'range: infinite 0, 5 10, 100 infinite' is valid
+PASS @counter-style 'range: infinite 10, 5 20, 15 infinite' is valid
 PASS @counter-style 'range: ' is invalid
 PASS @counter-style 'range: 0 -1' is invalid
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-speak-as-syntax-expected.txt (276487 => 276488)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-speak-as-syntax-expected.txt	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-speak-as-syntax-expected.txt	2021-04-23 05:25:40 UTC (rev 276488)
@@ -1,11 +1,11 @@
 
-FAIL @counter-style 'speak-as: auto' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'speak-as: bullets' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'speak-as: numbers' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'speak-as: words' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'speak-as: spell-out' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'speak-as: bar' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'speak-as: spellout' is valid assert_not_equals: got disallowed value -1
+PASS @counter-style 'speak-as: auto' is valid
+PASS @counter-style 'speak-as: bullets' is valid
+PASS @counter-style 'speak-as: numbers' is valid
+PASS @counter-style 'speak-as: words' is valid
+PASS @counter-style 'speak-as: spell-out' is valid
+PASS @counter-style 'speak-as: bar' is valid
+PASS @counter-style 'speak-as: spellout' is valid
 PASS @counter-style 'speak-as: bullets numbers' is invalid
 PASS @counter-style 'speak-as: none' is invalid
 PASS @counter-style 'speak-as: initial' is invalid

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-system-syntax-expected.txt (276487 => 276488)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-system-syntax-expected.txt	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-system-syntax-expected.txt	2021-04-23 05:25:40 UTC (rev 276488)
@@ -1,13 +1,13 @@
 
-FAIL @counter-style 'system: cyclic' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'system: fixed' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'system: fixed 100' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'system: fixed -1' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'system: symbolic' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'system: alphabetic' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'system: numeric' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'system: additive' is valid assert_not_equals: got disallowed value -1
-FAIL @counter-style 'system: extends bar' is valid assert_not_equals: got disallowed value -1
+PASS @counter-style 'system: cyclic' is valid
+PASS @counter-style 'system: fixed' is valid
+PASS @counter-style 'system: fixed 100' is valid
+PASS @counter-style 'system: fixed -1' is valid
+PASS @counter-style 'system: symbolic' is valid
+PASS @counter-style 'system: alphabetic' is valid
+PASS @counter-style 'system: numeric' is valid
+PASS @counter-style 'system: additive' is valid
+PASS @counter-style 'system: extends bar' is valid
 PASS @counter-style 'system: float' is invalid
 PASS @counter-style 'system: cyclic cyclic' is invalid
 PASS @counter-style 'system: extends none' is invalid

Modified: trunk/LayoutTests/platform/win/TestExpectations (276487 => 276488)


--- trunk/LayoutTests/platform/win/TestExpectations	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/LayoutTests/platform/win/TestExpectations	2021-04-23 05:25:40 UTC (rev 276488)
@@ -4657,3 +4657,7 @@
 fast/forms/option-mouseevents.html [ Pass Failure ]
 fast/forms/password-doubleclick-selection.html [ Pass Failure ]
 fast/text/offsetForPosition-complex-fallback.html [ Pass Failure ]
+
+# This test is skipped because the necessary feature flag functionality specific to the Windows WebKit legacy port is
+# not implemented.  The feature flags in question are CSSCounterStyleAtRulesEnabled and CSSCounterStyleAtRuleImageSymbolsEnabled.
+webexposed/counter-style-image-symbols-not-exposed.html [ Skip ]

Added: trunk/LayoutTests/webexposed/counter-style-image-symbols-not-exposed-expected.txt (0 => 276488)


--- trunk/LayoutTests/webexposed/counter-style-image-symbols-not-exposed-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webexposed/counter-style-image-symbols-not-exposed-expected.txt	2021-04-23 05:25:40 UTC (rev 276488)
@@ -0,0 +1,3 @@
+
+PASS @counter-style image symbols are not exposed
+

Added: trunk/LayoutTests/webexposed/counter-style-image-symbols-not-exposed.html (0 => 276488)


--- trunk/LayoutTests/webexposed/counter-style-image-symbols-not-exposed.html	                        (rev 0)
+++ trunk/LayoutTests/webexposed/counter-style-image-symbols-not-exposed.html	2021-04-23 05:25:40 UTC (rev 276488)
@@ -0,0 +1,17 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ CSSCounterStyleAtRuleImageSymbolsEnabled=false ] -->
+<script src=""
+<script src=""
+<style>
+    @counter-style foo {
+        system: cyclic;
+        suffix: " ";
+        symbols: linear-gradient(yellow, blue);
+    }
+</style>
+<script>
+    test(function() {
+        const cssRules = document.styleSheets[0].cssRules
+        assert_equals(cssRules.length, 1, 'Should\'ve been able to parse @counter-style.')
+        assert_equals(cssRules[0].symbols, '', 'Shouldn\'t have been able to parse image symbol value with the runtime feature flag disabled.')
+    }, '@counter-style image symbols are not exposed')
+</script>
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (276487 => 276488)


--- trunk/Source/WebCore/ChangeLog	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/Source/WebCore/ChangeLog	2021-04-23 05:25:40 UTC (rev 276488)
@@ -1,3 +1,69 @@
+2021-04-22  Tyler Wilcock  <[email protected]>
+
+        [css-counter-styles] Parse @counter-style descriptors
+        https://bugs.webkit.org/show_bug.cgi?id=224718
+
+        Reviewed by Darin Adler.
+
+        Implement parsing and CSSCounterStyleRule IDL interface for @counter-style descriptors.
+        See spec for full details on all descriptors:
+
+        https://drafts.csswg.org/css-counter-styles-3/#the-counter-style-rule
+
+        Test: webexposed/counter-style-image-symbols-not-exposed.html and WPTs
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::ComputedStyleExtractor::valueForPropertyInStyle):
+        Return `nullptr` for new @counter-style descriptor properties.
+
+        * css/CSSCounterStyleRule.cpp:
+        (WebCore::toCounterStyleSystemEnum):
+        (WebCore::symbolsValidForSystem):
+        (WebCore::StyleRuleCounterStyle::newValueInvalidOrEqual const):
+        (WebCore::CSSCounterStyleRule::cssText const):
+        (WebCore::CSSCounterStyleRule::setName):
+        (WebCore::CSSCounterStyleRule::setterInternal):
+        (WebCore::CSSCounterStyleRule::setSystem):
+        (WebCore::CSSCounterStyleRule::setNegative):
+        (WebCore::CSSCounterStyleRule::setPrefix):
+        (WebCore::CSSCounterStyleRule::setSuffix):
+        (WebCore::CSSCounterStyleRule::setRange):
+        (WebCore::CSSCounterStyleRule::setPad):
+        (WebCore::CSSCounterStyleRule::setFallback):
+        (WebCore::CSSCounterStyleRule::setSymbols):
+        (WebCore::CSSCounterStyleRule::setAdditiveSymbols):
+        (WebCore::CSSCounterStyleRule::setSpeakAs):
+        Implement setters and tangential functionality required by setters.
+
+        * css/CSSCounterStyleRule.h:
+        Replace FIXME with actual descriptor getter and setter
+        implementations.
+
+        * css/CSSProperties.json:
+        Add @counter-style descriptor properties.
+
+        * css/CSSValueKeywords.in:
+        Add new values required for `system` and `speak-as` 
+        @counter-style descriptor properties.
+
+        * css/parser/CSSParserContext.cpp:
+        (WebCore::CSSParserContext::isPropertyRuntimeDisabled const):
+        Ensure new @counter-style descriptors are disabled at runtime based
+        on CSSParserContext state.
+
+        * css/parser/CSSPropertyParser.cpp:
+        (WebCore::consumeCounterStyleSystem):
+        (WebCore::consumeCounterStyleSymbol):
+        (WebCore::consumeCounterStyleNegative):
+        (WebCore::consumeCounterStyleRangeBound):
+        (WebCore::consumeCounterStyleRange):
+        (WebCore::consumeCounterStylePad):
+        (WebCore::consumeCounterStyleSymbols):
+        (WebCore::consumeCounterStyleAdditiveSymbols):
+        (WebCore::consumeCounterStyleSpeakAs):
+        (WebCore::CSSPropertyParser::parseCounterStyleDescriptor):
+        Parse @counter-style descriptors.
+
 2021-04-22  Megan Gardner  <[email protected]>
 
         Sometimes appHighlights are not painted when created.

Modified: trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp (276487 => 276488)


--- trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp	2021-04-23 05:25:40 UTC (rev 276488)
@@ -4003,6 +4003,18 @@
             ASSERT_NOT_REACHED();
             break;
 
+        // These are intentionally unimplemented because they are actually descriptors for @counter-style.
+        case CSSPropertySystem:
+        case CSSPropertyNegative:
+        case CSSPropertyPrefix:
+        case CSSPropertySuffix:
+        case CSSPropertyRange:
+        case CSSPropertyPad:
+        case CSSPropertyFallback:
+        case CSSPropertySymbols:
+        case CSSPropertyAdditiveSymbols:
+            break;
+
         /* Unimplemented @font-face properties */
         case CSSPropertySrc:
         case CSSPropertyUnicodeRange:

Modified: trunk/Source/WebCore/css/CSSCounterStyleRule.cpp (276487 => 276488)


--- trunk/Source/WebCore/css/CSSCounterStyleRule.cpp	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/Source/WebCore/css/CSSCounterStyleRule.cpp	2021-04-23 05:25:40 UTC (rev 276488)
@@ -26,6 +26,12 @@
 #include "config.h"
 #include "CSSCounterStyleRule.h"
 
+#include "CSSPropertyParser.h"
+#include "CSSStyleSheet.h"
+#include "CSSTokenizer.h"
+#include "Pair.h"
+#include <wtf/text/StringBuilder.h>
+
 namespace WebCore {
     
 StyleRuleCounterStyle::StyleRuleCounterStyle(const AtomString& name, Ref<StyleProperties>&& properties)
@@ -40,6 +46,94 @@
     return adoptRef(*new StyleRuleCounterStyle(name, WTFMove(properties)));
 }
 
+static CounterStyleSystem toCounterStyleSystemEnum(RefPtr<CSSValue> system)
+{
+    if (!system || !system->isPrimitiveValue())
+        return CounterStyleSystem::Symbolic;
+
+    auto& primitiveSystemValue = downcast<CSSPrimitiveValue>(*system);
+    ASSERT(primitiveSystemValue.isValueID() || primitiveSystemValue.isPair());
+    CSSValueID systemKeyword = CSSValueInvalid;
+    if (primitiveSystemValue.isValueID())
+        systemKeyword = primitiveSystemValue.valueID();
+    else if (auto* pair = primitiveSystemValue.pairValue()) {
+        // This value must be `fixed` or `extends`, both of which can or must have an additional component.
+        auto firstValue = pair->first();
+        ASSERT(firstValue && firstValue->isValueID());
+        if (firstValue)
+            systemKeyword = firstValue->valueID();
+    }
+
+    switch (systemKeyword) {
+    case CSSValueCyclic:
+        return CounterStyleSystem::Cyclic;
+    case CSSValueFixed:
+        return CounterStyleSystem::Fixed;
+    case CSSValueSymbolic:
+        return CounterStyleSystem::Symbolic;
+    case CSSValueAlphabetic:
+        return CounterStyleSystem::Alphabetic;
+    case CSSValueNumeric:
+        return CounterStyleSystem::Numeric;
+    case CSSValueAdditive:
+        return CounterStyleSystem::Additive;
+    case CSSValueExtends:
+        return CounterStyleSystem::Extends;
+    default:
+        ASSERT_NOT_REACHED();
+        return CounterStyleSystem::Symbolic;
+    }
+}
+
+static bool symbolsValidForSystem(CounterStyleSystem system, RefPtr<CSSValue> symbols, RefPtr<CSSValue> additiveSymbols)
+{
+    switch (system) {
+    case CounterStyleSystem::Cyclic:
+    case CounterStyleSystem::Fixed:
+    case CounterStyleSystem::Symbolic:
+        return symbols && symbols->isValueList() && downcast<CSSValueList>(*symbols).length();
+    case CounterStyleSystem::Alphabetic:
+    case CounterStyleSystem::Numeric:
+        return symbols && symbols->isValueList() && downcast<CSSValueList>(*symbols).length() >= 2u;
+    case CounterStyleSystem::Additive:
+        return additiveSymbols && additiveSymbols->isValueList() && downcast<CSSValueList>(*additiveSymbols).length();
+    case CounterStyleSystem::Extends:
+        return !symbols && !additiveSymbols;
+    default:
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+}
+
+bool StyleRuleCounterStyle::newValueInvalidOrEqual(CSSPropertyID propertyID, const RefPtr<CSSValue> newValue) const
+{
+    auto currentValue = m_properties->getPropertyCSSValue(propertyID);
+    if (compareCSSValuePtr(currentValue, newValue))
+        return true;
+
+    RefPtr<CSSValue> symbols;
+    RefPtr<CSSValue> additiveSymbols;
+    switch (propertyID) {
+    case CSSPropertySystem:
+        // If the attribute being set is `system`, and the new value would change the algorithm used, do nothing
+        // and abort these steps.
+        // (It's okay to change an aspect of the algorithm, like the first symbol value of a `fixed` system.)
+        return toCounterStyleSystemEnum(currentValue) != toCounterStyleSystemEnum(newValue);
+    case CSSPropertySymbols:
+        symbols = newValue;
+        additiveSymbols = m_properties->getPropertyCSSValue(CSSPropertyAdditiveSymbols);
+        break;
+    case CSSPropertyAdditiveSymbols:
+        symbols = m_properties->getPropertyCSSValue(CSSPropertySymbols);
+        additiveSymbols = newValue;
+        break;
+    default:
+        return false;
+    }
+    auto system = m_properties->getPropertyCSSValue(CSSPropertySystem);
+    return symbolsValidForSystem(toCounterStyleSystemEnum(system), symbols, additiveSymbols);
+}
+
 StyleRuleCounterStyle::~StyleRuleCounterStyle() = default;
 
 MutableStyleProperties& StyleRuleCounterStyle::mutableProperties()
@@ -64,8 +158,58 @@
 
 String CSSCounterStyleRule::cssText() const
 {
-    // FIXME: Implement this function when we parse @counter-style descriptors.
-    return emptyString();
+    String systemText = system();
+    const char* systemPrefix = systemText.isEmpty() ? "" : " system: ";
+    const char* systemSuffix = systemText.isEmpty() ? "" : ";";
+
+    String symbolsText = symbols();
+    const char* symbolsPrefix = symbolsText.isEmpty() ? "" : " symbols: ";
+    const char* symbolsSuffix = symbolsText.isEmpty() ? "" : ";";
+
+    String additiveSymbolsText = additiveSymbols();
+    const char* additiveSymbolsPrefix = additiveSymbolsText.isEmpty() ? "" : " additive-symbols: ";
+    const char* additiveSymbolsSuffix = additiveSymbolsText.isEmpty() ? "" : ";";
+
+    String negativeText = negative();
+    const char* negativePrefix = negativeText.isEmpty() ? "" : " negative: ";
+    const char* negativeSuffix = negativeText.isEmpty() ? "" : ";";
+
+    String prefixText = prefix();
+    const char* prefixTextPrefix = prefixText.isEmpty() ? "" : " prefix: ";
+    const char* prefixTextSuffix = prefixText.isEmpty() ? "" : ";";
+
+    String suffixText = suffix();
+    const char* suffixTextPrefix = suffixText.isEmpty() ? "" : " suffix: ";
+    const char* suffixTextSuffix = suffixText.isEmpty() ? "" : ";";
+
+    String padText = pad();
+    const char* padPrefix = padText.isEmpty() ? "" : " pad: ";
+    const char* padSuffix = padText.isEmpty() ? "" : ";";
+
+    String rangeText = range();
+    const char* rangePrefix = rangeText.isEmpty() ? "" : " range: ";
+    const char* rangeSuffix = rangeText.isEmpty() ? "" : ";";
+
+    String fallbackText = fallback();
+    const char* fallbackPrefix = fallbackText.isEmpty() ? "" : " fallback: ";
+    const char* fallbackSuffix = fallbackText.isEmpty() ? "" : ";";
+
+    String speakAsText = speakAs();
+    const char* speakAsPrefix = speakAsText.isEmpty() ? "" : " speak-as: ";
+    const char* speakAsSuffix = speakAsText.isEmpty() ? "" : ";";
+
+    return makeString("@counter-style ", name(), " {",
+        systemPrefix, systemText, systemSuffix,
+        symbolsPrefix, symbolsText, symbolsSuffix,
+        additiveSymbolsPrefix, additiveSymbolsText, additiveSymbolsSuffix,
+        negativePrefix, negativeText, negativeSuffix,
+        prefixTextPrefix, prefixText, prefixTextSuffix,
+        suffixTextPrefix, suffixText, suffixTextSuffix,
+        padPrefix, padText, padSuffix,
+        rangePrefix, rangeText, rangeSuffix,
+        fallbackPrefix, fallbackText, fallbackSuffix,
+        speakAsPrefix, speakAsText, speakAsSuffix,
+    " }");
 }
 
 void CSSCounterStyleRule::reattach(StyleRuleBase& rule)
@@ -73,4 +217,79 @@
     m_counterStyleRule = static_cast<StyleRuleCounterStyle&>(rule);
 }
 
+// https://drafts.csswg.org/css-counter-styles-3/#dom-csscounterstylerule-name
+void CSSCounterStyleRule::setName(const String& text)
+{
+    auto tokenizer = CSSTokenizer(text);
+    auto tokenRange = tokenizer.tokenRange();
+    auto name = CSSPropertyParserHelpers::consumeCounterStyleNameInPrelude(tokenRange);
+    if (name.isNull() || name == m_counterStyleRule->name())
+        return;
+
+    CSSStyleSheet::RuleMutationScope mutationScope(this);
+    m_counterStyleRule->setName(name);
+}
+
+void CSSCounterStyleRule::setterInternal(CSSPropertyID propertyID, const String& valueText)
+{
+    auto tokenizer = CSSTokenizer(valueText);
+    auto tokenRange = tokenizer.tokenRange();
+    auto newValue = CSSPropertyParser::parseCounterStyleDescriptor(propertyID, tokenRange, parserContext());
+    if (m_counterStyleRule->newValueInvalidOrEqual(propertyID, newValue))
+        return;
+
+    CSSStyleSheet::RuleMutationScope mutationScope(this);
+    m_counterStyleRule->mutableProperties().setProperty(propertyID, WTFMove(newValue));
+}
+
+void CSSCounterStyleRule::setSystem(const String& text)
+{
+    setterInternal(CSSPropertySystem, text);
+}
+
+void CSSCounterStyleRule::setNegative(const String& text)
+{
+    setterInternal(CSSPropertyNegative, text);
+}
+
+void CSSCounterStyleRule::setPrefix(const String& text)
+{
+    setterInternal(CSSPropertyPrefix, text);
+}
+
+void CSSCounterStyleRule::setSuffix(const String& text)
+{
+    setterInternal(CSSPropertySuffix, text);
+}
+
+void CSSCounterStyleRule::setRange(const String& text)
+{
+    setterInternal(CSSPropertyRange, text);
+}
+
+void CSSCounterStyleRule::setPad(const String& text)
+{
+    setterInternal(CSSPropertyPad, text);
+}
+
+void CSSCounterStyleRule::setFallback(const String& text)
+{
+    setterInternal(CSSPropertyFallback, text);
+}
+
+void CSSCounterStyleRule::setSymbols(const String& text)
+{
+    setterInternal(CSSPropertySymbols, text);
+}
+
+void CSSCounterStyleRule::setAdditiveSymbols(const String& text)
+{
+    setterInternal(CSSPropertyAdditiveSymbols, text);
+}
+
+void CSSCounterStyleRule::setSpeakAs(const String& text)
+{
+    setterInternal(CSSPropertySpeakAs, text);
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/css/CSSCounterStyleRule.h (276487 => 276488)


--- trunk/Source/WebCore/css/CSSCounterStyleRule.h	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/Source/WebCore/css/CSSCounterStyleRule.h	2021-04-23 05:25:40 UTC (rev 276488)
@@ -32,6 +32,18 @@
 
 namespace WebCore {
 
+// The keywords that can be used as values for the counter-style `system` descriptor.
+// https://www.w3.org/TR/css-counter-styles-3/#counter-style-system
+enum class CounterStyleSystem : uint8_t {
+    Cyclic,
+    Numeric,
+    Alphabetic,
+    Symbolic,
+    Additive,
+    Fixed,
+    Extends
+};
+
 class StyleRuleCounterStyle final : public StyleRuleBase {
 public:
     static Ref<StyleRuleCounterStyle> create(const AtomString& name, Ref<StyleProperties>&&);
@@ -41,7 +53,21 @@
     MutableStyleProperties& mutableProperties();
 
     const AtomString& name() const { return m_name; }
+    String system() const { return m_properties->getPropertyValue(CSSPropertySystem); }
+    String negative() const { return m_properties->getPropertyValue(CSSPropertyNegative); }
+    String prefix() const { return m_properties->getPropertyValue(CSSPropertyPrefix); }
+    String suffix() const { return m_properties->getPropertyValue(CSSPropertySuffix); }
+    String range() const { return m_properties->getPropertyValue(CSSPropertyRange); }
+    String pad() const { return m_properties->getPropertyValue(CSSPropertyPad); }
+    String fallback() const { return m_properties->getPropertyValue(CSSPropertyFallback); }
+    String symbols() const { return m_properties->getPropertyValue(CSSPropertySymbols); }
+    String additiveSymbols() const { return m_properties->getPropertyValue(CSSPropertyAdditiveSymbols); }
+    String speakAs() const { return m_properties->getPropertyValue(CSSPropertySpeakAs); }
 
+    bool newValueInvalidOrEqual(CSSPropertyID, const RefPtr<CSSValue> newValue) const;
+
+    void setName(const AtomString& name) { m_name = name; }
+
 private:
     explicit StyleRuleCounterStyle(const AtomString&, Ref<StyleProperties>&&);
 
@@ -59,34 +85,34 @@
     CSSRule::Type type() const final { return COUNTER_STYLE_RULE; }
 
     String name() const { return m_counterStyleRule->name(); }
-    // FIXME: Implement after we parse @counter-style descriptors.
-    String system() const { return emptyString(); }
-    String negative() const { return emptyString(); }
-    String prefix() const { return emptyString(); }
-    String suffix() const { return emptyString(); }
-    String range() const { return emptyString(); }
-    String pad() const { return emptyString(); }
-    String fallback() const { return emptyString(); }
-    String symbols() const { return emptyString(); }
-    String additiveSymbols() const { return emptyString(); }
-    String speakAs() const { return emptyString(); }
+    String system() const { return m_counterStyleRule->system(); }
+    String negative() const { return m_counterStyleRule->negative(); }
+    String prefix() const { return m_counterStyleRule->prefix(); }
+    String suffix() const { return m_counterStyleRule->suffix(); }
+    String range() const { return m_counterStyleRule->range(); }
+    String pad() const { return m_counterStyleRule->pad(); }
+    String fallback() const { return m_counterStyleRule->fallback(); }
+    String symbols() const { return m_counterStyleRule->symbols(); }
+    String additiveSymbols() const { return m_counterStyleRule->additiveSymbols(); }
+    String speakAs() const { return m_counterStyleRule->speakAs(); }
 
-    // FIXME: Implement after we parse @counter-style descriptors.
-    void setName(const String&) { }
-    void setSystem(const String&) { }
-    void setNegative(const String&) { }
-    void setPrefix(const String&) { }
-    void setSuffix(const String&) { }
-    void setRange(const String&) { }
-    void setPad(const String&) { }
-    void setFallback(const String&) { }
-    void setSymbols(const String&) { }
-    void setAdditiveSymbols(const String&) { }
-    void setSpeakAs(const String&) { }
+    void setName(const String&);
+    void setSystem(const String&);
+    void setNegative(const String&);
+    void setPrefix(const String&);
+    void setSuffix(const String&);
+    void setRange(const String&);
+    void setPad(const String&);
+    void setFallback(const String&);
+    void setSymbols(const String&);
+    void setAdditiveSymbols(const String&);
+    void setSpeakAs(const String&);
 
 private:
     CSSCounterStyleRule(StyleRuleCounterStyle&, CSSStyleSheet* parent);
 
+    void setterInternal(CSSPropertyID, const String&);
+
     Ref<StyleRuleCounterStyle> m_counterStyleRule;
 };
 

Modified: trunk/Source/WebCore/css/CSSProperties.json (276487 => 276488)


--- trunk/Source/WebCore/css/CSSProperties.json	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/Source/WebCore/css/CSSProperties.json	2021-04-23 05:25:40 UTC (rev 276488)
@@ -803,6 +803,16 @@
                 "url": "https://www.w3.org/TR/css-ruby-1/#rubypos"
             }
         },
+        "additive-symbols": {
+            "codegen-properties": {
+                "settings-flag": "cssCounterStyleAtRules",
+                "skip-builder": true
+            },
+            "specification": {
+                "category": "css-counter-styles",
+                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-symbols"
+            }
+        },
         "alignment-baseline": {
             "values": [
                 "auto",
@@ -2436,6 +2446,16 @@
                 "category": "svg"
             }
         },
+        "fallback": {
+            "codegen-properties": {
+                "settings-flag": "cssCounterStyleAtRules",
+                "skip-builder": true
+            },
+            "specification": {
+                "category": "css-counter-styles",
+                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-fallback"
+            }
+        },
         "fill": {
             "inherited": true,
             "codegen-properties": {
@@ -3377,6 +3397,16 @@
                 "url": "https://drafts.csswg.org/css-overscroll-1/#propdef-overscroll-behavior-y"
             }
         },
+        "pad": {
+            "codegen-properties": {
+                "settings-flag": "cssCounterStyleAtRules",
+                "skip-builder": true
+            },
+            "specification": {
+                "category": "css-counter-styles",
+                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-pad"
+            }
+        },
         "padding": {
             "codegen-properties": {
                 "longhands": [
@@ -3850,6 +3880,16 @@
                 "url": "https://www.w3.org/TR/css3-speech/#speak-as"
             }
         },
+        "symbols": {
+            "codegen-properties": {
+                "settings-flag": "cssCounterStyleAtRules",
+                "skip-builder": true
+            },
+            "specification": {
+                "category": "css-counter-styles",
+                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-symbols"
+            }
+        },
         "table-layout": {
             "values": [
                 "auto",
@@ -6044,6 +6084,16 @@
             },
             "status": "non-standard"
         },
+        "negative": {
+            "codegen-properties": {
+                "settings-flag": "cssCounterStyleAtRules",
+                "skip-builder": true
+            },
+            "specification": {
+                "category": "css-counter-styles",
+                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-negative"
+            }
+        },
         "color-scheme": {
             "inherited": true,
             "values": [
@@ -6129,6 +6179,16 @@
                 "url": "https://www.w3.org/TR/css-transforms-1/#propdef-perspective-origin"
             }
         },
+        "prefix": {
+            "codegen-properties": {
+                "settings-flag": "cssCounterStyleAtRules",
+                "skip-builder": true
+            },
+            "specification": {
+                "category": "css-counter-styles",
+                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-prefix"
+            }
+        },
         "-webkit-print-color-adjust": {
             "inherited": true,
             "values": [
@@ -6137,6 +6197,16 @@
             ],
             "status": "non-standard"
         },
+        "range": {
+            "codegen-properties": {
+                "settings-flag": "cssCounterStyleAtRules",
+                "skip-builder": true
+            },
+            "specification": {
+                "category": "css-counter-styles",
+                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-range"
+            }
+        },
         "-webkit-rtl-ordering": {
             "inherited": true,
             "values": [
@@ -6149,6 +6219,16 @@
             },
             "status": "non-standard"
         },
+        "suffix": {
+            "codegen-properties": {
+                "settings-flag": "cssCounterStyleAtRules",
+                "skip-builder": true
+            },
+            "specification": {
+                "category": "css-counter-styles",
+                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-suffix"
+            }
+        },
         "-webkit-svg-shadow": {
             "codegen-properties": {
                 "skip-codegen": true
@@ -6971,6 +7051,16 @@
                 "url": "https://www.w3.org/TR/css-shapes/#propdef-shape-image-threshold"
             }
         },
+        "system": {
+            "codegen-properties": {
+                "settings-flag": "cssCounterStyleAtRules",
+                "skip-builder": true
+            },
+            "specification": {
+                "category": "css-counter-styles",
+                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-system"
+            }
+        },
         "-webkit-tap-highlight-color": {
             "inherited": true,
             "codegen-properties": {
@@ -7141,6 +7231,11 @@
             "longname": "CSS Generated Content Module",
             "url": "https://www.w3.org/TR/css-content-3/"
         },
+        "css-counter-styles": {
+            "shortname": "CSS Counter Styles",
+            "longname": "CSS Counter Styles Module",
+            "url": "https://www.w3.org/TR/css-counter-styles-3"
+        },
         "css-device-adapt": {
             "shortname": "CSS Device Adaptation",
             "longname": "CSS Device Adaptation Module",

Modified: trunk/Source/WebCore/css/CSSValueKeywords.in (276487 => 276488)


--- trunk/Source/WebCore/css/CSSValueKeywords.in	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/Source/WebCore/css/CSSValueKeywords.in	2021-04-23 05:25:40 UTC (rev 276488)
@@ -1505,6 +1505,24 @@
 standard
 high
 
+// @counter-style `system` descriptor values
+// https://www.w3.org/TR/css-counter-styles-3/#counter-style-system
+cyclic
+numeric
+// alphabetic
+symbolic
+additive
+// fixed
+extends
+
+// @counter-style `speak-as` descriptor values
+// https://www.w3.org/TR/css-counter-styles-3/#counter-style-speak-as
+// auto
+bullets
+numbers
+words
+// spell-out
+
 // @supports selector()
 // https://drafts.csswg.org/css-conditional-4/#typedef-supports-selector-fn
 selector

Modified: trunk/Source/WebCore/css/parser/CSSParserContext.cpp (276487 => 276488)


--- trunk/Source/WebCore/css/parser/CSSParserContext.cpp	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/Source/WebCore/css/parser/CSSParserContext.cpp	2021-04-23 05:25:40 UTC (rev 276488)
@@ -181,6 +181,16 @@
 bool CSSParserContext::isPropertyRuntimeDisabled(CSSPropertyID property) const
 {
     switch (property) {
+    case CSSPropertyAdditiveSymbols:
+    case CSSPropertyFallback:
+    case CSSPropertyPad:
+    case CSSPropertySymbols:
+    case CSSPropertyNegative:
+    case CSSPropertyPrefix:
+    case CSSPropertyRange:
+    case CSSPropertySuffix:
+    case CSSPropertySystem:
+        return !counterStyleAtRulesEnabled;
     case CSSPropertyAspectRatio:
         return !aspectRatioEnabled;
     case CSSPropertyContain:

Modified: trunk/Source/WebCore/css/parser/CSSPropertyParser.cpp (276487 => 276488)


--- trunk/Source/WebCore/css/parser/CSSPropertyParser.cpp	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/Source/WebCore/css/parser/CSSPropertyParser.cpp	2021-04-23 05:25:40 UTC (rev 276488)
@@ -4535,15 +4535,219 @@
     return nullptr;
 }
 
+// https://www.w3.org/TR/css-counter-styles-3/#counter-style-system
+static RefPtr<CSSPrimitiveValue> consumeCounterStyleSystem(CSSParserTokenRange& range)
+{
+    if (auto ident = consumeIdent<CSSValueCyclic, CSSValueNumeric, CSSValueAlphabetic, CSSValueSymbolic, CSSValueAdditive>(range))
+        return ident;
+
+    if (auto ident = consumeIdent<CSSValueFixed>(range)) {
+        if (range.atEnd())
+            return ident;
+        // If we have the `fixed` keyword but the range is not at the end, the next token must be a integer.
+        // If it's not, this value is invalid.
+        auto firstSymbolValue = consumeInteger(range);
+        if (!firstSymbolValue)
+            return nullptr;
+        return createPrimitiveValuePair(ident.releaseNonNull(), firstSymbolValue.releaseNonNull());
+    }
+
+    if (auto ident = consumeIdent<CSSValueExtends>(range)) {
+        // There must be a `<counter-style-name>` following the `extends` keyword. If there isn't, this value is invalid.
+        auto parsedCounterStyleName = consumeCounterStyleName(range);
+        if (!parsedCounterStyleName)
+            return nullptr;
+        return createPrimitiveValuePair(ident.releaseNonNull(), parsedCounterStyleName.releaseNonNull());
+    }
+    return nullptr;
+}
+
+// https://www.w3.org/TR/css-counter-styles-3/#typedef-symbol
+static RefPtr<CSSValue> consumeCounterStyleSymbol(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+    if (auto string = consumeString(range))
+        return string;
+    if (auto customIdent = consumeCustomIdent(range))
+        return customIdent;
+    // There are inherent difficulties in supporting <image> symbols in @counter-styles, so gate them behind a
+    // flag for now. https://bugs.webkit.org/show_bug.cgi?id=167645
+    if (context.counterStyleAtRuleImageSymbolsEnabled) {
+        if (auto image = consumeImage(range, context, { AllowedImageType::URLFunction, AllowedImageType::GeneratedImage }))
+            return image;
+    }
+    return nullptr;
+}
+
+// https://www.w3.org/TR/css-counter-styles-3/#counter-style-negative
+static RefPtr<CSSValue> consumeCounterStyleNegative(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+    auto prependValue = consumeCounterStyleSymbol(range, context);
+    if (!prependValue)
+        return nullptr;
+    if (range.atEnd())
+        return prependValue;
+
+    auto appendValue = consumeCounterStyleSymbol(range, context);
+    if (!appendValue || !range.atEnd())
+        return nullptr;
+
+    RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
+    values->append(prependValue.releaseNonNull());
+    values->append(appendValue.releaseNonNull());
+    return values;
+}
+
+// https://www.w3.org/TR/css-counter-styles-3/#counter-style-range
+static RefPtr<CSSPrimitiveValue> consumeCounterStyleRangeBound(CSSParserTokenRange& range)
+{
+    if (auto infinite = consumeIdent<CSSValueInfinite>(range))
+        return infinite;
+    if (auto integer = consumeInteger(range))
+        return integer;
+    return nullptr;
+}
+
+// https://www.w3.org/TR/css-counter-styles-3/#counter-style-range
+static RefPtr<CSSValue> consumeCounterStyleRange(CSSParserTokenRange& range)
+{
+    if (auto autoValue = consumeIdent<CSSValueAuto>(range))
+        return autoValue;
+
+    auto rangeList = CSSValueList::createCommaSeparated();
+    do {
+        auto lowerBound = consumeCounterStyleRangeBound(range);
+        if (!lowerBound)
+            return nullptr;
+        auto upperBound = consumeCounterStyleRangeBound(range);
+        if (!upperBound)
+            return nullptr;
+
+        // If the lower bound of any range is higher than the upper bound, the entire descriptor is invalid and must be
+        // ignored.
+        if (lowerBound->isNumber() && upperBound->isNumber() && lowerBound->intValue() > upperBound->intValue())
+            return nullptr;
+        rangeList->append(createPrimitiveValuePair(lowerBound.releaseNonNull(), upperBound.releaseNonNull(), Pair::IdenticalValueEncoding::DoNotCoalesce));
+    } while (consumeCommaIncludingWhitespace(range));
+    if (!range.atEnd() || !rangeList->length())
+        return nullptr;
+    return rangeList;
+}
+
+// https://www.w3.org/TR/css-counter-styles-3/#counter-style-pad
+static RefPtr<CSSValue> consumeCounterStylePad(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+    RefPtr<CSSValue> integer;
+    RefPtr<CSSValue> symbol;
+    while (!integer || !symbol) {
+        if (!integer) {
+            integer = consumeInteger(range, 0);
+            if (integer)
+                continue;
+        }
+        if (!symbol) {
+            symbol = consumeCounterStyleSymbol(range, context);
+            if (symbol)
+                continue;
+        }
+        return nullptr;
+    }
+    if (!range.atEnd())
+        return nullptr;
+    auto values = CSSValueList::createSpaceSeparated();
+    values->append(integer.releaseNonNull());
+    values->append(symbol.releaseNonNull());
+    return values;
+}
+
+// https://www.w3.org/TR/css-counter-styles-3/#counter-style-symbols
+static RefPtr<CSSValue> consumeCounterStyleSymbols(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+    auto symbols = CSSValueList::createSpaceSeparated();
+    while (!range.atEnd()) {
+        auto symbol = consumeCounterStyleSymbol(range, context);
+        if (!symbol)
+            return nullptr;
+        symbols->append(symbol.releaseNonNull());
+    }
+    if (!symbols->length())
+        return nullptr;
+    return symbols;
+}
+
+// https://www.w3.org/TR/css-counter-styles-3/#counter-style-symbols
+static RefPtr<CSSValue> consumeCounterStyleAdditiveSymbols(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+    auto values = CSSValueList::createCommaSeparated();
+    RefPtr<CSSPrimitiveValue> lastInteger;
+    do {
+        RefPtr<CSSPrimitiveValue> integer;
+        RefPtr<CSSValue> symbol;
+        while (!integer || !symbol) {
+            if (!integer) {
+                integer = consumeInteger(range, 0);
+                if (integer)
+                    continue;
+            }
+            if (!symbol) {
+                symbol = consumeCounterStyleSymbol(range, context);
+                if (symbol)
+                    continue;
+            }
+            return nullptr;
+        }
+
+        if (lastInteger) {
+            // The additive tuples must be specified in order of strictly descending
+            // weight; otherwise, the declaration is invalid and must be ignored.
+            if (integer->intValue() >= lastInteger->intValue())
+                return nullptr;
+        }
+        lastInteger = integer;
+        values->append(integer.releaseNonNull());
+        values->append(symbol.releaseNonNull());
+    } while (consumeCommaIncludingWhitespace(range));
+    if (!range.atEnd() || !values->length())
+        return nullptr;
+    return values;
+}
+
+// https://www.w3.org/TR/css-counter-styles-3/#counter-style-speak-as
+static RefPtr<CSSValue> consumeCounterStyleSpeakAs(CSSParserTokenRange& range)
+{
+    if (auto speakAsIdent = consumeIdent<CSSValueAuto, CSSValueBullets, CSSValueNumbers, CSSValueWords, CSSValueSpellOut>(range))
+        return speakAsIdent;
+    return consumeCounterStyleName(range);
+}
+
 RefPtr<CSSValue> CSSPropertyParser::parseCounterStyleDescriptor(CSSPropertyID propId, CSSParserTokenRange& range, const CSSParserContext& context)
 {
     if (!context.counterStyleAtRulesEnabled)
         return nullptr;
-    // FIXME: Implement this function when we can parse @counter-style descriptors.
-    UNUSED_PARAM(propId);
-    UNUSED_PARAM(range);
-    UNUSED_PARAM(context);
-    return nullptr;
+
+    switch (propId) {
+    case CSSPropertySystem:
+        return consumeCounterStyleSystem(range);
+    case CSSPropertyNegative:
+        return consumeCounterStyleNegative(range, context);
+    case CSSPropertyPrefix:
+    case CSSPropertySuffix:
+        return consumeCounterStyleSymbol(range, context);
+    case CSSPropertyRange:
+        return consumeCounterStyleRange(range);
+    case CSSPropertyPad:
+        return consumeCounterStylePad(range, context);
+    case CSSPropertyFallback:
+        return consumeCounterStyleName(range);
+    case CSSPropertySymbols:
+        return consumeCounterStyleSymbols(range, context);
+    case CSSPropertyAdditiveSymbols:
+        return consumeCounterStyleAdditiveSymbols(range, context);
+    case CSSPropertySpeakAs:
+        return consumeCounterStyleSpeakAs(range);
+    default:
+        ASSERT_NOT_REACHED();
+        return nullptr;
+    }
 }
 
 bool CSSPropertyParser::parseCounterStyleDescriptor(CSSPropertyID propId, const CSSParserContext& context)

Modified: trunk/Tools/ChangeLog (276487 => 276488)


--- trunk/Tools/ChangeLog	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/Tools/ChangeLog	2021-04-23 05:25:40 UTC (rev 276488)
@@ -1,3 +1,15 @@
+2021-04-22  Tyler Wilcock  <[email protected]>
+
+        [css-counter-styles] Parse @counter-style descriptors
+        https://bugs.webkit.org/show_bug.cgi?id=224718
+
+        Reviewed by Darin Adler.
+
+        * DumpRenderTree/TestOptions.cpp:
+        (WTR::TestOptions::defaults):
+        Fix typo (missing 's').  CSSCounterStyleAtRulesEnabled, not
+        CSSCounterStyleAtRuleEnabled.
+
 2021-04-22  BJ Burg  <[email protected]>
 
         [Cocoa] re-enable test case WKInspectorDelegate.InspectorConfiguration

Modified: trunk/Tools/DumpRenderTree/TestOptions.cpp (276487 => 276488)


--- trunk/Tools/DumpRenderTree/TestOptions.cpp	2021-04-23 05:20:30 UTC (rev 276487)
+++ trunk/Tools/DumpRenderTree/TestOptions.cpp	2021-04-23 05:25:40 UTC (rev 276488)
@@ -133,7 +133,7 @@
             { "AsyncClipboardAPIEnabled", false },
             { "AttachmentElementEnabled", false },
             { "CSSContainmentEnabled", false },
-            { "CSSCounterStyleAtRuleEnabled", false },
+            { "CSSCounterStyleAtRulesEnabled", false },
             { "CSSCounterStyleAtRuleImageSymbolsEnabled", false },
             { "CSSLogicalEnabled", false },
             { "CSSOMViewSmoothScrollingEnabled", false },
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to