summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc156
1 files changed, 136 insertions, 20 deletions
diff --git a/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc b/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc
index adc08f09890..3994c6abc7e 100644
--- a/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc
+++ b/chromium/third_party/blink/renderer/core/css/cssom/style_property_map.cc
@@ -22,6 +22,21 @@ namespace blink {
namespace {
+bool IsListValuedProperty(const CSSProperty& property,
+ const PropertyRegistration* registration) {
+ if (property.IsRepeated())
+ return true;
+ // TODO(andruud): The concept of "list-valued properties" doesn't fully work
+ // in all cases. See https://github.com/w3c/css-houdini-drafts/issues/823
+ // For now we only consider a custom property list-valued if it has a single
+ // syntax component that is repeatable (e.g. <length>+).
+ if (property.IDEquals(CSSPropertyVariable) && registration) {
+ const auto& components = registration->Syntax().Components();
+ return components.size() == 1 && components[0].IsRepeatable();
+ }
+ return false;
+}
+
CSSValueList* CssValueListForPropertyID(CSSPropertyID property_id) {
DCHECK(CSSProperty::Get(property_id).IsRepeated());
char separator = CSSProperty::Get(property_id).RepetitionSeparator();
@@ -38,6 +53,56 @@ CSSValueList* CssValueListForPropertyID(CSSPropertyID property_id) {
}
}
+String StyleValueToString(const CSSProperty& property,
+ const CSSStyleValue& style_value,
+ const CSSSyntaxComponent* syntax_component) {
+ if (style_value.GetType() == CSSStyleValue::kUnknownType)
+ return style_value.toString();
+ return style_value
+ .ToCSSValueWithProperty(property.PropertyID(), syntax_component)
+ ->CssText();
+}
+
+const CSSVariableReferenceValue* CreateVariableReferenceValue(
+ const String& value,
+ const CSSParserContext& context) {
+ CSSTokenizer tokenizer(value);
+ const auto tokens = tokenizer.TokenizeToEOF();
+ CSSParserTokenRange range(tokens);
+ scoped_refptr<CSSVariableData> variable_data = CSSVariableData::Create(
+ range, false, false, context.BaseURL(), context.Charset());
+ return CSSVariableReferenceValue::Create(variable_data, context);
+}
+
+const CSSVariableReferenceValue* CreateVariableReferenceValue(
+ const CSSProperty& property,
+ const AtomicString& custom_property_name,
+ const PropertyRegistration& registration,
+ const CSSStyleValueVector& values,
+ const CSSParserContext& context) {
+ DCHECK(IsListValuedProperty(property, &registration));
+ DCHECK_EQ(registration.Syntax().Components().size(), 1U);
+
+ char separator = registration.Syntax().Components()[0].Separator();
+
+ StringBuilder builder;
+
+ for (const auto& value : values) {
+ const CSSSyntaxComponent* syntax_component = nullptr;
+
+ if (!CSSOMTypes::PropertyCanTake(property.PropertyID(),
+ custom_property_name, &registration,
+ *value, syntax_component)) {
+ return nullptr;
+ }
+ if (!builder.IsEmpty())
+ builder.Append(separator);
+ builder.Append(StyleValueToString(property, *value, syntax_component));
+ }
+
+ return CreateVariableReferenceValue(builder.ToString(), context);
+}
+
const CSSValue* StyleValueToCSSValue(
const CSSProperty& property,
const AtomicString& custom_property_name,
@@ -47,9 +112,12 @@ const CSSValue* StyleValueToCSSValue(
DCHECK_EQ(property.IDEquals(CSSPropertyVariable),
!custom_property_name.IsNull());
+ const CSSSyntaxComponent* syntax_component = nullptr;
+
const CSSPropertyID property_id = property.PropertyID();
if (!CSSOMTypes::PropertyCanTake(property_id, custom_property_name,
- registration, style_value)) {
+ registration, style_value,
+ syntax_component)) {
return nullptr;
}
@@ -69,13 +137,10 @@ const CSSValue* StyleValueToCSSValue(
case CSSPropertyVariable:
if (registration &&
style_value.GetType() != CSSStyleValue::kUnparsedType) {
- CSSTokenizer tokenizer(style_value.toString());
- const auto tokens = tokenizer.TokenizeToEOF();
- CSSParserTokenRange range(tokens);
CSSParserContext* context = CSSParserContext::Create(execution_context);
- scoped_refptr<CSSVariableData> variable_data = CSSVariableData::Create(
- range, false, false, context->BaseURL(), context->Charset());
- return CSSVariableReferenceValue::Create(variable_data, *context);
+ String string =
+ StyleValueToString(property, style_value, syntax_component);
+ return CreateVariableReferenceValue(string, *context);
}
break;
case CSSPropertyBorderBottomLeftRadius:
@@ -198,7 +263,7 @@ const CSSValue* StyleValueToCSSValue(
break;
}
- return style_value.ToCSSValueWithProperty(property_id);
+ return style_value.ToCSSValueWithProperty(property_id, syntax_component);
}
const CSSValue* CoerceStyleValueOrString(
@@ -207,7 +272,7 @@ const CSSValue* CoerceStyleValueOrString(
const PropertyRegistration* registration,
const CSSStyleValueOrString& value,
const ExecutionContext& execution_context) {
- DCHECK(!property.IsRepeated());
+ DCHECK(!IsListValuedProperty(property, registration));
DCHECK_EQ(property.IDEquals(CSSPropertyVariable),
!custom_property_name.IsNull());
@@ -233,9 +298,10 @@ const CSSValue* CoerceStyleValueOrString(
const CSSValue* CoerceStyleValuesOrStrings(
const CSSProperty& property,
const AtomicString& custom_property_name,
+ const PropertyRegistration* registration,
const HeapVector<CSSStyleValueOrString>& values,
const ExecutionContext& execution_context) {
- DCHECK(property.IsRepeated());
+ DCHECK(IsListValuedProperty(property, registration));
DCHECK_EQ(property.IDEquals(CSSPropertyVariable),
!custom_property_name.IsNull());
if (values.IsEmpty())
@@ -243,11 +309,18 @@ const CSSValue* CoerceStyleValuesOrStrings(
CSSStyleValueVector style_values =
StyleValueFactory::CoerceStyleValuesOrStrings(
- property, custom_property_name, nullptr, values, execution_context);
+ property, custom_property_name, registration, values,
+ execution_context);
if (style_values.IsEmpty())
return nullptr;
+ if (property.IDEquals(CSSPropertyVariable) && registration) {
+ CSSParserContext* context = CSSParserContext::Create(execution_context);
+ return CreateVariableReferenceValue(property, custom_property_name,
+ *registration, style_values, *context);
+ }
+
CSSValueList* result = CssValueListForPropertyID(property.PropertyID());
for (const auto& style_value : style_values) {
const CSSValue* css_value =
@@ -286,8 +359,10 @@ void StylePropertyMap::set(const ExecutionContext* execution_context,
String css_text;
if (values[0].IsCSSStyleValue()) {
CSSStyleValue* style_value = values[0].GetAsCSSStyleValue();
- if (style_value && CSSOMTypes::PropertyCanTake(property_id, g_null_atom,
- nullptr, *style_value)) {
+ const CSSSyntaxComponent* syntax_component = nullptr;
+ if (style_value &&
+ CSSOMTypes::PropertyCanTake(property_id, g_null_atom, nullptr,
+ *style_value, syntax_component)) {
css_text = style_value->toString();
}
} else {
@@ -317,9 +392,10 @@ void StylePropertyMap::set(const ExecutionContext* execution_context,
}
const CSSValue* result = nullptr;
- if (property.IsRepeated()) {
- result = CoerceStyleValuesOrStrings(property, custom_property_name, values,
- *execution_context);
+ if (IsListValuedProperty(property, registration)) {
+ result =
+ CoerceStyleValuesOrStrings(property, custom_property_name, registration,
+ values, *execution_context);
} else if (values.size() == 1U) {
result =
CoerceStyleValueOrString(property, custom_property_name, registration,
@@ -351,13 +427,55 @@ void StylePropertyMap::append(const ExecutionContext* execution_context,
return;
}
+ const CSSProperty& property = CSSProperty::Get(property_id);
+
if (property_id == CSSPropertyVariable) {
+ AtomicString custom_property_name(property_name);
+
+ const PropertyRegistration* registration =
+ PropertyRegistration::From(execution_context, custom_property_name);
+
+ if (registration && IsListValuedProperty(property, registration)) {
+ CSSStyleValueVector style_values;
+
+ // Add existing CSSStyleValues:
+ if (const CSSValue* css_value =
+ GetCustomProperty(*execution_context, custom_property_name)) {
+ DCHECK(css_value->IsValueList());
+ style_values = StyleValueFactory::CssValueToStyleValueVector(
+ property_id, custom_property_name, *css_value);
+ }
+
+ // Append incoming CSSStyleValues:
+ CSSStyleValueVector incoming_style_values =
+ StyleValueFactory::CoerceStyleValuesOrStrings(
+ property, custom_property_name, registration, values,
+ *execution_context);
+
+ const CSSValue* result = nullptr;
+
+ if (!incoming_style_values.IsEmpty()) {
+ style_values.AppendVector(incoming_style_values);
+ CSSParserContext* context =
+ CSSParserContext::Create(*execution_context);
+ result =
+ CreateVariableReferenceValue(property, custom_property_name,
+ *registration, style_values, *context);
+ }
+
+ if (!result) {
+ exception_state.ThrowTypeError("Invalid type for property");
+ return;
+ }
+
+ SetCustomProperty(custom_property_name, *result);
+ return;
+ }
exception_state.ThrowTypeError(
"Appending to custom properties is not supported");
return;
}
- const CSSProperty& property = CSSProperty::Get(property_id);
if (!property.IsRepeated()) {
exception_state.ThrowTypeError("Property does not support multiple values");
return;
@@ -371,10 +489,8 @@ void StylePropertyMap::append(const ExecutionContext* execution_context,
current_value = CssValueListForPropertyID(property_id);
}
- // TODO(andruud): Don't pass g_null_atom as custom property name
- // once appending to custom properties is supported.
const CSSValue* result = CoerceStyleValuesOrStrings(
- property, g_null_atom, values, *execution_context);
+ property, g_null_atom, nullptr, values, *execution_context);
if (!result || !result->IsValueList()) {
exception_state.ThrowTypeError("Invalid type for property");
return;