Bug 1538021 - Use owner of WindowEventDispatcher as window for messaging. r=yzen a=pascalc
authorEitan Isaacson <eitan@monotonous.org>
Sat, 23 Mar 2019 21:22:02 +0000
changeset 525809 4ebcdc4fd000d0fe0c4f9efd5b629c0bc4167b4e
parent 525808 afe17b3276dad6530086634cf49f09917d8aee44
child 525810 f97ab548d6f1f30cca81c743364ba560d50b8222
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyzen, pascalc
bugs1538021
milestone67.0
Bug 1538021 - Use owner of WindowEventDispatcher as window for messaging. r=yzen a=pascalc Differential Revision: https://phabricator.services.mozilla.com/D24442
accessible/jsat/AccessFu.jsm
accessible/jsat/ContentControl.jsm
accessible/jsat/Traversal.jsm
accessible/jsat/Utils.jsm
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -110,85 +110,91 @@ var AccessFu = {
     // Set up frame script
     let mm = win.messageManager;
     for (let messageName of Object.values(ACCESSFU_MESSAGE)) {
       mm.addMessageListener(messageName, this);
     }
     mm.loadFrameScript(FRAME_SCRIPT, true);
 
     win.addEventListener("TabSelect", this);
-    if (win.WindowEventDispatcher) {
+    if (win.WindowEventDispatcher && !this._eventDispatcherListeners.has(win)) {
+      const listener = (event, data, callback) => {
+        this.onEvent(event, data, callback, win);
+      };
+      this._eventDispatcherListeners.set(win, listener);
       // desktop mochitests don't have this.
-      win.WindowEventDispatcher.registerListener(this,
+      win.WindowEventDispatcher.registerListener(listener,
         Object.values(GECKOVIEW_MESSAGE));
     }
   },
 
   _detachWindow: function _detachWindow(win) {
     let mm = win.messageManager;
     mm.broadcastAsyncMessage("AccessFu:Stop");
     mm.removeDelayedFrameScript(FRAME_SCRIPT);
     for (let messageName of Object.values(ACCESSFU_MESSAGE)) {
       mm.removeMessageListener(messageName, this);
     }
 
     win.removeEventListener("TabSelect", this);
-    if (win.WindowEventDispatcher) {
+    if (win.WindowEventDispatcher && this._eventDispatcherListeners.has(win)) {
       // desktop mochitests don't have this.
-      win.WindowEventDispatcher.unregisterListener(this,
+      win.WindowEventDispatcher.unregisterListener(
+        this._eventDispatcherListeners.get(win),
         Object.values(GECKOVIEW_MESSAGE));
+      this._eventDispatcherListeners.delete(win);
     }
   },
 
-  onEvent(event, data, callback) {
+  onEvent(event, data, callback, win) {
     switch (event) {
       case GECKOVIEW_MESSAGE.SETTINGS:
         if (data.enabled) {
           this._enable();
         } else {
           this._disable();
         }
         break;
       case GECKOVIEW_MESSAGE.NEXT:
       case GECKOVIEW_MESSAGE.PREVIOUS: {
         let rule = "Simple";
         if (data && data.rule && data.rule.length) {
           rule = data.rule.substr(0, 1).toUpperCase() +
             data.rule.substr(1).toLowerCase();
         }
         let method = event.replace(/GeckoView:Accessibility(\w+)/, "move$1");
-        this.Input.moveCursor(method, rule, "gesture");
+        this.Input.moveCursor(method, rule, "gesture", win);
         break;
       }
       case GECKOVIEW_MESSAGE.ACTIVATE:
-        this.Input.activateCurrent(data);
+        this.Input.activateCurrent(data, win);
         break;
       case GECKOVIEW_MESSAGE.LONG_PRESS:
         // XXX: Advertize long press on supported objects and implement action
         break;
       case GECKOVIEW_MESSAGE.SCROLL_FORWARD:
-        this.Input.androidScroll("forward");
+        this.Input.androidScroll("forward", win);
         break;
       case GECKOVIEW_MESSAGE.SCROLL_BACKWARD:
-        this.Input.androidScroll("backward");
+        this.Input.androidScroll("backward", win);
         break;
       case GECKOVIEW_MESSAGE.CURSOR_TO_FOCUSED:
-        this.autoMove({ moveToFocused: true });
+        this.autoMove({ moveToFocused: true }, win);
         break;
       case GECKOVIEW_MESSAGE.BY_GRANULARITY:
-        this.Input.moveByGranularity(data);
+        this.Input.moveByGranularity(data, win);
         break;
       case GECKOVIEW_MESSAGE.EXPLORE_BY_TOUCH:
-        this.Input.moveToPoint("Simple", ...data.coordinates);
+        this.Input.moveToPoint("Simple", ...data.coordinates, win);
         break;
       case GECKOVIEW_MESSAGE.SET_SELECTION:
-        this.Input.setSelection(data);
+        this.Input.setSelection(data, win);
         break;
       case GECKOVIEW_MESSAGE.CLIPBOARD:
-        this.Input.clipboard(data);
+        this.Input.clipboard(data, win);
         break;
     }
   },
 
   observe: function observe(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "domwindowopened": {
         let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
@@ -216,27 +222,29 @@ var AccessFu = {
         }
         break;
       }
       default:
         break;
     }
   },
 
-  autoMove: function autoMove(aOptions) {
-    const mm = Utils.getMessageManager();
+  autoMove: function autoMove(aOptions, aWindow) {
+    const mm = Utils.getCurrentMessageManager(aWindow);
     mm.sendAsyncMessage("AccessFu:AutoMove", aOptions);
   },
 
   // So we don't enable/disable twice
   _enabled: false,
 
   // Layerview is focused
   _focused: false,
 
+  _eventDispatcherListeners: new WeakMap(),
+
   /**
    * Adjusts the given bounds that are defined in device display pixels
    * to client-relative CSS pixels of the chrome window.
    * @param {Rect} aJsonBounds the bounds to adjust
    * @param {Window} aWindow the window containing the item
    */
   screenToClientBounds(aJsonBounds, aWindow) {
       let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
@@ -246,53 +254,53 @@ var AccessFu = {
 
       bounds = bounds.scale(1 / devicePixelRatio, 1 / devicePixelRatio);
       bounds = bounds.translate(-mozInnerScreenX, -mozInnerScreenY);
       return bounds.expandToIntegers();
     },
 };
 
 var Input = {
-  moveToPoint: function moveToPoint(aRule, aX, aY) {
-    const mm = Utils.getMessageManager();
+  moveToPoint: function moveToPoint(aRule, aX, aY, aWindow) {
+    Logger.debug("moveToPoint", aX, aY);
+    const mm = Utils.getCurrentMessageManager(aWindow);
     mm.sendAsyncMessage("AccessFu:MoveToPoint",
       {rule: aRule, x: aX, y: aY, origin: "top"});
   },
 
-  moveCursor: function moveCursor(aAction, aRule, aInputType, aAdjustRange) {
-    const mm = Utils.getMessageManager();
+  moveCursor: function moveCursor(aAction, aRule, aInputType, aWindow) {
+    const mm = Utils.getCurrentMessageManager(aWindow);
     mm.sendAsyncMessage("AccessFu:MoveCursor",
                         { action: aAction, rule: aRule,
-                          origin: "top", inputType: aInputType,
-                          adjustRange: aAdjustRange });
+                          origin: "top", inputType: aInputType });
   },
 
-  androidScroll: function androidScroll(aDirection) {
-    const mm = Utils.getMessageManager();
+  androidScroll: function androidScroll(aDirection, aWindow) {
+    const mm = Utils.getCurrentMessageManager(aWindow);
     mm.sendAsyncMessage("AccessFu:AndroidScroll",
                         { direction: aDirection, origin: "top" });
   },
 
-  moveByGranularity: function moveByGranularity(aDetails) {
-    const mm = Utils.getMessageManager();
+  moveByGranularity: function moveByGranularity(aDetails, aWindow) {
+    const mm = Utils.getCurrentMessageManager(aWindow);
     mm.sendAsyncMessage("AccessFu:MoveByGranularity", aDetails);
   },
 
-  setSelection: function setSelection(aDetails) {
-    const mm = Utils.getMessageManager();
+  setSelection: function setSelection(aDetails, aWindow) {
+    const mm = Utils.getCurrentMessageManager(aWindow);
     mm.sendAsyncMessage("AccessFu:SetSelection", aDetails);
   },
 
-  clipboard: function clipboard(aDetails) {
-    const mm = Utils.getMessageManager();
+  clipboard: function clipboard(aDetails, aWindow) {
+    const mm = Utils.getCurrentMessageManager(aWindow);
     mm.sendAsyncMessage("AccessFu:Clipboard", aDetails);
   },
 
-  activateCurrent: function activateCurrent(aData) {
-    let mm = Utils.getMessageManager();
+  activateCurrent: function activateCurrent(aData, aWindow) {
+    let mm = Utils.getCurrentMessageManager(aWindow);
     mm.sendAsyncMessage("AccessFu:Activate", { offset: 0 });
   },
 
   doScroll: function doScroll(aDetails, aBrowser) {
     let horizontal = aDetails.horizontal;
     let page = aDetails.page;
     let win = aBrowser.ownerGlobal;
     let winUtils = win.windowUtils;
--- a/accessible/jsat/ContentControl.jsm
+++ b/accessible/jsat/ContentControl.jsm
@@ -126,17 +126,17 @@ this.ContentControl.prototype = {
       return;
     }
 
     let moved = TraversalHelper.move(vc, action, aMessage.json.rule);
 
     if (moved) {
       if (origin === "child") {
         // We just stepped out of a child, clear child cursor.
-        Utils.getMessageManager(aMessage.target).sendAsyncMessage(
+        Utils.getMessageManagerForFrame(aMessage.target).sendAsyncMessage(
           "AccessFu:ClearCursor", {});
       } else {
         // We potentially landed on a new child cursor. If so, we want to
         // either be on the first or last item in the child doc.
         let childAction = action;
         if (action === "moveNext") {
           childAction = "moveFirst";
         } else if (action === "movePrevious") {
@@ -373,17 +373,17 @@ this.ContentControl.prototype = {
   },
 
   getChildCursor: function cc_getChildCursor(aAccessible) {
     let acc = aAccessible || this.vc.position;
     if (Utils.isAliveAndVisible(acc) && acc.role === Roles.INTERNAL_FRAME) {
       let domNode = acc.DOMNode;
       let mm = this._childMessageSenders.get(domNode, null);
       if (!mm) {
-        mm = Utils.getMessageManager(domNode);
+        mm = Utils.getMessageManagerForFrame(domNode);
         mm.addWeakMessageListener("AccessFu:MoveCursor", this);
         this._childMessageSenders.set(domNode, mm);
       }
 
       return mm;
     }
 
     return null;
--- a/accessible/jsat/Traversal.jsm
+++ b/accessible/jsat/Traversal.jsm
@@ -39,17 +39,17 @@ BaseTraversalRule.prototype = {
     getMatchRoles: function BaseTraversalRule_getmatchRoles(aRoles) {
       aRoles.value = this._matchRoles;
       return aRoles.value.length;
     },
 
     match: function BaseTraversalRule_match(aAccessible) {
       let role = aAccessible.role;
       if (role == Roles.INTERNAL_FRAME) {
-        return (Utils.getMessageManager(aAccessible.DOMNode)) ?
+        return (Utils.getMessageManagerForFrame(aAccessible.DOMNode)) ?
           Filters.MATCH | Filters.IGNORE_SUBTREE : Filters.IGNORE;
       }
 
       if (this._explicitMatchRoles.has(role) ||
           !this._explicitMatchRoles.size) {
         return this._matchFunc(aAccessible);
       }
 
--- a/accessible/jsat/Utils.jsm
+++ b/accessible/jsat/Utils.jsm
@@ -71,20 +71,17 @@ var Utils = { // jshint ignore:line
   },
 
   set AndroidSdkVersion(value) {
     // When we want to mimic another version.
     this._AndroidSdkVersion = value;
   },
 
   getCurrentBrowser: function getCurrentBrowser(aWindow) {
-    let win = aWindow ||
-      Services.wm.getMostRecentWindow("navigator:browser") ||
-      Services.wm.getMostRecentWindow("navigator:geckoview");
-    return win.document.querySelector("browser[type=content][primary=true]");
+    return aWindow.document.querySelector("browser[type=content][primary=true]");
   },
 
   get isContentProcess() {
     delete this.isContentProcess;
     this.isContentProcess =
       Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
     return this.isContentProcess;
   },
@@ -128,20 +125,27 @@ var Utils = { // jshint ignore:line
           Logger.debug("Failed to get a string from a bundle for", string);
         }
         return str;
       },
     };
     return this.stringBundle;
   },
 
-  getMessageManager: function getMessageManager(aBrowser) {
-    let browser = aBrowser || this.getCurrentBrowser();
+  getCurrentMessageManager: function getCurrentMessageManager(aWindow) {
     try {
-      return browser.frameLoader.messageManager;
+      return this.getCurrentBrowser(aWindow).frameLoader.messageManager;
+    } catch (x) {
+      return null;
+    }
+  },
+
+  getMessageManagerForFrame: function getMessageManagerForFrame(aFrame) {
+    try {
+      return aFrame.frameLoader.messageManager;
     } catch (x) {
       return null;
     }
   },
 
   getState: function getState(aAccessibleOrEvent) {
     if (aAccessibleOrEvent instanceof Ci.nsIAccessibleStateChangeEvent) {
       return new State(