Changeset 252455 in webkit


Ignore:
Timestamp:
Nov 14, 2019 6:25:21 AM (4 years ago)
Author:
graouts@webkit.org
Message:

[Web Animations] Retargeted transitions targeting accelerated properties do not stop the original transition
https://bugs.webkit.org/show_bug.cgi?id=204116
<rdar://problem/57116961>

Reviewed by Dean Jackson.

Source/WebCore:

Test: webanimations/css-transition-in-flight-reversal-accelerated.html

There were two problems with the reversal of in-flight transitions targeting accelerated properties. The first issue
was that the animated value for the accelerated property would be missing from the before-change style since animating
acceelerated properties do not update RenderStyle while running. As such, we would not detect the need to reverse a
transition, but rather simply cancel the initial transition with no new transition to reverse its effect, since the
value in the before-change and after-change styles were the same. We now fix this by figuring out whether the running
transition for that property is accelerated in AnimationTimeline::updateCSSTransitionsForElementAndProperty() and
applying the animated value to the before-change style.

The second issue was that canceling an accelerated transition had no visible effect since the accelerated animation
was not stopped. We now have a new AnimationEffect::animationWasCanceled() virtual method which KeyframeEffect overrides
to add AcceleratedAction::Stop to the list of pending acceleration actions for this effect. We also ensure that the document
timeline knows to run DocumentTimeline::updateAnimationsAndSendEvents() if there are pending accelerated actions, even if
there aren't any animations waiting to be resolved, since a single canceled transition would prevent this method from
completing.

  • animation/AnimationEffect.h:
  • animation/AnimationTimeline.cpp:

(WebCore::AnimationTimeline::updateCSSTransitionsForElementAndProperty):

  • animation/DocumentTimeline.cpp:

(WebCore::DocumentTimeline::removeAnimation):
(WebCore::DocumentTimeline::scheduleAnimationResolution):
(WebCore::DocumentTimeline::shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState const):
(WebCore::DocumentTimeline::updateAnimationsAndSendEvents):
(WebCore::DocumentTimeline::updateListOfElementsWithRunningAcceleratedAnimationsForElement):

  • animation/DocumentTimeline.h:
  • animation/KeyframeEffect.cpp:

(WebCore::KeyframeEffect::animationWasCanceled):

  • animation/KeyframeEffect.h:
  • animation/WebAnimation.cpp:

(WebCore::WebAnimation::cancel):

LayoutTests:

Add a new test that checks that reversing an in-flight transition for "opacity" and "transform" correctly reverses the transition.

  • platform/mac-wk1/imported/w3c/web-platform-tests/dom/events/Event-dispatch-on-disabled-elements-expected.txt: Added.
  • webanimations/css-transition-in-flight-reversal-accelerated-expected.txt: Added.
  • webanimations/css-transition-in-flight-reversal-accelerated.html: Added.
Location:
trunk
Files:
5 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r252450 r252455  
     12019-11-14  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Retargeted transitions targeting accelerated properties do not stop the original transition
     4        https://bugs.webkit.org/show_bug.cgi?id=204116
     5        <rdar://problem/57116961>
     6
     7        Reviewed by Dean Jackson.
     8
     9        Add a new test that checks that reversing an in-flight transition for "opacity" and "transform" correctly reverses the transition.
     10
     11        * platform/mac-wk1/imported/w3c/web-platform-tests/dom/events/Event-dispatch-on-disabled-elements-expected.txt: Added.
     12        * webanimations/css-transition-in-flight-reversal-accelerated-expected.txt: Added.
     13        * webanimations/css-transition-in-flight-reversal-accelerated.html: Added.
     14
    1152019-11-13  Wenson Hsieh  <wenson_hsieh@apple.com>
    216
  • trunk/Source/WebCore/ChangeLog

    r252451 r252455  
     12019-11-14  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Retargeted transitions targeting accelerated properties do not stop the original transition
     4        https://bugs.webkit.org/show_bug.cgi?id=204116
     5        <rdar://problem/57116961>
     6
     7        Reviewed by Dean Jackson.
     8
     9        Test: webanimations/css-transition-in-flight-reversal-accelerated.html
     10
     11        There were two problems with the reversal of in-flight transitions targeting accelerated properties. The first issue
     12        was that the animated value for the accelerated property would be missing from the before-change style since animating
     13        acceelerated properties do not update RenderStyle while running. As such, we would not detect the need to reverse a
     14        transition, but rather simply cancel the initial transition with no new transition to reverse its effect, since the
     15        value in the before-change and after-change styles were the same. We now fix this by figuring out whether the running
     16        transition for that property is accelerated in AnimationTimeline::updateCSSTransitionsForElementAndProperty() and
     17        applying the animated value to the before-change style.
     18
     19        The second issue was that canceling an accelerated transition had no visible effect since the accelerated animation
     20        was not stopped. We now have a new AnimationEffect::animationWasCanceled() virtual method which KeyframeEffect overrides
     21        to add AcceleratedAction::Stop to the list of pending acceleration actions for this effect. We also ensure that the document
     22        timeline knows to run DocumentTimeline::updateAnimationsAndSendEvents() if there are pending accelerated actions, even if
     23        there aren't any animations waiting to be resolved, since a single canceled transition would prevent this method from
     24        completing.
     25
     26        * animation/AnimationEffect.h:
     27        * animation/AnimationTimeline.cpp:
     28        (WebCore::AnimationTimeline::updateCSSTransitionsForElementAndProperty):
     29        * animation/DocumentTimeline.cpp:
     30        (WebCore::DocumentTimeline::removeAnimation):
     31        (WebCore::DocumentTimeline::scheduleAnimationResolution):
     32        (WebCore::DocumentTimeline::shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState const):
     33        (WebCore::DocumentTimeline::updateAnimationsAndSendEvents):
     34        (WebCore::DocumentTimeline::updateListOfElementsWithRunningAcceleratedAnimationsForElement):
     35        * animation/DocumentTimeline.h:
     36        * animation/KeyframeEffect.cpp:
     37        (WebCore::KeyframeEffect::animationWasCanceled):
     38        * animation/KeyframeEffect.h:
     39        * animation/WebAnimation.cpp:
     40        (WebCore::WebAnimation::cancel):
     41
    1422019-11-13  Nikolas Zimmermann  <nzimmermann@igalia.com>
    243
  • trunk/Source/WebCore/animation/AnimationEffect.h

    r252253 r252455  
    6262    virtual void invalidate() = 0;
    6363    virtual void animationDidSeek() = 0;
     64    virtual void animationWasCanceled() = 0;
    6465    virtual void animationSuspensionStateDidChange(bool) = 0;
    6566    virtual void animationTimelineDidChange(AnimationTimeline*) = 0;
  • trunk/Source/WebCore/animation/AnimationTimeline.cpp

    r252253 r252455  
    400400    // Define the before-change style as the computed values of all properties on the element as of the previous style change event, except with
    401401    // any styles derived from declarative animations such as CSS Transitions, CSS Animations, and SMIL Animations updated to the current time.
    402     auto existingAnimation = cssAnimationForElementAndProperty(element, property);
    403     const auto& beforeChangeStyle = existingAnimation ? downcast<CSSAnimation>(existingAnimation.get())->unanimatedStyle() : currentStyle;
    404 
    405     if (!runningTransitionsByProperty.contains(property)
     402    bool hasRunningTransition = runningTransitionsByProperty.contains(property);
     403    auto& beforeChangeStyle = [&]() -> const RenderStyle& {
     404        if (hasRunningTransition && CSSPropertyAnimation::animationOfPropertyIsAccelerated(property)) {
     405            // In case we have an accelerated transition running for this element, we need to get its computed style as the before-change style
     406            // since otherwise the animated value for that property won't be visible.
     407            auto* runningTransition = runningTransitionsByProperty.get(property);
     408            if (is<KeyframeEffect>(runningTransition->effect())) {
     409                auto& keyframeEffect = *downcast<KeyframeEffect>(runningTransition->effect());
     410                if (keyframeEffect.isAccelerated()) {
     411                    auto animatedStyle = RenderStyle::clonePtr(currentStyle);
     412                    runningTransition->resolve(*animatedStyle);
     413                    return *animatedStyle;
     414                }
     415            }
     416        }
     417
     418        if (auto existingAnimation = cssAnimationForElementAndProperty(element, property))
     419            return downcast<CSSAnimation>(existingAnimation.get())->unanimatedStyle();
     420
     421        return currentStyle;
     422    }();
     423
     424    if (!hasRunningTransition
    406425        && !CSSPropertyAnimation::propertiesEqual(property, &beforeChangeStyle, &afterChangeStyle)
    407426        && CSSPropertyAnimation::canPropertyBeInterpolated(property, &beforeChangeStyle, &afterChangeStyle)
     
    436455    }
    437456
    438     bool hasRunningTransition = runningTransitionsByProperty.contains(property);
     457    hasRunningTransition = runningTransitionsByProperty.contains(property);
    439458    if ((hasRunningTransition || completedTransitionsByProperty.contains(property)) && !matchingBackingAnimation) {
    440459        // 3. If the element has a running transition or completed transition for the property, and there is not a matching transition-property
  • trunk/Source/WebCore/animation/DocumentTimeline.cpp

    r252253 r252455  
    308308    AnimationTimeline::removeAnimation(animation);
    309309
    310     if (m_animations.isEmpty())
     310    if (!shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState())
    311311        unscheduleAnimationResolution();
    312312}
     
    314314void DocumentTimeline::scheduleAnimationResolution()
    315315{
    316     if (m_isSuspended || m_animations.isEmpty() || m_animationResolutionScheduled)
     316    if (m_isSuspended || m_animationResolutionScheduled || !shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState())
    317317        return;
    318318
     
    330330}
    331331
     332bool DocumentTimeline::shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState() const
     333{
     334    return !m_animations.isEmpty() || !m_acceleratedAnimationsPendingRunningStateChange.isEmpty();
     335}
     336
    332337void DocumentTimeline::updateAnimationsAndSendEvents(DOMHighResTimeStamp timestamp)
    333338{
     
    338343        cacheCurrentTime(timestamp);
    339344
    340     if (m_isSuspended || m_animations.isEmpty() || !m_animationResolutionScheduled)
     345    if (m_isSuspended || !m_animationResolutionScheduled || !shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState())
    341346        return;
    342347
     
    655660
    656661    m_elementsWithRunningAcceleratedAnimations.add(&element);
     662
     663    if (shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState())
     664        scheduleAnimationResolution();
     665    else
     666        unscheduleAnimationResolution();
    657667}
    658668
  • trunk/Source/WebCore/animation/DocumentTimeline.h

    r252253 r252455  
    100100    void removeReplacedAnimations();
    101101    bool animationCanBeRemoved(WebAnimation&);
     102    bool shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState() const;
    102103
    103104    Timer m_tickScheduleTimer;
  • trunk/Source/WebCore/animation/KeyframeEffect.cpp

    r252313 r252455  
    13411341}
    13421342
     1343void KeyframeEffect::animationWasCanceled()
     1344{
     1345    if (m_shouldRunAccelerated && isRunningAccelerated())
     1346        addPendingAcceleratedAction(AcceleratedAction::Stop);
     1347}
     1348
    13431349void KeyframeEffect::animationSuspensionStateDidChange(bool animationIsSuspended)
    13441350{
  • trunk/Source/WebCore/animation/KeyframeEffect.h

    r252253 r252455  
    114114    void invalidate() override;
    115115    void animationDidSeek() final;
     116    void animationWasCanceled() final;
    116117    void animationSuspensionStateDidChange(bool) final;
    117118    void animationTimelineDidChange(AnimationTimeline*) final;
  • trunk/Source/WebCore/animation/WebAnimation.cpp

    r252253 r252455  
    615615
    616616    invalidateEffect();
     617
     618    if (m_effect)
     619        m_effect->animationWasCanceled();
    617620}
    618621
Note: See TracChangeset for help on using the changeset viewer.