Bug 646972. Clamp the timeout interval after storing mInterval on the nsTimeout, so interval timers will correctly speed up when a tab goes from background to foreground. r=jst
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 04 Apr 2011 16:22:48 -0700
changeset 64670 299615ca371a3e17c57e60411564df1db6db35d6
parent 64669 5e74b6d598e762b661bbb1cb5841f590cdbea098
child 64671 77415b6ad9da8b484c1a6358802e193e2e15b201
push idunknown
push userunknown
push dateunknown
reviewersjst
bugs646972
milestone2.2a1pre
Bug 646972. Clamp the timeout interval after storing mInterval on the nsTimeout, so interval timers will correctly speed up when a tab goes from background to foreground. r=jst
dom/base/nsGlobalWindow.cpp
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8729,49 +8729,48 @@ nsGlobalWindow::SetTimeoutOrInterval(nsI
                    NS_ERROR_NOT_INITIALIZED);
 
   // If we don't have a document (we could have been unloaded since
   // the call to setTimeout was made), do nothing.
   if (!mDocument) {
     return NS_OK;
   }
 
-  PRUint32 nestingLevel = sNestingLevel + 1;
-  if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
-    // Don't allow timeouts less than DOMMinTimeoutValue() from
-    // now...
-    interval = NS_MAX(interval, DOMMinTimeoutValue());
-  }
-  else if (interval < 0) {
-    // Clamp negative intervals to 0.
-    interval = 0;
-  }
-
-  NS_ASSERTION(interval >= 0, "DOMMinTimeoutValue() lies");
-  PRUint32 realInterval = interval;
-
-  // Make sure we don't proceed with a interval larger than our timer
+  // Disallow negative intervals.  If aIsInterval also disallow 0,
+  // because we use that as a "don't repeat" flag.
+  interval = NS_MAX(aIsInterval ? 1 : 0, interval);
+
+  // Make sure we don't proceed with an interval larger than our timer
   // code can handle.
-  if (realInterval > PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE)) {
-    realInterval = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
+  if (interval > PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE)) {
+    interval = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
   }
 
   nsTimeout *timeout = new nsTimeout();
   if (!timeout)
     return NS_ERROR_OUT_OF_MEMORY;
 
   // Increment the timeout's reference count to represent this function's hold
   // on the timeout.
   timeout->AddRef();
 
   if (aIsInterval) {
-    timeout->mInterval = realInterval;
+    timeout->mInterval = interval;
   }
   timeout->mScriptHandler = aHandler;
 
+  // Now clamp the actual interval we will use for the timer based on
+  PRUint32 nestingLevel = sNestingLevel + 1;
+  PRInt32 realInterval = interval;
+  if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
+    // Don't allow timeouts less than DOMMinTimeoutValue() from
+    // now...
+    realInterval = NS_MAX(realInterval, DOMMinTimeoutValue());
+  }
+
   // Get principal of currently executing code, save for execution of timeout.
   // If our principals subsume the subject principal then use the subject
   // principal. Otherwise, use our principal to avoid running script in
   // elevated principals.
 
   nsCOMPtr<nsIPrincipal> subjectPrincipal;
   nsresult rv;
   rv = nsContentUtils::GetSecurityManager()->
@@ -8852,16 +8851,19 @@ nsGlobalWindow::SetTimeoutOrInterval(nsI
     // This timeout is *not* set from another timeout and it's set
     // while popups are enabled. Propagate the state to the timeout if
     // its delay (interval) is equal to or less than what
     // "dom.disable_open_click_delay" is set to (in ms).
 
     PRInt32 delay =
       nsContentUtils::GetIntPref("dom.disable_open_click_delay");
 
+    // This is checking |interval|, not realInterval, on purpose,
+    // because our lower bound for |realInterval| could be pretty high
+    // in some cases.
     if (interval <= delay) {
       timeout->mPopupState = gPopupControlState;
     }
   }
 
   InsertTimeoutIntoList(timeout);
 
   timeout->mPublicId = ++mTimeoutPublicIdCounter;