Commit 797edda2 authored by Darren Shen's avatar Darren Shen Committed by Commit Bot

[css-typed-om] Implement CSSStyleValue.parseAll.

CSSStyleValue.parseAll is similar to CSSStyleValue.parse in that it
converts a string value into a CSSStyleValue. The main difference is
how it handles list-valued properties.

Spec: https://drafts.css-houdini.org/css-typed-om-1/#dom-cssstylevalue-parseall

To reduce duplication, we move the common logic between parse and
parseAll into a helper function.

We also change the tests for parseAll because they wrongly expected that
parseAll return a CSSStyleValue instead of a sequence of CSSStyleValues.

Bug: 775802
Change-Id: I4b6b05d3a164e34709839ca2e059ec3fbf18a993
Reviewed-on: https://chromium-review.googlesource.com/742822
Commit-Queue: Darren Shen <shend@chromium.org>
Reviewed-by: default avatarnainar <nainar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#513054}
parent 6f337bcc
......@@ -3,17 +3,17 @@ PASS Calling CSSStyleValue.parse with an empty string throws a TypeError
PASS Calling CSSStyleValue.parse with an unsupported CSS property throws a TypeError
PASS Calling CSSStyleValue.parse with a CSS shorthand throws a TypeError
PASS Calling CSSStyleValue.parse with an invalid cssText for the given property throws a SyntaxError
PASS Calling CSSStyleValue.parse with a valid cssText for the given property returns a valid CSSStyleValue
PASS Calling CSSStyleValue.parse with a mixed case cssText returns a valid CSSStyleValue
FAIL Calling CSSStyleValue.parse with a custom property returns a valid CSSStyleValue Failed to execute 'parse' on 'CSSStyleValue': Invalid property name
PASS Calling CSSStyleValue.parseAll with an empty string throws a TypeError
PASS Calling CSSStyleValue.parseAll with an unsupported CSS property throws a TypeError
PASS Calling CSSStyleValue.parseAll with a CSS shorthand throws a TypeError
FAIL Calling CSSStyleValue.parseAll with an invalid cssText for the given property throws a SyntaxError assert_throws: function "() => CSSStyleValue[parseMethod]('width', '10deg')" threw object "TypeError: CSSStyleValue[parseMethod] is not a function" ("TypeError") expected object "SyntaxError" ("SyntaxError")
FAIL Calling CSSStyleValue.parseAll with a valid cssText for the given property returns a valid CSSStyleValue CSSStyleValue[parseMethod] is not a function
FAIL Calling CSSStyleValue.parseAll with a mixed case cssText returns a valid CSSStyleValue CSSStyleValue[parseMethod] is not a function
FAIL Calling CSSStyleValue.parseAll with a custom property returns a valid CSSStyleValue CSSStyleValue[parseMethod] is not a function
PASS Calling CSSStyleValue.parseAll with an invalid cssText for the given property throws a SyntaxError
PASS Calling CSSStyleValue.parse with a valid cssText for the given property returns a valid CSSStyleValue
PASS Calling CSSStyleValue.parse with a mixed case cssText returns a valid CSSStyleValue
FAIL Calling CSSStyleValue.parse with a custom property returns a valid CSSStyleValue Failed to execute 'parse' on 'CSSStyleValue': Invalid property name
PASS Calling CSSStyleValue.parseAll with a valid cssText for the given property returns a single-element list containing a valid CSSStyleValue
PASS Calling CSSStyleValue.parseAll with a mixed case cssText returns a single-element list containing a valid CSSStyleValue
FAIL Calling CSSStyleValue.parseAll with a custom property returns a single-element list containing a valid CSSStyleValue Failed to execute 'parseAll' on 'CSSStyleValue': Invalid property name
PASS Calling CSSStyleValue.parse with a list-value property returns first list value
FAIL Calling CSSStyleValue.parseAll with a list-value property returns a sequence of values CSSStyleValue.parseAll is not a function
PASS Calling CSSStyleValue.parseAll with a list-value property returns a sequence of values
Harness: the test ran to completion.
......@@ -25,21 +25,26 @@ for (const parseMethod of ['parse', 'parseAll']) {
test(() => {
assert_throws(new SyntaxError(), () => CSSStyleValue[parseMethod]('width', '10deg'));
}, 'Calling CSSStyleValue.' + parseMethod + ' with an invalid cssText for the given property throws a SyntaxError');
}
test(() => {
const result = CSSStyleValue[parseMethod]('width', '10px');
assert_style_value_equals(result, CSS.px(10));
}, 'Calling CSSStyleValue.' + parseMethod + ' with a valid cssText for the given property returns a valid CSSStyleValue');
const gValidNonListTests = [
{ property: 'width', value: '10px', expected: CSS.px(10), desc: 'a valid cssText for the given property' },
{ property: 'wIdTh', value: '10px', expected: CSS.px(10), desc: 'a mixed case cssText' },
{ property: '--foo', value: '10%', expected: CSS.percent(10), desc: 'a custom property' },
];
for (const {property, value, expected, desc} of gValidNonListTests) {
test(() => {
const result = CSSStyleValue[parseMethod]('wIdTh', '10px');
assert_style_value_equals(result, CSS.px(10));
}, 'Calling CSSStyleValue.' + parseMethod + ' with a mixed case cssText returns a valid CSSStyleValue');
const result = CSSStyleValue.parse(property, value);
assert_style_value_equals(result, expected);
}, 'Calling CSSStyleValue.parse with ' + desc + ' returns a valid CSSStyleValue');
}
for (const {property, value, expected, desc} of gValidNonListTests) {
test(() => {
const result = CSSStyleValue[parseMethod]('--foo', '10%');
assert_style_value_equals(result, CSS.percent(10));
}, 'Calling CSSStyleValue.' + parseMethod + ' with a custom property returns a valid CSSStyleValue');
const result = CSSStyleValue.parseAll(property, value);
assert_style_value_array_equals(result, [expected]);
}, 'Calling CSSStyleValue.parseAll with ' + desc + ' returns a single-element list containing a valid CSSStyleValue');
}
test(() => {
......
......@@ -794,6 +794,7 @@ interface CSSStyleSheet : StyleSheet
method removeRule
interface CSSStyleValue
static method parse
static method parseAll
attribute @@toStringTag
method constructor
method toString
......
......@@ -13,25 +13,23 @@
namespace blink {
ScriptValue CSSStyleValue::parse(ScriptState* script_state,
const String& property_name,
namespace {
CSSStyleValueVector ParseCSSStyleValue(const String& property_name,
const String& value,
ExceptionState& exception_state) {
if (property_name.IsEmpty()) {
exception_state.ThrowTypeError("Property name cannot be empty");
return ScriptValue::CreateNull(script_state);
}
const CSSPropertyID property_id = cssPropertyID(property_name);
CSSPropertyID property_id = cssPropertyID(property_name);
// TODO(timloh): Handle custom properties
// TODO(775804): Handle custom properties
if (property_id == CSSPropertyInvalid || property_id == CSSPropertyVariable) {
exception_state.ThrowTypeError("Invalid property name");
return ScriptValue::CreateNull(script_state);
return CSSStyleValueVector();
}
if (isShorthandProperty(property_id)) {
exception_state.ThrowTypeError(
"Parsing shorthand properties is not supported");
return ScriptValue::CreateNull(script_state);
return CSSStyleValueVector();
}
const CSSValue* css_value =
......@@ -41,17 +39,38 @@ ScriptValue CSSStyleValue::parse(ScriptState* script_state,
kSyntaxError, "The value provided ('" + value +
"') could not be parsed as a '" + property_name +
"'.");
return ScriptValue::CreateNull(script_state);
return CSSStyleValueVector();
}
CSSStyleValueVector style_value_vector =
StyleValueFactory::CssValueToStyleValueVector(property_id, *css_value);
DCHECK(!style_value_vector.IsEmpty());
return style_value_vector;
}
} // namespace
CSSStyleValue* CSSStyleValue::parse(const String& property_name,
const String& value,
ExceptionState& exception_state) {
CSSStyleValueVector style_value_vector =
ParseCSSStyleValue(property_name, value, exception_state);
if (style_value_vector.IsEmpty())
return nullptr;
return style_value_vector[0];
}
Nullable<CSSStyleValueVector> CSSStyleValue::parseAll(
const String& property_name,
const String& value,
ExceptionState& exception_state) {
CSSStyleValueVector style_value_vector =
ParseCSSStyleValue(property_name, value, exception_state);
if (style_value_vector.IsEmpty())
return nullptr;
v8::Local<v8::Value> wrapped_value =
ToV8(style_value_vector[0], script_state->GetContext()->Global(),
script_state->GetIsolate());
return ScriptValue(script_state, wrapped_value);
return style_value_vector;
}
String CSSStyleValue::StyleValueTypeToString(StyleValueType type) {
......
......@@ -5,6 +5,7 @@
#ifndef CSSStyleValue_h
#define CSSStyleValue_h
#include "bindings/core/v8/Nullable.h"
#include "core/CSSPropertyNames.h"
#include "core/CoreExport.h"
#include "core/css/CSSValue.h"
......@@ -14,8 +15,9 @@
namespace blink {
class ExceptionState;
class ScriptState;
class ScriptValue;
class CSSStyleValue;
using CSSStyleValueVector = HeapVector<Member<CSSStyleValue>>;
// The base class for all CSS values returned by the Typed OM.
// See CSSStyleValue.idl for additional documentation about this class.
......@@ -48,8 +50,10 @@ class CORE_EXPORT CSSStyleValue : public ScriptWrappable {
kInvalidType,
};
static ScriptValue parse(ScriptState*,
const String& property_name,
static CSSStyleValue* parse(const String& property_name,
const String& value,
ExceptionState&);
static Nullable<CSSStyleValueVector> parseAll(const String& property_name,
const String& value,
ExceptionState&);
......@@ -75,8 +79,6 @@ class CORE_EXPORT CSSStyleValue : public ScriptWrappable {
CSSStyleValue() {}
};
typedef HeapVector<Member<CSSStyleValue>> CSSStyleValueVector;
} // namespace blink
#endif
......@@ -10,7 +10,7 @@
Exposed(Window CSSTypedOM, PaintWorklet CSSPaintAPI)
] interface CSSStyleValue {
stringifier;
// TODO(meade): Should be (CSSStyleValue or sequence<CSSStyleValue>)? instead of object?. Fix when the code generator supports this.
// Putting Exposed=Window in the next line makes |parse| not exposed to PaintWorklet.
[RaisesException, CallWith=ScriptState, Exposed=Window] static object? parse(DOMString property, DOMString cssText);
[RaisesException, Exposed=Window] static CSSStyleValue? parse(DOMString property, DOMString cssText);
[RaisesException, Exposed=Window] static sequence<CSSStyleValue>? parseAll(DOMString property, DOMString cssText);
};
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