Commit f3c21211 authored by timloh's avatar timloh Committed by Commit bot

CSS Properties and Values API: Support more syntax strings

This patch implements proper parsing of syntax strings in the P&V API,
as well parsing of the actual values. In particular, we add support for
parsing of syntax strings like "<length> | <percentage>" and "<number>+".

- Whitespace is not mentioned in the spec but used in examples. This
patch allows whitespace in most places.
- The <ident> production is possibly not the best choice (see github
issue below), so until that is resolved we only allow name code points.
- <resolution> is not yet used in any CSS properties in Blink, so value
parsing support will be added separately.
- <transform-function> isn't factored to be trivially supported, so value
parsing support will also be added separately. There's also an
outstanding issue re. Typed OM integration which might result in changes
here.

https://drafts.css-houdini.org/css-properties-values-api/#supported-syntax-strings
https://github.com/w3c/css-houdini-drafts/issues/265

BUG=641877

Review-Url: https://codereview.chromium.org/2330893002
Cr-Commit-Position: refs/heads/master@{#419425}
parent 791af6c9
This is a testharness.js-based test.
PASS syntax:'*', initialValue:'a' is valid
PASS syntax:' * ', initialValue:'b' is valid
PASS syntax:'<length>', initialValue:'2px' is valid
PASS syntax:' <number>', initialValue:'5' is valid
PASS syntax:'<percentage> ', initialValue:'10%' is valid
PASS syntax:'<color>+', initialValue:'red' is valid
PASS syntax:' <length>+ | <percentage>', initialValue:'2px 8px' is valid
PASS syntax:'<length>|<percentage>|<length-percentage>', initialValue:'2px' is valid
PASS syntax:'<color> | <image> | <url> | <integer> | <angle>', initialValue:'red' is valid
PASS syntax:'<time> | <resolution> | <transform-function> | <custom-ident>', initialValue:'red' is valid
PASS syntax:'*', initialValue:':> hello' is valid
PASS syntax:'*', initialValue:'([ brackets ]) { yay (??)}' is valid
PASS syntax:'*', initialValue:'yep 'this is valid too'' is valid
PASS syntax:'*', initialValue:'unmatched opening bracket is valid :(' is valid
PASS syntax:'*', initialValue:'"' is valid
PASS syntax:'<length>', initialValue:'0' is valid
PASS syntax:'<length>', initialValue:'10px /*:)*/' is valid
PASS syntax:'<length>', initialValue:' calc(-2px)' is valid
PASS syntax:'<length>', initialValue:'calc(2px*4 + 10px)' is valid
PASS syntax:'<length>', initialValue:'7.1e-4cm' is valid
PASS syntax:'<length>', initialValue:'calc(7in - 12px)' is valid
PASS syntax:'<length>+', initialValue:'2px 7px calc(8px)' is valid
PASS syntax:'<percentage>', initialValue:'-9.3e3%' is valid
PASS syntax:'<length-percentage>', initialValue:'-54%' is valid
PASS syntax:'<length-percentage>', initialValue:'0' is valid
PASS syntax:'<length-percentage>', initialValue:'calc(-11px + 10.4%)' is valid
PASS syntax:'<number>', initialValue:'-109' is valid
PASS syntax:'<number>', initialValue:'2.3e4' is valid
PASS syntax:'<integer>', initialValue:'-109' is valid
PASS syntax:'<integer>', initialValue:'19' is valid
PASS syntax:'<angle>', initialValue:'10deg' is valid
PASS syntax:'<angle>', initialValue:'20.5rad' is valid
PASS syntax:'<angle>', initialValue:'calc(50grad + 3.14159rad)' is valid
PASS syntax:'<time>', initialValue:'2s' is valid
PASS syntax:'<time>', initialValue:'calc(2s - 9ms)' is valid
FAIL syntax:'<resolution>', initialValue:'10dpi' is valid Failed to execute 'registerProperty' on 'CSS': The initial value provided does not parse for the given syntax.
FAIL syntax:'<resolution>', initialValue:'-5.3dpcm' is valid Failed to execute 'registerProperty' on 'CSS': The initial value provided does not parse for the given syntax.
FAIL syntax:'<transform-function>', initialValue:'scale(2)' is valid Failed to execute 'registerProperty' on 'CSS': The initial value provided does not parse for the given syntax.
FAIL syntax:'<transform-function>+', initialValue:'translateX(2px) rotate(20deg)' is valid Failed to execute 'registerProperty' on 'CSS': The initial value provided does not parse for the given syntax.
PASS syntax:'<color>', initialValue:'rgb(12, 34, 56)' is valid
PASS syntax:'<color>', initialValue:'lightgoldenrodyellow' is valid
PASS syntax:'<image>', initialValue:'url(a)' is valid
PASS syntax:'<image>', initialValue:'linear-gradient(yellow, blue)' is valid
PASS syntax:'<url>', initialValue:'url(a)' is valid
PASS syntax:'banana', initialValue:'banana' is valid
PASS syntax:'bAnAnA', initialValue:'bAnAnA' is valid
PASS syntax:'ba-na-nya', initialValue:'ba-na-nya' is valid
PASS syntax:'banana', initialValue:'banan\61' is valid
PASS syntax:'<custom-ident>', initialValue:'banan\61' is valid
PASS syntax:'big | bigger | BIGGER', initialValue:'bigger' is valid
PASS syntax:'foo+|bar', initialValue:'foo foo foo' is valid
PASS syntax:'banana ', initialValue:'banana' is valid
PASS syntax:'
banana\r
', initialValue:'banana' is valid
PASS syntax:'ba
| na\r|nya', initialValue:'nya' is valid
PASS syntax:'null', initialValue:'null' is valid
PASS syntax:'undefined', initialValue:'undefined' is valid
PASS syntax:'banana', initialValue:'banana' is valid
PASS syntax:'banana,nya', initialValue:'banana' is invalid
PASS syntax:'banan\61', initialValue:'banana' is invalid
PASS syntax:'<\6c ength>', initialValue:'10px' is invalid
PASS syntax:'<banana>', initialValue:'banana' is invalid
PASS syntax:'<Number>', initialValue:'10' is invalid
PASS syntax:'<length', initialValue:'10px' is invalid
PASS syntax:'<LENGTH>', initialValue:'10px' is invalid
PASS syntax:'< length>', initialValue:'10px' is invalid
PASS syntax:'<length >', initialValue:'10px' is invalid
PASS syntax:'<length> +', initialValue:'10px' is invalid
PASS syntax:'<length>++', initialValue:'10px' is invalid
PASS syntax:'<length> | *', initialValue:'10px' is invalid
PASS syntax:'*|banana', initialValue:'banana' is invalid
PASS syntax:'*+', initialValue:'banana' is invalid
FAIL syntax:'initial', initialValue:'initial' is invalid assert_throws: function "() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue})" did not throw
FAIL syntax:'<length>|initial', initialValue:'10px' is invalid assert_throws: function "() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue})" did not throw
FAIL syntax:'<length>|INHERIT', initialValue:'10px' is invalid assert_throws: function "() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue})" did not throw
PASS syntax:'*', initialValue:'initial' is invalid
PASS syntax:'*', initialValue:'inherit' is invalid
PASS syntax:'*', initialValue:'unset' is invalid
FAIL syntax:'*', initialValue:'revert' is invalid assert_throws: function "() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue})" did not throw
PASS syntax:'<custom-ident>', initialValue:'initial' is invalid
PASS syntax:'<custom-ident>+', initialValue:'foo inherit bar' is invalid
PASS syntax:'*', initialValue:')' is invalid
PASS syntax:'*', initialValue:'([)]' is invalid
PASS syntax:'*', initialValue:'whee!' is invalid
PASS syntax:'*', initialValue:'"
' is invalid
PASS syntax:'*', initialValue:'url(moo '')' is invalid
PASS syntax:'*', initialValue:'semi;colon' is invalid
PASS syntax:'*', initialValue:'var(invalid var ref)' is invalid
FAIL syntax:'*', initialValue:'var(--foo)' is invalid assert_throws: function "() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue})" did not throw
PASS syntax:'banana', initialValue:'bAnAnA' is invalid
FAIL syntax:'<length>', initialValue:'var(--moo)' is invalid assert_throws: function "() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue})" did not throw
PASS syntax:'<length>', initialValue:'10' is invalid
PASS syntax:'<length>', initialValue:'10%' is invalid
PASS syntax:'<length>', initialValue:'calc(5px + 10%)' is invalid
PASS syntax:'<length>', initialValue:'calc(5px * 3px / 6px)' is invalid
FAIL syntax:'<length>', initialValue:'10em' is invalid assert_throws: function "() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue})" did not throw
FAIL syntax:'<length>', initialValue:'10vmin' is invalid assert_throws: function "() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue})" did not throw
FAIL syntax:'<length>', initialValue:'calc(4px + 3em)' is invalid assert_throws: function "() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue})" did not throw
FAIL syntax:'<length>', initialValue:'calc(4px + calc(8 * 2em))' is invalid assert_throws: function "() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue})" did not throw
PASS syntax:'<length>', initialValue:'10px;' is invalid
FAIL syntax:'<length-percentage>', initialValue:'calc(2px + 10% + 7ex)' is invalid assert_throws: function "() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue})" did not throw
PASS syntax:'<percentage>', initialValue:'0' is invalid
PASS syntax:'<integer>', initialValue:'1.0' is invalid
PASS syntax:'<integer>', initialValue:'1e0' is invalid
FAIL syntax:'<number>|foo', initialValue:'foo var(--foo, bla)' is invalid assert_throws: function "() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue})" did not throw
PASS syntax:'<angle>', initialValue:'10%' is invalid
PASS syntax:'<time>', initialValue:'2px' is invalid
PASS syntax:'<resolution>', initialValue:'10' is invalid
PASS syntax:'<transform-function>', initialValue:'scale()' is invalid
PASS syntax:'<color>', initialValue:'fancy-looking' is invalid
PASS syntax:'<image>', initialValue:'banana.png' is invalid
PASS syntax:'<url>', initialValue:'banana.png' is invalid
Harness: the test ran to completion.
<!DOCTYPE HTML>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script>
function assert_valid(syntax, initialValue) {
// No actual assertions, this just shouldn't throw
test(function() {
try { CSS.unregisterProperty('--syntax-test'); } catch(e) { }
CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue});
}, "syntax:'" + syntax + "', initialValue:'" + initialValue + "' is valid");
}
function assert_invalid(syntax, initialValue) {
test(function(){
try { CSS.unregisterProperty('--syntax-test'); } catch(e) { }
assert_throws(new SyntaxError(),
() => CSS.registerProperty({name: '--syntax-test', syntax: syntax, initialValue: initialValue}));
}, "syntax:'" + syntax + "', initialValue:'" + initialValue + "' is invalid");
}
assert_valid("*", "a");
assert_valid(" * ", "b");
assert_valid("<length>", "2px");
assert_valid(" <number>", "5");
assert_valid("<percentage> ", "10%");
assert_valid("<color>+", "red");
assert_valid(" <length>+ | <percentage>", "2px 8px");
assert_valid("<length>|<percentage>|<length-percentage>", "2px"); // Valid but silly
assert_valid("<color> | <image> | <url> | <integer> | <angle>", "red");
assert_valid("<time> | <resolution> | <transform-function> | <custom-ident>", "red");
assert_valid("*", ":> hello");
assert_valid("*", "([ brackets ]) { yay (??)}");
assert_valid("*", "yep 'this is valid too'");
assert_valid("*", "unmatched opening bracket is valid :(");
assert_valid("*", '"');
assert_valid("<length>", "0");
assert_valid("<length>", "10px /*:)*/");
assert_valid("<length>", " calc(-2px)");
assert_valid("<length>", "calc(2px*4 + 10px)");
assert_valid("<length>", "7.1e-4cm");
assert_valid("<length>", "calc(7in - 12px)");
assert_valid("<length>+", "2px 7px calc(8px)");
assert_valid("<percentage>", "-9.3e3%");
assert_valid("<length-percentage>", "-54%");
assert_valid("<length-percentage>", "0");
assert_valid("<length-percentage>", "calc(-11px + 10.4%)");
assert_valid("<number>", "-109");
assert_valid("<number>", "2.3e4");
assert_valid("<integer>", "-109");
assert_valid("<integer>", "19");
assert_valid("<angle>", "10deg");
assert_valid("<angle>", "20.5rad");
assert_valid("<angle>", "calc(50grad + 3.14159rad)");
assert_valid("<time>", "2s");
assert_valid("<time>", "calc(2s - 9ms)");
assert_valid("<resolution>", "10dpi");
assert_valid("<resolution>", "-5.3dpcm");
assert_valid("<transform-function>", "scale(2)");
assert_valid("<transform-function>+", "translateX(2px) rotate(20deg)");
assert_valid("<color>", "rgb(12, 34, 56)");
assert_valid("<color>", "lightgoldenrodyellow");
assert_valid("<image>", "url(a)");
assert_valid("<image>", "linear-gradient(yellow, blue)");
assert_valid("<url>", "url(a)");
assert_valid("banana", "banana");
assert_valid("bAnAnA", "bAnAnA");
assert_valid("ba-na-nya", "ba-na-nya");
assert_valid("banana", "banan\\61");
assert_valid("<custom-ident>", "banan\\61");
assert_valid("big | bigger | BIGGER", "bigger");
assert_valid("foo+|bar", "foo foo foo");
assert_valid("banana\t", "banana");
assert_valid("\nbanana\r\n", "banana");
assert_valid("ba\f\n|\tna\r|nya", "nya");
assert_valid(null, "null");
assert_valid(undefined, "undefined");
assert_valid(["banana"], "banana");
// Invalid syntax
assert_invalid("banana,nya", "banana");
assert_invalid("banan\\61", "banana");
assert_invalid("<\\6c ength>", "10px");
assert_invalid("<banana>", "banana");
assert_invalid("<Number>", "10");
assert_invalid("<length", "10px");
assert_invalid("<LENGTH>", "10px");
assert_invalid("< length>", "10px");
assert_invalid("<length >", "10px");
assert_invalid("<length> +", "10px");
assert_invalid("<length>++", "10px");
assert_invalid("<length> | *", "10px");
assert_invalid("*|banana", "banana");
assert_invalid("*+", "banana");
assert_invalid("initial", "initial");
assert_invalid("<length>|initial", "10px");
assert_invalid("<length>|INHERIT", "10px");
// Invalid initialValue
assert_invalid("*", "initial");
assert_invalid("*", "inherit");
assert_invalid("*", "unset");
assert_invalid("*", "revert");
assert_invalid("<custom-ident>", "initial");
assert_invalid("<custom-ident>+", "foo inherit bar");
assert_invalid("*", ")");
assert_invalid("*", "([)]");
assert_invalid("*", "whee!");
assert_invalid("*", '"\n');
assert_invalid("*", "url(moo '')");
assert_invalid("*", "semi;colon");
assert_invalid("*", "var(invalid var ref)");
assert_invalid("*", "var(--foo)");
assert_invalid("banana", "bAnAnA");
assert_invalid("<length>", "var(--moo)");
assert_invalid("<length>", "10");
assert_invalid("<length>", "10%");
assert_invalid("<length>", "calc(5px + 10%)");
assert_invalid("<length>", "calc(5px * 3px / 6px)");
assert_invalid("<length>", "10em");
assert_invalid("<length>", "10vmin");
assert_invalid("<length>", "calc(4px + 3em)");
assert_invalid("<length>", "calc(4px + calc(8 * 2em))");
assert_invalid("<length>", "10px;");
assert_invalid("<length-percentage>", "calc(2px + 10% + 7ex)");
assert_invalid("<percentage>", "0");
assert_invalid("<integer>", "1.0");
assert_invalid("<integer>", "1e0");
assert_invalid("<number>|foo", "foo var(--foo, bla)");
assert_invalid("<angle>", "10%");
assert_invalid("<time>", "2px");
assert_invalid("<resolution>", "10");
assert_invalid("<transform-function>", "scale()");
assert_invalid("<color>", "fancy-looking");
assert_invalid("<image>", "banana.png");
assert_invalid("<url>", "banana.png");
</script>
......@@ -2,6 +2,20 @@
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<style>
#div1 {
--length: 5px;
--color: notacolor;
}
#div2 {
--color: pink;
}
</style>
<div id=div1></div>
<div id=div2></div>
<div id=div3></div>
<script>
test(function() {
var reregisterError = {name: 'InvalidModificationError'};
......@@ -23,4 +37,42 @@ test(function() {
CSS.unregisterProperty('--property2');
assert_throws(unregisterError, () => CSS.unregisterProperty({name: '--property2'}));
}, "Registration state is correctly managed and correct errors are thrown");
test(function() {
computedStyle1 = getComputedStyle(div1);
computedStyle2 = getComputedStyle(div2);
assert_equals(computedStyle1.getPropertyValue('--length'), ' 5px');
assert_equals(computedStyle1.getPropertyValue('--color'), ' notacolor');
assert_equals(computedStyle2.getPropertyValue('--length'), '');
assert_equals(computedStyle2.getPropertyValue('--color'), ' pink');
CSS.registerProperty({name: '--length', syntax: '<length>', initialValue: '10px'});
CSS.registerProperty({name: '--color', syntax: '<color>', initialValue: 'red'});
assert_equals(computedStyle1.getPropertyValue('--length'), '5px');
assert_equals(computedStyle1.getPropertyValue('--color'), 'red');
assert_equals(computedStyle2.getPropertyValue('--length'), '10px');
assert_equals(computedStyle2.getPropertyValue('--color'), 'pink');
CSS.unregisterProperty('--length');
CSS.unregisterProperty('--color');
assert_equals(computedStyle1.getPropertyValue('--length'), ' 5px');
assert_equals(computedStyle1.getPropertyValue('--color'), ' notacolor');
assert_equals(computedStyle2.getPropertyValue('--length'), '');
assert_equals(computedStyle2.getPropertyValue('--color'), ' pink');
}, "Unregistration correctly updates computed style");
test(function() {
computedStyle = getComputedStyle(div3);
assert_equals(computedStyle.getPropertyValue('--x'), '');
CSS.registerProperty({name: '--x', syntax: '<length>', initialValue: '10px'});
assert_equals(computedStyle.getPropertyValue('--x'), '10px');
CSS.unregisterProperty('--x');
assert_equals(computedStyle.getPropertyValue('--x'), '');
CSS.registerProperty({name: '--x', syntax: '<color>', initialValue: 'purple'});
div3.style.setProperty('--x', '5px');
assert_equals(computedStyle.getPropertyValue('--x'), 'purple');
}, "Property can be re-registered with different type");
</script>
......@@ -8,19 +8,127 @@
#include "core/css/CSSURIValue.h"
#include "core/css/CSSValueList.h"
#include "core/css/CSSVariableReferenceValue.h"
#include "core/css/parser/CSSParserIdioms.h"
#include "core/css/parser/CSSPropertyParserHelpers.h"
#include "core/css/parser/CSSTokenizer.h"
#include "core/css/parser/CSSVariableParser.h"
#include "core/html/parser/HTMLParserIdioms.h"
namespace blink {
void consumeWhitespace(const String& string, size_t& offset)
{
while (isHTMLSpace(string[offset]))
offset++;
}
bool consumeCharacterAndWhitespace(const String& string, char character, size_t& offset)
{
if (string[offset] != character)
return false;
offset++;
consumeWhitespace(string, offset);
return true;
}
CSSSyntaxType parseSyntaxType(String type)
{
// TODO(timloh): Are these supposed to be case sensitive?
if (type == "length")
return CSSSyntaxType::Length;
if (type == "number")
return CSSSyntaxType::Number;
if (type == "percentage")
return CSSSyntaxType::Percentage;
if (type == "length-percentage")
return CSSSyntaxType::LengthPercentage;
if (type == "color")
return CSSSyntaxType::Color;
if (type == "image")
return CSSSyntaxType::Image;
if (type == "url")
return CSSSyntaxType::Url;
if (type == "integer")
return CSSSyntaxType::Integer;
if (type == "angle")
return CSSSyntaxType::Angle;
if (type == "time")
return CSSSyntaxType::Time;
if (type == "resolution")
return CSSSyntaxType::Resolution;
if (type == "transform-function")
return CSSSyntaxType::TransformFunction;
if (type == "custom-ident")
return CSSSyntaxType::CustomIdent;
// Not an Ident, just used to indicate failure
return CSSSyntaxType::Ident;
}
bool consumeSyntaxType(const String& input, size_t& offset, CSSSyntaxType& type)
{
DCHECK_EQ(input[offset], '<');
offset++;
size_t typeStart = offset;
while (offset < input.length() && input[offset] != '>')
offset++;
if (offset == input.length())
return false;
type = parseSyntaxType(input.substring(typeStart, offset - typeStart));
if (type == CSSSyntaxType::Ident)
return false;
offset++;
return true;
}
bool consumeSyntaxIdent(const String& input, size_t& offset, String& ident)
{
// TODO(timloh): Are CSS-wide keywords allowed here?
size_t identStart = offset;
while (isNameCodePoint(input[offset]))
offset++;
if (offset == identStart)
return false;
ident = input.substring(identStart, offset - identStart);
return true;
}
CSSSyntaxDescriptor::CSSSyntaxDescriptor(String input)
{
// TODO(timloh): Implement proper parsing
if (input.contains('*'))
m_syntaxComponents.append(CSSSyntaxComponent(CSSSyntaxType::TokenStream));
else
m_syntaxComponents.append(CSSSyntaxComponent(CSSSyntaxType::Length));
size_t offset = 0;
consumeWhitespace(input, offset);
if (consumeCharacterAndWhitespace(input, '*', offset)) {
if (offset != input.length())
return;
m_syntaxComponents.append(CSSSyntaxComponent(CSSSyntaxType::TokenStream, emptyString(), false));
return;
}
do {
CSSSyntaxType type;
String ident;
bool success;
if (input[offset] == '<') {
success = consumeSyntaxType(input, offset, type);
} else {
type = CSSSyntaxType::Ident;
success = consumeSyntaxIdent(input, offset, ident);
}
if (!success) {
m_syntaxComponents.clear();
return;
}
bool repeatable = consumeCharacterAndWhitespace(input, '+', offset);
consumeWhitespace(input, offset);
m_syntaxComponents.append(CSSSyntaxComponent(type, ident, repeatable));
} while (consumeCharacterAndWhitespace(input, '|', offset));
if (offset != input.length())
m_syntaxComponents.clear();
}
const CSSValue* consumeSingleType(const CSSSyntaxComponent& syntax, CSSParserTokenRange& range)
......@@ -29,8 +137,40 @@ const CSSValue* consumeSingleType(const CSSSyntaxComponent& syntax, CSSParserTok
// TODO(timloh): Calc values need to be normalized
switch (syntax.m_type) {
case CSSSyntaxType::Ident:
if (range.peek().type() == IdentToken
&& range.peek().value() == syntax.m_string) {
range.consumeIncludingWhitespace();
return CSSCustomIdentValue::create(AtomicString(syntax.m_string));
}
return nullptr;
case CSSSyntaxType::Length:
return consumeLength(range, HTMLStandardMode, ValueRange::ValueRangeAll);
case CSSSyntaxType::Number:
return consumeNumber(range, ValueRange::ValueRangeAll);
case CSSSyntaxType::Percentage:
return consumePercent(range, ValueRange::ValueRangeAll);
case CSSSyntaxType::LengthPercentage:
return consumeLengthOrPercent(range, HTMLStandardMode, ValueRange::ValueRangeAll);
case CSSSyntaxType::Color:
return consumeColor(range, HTMLStandardMode);
case CSSSyntaxType::Image:
// TODO(timloh): This probably needs a proper parser context for relative URL resolution.
return consumeImage(range, strictCSSParserContext());
case CSSSyntaxType::Url:
return consumeUrl(range);
case CSSSyntaxType::Integer:
return consumeInteger(range);
case CSSSyntaxType::Angle:
return consumeAngle(range);
case CSSSyntaxType::Time:
return consumeTime(range, ValueRange::ValueRangeAll);
case CSSSyntaxType::Resolution:
return nullptr; // TODO(timloh): Implement this.
case CSSSyntaxType::TransformFunction:
return nullptr; // TODO(timloh): Implement this.
case CSSSyntaxType::CustomIdent:
return consumeCustomIdent(range);
default:
NOTREACHED();
return nullptr;
......@@ -40,6 +180,16 @@ const CSSValue* consumeSingleType(const CSSSyntaxComponent& syntax, CSSParserTok
const CSSValue* consumeSyntaxComponent(const CSSSyntaxComponent& syntax, CSSParserTokenRange range)
{
// CSS-wide keywords are already handled by the CSSPropertyParser
if (syntax.m_repeatable) {
CSSValueList* list = CSSValueList::createSpaceSeparated();
while (!range.atEnd()) {
const CSSValue* value = consumeSingleType(syntax, range);
if (!value)
return nullptr;
list->append(*value);
}
return list;
}
const CSSValue* result = consumeSingleType(syntax, range);
if (!range.atEnd())
return nullptr;
......
......@@ -13,18 +13,33 @@ class CSSValue;
enum class CSSSyntaxType {
TokenStream,
Ident,
Length,
// TODO(timloh): Add all the other types
Number,
Percentage,
LengthPercentage,
Color,
Image,
Url,
Integer,
Angle,
Time,
Resolution,
TransformFunction,
CustomIdent,
};
struct CSSSyntaxComponent {
CSSSyntaxComponent(CSSSyntaxType type)
CSSSyntaxComponent(CSSSyntaxType type, const String& string, bool repeatable)
: m_type(type)
, m_string(string)
, m_repeatable(repeatable)
{
}
CSSSyntaxType m_type;
// TODO(timloh): This will need to support arbitrary idents and list types
String m_string; // Only used when m_type is CSSSyntaxType::Ident
bool m_repeatable;
};
class CSSSyntaxDescriptor {
......
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