Bug 1367077 - 3. Move form fill event listeners out of browser.js; r=sebastian
☠☠ backed out by 04bf10e9a1f7 ☠ ☠
authorJim Chen <nchen@mozilla.com>
Tue, 12 Sep 2017 13:35:04 -0400
changeset 429904 8df5e093dd92890fa36fde7c648b097501603e44
parent 429903 c6300312d42adeed70b34434f03d682dfe58ad6a
child 429905 0509b09c11fa0d9b72173404eecfcbe1752d89df
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssebastian
bugs1367077
milestone57.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 1367077 - 3. Move form fill event listeners out of browser.js; r=sebastian Move the form fill event listeners out of browser.js and into BrowserCLH.js, and update them to support chrome windows, so we can handle form fill events for Fennec, custom tabs, and PWAs. MozReview-Commit-ID: Fb5gWmGvxfE
mobile/android/chrome/content/browser.js
mobile/android/components/BrowserCLH.js
mobile/android/modules/DelayedInit.jsm
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -41,22 +41,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/PluralForm.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
                                   "resource://gre/modules/Downloads.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "UserAgentOverrides",
                                   "resource://gre/modules/UserAgentOverrides.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent",
-                                  "resource://gre/modules/LoginManagerContent.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerParent",
-                                  "resource://gre/modules/LoginManagerParent.jsm");
-
 XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
                                   "resource://gre/modules/SafeBrowsing.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
                                   "resource://gre/modules/BrowserUtils.jsm");
@@ -551,19 +545,16 @@ var BrowserApp = {
 
       InitLater(() => LightWeightThemeWebInstaller.init());
       InitLater(() => CastingApps.init(), window, "CastingApps");
       InitLater(() => Services.search.init(), Services, "search");
 
       // Bug 778855 - Perf regression if we do this here. To be addressed in bug 779008.
       InitLater(() => SafeBrowsing.init(), window, "SafeBrowsing");
 
-      InitLater(() => Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager));
-      InitLater(() => LoginManagerParent.init(), window, "LoginManagerParent");
-
     }, {once: true});
 
     // Pass caret StateChanged events to ActionBarHandler.
     window.addEventListener("mozcaretstatechanged", e => {
       ActionBarHandler.caretStateChangedHandler(e);
     }, /* useCapture = */ true, /* wantsUntrusted = */ false);
   },
 
@@ -3769,27 +3760,24 @@ Tab.prototype = {
 
     this.browser.removeProgressListener(this.filter);
     this.filter.removeProgressListener(this);
     this.filter = null;
     this.browser.sessionHistory.removeSHistoryListener(this);
 
     this.browser.removeEventListener("DOMContentLoaded", this, true);
     this.browser.removeEventListener("DOMFormHasPassword", this, true);
-    this.browser.removeEventListener("DOMInputPasswordAdded", this, true);
     this.browser.removeEventListener("DOMLinkAdded", this, true);
     this.browser.removeEventListener("DOMLinkChanged", this, true);
     this.browser.removeEventListener("DOMMetaAdded", this);
     this.browser.removeEventListener("DOMTitleChanged", this, true);
     this.browser.removeEventListener("DOMAudioPlaybackStarted", this, true);
     this.browser.removeEventListener("DOMAudioPlaybackStopped", this, true);
     this.browser.removeEventListener("DOMWindowClose", this, true);
     this.browser.removeEventListener("DOMWillOpenModalDialog", this, true);
-    this.browser.removeEventListener("DOMAutoComplete", this, true);
-    this.browser.removeEventListener("blur", this, true);
     this.browser.removeEventListener("pageshow", this, true);
     this.browser.removeEventListener("MozApplicationManifest", this, true);
     this.browser.removeEventListener("TabPreZombify", this, true);
     this.browser.removeEventListener("DOMWindowFocus", this, true);
 
     this.browser.removeEventListener("VideoBindingAttached", this, true, true);
     this.browser.removeEventListener("VideoBindingCast", this, true, true);
 
@@ -4139,39 +4127,31 @@ Tab.prototype = {
         if (!docURI.startsWith("about:")) {
           WebsiteMetadata.parseAsynchronously(this.browser.contentDocument);
         }
 
         break;
       }
 
       case "DOMFormHasPassword": {
-        LoginManagerContent.onDOMFormHasPassword(aEvent,
-                                                 this.browser.contentWindow);
-
         // Send logins for this hostname to Java.
         let hostname = aEvent.target.baseURIObject.prePath;
         let foundLogins = Services.logins.findLogins({}, hostname, "", "");
         if (foundLogins.length > 0) {
           let displayHost = IdentityHandler.getEffectiveHost();
           let title = { text: displayHost, resource: hostname };
           let selectObj = { title: title, logins: foundLogins };
           GlobalEventDispatcher.sendRequest({
             type: "Doorhanger:Logins",
             data: selectObj
           });
         }
         break;
       }
 
-      case "DOMInputPasswordAdded": {
-        LoginManagerContent.onDOMInputPasswordAdded(aEvent,
-                                                    this.browser.contentWindow);
-      }
-
       case "DOMMetaAdded":
         let target = aEvent.originalTarget;
         let browser = BrowserApp.getBrowserForDocument(target.ownerDocument);
 
         switch (target.name) {
           case "msapplication-TileImage":
             this.addMetadata("tileImage", browser.currentURI.resolve(target.content), this.METADATA_GOOD_MATCH);
             break;
@@ -4291,22 +4271,16 @@ Tab.prototype = {
 
         // We're about to open a modal dialog, make sure the opening
         // tab is brought to the front.
         let tab = BrowserApp.getTabForWindow(aEvent.target.top);
         BrowserApp.selectTab(tab);
         break;
       }
 
-      case "DOMAutoComplete":
-      case "blur": {
-        LoginManagerContent.onUsernameInput(aEvent);
-        break;
-      }
-
       case "VideoBindingAttached": {
         CastingApps.handleVideoBindingAttached(this, aEvent);
         break;
       }
 
       case "VideoBindingCast": {
         CastingApps.handleVideoBindingCast(this, aEvent);
         break;
@@ -4322,18 +4296,16 @@ Tab.prototype = {
           type: "Tab:Select",
           tabID: this.id,
           foreground: true,
         });
         break;
       }
 
       case "pageshow": {
-        LoginManagerContent.onPageShow(aEvent, this.browser.contentWindow);
-
         // The rest of this only handles pageshow for the top-level document.
         if (aEvent.originalTarget.defaultView != this.browser.contentWindow)
           return;
 
         let target = aEvent.originalTarget;
         let docURI = target.documentURI;
         if (!docURI.startsWith("about:neterror") && !this.isSearch) {
           // If this wasn't an error page and the user isn't search, don't retain the typed entry
--- a/mobile/android/components/BrowserCLH.js
+++ b/mobile/android/components/BrowserCLH.js
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   AppConstants: "resource://gre/modules/AppConstants.jsm",
+  DelayedInit: "resource://gre/modules/DelayedInit.jsm",
   GeckoViewUtils: "resource://gre/modules/GeckoViewUtils.jsm",
   Services: "resource://gre/modules/Services.jsm",
 });
 
 var Strings = {};
 
 XPCOMUtils.defineLazyGetter(Strings, "brand", _ =>
         Services.strings.createBundle("chrome://branding/locale/brand.properties"));
@@ -69,16 +70,43 @@ BrowserCLH.prototype = {
         }
 
         GeckoViewUtils.addLazyGetter(this, "SelectHelper", {
           script: "chrome://browser/content/SelectHelper.js",
         });
         GeckoViewUtils.addLazyGetter(this, "InputWidgetHelper", {
           script: "chrome://browser/content/InputWidgetHelper.js",
         });
+
+        GeckoViewUtils.addLazyGetter(this, "LoginManagerParent", {
+          module: "resource://gre/modules/LoginManagerParent.jsm",
+          mm: [
+            // PLEASE KEEP THIS LIST IN SYNC WITH THE DESKTOP LIST IN nsBrowserGlue.js
+            "RemoteLogins:findLogins",
+            "RemoteLogins:findRecipes",
+            "RemoteLogins:onFormSubmit",
+            "RemoteLogins:autoCompleteLogins",
+            "RemoteLogins:removeLogin",
+            "RemoteLogins:insecureLoginFormPresent",
+            // PLEASE KEEP THIS LIST IN SYNC WITH THE DESKTOP LIST IN nsBrowserGlue.js
+          ],
+        });
+        GeckoViewUtils.addLazyGetter(this, "LoginManagerContent", {
+          module: "resource://gre/modules/LoginManagerContent.jsm",
+        });
+
+        // Once the first chrome window is loaded, schedule a list of startup
+        // tasks to be performed on idle.
+        GeckoViewUtils.addLazyGetter(this, "DelayedStartup", {
+          observers: ["chrome-document-loaded"],
+          once: true,
+          handler: _ => DelayedInit.scheduleList([
+            _ => Services.logins,
+          ], 10000 /* 10 seconds maximum wait. */),
+        });
         break;
       }
 
       case "chrome-document-global-created":
       case "content-document-global-created": {
         let win = GeckoViewUtils.getChromeWindow(subject);
         if (win !== subject) {
           // Only attach to top-level windows.
@@ -87,21 +115,58 @@ BrowserCLH.prototype = {
 
         GeckoViewUtils.addLazyEventListener(win, "click", {
           handler: _ => [this.SelectHelper, this.InputWidgetHelper],
           options: {
             capture: true,
             mozSystemGroup: true,
           },
         });
+
+        this._initLoginManagerEvents(aWindow);
         break;
       }
     }
   },
 
+  _initLoginManagerEvents: function(aWindow) {
+    let options = {
+      capture: true,
+      mozSystemGroup: true,
+    };
+
+    aWindow.addEventListener("DOMFormHasPassword", event => {
+      this.LoginManagerContent.onDOMFormHasPassword(event, event.target.ownerGlobal.top);
+    }, options);
+
+    aWindow.addEventListener("DOMInputPasswordAdded", event => {
+      this.LoginManagerContent.onDOMInputPasswordAdded(event, event.target.ownerGlobal.top);
+    }, options);
+
+    aWindow.addEventListener("DOMAutoComplete", event => {
+      this.LoginManagerContent.onUsernameInput(event);
+    }, options);
+
+    aWindow.addEventListener("blur", event => {
+      let win = event.target && event.target.ownerGlobal;
+      if (win && win.HTMLDocument &&
+          event.target instanceof win.HTMLInputElement) {
+        this.LoginManagerContent.onUsernameInput(event);
+      }
+    }, options);
+
+    aWindow.addEventListener("pageshow", event => {
+      let win = event.target && event.target.defaultView;
+      if (win && win.HTMLDocument &&
+          event.target instanceof win.HTMLDocument) {
+        this.LoginManagerContent.onPageShow(event, win.top);
+      }
+    }, options);
+  },
+
   // QI
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
   // XPCOMUtils factory
   classID: Components.ID("{be623d20-d305-11de-8a39-0800200c9a66}")
 };
 
 var components = [ BrowserCLH ];
--- a/mobile/android/modules/DelayedInit.jsm
+++ b/mobile/android/modules/DelayedInit.jsm
@@ -47,16 +47,22 @@ XPCOMUtils.defineLazyServiceGetter(this,
  *   }
  *   InitLater(() => Foo.init());
  *   InitLater(() => Bar.init(), this, "Bar");
  */
 var DelayedInit = {
   schedule: function(fn, object, name, maxWait) {
     return Impl.scheduleInit(fn, object, name, maxWait);
   },
+
+  scheduleList: function(fns, maxWait) {
+    for (let fn of fns) {
+      Impl.scheduleInit(fn, null, null, maxWait);
+    }
+  },
 };
 
 // Maximum duration for each idling period. Pending inits are run until this
 // duration is exceeded; then we wait for next idling period.
 const MAX_IDLE_RUN_MS = 50;
 
 var Impl = {
   pendingInits: [],