Changeset 230581 in webkit


Ignore:
Timestamp:
Apr 12, 2018 10:37:55 AM (6 years ago)
Author:
graouts@webkit.org
Message:

[Web Animations] Suspend animations when required
https://bugs.webkit.org/show_bug.cgi?id=184541

Reviewed by Jon Lee.

Source/WebCore:

Animations managed by CSSAnimationController get suspended under a number of scenarios, we now add the possibility
to suspend animations on a DocumentTimeline as well such that Web Animations and CSS Animations and CSS Transitions
implemented as Web Animations get suspended under the same conditions as well. We also update the implementation for
Internals::numberOfActiveAnimations() such that tests checking that animations get suspended pass.

  • animation/DocumentTimeline.cpp:

(WebCore::DocumentTimeline::suspendAnimations): When asked to be suspended, the DocumentTimeline cancels pending
invalidation tasks and updates all of the animations it manages, including those running on the compositor.
(WebCore::DocumentTimeline::resumeAnimations): When asked to be resumed, the DocumentTimeline resumes animations
it manages and rewinds its invalidation timer.
(WebCore::DocumentTimeline::animationsAreSuspended):
(WebCore::DocumentTimeline::numberOfActiveAnimationsForTesting const): Called by Internals::numberOfActiveAnimations(),
this returns the number of animations managed by this timeline that are not suspended.
(WebCore::DocumentTimeline::currentTime):
(WebCore::DocumentTimeline::timingModelDidChange): Ensure the invalidation timer is not rewound if the timeline
is suspended.

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

(WebCore::WebAnimation::setTimeline): When moving to a new timeline, ensure we match the new timeline's animation state.
(WebCore::WebAnimation::setSuspended): Toggle the accelerated running state of any backing hardware animations when
the suspension state of an animation changes.

  • animation/WebAnimation.h:

(WebCore::WebAnimation::isSuspended const):

  • dom/Document.cpp:

(WebCore::Document::didBecomeCurrentDocumentInFrame):
(WebCore::Document::resume):

  • dom/Document.h:
  • history/CachedFrame.cpp:

(WebCore::CachedFrameBase::restore):

  • page/Frame.cpp:

(WebCore::Frame::clearTimers):

  • page/Page.cpp:

(WebCore::Page::setIsVisibleInternal):
(WebCore::Page::hiddenPageCSSAnimationSuspensionStateChanged):

  • testing/Internals.cpp:

(WebCore::Internals::numberOfActiveAnimations const):
(WebCore::Internals::animationsAreSuspended const):
(WebCore::Internals::suspendAnimations const):
(WebCore::Internals::resumeAnimations const):

LayoutTests:

Mark more tests as passing when the CSS Animations and CSS Transitions as Web Animations flag is on.

  • animations/animation-controller-drt-api.html:
  • animations/animation-followed-by-transition.html:
  • fast/animation/css-animation-resuming-when-visible-with-style-change.html:
  • fast/animation/css-animation-resuming-when-visible.html:
Location:
trunk
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r230579 r230581  
     12018-04-12  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Suspend animations when required
     4        https://bugs.webkit.org/show_bug.cgi?id=184541
     5
     6        Reviewed by Jon Lee.
     7
     8        Mark more tests as passing when the CSS Animations and CSS Transitions as Web Animations flag is on.
     9
     10        * animations/animation-controller-drt-api.html:
     11        * animations/animation-followed-by-transition.html:
     12        * fast/animation/css-animation-resuming-when-visible-with-style-change.html:
     13        * fast/animation/css-animation-resuming-when-visible.html:
     14
    1152018-04-12  Antoine Quint  <graouts@apple.com>
    216
  • trunk/LayoutTests/animations/added-while-suspended.html

    r180441 r230581  
     1<!DOCTYPE html>
    12<title>Test that new animations do not run while we are suspended</title>
    23<style>
  • trunk/LayoutTests/animations/animation-controller-drt-api.html

    r141849 r230581  
    1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    2    "http://www.w3.org/TR/html4/loose.dtd">
     1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><!-- webkit-test-runner [ enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations=true ] -->
    32
    43<html lang="en">
  • trunk/LayoutTests/animations/animation-followed-by-transition.html

    r209675 r230581  
    1 <!DOCTYPE html>
     1<!DOCTYPE html><!-- webkit-test-runner [ enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations=true ] -->
    22<html>
    33<head>
  • trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible-with-style-change.html

    r218257 r230581  
    1 <!DOCTYPE html>
     1<!DOCTYPE html><!-- webkit-test-runner [ enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations=true ] -->
    22<html>
    33<head>
  • trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible.html

    r217997 r230581  
    1 <!DOCTYPE html>
     1<!DOCTYPE html><!-- webkit-test-runner [ enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations=true ] -->
    22<html>
    33<head>
  • trunk/LayoutTests/transitions/created-while-suspended.html

    r218277 r230581  
     1<!DOCTYPE html>
    12<title>Test that newly created transitions do not run while we are suspended</title>
    23<style>
  • trunk/Source/WebCore/ChangeLog

    r230579 r230581  
     12018-04-12  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Suspend animations when required
     4        https://bugs.webkit.org/show_bug.cgi?id=184541
     5
     6        Reviewed by Jon Lee.
     7
     8        Animations managed by CSSAnimationController get suspended under a number of scenarios, we now add the possibility
     9        to suspend animations on a DocumentTimeline as well such that Web Animations and CSS Animations and CSS Transitions
     10        implemented as Web Animations get suspended under the same conditions as well. We also update the implementation for
     11        Internals::numberOfActiveAnimations() such that tests checking that animations get suspended pass.
     12
     13        * animation/DocumentTimeline.cpp:
     14        (WebCore::DocumentTimeline::suspendAnimations): When asked to be suspended, the DocumentTimeline cancels pending
     15        invalidation tasks and updates all of the animations it manages, including those running on the compositor.
     16        (WebCore::DocumentTimeline::resumeAnimations): When asked to be resumed, the DocumentTimeline resumes animations
     17        it manages and rewinds its invalidation timer.
     18        (WebCore::DocumentTimeline::animationsAreSuspended):
     19        (WebCore::DocumentTimeline::numberOfActiveAnimationsForTesting const): Called by Internals::numberOfActiveAnimations(),
     20        this returns the number of animations managed by this timeline that are not suspended.
     21        (WebCore::DocumentTimeline::currentTime):
     22        (WebCore::DocumentTimeline::timingModelDidChange): Ensure the invalidation timer is not rewound if the timeline
     23        is suspended.
     24        * animation/DocumentTimeline.h:
     25        * animation/WebAnimation.cpp:
     26        (WebCore::WebAnimation::setTimeline): When moving to a new timeline, ensure we match the new timeline's animation state.
     27        (WebCore::WebAnimation::setSuspended): Toggle the accelerated running state of any backing hardware animations when
     28        the suspension state of an animation changes.
     29        * animation/WebAnimation.h:
     30        (WebCore::WebAnimation::isSuspended const):
     31        * dom/Document.cpp:
     32        (WebCore::Document::didBecomeCurrentDocumentInFrame):
     33        (WebCore::Document::resume):
     34        * dom/Document.h:
     35        * history/CachedFrame.cpp:
     36        (WebCore::CachedFrameBase::restore):
     37        * page/Frame.cpp:
     38        (WebCore::Frame::clearTimers):
     39        * page/Page.cpp:
     40        (WebCore::Page::setIsVisibleInternal):
     41        (WebCore::Page::hiddenPageCSSAnimationSuspensionStateChanged):
     42        * testing/Internals.cpp:
     43        (WebCore::Internals::numberOfActiveAnimations const):
     44        (WebCore::Internals::animationsAreSuspended const):
     45        (WebCore::Internals::suspendAnimations const):
     46        (WebCore::Internals::resumeAnimations const):
     47
    1482018-04-12  Antoine Quint  <graouts@apple.com>
    249
  • trunk/Source/WebCore/animation/DocumentTimeline.cpp

    r230579 r230581  
    8484}
    8585
     86void DocumentTimeline::suspendAnimations()
     87{
     88    if (animationsAreSuspended())
     89        return;
     90
     91    m_isSuspended = true;
     92
     93    m_invalidationTaskQueue.cancelAllTasks();
     94    if (m_animationScheduleTimer.isActive())
     95        m_animationScheduleTimer.stop();
     96
     97    for (const auto& animation : animations())
     98        animation->setSuspended(true);
     99
     100    applyPendingAcceleratedAnimations();
     101}
     102
     103void DocumentTimeline::resumeAnimations()
     104{
     105    if (!animationsAreSuspended())
     106        return;
     107
     108    m_isSuspended = false;
     109
     110    for (const auto& animation : animations())
     111        animation->setSuspended(false);
     112
     113    m_needsUpdateAnimationSchedule = false;
     114    timingModelDidChange();
     115}
     116
     117bool DocumentTimeline::animationsAreSuspended()
     118{
     119    return m_isSuspended;
     120}
     121
     122unsigned DocumentTimeline::numberOfActiveAnimationsForTesting() const
     123{
     124    unsigned count = 0;
     125    for (const auto& animation : animations()) {
     126        if (!animation->isSuspended())
     127            ++count;
     128    }
     129    return count;
     130}
     131
    86132std::optional<Seconds> DocumentTimeline::currentTime()
    87133{
    88     if (m_paused || !m_document || !m_document->domWindow())
     134    if (m_paused || m_isSuspended || !m_document || !m_document->domWindow())
    89135        return AnimationTimeline::currentTime();
    90136
     
    103149void DocumentTimeline::timingModelDidChange()
    104150{
    105     if (m_needsUpdateAnimationSchedule)
     151    if (m_needsUpdateAnimationSchedule || m_isSuspended)
    106152        return;
    107153
  • trunk/Source/WebCore/animation/DocumentTimeline.h

    r230579 r230581  
    7474    void updateThrottlingState();
    7575    WEBCORE_EXPORT Seconds animationInterval() const;
     76    WEBCORE_EXPORT void suspendAnimations();
     77    WEBCORE_EXPORT void resumeAnimations();
     78    WEBCORE_EXPORT bool animationsAreSuspended();
     79    WEBCORE_EXPORT unsigned numberOfActiveAnimationsForTesting() const;
    7680
    7781private:
     
    8892    RefPtr<Document> m_document;
    8993    bool m_paused { false };
     94    bool m_isSuspended { false };
    9095    std::optional<Seconds> m_cachedCurrentTime;
    9196    GenericTaskQueue<Timer> m_invalidationTaskQueue;
  • trunk/Source/WebCore/animation/WebAnimation.cpp

    r230574 r230581  
    177177
    178178    m_timeline = WTFMove(timeline);
     179
     180    setSuspended(is<DocumentTimeline>(m_timeline) && downcast<DocumentTimeline>(*m_timeline).animationsAreSuspended());
    179181
    180182    updatePendingTasks();
     
    10181020}
    10191021
     1022void WebAnimation::setSuspended(bool isSuspended)
     1023{
     1024    if (m_isSuspended == isSuspended)
     1025        return;
     1026
     1027    m_isSuspended = isSuspended;
     1028
     1029    if (!is<KeyframeEffectReadOnly>(m_effect))
     1030        return;
     1031
     1032    auto& keyframeEffect = downcast<KeyframeEffectReadOnly>(*m_effect);
     1033    if (keyframeEffect.isRunningAccelerated() && playState() == PlayState::Running)
     1034        keyframeEffect.animationPlayStateDidChange(isSuspended ? PlayState::Paused : PlayState::Running);
     1035}
     1036
    10201037void WebAnimation::acceleratedStateDidChange()
    10211038{
  • trunk/Source/WebCore/animation/WebAnimation.h

    r230574 r230581  
    107107    void suspendEffectInvalidation();
    108108    void unsuspendEffectInvalidation();
     109    void setSuspended(bool);
     110    bool isSuspended() const { return m_isSuspended; }
    109111
    110112    String description();
     
    155157    double m_playbackRate { 1 };
    156158    bool m_isStopped { false };
     159    bool m_isSuspended { false };
    157160    bool m_finishNotificationStepsMicrotaskPending;
    158161    bool m_scheduledMicrotask;
  • trunk/Source/WebCore/dom/Document.cpp

    r230368 r230581  
    22602260    // page cache, or simply newly created).
    22612261    if (m_frame->activeDOMObjectsAndAnimationsSuspended()) {
    2262         m_frame->animation().suspendAnimationsForDocument(this);
     2262        if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
     2263            timeline().suspendAnimations();
     2264        else
     2265            m_frame->animation().suspendAnimationsForDocument(this);
    22632266        suspendScheduledTasks(ActiveDOMObject::PageWillBeSuspended);
    22642267    } else {
    22652268        resumeScheduledTasks(ActiveDOMObject::PageWillBeSuspended);
    2266         m_frame->animation().resumeAnimationsForDocument(this);
     2269        if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
     2270            timeline().resumeAnimations();
     2271        else
     2272            m_frame->animation().resumeAnimationsForDocument(this);
    22672273    }
    22682274}
     
    49244930    ASSERT(m_frame);
    49254931    m_frame->loader().client().dispatchDidBecomeFrameset(isFrameSet());
    4926     m_frame->animation().resumeAnimationsForDocument(this);
     4932
     4933    if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
     4934        timeline().resumeAnimations();
     4935    else
     4936        m_frame->animation().resumeAnimationsForDocument(this);
    49274937
    49284938    resumeScheduledTasks(reason);
  • trunk/Source/WebCore/dom/Document.h

    r230368 r230581  
    13931393    WEBCORE_EXPORT void setConsoleMessageListener(RefPtr<StringCallback>&&); // For testing.
    13941394
    1395     DocumentTimeline& timeline();
     1395    WEBCORE_EXPORT DocumentTimeline& timeline();
    13961396    DocumentTimeline* existingTimeline() const { return m_timeline.get(); }
    13971397    Vector<RefPtr<WebAnimation>> getAnimations();
  • trunk/Source/WebCore/history/CachedFrame.cpp

    r230211 r230581  
    3333#include "Document.h"
    3434#include "DocumentLoader.h"
     35#include "DocumentTimeline.h"
    3536#include "Frame.h"
    3637#include "FrameLoader.h"
     
    4041#include "Page.h"
    4142#include "PageCache.h"
     43#include "RuntimeEnabledFeatures.h"
    4244#include "SVGDocumentExtensions.h"
    4345#include "ScriptController.h"
     
    9799        m_document->accessSVGExtensions().unpauseAnimations();
    98100
    99     frame.animation().resumeAnimationsForDocument(m_document.get());
     101    if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
     102        m_document->timeline().resumeAnimations();
     103    else
     104        frame.animation().resumeAnimationsForDocument(m_document.get());
    100105
    101106    m_document->resume(ActiveDOMObject::PageCache);
  • trunk/Source/WebCore/page/Frame.cpp

    r230211 r230581  
    4141#include "ChromeClient.h"
    4242#include "DOMWindow.h"
     43#include "DocumentTimeline.h"
    4344#include "DocumentType.h"
    4445#include "Editing.h"
     
    778779    if (view) {
    779780        view->layoutContext().unscheduleLayout();
    780         view->frame().animation().suspendAnimationsForDocument(document);
     781        if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
     782            document->timeline().suspendAnimations();
     783        else
     784            view->frame().animation().suspendAnimationsForDocument(document);
    781785        view->frame().eventHandler().stopAutoscrollTimer();
    782786    }
  • trunk/Source/WebCore/page/Page.cpp

    r230579 r230581  
    16381638            view->show();
    16391639
    1640         if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
    1641             mainFrame().animation().resumeAnimations();
     1640        if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) {
     1641            if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
     1642                forEachDocument([&] (Document& document) {
     1643                    document.timeline().resumeAnimations();
     1644                });
     1645            } else
     1646                mainFrame().animation().resumeAnimations();
     1647        }
    16421648
    16431649        setSVGAnimationsState(*this, SVGAnimationsState::Resumed);
     
    16521658
    16531659    if (!isVisible) {
    1654         if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
    1655             mainFrame().animation().suspendAnimations();
     1660        if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) {
     1661            if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
     1662                forEachDocument([&] (Document& document) {
     1663                    document.timeline().suspendAnimations();
     1664                });
     1665            } else
     1666                mainFrame().animation().suspendAnimations();
     1667        }
    16561668
    16571669        setSVGAnimationsState(*this, SVGAnimationsState::Paused);
     
    19992011{
    20002012    if (!isVisible()) {
    2001         if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
    2002             mainFrame().animation().suspendAnimations();
    2003         else
    2004             mainFrame().animation().resumeAnimations();
     2013        if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
     2014            forEachDocument([&] (Document& document) {
     2015                if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
     2016                    document.timeline().suspendAnimations();
     2017                else
     2018                    document.timeline().resumeAnimations();
     2019            });
     2020        } else {
     2021            if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
     2022                mainFrame().animation().suspendAnimations();
     2023            else
     2024                mainFrame().animation().resumeAnimations();
     2025        }
    20052026    }
    20062027}
  • trunk/Source/WebCore/testing/Internals.cpp

    r230579 r230581  
    916916unsigned Internals::numberOfActiveAnimations() const
    917917{
     918    if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
     919        return frame()->document()->timeline().numberOfActiveAnimationsForTesting();
    918920    return frame()->animation().numberOfActiveAnimations(frame()->document());
    919921}
     
    925927        return Exception { InvalidAccessError };
    926928
     929    if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
     930        return document->timeline().animationsAreSuspended();
    927931    return document->frame()->animation().animationsAreSuspendedForDocument(document);
    928932}
     
    951955        return Exception { InvalidAccessError };
    952956
    953     document->frame()->animation().suspendAnimationsForDocument(document);
    954 
    955     for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
    956         if (Document* document = frame->document())
    957             frame->animation().suspendAnimationsForDocument(document);
     957    if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
     958        document->timeline().suspendAnimations();
     959        for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
     960            if (Document* document = frame->document())
     961                document->timeline().suspendAnimations();
     962        }
     963    } else {
     964        document->frame()->animation().suspendAnimationsForDocument(document);
     965
     966        for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
     967            if (Document* document = frame->document())
     968                frame->animation().suspendAnimationsForDocument(document);
     969        }
    958970    }
    959971
     
    967979        return Exception { InvalidAccessError };
    968980
    969     document->frame()->animation().resumeAnimationsForDocument(document);
    970 
    971     for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
    972         if (Document* document = frame->document())
    973             frame->animation().resumeAnimationsForDocument(document);
     981    if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
     982        document->timeline().resumeAnimations();
     983        for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
     984            if (Document* document = frame->document())
     985                document->timeline().resumeAnimations();
     986        }
     987    } else {
     988        document->frame()->animation().resumeAnimationsForDocument(document);
     989
     990        for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
     991            if (Document* document = frame->document())
     992                frame->animation().resumeAnimationsForDocument(document);
     993        }
    974994    }
    975995
Note: See TracChangeset for help on using the changeset viewer.