summaryrefslogtreecommitdiff
path: root/Source/WebCore/page/animation/KeyframeAnimation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/page/animation/KeyframeAnimation.cpp')
-rw-r--r--Source/WebCore/page/animation/KeyframeAnimation.cpp342
1 files changed, 215 insertions, 127 deletions
diff --git a/Source/WebCore/page/animation/KeyframeAnimation.cpp b/Source/WebCore/page/animation/KeyframeAnimation.cpp
index 8f661c6c3..5294b0a31 100644
--- a/Source/WebCore/page/animation/KeyframeAnimation.cpp
+++ b/Source/WebCore/page/animation/KeyframeAnimation.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -29,33 +29,37 @@
#include "config.h"
#include "KeyframeAnimation.h"
-#include "AnimationControllerPrivate.h"
+#include "CSSAnimationControllerPrivate.h"
#include "CSSPropertyAnimation.h"
#include "CSSPropertyNames.h"
#include "CompositeAnimation.h"
#include "EventNames.h"
-#include "RenderBoxModelObject.h"
+#include "GeometryUtilities.h"
+#include "RenderBox.h"
#include "RenderStyle.h"
+#include "StylePendingResources.h"
#include "StyleResolver.h"
+#include "StyleScope.h"
+#include "TranslateTransformOperation.h"
+#include "WillChangeData.h"
namespace WebCore {
-KeyframeAnimation::KeyframeAnimation(const Animation& animation, RenderElement* renderer, int index, CompositeAnimation* compAnim, RenderStyle* unanimatedStyle)
- : AnimationBase(animation, renderer, compAnim)
+KeyframeAnimation::KeyframeAnimation(const Animation& animation, RenderElement* renderer, CompositeAnimation* compositeAnimation, const RenderStyle* unanimatedStyle)
+ : AnimationBase(animation, renderer, compositeAnimation)
, m_keyframes(animation.name())
- , m_index(index)
- , m_startEventDispatched(false)
- , m_unanimatedStyle(unanimatedStyle)
+ , m_unanimatedStyle(RenderStyle::clonePtr(*unanimatedStyle))
{
- // Get the keyframe RenderStyles
- if (m_object && m_object->element())
- m_object->document().ensureStyleResolver().keyframeStylesForAnimation(m_object->element(), unanimatedStyle, m_keyframes);
+ resolveKeyframeStyles();
// Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
validateTransformFunctionList();
-#if ENABLE(CSS_FILTERS)
checkForMatchingFilterFunctionLists();
+#if ENABLE(FILTERS_LEVEL_2)
+ checkForMatchingBackdropFilterFunctionLists();
#endif
+ computeStackingContextImpact();
+ computeLayoutDependency();
}
KeyframeAnimation::~KeyframeAnimation()
@@ -65,38 +69,60 @@ KeyframeAnimation::~KeyframeAnimation()
endAnimation();
}
-static const Animation* getAnimationFromStyleByName(const RenderStyle* style, const AtomicString& name)
+void KeyframeAnimation::computeStackingContextImpact()
{
- if (!style->animations())
- return 0;
-
- for (size_t i = 0; i < style->animations()->size(); i++) {
- if (name == style->animations()->animation(i).name())
- return &style->animations()->animation(i);
+ for (auto propertyID : m_keyframes.properties()) {
+ if (WillChangeData::propertyCreatesStackingContext(propertyID)) {
+ m_triggersStackingContext = true;
+ break;
+ }
}
+}
+
+void KeyframeAnimation::computeLayoutDependency()
+{
+ if (!m_keyframes.containsProperty(CSSPropertyTransform))
+ return;
- return 0;
+ size_t numKeyframes = m_keyframes.size();
+ for (size_t i = 0; i < numKeyframes; i++) {
+ auto* keyframeStyle = m_keyframes[i].style();
+ if (!keyframeStyle) {
+ ASSERT_NOT_REACHED();
+ continue;
+ }
+ if (keyframeStyle->hasTransform()) {
+ auto& transformOperations = keyframeStyle->transform();
+ for (auto operation : transformOperations.operations()) {
+ if (operation->isTranslateTransformOperationType()) {
+ auto translation = downcast<TranslateTransformOperation>(operation.get());
+ if (translation->x().isPercent() || translation->y().isPercent()) {
+ m_dependsOnLayout = true;
+ return;
+ }
+ }
+ }
+ }
+ }
}
void KeyframeAnimation::fetchIntervalEndpointsForProperty(CSSPropertyID property, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const
{
+ size_t numKeyframes = m_keyframes.size();
+ if (!numKeyframes)
+ return;
+
// Find the first key
double elapsedTime = getElapsedTime();
if (m_animation->duration() && m_animation->iterationCount() != Animation::IterationCountInfinite)
elapsedTime = std::min(elapsedTime, m_animation->duration() * m_animation->iterationCount());
const double fractionalTime = this->fractionalTime(1, elapsedTime, 0);
-
- size_t numKeyframes = m_keyframes.size();
- if (!numKeyframes)
- return;
-
ASSERT(!m_keyframes[0].key());
ASSERT(m_keyframes[m_keyframes.size() - 1].key() == 1);
-
+
int prevIndex = -1;
int nextIndex = -1;
-
// FIXME: with a lot of keys, this linear search will be slow. We could binary search.
for (size_t i = 0; i < numKeyframes; ++i) {
const KeyframeValue& currKeyFrame = m_keyframes[i];
@@ -108,16 +134,11 @@ void KeyframeAnimation::fetchIntervalEndpointsForProperty(CSSPropertyID property
nextIndex = i;
break;
}
-
prevIndex = i;
}
- double scale = 1;
- double offset = 0;
-
if (prevIndex == -1)
prevIndex = 0;
-
if (nextIndex == -1)
nextIndex = m_keyframes.size() - 1;
@@ -126,32 +147,32 @@ void KeyframeAnimation::fetchIntervalEndpointsForProperty(CSSPropertyID property
fromStyle = prevKeyframe.style();
toStyle = nextKeyframe.style();
-
- offset = prevKeyframe.key();
- scale = 1.0 / (nextKeyframe.key() - prevKeyframe.key());
- const TimingFunction* timingFunction = 0;
- if (const Animation* matchedAnimation = getAnimationFromStyleByName(fromStyle, name()))
- timingFunction = matchedAnimation->timingFunction().get();
+ double offset = prevKeyframe.key();
+ double scale = 1.0 / (nextIndex == prevIndex ? 1 : (nextKeyframe.key() - prevKeyframe.key()));
- prog = progress(scale, offset, timingFunction);
+ prog = progress(scale, offset, prevKeyframe.timingFunction(name()));
}
-void KeyframeAnimation::animate(CompositeAnimation* compositeAnimation, RenderElement*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
+bool KeyframeAnimation::animate(CompositeAnimation* compositeAnimation, RenderElement*, const RenderStyle*, const RenderStyle* targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle)
{
// Fire the start timeout if needed
fireAnimationEventsIfNeeded();
// If we have not yet started, we will not have a valid start time, so just start the animation if needed.
- if (isNew() && m_animation->playState() == AnimPlayStatePlaying && !compositeAnimation->isSuspended())
- updateStateMachine(AnimationStateInputStartAnimation, -1);
+ if (isNew()) {
+ if (m_animation->playState() == AnimPlayStatePlaying && !compositeAnimation->isSuspended())
+ updateStateMachine(AnimationStateInput::StartAnimation, -1);
+ else if (m_animation->playState() == AnimPlayStatePaused)
+ updateStateMachine(AnimationStateInput::PlayStatePaused, -1);
+ }
// If we get this far and the animation is done, it means we are cleaning up a just finished animation.
// If so, we need to send back the targetStyle.
if (postActive()) {
if (!animatedStyle)
- animatedStyle = const_cast<RenderStyle*>(targetStyle);
- return;
+ animatedStyle = RenderStyle::clonePtr(*targetStyle);
+ return false;
}
// If we are waiting for the start timer, we don't want to change the style yet.
@@ -160,65 +181,95 @@ void KeyframeAnimation::animate(CompositeAnimation* compositeAnimation, RenderEl
// Special case 2 - if there is a backwards fill mode, then we want to continue
// through to the style blend so that we get the fromStyle.
if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
- return;
+ return false;
// If we have no keyframes, don't animate.
if (!m_keyframes.size()) {
- updateStateMachine(AnimationStateInputEndAnimation, -1);
- return;
+ updateStateMachine(AnimationStateInput::EndAnimation, -1);
+ return false;
}
+ // FIXME: the code below never changes the state, so this function always returns false.
+ AnimationState oldState = state();
+
// Run a cycle of animation.
// We know we will need a new render style, so make one if needed.
if (!animatedStyle)
- animatedStyle = RenderStyle::clone(targetStyle);
+ animatedStyle = RenderStyle::clonePtr(*targetStyle);
// FIXME: we need to be more efficient about determining which keyframes we are animating between.
// We should cache the last pair or something.
- HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties();
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
+ for (auto propertyID : m_keyframes.properties()) {
// Get the from/to styles and progress between
- const RenderStyle* fromStyle = 0;
- const RenderStyle* toStyle = 0;
- double progress = 0.0;
- fetchIntervalEndpointsForProperty(*it, fromStyle, toStyle, progress);
-
-#if USE(ACCELERATED_COMPOSITING)
- bool needsAnim = CSSPropertyAnimation::blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress);
- if (!needsAnim)
- // If we are running an accelerated animation, set a flag in the style
- // to indicate it. This can be used to make sure we get an updated
- // style for hit testing, etc.
- animatedStyle->setIsRunningAcceleratedAnimation();
-#endif
+ const RenderStyle* fromStyle = nullptr;
+ const RenderStyle* toStyle = nullptr;
+ double progress = 0;
+ fetchIntervalEndpointsForProperty(propertyID, fromStyle, toStyle, progress);
+
+ CSSPropertyAnimation::blendProperties(this, propertyID, animatedStyle.get(), fromStyle, toStyle, progress);
}
+
+ didBlendStyle = true;
+ return state() != oldState;
}
-void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle)
+void KeyframeAnimation::getAnimatedStyle(std::unique_ptr<RenderStyle>& animatedStyle)
{
- // If we're in the delay phase and we're not backwards filling, tell the caller
- // to use the current style.
- if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
+ // If we're done, or in the delay phase and we're not backwards filling, tell the caller to use the current style.
+ if (postActive() || (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards()))
return;
if (!m_keyframes.size())
return;
if (!animatedStyle)
- animatedStyle = RenderStyle::clone(&m_object->style());
+ animatedStyle = RenderStyle::clonePtr(m_object->style());
- HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties();
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
+ for (auto propertyID : m_keyframes.properties()) {
// Get the from/to styles and progress between
- const RenderStyle* fromStyle = 0;
- const RenderStyle* toStyle = 0;
- double progress = 0.0;
- fetchIntervalEndpointsForProperty(*it, fromStyle, toStyle, progress);
+ const RenderStyle* fromStyle = nullptr;
+ const RenderStyle* toStyle = nullptr;
+ double progress = 0;
+ fetchIntervalEndpointsForProperty(propertyID, fromStyle, toStyle, progress);
- CSSPropertyAnimation::blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress);
+ CSSPropertyAnimation::blendProperties(this, propertyID, animatedStyle.get(), fromStyle, toStyle, progress);
}
}
+bool KeyframeAnimation::computeExtentOfTransformAnimation(LayoutRect& bounds) const
+{
+ ASSERT(m_keyframes.containsProperty(CSSPropertyTransform));
+
+ if (!is<RenderBox>(m_object))
+ return true; // Non-boxes don't get transformed;
+
+ RenderBox& box = downcast<RenderBox>(*m_object);
+ FloatRect rendererBox = snapRectToDevicePixels(box.borderBoxRect(), box.document().deviceScaleFactor());
+
+ FloatRect cumulativeBounds = bounds;
+
+ for (auto& keyframe : m_keyframes.keyframes()) {
+ if (!keyframe.containsProperty(CSSPropertyTransform))
+ continue;
+
+ LayoutRect keyframeBounds = bounds;
+
+ bool canCompute;
+ if (transformFunctionListsMatch())
+ canCompute = computeTransformedExtentViaTransformList(rendererBox, *keyframe.style(), keyframeBounds);
+ else
+ canCompute = computeTransformedExtentViaMatrix(rendererBox, *keyframe.style(), keyframeBounds);
+
+ if (!canCompute)
+ return false;
+
+ cumulativeBounds.unite(keyframeBounds);
+ }
+
+ bounds = LayoutRect(cumulativeBounds);
+ return true;
+}
+
bool KeyframeAnimation::hasAnimationForProperty(CSSPropertyID property) const
{
return m_keyframes.containsProperty(property);
@@ -226,13 +277,8 @@ bool KeyframeAnimation::hasAnimationForProperty(CSSPropertyID property) const
bool KeyframeAnimation::startAnimation(double timeOffset)
{
-#if USE(ACCELERATED_COMPOSITING)
- if (m_object && m_object->isComposited()) {
- return toRenderBoxModelObject(m_object)->startAnimation(timeOffset, m_animation.get(), m_keyframes);
- }
-#else
- UNUSED_PARAM(timeOffset);
-#endif
+ if (m_object && m_object->isComposited())
+ return downcast<RenderBoxModelObject>(*m_object).startAnimation(timeOffset, m_animation.ptr(), m_keyframes);
return false;
}
@@ -241,12 +287,9 @@ void KeyframeAnimation::pauseAnimation(double timeOffset)
if (!m_object)
return;
-#if USE(ACCELERATED_COMPOSITING)
if (m_object->isComposited())
- toRenderBoxModelObject(m_object)->animationPaused(timeOffset, m_keyframes.animationName());
-#else
- UNUSED_PARAM(timeOffset);
-#endif
+ downcast<RenderBoxModelObject>(*m_object).animationPaused(timeOffset, m_keyframes.animationName());
+
// Restore the original (unanimated) style
if (!paused())
setNeedsStyleRecalc(m_object->element());
@@ -257,10 +300,9 @@ void KeyframeAnimation::endAnimation()
if (!m_object)
return;
-#if USE(ACCELERATED_COMPOSITING)
if (m_object->isComposited())
- toRenderBoxModelObject(m_object)->animationFinished(m_keyframes.animationName());
-#endif
+ downcast<RenderBoxModelObject>(*m_object).animationFinished(m_keyframes.animationName());
+
// Restore the original (unanimated) style
if (!paused())
setNeedsStyleRecalc(m_object->element());
@@ -273,17 +315,17 @@ bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listen
void KeyframeAnimation::onAnimationStart(double elapsedTime)
{
- sendAnimationEvent(eventNames().webkitAnimationStartEvent, elapsedTime);
+ sendAnimationEvent(eventNames().animationstartEvent, elapsedTime);
}
void KeyframeAnimation::onAnimationIteration(double elapsedTime)
{
- sendAnimationEvent(eventNames().webkitAnimationIterationEvent, elapsedTime);
+ sendAnimationEvent(eventNames().animationiterationEvent, elapsedTime);
}
void KeyframeAnimation::onAnimationEnd(double elapsedTime)
{
- sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime);
+ sendAnimationEvent(eventNames().animationendEvent, elapsedTime);
// End the animation if we don't fill forwards. Forward filling
// animations are ended properly in the class destructor.
if (!m_animation->fillsForwards())
@@ -293,12 +335,12 @@ void KeyframeAnimation::onAnimationEnd(double elapsedTime)
bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime)
{
Document::ListenerType listenerType;
- if (eventType == eventNames().webkitAnimationIterationEvent)
+ if (eventType == eventNames().webkitAnimationIterationEvent || eventType == eventNames().animationiterationEvent)
listenerType = Document::ANIMATIONITERATION_LISTENER;
- else if (eventType == eventNames().webkitAnimationEndEvent)
+ else if (eventType == eventNames().webkitAnimationEndEvent || eventType == eventNames().animationendEvent)
listenerType = Document::ANIMATIONEND_LISTENER;
else {
- ASSERT(eventType == eventNames().webkitAnimationStartEvent);
+ ASSERT(eventType == eventNames().webkitAnimationStartEvent || eventType == eventNames().animationstartEvent);
if (m_startEventDispatched)
return false;
m_startEventDispatched = true;
@@ -309,15 +351,15 @@ bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double
// Dispatch the event
RefPtr<Element> element = m_object->element();
- ASSERT(!element || !element->document().inPageCache());
+ ASSERT(!element || element->document().pageCacheState() == Document::NotInPageCache);
if (!element)
return false;
// Schedule event handling
- m_compAnim->animationController()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime);
+ m_compositeAnimation->animationController().addEventToDispatch(*element, eventType, m_keyframes.animationName(), elapsedTime);
// Restore the original (unanimated) style
- if (eventType == eventNames().webkitAnimationEndEvent && element->renderer())
+ if ((eventType == eventNames().webkitAnimationEndEvent || eventType == eventNames().animationendEvent) && element->renderer())
setNeedsStyleRecalc(element.get());
return true; // Did dispatch an event
@@ -329,17 +371,15 @@ bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double
void KeyframeAnimation::overrideAnimations()
{
// This will override implicit animations that match the properties in the keyframe animation
- HashSet<CSSPropertyID>::const_iterator end = m_keyframes.endProperties();
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
- compositeAnimation()->overrideImplicitAnimations(*it);
+ for (auto propertyID : m_keyframes.properties())
+ compositeAnimation()->overrideImplicitAnimations(propertyID);
}
void KeyframeAnimation::resumeOverriddenAnimations()
{
// This will resume overridden implicit animations
- HashSet<CSSPropertyID>::const_iterator end = m_keyframes.endProperties();
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
- compositeAnimation()->resumeOverriddenImplicitAnimations(*it);
+ for (auto propertyID : m_keyframes.properties())
+ compositeAnimation()->resumeOverriddenImplicitAnimations(propertyID);
}
bool KeyframeAnimation::affectsProperty(CSSPropertyID property) const
@@ -347,11 +387,27 @@ bool KeyframeAnimation::affectsProperty(CSSPropertyID property) const
return m_keyframes.containsProperty(property);
}
+void KeyframeAnimation::resolveKeyframeStyles()
+{
+ if (!m_object || !m_object->element())
+ return;
+ auto& element = *m_object->element();
+
+ if (auto* styleScope = Style::Scope::forOrdinal(element, m_animation->nameStyleScopeOrdinal()))
+ styleScope->resolver().keyframeStylesForAnimation(*m_object->element(), m_unanimatedStyle.get(), m_keyframes);
+
+ // Ensure resource loads for all the frames.
+ for (auto& keyframe : m_keyframes.keyframes()) {
+ if (auto* style = const_cast<RenderStyle*>(keyframe.style()))
+ Style::loadPendingResources(*style, element.document(), &element);
+ }
+}
+
void KeyframeAnimation::validateTransformFunctionList()
{
- m_transformFunctionListValid = false;
+ m_transformFunctionListsMatch = false;
- if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform))
+ if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyTransform))
return;
// Empty transforms match anything, so find the first non-empty entry as the reference
@@ -384,16 +440,14 @@ void KeyframeAnimation::validateTransformFunctionList()
return;
}
- // Keyframes are valid
- m_transformFunctionListValid = true;
+ m_transformFunctionListsMatch = true;
}
-#if ENABLE(CSS_FILTERS)
void KeyframeAnimation::checkForMatchingFilterFunctionLists()
{
m_filterFunctionListsMatch = false;
- if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitFilter))
+ if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyFilter))
return;
// Empty filters match anything, so find the first non-empty entry as the reference
@@ -401,8 +455,7 @@ void KeyframeAnimation::checkForMatchingFilterFunctionLists()
size_t firstNonEmptyFilterKeyframeIndex = numKeyframes;
for (size_t i = 0; i < numKeyframes; ++i) {
- const KeyframeValue& currentKeyframe = m_keyframes[i];
- if (currentKeyframe.style()->filter().operations().size()) {
+ if (m_keyframes[i].style()->filter().operations().size()) {
firstNonEmptyFilterKeyframeIndex = i;
break;
}
@@ -410,39 +463,74 @@ void KeyframeAnimation::checkForMatchingFilterFunctionLists()
if (firstNonEmptyFilterKeyframeIndex == numKeyframes)
return;
-
- const FilterOperations* firstVal = &m_keyframes[firstNonEmptyFilterKeyframeIndex].style()->filter();
+
+ auto& firstVal = m_keyframes[firstNonEmptyFilterKeyframeIndex].style()->filter();
for (size_t i = firstNonEmptyFilterKeyframeIndex + 1; i < numKeyframes; ++i) {
- const KeyframeValue& currentKeyframe = m_keyframes[i];
- const FilterOperations* val = &currentKeyframe.style()->filter();
-
+ auto& value = m_keyframes[i].style()->filter();
+
// An emtpy filter list matches anything.
- if (val->operations().isEmpty())
+ if (value.operations().isEmpty())
continue;
-
- if (!firstVal->operationsMatch(*val))
+
+ if (!firstVal.operationsMatch(value))
return;
}
-
+
m_filterFunctionListsMatch = true;
}
+
+#if ENABLE(FILTERS_LEVEL_2)
+void KeyframeAnimation::checkForMatchingBackdropFilterFunctionLists()
+{
+ m_backdropFilterFunctionListsMatch = false;
+
+ if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitBackdropFilter))
+ return;
+
+ // Empty filters match anything, so find the first non-empty entry as the reference
+ size_t numKeyframes = m_keyframes.size();
+ size_t firstNonEmptyFilterKeyframeIndex = numKeyframes;
+
+ for (size_t i = 0; i < numKeyframes; ++i) {
+ if (m_keyframes[i].style()->backdropFilter().operations().size()) {
+ firstNonEmptyFilterKeyframeIndex = i;
+ break;
+ }
+ }
+
+ if (firstNonEmptyFilterKeyframeIndex == numKeyframes)
+ return;
+
+ auto& firstVal = m_keyframes[firstNonEmptyFilterKeyframeIndex].style()->backdropFilter();
+
+ for (size_t i = firstNonEmptyFilterKeyframeIndex + 1; i < numKeyframes; ++i) {
+ auto& value = m_keyframes[i].style()->backdropFilter();
+
+ // An emtpy filter list matches anything.
+ if (value.operations().isEmpty())
+ continue;
+
+ if (!firstVal.operationsMatch(value))
+ return;
+ }
+
+ m_backdropFilterFunctionListsMatch = true;
+}
#endif
double KeyframeAnimation::timeToNextService()
{
double t = AnimationBase::timeToNextService();
-#if USE(ACCELERATED_COMPOSITING)
if (t != 0 || preActive())
return t;
// A return value of 0 means we need service. But if we only have accelerated animations we
// only need service at the end of the transition
- HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties();
bool acceleratedPropertiesOnly = true;
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
- if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(*it) || !isAccelerated()) {
+ for (auto propertyID : m_keyframes.properties()) {
+ if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(propertyID) || !isAccelerated()) {
acceleratedPropertiesOnly = false;
break;
}
@@ -452,7 +540,7 @@ double KeyframeAnimation::timeToNextService()
bool isLooping;
getTimeToNextEvent(t, isLooping);
}
-#endif
+
return t;
}