Commit b21c5ef0 authored by Xiaocheng Hu's avatar Xiaocheng Hu Committed by Commit Bot

Parse descriptors of @counter-style

This patch implements the parsing of the descriptors of @counter-style
following spec:

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

WPT verifying the parsing is also added.

Bug: 687225
Change-Id: Ifecdfbdfb9efcb330453d0059a0f1e73c0f3e662
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2530523Reviewed-by: default avatarRune Lillesveen <futhark@chromium.org>
Reviewed-by: default avatarAnders Hartvoll Ruud <andruud@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827550}
parent a156776c
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/css/css_counter_style_rule.h" #include "third_party/blink/renderer/core/css/css_counter_style_rule.h"
#include "third_party/blink/renderer/core/css/style_rule.h" #include "third_party/blink/renderer/core/css/style_rule.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink { namespace blink {
...@@ -15,7 +16,84 @@ CSSCounterStyleRule::CSSCounterStyleRule( ...@@ -15,7 +16,84 @@ CSSCounterStyleRule::CSSCounterStyleRule(
CSSCounterStyleRule::~CSSCounterStyleRule() = default; CSSCounterStyleRule::~CSSCounterStyleRule() = default;
String CSSCounterStyleRule::cssText() const { String CSSCounterStyleRule::cssText() const {
return String(); StringBuilder result;
result.Append("@counter-style ");
result.Append(name());
result.Append(" {");
// Note: The exact serialization isn't well specified.
String system_text = system();
if (system_text.length()) {
result.Append(" system: ");
result.Append(system_text);
result.Append(";");
}
String symbols_text = symbols();
if (symbols_text.length()) {
result.Append(" symbols: ");
result.Append(symbols_text);
result.Append(";");
}
String additive_symbols_text = additiveSymbols();
if (additive_symbols_text.length()) {
result.Append(" additive-symbols: ");
result.Append(additive_symbols_text);
result.Append(";");
}
String negative_text = negative();
if (negative_text.length()) {
result.Append(" negative: ");
result.Append(negative_text);
result.Append(";");
}
String prefix_text = prefix();
if (prefix_text.length()) {
result.Append(" prefix: ");
result.Append(prefix_text);
result.Append(";");
}
String suffix_text = suffix();
if (suffix_text.length()) {
result.Append(" suffix: ");
result.Append(suffix_text);
result.Append(";");
}
String pad_text = pad();
if (pad_text.length()) {
result.Append(" pad: ");
result.Append(pad_text);
result.Append(";");
}
String range_text = range();
if (range_text.length()) {
result.Append(" range: ");
result.Append(range_text);
result.Append(";");
}
String fallback_text = fallback();
if (fallback_text.length()) {
result.Append(" fallback: ");
result.Append(fallback_text);
result.Append(";");
}
String speak_as_text = speakAs();
if (speak_as_text.length()) {
result.Append(" speak-as: ");
result.Append(speak_as_text);
result.Append(";");
}
result.Append(" }");
return result.ToString();
} }
void CSSCounterStyleRule::Reattach(StyleRuleBase* rule) { void CSSCounterStyleRule::Reattach(StyleRuleBase* rule) {
......
...@@ -1447,5 +1447,24 @@ ...@@ -1447,5 +1447,24 @@
"more", "more",
"less", "less",
"forced", "forced",
// @counter-style system
"cyclic",
// fixed,
"symbolic",
// alphabetic,
"numeric",
"additive",
"extends",
// @counter-style range
// infinite,
// @counter-style speak-as
// auto
"bullets",
"numbers",
"words",
// spell-out,
], ],
} }
...@@ -445,6 +445,7 @@ ...@@ -445,6 +445,7 @@
{ {
// https://drafts.csswg.org/css-counter-styles-3 // https://drafts.csswg.org/css-counter-styles-3
name: "CSSAtRuleCounterStyle", name: "CSSAtRuleCounterStyle",
status: "test",
}, },
{ {
name: "CSSCalcAsInt", name: "CSSCalcAsInt",
......
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-counter-styles-3/#counter-style-symbols">
<link rel="author" href="mailto:xiaochengh@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/counter-style-testcommon.js"></script>
<script>
function test_valid_additive_symbols(value, expected) {
test_valid_counter_style_descriptor('additive-symbols', value, expected);
}
function test_invalid_additive_symbols(value) {
test_invalid_counter_style_descriptor('additive-symbols', value);
}
// [ <integer [0,]> && <symbol> ]#
test_valid_additive_symbols('1 "X"');
test_valid_additive_symbols('"X" 1', '1 "X"');
test_valid_additive_symbols('5 "V", 1 "I"');
test_invalid_additive_symbols('');
// Weights must be non-negative
test_invalid_additive_symbols('-1 "X"');
// Weights must be in strictly decreasing order
test_invalid_additive_symbols('1 "I", 5 "V"');
test_invalid_additive_symbols('1 "X", 1 "Y"');
</script>
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-counter-styles-3/#counter-style-fallback">
<link rel="author" href="mailto:xiaochengh@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/counter-style-testcommon.js"></script>
<script>
function test_valid_fallback(value) {
test_valid_counter_style_descriptor('fallback', value);
}
function test_invalid_fallback(value) {
test_invalid_counter_style_descriptor('fallback', value);
}
// <counter-style-name>
test_valid_fallback('bar');
// Counter style names are custom identifiers, not strings
test_invalid_fallback('"bar"');
// The following are not valid counter style names
test_invalid_fallback('none');
test_invalid_fallback('initial');
test_invalid_fallback('inherit');
test_invalid_fallback('unset');
</script>
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-counter-styles-3/#counter-style-negative">
<link rel="author" href="mailto:xiaochengh@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/counter-style-testcommon.js"></script>
<script>
function test_valid_negative(value) {
test_valid_counter_style_descriptor('negative', value);
}
function test_invalid_negative(value) {
test_invalid_counter_style_descriptor('negative', value);
}
// <symbol> <symbol>?
test_valid_negative('"X"');
test_valid_negative('"X" "X"');
test_invalid_negative('"X" "X" "X"');
</script>
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-counter-styles-3/#counter-style-pad">
<link rel="author" href="mailto:xiaochengh@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/counter-style-testcommon.js"></script>
<script>
function test_valid_pad(value, expected) {
test_valid_counter_style_descriptor('pad', value, expected);
}
function test_invalid_pad(value) {
test_invalid_counter_style_descriptor('pad', value);
}
// <integer [0,]> && <symbol>
test_invalid_pad('10');
test_invalid_pad('"X"');
test_valid_pad('10 "X"');
test_valid_pad('"X" 10', '10 "X"');
test_invalid_pad('-1 "X"');
test_invalid_pad('"X" -1');
test_invalid_pad('10 "X" "Y"');
test_invalid_pad('10 10 "X"');
</script>
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-counter-styles-3/#counter-style-prefix">
<link rel="help" href="https://drafts.csswg.org/css-counter-styles-3/#counter-style-suffix">
<link rel="author" href="mailto:xiaochengh@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/counter-style-testcommon.js"></script>
<script>
function test_valid_prefix_suffix(value, expected) {
test_valid_counter_style_descriptor('prefix', value, expected);
test_valid_counter_style_descriptor('suffix', value, expected);
}
function test_invalid_prefix_suffix(value) {
test_invalid_counter_style_descriptor('prefix', value);
test_invalid_counter_style_descriptor('suffix', value);
}
// <symbol>
// <symbol> = <string> | <image> | <custom-ident>
// string values
test_valid_prefix_suffix('"string"');
test_valid_prefix_suffix('"initial"');
test_valid_prefix_suffix('"inherit"');
test_valid_prefix_suffix('"unset"');
// custom-ident values
test_valid_prefix_suffix('custom-ident')
test_invalid_prefix_suffix('initial');
test_invalid_prefix_suffix('inherit');
test_invalid_prefix_suffix('unset');
// image values
test_valid_prefix_suffix('url("https://example.com/foo.png")');
test_valid_prefix_suffix('url(https://example.com/foo.png)', 'url("https://example.com/foo.png")');
test_valid_prefix_suffix('linear-gradient(yellow, blue)');
// Must be exactly one symbol
test_invalid_prefix_suffix('');
test_invalid_prefix_suffix('foo bar');
</script>
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-counter-styles-3/#counter-style-range">
<link rel="author" href="mailto:xiaochengh@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/counter-style-testcommon.js"></script>
<script>
function test_valid_range(value) {
test_valid_counter_style_descriptor('range', value);
}
function test_invalid_range(value) {
test_invalid_counter_style_descriptor('range', value);
}
// [ <integer> | infinite ]{2} ]# | auto
test_valid_range('auto');
test_valid_range('infinite infinite');
test_valid_range('infinite 0');
test_valid_range('0 infinite');
test_valid_range('infinite 0, 5 10, 100 infinite');
test_valid_range('infinite 10, 5 20, 15 infinite');
test_invalid_range('');
test_invalid_range('0 -1');
</script>
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-counter-styles-3/#counter-style-speak_as">
<link rel="author" href="mailto:xiaochengh@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/counter-style-testcommon.js"></script>
<script>
function test_valid_speak_as(value) {
test_valid_counter_style_descriptor('speak-as', value);
}
function test_invalid_speak_as(value) {
test_invalid_counter_style_descriptor('speak-as', value);
}
// auto | bullets | numbers | words | spell-out | <counter-style-name>
test_valid_speak_as('auto');
test_valid_speak_as('bullets');
test_valid_speak_as('numbers');
test_valid_speak_as('words');
test_valid_speak_as('spell-out');
test_valid_speak_as('bar');
test_valid_speak_as('spellout'); // 'spellout' is a valid counter style name
test_invalid_speak_as('bullets numbers');
// The following are not valid counter style names
test_invalid_speak_as('none');
test_invalid_speak_as('initial');
test_invalid_speak_as('inherit');
test_invalid_speak_as('unset');
</script>
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-counter-styles-3/#counter-style-symbols">
<link rel="author" href="mailto:xiaochengh@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/counter-style-testcommon.js"></script>
<script>
function test_valid_symbols(value, expected) {
test_valid_counter_style_descriptor('symbols', value, expected);
}
function test_invalid_symbols(value) {
test_invalid_counter_style_descriptor('symbols', value);
}
// <symbol>+
test_valid_symbols('"X"');
test_valid_symbols('"X" "X"');
test_valid_symbols('ident "X"');
test_valid_symbols('ident "X" url("foo.jpg")');
test_invalid_symbols('');
test_invalid_symbols('initial "X" "X"');
test_invalid_symbols('inherit "X" "X"');
test_invalid_symbols('unset "X" "X"');
</script>
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-counter-styles-3/#counter-style-system">
<link rel="author" href="mailto:xiaochengh@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/counter-style-testcommon.js"></script>
<script>
function test_valid_system(value) {
test_valid_counter_style_descriptor('system', value);
}
function test_invalid_system(value) {
test_invalid_counter_style_descriptor('system', value);
}
// cyclic | numeric | alphabetic | symbolic | additive |
// [fixed <integer>?] | [ extends <counter-style-name> ]
test_valid_system('cyclic');
test_valid_system('fixed');
test_valid_system('fixed 100');
test_valid_system('fixed -1');
test_valid_system('symbolic');
test_valid_system('alphabetic');
test_valid_system('numeric');
test_valid_system('additive');
test_valid_system('extends bar');
test_invalid_system('float');
test_invalid_system('cyclic cyclic');
// The following are not valid counter style names
test_invalid_system('extends none');
test_invalid_system('extends initial');
test_invalid_system('extends inherit');
test_invalid_system('extends unset');
</script>
function test_counter_style_descriptor(descriptor, value, expected) {
let descriptors = [];
descriptors.push(`${descriptor}: ${value}`);
// Fill out the remaining necessary descriptors
if (descriptor === 'system') {
if (value === 'additive')
descriptors.push('additive-symbols: 1 "I"');
else if (!value.startsWith('extends'))
descriptors.push('symbols: "X" "Y"');
} else if (descriptor === 'symbols') {
descriptors.push('system: symbolic');
} else if (descriptor === 'additive-symbols') {
descriptors.push('system: additive');
} else {
descriptors.push('system: symbolic');
descriptors.push('symbols: "X" "Y"');
}
let style = document.createElement('style');
style.textContent = `@counter-style foo { ${descriptors.join(';')} }`;
document.head.appendChild(style);
test(() => {
let rule = style.sheet.cssRules[0];
// TODO: The spec is inconsistent on when the entire rule is invalid
// (and hence absent from OM), and when only the descriptor is invalid.
// Revise when spec issue is resolved.
// See https://github.com/w3c/csswg-drafts/issues/5717
if (!rule) {
assert_equals(expected, undefined);
return;
}
assert_equals(rule.constructor.name, 'CSSCounterStyleRule');
let text = rule.cssText;
if (expected)
assert_not_equals(text.indexOf(`${descriptor}: ${expected}`), -1);
else
assert_equals(text.indexOf(`${descriptor}:`), -1);
}, `@counter-style '${descriptor}: ${value}' is ${expected ? 'valid' : 'invalid'}`);
style.remove();
}
function test_valid_counter_style_descriptor(descriptor, value, expected) {
expected = expected || value;
test_counter_style_descriptor(descriptor, value, expected);
}
function test_invalid_counter_style_descriptor(descriptor, value) {
test_counter_style_descriptor(descriptor, value, undefined);
}
This is a testharness.js-based test.
FAIL CSSCounterStyleRule.cssText doesn't serialize with newlines Cannot read property 'cssText' of undefined
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL CSSCounterStyleRule.cssText doesn't serialize with newlines Cannot read property 'cssText' of undefined
Harness: the test ran to completion.
This test (crudely) documents Blink's web-exposed CSS properties. All changes to this list should go through Blink's feature review process: http://www.chromium.org/blink#new-features This test (crudely) documents Blink's web-exposed CSS properties. All changes to this list should go through Blink's feature review process: http://www.chromium.org/blink#new-features
additiveSymbols
advanceOverride advanceOverride
advanceProportionalOverride advanceProportionalOverride
alignContent alignContent
...@@ -143,6 +144,7 @@ display ...@@ -143,6 +144,7 @@ display
dominantBaseline dominantBaseline
emptyCells emptyCells
end end
fallback
fill fill
fillOpacity fillOpacity
fillRule fillRule
...@@ -257,6 +259,7 @@ minInlineSize ...@@ -257,6 +259,7 @@ minInlineSize
minWidth minWidth
minZoom minZoom
mixBlendMode mixBlendMode
negative
objectFit objectFit
objectPosition objectPosition
offset offset
...@@ -287,6 +290,7 @@ overscrollBehaviorBlock ...@@ -287,6 +290,7 @@ overscrollBehaviorBlock
overscrollBehaviorInline overscrollBehaviorInline
overscrollBehaviorX overscrollBehaviorX
overscrollBehaviorY overscrollBehaviorY
pad
padding padding
paddingBlock paddingBlock
paddingBlockEnd paddingBlockEnd
...@@ -312,8 +316,10 @@ placeItems ...@@ -312,8 +316,10 @@ placeItems
placeSelf placeSelf
pointerEvents pointerEvents
position position
prefix
quotes quotes
r r
range
removeProperty removeProperty
resize resize
right right
...@@ -359,6 +365,7 @@ shapeRendering ...@@ -359,6 +365,7 @@ shapeRendering
size size
source source
speak speak
speakAs
src src
start start
stopColor stopColor
...@@ -371,7 +378,10 @@ strokeLinejoin ...@@ -371,7 +378,10 @@ strokeLinejoin
strokeMiterlimit strokeMiterlimit
strokeOpacity strokeOpacity
strokeWidth strokeWidth
suffix
symbols
syntax syntax
system
tabSize tabSize
tableLayout tableLayout
textAlign textAlign
......
...@@ -601,6 +601,31 @@ interface CSSConditionRule : CSSGroupingRule ...@@ -601,6 +601,31 @@ interface CSSConditionRule : CSSGroupingRule
attribute @@toStringTag attribute @@toStringTag
getter conditionText getter conditionText
method constructor method constructor
interface CSSCounterStyleRule : CSSRule
attribute @@toStringTag
getter additiveSymbols
getter fallback
getter name
getter negative
getter pad
getter prefix
getter range
getter speakAs
getter suffix
getter symbols
getter system
method constructor
setter additiveSymbols
setter fallback
setter name
setter negative
setter pad
setter prefix
setter range
setter speakAs
setter suffix
setter symbols
setter system
interface CSSFontFaceRule : CSSRule interface CSSFontFaceRule : CSSRule
attribute @@toStringTag attribute @@toStringTag
getter style getter style
...@@ -748,6 +773,7 @@ interface CSSRotate : CSSTransformComponent ...@@ -748,6 +773,7 @@ interface CSSRotate : CSSTransformComponent
interface CSSRule interface CSSRule
attribute @@toStringTag attribute @@toStringTag
attribute CHARSET_RULE attribute CHARSET_RULE
attribute COUNTER_STYLE_RULE
attribute FONT_FACE_RULE attribute FONT_FACE_RULE
attribute IMPORT_RULE attribute IMPORT_RULE
attribute KEYFRAMES_RULE attribute KEYFRAMES_RULE
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment