Bug 1453487 part 1. Stop using XPCWrappedNative for nsIDOMEventListener. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 12 Apr 2018 00:05:38 -0400
changeset 412925 a5d3181f3b27516389832323e67b600c91999839
parent 412924 1c2716f85b46caf57f1a096d729508d4b289c15e
child 412926 2a9b18f3f4ace72abfcb323612eb7cf9bd147076
push id33824
push userebalazs@mozilla.com
push dateThu, 12 Apr 2018 09:39:57 +0000
treeherdermozilla-central@246c614e1605 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1453487
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1453487 part 1. Stop using XPCWrappedNative for nsIDOMEventListener. r=smaug MozReview-Commit-ID: Es4fEdGDzbx
browser/components/sessionstore/content/content-sessionStore.js
browser/components/sessionstore/nsISessionStoreUtils.idl
browser/components/sessionstore/nsSessionStoreUtils.cpp
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -46,16 +46,19 @@ const DOM_STORAGE_LIMIT_PREF = "browser.
 // or not, and should only be used for tests or debugging.
 const TIMEOUT_DISABLED_PREF = "browser.sessionstore.debug.no_auto_updates";
 
 const PREF_INTERVAL = "browser.sessionstore.interval";
 
 const kNoIndex = Number.MAX_SAFE_INTEGER;
 const kLastIndex = Number.MAX_SAFE_INTEGER - 1;
 
+// Grab our global so we can access it in functions below.
+const global = this;
+
 /**
  * A function that will recursively call |cb| to collected data for all
  * non-dynamic frames in the current frame/docShell tree.
  */
 function mapFrameTree(callback) {
   return (function map(frame, cb) {
     // Collect data for the current frame.
     let obj = cb(frame) || {};
@@ -145,17 +148,17 @@ var StateChangeNotifier = {
 
 /**
  * Listens for and handles content events that we need for the
  * session store service to be notified of state changes in content.
  */
 var EventListener = {
 
   init() {
-    addEventListener("load", ssu.createDynamicFrameEventFilter(this), true);
+    ssu.addDynamicFrameFilteredListener(global, "load", this, true);
   },
 
   handleEvent(event) {
     // Ignore load events from subframes.
     if (event.target != content.document) {
       return;
     }
 
@@ -459,17 +462,17 @@ var SessionHistoryListener = {
  * is scrolled this will return null so that we don't tack a property onto
  * the tabData object in the parent process.
  *
  * Example:
  *   {scroll: "100,100", children: [null, null, {scroll: "200,200"}]}
  */
 var ScrollPositionListener = {
   init() {
-    addEventListener("scroll", ssu.createDynamicFrameEventFilter(this));
+    ssu.addDynamicFrameFilteredListener(global, "scroll", this, false);
     StateChangeNotifier.addObserver(this);
   },
 
   handleEvent() {
     MessageQueue.push("scroll", () => this.collect());
   },
 
   onPageLoadCompleted() {
@@ -499,17 +502,17 @@ var ScrollPositionListener = {
  *     children: [
  *       null,
  *       {url: "http://sub.mozilla.org/", id: {input_id: "input value 2"}}
  *     ]
  *   }
  */
 var FormDataListener = {
   init() {
-    addEventListener("input", ssu.createDynamicFrameEventFilter(this), true);
+    ssu.addDynamicFrameFilteredListener(global, "input", this, true);
     StateChangeNotifier.addObserver(this);
   },
 
   handleEvent() {
     MessageQueue.push("formdata", () => this.collect());
   },
 
   onPageLoadStarted() {
@@ -591,23 +594,25 @@ var SessionStorageListener = {
     this._changes = undefined;
   },
 
   // The event listener waiting for MozSessionStorageChanged events.
   _listener: null,
 
   resetEventListener() {
     if (!this._listener) {
-      this._listener = ssu.createDynamicFrameEventFilter(this);
-      addEventListener("MozSessionStorageChanged", this._listener, true);
+      this._listener =
+        ssu.addDynamicFrameFilteredListener(global, "MozSessionStorageChanged",
+                                            this, true);
     }
   },
 
   removeEventListener() {
-    removeEventListener("MozSessionStorageChanged", this._listener, true);
+    ssu.removeDynamicFrameFilteredListener(global, "MozSessionStorageChanged",
+                                           this._listener, true);
     this._listener = null;
   },
 
   handleEvent(event) {
     if (!docShell) {
       return;
     }
 
--- a/browser/components/sessionstore/nsISessionStoreUtils.idl
+++ b/browser/components/sessionstore/nsISessionStoreUtils.idl
@@ -1,16 +1,16 @@
 /* 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 mozIDOMWindowProxy;
-interface nsIDOMEventListener;
+interface nsIDOMEventTarget;
 
 /**
  * A callback passed to nsISessionStoreUtils.forEachNonDynamicChildFrame().
  */
 [function, scriptable, uuid(8199ebf7-76c0-43d6-bcbe-913dd3de3ebf)]
 interface nsISessionStoreUtilsFrameCallback : nsISupports
 {
   /**
@@ -30,18 +30,40 @@ interface nsISessionStoreUtils : nsISupp
   /**
    * Calls the given |callback| once for each non-dynamic child frame of the
    * given |window|.
    */
   void forEachNonDynamicChildFrame(in mozIDOMWindowProxy window,
                                    in nsISessionStoreUtilsFrameCallback callback);
 
   /**
-   * Creates and returns an event listener that filters events from dynamic
-   * docShells. It forwards those from non-dynamic docShells to the given
-   * |listener|.
+   * Takes the given listener, wraps it in a filter that filters out events from
+   * dynamic docShells, and adds that filter as a listener for the given event
+   * type on the given event target.  The listener that was added is returned
+   * (as nsISupports) so that it can later be removed via
+   * removeDynamicFrameFilteredListener.
    *
    * This is implemented as a native filter, rather than a JS-based one, for
    * performance reasons.
+   *
+   * Once bug 1444991 is fixed, this should start taking an EventTarget.
    */
   [implicit_jscontext]
-  nsIDOMEventListener createDynamicFrameEventFilter(in jsval listener);
+  nsISupports addDynamicFrameFilteredListener(in nsIDOMEventTarget target,
+                                              in AString type,
+                                              in jsval listener,
+                                              in boolean useCapture);
+
+  /**
+   * Remove the passed-in filtered listener from the given event target, if it's
+   * currently a listener for the given event type there.  The 'listener'
+   * argument must be something that was returned by
+   * addDynamicFrameFilteredListener.
+   *
+   * This is needed, instead of the normal removeEventListener, because the
+   * caller doesn't actually have something that WebIDL considers an
+   * EventListener.
+   */
+  void removeDynamicFrameFilteredListener(in nsIDOMEventTarget target,
+                                          in AString type,
+                                          in nsISupports listener,
+                                          in boolean useCapture);
 };
--- a/browser/components/sessionstore/nsSessionStoreUtils.cpp
+++ b/browser/components/sessionstore/nsSessionStoreUtils.cpp
@@ -1,16 +1,17 @@
 /* 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 "nsSessionStoreUtils.h"
 
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/EventListenerBinding.h"
+#include "mozilla/dom/EventTarget.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocShell.h"
 
 using namespace mozilla::dom;
 
 namespace {
 
@@ -111,25 +112,50 @@ nsSessionStoreUtils::ForEachNonDynamicCh
 
     aCallback->HandleFrame(item->GetWindow(), childOffset);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSessionStoreUtils::CreateDynamicFrameEventFilter(JS::Handle<JS::Value> aListener,
-                                                   JSContext* aCx,
-                                                   nsIDOMEventListener** aResult)
+nsSessionStoreUtils::AddDynamicFrameFilteredListener(nsIDOMEventTarget* aTarget,
+                                                     const nsAString& aType,
+                                                     JS::Handle<JS::Value> aListener,
+                                                     bool aUseCapture,
+                                                     JSContext* aCx,
+                                                     nsISupports** aResult)
 {
   if (NS_WARN_IF(!aListener.isObject())) {
     return NS_ERROR_INVALID_ARG;
   }
 
+  nsCOMPtr<EventTarget> target = do_QueryInterface(aTarget);
+  NS_ENSURE_TRUE(target, NS_ERROR_NO_INTERFACE);
+
   JS::Rooted<JSObject*> obj(aCx, &aListener.toObject());
   RefPtr<EventListener> listener =
     new EventListener(aCx, obj, GetIncumbentGlobal());
 
   nsCOMPtr<nsIDOMEventListener> filter(new DynamicFrameEventFilter(listener));
+
+  nsresult rv = target->AddEventListener(aType, filter, aUseCapture);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   filter.forget(aResult);
-
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsSessionStoreUtils::RemoveDynamicFrameFilteredListener(nsIDOMEventTarget* aTarget,
+                                                        const nsAString& aType,
+                                                        nsISupports* aListener,
+                                                        bool aUseCapture)
+{
+  nsCOMPtr<EventTarget> target = do_QueryInterface(aTarget);
+  NS_ENSURE_TRUE(target, NS_ERROR_NO_INTERFACE);
+
+  nsCOMPtr<nsIDOMEventListener> listener = do_QueryInterface(aListener);
+  NS_ENSURE_TRUE(listener, NS_ERROR_NO_INTERFACE);
+
+  target->RemoveEventListener(aType, listener, aUseCapture);
+  return NS_OK;
+}