diff options
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.cc | 156 |
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, ®istration)); + 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, ®istration, + *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; |