Bug 261633: treat setInterval('foo()') as setTimeout('foo()', 0) to match IE and avoid recursive timeouts, r+sr=jst
authorgavin@gavinsharp.com
Tue, 03 Jul 2007 15:38:04 -0700
changeset 3106 3ce7e9699bc7026229c8ba1422d5d6b742f026af
parent 3105 b84388393d8cf12c6498392845149bc881269b6d
child 3107 003f45bcaa337cda1c4b7134bd817b302d55fa14
push idunknown
push userunknown
push dateunknown
bugs261633
milestone1.9a7pre
Bug 261633: treat setInterval('foo()') as setTimeout('foo()', 0) to match IE and avoid recursive timeouts, r+sr=jst
dom/src/base/nsGlobalWindow.cpp
dom/src/base/nsGlobalWindow.h
dom/src/base/nsJSTimeoutHandler.cpp
--- a/dom/src/base/nsGlobalWindow.cpp
+++ b/dom/src/base/nsGlobalWindow.cpp
@@ -6666,25 +6666,26 @@ nsGlobalWindow::SetTimeoutOrInterval(nsI
 
 nsresult
 nsGlobalWindow::SetTimeoutOrInterval(PRBool aIsInterval, PRInt32 *aReturn)
 {
   FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
                    NS_ERROR_NOT_INITIALIZED);
 
   PRInt32 interval = 0;
+  PRBool isInterval = aIsInterval;
   nsCOMPtr<nsIScriptTimeoutHandler> handler;
   nsresult rv = NS_CreateJSTimeoutHandler(GetContextInternal(),
-                                          aIsInterval,
+                                          &isInterval,
                                           &interval,
                                           getter_AddRefs(handler));
   if (NS_FAILED(rv))
     return (rv == NS_ERROR_DOM_TYPE_ERR) ? NS_OK : rv;
 
-  return SetTimeoutOrInterval(handler, interval, aIsInterval, aReturn);
+  return SetTimeoutOrInterval(handler, interval, isInterval, aReturn);
 }
 
 // static
 void
 nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
 {
   // If a modal dialog is open for this window, return early. Pending
   // timeouts will run when the modal dialog is dismissed.
--- a/dom/src/base/nsGlobalWindow.h
+++ b/dom/src/base/nsGlobalWindow.h
@@ -124,17 +124,17 @@ class nsDOMOfflineResourceList;
 enum OpenAllowValue {
   allowNot = 0,     // the window opening is denied
   allowNoAbuse,     // allowed: not a popup
   allowWhitelisted  // allowed: it's whitelisted or popup blocking is disabled
 };
 
 extern nsresult
 NS_CreateJSTimeoutHandler(nsIScriptContext *aContext,
-                          PRBool aIsInterval,
+                          PRBool *aIsInterval,
                           PRInt32 *aInterval,
                           nsIScriptTimeoutHandler **aRet);
 
 /*
  * Timeout struct that holds information about each script
  * timeout.  Holds a strong reference to an nsIScriptTimeoutHandler, which
  * abstracts the language specific cruft.
  */
--- a/dom/src/base/nsJSTimeoutHandler.cpp
+++ b/dom/src/base/nsJSTimeoutHandler.cpp
@@ -82,17 +82,17 @@ public:
 
   virtual nsIArray *GetArgv() {
     return mArgv;
   }
   // Called by the timeout mechanism so the secret 'lateness' arg can be
   // added.
   virtual void SetLateness(PRIntervalTime aHowLate);
 
-  nsresult Init(nsIScriptContext *aContext, PRBool aIsInterval,
+  nsresult Init(nsIScriptContext *aContext, PRBool *aIsInterval,
                 PRInt32 *aInterval);
 
   void ReleaseJSObjects();
 
 private:
 
   nsCOMPtr<nsIScriptContext> mContext;
 
@@ -192,17 +192,17 @@ nsJSScriptTimeoutHandler::ReleaseJSObjec
       mFunObj = nsnull;
     } else {
       NS_WARNING("No func and no expr - roots may not have been removed");
     }
   }
 }
 
 nsresult
-nsJSScriptTimeoutHandler::Init(nsIScriptContext *aContext, PRBool aIsInterval,
+nsJSScriptTimeoutHandler::Init(nsIScriptContext *aContext, PRBool *aIsInterval,
                                PRInt32 *aInterval)
 {
   if (!aContext) {
     // This window was already closed, or never properly initialized,
     // don't let a timer be scheduled on such a window.
 
     return NS_ERROR_NOT_INITIALIZED;
   }
@@ -231,47 +231,53 @@ nsJSScriptTimeoutHandler::Init(nsIScript
   JSString *expr = nsnull;
   JSObject *funobj = nsnull;
   int32 interval = 0;
 
   JSAutoRequest ar(cx);
 
   if (argc < 1) {
     ::JS_ReportError(cx, "Function %s requires at least 1 parameter",
-                     aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
+                     *aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
 
     ncc->SetExceptionWasThrown(PR_TRUE);
     return NS_ERROR_DOM_TYPE_ERR;
   }
 
   if (argc > 1 && !::JS_ValueToECMAInt32(cx, argv[1], &interval)) {
     ::JS_ReportError(cx,
                      "Second argument to %s must be a millisecond interval",
                      aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
 
     ncc->SetExceptionWasThrown(PR_TRUE);
     return NS_ERROR_DOM_TYPE_ERR;
   }
 
+  if (argc == 1) {
+    // If no interval was specified, treat this like a timeout, to avoid
+    // setting an interval of 0 milliseconds.
+    *aIsInterval = PR_FALSE;
+  }
+
   switch (::JS_TypeOfValue(cx, argv[0])) {
   case JSTYPE_FUNCTION:
     funobj = JSVAL_TO_OBJECT(argv[0]);
     break;
 
   case JSTYPE_STRING:
   case JSTYPE_OBJECT:
     expr = ::JS_ValueToString(cx, argv[0]);
     if (!expr)
       return NS_ERROR_OUT_OF_MEMORY;
     argv[0] = STRING_TO_JSVAL(expr);
     break;
 
   default:
     ::JS_ReportError(cx, "useless %s call (missing quotes around argument?)",
-                     aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
+                     *aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
 
     // Return an error that nsGlobalWindow can recognize and turn into NS_OK.
     ncc->SetExceptionWasThrown(PR_TRUE);
     return NS_ERROR_DOM_TYPE_ERR;
   }
 
   if (expr) {
     if (!::JS_AddNamedRoot(cx, &mExpr, "timeout.mExpr")) {
@@ -342,17 +348,17 @@ const PRUnichar *
 nsJSScriptTimeoutHandler::GetHandlerText()
 {
   NS_ASSERTION(mExpr, "No expression, so no handler text!");
   return NS_REINTERPRET_CAST(const PRUnichar *,
                              ::JS_GetStringChars(mExpr));
 }
 
 nsresult NS_CreateJSTimeoutHandler(nsIScriptContext *aContext,
-                                   PRBool aIsInterval,
+                                   PRBool *aIsInterval,
                                    PRInt32 *aInterval,
                                    nsIScriptTimeoutHandler **aRet)
 {
   *aRet = nsnull;
   nsJSScriptTimeoutHandler *handler = new nsJSScriptTimeoutHandler();
   if (!handler)
     return NS_ERROR_OUT_OF_MEMORY;