Title: [175441] trunk/Source/WebCore
Revision
175441
Author
cdu...@apple.com
Date
2014-10-31 17:12:51 -0700 (Fri, 31 Oct 2014)

Log Message

Support throttling of DOMTimers using nested setTimeout() calls
https://bugs.webkit.org/show_bug.cgi?id=138262

Reviewed by Gavin Barraclough.

Extend DOMTimers throttling support to timers that are using nested
setTimeout() calls instead of a setInterval(). To achieve this, this
patch introduces a NestedTimersVector singleton class where nested
timers are appended, and for which we potentially update the next
firing time, after the parent timer is done executing.

I have verified this helps on cnn.com for example, which has timers
interacting with non-visible plugins that are scheduled using nested
setTimeout() calls with a frequency of 150 / 200 ms.

* page/DOMTimer.cpp:
(WebCore::NestedTimersVector::NestedTimersVector):
(WebCore::NestedTimersVector::~NestedTimersVector):
(WebCore::NestedTimersVector::registerTimer):
(WebCore::NestedTimersVector::begin):
(WebCore::NestedTimersVector::end):
(WebCore::DOMTimer::install):
(WebCore::DOMTimer::updateThrottlingStateIfNecessary):
(WebCore::DOMTimer::fired):
* page/DOMTimer.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (175440 => 175441)


--- trunk/Source/WebCore/ChangeLog	2014-10-31 23:58:53 UTC (rev 175440)
+++ trunk/Source/WebCore/ChangeLog	2014-11-01 00:12:51 UTC (rev 175441)
@@ -1,5 +1,33 @@
 2014-10-31  Chris Dumez  <cdu...@apple.com>
 
+        Support throttling of DOMTimers using nested setTimeout() calls
+        https://bugs.webkit.org/show_bug.cgi?id=138262
+
+        Reviewed by Gavin Barraclough.
+
+        Extend DOMTimers throttling support to timers that are using nested
+        setTimeout() calls instead of a setInterval(). To achieve this, this
+        patch introduces a NestedTimersVector singleton class where nested
+        timers are appended, and for which we potentially update the next
+        firing time, after the parent timer is done executing.
+
+        I have verified this helps on cnn.com for example, which has timers
+        interacting with non-visible plugins that are scheduled using nested
+        setTimeout() calls with a frequency of 150 / 200 ms.
+
+        * page/DOMTimer.cpp:
+        (WebCore::NestedTimersVector::NestedTimersVector):
+        (WebCore::NestedTimersVector::~NestedTimersVector):
+        (WebCore::NestedTimersVector::registerTimer):
+        (WebCore::NestedTimersVector::begin):
+        (WebCore::NestedTimersVector::end):
+        (WebCore::DOMTimer::install):
+        (WebCore::DOMTimer::updateThrottlingStateIfNecessary):
+        (WebCore::DOMTimer::fired):
+        * page/DOMTimer.h:
+
+2014-10-31  Chris Dumez  <cdu...@apple.com>
+
         Move -webkit-marquee-increment property to the new StyleBuilder
         https://bugs.webkit.org/show_bug.cgi?id=138208
 

Modified: trunk/Source/WebCore/page/DOMTimer.cpp (175440 => 175441)


--- trunk/Source/WebCore/page/DOMTimer.cpp	2014-10-31 23:58:53 UTC (rev 175440)
+++ trunk/Source/WebCore/page/DOMTimer.cpp	2014-11-01 00:12:51 UTC (rev 175441)
@@ -84,6 +84,42 @@
 
 DOMTimerFireState* DOMTimerFireState::current = nullptr;
 
+struct NestedTimersVector {
+    typedef Vector<DOMTimer*, 1>::const_iterator const_iterator;
+
+    NestedTimersVector(ScriptExecutionContext* context)
+        : shouldSetCurrent(context->isDocument())
+    {
+        if (shouldSetCurrent) {
+            previous = current;
+            current = this;
+        }
+    }
+
+    ~NestedTimersVector()
+    {
+        if (shouldSetCurrent)
+            current = previous;
+    }
+
+    static NestedTimersVector* current;
+
+    void registerTimer(DOMTimer* timer)
+    {
+        nestedTimers.append(timer);
+    }
+
+    const_iterator begin() const { return nestedTimers.begin(); }
+    const_iterator end() const { return nestedTimers.end(); }
+
+private:
+    bool shouldSetCurrent;
+    NestedTimersVector* previous;
+    Vector<DOMTimer*, 1> nestedTimers;
+};
+
+NestedTimersVector* NestedTimersVector::current = nullptr;
+
 static inline bool shouldForwardUserGesture(int interval, int nestingLevel)
 {
     return UserGestureIndicator::processingUserGesture()
@@ -133,6 +169,10 @@
     timer->suspendIfNeeded();
     InspectorInstrumentation::didInstallTimer(context, timer->m_timeoutId, timeout, singleShot);
 
+    // Keep track of nested timer installs.
+    if (NestedTimersVector::current)
+        NestedTimersVector::current->registerTimer(timer);
+
     return timer->m_timeoutId;
 }
 
@@ -148,6 +188,17 @@
     context->removeTimeout(timeoutId);
 }
 
+void DOMTimer::updateThrottlingStateIfNecessary(const DOMTimerFireState& fireState)
+{
+    if (fireState.scriptDidInteractWithUserObservablePlugin && m_throttleState != ShouldNotThrottle) {
+        m_throttleState = ShouldNotThrottle;
+        updateTimerIntervalIfNecessary();
+    } else if (fireState.scriptDidInteractWithNonUserObservablePlugin && m_throttleState == Undetermined) {
+        m_throttleState = ShouldThrottle;
+        updateTimerIntervalIfNecessary();
+    }
+}
+
 void DOMTimer::scriptDidInteractWithPlugin(HTMLPlugInElement& pluginElement)
 {
     if (!DOMTimerFireState::current)
@@ -198,15 +249,8 @@
         m_action->execute(context);
 
         InspectorInstrumentation::didFireTimer(cookie);
+        updateThrottlingStateIfNecessary(fireState);
 
-        if (fireState.scriptDidInteractWithUserObservablePlugin && m_throttleState != ShouldNotThrottle) {
-            m_throttleState = ShouldNotThrottle;
-            updateTimerIntervalIfNecessary();
-        } else if (fireState.scriptDidInteractWithNonUserObservablePlugin && m_throttleState == Undetermined) {
-            m_throttleState = ShouldThrottle;
-            updateTimerIntervalIfNecessary();
-        }
-
         return;
     }
 
@@ -229,6 +273,8 @@
     }
 #endif
 
+    // Keep track nested timer installs.
+    NestedTimersVector nestedTimers(context);
     m_action->execute(context);
 
 #if PLATFORM(IOS)
@@ -243,6 +289,12 @@
 
     InspectorInstrumentation::didFireTimer(cookie);
 
+    // Check if we should throttle nested single-shot timers.
+    for (auto* timer : nestedTimers) {
+        if (!timer->repeatInterval())
+            timer->updateThrottlingStateIfNecessary(fireState);
+    }
+
     context->setTimerNestingLevel(0);
 }
 

Modified: trunk/Source/WebCore/page/DOMTimer.h (175440 => 175441)


--- trunk/Source/WebCore/page/DOMTimer.h	2014-10-31 23:58:53 UTC (rev 175440)
+++ trunk/Source/WebCore/page/DOMTimer.h	2014-11-01 00:12:51 UTC (rev 175441)
@@ -33,6 +33,7 @@
 
 namespace WebCore {
 
+    struct DOMTimerFireState;
     class HTMLPlugInElement;
     class ScheduledAction;
 
@@ -54,6 +55,7 @@
     private:
         DOMTimer(ScriptExecutionContext*, std::unique_ptr<ScheduledAction>, int interval, bool singleShot);
         double intervalClampedToMinimum() const;
+        void updateThrottlingStateIfNecessary(const DOMTimerFireState&);
 
         // SuspendableTimer
         virtual void fired() override;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to