void InvalidatableInterpolation::setFlagIfInheritUsed(InterpolationEnvironment& environment) const { if (!m_property.isCSSProperty() && !m_property.isPresentationAttribute()) return; if (!environment.state().parentStyle()) return; const CSSValue* startValue = toCSSPropertySpecificKeyframe(m_startKeyframe)->value(); const CSSValue* endValue = toCSSPropertySpecificKeyframe(m_endKeyframe)->value(); if ((startValue && startValue->isInheritedValue()) || (endValue && endValue->isInheritedValue())) { environment.state().parentStyle()->setHasExplicitlyInheritedProperties(); } }
InterpolationValue CSSInterpolationType::maybeConvertSingle( const PropertySpecificKeyframe& keyframe, const InterpolationEnvironment& environment, const InterpolationValue& underlying, ConversionCheckers& conversionCheckers) const { const CSSValue* value = toCSSPropertySpecificKeyframe(keyframe).value(); if (!value) return maybeConvertNeutral(underlying, conversionCheckers); if (value->isVariableReferenceValue() || value->isPendingSubstitutionValue()) { bool omitAnimationTainted = false; const CSSValue* resolvedValue = CSSVariableResolver::resolveVariableReferences( environment.state(), cssProperty(), *value, omitAnimationTainted); conversionCheckers.push_back( ResolvedVariableChecker::create(cssProperty(), value, resolvedValue)); value = resolvedValue; } if (value->isInitialValue() || (value->isUnsetValue() && !CSSPropertyMetadata::isInheritedProperty(cssProperty()))) return maybeConvertInitial(environment.state(), conversionCheckers); if (value->isInheritedValue() || (value->isUnsetValue() && CSSPropertyMetadata::isInheritedProperty(cssProperty()))) return maybeConvertInherit(environment.state(), conversionCheckers); return maybeConvertValue(*value, environment.state(), conversionCheckers); }
PassRefPtr<Interpolation> StringKeyframe::CSSPropertySpecificKeyframe::createLegacyStyleInterpolation(CSSPropertyID property, Keyframe::PropertySpecificKeyframe& end, Element* element, const ComputedStyle* baseStyle) const { CSSValue& fromCSSValue = *m_value.get(); CSSValue& toCSSValue = *toCSSPropertySpecificKeyframe(end).value(); if (DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(fromCSSValue) || DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(toCSSValue)) { // FIXME: Handle these cases outside of DeferredLegacyStyleInterpolation. return DeferredLegacyStyleInterpolation::create(&fromCSSValue, &toCSSValue, property); } // FIXME: Remove the use of AnimatableValues and Elements here. ASSERT(element); populateAnimatableValue(property, *element, baseStyle, false); end.populateAnimatableValue(property, *element, baseStyle, false); return LegacyStyleInterpolation::create(getAnimatableValue(), end.getAnimatableValue(), property); }
PassOwnPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::CSSPropertySpecificKeyframe::cloneWithOffset(double offset) const { Keyframe::PropertySpecificKeyframe* theClone = new CSSPropertySpecificKeyframe(offset, m_easing, m_value.get()); toCSSPropertySpecificKeyframe(theClone)->m_animatableValueCache = m_animatableValueCache; return adoptPtr(theClone); }
PassRefPtr<Interpolation> StringKeyframe::CSSPropertySpecificKeyframe::maybeCreateInterpolation(PropertyHandle propertyHandle, Keyframe::PropertySpecificKeyframe& end, Element* element, const ComputedStyle* baseStyle) const { const InterpolationTypes* applicableTypes = applicableTypesForProperty(propertyHandle); if (applicableTypes) return InvalidatableInterpolation::create(propertyHandle, *applicableTypes, *this, end); // TODO(alancutter): Remove the remainder of this function. // FIXME: Refactor this into a generic piece that lives in InterpolationEffect, and a template parameter specific converter. CSSPropertyID property = propertyHandle.isCSSProperty() ? propertyHandle.cssProperty() : propertyHandle.presentationAttribute(); CSSValue* fromCSSValue = m_value.get(); CSSValue* toCSSValue = toCSSPropertySpecificKeyframe(end).value(); InterpolationRange range = RangeAll; // FIXME: Remove this flag once we can rely on legacy's behaviour being correct. bool forceDefaultInterpolation = false; // FIXME: Remove this check once neutral keyframes are implemented in StringKeyframes. if (!fromCSSValue || !toCSSValue) return DeferredLegacyStyleInterpolation::create(fromCSSValue, toCSSValue, property); ASSERT(fromCSSValue && toCSSValue); if (!CSSPropertyMetadata::isInterpolableProperty(property)) { if (fromCSSValue == toCSSValue) return ConstantStyleInterpolation::create(fromCSSValue, property); return nullptr; } if (fromCSSValue->isCSSWideKeyword() || toCSSValue->isCSSWideKeyword()) return createLegacyStyleInterpolation(property, end, element, baseStyle); switch (property) { case CSSPropertyFontSize: if (LengthStyleInterpolation::canCreateFrom(*fromCSSValue) && LengthStyleInterpolation::canCreateFrom(*toCSSValue)) return LengthStyleInterpolation::create(*fromCSSValue, *toCSSValue, property, RangeNonNegative); // FIXME: Handle keywords e.g. 'smaller', 'larger'. if (property == CSSPropertyFontSize) return createLegacyStyleInterpolation(property, end, element, baseStyle); // FIXME: Handle keywords e.g. 'baseline', 'sub'. if (property == CSSPropertyBaselineShift) return createLegacyStyleInterpolation(property, end, element, baseStyle); break; case CSSPropertyMotionRotation: { RefPtr<Interpolation> interpolation = DoubleStyleInterpolation::maybeCreateFromMotionRotation(*fromCSSValue, *toCSSValue, property); if (interpolation) return interpolation.release(); break; } case CSSPropertyVisibility: if (VisibilityStyleInterpolation::canCreateFrom(*fromCSSValue) && VisibilityStyleInterpolation::canCreateFrom(*toCSSValue) && (VisibilityStyleInterpolation::isVisible(*fromCSSValue) || VisibilityStyleInterpolation::isVisible(*toCSSValue))) return VisibilityStyleInterpolation::create(*fromCSSValue, *toCSSValue, property); break; case CSSPropertyBorderBottomLeftRadius: case CSSPropertyBorderBottomRightRadius: case CSSPropertyBorderTopLeftRadius: case CSSPropertyBorderTopRightRadius: if (LengthPairStyleInterpolation::canCreateFrom(*fromCSSValue) && LengthPairStyleInterpolation::canCreateFrom(*toCSSValue)) return LengthPairStyleInterpolation::create(*fromCSSValue, *toCSSValue, property, RangeNonNegative); break; case CSSPropertyPerspectiveOrigin: case CSSPropertyTransformOrigin: { RefPtr<Interpolation> interpolation = ListStyleInterpolation<LengthStyleInterpolation>::maybeCreateFromList(*fromCSSValue, *toCSSValue, property, range); if (interpolation) return interpolation.release(); // FIXME: Handle keywords: top, right, left, center, bottom return createLegacyStyleInterpolation(property, end, element, baseStyle); } case CSSPropertyClip: { if (LengthBoxStyleInterpolation::usesDefaultInterpolation(*fromCSSValue, *toCSSValue)) { forceDefaultInterpolation = true; break; } RefPtr<Interpolation> interpolation = LengthBoxStyleInterpolation::maybeCreateFrom(*fromCSSValue, *toCSSValue, property); if (interpolation) return interpolation.release(); break; } case CSSPropertyBorderImageSlice: case CSSPropertyWebkitMaskBoxImageSlice: { RefPtr<Interpolation> interpolation = ImageSliceStyleInterpolation::maybeCreate(*fromCSSValue, *toCSSValue, property); if (interpolation) return interpolation.release(); if (ImageSliceStyleInterpolation::usesDefaultInterpolation(*fromCSSValue, *toCSSValue)) forceDefaultInterpolation = true; break; } case CSSPropertyWebkitFilter: case CSSPropertyBackdropFilter: { RefPtr<Interpolation> interpolation = FilterStyleInterpolation::maybeCreateList(*fromCSSValue, *toCSSValue, property); if (interpolation) return interpolation.release(); // FIXME: Support drop shadow interpolation. return createLegacyStyleInterpolation(property, end, element, baseStyle); break; } case CSSPropertyTranslate: { RefPtr<Interpolation> interpolation = ListStyleInterpolation<LengthStyleInterpolation>::maybeCreateFromList(*fromCSSValue, *toCSSValue, property, range); if (interpolation) return interpolation.release(); // TODO(soonm): Legacy mode is used when from and to cssvaluelist length does not match. return createLegacyStyleInterpolation(property, end, element, baseStyle); break; } case CSSPropertyScale: { RefPtr<Interpolation> interpolation = ListStyleInterpolation<DoubleStyleInterpolation>::maybeCreateFromList(*fromCSSValue, *toCSSValue, property, range); if (interpolation) return interpolation.release(); // TODO(soonm): Legacy mode is used when from and to cssvaluelist length does not match. return createLegacyStyleInterpolation(property, end, element, baseStyle); break; } default: // Fall back to LegacyStyleInterpolation. return createLegacyStyleInterpolation(property, end, element, baseStyle); break; } if (fromCSSValue == toCSSValue) return ConstantStyleInterpolation::create(fromCSSValue, property); if (!forceDefaultInterpolation) { ASSERT(AnimatableValue::usesDefaultInterpolation( StyleResolver::createAnimatableValueSnapshot(*element, baseStyle, property, fromCSSValue).get(), StyleResolver::createAnimatableValueSnapshot(*element, baseStyle, property, toCSSValue).get())); } return nullptr; }
PassRefPtrWillBeRawPtr<Interpolation> StringKeyframe::CSSPropertySpecificKeyframe::maybeCreateInterpolation(PropertyHandle propertyHandle, Keyframe::PropertySpecificKeyframe& end, Element* element, const ComputedStyle* baseStyle) const { CSSPropertyID property = propertyHandle.cssProperty(); const Vector<const InterpolationType*>* applicableTypes = applicableTypesForProperty(property); if (applicableTypes) return InvalidatableStyleInterpolation::create(*applicableTypes, *this, toCSSPropertySpecificKeyframe(end)); // TODO(alancutter): Remove the remainder of this function. // FIXME: Refactor this into a generic piece that lives in InterpolationEffect, and a template parameter specific converter. CSSValue* fromCSSValue = m_value.get(); CSSValue* toCSSValue = toCSSPropertySpecificKeyframe(end).value(); InterpolationRange range = RangeAll; // FIXME: Remove this flag once we can rely on legacy's behaviour being correct. bool forceDefaultInterpolation = false; // FIXME: Remove this check once neutral keyframes are implemented in StringKeyframes. if (!fromCSSValue || !toCSSValue) return DeferredLegacyStyleInterpolation::create(fromCSSValue, toCSSValue, property); ASSERT(fromCSSValue && toCSSValue); if (!CSSPropertyMetadata::isInterpolableProperty(property)) { if (fromCSSValue == toCSSValue) return ConstantStyleInterpolation::create(fromCSSValue, property); return nullptr; } if (fromCSSValue->isCSSWideKeyword() || toCSSValue->isCSSWideKeyword()) return createLegacyStyleInterpolation(property, end, element, baseStyle); switch (property) { case CSSPropertyLineHeight: if (LengthStyleInterpolation::canCreateFrom(*fromCSSValue) && LengthStyleInterpolation::canCreateFrom(*toCSSValue)) return LengthStyleInterpolation::create(*fromCSSValue, *toCSSValue, property, RangeNonNegative); if (DoubleStyleInterpolation::canCreateFrom(*fromCSSValue) && DoubleStyleInterpolation::canCreateFrom(*toCSSValue)) return DoubleStyleInterpolation::create(*fromCSSValue, *toCSSValue, property, true, RangeNonNegative); break; case CSSPropertyBorderBottomWidth: case CSSPropertyBorderLeftWidth: case CSSPropertyBorderRightWidth: case CSSPropertyBorderTopWidth: case CSSPropertyFlexBasis: case CSSPropertyFontSize: case CSSPropertyHeight: case CSSPropertyMaxHeight: case CSSPropertyMaxWidth: case CSSPropertyMinHeight: case CSSPropertyMinWidth: case CSSPropertyOutlineWidth: case CSSPropertyPaddingBottom: case CSSPropertyPaddingLeft: case CSSPropertyPaddingRight: case CSSPropertyPaddingTop: case CSSPropertyPerspective: case CSSPropertyR: case CSSPropertyRx: case CSSPropertyRy: case CSSPropertyShapeMargin: case CSSPropertyStrokeWidth: case CSSPropertyWebkitBorderHorizontalSpacing: case CSSPropertyWebkitBorderVerticalSpacing: case CSSPropertyWebkitColumnGap: case CSSPropertyWebkitColumnWidth: case CSSPropertyWidth: range = RangeNonNegative; // Fall through case CSSPropertyBaselineShift: case CSSPropertyBottom: case CSSPropertyCx: case CSSPropertyCy: case CSSPropertyLeft: case CSSPropertyLetterSpacing: case CSSPropertyMarginBottom: case CSSPropertyMarginLeft: case CSSPropertyMarginRight: case CSSPropertyMarginTop: case CSSPropertyMotionOffset: case CSSPropertyOutlineOffset: case CSSPropertyRight: case CSSPropertyStrokeDashoffset: case CSSPropertyTop: case CSSPropertyVerticalAlign: case CSSPropertyWordSpacing: case CSSPropertyWebkitColumnRuleWidth: case CSSPropertyWebkitPerspectiveOriginX: case CSSPropertyWebkitPerspectiveOriginY: case CSSPropertyWebkitTransformOriginX: case CSSPropertyWebkitTransformOriginY: case CSSPropertyWebkitTransformOriginZ: case CSSPropertyX: case CSSPropertyY: if (LengthStyleInterpolation::canCreateFrom(*fromCSSValue, property) && LengthStyleInterpolation::canCreateFrom(*toCSSValue, property)) return LengthStyleInterpolation::create(*fromCSSValue, *toCSSValue, property, range); // FIXME: Handle keywords e.g. 'smaller', 'larger'. if (property == CSSPropertyFontSize) return createLegacyStyleInterpolation(property, end, element, baseStyle); // FIXME: Handle keywords e.g. 'baseline', 'sub'. if (property == CSSPropertyBaselineShift) return createLegacyStyleInterpolation(property, end, element, baseStyle); break; case CSSPropertyOrphans: case CSSPropertyWidows: case CSSPropertyZIndex: case CSSPropertyWebkitColumnCount: case CSSPropertyShapeImageThreshold: case CSSPropertyFillOpacity: case CSSPropertyFloodOpacity: case CSSPropertyFontSizeAdjust: case CSSPropertyOpacity: case CSSPropertyStopOpacity: case CSSPropertyStrokeOpacity: case CSSPropertyStrokeMiterlimit: if (DoubleStyleInterpolation::canCreateFrom(*fromCSSValue) && DoubleStyleInterpolation::canCreateFrom(*toCSSValue)) return DoubleStyleInterpolation::create(*fromCSSValue, *toCSSValue, property, toCSSPrimitiveValue(fromCSSValue)->isNumber(), setRange(property)); break; case CSSPropertyMotionRotation: { RefPtrWillBeRawPtr<Interpolation> interpolation = DoubleStyleInterpolation::maybeCreateFromMotionRotation(*fromCSSValue, *toCSSValue, property); if (interpolation) return interpolation.release(); break; } case CSSPropertyVisibility: if (VisibilityStyleInterpolation::canCreateFrom(*fromCSSValue) && VisibilityStyleInterpolation::canCreateFrom(*toCSSValue) && (VisibilityStyleInterpolation::isVisible(*fromCSSValue) || VisibilityStyleInterpolation::isVisible(*toCSSValue))) return VisibilityStyleInterpolation::create(*fromCSSValue, *toCSSValue, property); break; case CSSPropertyBackgroundColor: case CSSPropertyBorderBottomColor: case CSSPropertyBorderLeftColor: case CSSPropertyBorderRightColor: case CSSPropertyBorderTopColor: case CSSPropertyColor: case CSSPropertyFill: case CSSPropertyFloodColor: case CSSPropertyLightingColor: case CSSPropertyOutlineColor: case CSSPropertyStopColor: case CSSPropertyStroke: case CSSPropertyTextDecorationColor: case CSSPropertyWebkitColumnRuleColor: case CSSPropertyWebkitTextStrokeColor: { RefPtrWillBeRawPtr<Interpolation> interpolation = ColorStyleInterpolation::maybeCreateFromColor(*fromCSSValue, *toCSSValue, property); if (interpolation) return interpolation.release(); // Current color should use LegacyStyleInterpolation if (ColorStyleInterpolation::shouldUseLegacyStyleInterpolation(*fromCSSValue, *toCSSValue)) return createLegacyStyleInterpolation(property, end, element, baseStyle); break; } case CSSPropertyBorderImageSource: case CSSPropertyListStyleImage: case CSSPropertyWebkitMaskBoxImageSource: if (fromCSSValue == toCSSValue) return ConstantStyleInterpolation::create(fromCSSValue, property); if (ImageStyleInterpolation::canCreateFrom(*fromCSSValue) && ImageStyleInterpolation::canCreateFrom(*toCSSValue)) return ImageStyleInterpolation::create(*fromCSSValue, *toCSSValue, property); forceDefaultInterpolation = true; break; case CSSPropertyBorderBottomLeftRadius: case CSSPropertyBorderBottomRightRadius: case CSSPropertyBorderTopLeftRadius: case CSSPropertyBorderTopRightRadius: range = RangeNonNegative; // Fall through case CSSPropertyObjectPosition: if (LengthPairStyleInterpolation::canCreateFrom(*fromCSSValue) && LengthPairStyleInterpolation::canCreateFrom(*toCSSValue)) return LengthPairStyleInterpolation::create(*fromCSSValue, *toCSSValue, property, range); break; case CSSPropertyPerspectiveOrigin: case CSSPropertyTransformOrigin: { RefPtrWillBeRawPtr<Interpolation> interpolation = ListStyleInterpolation<LengthStyleInterpolation>::maybeCreateFromList(*fromCSSValue, *toCSSValue, property, range); if (interpolation) return interpolation.release(); // FIXME: Handle keywords: top, right, left, center, bottom return createLegacyStyleInterpolation(property, end, element, baseStyle); } case CSSPropertyBoxShadow: case CSSPropertyTextShadow: { RefPtrWillBeRawPtr<Interpolation> interpolation = ListStyleInterpolation<ShadowStyleInterpolation>::maybeCreateFromList(*fromCSSValue, *toCSSValue, property); if (interpolation) return interpolation.release(); // FIXME: AnimatableShadow incorrectly animates between inset and non-inset values so it will never indicate it needs default interpolation if (ShadowStyleInterpolation::usesDefaultStyleInterpolation(*fromCSSValue, *toCSSValue)) { forceDefaultInterpolation = true; break; } // FIXME: Handle interpolation from/to none, unspecified color values return createLegacyStyleInterpolation(property, end, element, baseStyle); } case CSSPropertyClip: { if (LengthBoxStyleInterpolation::usesDefaultInterpolation(*fromCSSValue, *toCSSValue)) { forceDefaultInterpolation = true; break; } RefPtrWillBeRawPtr<Interpolation> interpolation = LengthBoxStyleInterpolation::maybeCreateFrom(*fromCSSValue, *toCSSValue, property); if (interpolation) return interpolation.release(); break; } case CSSPropertyBorderImageSlice: case CSSPropertyWebkitMaskBoxImageSlice: { RefPtrWillBeRawPtr<Interpolation> interpolation = ImageSliceStyleInterpolation::maybeCreate(*fromCSSValue, *toCSSValue, property); if (interpolation) return interpolation.release(); if (ImageSliceStyleInterpolation::usesDefaultInterpolation(*fromCSSValue, *toCSSValue)) forceDefaultInterpolation = true; break; } case CSSPropertyStrokeDasharray: { RefPtrWillBeRawPtr<Interpolation> interpolation = SVGStrokeDasharrayStyleInterpolation::maybeCreate(*fromCSSValue, *toCSSValue, property); if (interpolation) return interpolation.release(); break; } case CSSPropertyWebkitFilter: { RefPtrWillBeRawPtr<Interpolation> interpolation = FilterStyleInterpolation::maybeCreateList(*fromCSSValue, *toCSSValue, property); if (interpolation) return interpolation.release(); // FIXME: Support drop shadow interpolation. return createLegacyStyleInterpolation(property, end, element, baseStyle); break; } case CSSPropertyTranslate: { RefPtrWillBeRawPtr<Interpolation> interpolation = ListStyleInterpolation<LengthStyleInterpolation>::maybeCreateFromList(*fromCSSValue, *toCSSValue, property, range); if (interpolation) return interpolation.release(); // TODO(soonm): Legacy mode is used when from and to cssvaluelist length does not match. return createLegacyStyleInterpolation(property, end, element, baseStyle); break; } case CSSPropertyScale: { RefPtrWillBeRawPtr<Interpolation> interpolation = ListStyleInterpolation<DoubleStyleInterpolation>::maybeCreateFromList(*fromCSSValue, *toCSSValue, property, range); if (interpolation) return interpolation.release(); // TODO(soonm): Legacy mode is used when from and to cssvaluelist length does not match. return createLegacyStyleInterpolation(property, end, element, baseStyle); break; } default: // Fall back to LegacyStyleInterpolation. return createLegacyStyleInterpolation(property, end, element, baseStyle); break; } if (fromCSSValue == toCSSValue) return ConstantStyleInterpolation::create(fromCSSValue, property); if (!forceDefaultInterpolation) { ASSERT(AnimatableValue::usesDefaultInterpolation( StyleResolver::createAnimatableValueSnapshot(*element, baseStyle, property, fromCSSValue).get(), StyleResolver::createAnimatableValueSnapshot(*element, baseStyle, property, toCSSValue).get())); } return nullptr; }
PassOwnPtr<InterpolationValue> CSSValueInterpolationType::maybeConvertSingle(const PropertySpecificKeyframe& keyframe, const InterpolationEnvironment&, const UnderlyingValue&, ConversionCheckers&) const { if (keyframe.isNeutral()) return nullptr; return InterpolationValue::create(*this, InterpolableList::create(0), CSSValueNonInterpolableValue::create(toCSSPropertySpecificKeyframe(keyframe).value())); }
bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& timing, const Element& targetElement, const Animation* animationToAdd, const EffectModel& effect, double animationPlaybackRate) { const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(effect); PropertyHandleSet properties = keyframeEffect.properties(); if (properties.isEmpty()) return false; unsigned transformPropertyCount = 0; for (const auto& property : properties) { if (!property.isCSSProperty()) return false; if (isTransformRelatedCSSProperty(property)) { if (targetElement.layoutObject() && targetElement.layoutObject()->isInline()) { return false; } transformPropertyCount++; } const PropertySpecificKeyframeVector& keyframes = keyframeEffect.getPropertySpecificKeyframes(property); ASSERT(keyframes.size() >= 2); for (const auto& keyframe : keyframes) { // FIXME: Determine candidacy based on the CSSValue instead of a snapshot AnimatableValue. bool isNeutralKeyframe = keyframe->isCSSPropertySpecificKeyframe() && !toCSSPropertySpecificKeyframe(keyframe.get())->value() && keyframe->composite() == EffectModel::CompositeAdd; if ((keyframe->composite() != EffectModel::CompositeReplace && !isNeutralKeyframe) || !keyframe->getAnimatableValue()) return false; switch (property.cssProperty()) { case CSSPropertyOpacity: break; case CSSPropertyRotate: case CSSPropertyScale: case CSSPropertyTranslate: case CSSPropertyTransform: if (toAnimatableTransform(keyframe->getAnimatableValue().get())->transformOperations().dependsOnBoxSize()) return false; break; case CSSPropertyWebkitFilter: case CSSPropertyBackdropFilter: { const FilterOperations& operations = toAnimatableFilterOperations(keyframe->getAnimatableValue().get())->operations(); if (operations.hasFilterThatMovesPixels()) return false; break; } default: // any other types are not allowed to run on compositor. return false; } } } // TODO: Support multiple transform property animations on the compositor if (transformPropertyCount > 1) return false; if (animationToAdd && hasIncompatibleAnimations(targetElement, *animationToAdd, effect)) return false; CompositorAnimationsImpl::CompositorTiming out; if (!CompositorAnimationsImpl::convertTimingForCompositor(timing, 0, out, animationPlaybackRate)) return false; return true; }