Diff
Modified: trunk/LayoutTests/ChangeLog (230580 => 230581)
--- trunk/LayoutTests/ChangeLog 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/LayoutTests/ChangeLog 2018-04-12 17:37:55 UTC (rev 230581)
@@ -1,5 +1,19 @@
2018-04-12 Antoine Quint <grao...@apple.com>
+ [Web Animations] Suspend animations when required
+ https://bugs.webkit.org/show_bug.cgi?id=184541
+
+ Reviewed by Jon Lee.
+
+ 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:
+
+2018-04-12 Antoine Quint <grao...@apple.com>
+
[Web Animations] Throttle animations when lowPowerMode is on
https://bugs.webkit.org/show_bug.cgi?id=184540
Modified: trunk/LayoutTests/animations/added-while-suspended.html (230580 => 230581)
--- trunk/LayoutTests/animations/added-while-suspended.html 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/LayoutTests/animations/added-while-suspended.html 2018-04-12 17:37:55 UTC (rev 230581)
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
<title>Test that new animations do not run while we are suspended</title>
<style>
#box {
Modified: trunk/LayoutTests/animations/animation-controller-drt-api.html (230580 => 230581)
--- trunk/LayoutTests/animations/animation-controller-drt-api.html 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/LayoutTests/animations/animation-controller-drt-api.html 2018-04-12 17:37:55 UTC (rev 230581)
@@ -1,5 +1,4 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><!-- webkit-test-runner [ enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations=true ] -->
<html lang="en">
<head>
Modified: trunk/LayoutTests/animations/animation-followed-by-transition.html (230580 => 230581)
--- trunk/LayoutTests/animations/animation-followed-by-transition.html 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/LayoutTests/animations/animation-followed-by-transition.html 2018-04-12 17:37:55 UTC (rev 230581)
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!DOCTYPE html><!-- webkit-test-runner [ enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations=true ] -->
<html>
<head>
<style>
Modified: trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible-with-style-change.html (230580 => 230581)
--- trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible-with-style-change.html 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible-with-style-change.html 2018-04-12 17:37:55 UTC (rev 230581)
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!DOCTYPE html><!-- webkit-test-runner [ enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations=true ] -->
<html>
<head>
<style>
Modified: trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible.html (230580 => 230581)
--- trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible.html 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible.html 2018-04-12 17:37:55 UTC (rev 230581)
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!DOCTYPE html><!-- webkit-test-runner [ enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations=true ] -->
<html>
<head>
<style>
Modified: trunk/LayoutTests/transitions/created-while-suspended.html (230580 => 230581)
--- trunk/LayoutTests/transitions/created-while-suspended.html 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/LayoutTests/transitions/created-while-suspended.html 2018-04-12 17:37:55 UTC (rev 230581)
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
<title>Test that newly created transitions do not run while we are suspended</title>
<style>
#box {
Modified: trunk/Source/WebCore/ChangeLog (230580 => 230581)
--- trunk/Source/WebCore/ChangeLog 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/Source/WebCore/ChangeLog 2018-04-12 17:37:55 UTC (rev 230581)
@@ -1,5 +1,52 @@
2018-04-12 Antoine Quint <grao...@apple.com>
+ [Web Animations] Suspend animations when required
+ https://bugs.webkit.org/show_bug.cgi?id=184541
+
+ Reviewed by Jon Lee.
+
+ 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):
+
+2018-04-12 Antoine Quint <grao...@apple.com>
+
[Web Animations] Throttle animations when lowPowerMode is on
https://bugs.webkit.org/show_bug.cgi?id=184540
Modified: trunk/Source/WebCore/animation/DocumentTimeline.cpp (230580 => 230581)
--- trunk/Source/WebCore/animation/DocumentTimeline.cpp 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/Source/WebCore/animation/DocumentTimeline.cpp 2018-04-12 17:37:55 UTC (rev 230581)
@@ -83,9 +83,55 @@
return m_document->page()->isLowPowerModeEnabled() ? throttledAnimationInterval : defaultAnimationInterval;
}
+void DocumentTimeline::suspendAnimations()
+{
+ if (animationsAreSuspended())
+ return;
+
+ m_isSuspended = true;
+
+ m_invalidationTaskQueue.cancelAllTasks();
+ if (m_animationScheduleTimer.isActive())
+ m_animationScheduleTimer.stop();
+
+ for (const auto& animation : animations())
+ animation->setSuspended(true);
+
+ applyPendingAcceleratedAnimations();
+}
+
+void DocumentTimeline::resumeAnimations()
+{
+ if (!animationsAreSuspended())
+ return;
+
+ m_isSuspended = false;
+
+ for (const auto& animation : animations())
+ animation->setSuspended(false);
+
+ m_needsUpdateAnimationSchedule = false;
+ timingModelDidChange();
+}
+
+bool DocumentTimeline::animationsAreSuspended()
+{
+ return m_isSuspended;
+}
+
+unsigned DocumentTimeline::numberOfActiveAnimationsForTesting() const
+{
+ unsigned count = 0;
+ for (const auto& animation : animations()) {
+ if (!animation->isSuspended())
+ ++count;
+ }
+ return count;
+}
+
std::optional<Seconds> DocumentTimeline::currentTime()
{
- if (m_paused || !m_document || !m_document->domWindow())
+ if (m_paused || m_isSuspended || !m_document || !m_document->domWindow())
return AnimationTimeline::currentTime();
if (!m_cachedCurrentTime) {
@@ -102,7 +148,7 @@
void DocumentTimeline::timingModelDidChange()
{
- if (m_needsUpdateAnimationSchedule)
+ if (m_needsUpdateAnimationSchedule || m_isSuspended)
return;
m_needsUpdateAnimationSchedule = true;
Modified: trunk/Source/WebCore/animation/DocumentTimeline.h (230580 => 230581)
--- trunk/Source/WebCore/animation/DocumentTimeline.h 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/Source/WebCore/animation/DocumentTimeline.h 2018-04-12 17:37:55 UTC (rev 230581)
@@ -73,6 +73,10 @@
void updateThrottlingState();
WEBCORE_EXPORT Seconds animationInterval() const;
+ WEBCORE_EXPORT void suspendAnimations();
+ WEBCORE_EXPORT void resumeAnimations();
+ WEBCORE_EXPORT bool animationsAreSuspended();
+ WEBCORE_EXPORT unsigned numberOfActiveAnimationsForTesting() const;
private:
DocumentTimeline(Document&, PlatformDisplayID);
@@ -87,6 +91,7 @@
RefPtr<Document> m_document;
bool m_paused { false };
+ bool m_isSuspended { false };
std::optional<Seconds> m_cachedCurrentTime;
GenericTaskQueue<Timer> m_invalidationTaskQueue;
GenericTaskQueue<Timer> m_eventDispatchTaskQueue;
Modified: trunk/Source/WebCore/animation/WebAnimation.cpp (230580 => 230581)
--- trunk/Source/WebCore/animation/WebAnimation.cpp 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/Source/WebCore/animation/WebAnimation.cpp 2018-04-12 17:37:55 UTC (rev 230581)
@@ -177,6 +177,8 @@
m_timeline = WTFMove(timeline);
+ setSuspended(is<DocumentTimeline>(m_timeline) && downcast<DocumentTimeline>(*m_timeline).animationsAreSuspended());
+
updatePendingTasks();
// 5. Run the procedure to update an animation’s finished state for animation with the did seek flag set to false,
@@ -1017,6 +1019,21 @@
m_effect->apply(targetStyle);
}
+void WebAnimation::setSuspended(bool isSuspended)
+{
+ if (m_isSuspended == isSuspended)
+ return;
+
+ m_isSuspended = isSuspended;
+
+ if (!is<KeyframeEffectReadOnly>(m_effect))
+ return;
+
+ auto& keyframeEffect = downcast<KeyframeEffectReadOnly>(*m_effect);
+ if (keyframeEffect.isRunningAccelerated() && playState() == PlayState::Running)
+ keyframeEffect.animationPlayStateDidChange(isSuspended ? PlayState::Paused : PlayState::Running);
+}
+
void WebAnimation::acceleratedStateDidChange()
{
if (is<DocumentTimeline>(m_timeline))
Modified: trunk/Source/WebCore/animation/WebAnimation.h (230580 => 230581)
--- trunk/Source/WebCore/animation/WebAnimation.h 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/Source/WebCore/animation/WebAnimation.h 2018-04-12 17:37:55 UTC (rev 230581)
@@ -106,6 +106,8 @@
void timingModelDidChange();
void suspendEffectInvalidation();
void unsuspendEffectInvalidation();
+ void setSuspended(bool);
+ bool isSuspended() const { return m_isSuspended; }
String description();
@@ -154,6 +156,7 @@
int m_suspendCount { 0 };
double m_playbackRate { 1 };
bool m_isStopped { false };
+ bool m_isSuspended { false };
bool m_finishNotificationStepsMicrotaskPending;
bool m_scheduledMicrotask;
UniqueRef<ReadyPromise> m_readyPromise;
Modified: trunk/Source/WebCore/dom/Document.cpp (230580 => 230581)
--- trunk/Source/WebCore/dom/Document.cpp 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/Source/WebCore/dom/Document.cpp 2018-04-12 17:37:55 UTC (rev 230581)
@@ -2259,11 +2259,17 @@
// be out of sync if the DOM suspension state changed while the document was not in the frame (possibly in the
// page cache, or simply newly created).
if (m_frame->activeDOMObjectsAndAnimationsSuspended()) {
- m_frame->animation().suspendAnimationsForDocument(this);
+ if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
+ timeline().suspendAnimations();
+ else
+ m_frame->animation().suspendAnimationsForDocument(this);
suspendScheduledTasks(ActiveDOMObject::PageWillBeSuspended);
} else {
resumeScheduledTasks(ActiveDOMObject::PageWillBeSuspended);
- m_frame->animation().resumeAnimationsForDocument(this);
+ if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
+ timeline().resumeAnimations();
+ else
+ m_frame->animation().resumeAnimationsForDocument(this);
}
}
@@ -4923,8 +4929,12 @@
ASSERT(m_frame);
m_frame->loader().client().dispatchDidBecomeFrameset(isFrameSet());
- m_frame->animation().resumeAnimationsForDocument(this);
+ if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
+ timeline().resumeAnimations();
+ else
+ m_frame->animation().resumeAnimationsForDocument(this);
+
resumeScheduledTasks(reason);
m_visualUpdatesAllowed = true;
Modified: trunk/Source/WebCore/dom/Document.h (230580 => 230581)
--- trunk/Source/WebCore/dom/Document.h 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/Source/WebCore/dom/Document.h 2018-04-12 17:37:55 UTC (rev 230581)
@@ -1392,7 +1392,7 @@
WEBCORE_EXPORT void setConsoleMessageListener(RefPtr<StringCallback>&&); // For testing.
- DocumentTimeline& timeline();
+ WEBCORE_EXPORT DocumentTimeline& timeline();
DocumentTimeline* existingTimeline() const { return m_timeline.get(); }
Vector<RefPtr<WebAnimation>> getAnimations();
Modified: trunk/Source/WebCore/history/CachedFrame.cpp (230580 => 230581)
--- trunk/Source/WebCore/history/CachedFrame.cpp 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/Source/WebCore/history/CachedFrame.cpp 2018-04-12 17:37:55 UTC (rev 230581)
@@ -32,6 +32,7 @@
#include "DOMWindow.h"
#include "Document.h"
#include "DocumentLoader.h"
+#include "DocumentTimeline.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
@@ -39,6 +40,7 @@
#include "Logging.h"
#include "Page.h"
#include "PageCache.h"
+#include "RuntimeEnabledFeatures.h"
#include "SVGDocumentExtensions.h"
#include "ScriptController.h"
#include "SerializedScriptValue.h"
@@ -96,7 +98,10 @@
if (m_document->svgExtensions())
m_document->accessSVGExtensions().unpauseAnimations();
- frame.animation().resumeAnimationsForDocument(m_document.get());
+ if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
+ m_document->timeline().resumeAnimations();
+ else
+ frame.animation().resumeAnimationsForDocument(m_document.get());
m_document->resume(ActiveDOMObject::PageCache);
Modified: trunk/Source/WebCore/page/Frame.cpp (230580 => 230581)
--- trunk/Source/WebCore/page/Frame.cpp 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/Source/WebCore/page/Frame.cpp 2018-04-12 17:37:55 UTC (rev 230581)
@@ -40,6 +40,7 @@
#include "Chrome.h"
#include "ChromeClient.h"
#include "DOMWindow.h"
+#include "DocumentTimeline.h"
#include "DocumentType.h"
#include "Editing.h"
#include "Editor.h"
@@ -777,7 +778,10 @@
{
if (view) {
view->layoutContext().unscheduleLayout();
- view->frame().animation().suspendAnimationsForDocument(document);
+ if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
+ document->timeline().suspendAnimations();
+ else
+ view->frame().animation().suspendAnimationsForDocument(document);
view->frame().eventHandler().stopAutoscrollTimer();
}
}
Modified: trunk/Source/WebCore/page/Page.cpp (230580 => 230581)
--- trunk/Source/WebCore/page/Page.cpp 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/Source/WebCore/page/Page.cpp 2018-04-12 17:37:55 UTC (rev 230581)
@@ -1637,8 +1637,14 @@
if (FrameView* view = mainFrame().view())
view->show();
- if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
- mainFrame().animation().resumeAnimations();
+ if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) {
+ if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
+ forEachDocument([&] (Document& document) {
+ document.timeline().resumeAnimations();
+ });
+ } else
+ mainFrame().animation().resumeAnimations();
+ }
setSVGAnimationsState(*this, SVGAnimationsState::Resumed);
@@ -1651,8 +1657,14 @@
}
if (!isVisible) {
- if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
- mainFrame().animation().suspendAnimations();
+ if (m_settings->hiddenPageCSSAnimationSuspensionEnabled()) {
+ if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
+ forEachDocument([&] (Document& document) {
+ document.timeline().suspendAnimations();
+ });
+ } else
+ mainFrame().animation().suspendAnimations();
+ }
setSVGAnimationsState(*this, SVGAnimationsState::Paused);
@@ -1998,10 +2010,19 @@
void Page::hiddenPageCSSAnimationSuspensionStateChanged()
{
if (!isVisible()) {
- if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
- mainFrame().animation().suspendAnimations();
- else
- mainFrame().animation().resumeAnimations();
+ if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
+ forEachDocument([&] (Document& document) {
+ if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
+ document.timeline().suspendAnimations();
+ else
+ document.timeline().resumeAnimations();
+ });
+ } else {
+ if (m_settings->hiddenPageCSSAnimationSuspensionEnabled())
+ mainFrame().animation().suspendAnimations();
+ else
+ mainFrame().animation().resumeAnimations();
+ }
}
}
Modified: trunk/Source/WebCore/testing/Internals.cpp (230580 => 230581)
--- trunk/Source/WebCore/testing/Internals.cpp 2018-04-12 17:26:55 UTC (rev 230580)
+++ trunk/Source/WebCore/testing/Internals.cpp 2018-04-12 17:37:55 UTC (rev 230581)
@@ -915,6 +915,8 @@
unsigned Internals::numberOfActiveAnimations() const
{
+ if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
+ return frame()->document()->timeline().numberOfActiveAnimationsForTesting();
return frame()->animation().numberOfActiveAnimations(frame()->document());
}
@@ -924,6 +926,8 @@
if (!document || !document->frame())
return Exception { InvalidAccessError };
+ if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled())
+ return document->timeline().animationsAreSuspended();
return document->frame()->animation().animationsAreSuspendedForDocument(document);
}
@@ -950,11 +954,19 @@
if (!document || !document->frame())
return Exception { InvalidAccessError };
- document->frame()->animation().suspendAnimationsForDocument(document);
+ if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
+ document->timeline().suspendAnimations();
+ for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
+ if (Document* document = frame->document())
+ document->timeline().suspendAnimations();
+ }
+ } else {
+ document->frame()->animation().suspendAnimationsForDocument(document);
- for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
- if (Document* document = frame->document())
- frame->animation().suspendAnimationsForDocument(document);
+ for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
+ if (Document* document = frame->document())
+ frame->animation().suspendAnimationsForDocument(document);
+ }
}
return { };
@@ -966,11 +978,19 @@
if (!document || !document->frame())
return Exception { InvalidAccessError };
- document->frame()->animation().resumeAnimationsForDocument(document);
+ if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
+ document->timeline().resumeAnimations();
+ for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
+ if (Document* document = frame->document())
+ document->timeline().resumeAnimations();
+ }
+ } else {
+ document->frame()->animation().resumeAnimationsForDocument(document);
- for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
- if (Document* document = frame->document())
- frame->animation().resumeAnimationsForDocument(document);
+ for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
+ if (Document* document = frame->document())
+ frame->animation().resumeAnimationsForDocument(document);
+ }
}
return { };