| Index: third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp
|
| diff --git a/third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp
|
| index 0aa388db0bf3dca304d164fae5093570908ffe4c..56f5e359f37fd2718294bd0ffc6af5596e641c25 100644
|
| --- a/third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp
|
| +++ b/third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp
|
| @@ -6,9 +6,16 @@
|
|
|
| #include "core/StylePropertyShorthand.h"
|
| #include "core/animation/StringKeyframe.h"
|
| +#include "core/css/CSSCustomPropertyDeclaration.h"
|
| +#include "core/css/CSSValue.h"
|
| #include "core/css/CSSVariableReferenceValue.h"
|
| +#include "core/css/ComputedStyleCSSValueMapping.h"
|
| +#include "core/css/PropertyRegistry.h"
|
| +#include "core/css/parser/CSSTokenizer.h"
|
| #include "core/css/resolver/CSSVariableResolver.h"
|
| +#include "core/css/resolver/StyleBuilder.h"
|
| #include "core/css/resolver/StyleResolverState.h"
|
| +#include "core/style/DataEquivalency.h"
|
| #include "platform/RuntimeEnabledFeatures.h"
|
| #include "wtf/PtrUtil.h"
|
| #include <memory>
|
| @@ -50,6 +57,45 @@ class ResolvedVariableChecker : public InterpolationType::ConversionChecker {
|
| Persistent<const CSSValue> m_resolvedValue;
|
| };
|
|
|
| +class InheritedCustomPropertyChecker
|
| + : public InterpolationType::ConversionChecker {
|
| + public:
|
| + static std::unique_ptr<InheritedCustomPropertyChecker> create(
|
| + const AtomicString& property,
|
| + bool isInheritedProperty,
|
| + const CSSValue* inheritedValue,
|
| + const CSSValue* initialValue) {
|
| + return WTF::wrapUnique(new InheritedCustomPropertyChecker(
|
| + property, isInheritedProperty, inheritedValue, initialValue));
|
| + }
|
| +
|
| + private:
|
| + InheritedCustomPropertyChecker(const AtomicString& name,
|
| + bool isInheritedProperty,
|
| + const CSSValue* inheritedValue,
|
| + const CSSValue* initialValue)
|
| + : m_name(name),
|
| + m_isInheritedProperty(isInheritedProperty),
|
| + m_inheritedValue(inheritedValue),
|
| + m_initialValue(initialValue) {}
|
| +
|
| + bool isValid(const InterpolationEnvironment& environment,
|
| + const InterpolationValue&) const final {
|
| + const CSSValue* inheritedValue =
|
| + environment.state().parentStyle()->getRegisteredVariable(
|
| + m_name, m_isInheritedProperty);
|
| + if (!inheritedValue) {
|
| + inheritedValue = m_initialValue.get();
|
| + }
|
| + return m_inheritedValue->equals(*inheritedValue);
|
| + }
|
| +
|
| + const AtomicString& m_name;
|
| + const bool m_isInheritedProperty;
|
| + Persistent<const CSSValue> m_inheritedValue;
|
| + Persistent<const CSSValue> m_initialValue;
|
| +};
|
| +
|
| CSSInterpolationType::CSSInterpolationType(PropertyHandle property)
|
| : InterpolationType(property) {
|
| DCHECK(!isShorthandProperty(cssProperty()));
|
| @@ -76,16 +122,22 @@ InterpolationValue CSSInterpolationType::maybeConvertSingleInternal(
|
| const InterpolationValue& underlying,
|
| ConversionCheckers& conversionCheckers) const {
|
| const CSSValue* value = toCSSPropertySpecificKeyframe(keyframe).value();
|
| + const StyleResolverState& state = environment.state();
|
|
|
| if (!value)
|
| return maybeConvertNeutral(underlying, conversionCheckers);
|
|
|
| + if (getProperty().isCSSCustomProperty()) {
|
| + return maybeConvertCustomPropertyDeclaration(
|
| + toCSSCustomPropertyDeclaration(*value), state, conversionCheckers);
|
| + }
|
| +
|
| if (value->isVariableReferenceValue() ||
|
| value->isPendingSubstitutionValue()) {
|
| bool omitAnimationTainted = false;
|
| const CSSValue* resolvedValue =
|
| CSSVariableResolver::resolveVariableReferences(
|
| - environment.state(), cssProperty(), *value, omitAnimationTainted);
|
| + state, cssProperty(), *value, omitAnimationTainted);
|
| conversionCheckers.push_back(
|
| ResolvedVariableChecker::create(cssProperty(), value, resolvedValue));
|
| value = resolvedValue;
|
| @@ -93,32 +145,174 @@ InterpolationValue CSSInterpolationType::maybeConvertSingleInternal(
|
|
|
| if (value->isInitialValue() ||
|
| (value->isUnsetValue() &&
|
| - !CSSPropertyMetadata::isInheritedProperty(cssProperty())))
|
| - return maybeConvertInitial(environment.state(), conversionCheckers);
|
| + !CSSPropertyMetadata::isInheritedProperty(cssProperty()))) {
|
| + return maybeConvertInitial(state, conversionCheckers);
|
| + }
|
|
|
| if (value->isInheritedValue() ||
|
| (value->isUnsetValue() &&
|
| - CSSPropertyMetadata::isInheritedProperty(cssProperty())))
|
| - return maybeConvertInherit(environment.state(), conversionCheckers);
|
| + CSSPropertyMetadata::isInheritedProperty(cssProperty()))) {
|
| + return maybeConvertInherit(state, conversionCheckers);
|
| + }
|
| +
|
| + return maybeConvertValue(*value, state, conversionCheckers);
|
| +}
|
| +
|
| +const PropertyRegistry::Registration* getRegistration(
|
| + const StyleResolverState& state,
|
| + const AtomicString& propertyName) {
|
| + const PropertyRegistry* registry = state.document().propertyRegistry();
|
| + if (registry) {
|
| + return registry->registration(propertyName);
|
| + }
|
| + return nullptr;
|
| +}
|
| +
|
| +InterpolationValue CSSInterpolationType::maybeConvertCustomPropertyDeclaration(
|
| + const CSSCustomPropertyDeclaration& declaration,
|
| + const StyleResolverState& state,
|
| + ConversionCheckers& conversionCheckers) const {
|
| + InterpolationValue result = maybeConvertCustomPropertyDeclarationInternal(
|
| + declaration, state, conversionCheckers);
|
| + if (result) {
|
| + return result;
|
| + }
|
| +
|
| + // TODO(alancutter): Make explicit and assert in code that this falls back to
|
| + // the default CSSValueInterpolationType handler.
|
| + // This might involve making the "catch-all" InterpolationType explicit
|
| + // e.g. add bool InterpolationType::isCatchAll().
|
| + return maybeConvertValue(declaration, state, conversionCheckers);
|
| +}
|
| +
|
| +InterpolationValue
|
| +CSSInterpolationType::maybeConvertCustomPropertyDeclarationInternal(
|
| + const CSSCustomPropertyDeclaration& declaration,
|
| + const StyleResolverState& state,
|
| + ConversionCheckers& conversionCheckers) const {
|
| + const AtomicString& name = declaration.name();
|
| + DCHECK_EQ(getProperty().customPropertyName(), name);
|
| +
|
| + const PropertyRegistry::Registration* registration =
|
| + getRegistration(state, name);
|
| +
|
| + if (!declaration.value()) {
|
| + // Unregistered custom properties inherit:
|
| + // https://www.w3.org/TR/css-variables-1/#defining-variables
|
| + bool isInheritedProperty = registration ? registration->inherits() : true;
|
| + DCHECK(declaration.isInitial(isInheritedProperty) ||
|
| + declaration.isInherit(isInheritedProperty));
|
| +
|
| + if (!registration) {
|
| + return nullptr;
|
| + }
|
| +
|
| + if (declaration.isInitial(isInheritedProperty)) {
|
| + return maybeConvertValue(*registration->initial(), state,
|
| + conversionCheckers);
|
| + }
|
| +
|
| + DCHECK(declaration.isInherit(isInheritedProperty));
|
| + const CSSValue* inheritedValue =
|
| + state.parentStyle()->getRegisteredVariable(name, isInheritedProperty);
|
| + if (!inheritedValue) {
|
| + inheritedValue = registration->initial();
|
| + }
|
| + conversionCheckers.push_back(InheritedCustomPropertyChecker::create(
|
| + name, isInheritedProperty, inheritedValue, registration->initial()));
|
| + return maybeConvertValue(*inheritedValue, state, conversionCheckers);
|
| + }
|
|
|
| - return maybeConvertValue(*value, environment.state(), conversionCheckers);
|
| + if (declaration.value()->needsVariableResolution()) {
|
| + // TODO(alancutter): Support smooth interpolation with var() values for
|
| + // registered custom properties. This requires integrating animated custom
|
| + // property value application with the CSSVariableResolver to apply them in
|
| + // the appropriate order defined by the chain of var() dependencies.
|
| + // All CSSInterpolationTypes should fail convertion here except for
|
| + // CSSValueInterpolationType.
|
| + return nullptr;
|
| + }
|
| +
|
| + if (registration) {
|
| + const CSSValue* parsedValue =
|
| + declaration.value()->parseForSyntax(registration->syntax());
|
| + if (parsedValue) {
|
| + return maybeConvertValue(*parsedValue, state, conversionCheckers);
|
| + }
|
| + }
|
| +
|
| + return nullptr;
|
| }
|
|
|
| InterpolationValue CSSInterpolationType::maybeConvertUnderlyingValue(
|
| const InterpolationEnvironment& environment) const {
|
| - // TODO(alancutter): Add support for converting underlying registered custom
|
| - // property values.
|
| - return maybeConvertStandardPropertyUnderlyingValue(environment.state());
|
| + const StyleResolverState& state = environment.state();
|
| + if (!getProperty().isCSSCustomProperty()) {
|
| + return maybeConvertStandardPropertyUnderlyingValue(state);
|
| + }
|
| +
|
| + const AtomicString& name = getProperty().customPropertyName();
|
| + const PropertyRegistry::Registration* registration =
|
| + getRegistration(state, name);
|
| + if (!registration) {
|
| + return nullptr;
|
| + }
|
| + const CSSValue* underlyingValue =
|
| + state.style()->getRegisteredVariable(name, registration->inherits());
|
| + if (!underlyingValue) {
|
| + underlyingValue = registration->initial();
|
| + }
|
| + // TODO(alancutter): Remove the need for passing in conversion checkers.
|
| + ConversionCheckers dummyConversionCheckers;
|
| + return maybeConvertValue(*underlyingValue, environment.state(),
|
| + dummyConversionCheckers);
|
| }
|
|
|
| void CSSInterpolationType::apply(
|
| const InterpolableValue& interpolableValue,
|
| const NonInterpolableValue* nonInterpolableValue,
|
| InterpolationEnvironment& environment) const {
|
| - // TODO(alancutter): Add support for applying registered custom property
|
| - // values.
|
| - return applyStandardPropertyValue(interpolableValue, nonInterpolableValue,
|
| - environment.state());
|
| + StyleResolverState& state = environment.state();
|
| +
|
| + if (getProperty().isCSSCustomProperty()) {
|
| + applyCustomPropertyValue(interpolableValue, nonInterpolableValue, state);
|
| + return;
|
| + }
|
| + applyStandardPropertyValue(interpolableValue, nonInterpolableValue, state);
|
| +}
|
| +
|
| +void CSSInterpolationType::applyCustomPropertyValue(
|
| + const InterpolableValue& interpolableValue,
|
| + const NonInterpolableValue* nonInterpolableValue,
|
| + StyleResolverState& state) const {
|
| + DCHECK(getProperty().isCSSCustomProperty());
|
| +
|
| + const CSSValue* cssValue =
|
| + createCSSValue(interpolableValue, nonInterpolableValue, state);
|
| + if (cssValue->isCustomPropertyDeclaration()) {
|
| + StyleBuilder::applyProperty(cssProperty(), state, *cssValue);
|
| + return;
|
| + }
|
| +
|
| + // TODO(alancutter): Defer tokenization of the CSSValue until it is needed.
|
| + String stringValue = cssValue->cssText();
|
| + CSSTokenizer tokenizer(stringValue);
|
| + bool isAnimationTainted = true;
|
| + bool needsVariableResolution = false;
|
| + RefPtr<CSSVariableData> variableData = CSSVariableData::create(
|
| + tokenizer.tokenRange(), isAnimationTainted, needsVariableResolution);
|
| + ComputedStyle& style = *state.style();
|
| + const AtomicString& propertyName = getProperty().customPropertyName();
|
| + const PropertyRegistry::Registration* registration =
|
| + getRegistration(state, propertyName);
|
| + DCHECK(registration);
|
| + if (registration->inherits()) {
|
| + style.setResolvedInheritedVariable(propertyName, variableData.release(),
|
| + cssValue);
|
| + } else {
|
| + style.setResolvedNonInheritedVariable(propertyName, variableData.release(),
|
| + cssValue);
|
| + }
|
| }
|
|
|
| } // namespace blink
|
|
|