Bug 1354679 - Use highlighter actor from client instead of from the server draft
authoryulia <ystartsev@mozilla.com>
Fri, 17 Nov 2017 20:25:04 +0100
changeset 699818 74ba27d85dce13d6df02d4bc8f291f9997dd6f32
parent 684715 8d79d2611fbd6e7c71bb1e1a13ace04b6c1084d3
child 740745 bb64b8cead0fc24abde0f90f2a5f331e7e015c92
push id89698
push userbmo:ystartsev@mozilla.com
push dateFri, 17 Nov 2017 20:23:33 +0000
bugs1354679
milestone58.0a1
Bug 1354679 - Use highlighter actor from client instead of from the server MozReview-Commit-ID: J8DEwNJgpE9
devtools/client/framework/attach-thread.js
devtools/client/framework/toolbox-highlighter-utils.js
devtools/client/framework/toolbox.js
devtools/client/locales/en-US/debugger.properties
devtools/server/actors/script.js
devtools/shared/locales/en-US/debugger.properties
--- a/devtools/client/framework/attach-thread.js
+++ b/devtools/client/framework/attach-thread.js
@@ -5,42 +5,50 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {Cc, Ci, Cu} = require("chrome");
 const Services = require("Services");
 const defer = require("devtools/shared/defer");
 
 const {LocalizationHelper} = require("devtools/shared/l10n");
 const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
+const debuggerL10N = new LocalizationHelper("devtools/client/locales/debugger.properties");
 
 function handleThreadState(toolbox, event, packet) {
   // Suppress interrupted events by default because the thread is
   // paused/resumed a lot for various actions.
   if (event !== "paused" || packet.why.type !== "interrupted") {
     // TODO: Bug 1225492, we continue emitting events on the target
     // like we used to, but we should emit these only on the
     // threadClient now.
     toolbox.target.emit("thread-" + event);
   }
 
   if (event === "paused") {
     toolbox.highlightTool("jsdebugger");
 
     if (packet.why.type === "debuggerStatement" ||
        packet.why.type === "breakpoint" ||
-       packet.why.type === "exception") {
+       packet.why.type === "exception")
+    {
       toolbox.raise();
       toolbox.selectTool("jsdebugger");
-      toolbox._threadClient.clientPaused();
+
+      // TODO: move this to the frontend so we can make use of the paused reason
+      // directly
+      const reason = debuggerL10N.getStr("defaultPausedReason");
+      toolbox.highlighterUtils.showPausedOverlay(reason);
     }
   } else if (event === "resumed") {
+    toolbox.highlighterUtils.hidePausedOverlay();
     toolbox.unhighlightTool("jsdebugger");
   }
 }
 
+
 function attachThread(toolbox) {
   let deferred = defer();
 
   let target = toolbox.target;
   let { form: { chromeDebugger, actor } } = target;
 
   // Sourcemaps are always turned off when using the new debugger
   // frontend. This is because it does sourcemapping on the
--- a/devtools/client/framework/toolbox-highlighter-utils.js
+++ b/devtools/client/framework/toolbox-highlighter-utils.js
@@ -84,16 +84,53 @@ exports.getHighlighterUtils = function (
         yield toolbox.initInspector();
         isInspectorInitialized = true;
       }
       return yield generator.apply(null, args);
     });
   };
 
   /**
+   * Show/hide the paused overlays for a collection of tabs
+   * @param {TabActor} tabActor - Optionally focus the content area once the picker is
+   */
+
+  /*
+   * Manage a collection of PausedDebuggerOverlay highlighters and their HighlighterEnvironments indexed
+   * by TabActors (export it so it the paused state can be tested).
+   */
+  const pausedStateOverlays = new Map();
+
+  async function _getPausedStateOverlay(tabActor) {
+    if (pausedStateOverlays.has(tabActor)) {
+      return pausedStateOverlays.get(tabActor).overlay;
+    }
+    const overlay = await exported.getHighlighterByType("PausedDebuggerOverlay");
+    pausedStateOverlays.set(tabActor, { overlay });
+
+    return overlay;
+  }
+
+  exported.showPausedOverlay = async function (reason) {
+    let overlay = await _getPausedStateOverlay(target.activeTab);
+    // get the root node for the tab, where the highlighter will be displayed
+    let nodeFront = await toolbox.inspector.walker.getRootNode();
+    overlay.show(nodeFront, {reason});
+  };
+
+  exported.hidePausedOverlay = function () {
+    const overlayAndEnvironment = pausedStateOverlays.get(target.activeTab);
+    if (!overlayAndEnvironment) {
+      return;
+    }
+
+    overlayAndEnvironment.overlay.hide();
+  };
+
+  /**
    * Start/stop the element picker on the debuggee target.
    * @param {Boolean} doFocus - Optionally focus the content area once the picker is
    *                            activated.
    * @return A promise that resolves when done
    */
   exported.togglePicker = function (doFocus) {
     if (isPicking) {
       return cancelPicker();
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -428,19 +428,19 @@ Toolbox.prototype = {
       // Start tracking network activity on toolbox open for targets such as tabs.
       // (Workers and potentially others don't manage the console client in the target.)
       if (this._target.activeConsole) {
         yield this._target.activeConsole.startListeners([
           "NetworkActivity",
         ]);
       }
 
+      yield domReady.promise;
       // Attach the thread
       this._threadClient = yield attachThread(this);
-      yield domReady.promise;
 
       this.isReady = true;
 
       let framesPromise = this._listFrames();
 
       Services.prefs.addObserver("devtools.cache.disabled", this._applyCacheSettings);
       Services.prefs.addObserver("devtools.serviceWorkers.testing.enabled",
                                  this._applyServiceWorkersTestingSettings);
--- a/devtools/client/locales/en-US/debugger.properties
+++ b/devtools/client/locales/en-US/debugger.properties
@@ -543,16 +543,21 @@ ignoreExceptions=Ignore exceptions. Clic
 # LOCALIZATION NOTE (pauseOnUncaughtExceptions): The pause on exceptions button
 # tooltip when the debugger will pause on uncaught exceptions.
 pauseOnUncaughtExceptions=Pause on uncaught exceptions. Click to pause on all exceptions
 
 # LOCALIZATION NOTE (pauseOnExceptions): The pause on exceptions button tooltip
 # when the debugger will pause on all exceptions.
 pauseOnExceptions=Pause on all exceptions. Click to ignore exceptions
 
+# LOCALIZATION NOTE (defaultPausedReason): Text displayed inside the content page, in an
+# overlay, when the debugger is paused (so script execution is paused), explaining to the
+# user why the page is paused.
+defaultPausedReason=Paused in debugger
+
 # LOCALIZATION NOTE (loadingText): The text that is displayed in the script
 # editor when the loading process has started but there is no file to display
 # yet.
 loadingText=Loading\u2026
 
 # LOCALIZATION NOTE (errorLoadingText3): The text that is displayed in the debugger
 # viewer when there is an error loading a file
 errorLoadingText3=Error loading this URI: %S
--- a/devtools/server/actors/script.js
+++ b/devtools/server/actors/script.js
@@ -424,18 +424,16 @@ const ThreadActor = ActorClassWithSpec(t
     this._frameActors = [];
     this._parent = parent;
     this._dbg = null;
     this._gripDepth = 0;
     this._threadLifetimePool = null;
     this._tabClosed = false;
     this._scripts = null;
     this._pauseOnDOMEvents = null;
-    EventEmitter.decorate(this);
-    attachPauseStateListeners(this)
 
     this._options = {
       useSourceMaps: false,
       autoBlackBox: false
     };
 
     this.breakpointActorMap = new BreakpointActorMap();
     this.sourceActorStore = new SourceActorStore();
@@ -602,17 +600,16 @@ const ThreadActor = ActorClassWithSpec(t
     this._dbg.enabled = false;
     this._dbg = null;
   },
 
   /**
    * destroy the debugger and put the actor in the exited state.
    */
   exit: function () {
-    this.emit("exited");
     this.destroy();
     this._state = "exited";
   },
 
   // Request handlers
   onAttach: function (request) {
     if (this.state === "exited") {
       return { type: "exited" };
@@ -1223,24 +1220,16 @@ const ThreadActor = ActorClassWithSpec(t
   _getNextStepFrame: function (frame) {
     let stepFrame = frame.reportedPop ? frame.older : frame;
     if (!stepFrame || !stepFrame.script) {
       stepFrame = null;
     }
     return stepFrame;
   },
 
-  /**
-   * Client informs the server that we have a user significant pause.
-   */
-  onClientPaused: function () {
-    this.emit("clientPaused");
-    return { type: "clientPaused" };
-  },
-
   onClientEvaluate: function (request) {
     if (this.state !== "paused") {
       return { error: "wrongState",
                message: "Debuggee must be paused to evaluate code." };
     }
 
     let frame = this._requestFrame(request.frame);
     if (!frame) {
@@ -1604,17 +1593,16 @@ const ThreadActor = ActorClassWithSpec(t
     if (poppedFrames) {
       packet.poppedFrames = poppedFrames;
     }
 
     return packet;
   },
 
   _resumed: function () {
-    this.emit('resumed');
     this._state = "running";
 
     // Drop the actors in the pause actor pool.
     this.conn.removeActorPool(this._pausePool);
 
     this._pausePool = null;
     this._pauseActor = null;
 
@@ -2391,101 +2379,8 @@ exports.unwrapDebuggerObjectGlobal = wra
     // that any dead object proxies make themselves known.
     let global = wrappedGlobal.unsafeDereference();
     Object.getPrototypeOf(global) + "";
     return global;
   } catch (e) {
     return undefined;
   }
 };
-
-// Manage a collection of PausedDebuggerOverlays and their HighlighterEnvironments indexed
-// by TabActors (export it so it the paused state can be tested).
-const pausedStateOverlays = exports.pausedStateOverlays = new Map();
-
-function attachPauseStateListeners(threadActor) {
-  EventEmitter.on(threadActor, "clientPaused", () => showPausedStateOverlay(threadActor._parent));
-  EventEmitter.on(threadActor, "resumed",() => hidePausedStateOverlay(threadActor._parent));
-  EventEmitter.on(threadActor, "exiting",() => destroyPausedStateOverlay(threadActor._parent));
-}
-
-/**
- * Get the instance of the PausedDebuggerOverlay for a TabActor.
- *
- * @param {TabActor} tabActor
- *        The parent of the threadActor.
- *
- * @return {PausedDebuggerOverlay}
- *         The instance of the overlay, or null if it can't be created in this TabActor.
- *         For instance, we can't insert an overlay when debugging the whole browser UI
- *         from the Browser Toolbox or a worker.
- */
-function getPausedStateOverlay(tabActor) {
-  if (pausedStateOverlays.has(tabActor)) {
-    return pausedStateOverlays.get(tabActor).overlay;
-  }
-
-  if (!tabActor.window || !tabActor.window.document) {
-    return null;
-  }
-
-  const principal = tabActor.window.document.nodePrincipal;
-  if (Services.scriptSecurityManager.isSystemPrincipal(principal)) {
-    return null;
-  }
-
-  require("devtools/server/actors/inspector");
-  const { HighlighterEnvironment } = require("devtools/server/actors/highlighters");
-  const { PausedDebuggerOverlay } = require("devtools/server/actors/highlighters/paused-debugger");
-
-  const environment = new HighlighterEnvironment();
-  environment.initFromTabActor(tabActor);
-
-  const overlay = new PausedDebuggerOverlay(environment);
-  pausedStateOverlays.set(tabActor, { overlay, environment });
-
-  return overlay;
-}
-
-/**
- * Show the PausedDebuggerOverlay, creating it first if it doesn't exist.
- *
- * @param {TabActor} tabActor
- *        The parent of the threadActor.
- */
-function showPausedStateOverlay(tabActor) {
-  let overlay = getPausedStateOverlay(tabActor);
-  if (overlay) {
-    // TODO: for now, the same reason is always shown. In the future, we would like to
-    // show the same reason that is also shown inside the debugger panel UI (using the
-    // code in aReason.type). See the following issue for why we didn't do this already:
-    // https://github.com/devtools-html/debugger.html/pull/2581
-    overlay.show(null, {reason: l10n.GetStringFromName("debuggerPausedReason")});
-  }
-}
-
-/**
- * Hide the PausedDebuggerOverlay, if it was shown before.
- *
- * @param {TabActor} tabActor
- *        The parent of the threadActor.
- */
-function hidePausedStateOverlay(tabActor) {
-  // Check if it even exists first, if not we don't need to do anything.
-  const overlayAndEnvironment = pausedStateOverlays.get(tabActor);
-  if (!overlayAndEnvironment) {
-    return;
-  }
-
-  overlayAndEnvironment.overlay.hide();
-}
-
-/**
- * Destroy all PausedDebuggerOverlays instances and their HighlighterEnvironments too.
- * This is needed when we exit the debugger.
- */
-function destroyPausedStateOverlays() {
-  for (let { overlay, environment } of pausedStateOverlays.values()) {
-    overlay.destroy();
-    environment.destroy();
-  }
-  pausedStateOverlays.clear();
-}
--- a/devtools/shared/locales/en-US/debugger.properties
+++ b/devtools/shared/locales/en-US/debugger.properties
@@ -52,13 +52,8 @@ clientSendOOBHash=My Cert: %1$S
 clientSendOOBToken=Token: %1$S
 
 # LOCALIZATION NOTE (serverReceiveOOBTitle): The title displayed on the dialog
 # that instructs the user to provide an authentication token from the client.
 serverReceiveOOBTitle=Provide Client Token
 # LOCALIZATION NOTE (serverReceiveOOBBody): Main text displayed on the dialog
 # that instructs the user to provide an authentication token from the client.
 serverReceiveOOBBody=The client should be displaying a token value.  Enter that token value here to complete authentication with this client.
-
-# LOCALIZATION NOTE (debuggerPausedReason): Text displayed inside the content page, in an
-# overlay, when the debugger is paused (so script execution is paused), explaining to the
-# user why the page is paused.
-debuggerPausedReason=Paused in debugger