diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 8bff930388a7..3c9cd240c8a5 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -531,6 +531,9 @@ @BINPATH@/components/Push.manifest @BINPATH@/components/PushServiceLauncher.js +@BINPATH@/components/SlowScriptDebug.manifest +@BINPATH@/components/SlowScriptDebug.js + #ifndef RELEASE_BUILD @BINPATH@/components/InterAppComm.manifest @BINPATH@/components/InterAppCommService.js diff --git a/dom/base/SlowScriptDebug.js b/dom/base/SlowScriptDebug.js new file mode 100644 index 000000000000..c9603abe2aee --- /dev/null +++ b/dom/base/SlowScriptDebug.js @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +function SlowScriptDebug() { } + +SlowScriptDebug.prototype = { + classID: Components.ID("{e740ddb4-18b4-4aac-8ae1-9b0f4320769d}"), + classDescription: "Slow script debug handler", + contractID: "@mozilla.org/dom/slow-script-debug;1", + QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISlowScriptDebug]), + + get activationHandler() { return this._activationHandler; }, + set activationHandler(cb) { return this._activationHandler = cb; }, +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SlowScriptDebug]); diff --git a/dom/base/SlowScriptDebug.manifest b/dom/base/SlowScriptDebug.manifest new file mode 100644 index 000000000000..f84fd837dfd0 --- /dev/null +++ b/dom/base/SlowScriptDebug.manifest @@ -0,0 +1,2 @@ +component {e740ddb4-18b4-4aac-8ae1-9b0f4320769d} SlowScriptDebug.js +contract @mozilla.org/dom/slow-script-debug;1 {e740ddb4-18b4-4aac-8ae1-9b0f4320769d} diff --git a/dom/base/moz.build b/dom/base/moz.build index efed5169cf77..e72c4040f1af 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -13,6 +13,7 @@ XPIDL_SOURCES += [ 'nsIEntropyCollector.idl', 'nsIScriptChannel.idl', 'nsISiteSpecificUserAgent.idl', + 'nsISlowScriptDebug.idl', ] XPIDL_MODULE = 'dom' @@ -128,6 +129,8 @@ EXTRA_COMPONENTS += [ 'ConsoleAPIStorage.js', 'SiteSpecificUserAgent.js', 'SiteSpecificUserAgent.manifest', + 'SlowScriptDebug.js', + 'SlowScriptDebug.manifest', ] EXTRA_JS_MODULES += [ diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index eead7a548103..c86957221657 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -35,6 +35,7 @@ #include "nsIScriptTimeoutHandler.h" #include "nsIController.h" #include "nsScriptNameSpaceManager.h" +#include "nsISlowScriptDebug.h" #include "nsWindowMemoryReporter.h" #include "WindowNamedPropertiesHandler.h" @@ -10769,27 +10770,43 @@ nsGlobalWindow::ShowSlowScriptDialog() unsigned lineno; bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno); - bool debugPossible = hasFrame && js::CanCallContextDebugHandler(cx); -#ifdef MOZ_JSDEBUGGER - // Get the debugger service if necessary. - if (debugPossible) { - bool jsds_IsOn = false; - const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1"; - nsCOMPtr jsdHook; - nsCOMPtr jsds = do_GetService(jsdServiceCtrID, &rv); + // Prioritize the SlowScriptDebug interface over JSD1. + nsCOMPtr debugCallback; + bool oldDebugPossible = false; - // Check if there's a user for the debugger service that's 'on' for us + if (hasFrame) { + const char *debugCID = "@mozilla.org/dom/slow-script-debug;1"; + nsCOMPtr debugService = do_GetService(debugCID, &rv); if (NS_SUCCEEDED(rv)) { - jsds->GetDebuggerHook(getter_AddRefs(jsdHook)); - jsds->GetIsOn(&jsds_IsOn); + debugService->GetActivationHandler(getter_AddRefs(debugCallback)); } - // If there is a debug handler registered for this runtime AND - // ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs))) - // then something useful will be done with our request to debug. - debugPossible = ((jsds_IsOn && (jsdHook != nullptr)) || !jsds_IsOn); - } + if (!debugCallback) { + oldDebugPossible = js::CanCallContextDebugHandler(cx); +#ifdef MOZ_JSDEBUGGER + // Get the debugger service if necessary. + if (oldDebugPossible) { + bool jsds_IsOn = false; + const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1"; + nsCOMPtr jsdHook; + nsCOMPtr jsds = do_GetService(jsdServiceCtrID, &rv); + + // Check if there's a user for the debugger service that's 'on' for us + if (NS_SUCCEEDED(rv)) { + jsds->GetDebuggerHook(getter_AddRefs(jsdHook)); + jsds->GetIsOn(&jsds_IsOn); + } + + // If there is a debug handler registered for this runtime AND + // ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs))) + // then something useful will be done with our request to debug. + oldDebugPossible = ((jsds_IsOn && (jsdHook != nullptr)) || !jsds_IsOn); + } #endif + } + } + + bool showDebugButton = debugCallback || oldDebugPossible; // Get localizable strings nsXPIDLString title, msg, stopButton, waitButton, debugButton, neverShowDlg; @@ -10820,7 +10837,7 @@ nsGlobalWindow::ShowSlowScriptDialog() } - if (debugPossible) { + if (showDebugButton) { tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES, "DebugScriptButton", debugButton); @@ -10846,7 +10863,7 @@ nsGlobalWindow::ShowSlowScriptDialog() // GetStringFromName can return NS_OK and still give nullptr string if (NS_FAILED(rv) || !title || !msg || !stopButton || !waitButton || - (!debugButton && debugPossible) || !neverShowDlg) { + (!debugButton && showDebugButton) || !neverShowDlg) { NS_ERROR("Failed to get localized strings."); return ContinueSlowScript; } @@ -10876,7 +10893,7 @@ nsGlobalWindow::ShowSlowScriptDialog() (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1)); // Add a third button if necessary. - if (debugPossible) + if (showDebugButton) buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2; // Null out the operation callback while we're re-entering JS here. @@ -10893,8 +10910,15 @@ nsGlobalWindow::ShowSlowScriptDialog() if (NS_SUCCEEDED(rv) && (buttonPressed == 0)) { return neverShowDlgChk ? AlwaysContinueSlowScript : ContinueSlowScript; } - if ((buttonPressed == 2) && debugPossible) { - return js_CallContextDebugHandler(cx) ? ContinueSlowScript : KillSlowScript; + if (buttonPressed == 2) { + if (debugCallback) { + rv = debugCallback->HandleSlowScriptDebug(this); + return NS_SUCCEEDED(rv) ? ContinueSlowScript : KillSlowScript; + } + + if (oldDebugPossible) { + return js_CallContextDebugHandler(cx) ? ContinueSlowScript : KillSlowScript; + } } JS_ClearPendingException(cx); return KillSlowScript; diff --git a/dom/base/nsISlowScriptDebug.idl b/dom/base/nsISlowScriptDebug.idl new file mode 100644 index 000000000000..91e91086f332 --- /dev/null +++ b/dom/base/nsISlowScriptDebug.idl @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIDOMWindow; + +[scriptable, function, uuid(f7dbb80c-5d1e-4fd9-b55c-a9ffda4a75b1)] +interface nsISlowScriptDebugCallback : nsISupports +{ + void handleSlowScriptDebug(in nsIDOMWindow aWindow); +}; + +[scriptable, uuid(f75d4164-3aa7-4395-ba44-a5f95b2e8427)] +interface nsISlowScriptDebug : nsISupports +{ + attribute nsISlowScriptDebugCallback activationHandler; +};