<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[197006] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/197006">197006</a></dd>
<dt>Author</dt> <dd>barraclough@apple.com</dd>
<dt>Date</dt> <dd>2016-02-23 16:32:40 -0800 (Tue, 23 Feb 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add a mechanism to automatically ramp up timer alignment.
https://bugs.webkit.org/show_bug.cgi?id=154578

Reviewed by Antti Koivisto &amp; Chris Dumez.

Allow timer alignment duration to be proportional to the time the page
has been hidden. This implementation does so by scaling up the throttle
in exponential steps, spaced exponentially far apart.

* page/Page.cpp:
(WebCore::Page::Page):
    - initialize timer.
(WebCore::Page::hiddenPageDOMTimerThrottlingStateChanged):
    - if setting are changed fully disable/reenable to ensure new setting are read.
(WebCore::Page::setTimerThrottlingEnabled):
    - enebled bool flag converted to an Optional&lt;double&gt;, tracking time throttling
      is enabled.
(WebCore::Page::setDOMTimerAlignmentInterval):
    - when new mechanism is enabled schedule a timer to step up alignment.
(WebCore::Page::timerAlignmentIntervalIncreaseTimerFired):
    - when timer fires increase alignment.
* page/Page.h:
    - added new member.
* page/Settings.cpp:
(WebCore::Settings::Settings):
    - initialize new member.
(WebCore::Settings::setHiddenPageDOMTimerThrottlingAutoIncreaseLimit):
    - added, update new setting. Setting to zero disabled. A non-zero value is a
      duration in seconds for timer throttling to ramp up to.
* page/Settings.h:
(WebCore::Settings::hiddenPageDOMTimerThrottlingAutoIncreases):
    - read as boolean whether throttle increasing is enabled.
(WebCore::Settings::hiddenPageDOMTimerThrottlingAutoIncreaseLimit):
    - read throttle increasing limit.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorepagePagecpp">trunk/Source/WebCore/page/Page.cpp</a></li>
<li><a href="#trunkSourceWebCorepagePageh">trunk/Source/WebCore/page/Page.h</a></li>
<li><a href="#trunkSourceWebCorepageSettingscpp">trunk/Source/WebCore/page/Settings.cpp</a></li>
<li><a href="#trunkSourceWebCorepageSettingsh">trunk/Source/WebCore/page/Settings.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (197005 => 197006)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-02-24 00:30:48 UTC (rev 197005)
+++ trunk/Source/WebCore/ChangeLog        2016-02-24 00:32:40 UTC (rev 197006)
</span><span class="lines">@@ -1,3 +1,40 @@
</span><ins>+2016-02-23  Gavin Barraclough  &lt;barraclough@apple.com&gt;
+
+        Add a mechanism to automatically ramp up timer alignment.
+        https://bugs.webkit.org/show_bug.cgi?id=154578
+
+        Reviewed by Antti Koivisto &amp; Chris Dumez.
+
+        Allow timer alignment duration to be proportional to the time the page
+        has been hidden. This implementation does so by scaling up the throttle
+        in exponential steps, spaced exponentially far apart.
+
+        * page/Page.cpp:
+        (WebCore::Page::Page):
+            - initialize timer.
+        (WebCore::Page::hiddenPageDOMTimerThrottlingStateChanged):
+            - if setting are changed fully disable/reenable to ensure new setting are read.
+        (WebCore::Page::setTimerThrottlingEnabled):
+            - enebled bool flag converted to an Optional&lt;double&gt;, tracking time throttling
+              is enabled.
+        (WebCore::Page::setDOMTimerAlignmentInterval):
+            - when new mechanism is enabled schedule a timer to step up alignment.
+        (WebCore::Page::timerAlignmentIntervalIncreaseTimerFired):
+            - when timer fires increase alignment.
+        * page/Page.h:
+            - added new member.
+        * page/Settings.cpp:
+        (WebCore::Settings::Settings):
+            - initialize new member.
+        (WebCore::Settings::setHiddenPageDOMTimerThrottlingAutoIncreaseLimit):
+            - added, update new setting. Setting to zero disabled. A non-zero value is a
+              duration in seconds for timer throttling to ramp up to.
+        * page/Settings.h:
+        (WebCore::Settings::hiddenPageDOMTimerThrottlingAutoIncreases):
+            - read as boolean whether throttle increasing is enabled.
+        (WebCore::Settings::hiddenPageDOMTimerThrottlingAutoIncreaseLimit):
+            - read throttle increasing limit.
+
</ins><span class="cx"> 2016-02-22  Ada Chan  &lt;adachan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Refactor script that updates fullscreen buttons.
</span></span></pre></div>
<a id="trunkSourceWebCorepagePagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/Page.cpp (197005 => 197006)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/Page.cpp        2016-02-24 00:30:48 UTC (rev 197005)
+++ trunk/Source/WebCore/page/Page.cpp        2016-02-24 00:32:40 UTC (rev 197006)
</span><span class="lines">@@ -204,8 +204,8 @@
</span><span class="cx"> #if ENABLE(VIEW_MODE_CSS_MEDIA)
</span><span class="cx">     , m_viewMode(ViewModeWindowed)
</span><span class="cx"> #endif // ENABLE(VIEW_MODE_CSS_MEDIA)
</span><del>-    , m_timerThrottlingEnabled(false)
</del><span class="cx">     , m_timerAlignmentInterval(DOMTimer::defaultAlignmentInterval())
</span><ins>+    , m_timerAlignmentIntervalIncreaseTimer(*this, &amp;Page::timerAlignmentIntervalIncreaseTimerFired)
</ins><span class="cx">     , m_isEditable(false)
</span><span class="cx">     , m_isPrerender(false)
</span><span class="cx">     , m_viewState(PageInitialViewState)
</span><span class="lines">@@ -1157,6 +1157,8 @@
</span><span class="cx"> 
</span><span class="cx"> void Page::hiddenPageDOMTimerThrottlingStateChanged()
</span><span class="cx"> {
</span><ins>+    // Disable &amp; reengage to ensure state is updated.
+    setTimerThrottlingEnabled(false);
</ins><span class="cx">     setTimerThrottlingEnabled(m_viewState &amp; ViewState::IsVisuallyIdle);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1167,23 +1169,50 @@
</span><span class="cx">         enabled = false;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    if (enabled == m_timerThrottlingEnabled)
</del><ins>+    if (enabled == !!m_timerThrottlingEnabledTime)
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    m_timerThrottlingEnabled = enabled;
</del><ins>+    m_timerThrottlingEnabledTime = enabled ? monotonicallyIncreasingTime() : Optional&lt;double&gt;();
</ins><span class="cx">     setDOMTimerAlignmentInterval(enabled ? DOMTimer::hiddenPageAlignmentInterval() : DOMTimer::defaultAlignmentInterval());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Page::setDOMTimerAlignmentInterval(double alignmentInterval)
</span><span class="cx"> {
</span><ins>+    // If the new alignmentInterval is shorter than the one presently in effect we need to update
+    // existing timers (e.g. when a hidden page becomes visible throttled timers must be unthrottled).
+    // However when lengthening the alignment interval, no need to update existing timers. Not doing
+    // so means that timers scheduled while the page is visible get to fire accurately (repeating
+    // timers will be throttled on the next timer fire).
+    bool shouldRescheduleExistingTimers = alignmentInterval &lt; m_timerAlignmentInterval;
+
</ins><span class="cx">     m_timerAlignmentInterval = alignmentInterval;
</span><del>-    
-    for (Frame* frame = &amp;mainFrame(); frame; frame = frame-&gt;tree().traverseNext()) {
-        if (frame-&gt;document())
-            frame-&gt;document()-&gt;didChangeTimerAlignmentInterval();
</del><ins>+
+    if (shouldRescheduleExistingTimers) {
+        for (Frame* frame = &amp;mainFrame(); frame; frame = frame-&gt;tree().traverseNext()) {
+            if (auto* document = frame-&gt;document())
+                document-&gt;didChangeTimerAlignmentInterval();
+        }
</ins><span class="cx">     }
</span><ins>+
+    // If throttling is enabled and auto-increasing of throttling is enabled then arm the timer to
+    // consider an increase. Time to wait between increases is equal to the current throttle time.
+    // Since alinment interval increases exponentially, time between steps is exponential too.
+    if (m_timerThrottlingEnabledTime &amp;&amp; m_settings-&gt;hiddenPageDOMTimerThrottlingAutoIncreases())
+        m_timerAlignmentIntervalIncreaseTimer.startOneShot(m_timerAlignmentInterval);
+    else
+        m_timerAlignmentIntervalIncreaseTimer.stop();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Page::timerAlignmentIntervalIncreaseTimerFired()
+{
+    ASSERT(m_timerThrottlingEnabledTime &amp;&amp; m_settings-&gt;hiddenPageDOMTimerThrottlingAutoIncreases());
+        
+    // Alignment interval is increased to equal the time the page has been throttled.
+    double throttledDuration = monotonicallyIncreasingTime() - m_timerThrottlingEnabledTime.value();
+    double alignmentInterval = std::max(m_timerAlignmentInterval, throttledDuration);
+    setDOMTimerAlignmentInterval(alignmentInterval);
+}
+
</ins><span class="cx"> void Page::dnsPrefetchingStateChanged()
</span><span class="cx"> {
</span><span class="cx">     for (Frame* frame = &amp;mainFrame(); frame; frame = frame-&gt;tree().traverseNext())
</span></span></pre></div>
<a id="trunkSourceWebCorepagePageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/Page.h (197005 => 197006)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/Page.h        2016-02-24 00:30:48 UTC (rev 197005)
+++ trunk/Source/WebCore/page/Page.h        2016-02-24 00:32:40 UTC (rev 197006)
</span><span class="lines">@@ -42,6 +42,7 @@
</span><span class="cx"> #include &lt;wtf/HashMap.h&gt;
</span><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><span class="cx"> #include &lt;wtf/Noncopyable.h&gt;
</span><ins>+#include &lt;wtf/Optional.h&gt;
</ins><span class="cx"> #include &lt;wtf/Ref.h&gt;
</span><span class="cx"> #include &lt;wtf/RefCounted.h&gt;
</span><span class="cx"> #include &lt;wtf/text/WTFString.h&gt;
</span><span class="lines">@@ -523,7 +524,7 @@
</span><span class="cx">     void hiddenPageDOMTimerThrottlingStateChanged();
</span><span class="cx">     void setTimerThrottlingEnabled(bool);
</span><span class="cx">     void setDOMTimerAlignmentInterval(double);
</span><del>-    void timerAlignmentIntervalTimerFired();
</del><ins>+    void timerAlignmentIntervalIncreaseTimerFired();
</ins><span class="cx"> 
</span><span class="cx">     const std::unique_ptr&lt;Chrome&gt; m_chrome;
</span><span class="cx">     const std::unique_ptr&lt;DragCaretController&gt; m_dragCaretController;
</span><span class="lines">@@ -609,8 +610,9 @@
</span><span class="cx">     ViewMode m_viewMode;
</span><span class="cx"> #endif // ENABLE(VIEW_MODE_CSS_MEDIA)
</span><span class="cx"> 
</span><del>-    bool m_timerThrottlingEnabled;
</del><ins>+    Optional&lt;double&gt; m_timerThrottlingEnabledTime;
</ins><span class="cx">     double m_timerAlignmentInterval;
</span><ins>+    Timer m_timerAlignmentIntervalIncreaseTimer;
</ins><span class="cx"> 
</span><span class="cx">     bool m_isEditable;
</span><span class="cx">     bool m_isPrerender;
</span></span></pre></div>
<a id="trunkSourceWebCorepageSettingscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/Settings.cpp (197005 => 197006)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/Settings.cpp        2016-02-24 00:30:48 UTC (rev 197005)
+++ trunk/Source/WebCore/page/Settings.cpp        2016-02-24 00:32:40 UTC (rev 197006)
</span><span class="lines">@@ -681,6 +681,15 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+void Settings::setHiddenPageDOMTimerThrottlingAutoIncreases(bool flag)
+{
+    if (m_hiddenPageDOMTimerThrottlingAutoIncreases == flag)
+        return;
+    m_hiddenPageDOMTimerThrottlingAutoIncreases = flag;
+    if (m_page)
+        m_page-&gt;hiddenPageDOMTimerThrottlingStateChanged();
+}
+
</ins><span class="cx"> void Settings::setHiddenPageCSSAnimationSuspensionEnabled(bool flag)
</span><span class="cx"> {
</span><span class="cx">     if (m_hiddenPageCSSAnimationSuspensionEnabled == flag)
</span></span></pre></div>
<a id="trunkSourceWebCorepageSettingsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/Settings.h (197005 => 197006)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/Settings.h        2016-02-24 00:30:48 UTC (rev 197005)
+++ trunk/Source/WebCore/page/Settings.h        2016-02-24 00:32:40 UTC (rev 197006)
</span><span class="lines">@@ -165,6 +165,8 @@
</span><span class="cx">     bool hiddenPageDOMTimerThrottlingEnabled() const { return m_hiddenPageDOMTimerThrottlingEnabled; }
</span><span class="cx">     WEBCORE_EXPORT void setHiddenPageDOMTimerThrottlingEnabled(bool);
</span><span class="cx"> #endif
</span><ins>+    bool hiddenPageDOMTimerThrottlingAutoIncreases() const { return m_hiddenPageDOMTimerThrottlingAutoIncreases; }
+    WEBCORE_EXPORT void setHiddenPageDOMTimerThrottlingAutoIncreases(bool);
</ins><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT void setUsesPageCache(bool);
</span><span class="cx">     bool usesPageCache() const { return m_usesPageCache; }
</span><span class="lines">@@ -345,6 +347,8 @@
</span><span class="cx">     bool m_resourceUsageOverlayVisible { false };
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    bool m_hiddenPageDOMTimerThrottlingAutoIncreases { false };
+
</ins><span class="cx"> #if USE(AVFOUNDATION)
</span><span class="cx">     WEBCORE_EXPORT static bool gAVFoundationEnabled;
</span><span class="cx">     WEBCORE_EXPORT static bool gAVFoundationNSURLSessionEnabled;
</span></span></pre>
</div>
</div>

</body>
</html>