// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "third_party/blink/renderer/core/animation/css_var_cycle_interpolation_type.h" #include #include #include "base/memory/ptr_util.h" #include "third_party/blink/renderer/core/animation/css_interpolation_environment.h" #include "third_party/blink/renderer/core/animation/string_keyframe.h" #include "third_party/blink/renderer/core/css/css_custom_property_declaration.h" #include "third_party/blink/renderer/core/css/property_registration.h" #include "third_party/blink/renderer/core/css/resolver/css_variable_resolver.h" #include "third_party/blink/renderer/core/css/resolver/style_builder.h" #include "third_party/blink/renderer/core/style/computed_style.h" namespace blink { class CycleChecker : public InterpolationType::ConversionChecker { public: static std::unique_ptr Create( const CSSCustomPropertyDeclaration& declaration, bool cycle_detected) { return base::WrapUnique(new CycleChecker(declaration, cycle_detected)); } private: CycleChecker(const CSSCustomPropertyDeclaration& declaration, bool cycle_detected) : declaration_(declaration), cycle_detected_(cycle_detected) {} bool IsValid(const InterpolationEnvironment& environment, const InterpolationValue&) const final { DCHECK(ToCSSInterpolationEnvironment(environment).HasVariableResolver()); CSSVariableResolver& variable_resolver = ToCSSInterpolationEnvironment(environment).VariableResolver(); bool cycle_detected = false; variable_resolver.ResolveCustomPropertyAnimationKeyframe(*declaration_, cycle_detected); return cycle_detected == cycle_detected_; } Persistent declaration_; const bool cycle_detected_; }; CSSVarCycleInterpolationType::CSSVarCycleInterpolationType( const PropertyHandle& property, const PropertyRegistration& registration) : InterpolationType(property), registration_(registration) { DCHECK(property.IsCSSCustomProperty()); } static InterpolationValue CreateCycleDetectedValue() { return InterpolationValue(InterpolableList::Create(0)); } InterpolationValue CSSVarCycleInterpolationType::MaybeConvertSingle( const PropertySpecificKeyframe& keyframe, const InterpolationEnvironment& environment, const InterpolationValue& underlying, ConversionCheckers& conversion_checkers) const { const CSSCustomPropertyDeclaration& declaration = *ToCSSCustomPropertyDeclaration( ToCSSPropertySpecificKeyframe(keyframe).Value()); DCHECK_EQ(GetProperty().CustomPropertyName(), declaration.GetName()); if (!declaration.Value() || !declaration.Value()->NeedsVariableResolution()) { return nullptr; } DCHECK(ToCSSInterpolationEnvironment(environment).HasVariableResolver()); CSSVariableResolver& variable_resolver = ToCSSInterpolationEnvironment(environment).VariableResolver(); bool cycle_detected = false; variable_resolver.ResolveCustomPropertyAnimationKeyframe(declaration, cycle_detected); conversion_checkers.push_back( CycleChecker::Create(declaration, cycle_detected)); return cycle_detected ? CreateCycleDetectedValue() : nullptr; } static bool IsCycleDetected(const InterpolationValue& value) { return static_cast(value); } PairwiseInterpolationValue CSSVarCycleInterpolationType::MaybeConvertPairwise( const PropertySpecificKeyframe& start_keyframe, const PropertySpecificKeyframe& end_keyframe, const InterpolationEnvironment& environment, const InterpolationValue& underlying, ConversionCheckers& conversionCheckers) const { InterpolationValue start = MaybeConvertSingle(start_keyframe, environment, underlying, conversionCheckers); InterpolationValue end = MaybeConvertSingle(end_keyframe, environment, underlying, conversionCheckers); if (!IsCycleDetected(start) && !IsCycleDetected(end)) { return nullptr; } // If either keyframe has a cyclic dependency then the entire interpolation // unsets the custom property. if (!start) { start = CreateCycleDetectedValue(); } if (!end) { end = CreateCycleDetectedValue(); } return PairwiseInterpolationValue(std::move(start.interpolable_value), std::move(end.interpolable_value)); } InterpolationValue CSSVarCycleInterpolationType::MaybeConvertUnderlyingValue( const InterpolationEnvironment& environment) const { const ComputedStyle& style = ToCSSInterpolationEnvironment(environment).Style(); DCHECK(!style.GetVariable(GetProperty().CustomPropertyName()) || !style.GetVariable(GetProperty().CustomPropertyName()) ->NeedsVariableResolution()); return nullptr; } void CSSVarCycleInterpolationType::Apply( const InterpolableValue&, const NonInterpolableValue*, InterpolationEnvironment& environment) const { StyleBuilder::ApplyProperty( GetProperty().GetCSSPropertyName(), ToCSSInterpolationEnvironment(environment).GetState(), *CSSCustomPropertyDeclaration::Create(GetProperty().CustomPropertyName(), CSSValueUnset)); } } // namespace blink