diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 18f9b05f49b..6eb57c13c3a 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -4453,7 +4453,9 @@ nsGlobalWindow::Print() printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings)); } + EnterModalState(); webBrowserPrint->Print(printSettings, nsnull); + LeaveModalState(); PRBool savePrintSettings = nsContentUtils::GetBoolPref("print.save_print_settings", PR_FALSE); @@ -5640,6 +5642,13 @@ nsGlobalWindow::EnterModalState() } } topWin->mModalStateDepth++; + + JSContext *cx = nsContentUtils::GetCurrentJSContext(); + + nsIScriptContext *scx; + if (cx && (scx = GetScriptContextFromJSContext(cx))) { + scx->EnterModalState(); + } } // static @@ -5743,6 +5752,13 @@ nsGlobalWindow::LeaveModalState() mSuspendedDoc = nsnull; } } + + JSContext *cx = nsContentUtils::GetCurrentJSContext(); + + nsIScriptContext *scx; + if (cx && (scx = GetScriptContextFromJSContext(cx))) { + scx->LeaveModalState(); + } } PRBool diff --git a/dom/base/nsIScriptContext.h b/dom/base/nsIScriptContext.h index c0a54d91a45..f72ec7aa6da 100644 --- a/dom/base/nsIScriptContext.h +++ b/dom/base/nsIScriptContext.h @@ -56,10 +56,10 @@ class nsScriptObjectHolder; typedef void (*nsScriptTerminationFunc)(nsISupports* aRef); +// 87482b5e-e019-4df5-9bc2-b2a51b1f2d28 #define NS_ISCRIPTCONTEXT_IID \ -{ /* {09316a0e-8d05-4d26-9efd-8f907a7c79d2} */ \ - 0x09316a0e, 0x8d05, 0x4d26, \ - { 0x9e, 0xfd, 0x8f, 0x90, 0x7a, 0x7c, 0x79, 0xd2 } } +{ 0x87482b5e, 0xe019, 0x4df5, \ + { 0x9b, 0xc2, 0xb2, 0xa5, 0x1b, 0x1f, 0x2d, 0x28 } } /* This MUST match JSVERSION_DEFAULT. This version stuff if we don't know what language we have is a little silly... */ @@ -456,6 +456,9 @@ public: */ virtual nsresult DropScriptObject(void *object) = 0; virtual nsresult HoldScriptObject(void *object) = 0; + + virtual void EnterModalState() = 0; + virtual void LeaveModalState() = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContext, NS_ISCRIPTCONTEXT_IID) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 017f067227d..8361d9db83b 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -906,11 +906,13 @@ nsJSContext::DOMOperationCallback(JSContext *cx) // ScriptEvaluated to be called, and clearing our operation callback time. // See bug 302333. PRTime callbackTime = ctx->mOperationCallbackTime; + PRTime modalStateTime = ctx->mModalStateTime; MaybeGC(cx); // Now restore the callback time and count, in case they got reset. ctx->mOperationCallbackTime = callbackTime; + ctx->mModalStateTime = modalStateTime; // Check to see if we are running OOM nsCOMPtr mem; @@ -965,15 +967,20 @@ nsJSContext::DOMOperationCallback(JSContext *cx) PRTime now = PR_Now(); - if (LL_IS_ZERO(callbackTime)) { + if (callbackTime == 0) { // Initialize mOperationCallbackTime to start timing how long the // script has run ctx->mOperationCallbackTime = now; return JS_TRUE; } - PRTime duration; - LL_SUB(duration, now, callbackTime); + if (ctx->mModalStateDepth) { + // We're waiting on a modal dialog, nothing more to do here. + + return JS_TRUE; + } + + PRTime duration = now - callbackTime; // Check the amount of time this script has been running, or if the // dialog is disabled. @@ -1153,6 +1160,46 @@ nsJSContext::DOMOperationCallback(JSContext *cx) return JS_FALSE; } +void +nsJSContext::EnterModalState() +{ + if (!mModalStateDepth) { + mModalStateTime = mOperationCallbackTime ? PR_Now() : 0; + } + ++mModalStateDepth; +} + +void +nsJSContext::LeaveModalState() +{ + if (!mModalStateDepth) { + NS_ERROR("Uh, mismatched LeaveModalState() call!"); + + return; + } + + --mModalStateDepth; + + // If we're still in a modal dialog, or mOperationCallbackTime is still + // uninitialized, do nothing. + if (mModalStateDepth || !mOperationCallbackTime) { + return; + } + + // If mOperationCallbackTime was set when we entered the first dialog + // (and mModalStateTime is thus non-zero), adjust mOperationCallbackTime + // to account for time spent in the dialog. + // If mOperationCallbackTime got set while the modal dialog was open, + // simply set mOperationCallbackTime to the closing time of the dialog so + // that we never adjust mOperationCallbackTime to be in the future. + if (mModalStateTime) { + mOperationCallbackTime += PR_Now() - mModalStateTime; + } + else { + mOperationCallbackTime = PR_Now(); + } +} + #define JS_OPTIONS_DOT_STR "javascript.options." static const char js_options_dot_str[] = JS_OPTIONS_DOT_STR; @@ -1275,7 +1322,9 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE) mNumEvaluations = 0; mTerminations = nsnull; mScriptsEnabled = PR_TRUE; - mOperationCallbackTime = LL_ZERO; + mOperationCallbackTime = 0; + mModalStateTime = 0; + mModalStateDepth = 0; mProcessingScriptTag = PR_FALSE; } @@ -3363,7 +3412,8 @@ nsJSContext::ScriptEvaluated(PRBool aTerminated) } if (aTerminated) { - mOperationCallbackTime = LL_ZERO; + mOperationCallbackTime = 0; + mModalStateTime = 0; } } diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index ca972acd8dd..05a67862d72 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -165,6 +165,9 @@ public: virtual nsresult DropScriptObject(void *object); virtual nsresult HoldScriptObject(void *object); + virtual void EnterModalState(); + virtual void LeaveModalState(); + NS_DECL_NSIXPCSCRIPTNOTIFY static void LoadStart(); @@ -288,6 +291,9 @@ private: PRUint32 mDefaultJSOptions; PRTime mOperationCallbackTime; + PRTime mModalStateTime; + PRUint32 mModalStateDepth; + // mGlobalWrapperRef is used only to hold a strong reference to the // global object wrapper while the nsJSContext is alive. This cuts // down on the number of rooting and unrooting calls XPConnect has