Title: [213473] trunk
Revision
213473
Author
[email protected]
Date
2017-03-06 15:07:50 -0800 (Mon, 06 Mar 2017)

Log Message

[iOS] Throttle CSS animations to 30fps in low power mode
https://bugs.webkit.org/show_bug.cgi?id=169138
<rdar://problem/30837805>

Reviewed by Said Abou-Hallawa.

Source/WebCore:

Throttle software CSS animations to 30fps in low power mode on iOS
to save battery.

Test: fast/animation/css-animation-throttling-lowPowerMode.html

* page/Page.cpp:
(WebCore::Page::handleLowModePowerChange):
* page/animation/CSSAnimationController.cpp:
(WebCore::CSSAnimationControllerPrivate::CSSAnimationControllerPrivate):
(WebCore::CSSAnimationControllerPrivate::updateAnimationTimer):
(WebCore::CSSAnimationControllerPrivate::updateThrottlingState):
(WebCore::CSSAnimationControllerPrivate::animationInterval):
(WebCore::CSSAnimationControllerPrivate::beginAnimationUpdateTime):
(WebCore::CSSAnimationControllerPrivate::beginAnimationUpdate):
(WebCore::CSSAnimationController::updateThrottlingState):
(WebCore::CSSAnimationController::animationInterval):
* page/animation/CSSAnimationController.h:
* page/animation/CSSAnimationControllerPrivate.h:
* testing/Internals.cpp:
(WebCore::Internals::animationsInterval):
* testing/Internals.h:
* testing/Internals.idl:

LayoutTests:

Add layout test coverage.

* fast/animation/css-animation-throttling-lowPowerMode-expected.txt: Added.
* fast/animation/css-animation-throttling-lowPowerMode.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (213472 => 213473)


--- trunk/LayoutTests/ChangeLog	2017-03-06 23:07:27 UTC (rev 213472)
+++ trunk/LayoutTests/ChangeLog	2017-03-06 23:07:50 UTC (rev 213473)
@@ -1,3 +1,16 @@
+2017-03-06  Chris Dumez  <[email protected]>
+
+        [iOS] Throttle CSS animations to 30fps in low power mode
+        https://bugs.webkit.org/show_bug.cgi?id=169138
+        <rdar://problem/30837805>
+
+        Reviewed by Said Abou-Hallawa.
+
+        Add layout test coverage.
+
+        * fast/animation/css-animation-throttling-lowPowerMode-expected.txt: Added.
+        * fast/animation/css-animation-throttling-lowPowerMode.html: Added.
+
 2017-03-06  Alex Christensen  <[email protected]>
 
         Fix URLs relative to file URLs with paths beginning with Windows drive letters

Added: trunk/LayoutTests/fast/animation/css-animation-throttling-lowPowerMode-expected.txt (0 => 213473)


--- trunk/LayoutTests/fast/animation/css-animation-throttling-lowPowerMode-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/animation/css-animation-throttling-lowPowerMode-expected.txt	2017-03-06 23:07:50 UTC (rev 213473)
@@ -0,0 +1,14 @@
+Tests that CSS animations are throttled in low power mode.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS internals.animationsInterval is 0.015
+internals.setLowPowerModeEnabled(true)
+PASS internals.animationsInterval is 0.030
+internals.setLowPowerModeEnabled(false)
+PASS internals.animationsInterval is 0.015
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Test text

Added: trunk/LayoutTests/fast/animation/css-animation-throttling-lowPowerMode.html (0 => 213473)


--- trunk/LayoutTests/fast/animation/css-animation-throttling-lowPowerMode.html	                        (rev 0)
+++ trunk/LayoutTests/fast/animation/css-animation-throttling-lowPowerMode.html	2017-03-06 23:07:50 UTC (rev 213473)
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<style>
+@keyframes my-animation {        
+  from {
+    left : 0px;
+  }
+  to {
+    left : 100px;
+  }      
+}
+
+.run-animation {
+  position: relative;
+  animation: my-animation 0.5s infinite;
+  animation-direction: alternate;
+}
+</style>
+</head>
+<body>
+<p id="testElement" class="run-animation">Test text</p>
+<script>
+description("Tests that CSS animations are throttled in low power mode.");
+jsTestIsAsync = true;
+
+const element = document.getElementById("testElement");
+element._onanimationstart_ = function() {
+    element._onanimationstart_ = null;
+
+    shouldBe("internals.animationsInterval", "0.015");
+    evalAndLog("internals.setLowPowerModeEnabled(true)");
+    shouldBe("internals.animationsInterval", "0.030");
+    evalAndLog("internals.setLowPowerModeEnabled(false)");
+    shouldBe("internals.animationsInterval", "0.015");
+    finishJSTest();
+};
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (213472 => 213473)


--- trunk/Source/WebCore/ChangeLog	2017-03-06 23:07:27 UTC (rev 213472)
+++ trunk/Source/WebCore/ChangeLog	2017-03-06 23:07:50 UTC (rev 213473)
@@ -1,3 +1,34 @@
+2017-03-06  Chris Dumez  <[email protected]>
+
+        [iOS] Throttle CSS animations to 30fps in low power mode
+        https://bugs.webkit.org/show_bug.cgi?id=169138
+        <rdar://problem/30837805>
+
+        Reviewed by Said Abou-Hallawa.
+
+        Throttle software CSS animations to 30fps in low power mode on iOS
+        to save battery.
+
+        Test: fast/animation/css-animation-throttling-lowPowerMode.html
+
+        * page/Page.cpp:
+        (WebCore::Page::handleLowModePowerChange):
+        * page/animation/CSSAnimationController.cpp:
+        (WebCore::CSSAnimationControllerPrivate::CSSAnimationControllerPrivate):
+        (WebCore::CSSAnimationControllerPrivate::updateAnimationTimer):
+        (WebCore::CSSAnimationControllerPrivate::updateThrottlingState):
+        (WebCore::CSSAnimationControllerPrivate::animationInterval):
+        (WebCore::CSSAnimationControllerPrivate::beginAnimationUpdateTime):
+        (WebCore::CSSAnimationControllerPrivate::beginAnimationUpdate):
+        (WebCore::CSSAnimationController::updateThrottlingState):
+        (WebCore::CSSAnimationController::animationInterval):
+        * page/animation/CSSAnimationController.h:
+        * page/animation/CSSAnimationControllerPrivate.h:
+        * testing/Internals.cpp:
+        (WebCore::Internals::animationsInterval):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2017-03-03  Matt Rajca  <[email protected]>
 
         Media: notify clients when the user never plays a media element that was prevented from auto-playing

Modified: trunk/Source/WebCore/page/Page.cpp (213472 => 213473)


--- trunk/Source/WebCore/page/Page.cpp	2017-03-06 23:07:27 UTC (rev 213472)
+++ trunk/Source/WebCore/page/Page.cpp	2017-03-06 23:07:50 UTC (rev 213473)
@@ -1137,6 +1137,7 @@
 void Page::handleLowModePowerChange(bool isLowPowerModeEnabled)
 {
     updateScriptedAnimationsThrottlingReason(*this, isLowPowerModeEnabled ? ThrottlingReasonOperation::Add : ThrottlingReasonOperation::Remove, ScriptedAnimationController::ThrottlingReason::LowPowerMode);
+    mainFrame().animation().updateThrottlingState();
 }
 
 void Page::userStyleSheetLocationChanged()

Modified: trunk/Source/WebCore/page/animation/CSSAnimationController.cpp (213472 => 213473)


--- trunk/Source/WebCore/page/animation/CSSAnimationController.cpp	2017-03-06 23:07:27 UTC (rev 213472)
+++ trunk/Source/WebCore/page/animation/CSSAnimationController.cpp	2017-03-06 23:07:50 UTC (rev 213473)
@@ -49,8 +49,9 @@
 namespace WebCore {
 
 // Allow a little more than 60fps to make sure we can at least hit that frame rate.
-static const double cAnimationTimerDelay = 0.015;
-static const double cBeginAnimationUpdateTimeNotSet = -1;
+static const Seconds animationTimerDelay { 0.015 };
+// Allow a little more than 30fps to make sure we can at least hit that frame rate.
+static const Seconds animationTimerThrottledDelay { 0.030 };
 
 class AnimationPrivateUpdateBlock {
 public:
@@ -72,10 +73,8 @@
     : m_animationTimer(*this, &CSSAnimationControllerPrivate::animationTimerFired)
     , m_updateStyleIfNeededDispatcher(*this, &CSSAnimationControllerPrivate::updateStyleIfNeededDispatcherFired)
     , m_frame(frame)
-    , m_beginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet)
     , m_beginAnimationUpdateCount(0)
     , m_waitingForAsyncStartNotification(false)
-    , m_isSuspended(false)
     , m_allowsNewAnimationsWhileSuspended(false)
 {
 }
@@ -176,8 +175,12 @@
 
     // If we want service immediately, we start a repeating timer to reduce the overhead of starting
     if (!timeToNextService) {
-        if (!m_animationTimer.isActive() || !m_animationTimer.repeatInterval())
-            m_animationTimer.startRepeating(cAnimationTimerDelay);
+        auto* page = m_frame.page();
+        bool shouldThrottle = page && page->isLowPowerModeEnabled();
+        Seconds delay = shouldThrottle ? animationTimerThrottledDelay : animationTimerDelay;
+
+        if (!m_animationTimer.isActive() || m_animationTimer.repeatInterval() != delay.value())
+            m_animationTimer.startRepeating(delay);
         return;
     }
 
@@ -284,6 +287,22 @@
     return animation.isAnimatingProperty(property, true, runningState);
 }
 
+void CSSAnimationControllerPrivate::updateThrottlingState()
+{
+    updateAnimationTimer();
+
+    for (auto* childFrame = m_frame.tree().firstChild(); childFrame; childFrame = childFrame->tree().nextSibling())
+        childFrame->animation().updateThrottlingState();
+}
+
+Seconds CSSAnimationControllerPrivate::animationInterval() const
+{
+    if (!m_animationTimer.isActive())
+        return Seconds { INFINITY };
+
+    return Seconds { m_animationTimer.repeatInterval() };
+}
+
 void CSSAnimationControllerPrivate::suspendAnimations()
 {
     if (isSuspended())
@@ -400,16 +419,16 @@
 double CSSAnimationControllerPrivate::beginAnimationUpdateTime()
 {
     ASSERT(m_beginAnimationUpdateCount);
-    if (m_beginAnimationUpdateTime == cBeginAnimationUpdateTimeNotSet)
+    if (!m_beginAnimationUpdateTime)
         m_beginAnimationUpdateTime = monotonicallyIncreasingTime();
 
-    return m_beginAnimationUpdateTime;
+    return m_beginAnimationUpdateTime.value();
 }
 
 void CSSAnimationControllerPrivate::beginAnimationUpdate()
 {
     if (!m_beginAnimationUpdateCount)
-        setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
+        m_beginAnimationUpdateTime = std::nullopt;
     ++m_beginAnimationUpdateCount;
 }
 
@@ -725,6 +744,16 @@
     m_data->animationFrameCallbackFired();
 }
 
+void CSSAnimationController::updateThrottlingState()
+{
+    m_data->updateThrottlingState();
+}
+
+Seconds CSSAnimationController::animationInterval() const
+{
+    return m_data->animationInterval();
+}
+
 bool CSSAnimationController::animationsAreSuspendedForDocument(Document* document)
 {
     return m_data->animationsAreSuspendedForDocument(document);

Modified: trunk/Source/WebCore/page/animation/CSSAnimationController.h (213472 => 213473)


--- trunk/Source/WebCore/page/animation/CSSAnimationController.h	2017-03-06 23:07:27 UTC (rev 213472)
+++ trunk/Source/WebCore/page/animation/CSSAnimationController.h	2017-03-06 23:07:50 UTC (rev 213473)
@@ -72,6 +72,9 @@
     WEBCORE_EXPORT void resumeAnimations();
     void serviceAnimations();
 
+    void updateThrottlingState();
+    WEBCORE_EXPORT Seconds animationInterval() const;
+
     WEBCORE_EXPORT void suspendAnimationsForDocument(Document*);
     WEBCORE_EXPORT void resumeAnimationsForDocument(Document*);
     WEBCORE_EXPORT bool animationsAreSuspendedForDocument(Document*);

Modified: trunk/Source/WebCore/page/animation/CSSAnimationControllerPrivate.h (213472 => 213473)


--- trunk/Source/WebCore/page/animation/CSSAnimationControllerPrivate.h	2017-03-06 23:07:27 UTC (rev 213472)
+++ trunk/Source/WebCore/page/animation/CSSAnimationControllerPrivate.h	2017-03-06 23:07:50 UTC (rev 213473)
@@ -67,6 +67,9 @@
     void resumeAnimations();
     void animationFrameCallbackFired();
 
+    void updateThrottlingState();
+    Seconds animationInterval() const;
+
     void suspendAnimationsForDocument(Document*);
     void resumeAnimationsForDocument(Document*);
     bool animationsAreSuspendedForDocument(Document*);
@@ -85,7 +88,6 @@
     bool computeExtentOfAnimation(RenderElement&, LayoutRect&) const;
 
     double beginAnimationUpdateTime();
-    void setBeginAnimationUpdateTime(double t) { m_beginAnimationUpdateTime = t; }
     
     void beginAnimationUpdate();
     void endAnimationUpdate();
@@ -135,7 +137,7 @@
     Vector<Ref<Element>> m_elementChangesToDispatch;
     HashSet<Document*> m_suspendedDocuments;
 
-    double m_beginAnimationUpdateTime;
+    std::optional<double> m_beginAnimationUpdateTime;
 
     using AnimationsSet = HashSet<RefPtr<AnimationBase>>;
     AnimationsSet m_animationsWaitingForStyle;
@@ -144,7 +146,7 @@
     int m_beginAnimationUpdateCount;
 
     bool m_waitingForAsyncStartNotification;
-    bool m_isSuspended;
+    bool m_isSuspended { false };
 
     // Used to flag whether we should revert to previous buggy
     // behavior of allowing new transitions and animations to

Modified: trunk/Source/WebCore/testing/Internals.cpp (213472 => 213473)


--- trunk/Source/WebCore/testing/Internals.cpp	2017-03-06 23:07:27 UTC (rev 213472)
+++ trunk/Source/WebCore/testing/Internals.cpp	2017-03-06 23:07:50 UTC (rev 213473)
@@ -796,6 +796,15 @@
     return document->frame()->animation().animationsAreSuspendedForDocument(document);
 }
 
+double Internals::animationsInterval() const
+{
+    Document* document = contextDocument();
+    if (!document || !document->frame())
+        return INFINITY;
+
+    return document->frame()->animation().animationInterval().value();
+}
+
 ExceptionOr<void> Internals::suspendAnimations() const
 {
     Document* document = contextDocument();

Modified: trunk/Source/WebCore/testing/Internals.h (213472 => 213473)


--- trunk/Source/WebCore/testing/Internals.h	2017-03-06 23:07:27 UTC (rev 213472)
+++ trunk/Source/WebCore/testing/Internals.h	2017-03-06 23:07:50 UTC (rev 213473)
@@ -148,6 +148,7 @@
     ExceptionOr<void> resumeAnimations() const;
     ExceptionOr<bool> pauseAnimationAtTimeOnElement(const String& animationName, double pauseTime, Element&);
     ExceptionOr<bool> pauseAnimationAtTimeOnPseudoElement(const String& animationName, double pauseTime, Element&, const String& pseudoId);
+    double animationsInterval() const;
 
     // CSS Transition testing.
     ExceptionOr<bool> pauseTransitionAtTimeOnElement(const String& propertyName, double pauseTime, Element&);

Modified: trunk/Source/WebCore/testing/Internals.idl (213472 => 213473)


--- trunk/Source/WebCore/testing/Internals.idl	2017-03-06 23:07:27 UTC (rev 213472)
+++ trunk/Source/WebCore/testing/Internals.idl	2017-03-06 23:07:50 UTC (rev 213473)
@@ -135,6 +135,7 @@
     [MayThrowException] boolean animationsAreSuspended();
     [MayThrowException] boolean pauseAnimationAtTimeOnElement(DOMString animationName, unrestricted double pauseTime, Element element);
     [MayThrowException] boolean pauseAnimationAtTimeOnPseudoElement(DOMString animationName, unrestricted double pauseTime, Element element, DOMString pseudoId);
+    readonly attribute double animationsInterval;
 
     // CSS Transition testing.
     [MayThrowException] boolean pauseTransitionAtTimeOnElement(DOMString propertyName, unrestricted double pauseTime, Element element);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to