Changeset 276488 in webkit


Ignore:
Timestamp:
Apr 22, 2021 10:25:40 PM (15 months ago)
Author:
commit-queue@webkit.org
Message:

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

Patch by Tyler Wilcock <Tyler Wilcock> 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=edit

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=edit

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

Location:
trunk
Files:
2 added
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r276484 r276488  
     12021-04-22  Tyler Wilcock  <twilco.o@protonmail.com>
     2
     3        [css-counter-styles] Parse @counter-style descriptors
     4        https://bugs.webkit.org/show_bug.cgi?id=224718
     5
     6        Reviewed by Darin Adler.
     7
     8        Add test ensuring <image> @counter-style symbol values cannot be
     9        parsed when the `counterStyleAtRuleImageSymbolsEnabled` feature flag
     10        is disabled.
     11
     12        ---
     13
     14        This test is skipped on Windows because I haven't been able to get the
     15        required feature flags (CSSCounterStyleAtRulesEnabled and
     16        CSSCounterStyleAtRuleImageSymbolsEnabled) to work properly for that
     17        port.
     18
     19        The code hidden behind these flags is all in the CSS parser, which is not
     20        unique to Windows, so I think we can be confident that if the test passes
     21        on all other platforms, that the behavior is correct on Windows too.
     22
     23        One attempt at implementing the necessary Windows-specific flag functionality is here:
     24
     25        https://bugs.webkit.org/attachment.cgi?id=426371&action=edit
     26
     27        Which failed to compile[1] with this error:
     28
     29        > 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]
     30        > 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]
     31
     32        Those methods are present in `IWebPreferencesPrivate7.idl`, and implemented similarly to other
     33        flags in other places (e.g. win/WebPreferences.{h, cpp}, win/WebPreferenceKeysPrivate.h).
     34        I can't reproduce this compilation error on my Windows machine.
     35
     36        I then tried removing the lines that caused the above compilation failure.
     37        Those setters are called in DumpRenderTree::enableExperimentalFeatures, so in
     38        lieu of enabling these flags there I could enable the flag I need via test header.
     39
     40        That patch is: https://bugs.webkit.org/attachment.cgi?id=426509&action=edit
     41
     42        This results in successful compilation, but causes lots (all?) of the
     43        layout tests to fail[2] with a stacktrace that looks like:
     44
     4500007ffc`3e9e3113 WebKit!WebPreferences::speechRecognitionEnabled(int * enabled = 0x00007ffc`3eae0f50)+0x29 [C:\cygwin\home\buildbot\worker\Windows-EWS\build\Source\WebKitLegacy\win\WebPreferences.cpp @ 2617]
     4600007ffc`3e9e3cc0 DumpRenderTreeLib!resetWebPreferencesToConsistentValues(struct IWebPreferences * preferences = 0x00000205`e2f204b0)+0x63 [C:\cygwin\home\buildbot\worker\Windows-EWS\build\Tools\DumpRenderTree\win\DumpRenderTree.cpp @ 847]
     4700007ffc`3e9e4171 DumpRenderTreeLib!resetWebViewToConsistentStateBeforeTesting(class WTR::TestOptions * options = 0x00000065`738fea60)+0x2e0 [C:\cygwin\home\buildbot\worker\Windows-EWS\build\Tools\DumpRenderTree\win\DumpRenderTree.cpp @ 1054]
     4800007ffc`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]
     4900007ff7`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]
     5000007ff7`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]
     51
     52        I haven't done much digging into why this happens, and cannot reproduce it on my Windows machine.
     53
     54        [1]: https://ews-build.webkit.org/#/builders/10/builds/86747
     55        [2]: https://ews-build.webkit.org/#/builders/10/builds/86897
     56
     57        * platform/win/TestExpectations: Skip newly added test on Windows.
     58        * webexposed/counter-style-image-symbols-not-exposed-expected.txt: Added.
     59        * webexposed/counter-style-image-symbols-not-exposed.html: Added.
     60
    1612021-04-22  Megan Gardner  <megan_gardner@apple.com>
    262
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r276465 r276488  
     12021-04-22  Tyler Wilcock  <twilco.o@protonmail.com>
     2
     3        [css-counter-styles] Parse @counter-style descriptors
     4        https://bugs.webkit.org/show_bug.cgi?id=224718
     5
     6        Reviewed by Darin Adler.
     7
     8        Parsing for all @counter-style descriptors is implemented with this
     9        patch, so mark more tests passing.
     10
     11        You'll notice that some @counter-style descriptors implemented in this
     12        patch did not gain any passing tests (e.g. `pad`, `negative`).  In all
     13        of these cases, the expected results contain a <string> value, and we
     14        fail only because we incorrectly don't serialize these <string> values
     15        with quotes.  I have manually confirmed in all cases that these values
     16        are properly parsed, so it's just the serialization that's incorrect.
     17
     18        These <string> values serialize without quotes because WebKit's representation
     19        of custom identifiers is not a separate type, but instead overloaded onto the
     20        CSS_STRING type.  This means that during serialization time, WebKit must guess
     21        whether it is actually serializing a string (and include quotes if so), or if
     22        it's serializing a custom ident (leaving off quotes if so).
     23
     24        Relevant code snippet:
     25
     26        https://github.com/WebKit/WebKit/blob/36caeec07975bd5f47db8ac6b749c2787230a461/Source/WebCore/css/CSSMarkup.cpp#L153#L161
     27
     28        Relevant changelog snippet from David Hyatt, 2016-12-07:
     29
     30        > We also overload CSS_STRING primitive value type and have it act as both a string
     31        > and a custom identifier. This is lame, since the parser should have made two different
     32        > types of objects instead, but since our parser doesn't do that yet, I added a serializeAsStringOrCustomIdent
     33        > that preserves our old behavior of "quote the string only if needed." In this case what
     34        > that really meant was "Try to guess that we were originally a custom ident and leave off
     35        > quotes if so." This function will go away once we properly create CSSStringValues and
     36        > CSSCustomIdentValues instead of turning the latter into strings.
     37
     38        * web-platform-tests/css/css-counter-styles/counter-style-fallback-expected.txt:
     39        * web-platform-tests/css/css-counter-styles/counter-style-prefix-suffix-syntax-expected.txt:
     40        * web-platform-tests/css/css-counter-styles/counter-style-range-syntax-expected.txt:
     41        * web-platform-tests/css/css-counter-styles/counter-style-speak-as-syntax-expected.txt:
     42        * web-platform-tests/css/css-counter-styles/counter-style-system-syntax-expected.txt:
     43
    1442021-04-22  Antoine Quint  <graouts@webkit.org>
    245
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-fallback-expected.txt

    r276418 r276488  
    11
    2 FAIL @counter-style 'fallback: bar' is valid assert_not_equals: got disallowed value -1
     2PASS @counter-style 'fallback: bar' is valid
    33PASS @counter-style 'fallback: "bar"' is invalid
    44PASS @counter-style 'fallback: none' is invalid
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-prefix-suffix-syntax-expected.txt

    r276418 r276488  
    88FAIL @counter-style 'prefix: "unset"' is valid assert_not_equals: got disallowed value -1
    99FAIL @counter-style 'suffix: "unset"' is valid assert_not_equals: got disallowed value -1
    10 FAIL @counter-style 'prefix: custom-ident' is valid assert_not_equals: got disallowed value -1
    11 FAIL @counter-style 'suffix: custom-ident' is valid assert_not_equals: got disallowed value -1
     10PASS @counter-style 'prefix: custom-ident' is valid
     11PASS @counter-style 'suffix: custom-ident' is valid
    1212PASS @counter-style 'prefix: initial' is invalid
    1313PASS @counter-style 'suffix: initial' is invalid
     
    1616PASS @counter-style 'prefix: unset' is invalid
    1717PASS @counter-style 'suffix: unset' is invalid
    18 FAIL @counter-style 'prefix: url("https://example.com/foo.png")' is valid assert_not_equals: got disallowed value -1
    19 FAIL @counter-style 'suffix: url("https://example.com/foo.png")' is valid assert_not_equals: got disallowed value -1
    20 FAIL @counter-style 'prefix: url(https://example.com/foo.png)' is valid assert_not_equals: got disallowed value -1
    21 FAIL @counter-style 'suffix: url(https://example.com/foo.png)' is valid assert_not_equals: got disallowed value -1
    22 FAIL @counter-style 'prefix: linear-gradient(yellow, blue)' is valid assert_not_equals: got disallowed value -1
    23 FAIL @counter-style 'suffix: linear-gradient(yellow, blue)' is valid assert_not_equals: got disallowed value -1
     18PASS @counter-style 'prefix: url("https://example.com/foo.png")' is valid
     19PASS @counter-style 'suffix: url("https://example.com/foo.png")' is valid
     20PASS @counter-style 'prefix: url(https://example.com/foo.png)' is valid
     21PASS @counter-style 'suffix: url(https://example.com/foo.png)' is valid
     22PASS @counter-style 'prefix: linear-gradient(yellow, blue)' is valid
     23PASS @counter-style 'suffix: linear-gradient(yellow, blue)' is valid
    2424PASS @counter-style 'prefix: ' is invalid
    2525PASS @counter-style 'suffix: ' is invalid
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-range-syntax-expected.txt

    r276418 r276488  
    11
    2 FAIL @counter-style 'range: auto' is valid assert_not_equals: got disallowed value -1
    3 FAIL @counter-style 'range: infinite infinite' is valid assert_not_equals: got disallowed value -1
    4 FAIL @counter-style 'range: infinite 0' is valid assert_not_equals: got disallowed value -1
    5 FAIL @counter-style 'range: 0 infinite' is valid assert_not_equals: got disallowed value -1
    6 FAIL @counter-style 'range: infinite 0, 5 10, 100 infinite' is valid assert_not_equals: got disallowed value -1
    7 FAIL @counter-style 'range: infinite 10, 5 20, 15 infinite' is valid assert_not_equals: got disallowed value -1
     2PASS @counter-style 'range: auto' is valid
     3PASS @counter-style 'range: infinite infinite' is valid
     4PASS @counter-style 'range: infinite 0' is valid
     5PASS @counter-style 'range: 0 infinite' is valid
     6PASS @counter-style 'range: infinite 0, 5 10, 100 infinite' is valid
     7PASS @counter-style 'range: infinite 10, 5 20, 15 infinite' is valid
    88PASS @counter-style 'range: ' is invalid
    99PASS @counter-style 'range: 0 -1' is invalid
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-speak-as-syntax-expected.txt

    r276418 r276488  
    11
    2 FAIL @counter-style 'speak-as: auto' is valid assert_not_equals: got disallowed value -1
    3 FAIL @counter-style 'speak-as: bullets' is valid assert_not_equals: got disallowed value -1
    4 FAIL @counter-style 'speak-as: numbers' is valid assert_not_equals: got disallowed value -1
    5 FAIL @counter-style 'speak-as: words' is valid assert_not_equals: got disallowed value -1
    6 FAIL @counter-style 'speak-as: spell-out' is valid assert_not_equals: got disallowed value -1
    7 FAIL @counter-style 'speak-as: bar' is valid assert_not_equals: got disallowed value -1
    8 FAIL @counter-style 'speak-as: spellout' is valid assert_not_equals: got disallowed value -1
     2PASS @counter-style 'speak-as: auto' is valid
     3PASS @counter-style 'speak-as: bullets' is valid
     4PASS @counter-style 'speak-as: numbers' is valid
     5PASS @counter-style 'speak-as: words' is valid
     6PASS @counter-style 'speak-as: spell-out' is valid
     7PASS @counter-style 'speak-as: bar' is valid
     8PASS @counter-style 'speak-as: spellout' is valid
    99PASS @counter-style 'speak-as: bullets numbers' is invalid
    1010PASS @counter-style 'speak-as: none' is invalid
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-counter-styles/counter-style-system-syntax-expected.txt

    r276418 r276488  
    11
    2 FAIL @counter-style 'system: cyclic' is valid assert_not_equals: got disallowed value -1
    3 FAIL @counter-style 'system: fixed' is valid assert_not_equals: got disallowed value -1
    4 FAIL @counter-style 'system: fixed 100' is valid assert_not_equals: got disallowed value -1
    5 FAIL @counter-style 'system: fixed -1' is valid assert_not_equals: got disallowed value -1
    6 FAIL @counter-style 'system: symbolic' is valid assert_not_equals: got disallowed value -1
    7 FAIL @counter-style 'system: alphabetic' is valid assert_not_equals: got disallowed value -1
    8 FAIL @counter-style 'system: numeric' is valid assert_not_equals: got disallowed value -1
    9 FAIL @counter-style 'system: additive' is valid assert_not_equals: got disallowed value -1
    10 FAIL @counter-style 'system: extends bar' is valid assert_not_equals: got disallowed value -1
     2PASS @counter-style 'system: cyclic' is valid
     3PASS @counter-style 'system: fixed' is valid
     4PASS @counter-style 'system: fixed 100' is valid
     5PASS @counter-style 'system: fixed -1' is valid
     6PASS @counter-style 'system: symbolic' is valid
     7PASS @counter-style 'system: alphabetic' is valid
     8PASS @counter-style 'system: numeric' is valid
     9PASS @counter-style 'system: additive' is valid
     10PASS @counter-style 'system: extends bar' is valid
    1111PASS @counter-style 'system: float' is invalid
    1212PASS @counter-style 'system: cyclic cyclic' is invalid
  • trunk/LayoutTests/platform/win/TestExpectations

    r276418 r276488  
    46584658fast/forms/password-doubleclick-selection.html [ Pass Failure ]
    46594659fast/text/offsetForPosition-complex-fallback.html [ Pass Failure ]
     4660
     4661# This test is skipped because the necessary feature flag functionality specific to the Windows WebKit legacy port is
     4662# not implemented.  The feature flags in question are CSSCounterStyleAtRulesEnabled and CSSCounterStyleAtRuleImageSymbolsEnabled.
     4663webexposed/counter-style-image-symbols-not-exposed.html [ Skip ]
  • trunk/Source/WebCore/ChangeLog

    r276484 r276488  
     12021-04-22  Tyler Wilcock  <twilco.o@protonmail.com>
     2
     3        [css-counter-styles] Parse @counter-style descriptors
     4        https://bugs.webkit.org/show_bug.cgi?id=224718
     5
     6        Reviewed by Darin Adler.
     7
     8        Implement parsing and CSSCounterStyleRule IDL interface for @counter-style descriptors.
     9        See spec for full details on all descriptors:
     10
     11        https://drafts.csswg.org/css-counter-styles-3/#the-counter-style-rule
     12
     13        Test: webexposed/counter-style-image-symbols-not-exposed.html and WPTs
     14
     15        * css/CSSComputedStyleDeclaration.cpp:
     16        (WebCore::ComputedStyleExtractor::valueForPropertyInStyle):
     17        Return `nullptr` for new @counter-style descriptor properties.
     18
     19        * css/CSSCounterStyleRule.cpp:
     20        (WebCore::toCounterStyleSystemEnum):
     21        (WebCore::symbolsValidForSystem):
     22        (WebCore::StyleRuleCounterStyle::newValueInvalidOrEqual const):
     23        (WebCore::CSSCounterStyleRule::cssText const):
     24        (WebCore::CSSCounterStyleRule::setName):
     25        (WebCore::CSSCounterStyleRule::setterInternal):
     26        (WebCore::CSSCounterStyleRule::setSystem):
     27        (WebCore::CSSCounterStyleRule::setNegative):
     28        (WebCore::CSSCounterStyleRule::setPrefix):
     29        (WebCore::CSSCounterStyleRule::setSuffix):
     30        (WebCore::CSSCounterStyleRule::setRange):
     31        (WebCore::CSSCounterStyleRule::setPad):
     32        (WebCore::CSSCounterStyleRule::setFallback):
     33        (WebCore::CSSCounterStyleRule::setSymbols):
     34        (WebCore::CSSCounterStyleRule::setAdditiveSymbols):
     35        (WebCore::CSSCounterStyleRule::setSpeakAs):
     36        Implement setters and tangential functionality required by setters.
     37
     38        * css/CSSCounterStyleRule.h:
     39        Replace FIXME with actual descriptor getter and setter
     40        implementations.
     41
     42        * css/CSSProperties.json:
     43        Add @counter-style descriptor properties.
     44
     45        * css/CSSValueKeywords.in:
     46        Add new values required for `system` and `speak-as`
     47        @counter-style descriptor properties.
     48
     49        * css/parser/CSSParserContext.cpp:
     50        (WebCore::CSSParserContext::isPropertyRuntimeDisabled const):
     51        Ensure new @counter-style descriptors are disabled at runtime based
     52        on CSSParserContext state.
     53
     54        * css/parser/CSSPropertyParser.cpp:
     55        (WebCore::consumeCounterStyleSystem):
     56        (WebCore::consumeCounterStyleSymbol):
     57        (WebCore::consumeCounterStyleNegative):
     58        (WebCore::consumeCounterStyleRangeBound):
     59        (WebCore::consumeCounterStyleRange):
     60        (WebCore::consumeCounterStylePad):
     61        (WebCore::consumeCounterStyleSymbols):
     62        (WebCore::consumeCounterStyleAdditiveSymbols):
     63        (WebCore::consumeCounterStyleSpeakAs):
     64        (WebCore::CSSPropertyParser::parseCounterStyleDescriptor):
     65        Parse @counter-style descriptors.
     66
    1672021-04-22  Megan Gardner  <megan_gardner@apple.com>
    268
  • trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp

    r276418 r276488  
    40044004            break;
    40054005
     4006        // These are intentionally unimplemented because they are actually descriptors for @counter-style.
     4007        case CSSPropertySystem:
     4008        case CSSPropertyNegative:
     4009        case CSSPropertyPrefix:
     4010        case CSSPropertySuffix:
     4011        case CSSPropertyRange:
     4012        case CSSPropertyPad:
     4013        case CSSPropertyFallback:
     4014        case CSSPropertySymbols:
     4015        case CSSPropertyAdditiveSymbols:
     4016            break;
     4017
    40064018        /* Unimplemented @font-face properties */
    40074019        case CSSPropertySrc:
  • trunk/Source/WebCore/css/CSSCounterStyleRule.cpp

    r276418 r276488  
    2727#include "CSSCounterStyleRule.h"
    2828
     29#include "CSSPropertyParser.h"
     30#include "CSSStyleSheet.h"
     31#include "CSSTokenizer.h"
     32#include "Pair.h"
     33#include <wtf/text/StringBuilder.h>
     34
    2935namespace WebCore {
    3036   
     
    4147}
    4248
     49static CounterStyleSystem toCounterStyleSystemEnum(RefPtr<CSSValue> system)
     50{
     51    if (!system || !system->isPrimitiveValue())
     52        return CounterStyleSystem::Symbolic;
     53
     54    auto& primitiveSystemValue = downcast<CSSPrimitiveValue>(*system);
     55    ASSERT(primitiveSystemValue.isValueID() || primitiveSystemValue.isPair());
     56    CSSValueID systemKeyword = CSSValueInvalid;
     57    if (primitiveSystemValue.isValueID())
     58        systemKeyword = primitiveSystemValue.valueID();
     59    else if (auto* pair = primitiveSystemValue.pairValue()) {
     60        // This value must be `fixed` or `extends`, both of which can or must have an additional component.
     61        auto firstValue = pair->first();
     62        ASSERT(firstValue && firstValue->isValueID());
     63        if (firstValue)
     64            systemKeyword = firstValue->valueID();
     65    }
     66
     67    switch (systemKeyword) {
     68    case CSSValueCyclic:
     69        return CounterStyleSystem::Cyclic;
     70    case CSSValueFixed:
     71        return CounterStyleSystem::Fixed;
     72    case CSSValueSymbolic:
     73        return CounterStyleSystem::Symbolic;
     74    case CSSValueAlphabetic:
     75        return CounterStyleSystem::Alphabetic;
     76    case CSSValueNumeric:
     77        return CounterStyleSystem::Numeric;
     78    case CSSValueAdditive:
     79        return CounterStyleSystem::Additive;
     80    case CSSValueExtends:
     81        return CounterStyleSystem::Extends;
     82    default:
     83        ASSERT_NOT_REACHED();
     84        return CounterStyleSystem::Symbolic;
     85    }
     86}
     87
     88static bool symbolsValidForSystem(CounterStyleSystem system, RefPtr<CSSValue> symbols, RefPtr<CSSValue> additiveSymbols)
     89{
     90    switch (system) {
     91    case CounterStyleSystem::Cyclic:
     92    case CounterStyleSystem::Fixed:
     93    case CounterStyleSystem::Symbolic:
     94        return symbols && symbols->isValueList() && downcast<CSSValueList>(*symbols).length();
     95    case CounterStyleSystem::Alphabetic:
     96    case CounterStyleSystem::Numeric:
     97        return symbols && symbols->isValueList() && downcast<CSSValueList>(*symbols).length() >= 2u;
     98    case CounterStyleSystem::Additive:
     99        return additiveSymbols && additiveSymbols->isValueList() && downcast<CSSValueList>(*additiveSymbols).length();
     100    case CounterStyleSystem::Extends:
     101        return !symbols && !additiveSymbols;
     102    default:
     103        ASSERT_NOT_REACHED();
     104        return false;
     105    }
     106}
     107
     108bool StyleRuleCounterStyle::newValueInvalidOrEqual(CSSPropertyID propertyID, const RefPtr<CSSValue> newValue) const
     109{
     110    auto currentValue = m_properties->getPropertyCSSValue(propertyID);
     111    if (compareCSSValuePtr(currentValue, newValue))
     112        return true;
     113
     114    RefPtr<CSSValue> symbols;
     115    RefPtr<CSSValue> additiveSymbols;
     116    switch (propertyID) {
     117    case CSSPropertySystem:
     118        // If the attribute being set is `system`, and the new value would change the algorithm used, do nothing
     119        // and abort these steps.
     120        // (It's okay to change an aspect of the algorithm, like the first symbol value of a `fixed` system.)
     121        return toCounterStyleSystemEnum(currentValue) != toCounterStyleSystemEnum(newValue);
     122    case CSSPropertySymbols:
     123        symbols = newValue;
     124        additiveSymbols = m_properties->getPropertyCSSValue(CSSPropertyAdditiveSymbols);
     125        break;
     126    case CSSPropertyAdditiveSymbols:
     127        symbols = m_properties->getPropertyCSSValue(CSSPropertySymbols);
     128        additiveSymbols = newValue;
     129        break;
     130    default:
     131        return false;
     132    }
     133    auto system = m_properties->getPropertyCSSValue(CSSPropertySystem);
     134    return symbolsValidForSystem(toCounterStyleSystemEnum(system), symbols, additiveSymbols);
     135}
     136
    43137StyleRuleCounterStyle::~StyleRuleCounterStyle() = default;
    44138
     
    65159String CSSCounterStyleRule::cssText() const
    66160{
    67     // FIXME: Implement this function when we parse @counter-style descriptors.
    68     return emptyString();
     161    String systemText = system();
     162    const char* systemPrefix = systemText.isEmpty() ? "" : " system: ";
     163    const char* systemSuffix = systemText.isEmpty() ? "" : ";";
     164
     165    String symbolsText = symbols();
     166    const char* symbolsPrefix = symbolsText.isEmpty() ? "" : " symbols: ";
     167    const char* symbolsSuffix = symbolsText.isEmpty() ? "" : ";";
     168
     169    String additiveSymbolsText = additiveSymbols();
     170    const char* additiveSymbolsPrefix = additiveSymbolsText.isEmpty() ? "" : " additive-symbols: ";
     171    const char* additiveSymbolsSuffix = additiveSymbolsText.isEmpty() ? "" : ";";
     172
     173    String negativeText = negative();
     174    const char* negativePrefix = negativeText.isEmpty() ? "" : " negative: ";
     175    const char* negativeSuffix = negativeText.isEmpty() ? "" : ";";
     176
     177    String prefixText = prefix();
     178    const char* prefixTextPrefix = prefixText.isEmpty() ? "" : " prefix: ";
     179    const char* prefixTextSuffix = prefixText.isEmpty() ? "" : ";";
     180
     181    String suffixText = suffix();
     182    const char* suffixTextPrefix = suffixText.isEmpty() ? "" : " suffix: ";
     183    const char* suffixTextSuffix = suffixText.isEmpty() ? "" : ";";
     184
     185    String padText = pad();
     186    const char* padPrefix = padText.isEmpty() ? "" : " pad: ";
     187    const char* padSuffix = padText.isEmpty() ? "" : ";";
     188
     189    String rangeText = range();
     190    const char* rangePrefix = rangeText.isEmpty() ? "" : " range: ";
     191    const char* rangeSuffix = rangeText.isEmpty() ? "" : ";";
     192
     193    String fallbackText = fallback();
     194    const char* fallbackPrefix = fallbackText.isEmpty() ? "" : " fallback: ";
     195    const char* fallbackSuffix = fallbackText.isEmpty() ? "" : ";";
     196
     197    String speakAsText = speakAs();
     198    const char* speakAsPrefix = speakAsText.isEmpty() ? "" : " speak-as: ";
     199    const char* speakAsSuffix = speakAsText.isEmpty() ? "" : ";";
     200
     201    return makeString("@counter-style ", name(), " {",
     202        systemPrefix, systemText, systemSuffix,
     203        symbolsPrefix, symbolsText, symbolsSuffix,
     204        additiveSymbolsPrefix, additiveSymbolsText, additiveSymbolsSuffix,
     205        negativePrefix, negativeText, negativeSuffix,
     206        prefixTextPrefix, prefixText, prefixTextSuffix,
     207        suffixTextPrefix, suffixText, suffixTextSuffix,
     208        padPrefix, padText, padSuffix,
     209        rangePrefix, rangeText, rangeSuffix,
     210        fallbackPrefix, fallbackText, fallbackSuffix,
     211        speakAsPrefix, speakAsText, speakAsSuffix,
     212    " }");
    69213}
    70214
     
    74218}
    75219
     220// https://drafts.csswg.org/css-counter-styles-3/#dom-csscounterstylerule-name
     221void CSSCounterStyleRule::setName(const String& text)
     222{
     223    auto tokenizer = CSSTokenizer(text);
     224    auto tokenRange = tokenizer.tokenRange();
     225    auto name = CSSPropertyParserHelpers::consumeCounterStyleNameInPrelude(tokenRange);
     226    if (name.isNull() || name == m_counterStyleRule->name())
     227        return;
     228
     229    CSSStyleSheet::RuleMutationScope mutationScope(this);
     230    m_counterStyleRule->setName(name);
     231}
     232
     233void CSSCounterStyleRule::setterInternal(CSSPropertyID propertyID, const String& valueText)
     234{
     235    auto tokenizer = CSSTokenizer(valueText);
     236    auto tokenRange = tokenizer.tokenRange();
     237    auto newValue = CSSPropertyParser::parseCounterStyleDescriptor(propertyID, tokenRange, parserContext());
     238    if (m_counterStyleRule->newValueInvalidOrEqual(propertyID, newValue))
     239        return;
     240
     241    CSSStyleSheet::RuleMutationScope mutationScope(this);
     242    m_counterStyleRule->mutableProperties().setProperty(propertyID, WTFMove(newValue));
     243}
     244
     245void CSSCounterStyleRule::setSystem(const String& text)
     246{
     247    setterInternal(CSSPropertySystem, text);
     248}
     249
     250void CSSCounterStyleRule::setNegative(const String& text)
     251{
     252    setterInternal(CSSPropertyNegative, text);
     253}
     254
     255void CSSCounterStyleRule::setPrefix(const String& text)
     256{
     257    setterInternal(CSSPropertyPrefix, text);
     258}
     259
     260void CSSCounterStyleRule::setSuffix(const String& text)
     261{
     262    setterInternal(CSSPropertySuffix, text);
     263}
     264
     265void CSSCounterStyleRule::setRange(const String& text)
     266{
     267    setterInternal(CSSPropertyRange, text);
     268}
     269
     270void CSSCounterStyleRule::setPad(const String& text)
     271{
     272    setterInternal(CSSPropertyPad, text);
     273}
     274
     275void CSSCounterStyleRule::setFallback(const String& text)
     276{
     277    setterInternal(CSSPropertyFallback, text);
     278}
     279
     280void CSSCounterStyleRule::setSymbols(const String& text)
     281{
     282    setterInternal(CSSPropertySymbols, text);
     283}
     284
     285void CSSCounterStyleRule::setAdditiveSymbols(const String& text)
     286{
     287    setterInternal(CSSPropertyAdditiveSymbols, text);
     288}
     289
     290void CSSCounterStyleRule::setSpeakAs(const String& text)
     291{
     292    setterInternal(CSSPropertySpeakAs, text);
     293}
     294
    76295} // namespace WebCore
  • trunk/Source/WebCore/css/CSSCounterStyleRule.h

    r276418 r276488  
    3333namespace WebCore {
    3434
     35// The keywords that can be used as values for the counter-style `system` descriptor.
     36// https://www.w3.org/TR/css-counter-styles-3/#counter-style-system
     37enum class CounterStyleSystem : uint8_t {
     38    Cyclic,
     39    Numeric,
     40    Alphabetic,
     41    Symbolic,
     42    Additive,
     43    Fixed,
     44    Extends
     45};
     46
    3547class StyleRuleCounterStyle final : public StyleRuleBase {
    3648public:
     
    4254
    4355    const AtomString& name() const { return m_name; }
     56    String system() const { return m_properties->getPropertyValue(CSSPropertySystem); }
     57    String negative() const { return m_properties->getPropertyValue(CSSPropertyNegative); }
     58    String prefix() const { return m_properties->getPropertyValue(CSSPropertyPrefix); }
     59    String suffix() const { return m_properties->getPropertyValue(CSSPropertySuffix); }
     60    String range() const { return m_properties->getPropertyValue(CSSPropertyRange); }
     61    String pad() const { return m_properties->getPropertyValue(CSSPropertyPad); }
     62    String fallback() const { return m_properties->getPropertyValue(CSSPropertyFallback); }
     63    String symbols() const { return m_properties->getPropertyValue(CSSPropertySymbols); }
     64    String additiveSymbols() const { return m_properties->getPropertyValue(CSSPropertyAdditiveSymbols); }
     65    String speakAs() const { return m_properties->getPropertyValue(CSSPropertySpeakAs); }
     66
     67    bool newValueInvalidOrEqual(CSSPropertyID, const RefPtr<CSSValue> newValue) const;
     68
     69    void setName(const AtomString& name) { m_name = name; }
    4470
    4571private:
     
    6086
    6187    String name() const { return m_counterStyleRule->name(); }
    62     // FIXME: Implement after we parse @counter-style descriptors.
    63     String system() const { return emptyString(); }
    64     String negative() const { return emptyString(); }
    65     String prefix() const { return emptyString(); }
    66     String suffix() const { return emptyString(); }
    67     String range() const { return emptyString(); }
    68     String pad() const { return emptyString(); }
    69     String fallback() const { return emptyString(); }
    70     String symbols() const { return emptyString(); }
    71     String additiveSymbols() const { return emptyString(); }
    72     String speakAs() const { return emptyString(); }
     88    String system() const { return m_counterStyleRule->system(); }
     89    String negative() const { return m_counterStyleRule->negative(); }
     90    String prefix() const { return m_counterStyleRule->prefix(); }
     91    String suffix() const { return m_counterStyleRule->suffix(); }
     92    String range() const { return m_counterStyleRule->range(); }
     93    String pad() const { return m_counterStyleRule->pad(); }
     94    String fallback() const { return m_counterStyleRule->fallback(); }
     95    String symbols() const { return m_counterStyleRule->symbols(); }
     96    String additiveSymbols() const { return m_counterStyleRule->additiveSymbols(); }
     97    String speakAs() const { return m_counterStyleRule->speakAs(); }
    7398
    74     // FIXME: Implement after we parse @counter-style descriptors.
    75     void setName(const String&) { }
    76     void setSystem(const String&) { }
    77     void setNegative(const String&) { }
    78     void setPrefix(const String&) { }
    79     void setSuffix(const String&) { }
    80     void setRange(const String&) { }
    81     void setPad(const String&) { }
    82     void setFallback(const String&) { }
    83     void setSymbols(const String&) { }
    84     void setAdditiveSymbols(const String&) { }
    85     void setSpeakAs(const String&) { }
     99    void setName(const String&);
     100    void setSystem(const String&);
     101    void setNegative(const String&);
     102    void setPrefix(const String&);
     103    void setSuffix(const String&);
     104    void setRange(const String&);
     105    void setPad(const String&);
     106    void setFallback(const String&);
     107    void setSymbols(const String&);
     108    void setAdditiveSymbols(const String&);
     109    void setSpeakAs(const String&);
    86110
    87111private:
    88112    CSSCounterStyleRule(StyleRuleCounterStyle&, CSSStyleSheet* parent);
     113
     114    void setterInternal(CSSPropertyID, const String&);
    89115
    90116    Ref<StyleRuleCounterStyle> m_counterStyleRule;
  • trunk/Source/WebCore/css/CSSProperties.json

    r276418 r276488  
    804804            }
    805805        },
     806        "additive-symbols": {
     807            "codegen-properties": {
     808                "settings-flag": "cssCounterStyleAtRules",
     809                "skip-builder": true
     810            },
     811            "specification": {
     812                "category": "css-counter-styles",
     813                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-symbols"
     814            }
     815        },
    806816        "alignment-baseline": {
    807817            "values": [
     
    24352445            "specification": {
    24362446                "category": "svg"
     2447            }
     2448        },
     2449        "fallback": {
     2450            "codegen-properties": {
     2451                "settings-flag": "cssCounterStyleAtRules",
     2452                "skip-builder": true
     2453            },
     2454            "specification": {
     2455                "category": "css-counter-styles",
     2456                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-fallback"
    24372457            }
    24382458        },
     
    33783398            }
    33793399        },
     3400        "pad": {
     3401            "codegen-properties": {
     3402                "settings-flag": "cssCounterStyleAtRules",
     3403                "skip-builder": true
     3404            },
     3405            "specification": {
     3406                "category": "css-counter-styles",
     3407                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-pad"
     3408            }
     3409        },
    33803410        "padding": {
    33813411            "codegen-properties": {
     
    38493879                "category": "css-speech",
    38503880                "url": "https://www.w3.org/TR/css3-speech/#speak-as"
     3881            }
     3882        },
     3883        "symbols": {
     3884            "codegen-properties": {
     3885                "settings-flag": "cssCounterStyleAtRules",
     3886                "skip-builder": true
     3887            },
     3888            "specification": {
     3889                "category": "css-counter-styles",
     3890                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-symbols"
    38513891            }
    38523892        },
     
    60456085            "status": "non-standard"
    60466086        },
     6087        "negative": {
     6088            "codegen-properties": {
     6089                "settings-flag": "cssCounterStyleAtRules",
     6090                "skip-builder": true
     6091            },
     6092            "specification": {
     6093                "category": "css-counter-styles",
     6094                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-negative"
     6095            }
     6096        },
    60476097        "color-scheme": {
    60486098            "inherited": true,
     
    61306180            }
    61316181        },
     6182        "prefix": {
     6183            "codegen-properties": {
     6184                "settings-flag": "cssCounterStyleAtRules",
     6185                "skip-builder": true
     6186            },
     6187            "specification": {
     6188                "category": "css-counter-styles",
     6189                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-prefix"
     6190            }
     6191        },
    61326192        "-webkit-print-color-adjust": {
    61336193            "inherited": true,
     
    61386198            "status": "non-standard"
    61396199        },
     6200        "range": {
     6201            "codegen-properties": {
     6202                "settings-flag": "cssCounterStyleAtRules",
     6203                "skip-builder": true
     6204            },
     6205            "specification": {
     6206                "category": "css-counter-styles",
     6207                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-range"
     6208            }
     6209        },
    61406210        "-webkit-rtl-ordering": {
    61416211            "inherited": true,
     
    61496219            },
    61506220            "status": "non-standard"
     6221        },
     6222        "suffix": {
     6223            "codegen-properties": {
     6224                "settings-flag": "cssCounterStyleAtRules",
     6225                "skip-builder": true
     6226            },
     6227            "specification": {
     6228                "category": "css-counter-styles",
     6229                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-suffix"
     6230            }
    61516231        },
    61526232        "-webkit-svg-shadow": {
     
    69727052            }
    69737053        },
     7054        "system": {
     7055            "codegen-properties": {
     7056                "settings-flag": "cssCounterStyleAtRules",
     7057                "skip-builder": true
     7058            },
     7059            "specification": {
     7060                "category": "css-counter-styles",
     7061                "url": "https://www.w3.org/TR/css-counter-styles-3/#counter-style-system"
     7062            }
     7063        },
    69747064        "-webkit-tap-highlight-color": {
    69757065            "inherited": true,
     
    71427232            "url": "https://www.w3.org/TR/css-content-3/"
    71437233        },
     7234        "css-counter-styles": {
     7235            "shortname": "CSS Counter Styles",
     7236            "longname": "CSS Counter Styles Module",
     7237            "url": "https://www.w3.org/TR/css-counter-styles-3"
     7238        },
    71447239        "css-device-adapt": {
    71457240            "shortname": "CSS Device Adaptation",
  • trunk/Source/WebCore/css/CSSValueKeywords.in

    r276418 r276488  
    15061506high
    15071507
     1508// @counter-style `system` descriptor values
     1509// https://www.w3.org/TR/css-counter-styles-3/#counter-style-system
     1510cyclic
     1511numeric
     1512// alphabetic
     1513symbolic
     1514additive
     1515// fixed
     1516extends
     1517
     1518// @counter-style `speak-as` descriptor values
     1519// https://www.w3.org/TR/css-counter-styles-3/#counter-style-speak-as
     1520// auto
     1521bullets
     1522numbers
     1523words
     1524// spell-out
     1525
    15081526// @supports selector()
    15091527// https://drafts.csswg.org/css-conditional-4/#typedef-supports-selector-fn
  • trunk/Source/WebCore/css/parser/CSSParserContext.cpp

    r276152 r276488  
    182182{
    183183    switch (property) {
     184    case CSSPropertyAdditiveSymbols:
     185    case CSSPropertyFallback:
     186    case CSSPropertyPad:
     187    case CSSPropertySymbols:
     188    case CSSPropertyNegative:
     189    case CSSPropertyPrefix:
     190    case CSSPropertyRange:
     191    case CSSPropertySuffix:
     192    case CSSPropertySystem:
     193        return !counterStyleAtRulesEnabled;
    184194    case CSSPropertyAspectRatio:
    185195        return !aspectRatioEnabled;
  • trunk/Source/WebCore/css/parser/CSSPropertyParser.cpp

    r276418 r276488  
    45364536}
    45374537
     4538// https://www.w3.org/TR/css-counter-styles-3/#counter-style-system
     4539static RefPtr<CSSPrimitiveValue> consumeCounterStyleSystem(CSSParserTokenRange& range)
     4540{
     4541    if (auto ident = consumeIdent<CSSValueCyclic, CSSValueNumeric, CSSValueAlphabetic, CSSValueSymbolic, CSSValueAdditive>(range))
     4542        return ident;
     4543
     4544    if (auto ident = consumeIdent<CSSValueFixed>(range)) {
     4545        if (range.atEnd())
     4546            return ident;
     4547        // If we have the `fixed` keyword but the range is not at the end, the next token must be a integer.
     4548        // If it's not, this value is invalid.
     4549        auto firstSymbolValue = consumeInteger(range);
     4550        if (!firstSymbolValue)
     4551            return nullptr;
     4552        return createPrimitiveValuePair(ident.releaseNonNull(), firstSymbolValue.releaseNonNull());
     4553    }
     4554
     4555    if (auto ident = consumeIdent<CSSValueExtends>(range)) {
     4556        // There must be a `<counter-style-name>` following the `extends` keyword. If there isn't, this value is invalid.
     4557        auto parsedCounterStyleName = consumeCounterStyleName(range);
     4558        if (!parsedCounterStyleName)
     4559            return nullptr;
     4560        return createPrimitiveValuePair(ident.releaseNonNull(), parsedCounterStyleName.releaseNonNull());
     4561    }
     4562    return nullptr;
     4563}
     4564
     4565// https://www.w3.org/TR/css-counter-styles-3/#typedef-symbol
     4566static RefPtr<CSSValue> consumeCounterStyleSymbol(CSSParserTokenRange& range, const CSSParserContext& context)
     4567{
     4568    if (auto string = consumeString(range))
     4569        return string;
     4570    if (auto customIdent = consumeCustomIdent(range))
     4571        return customIdent;
     4572    // There are inherent difficulties in supporting <image> symbols in @counter-styles, so gate them behind a
     4573    // flag for now. https://bugs.webkit.org/show_bug.cgi?id=167645
     4574    if (context.counterStyleAtRuleImageSymbolsEnabled) {
     4575        if (auto image = consumeImage(range, context, { AllowedImageType::URLFunction, AllowedImageType::GeneratedImage }))
     4576            return image;
     4577    }
     4578    return nullptr;
     4579}
     4580
     4581// https://www.w3.org/TR/css-counter-styles-3/#counter-style-negative
     4582static RefPtr<CSSValue> consumeCounterStyleNegative(CSSParserTokenRange& range, const CSSParserContext& context)
     4583{
     4584    auto prependValue = consumeCounterStyleSymbol(range, context);
     4585    if (!prependValue)
     4586        return nullptr;
     4587    if (range.atEnd())
     4588        return prependValue;
     4589
     4590    auto appendValue = consumeCounterStyleSymbol(range, context);
     4591    if (!appendValue || !range.atEnd())
     4592        return nullptr;
     4593
     4594    RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
     4595    values->append(prependValue.releaseNonNull());
     4596    values->append(appendValue.releaseNonNull());
     4597    return values;
     4598}
     4599
     4600// https://www.w3.org/TR/css-counter-styles-3/#counter-style-range
     4601static RefPtr<CSSPrimitiveValue> consumeCounterStyleRangeBound(CSSParserTokenRange& range)
     4602{
     4603    if (auto infinite = consumeIdent<CSSValueInfinite>(range))
     4604        return infinite;
     4605    if (auto integer = consumeInteger(range))
     4606        return integer;
     4607    return nullptr;
     4608}
     4609
     4610// https://www.w3.org/TR/css-counter-styles-3/#counter-style-range
     4611static RefPtr<CSSValue> consumeCounterStyleRange(CSSParserTokenRange& range)
     4612{
     4613    if (auto autoValue = consumeIdent<CSSValueAuto>(range))
     4614        return autoValue;
     4615
     4616    auto rangeList = CSSValueList::createCommaSeparated();
     4617    do {
     4618        auto lowerBound = consumeCounterStyleRangeBound(range);
     4619        if (!lowerBound)
     4620            return nullptr;
     4621        auto upperBound = consumeCounterStyleRangeBound(range);
     4622        if (!upperBound)
     4623            return nullptr;
     4624
     4625        // If the lower bound of any range is higher than the upper bound, the entire descriptor is invalid and must be
     4626        // ignored.
     4627        if (lowerBound->isNumber() && upperBound->isNumber() && lowerBound->intValue() > upperBound->intValue())
     4628            return nullptr;
     4629        rangeList->append(createPrimitiveValuePair(lowerBound.releaseNonNull(), upperBound.releaseNonNull(), Pair::IdenticalValueEncoding::DoNotCoalesce));
     4630    } while (consumeCommaIncludingWhitespace(range));
     4631    if (!range.atEnd() || !rangeList->length())
     4632        return nullptr;
     4633    return rangeList;
     4634}
     4635
     4636// https://www.w3.org/TR/css-counter-styles-3/#counter-style-pad
     4637static RefPtr<CSSValue> consumeCounterStylePad(CSSParserTokenRange& range, const CSSParserContext& context)
     4638{
     4639    RefPtr<CSSValue> integer;
     4640    RefPtr<CSSValue> symbol;
     4641    while (!integer || !symbol) {
     4642        if (!integer) {
     4643            integer = consumeInteger(range, 0);
     4644            if (integer)
     4645                continue;
     4646        }
     4647        if (!symbol) {
     4648            symbol = consumeCounterStyleSymbol(range, context);
     4649            if (symbol)
     4650                continue;
     4651        }
     4652        return nullptr;
     4653    }
     4654    if (!range.atEnd())
     4655        return nullptr;
     4656    auto values = CSSValueList::createSpaceSeparated();
     4657    values->append(integer.releaseNonNull());
     4658    values->append(symbol.releaseNonNull());
     4659    return values;
     4660}
     4661
     4662// https://www.w3.org/TR/css-counter-styles-3/#counter-style-symbols
     4663static RefPtr<CSSValue> consumeCounterStyleSymbols(CSSParserTokenRange& range, const CSSParserContext& context)
     4664{
     4665    auto symbols = CSSValueList::createSpaceSeparated();
     4666    while (!range.atEnd()) {
     4667        auto symbol = consumeCounterStyleSymbol(range, context);
     4668        if (!symbol)
     4669            return nullptr;
     4670        symbols->append(symbol.releaseNonNull());
     4671    }
     4672    if (!symbols->length())
     4673        return nullptr;
     4674    return symbols;
     4675}
     4676
     4677// https://www.w3.org/TR/css-counter-styles-3/#counter-style-symbols
     4678static RefPtr<CSSValue> consumeCounterStyleAdditiveSymbols(CSSParserTokenRange& range, const CSSParserContext& context)
     4679{
     4680    auto values = CSSValueList::createCommaSeparated();
     4681    RefPtr<CSSPrimitiveValue> lastInteger;
     4682    do {
     4683        RefPtr<CSSPrimitiveValue> integer;
     4684        RefPtr<CSSValue> symbol;
     4685        while (!integer || !symbol) {
     4686            if (!integer) {
     4687                integer = consumeInteger(range, 0);
     4688                if (integer)
     4689                    continue;
     4690            }
     4691            if (!symbol) {
     4692                symbol = consumeCounterStyleSymbol(range, context);
     4693                if (symbol)
     4694                    continue;
     4695            }
     4696            return nullptr;
     4697        }
     4698
     4699        if (lastInteger) {
     4700            // The additive tuples must be specified in order of strictly descending
     4701            // weight; otherwise, the declaration is invalid and must be ignored.
     4702            if (integer->intValue() >= lastInteger->intValue())
     4703                return nullptr;
     4704        }
     4705        lastInteger = integer;
     4706        values->append(integer.releaseNonNull());
     4707        values->append(symbol.releaseNonNull());
     4708    } while (consumeCommaIncludingWhitespace(range));
     4709    if (!range.atEnd() || !values->length())
     4710        return nullptr;
     4711    return values;
     4712}
     4713
     4714// https://www.w3.org/TR/css-counter-styles-3/#counter-style-speak-as
     4715static RefPtr<CSSValue> consumeCounterStyleSpeakAs(CSSParserTokenRange& range)
     4716{
     4717    if (auto speakAsIdent = consumeIdent<CSSValueAuto, CSSValueBullets, CSSValueNumbers, CSSValueWords, CSSValueSpellOut>(range))
     4718        return speakAsIdent;
     4719    return consumeCounterStyleName(range);
     4720}
     4721
    45384722RefPtr<CSSValue> CSSPropertyParser::parseCounterStyleDescriptor(CSSPropertyID propId, CSSParserTokenRange& range, const CSSParserContext& context)
    45394723{
    45404724    if (!context.counterStyleAtRulesEnabled)
    45414725        return nullptr;
    4542     // FIXME: Implement this function when we can parse @counter-style descriptors.
    4543     UNUSED_PARAM(propId);
    4544     UNUSED_PARAM(range);
    4545     UNUSED_PARAM(context);
    4546     return nullptr;
     4726
     4727    switch (propId) {
     4728    case CSSPropertySystem:
     4729        return consumeCounterStyleSystem(range);
     4730    case CSSPropertyNegative:
     4731        return consumeCounterStyleNegative(range, context);
     4732    case CSSPropertyPrefix:
     4733    case CSSPropertySuffix:
     4734        return consumeCounterStyleSymbol(range, context);
     4735    case CSSPropertyRange:
     4736        return consumeCounterStyleRange(range);
     4737    case CSSPropertyPad:
     4738        return consumeCounterStylePad(range, context);
     4739    case CSSPropertyFallback:
     4740        return consumeCounterStyleName(range);
     4741    case CSSPropertySymbols:
     4742        return consumeCounterStyleSymbols(range, context);
     4743    case CSSPropertyAdditiveSymbols:
     4744        return consumeCounterStyleAdditiveSymbols(range, context);
     4745    case CSSPropertySpeakAs:
     4746        return consumeCounterStyleSpeakAs(range);
     4747    default:
     4748        ASSERT_NOT_REACHED();
     4749        return nullptr;
     4750    }
    45474751}
    45484752
  • trunk/Tools/ChangeLog

    r276476 r276488  
     12021-04-22  Tyler Wilcock  <twilco.o@protonmail.com>
     2
     3        [css-counter-styles] Parse @counter-style descriptors
     4        https://bugs.webkit.org/show_bug.cgi?id=224718
     5
     6        Reviewed by Darin Adler.
     7
     8        * DumpRenderTree/TestOptions.cpp:
     9        (WTR::TestOptions::defaults):
     10        Fix typo (missing 's').  CSSCounterStyleAtRulesEnabled, not
     11        CSSCounterStyleAtRuleEnabled.
     12
    1132021-04-22  BJ Burg  <bburg@apple.com>
    214
  • trunk/Tools/DumpRenderTree/TestOptions.cpp

    r276418 r276488  
    134134            { "AttachmentElementEnabled", false },
    135135            { "CSSContainmentEnabled", false },
    136             { "CSSCounterStyleAtRuleEnabled", false },
     136            { "CSSCounterStyleAtRulesEnabled", false },
    137137            { "CSSCounterStyleAtRuleImageSymbolsEnabled", false },
    138138            { "CSSLogicalEnabled", false },
Note: See TracChangeset for help on using the changeset viewer.