Bug 581072. Fix the handling of long timeouts across timeout suspend/resume and add APIs to suspend/resume timeouts from trusted script. r=jst
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 22 Jul 2010 17:33:37 -0400
changeset 48101 308a5a2782b0b2f538ffdcb8ea57754029b66aff
parent 48100 228c38e68ddace157f5610e0b8762a324b7b9b40
child 48102 9d16542a1af28778544ddd3e5947d4224fb4020e
push id14571
push userbzbarsky@mozilla.com
push dateThu, 22 Jul 2010 21:35:07 +0000
treeherdermozilla-central@9d16542a1af2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs581072
milestone2.0b3pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 581072. Fix the handling of long timeouts across timeout suspend/resume and add APIs to suspend/resume timeouts from trusted script. r=jst
dom/base/nsDOMWindowUtils.cpp
dom/base/nsGlobalWindow.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
dom/tests/mochitest/bugs/Makefile.in
dom/tests/mochitest/bugs/test_bug581072.html
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1377,8 +1377,32 @@ nsDOMWindowUtils::GetCurrentInnerWindowI
   NS_ASSERTION(mWindow->IsOuterWindow(), "How did that happen?");
   nsGlobalWindow* inner = mWindow->GetCurrentInnerWindowInternal();
   if (!inner) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   *aWindowID = inner->mWindowID;
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsDOMWindowUtils::SuspendTimeouts()
+{
+  if (!IsUniversalXPConnectCapable()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  mWindow->SuspendTimeouts();
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::ResumeTimeouts()
+{
+  if (!IsUniversalXPConnectCapable()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  mWindow->ResumeTimeouts();
+
+  return NS_OK;
+}
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -9133,17 +9133,17 @@ nsGlobalWindow::SuspendTimeouts(PRUint32
     if (dts) {
       dts->SuspendWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
     }
   
     TimeStamp now = TimeStamp::Now();
     for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
       // Set mTimeRemaining to be the time remaining for this timer.
       if (t->mWhen > now)
-        t->mTimeRemaining = now - t->mWhen;
+        t->mTimeRemaining = t->mWhen - now;
       else
         t->mTimeRemaining = TimeDuration(0);
   
       // Drop the XPCOM timer; we'll reschedule when restoring the state.
       if (t->mTimer) {
         t->mTimer->Cancel();
         t->mTimer = nsnull;
   
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -48,17 +48,17 @@
 interface nsIDOMNode;
 interface nsIDOMNodeList;
 interface nsIDOMElement;
 interface nsIDOMHTMLCanvasElement;
 interface nsIDOMEvent;
 interface nsITransferable;
 interface nsIQueryContentEventResult;
 
-[scriptable, uuid(a6dbdbc9-5564-4e52-820a-4056c698f699)]
+[scriptable, uuid(1e042706-0343-4cba-a549-6a83eefb1835)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -686,9 +686,15 @@ interface nsIDOMWindowUtils : nsISupport
    * delivered.
    */
   void leaveModalState();
 
   /**
    * Is the window is in a modal state? [See enterModalState()]
    */
   boolean isInModalState();
+
+  /**
+   * Suspend/resume timeouts on this window and its descendant windows.
+   */
+  void suspendTimeouts();
+  void resumeTimeouts();
 };
--- a/dom/tests/mochitest/bugs/Makefile.in
+++ b/dom/tests/mochitest/bugs/Makefile.in
@@ -112,12 +112,13 @@ include $(topsrcdir)/config/rules.mk
 		test_bug531542.html \
 		test_bug456151.html \
 		test_bug534149.html \
 		test_bug558973.html \
 		test_bug563487.html \
 		test_bug545314.html \
 		test_bug548828.html \
 		test_DOMWindowCreated_chromeonly.html \
+		test_bug581072.html \
 		$(NULL)
 
 libs:: 	$(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/bugs/test_bug581072.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=581072
+-->
+<head>
+  <title>Test for Bug 581072</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=581072">Mozilla Bug 581072</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+  
+/** Test for Bug 581072 **/
+var longTimerFired = 0;
+
+// Set up a one-hour timeout
+setTimeout(function() { longTimerFired = true; }, 3600000);
+
+// Trigger suspend and resume timeouts
+(function() {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                    .getInterface(Components.interfaces.nsIDOMWindowUtils);
+  utils.suspendTimeouts();  
+  utils.resumeTimeouts();  
+})()
+
+// Now set up another timeout which should fire before the one-hour one
+setTimeout(function() {
+  is(longTimerFired, false, "One-hour timer should not fire before our 0ms one");
+  SimpleTest.finish();
+}, 0);
+
+
+
+</script>
+</pre>
+</body>
+</html>