Changeset 261637 in webkit
- Timestamp:
- May 13, 2020 12:26:58 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r261632 r261637 1 2020-05-13 Antoine Quint <graouts@apple.com> 2 3 [Web Animations] Calling reverse() on an accelerated animation has no effect 4 https://bugs.webkit.org/show_bug.cgi?id=204717 5 <rdar://problem/62503582> 6 7 Reviewed by Dean Jackson. 8 9 Add a test where we play an animation for an accelerated property in reverse. 10 11 * webanimations/accelerated-animation-playback-rate-expected.html: Added. 12 * webanimations/accelerated-animation-playback-rate.html: Added. 13 1 14 2020-05-13 Simon Fraser <simon.fraser@apple.com> 2 15 -
trunk/Source/WebCore/ChangeLog
r261636 r261637 1 2020-05-13 Antoine Quint <graouts@apple.com> 2 3 [Web Animations] Calling reverse() on an accelerated animation has no effect 4 https://bugs.webkit.org/show_bug.cgi?id=204717 5 <rdar://problem/62503582> 6 7 Reviewed by Dean Jackson. 8 9 Test: webanimations/accelerated-animation-playback-rate.html 10 11 We completely ignored the playbackRate set on a WebAnimation object when considering whether we could run an accelerated animation. 12 To address this we do several things. 13 14 First, we now add a playbackRate() on Animation objects such that we can make GraphicsLayerCA aware of the originating WebAnimation's 15 playback rate and use this data to opt out of running CA animations for animations with a playbackRate other than 1 in 16 GraphicsLayerCA::animationCanBeAccelerated(). We'll be looking to add support for variable playback rates for CA animations in 17 https://bugs.webkit.org/show_bug.cgi?id=211839. 18 19 Then, we make sure to completely replace an accelerated animation whenever one of the properties affected timing would change. Up until 20 now we would onyl do this for a change in the effective currentTime, but this needs to also happen when the current time doesn't change 21 but the animation may have changed playback rate or any of its timing properties that could change the duration of the animation. So we 22 remove the "Seek" command and instead use an "UpdateTiming" command that will remove the existing animation and add a new one. 23 24 This allows us to remove any notion of seeking in GraphicsLayer since now we'll just create a new animation when its timing attributes 25 changed. 26 27 This revealed an issue where if we called animationFinished() and startAnimation() on a RenderLayerModelObject in succession, theanimation 28 removal would not occur on the GraphicsLayerCA because we disregarded any pending accelerated action for an animation we knew would be 29 replaced. We now ensure we honor the removal in GraphicsLayerCA::appendToUncommittedAnimations(). 30 31 * animation/AnimationEffect.cpp: 32 (WebCore::AnimationEffect::updateTiming): 33 * animation/AnimationEffect.h: 34 * animation/CSSAnimation.cpp: 35 (WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): 36 * animation/KeyframeEffect.cpp: 37 (WebCore::KeyframeEffect::addPendingAcceleratedAction): 38 (WebCore::KeyframeEffect::animationDidChangeTimingProperties): 39 (WebCore::KeyframeEffect::applyPendingAcceleratedActions): 40 (WebCore::KeyframeEffect::backingAnimationForCompositedRenderer const): 41 (WebCore::KeyframeEffect::animationDidSeek): Deleted. 42 * animation/KeyframeEffect.h: 43 * animation/WebAnimation.cpp: 44 (WebCore::WebAnimation::effectTimingDidChange): 45 (WebCore::WebAnimation::setCurrentTime): 46 (WebCore::WebAnimation::setPlaybackRate): 47 (WebCore::WebAnimation::updatePlaybackRate): 48 (WebCore::WebAnimation::reverse): 49 * animation/WebAnimation.h: 50 * platform/animation/Animation.h: 51 (WebCore::Animation::playbackRate const): 52 (WebCore::Animation::setPlaybackRate): 53 * platform/graphics/GraphicsLayer.h: 54 (WebCore::GraphicsLayer::pauseAnimation): 55 (WebCore::GraphicsLayer::seekAnimation): Deleted. 56 * platform/graphics/ca/GraphicsLayerCA.cpp: 57 (WebCore::GraphicsLayerCA::animationCanBeAccelerated const): 58 (WebCore::GraphicsLayerCA::updateAnimations): 59 (WebCore::GraphicsLayerCA::pauseCAAnimationOnLayer): 60 (WebCore::GraphicsLayerCA::createTransformAnimationsFromKeyframes): 61 (WebCore::GraphicsLayerCA::seekAnimation): Deleted. 62 (WebCore::GraphicsLayerCA::seekCAAnimationOnLayer): Deleted. 63 * platform/graphics/ca/GraphicsLayerCA.h: 64 * rendering/RenderElement.h: 65 (WebCore::RenderElement::animationPaused): 66 (WebCore::RenderElement::animationSeeked): Deleted. 67 * rendering/RenderLayerBacking.cpp: 68 (WebCore::RenderLayerBacking::animationSeeked): Deleted. 69 * rendering/RenderLayerBacking.h: 70 * rendering/RenderLayerModelObject.cpp: 71 (WebCore::RenderLayerModelObject::animationSeeked): Deleted. 72 * rendering/RenderLayerModelObject.h: 73 1 74 2020-05-13 Antti Koivisto <antti@apple.com> 2 75 -
trunk/Source/WebCore/animation/AnimationEffect.cpp
r260671 r261637 370 370 return { }; 371 371 372 Optional<ComputedEffectTiming> previousTiming;373 if (m_animation)374 previousTiming = getComputedTiming();375 376 372 // 1. If the iterationStart member of input is present and less than zero, throw a TypeError and abort this procedure. 377 373 if (timing->iterationStart) { … … 442 438 443 439 if (m_animation) 444 m_animation->effectTimingDidChange( previousTiming);440 m_animation->effectTimingDidChange(); 445 441 446 442 return { }; -
trunk/Source/WebCore/animation/AnimationEffect.h
r260671 r261637 66 66 virtual void animationDidTick() = 0; 67 67 virtual void animationDidPlay() = 0; 68 virtual void animationDid Seek() = 0;68 virtual void animationDidChangeTimingProperties() = 0; 69 69 virtual void animationWasCanceled() = 0; 70 70 virtual void animationSuspensionStateDidChange(bool) = 0; -
trunk/Source/WebCore/animation/CSSAnimation.cpp
r260671 r261637 66 66 auto* animationEffect = effect(); 67 67 68 auto previousTiming = animationEffect->getComputedTiming();69 70 68 if (!m_overriddenProperties.contains(Property::FillMode)) { 71 69 switch (animation.fillMode()) { … … 114 112 115 113 animationEffect->updateStaticTimingProperties(); 116 effectTimingDidChange( previousTiming);114 effectTimingDidChange(); 117 115 118 116 // Synchronize the play state -
trunk/Source/WebCore/animation/KeyframeEffect.cpp
r261585 r261637 1509 1509 m_pendingAcceleratedActions.clear(); 1510 1510 m_pendingAcceleratedActions.append(action); 1511 if (action != AcceleratedAction:: Seek)1511 if (action != AcceleratedAction::UpdateTiming) 1512 1512 m_lastRecordedAcceleratedAction = action; 1513 1513 animation()->acceleratedStateDidChange(); … … 1526 1526 } 1527 1527 1528 void KeyframeEffect::animationDid Seek()1529 { 1530 // There is no need to seek if we're not playing an animation already. If seeking1528 void KeyframeEffect::animationDidChangeTimingProperties() 1529 { 1530 // There is no need to update the animation if we're not playing already. If updating timing 1531 1531 // means we're moving into an active lexicalGlobalObject, we'll pick this up in apply(). 1532 1532 if (m_isRunningAccelerated || isAboutToRunAccelerated()) 1533 addPendingAcceleratedAction(AcceleratedAction:: Seek);1533 addPendingAcceleratedAction(AcceleratedAction::UpdateTiming); 1534 1534 } 1535 1535 … … 1582 1582 switch (action) { 1583 1583 case AcceleratedAction::Play: 1584 renderer->animationFinished(m_blendingKeyframes.animationName()); 1584 1585 m_isRunningAccelerated = renderer->startAnimation(timeOffset, backingAnimationForCompositedRenderer(), m_blendingKeyframes); 1585 1586 if (!m_isRunningAccelerated) { … … 1591 1592 renderer->animationPaused(timeOffset, m_blendingKeyframes.animationName()); 1592 1593 break; 1593 case AcceleratedAction::Seek: 1594 renderer->animationSeeked(timeOffset, m_blendingKeyframes.animationName()); 1594 case AcceleratedAction::UpdateTiming: 1595 renderer->animationFinished(m_blendingKeyframes.animationName()); 1596 renderer->startAnimation(timeOffset, backingAnimationForCompositedRenderer(), m_blendingKeyframes); 1597 if (animation()->playState() == WebAnimation::PlayState::Paused) 1598 renderer->animationPaused(timeOffset, m_blendingKeyframes.animationName()); 1595 1599 break; 1596 1600 case AcceleratedAction::Stop: … … 1618 1622 animation->setIterationCount(iterations()); 1619 1623 animation->setTimingFunction(timingFunction()->clone()); 1624 animation->setPlaybackRate(effectAnimation->playbackRate()); 1620 1625 1621 1626 switch (fill()) { -
trunk/Source/WebCore/animation/KeyframeEffect.h
r260705 r261637 125 125 void animationDidTick() final; 126 126 void animationDidPlay() final; 127 void animationDid Seek() final;127 void animationDidChangeTimingProperties() final; 128 128 void animationWasCanceled() final; 129 129 void animationSuspensionStateDidChange(bool) final; … … 170 170 KeyframeEffect(Element*, PseudoId); 171 171 172 enum class AcceleratedAction : uint8_t { Play, Pause, Seek, Stop };172 enum class AcceleratedAction : uint8_t { Play, Pause, UpdateTiming, Stop }; 173 173 enum class BlendingKeyframesSource : uint8_t { CSSAnimation, CSSTransition, WebAnimation }; 174 174 enum class AcceleratedProperties : uint8_t { None, Some, All }; -
trunk/Source/WebCore/animation/WebAnimation.cpp
r261470 r261637 135 135 } 136 136 137 void WebAnimation::effectTimingDidChange( Optional<ComputedEffectTiming> previousTiming)137 void WebAnimation::effectTimingDidChange() 138 138 { 139 139 timingDidChange(DidSeek::No, SynchronouslyNotify::Yes); 140 140 141 if (previousTiming) { 142 auto* effect = this->effect(); 143 ASSERT(effect); 144 if (previousTiming->progress != effect->getComputedTiming().progress) 145 effect->animationDidSeek(); 146 } 141 if (m_effect) 142 m_effect->animationDidChangeTimingProperties(); 147 143 148 144 InspectorInstrumentation::didChangeWebAnimationEffectTiming(*this); … … 478 474 479 475 if (m_effect) 480 m_effect->animationDid Seek();476 m_effect->animationDidChangeTimingProperties(); 481 477 482 478 invalidateEffect(); … … 509 505 if (previousTime) 510 506 setCurrentTime(previousTime); 507 508 if (m_effect) 509 m_effect->animationDidChangeTimingProperties(); 511 510 } 512 511 … … 561 560 play(AutoRewind::No); 562 561 } 562 563 if (m_effect) 564 m_effect->animationDidChangeTimingProperties(); 563 565 } 564 566 … … 1153 1155 } 1154 1156 1157 if (m_effect) 1158 m_effect->animationDidChangeTimingProperties(); 1159 1155 1160 return { }; 1156 1161 } -
trunk/Source/WebCore/animation/WebAnimation.h
r260671 r261637 27 27 28 28 #include "ActiveDOMObject.h" 29 #include "ComputedEffectTiming.h"30 29 #include "EventTarget.h" 31 30 #include "ExceptionOr.h" … … 133 132 bool isRelevant() const { return m_isRelevant; } 134 133 void updateRelevance(); 135 void effectTimingDidChange( Optional<ComputedEffectTiming> = WTF::nullopt);134 void effectTimingDidChange(); 136 135 void suspendEffectInvalidation(); 137 136 void unsuspendEffectInvalidation(); -
trunk/Source/WebCore/platform/animation/Animation.h
r259720 r261637 118 118 119 119 double duration() const { return m_duration; } 120 double playbackRate() const { return m_playbackRate; } 120 121 121 122 enum { IterationCountInfinite = -1 }; … … 131 132 void setDirection(AnimationDirection d) { m_direction = d; m_directionSet = true; } 132 133 void setDuration(double d) { ASSERT(d >= 0); m_duration = d; m_durationSet = true; } 134 void setPlaybackRate(double d) { m_playbackRate = d; } 133 135 void setFillMode(AnimationFillMode f) { m_fillMode = static_cast<unsigned>(f); m_fillModeSet = true; } 134 136 void setIterationCount(double c) { m_iterationCount = c; m_iterationCountSet = true; } … … 170 172 double m_delay; 171 173 double m_duration; 174 double m_playbackRate { 1 }; 172 175 RefPtr<TimingFunction> m_timingFunction; 173 176 -
trunk/Source/WebCore/platform/graphics/GraphicsLayer.h
r260950 r261637 479 479 virtual bool addAnimation(const KeyframeValueList&, const FloatSize& /*boxSize*/, const Animation*, const String& /*animationName*/, double /*timeOffset*/) { return false; } 480 480 virtual void pauseAnimation(const String& /*animationName*/, double /*timeOffset*/) { } 481 virtual void seekAnimation(const String& /*animationName*/, double /*timeOffset*/) { }482 481 virtual void removeAnimation(const String& /*animationName*/) { } 483 482 -
trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp
r260950 r261637 1030 1030 bool GraphicsLayerCA::animationCanBeAccelerated(const KeyframeValueList& valueList, const Animation* anim) const 1031 1031 { 1032 if (anim->playbackRate() != 1) 1033 return false; 1034 1032 1035 if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2) 1033 1036 return false; … … 1090 1093 // Call add since if there is already a Remove in there, we don't want to overwrite it with a Pause. 1091 1094 addProcessingActionForAnimation(animationName, AnimationProcessingAction { Pause, Seconds { timeOffset } }); 1092 1093 noteLayerPropertyChanged(AnimationChanged);1094 }1095 1096 void GraphicsLayerCA::seekAnimation(const String& animationName, double timeOffset)1097 {1098 LOG_WITH_STREAM(Animations, stream << "GraphicsLayerCA " << this << " id " << primaryLayerID() << " seekAnimation " << animationName << " to " << timeOffset << " (is running " << animationIsRunning(animationName) << ")");1099 1100 // Call add since if there is already a Remove in there, we don't want to overwrite it with a Pause.1101 addProcessingActionForAnimation(animationName, AnimationProcessingAction { Seek, Seconds { timeOffset } });1102 1095 1103 1096 noteLayerPropertyChanged(AnimationChanged); … … 2922 2915 pauseCAAnimationOnLayer(currentAnimation.m_property, currentAnimationName, currentAnimation.m_index, currentAnimation.m_subIndex, processingInfo.timeOffset); 2923 2916 break; 2924 case Seek:2925 seekCAAnimationOnLayer(currentAnimation.m_property, currentAnimationName, currentAnimation.m_index, currentAnimation.m_subIndex, processingInfo.timeOffset);2926 break;2927 2917 } 2928 2918 } … … 3036 3026 3037 3027 newAnim->setSpeed(0); 3038 newAnim->setTimeOffset(timeOffset.seconds());3039 3040 layer->addAnimationForKey(animationID, *newAnim); // This will replace the running animation.3041 3042 // Pause the animations on the clones too.3043 if (LayerMap* layerCloneMap = animatedLayerClones(property)) {3044 for (auto& clone : *layerCloneMap) {3045 // Skip immediate replicas, since they move with the original.3046 if (m_replicaLayer && isReplicatedRootClone(clone.key))3047 continue;3048 clone.value->addAnimationForKey(animationID, *newAnim);3049 }3050 }3051 }3052 3053 void GraphicsLayerCA::seekCAAnimationOnLayer(AnimatedPropertyID property, const String& animationName, int index, int subIndex, Seconds timeOffset)3054 {3055 // FIXME: this can be refactored a fair bit or merged with pauseCAAnimationOnLayer() with an operation flag.3056 PlatformCALayer* layer = animatedLayer(property);3057 3058 String animationID = animationIdentifier(animationName, property, index, subIndex);3059 3060 RefPtr<PlatformCAAnimation> currentAnimation = layer->animationForKey(animationID);3061 if (!currentAnimation)3062 return;3063 3064 // Animations on the layer are immutable, so we have to clone and modify.3065 RefPtr<PlatformCAAnimation> newAnim = currentAnimation->copy();3066 3067 newAnim->setBeginTime(CACurrentMediaTime());3068 3028 newAnim->setTimeOffset(timeOffset.seconds()); 3069 3029 … … 3233 3193 3234 3194 // Since we're adding a new animation, make sure we clear any pending AnimationProcessingAction for this animation 3235 // as these are applied after we've committed new animations. 3236 m_animations->animationsToProcess.remove(animation.m_name); 3195 // as these are applied after we've committed new animations. However, we want to check if we had a pending removal 3196 // such that removing an animation prior to adding a new one for the same name works. 3197 auto processingInfoIterator = m_animations->animationsToProcess.find(animation.m_name); 3198 if (processingInfoIterator != m_animations->animationsToProcess.end()) { 3199 auto animationIterator = m_animations->runningAnimations.find(animation.m_name); 3200 if (animationIterator != m_animations->runningAnimations.end()) { 3201 auto& animations = animationIterator->value; 3202 for (const auto& processingInfo : processingInfoIterator->value) { 3203 if (processingInfo.action == Remove) { 3204 for (const auto& currentAnimation : animations) 3205 removeCAAnimationFromLayer(currentAnimation.m_property, animation.m_name, currentAnimation.m_index, currentAnimation.m_subIndex); 3206 m_animations->runningAnimations.remove(animationIterator); 3207 break; 3208 } 3209 } 3210 } 3211 m_animations->animationsToProcess.remove(processingInfoIterator); 3212 } 3237 3213 3238 3214 m_animations->uncomittedAnimations.append(WTFMove(animation)); -
trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h
r260950 r261637 137 137 WEBCORE_EXPORT bool addAnimation(const KeyframeValueList&, const FloatSize& boxSize, const Animation*, const String& animationName, double timeOffset) override; 138 138 WEBCORE_EXPORT void pauseAnimation(const String& animationName, double timeOffset) override; 139 WEBCORE_EXPORT void seekAnimation(const String& animationName, double timeOffset) override;140 139 WEBCORE_EXPORT void removeAnimation(const String& animationName) override; 141 140 … … 462 461 bool removeCAAnimationFromLayer(AnimatedPropertyID, const String& animationName, int index, int subINdex); 463 462 void pauseCAAnimationOnLayer(AnimatedPropertyID, const String& animationName, int index, int subIndex, Seconds timeOffset); 464 void seekCAAnimationOnLayer(AnimatedPropertyID, const String& animationName, int index, int subIndex, Seconds timeOffset);465 463 466 464 enum MoveOrCopy { Move, Copy }; … … 564 562 void repaintLayerDirtyRects(); 565 563 566 enum Action { Remove, Pause , Seek};564 enum Action { Remove, Pause }; 567 565 struct AnimationProcessingAction { 568 566 AnimationProcessingAction(Action action = Remove, Seconds timeOffset = 0_s) -
trunk/Source/WebCore/rendering/RenderElement.h
r261597 r261637 233 233 virtual bool startAnimation(double /* timeOffset */, const Animation&, const KeyframeList&) { return false; } 234 234 virtual void animationPaused(double /* timeOffset */, const String& /* name */) { } 235 virtual void animationSeeked(double /* timeOffset */, const String& /* name */) { }236 235 virtual void animationFinished(const String& /* name */) { } 237 236 -
trunk/Source/WebCore/rendering/RenderLayerBacking.cpp
r261636 r261637 3498 3498 } 3499 3499 3500 void RenderLayerBacking::animationSeeked(double timeOffset, const String& animationName)3501 {3502 m_graphicsLayer->seekAnimation(animationName, timeOffset);3503 }3504 3505 3500 void RenderLayerBacking::animationFinished(const String& animationName) 3506 3501 { -
trunk/Source/WebCore/rendering/RenderLayerBacking.h
r261592 r261637 189 189 bool startAnimation(double timeOffset, const Animation&, const KeyframeList&); 190 190 void animationPaused(double timeOffset, const String& name); 191 void animationSeeked(double timeOffset, const String& name);192 191 void animationFinished(const String& name); 193 192 -
trunk/Source/WebCore/rendering/RenderLayerModelObject.cpp
r257933 r261637 319 319 } 320 320 321 void RenderLayerModelObject::animationSeeked(double timeOffset, const String& name)322 {323 if (!layer() || !layer()->backing())324 return;325 layer()->backing()->animationSeeked(timeOffset, name);326 }327 328 321 void RenderLayerModelObject::animationFinished(const String& name) 329 322 { -
trunk/Source/WebCore/rendering/RenderLayerModelObject.h
r243151 r261637 76 76 bool startAnimation(double timeOffset, const Animation&, const KeyframeList&) override; 77 77 void animationPaused(double timeOffset, const String& name) override; 78 void animationSeeked(double timeOffset, const String& name) override;79 78 void animationFinished(const String& name) override; 80 79
Note: See TracChangeset
for help on using the changeset viewer.