Bug 1479318: Minimize the amount of content Findbar code loaded by default. r?felipe draft
authorKris Maglione <maglione.k@gmail.com>
Sun, 29 Jul 2018 14:38:44 -0700
changeset 823911 239414259533669b687dc67b09c2c3f2ed16f11d
parent 823904 f6f417f660c4954aa6000b1bc98979f0c2865517
push id117819
push usermaglione.k@gmail.com
push dateSun, 29 Jul 2018 21:39:12 +0000
reviewersfelipe
bugs1479318
milestone63.0a1
Bug 1479318: Minimize the amount of content Findbar code loaded by default. r?felipe MozReview-Commit-ID: Gu4RyWKmaAz
browser/base/content/tabbrowser.js
toolkit/content/browser-content.js
toolkit/content/widgets/findbar.xml
toolkit/modules/BrowserUtils.jsm
toolkit/modules/FindBarChild.jsm
toolkit/modules/moz.build
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -447,32 +447,28 @@ window._gBrowser = {
   },
 
   get userTypedValue() {
     return this.selectedBrowser.userTypedValue;
   },
 
   _setFindbarData() {
     // Ensure we know what the find bar key is in the content process:
-    let initialProcessData = Services.ppmm.initialProcessData;
-    if (!initialProcessData.findBarShortcutData) {
+    let {sharedData} = Services.ppmm;
+    if (!sharedData.has("Findbar:Shortcut")) {
       let keyEl = document.getElementById("key_find");
       let mods = keyEl.getAttribute("modifiers")
         .replace(/accel/i, AppConstants.platform == "macosx" ? "meta" : "control");
-      initialProcessData.findBarShortcutData = {
+      sharedData.set("Findbar:Shortcut", {
         key: keyEl.getAttribute("key"),
-        modifiers: {
-          shiftKey: mods.includes("shift"),
-          ctrlKey: mods.includes("control"),
-          altKey: mods.includes("alt"),
-          metaKey: mods.includes("meta"),
-        },
-      };
-      Services.ppmm.broadcastAsyncMessage("Findbar:ShortcutData",
-        initialProcessData.findBarShortcutData);
+        shiftKey: mods.includes("shift"),
+        ctrlKey: mods.includes("control"),
+        altKey: mods.includes("alt"),
+        metaKey: mods.includes("meta"),
+      });
     }
   },
 
   isFindBarInitialized(aTab) {
     return (aTab || this.selectedTab)._findBar != undefined;
   },
 
   /**
--- a/toolkit/content/browser-content.js
+++ b/toolkit/content/browser-content.js
@@ -56,16 +56,22 @@ XPCOMUtils.defineLazyProxy(this, "WebCha
   "resource://gre/modules/WebChannelContent.jsm");
 
 XPCOMUtils.defineLazyProxy(this, "DateTimePickerContent", () => {
   let tmp = {};
   ChromeUtils.import("resource://gre/modules/DateTimePickerContent.jsm", tmp);
   return new tmp.DateTimePickerContent(this);
 });
 
+XPCOMUtils.defineLazyProxy(this, "FindBarChild", () => {
+  let tmp = {};
+  ChromeUtils.import("resource://gre/modules/FindBarChild.jsm", tmp);
+  return new tmp.FindBarChild(this);
+}, {inQuickFind: false, inPassThrough: false});
+
 
 // Lazily load the finder code
 addMessageListener("Finder:Initialize", function() {
   let {RemoteFinderListener} = ChromeUtils.import("resource://gre/modules/RemoteFinder.jsm", {});
   new RemoteFinderListener(global);
 });
 
 var AutoScrollListener = {
@@ -124,183 +130,73 @@ function SwitchDocumentDirection(aWindow
   }
 }
 
 addMessageListener("SwitchDocumentDirection", () => {
   SwitchDocumentDirection(content.window);
 });
 
 var FindBar = {
-  /* Please keep in sync with toolkit/content/widgets/findbar.xml */
-  FIND_NORMAL: 0,
-  FIND_TYPEAHEAD: 1,
-  FIND_LINKS: 2,
-
-  _findMode: 0,
-
   /**
    * _findKey and _findModifiers are used to determine whether a keypress
    * is a user attempting to use the find shortcut, after which we'll
    * route keypresses to the parent until we know the findbar has focus
    * there. To do this, we need shortcut data from the parent.
    */
   _findKey: null,
-  _findModifiers: null,
 
   init() {
-    addMessageListener("Findbar:UpdateState", this);
-    Services.els.addSystemEventListener(global, "keypress", this, false);
-    Services.els.addSystemEventListener(global, "mouseup", this, false);
-    this._initShortcutData();
+    Services.els.addSystemEventListener(global, "keypress",
+                                        this.onKeypress.bind(this), false);
     this.init = null;
   },
 
-  receiveMessage(msg) {
-    switch (msg.name) {
-      case "Findbar:UpdateState":
-        this._findMode = msg.data.findMode;
-        this._quickFindTimeout = msg.data.hasQuickFindTimeout;
-        if (msg.data.isOpenAndFocused) {
-          this._keepPassingUntilToldOtherwise = false;
-        }
-        break;
-      case "Findbar:ShortcutData":
-        // Set us up to never need this again for the lifetime of this process,
-        // and remove the listener.
-        Services.cpmm.initialProcessData.findBarShortcutData = msg.data;
-        Services.cpmm.removeMessageListener("Findbar:ShortcutData", this);
-        this._initShortcutData(msg.data);
-        break;
-    }
-  },
-
-  handleEvent(event) {
-    switch (event.type) {
-      case "keypress":
-        this._onKeypress(event);
-        break;
-      case "mouseup":
-        this._onMouseup(event);
-        break;
-    }
-  },
-
-  /**
-   * Use initial process data for find key/modifier data if we have it.
-   * Otherwise, add a listener so we get the data when the parent process has
-   * it.
-   */
-  _initShortcutData(data = Services.cpmm.initialProcessData.findBarShortcutData) {
-    if (data) {
-      this._findKey = data.key;
-      this._findModifiers = data.modifiers;
-    } else {
-      Services.cpmm.addMessageListener("Findbar:ShortcutData", this);
-    }
-  },
-
   /**
    * Check whether this key event will start the findbar in the parent,
    * in which case we should pass any further key events to the parent to avoid
    * them being lost.
    * @param aEvent the key event to check.
    */
-  _eventMatchesFindShortcut(aEvent) {
-    let modifiers = this._findModifiers;
-    if (!modifiers) {
-      return false;
+  eventMatchesFindShortcut(aEvent) {
+    if (!this._findKey) {
+      this._findKey = Services.cpmm.sharedData.get("Findbar:Shortcut");
     }
-    return aEvent.ctrlKey == modifiers.ctrlKey && aEvent.altKey == modifiers.altKey &&
-      aEvent.shiftKey == modifiers.shiftKey && aEvent.metaKey == modifiers.metaKey &&
-      aEvent.key == this._findKey;
+    for (let k in this._findKey) {
+      if (this._findKey[k] != aEvent[k]) {
+        return false;
+      }
+    }
+    return true;
   },
 
-  /**
-   * Returns whether FAYT can be used for the given event in
-   * the current content state.
-   */
-  _canAndShouldFastFind() {
-    let should = false;
-    let can = BrowserUtils.canFastFind(content);
-    if (can) {
-      // XXXgijs: why all these shenanigans? Why not use the event's target?
-      let focusedWindow = {};
-      let elt = Services.focus.getFocusedElementForWindow(content, true, focusedWindow);
-      let win = focusedWindow.value;
-      should = BrowserUtils.shouldFastFind(elt, win);
-    }
-    return { can, should };
-  },
-
-  _onKeypress(event) {
-    const FAYT_LINKS_KEY = "'";
-    const FAYT_TEXT_KEY = "/";
-    if (this._eventMatchesFindShortcut(event)) {
-      this._keepPassingUntilToldOtherwise = true;
-    }
-    // Useless keys:
-    if (event.ctrlKey || event.altKey || event.metaKey || event.defaultPrevented) {
-      return;
+  onKeypress(event) {
+    if (!FindBarChild.inPassThrough &&
+        this.eventMatchesFindShortcut(event)) {
+      return FindBarChild.start(event);
     }
 
-    // Check the focused element etc.
-    let fastFind = this._canAndShouldFastFind();
-
-    // Can we even use find in this page at all?
-    if (!fastFind.can) {
-      return;
+    if (event.ctrlKey || event.altKey || event.metaKey || event.defaultPrevented ||
+        !BrowserUtils.canFastFind(content)) {
+      return null;
     }
-    if (this._keepPassingUntilToldOtherwise) {
-      this._passKeyToParent(event);
-      return;
-    }
-    if (!fastFind.should) {
-      return;
+
+    if (FindBarChild.inPassThrough || FindBarChild.inQuickFind) {
+      return FindBarChild.onKeypress(event);
     }
 
-    let charCode = event.charCode;
-    // If the find bar is open and quick find is on, send the key to the parent.
-    if (this._findMode != this.FIND_NORMAL && this._quickFindTimeout) {
-      if (!charCode)
-        return;
-      this._passKeyToParent(event);
-    } else {
-      let key = charCode ? String.fromCharCode(charCode) : null;
-      let manualstartFAYT = (key == FAYT_LINKS_KEY || key == FAYT_TEXT_KEY) && RemoteFinder._manualFAYT;
-      let autostartFAYT = !manualstartFAYT && RemoteFinder._findAsYouType && key && key != " ";
-      if (manualstartFAYT || autostartFAYT) {
-        let mode = (key == FAYT_LINKS_KEY || (autostartFAYT && RemoteFinder._typeAheadLinksOnly)) ?
-          this.FIND_LINKS : this.FIND_TYPEAHEAD;
-        // Set _findMode immediately (without waiting for child->parent->child roundtrip)
-        // to ensure we pass any further keypresses, too.
-        this._findMode = mode;
-        this._passKeyToParent(event);
+    if (event.charCode && BrowserUtils.shouldFastFind(event.target)) {
+      let key = String.fromCharCode(event.charCode);
+      if ((key == "/" || key == "'") && RemoteFinder._manualFAYT) {
+        return FindBarChild.startQuickFind(event);
+      }
+      if (key != " " && RemoteFinder._findAsYouType) {
+        return FindBarChild.startQuickFind(event, true);
       }
     }
-  },
-
-  _passKeyToParent(event) {
-    event.preventDefault();
-    // These are the properties required to dispatch another 'real' event
-    // to the findbar in the parent in _dispatchKeypressEvent in findbar.xml .
-    // If you make changes here, verify that that method can still do its job.
-    const kRequiredProps = [
-      "type", "bubbles", "cancelable", "ctrlKey", "altKey", "shiftKey",
-      "metaKey", "keyCode", "charCode",
-    ];
-    let fakeEvent = {};
-    for (let prop of kRequiredProps) {
-      fakeEvent[prop] = event[prop];
-    }
-    sendAsyncMessage("Findbar:Keypress", fakeEvent);
-  },
-
-  _onMouseup(event) {
-    if (this._findMode != this.FIND_NORMAL)
-      sendAsyncMessage("Findbar:Mouseup");
+    return null;
   },
 };
 FindBar.init();
 
 addEventListener("WebChannelMessageToChrome", WebChannelContent,
                  true, true);
 addMessageListener("WebChannelMessageToContent", WebChannelContent);
 
--- a/toolkit/content/widgets/findbar.xml
+++ b/toolkit/content/widgets/findbar.xml
@@ -215,17 +215,17 @@
     </xul:hbox>
     <xul:toolbarbutton anonid="find-closebutton"
                        class="findbar-closebutton close-icon"
                        tooltiptext="&findCloseButton.tooltip;"
                        oncommand="close();"/>
     </content>
 
     <implementation>
-      <!-- Please keep in sync with toolkit/content/browser-content.js -->
+      <!-- Please keep in sync with toolkit/modules/FindBarChild.jsm -->
       <field name="FIND_NORMAL">0</field>
       <field name="FIND_TYPEAHEAD">1</field>
       <field name="FIND_LINKS">2</field>
 
       <field name="__findMode">0</field>
       <property name="_findMode" onget="return this.__findMode;"
                 onset="this.__findMode = val; this._updateBrowserWithState(); return val;"/>
 
--- a/toolkit/modules/BrowserUtils.jsm
+++ b/toolkit/modules/BrowserUtils.jsm
@@ -285,22 +285,20 @@ var BrowserUtils = {
            mimeType == "mozilla.application/cached-xul";
   },
 
   /**
    * Return true if we should FAYT for this node + window (could be CPOW):
    *
    * @param elt
    *        The element that is focused
-   * @param win
-   *        The window that is focused
-   *
    */
-  shouldFastFind(elt, win) {
+  shouldFastFind(elt) {
     if (elt) {
+      let win = elt.ownerGlobal;
       if (elt instanceof win.HTMLInputElement && elt.mozIsTextField(false))
         return false;
 
       if (elt.isContentEditable || win.document.designMode == "on")
         return false;
 
       if (elt instanceof win.HTMLTextAreaElement ||
           elt instanceof win.HTMLSelectElement ||
copy from toolkit/content/browser-content.js
copy to toolkit/modules/FindBarChild.jsm
--- a/toolkit/content/browser-content.js
+++ b/toolkit/modules/FindBarChild.jsm
@@ -1,541 +1,100 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* 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/. */
-
-/* eslint-env mozilla/frame-script */
-/* eslint no-unused-vars: ["error", {args: "none"}] */
-/* global sendAsyncMessage */
-
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+// vim: set ts=2 sw=2 sts=2 tw=80:
+// 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";
 
-ChromeUtils.defineModuleGetter(this, "AutoCompletePopup",
-  "resource://gre/modules/AutoCompletePopupContent.jsm");
-ChromeUtils.defineModuleGetter(this, "AutoScrollController",
-  "resource://gre/modules/AutoScrollController.jsm");
-ChromeUtils.defineModuleGetter(this, "BrowserUtils",
-  "resource://gre/modules/BrowserUtils.jsm");
-ChromeUtils.defineModuleGetter(this, "SelectContentHelper",
-  "resource://gre/modules/SelectContentHelper.jsm");
-ChromeUtils.defineModuleGetter(this, "FindContent",
-  "resource://gre/modules/FindContent.jsm");
-ChromeUtils.defineModuleGetter(this, "PrintingContent",
-  "resource://gre/modules/PrintingContent.jsm");
-ChromeUtils.defineModuleGetter(this, "RemoteFinder",
-  "resource://gre/modules/RemoteFinder.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "formFill",
-                                   "@mozilla.org/satchel/form-fill-controller;1",
-                                   "nsIFormFillController");
-
-var global = this;
+var EXPORTED_SYMBOLS = ["FindBarChild"];
 
-XPCOMUtils.defineLazyProxy(this, "PopupBlocking", () => {
-  let tmp = {};
-  ChromeUtils.import("resource://gre/modules/PopupBlocking.jsm", tmp);
-  return new tmp.PopupBlocking(global);
-});
-
-XPCOMUtils.defineLazyProxy(this, "ShieldFrameListener", () => {
-  let tmp = {};
-  ChromeUtils.import("resource://normandy-content/ShieldFrameListener.jsm", tmp);
-  return new tmp.ShieldFrameListener(global);
-});
-
-XPCOMUtils.defineLazyProxy(this, "UITourListener", () => {
-  let tmp = {};
-  ChromeUtils.import("resource:///modules/ContentUITour.jsm", tmp);
-  return new tmp.UITourListener(global);
-});
+ChromeUtils.defineModuleGetter(this, "RemoteFinder",
+                               "resource://gre/modules/RemoteFinder.jsm");
+ChromeUtils.defineModuleGetter(this, "Services",
+                               "resource://gre/modules/Services.jsm");
 
-XPCOMUtils.defineLazyProxy(this, "SelectionSourceContent",
-  "resource://gre/modules/SelectionSourceContent.jsm");
-
-XPCOMUtils.defineLazyProxy(this, "WebChannelContent",
-  "resource://gre/modules/WebChannelContent.jsm");
+/* Please keep in sync with toolkit/this.mm.content/widgets/findbar.xml */
+const FIND_NORMAL = 0;
+const FIND_TYPEAHEAD = 1;
+const FIND_LINKS = 2;
 
-XPCOMUtils.defineLazyProxy(this, "DateTimePickerContent", () => {
-  let tmp = {};
-  ChromeUtils.import("resource://gre/modules/DateTimePickerContent.jsm", tmp);
-  return new tmp.DateTimePickerContent(this);
-});
-
-
-// Lazily load the finder code
-addMessageListener("Finder:Initialize", function() {
-  let {RemoteFinderListener} = ChromeUtils.import("resource://gre/modules/RemoteFinder.jsm", {});
-  new RemoteFinderListener(global);
-});
+class FindBarChild {
+  constructor(mm) {
+    this.mm = mm;
 
-var AutoScrollListener = {
-  handleEvent(event) {
-    if (event.isTrusted &
-        !event.defaultPrevented &&
-        event.button == 1) {
-      if (!this._controller) {
-        this._controller = new AutoScrollController(global);
-      }
-      this._controller.handleEvent(event);
-    }
-  }
-};
-Services.els.addSystemEventListener(global, "mousedown", AutoScrollListener, true);
+    this.findMode = 0;
+    this.inQuickFind = false;
 
-addEventListener("MozOpenDateTimePicker", DateTimePickerContent);
-
-addEventListener("DOMPopupBlocked", PopupBlocking, true);
+    this.mm.addMessageListener("Findbar:UpdateState", this);
 
-var Printing = {
-  MESSAGES: [
-    "Printing:Preview:Enter",
-    "Printing:Preview:Exit",
-    "Printing:Preview:Navigate",
-    "Printing:Preview:ParseDocument",
-    "Printing:Print",
-  ],
+    Services.els.addSystemEventListener(this.mm, "mouseup", this, false);
+  }
 
-  init() {
-    this.MESSAGES.forEach(msgName => addMessageListener(msgName, this));
-    addEventListener("PrintingError", this, true);
-    addEventListener("printPreviewUpdate", this, true);
-    this.init = null;
-  },
-
-  handleEvent(event) {
-    return PrintingContent.handleEvent(global, event);
-  },
+  start(event) {
+    this.inPassThrough = true;
+    this.passKeyToParent(event);
+  }
 
-  receiveMessage(message) {
-    return PrintingContent.receiveMessage(global, message);
-  },
-};
-Printing.init();
-
-function SwitchDocumentDirection(aWindow) {
- // document.dir can also be "auto", in which case it won't change
-  if (aWindow.document.dir == "ltr" || aWindow.document.dir == "") {
-    aWindow.document.dir = "rtl";
-  } else if (aWindow.document.dir == "rtl") {
-    aWindow.document.dir = "ltr";
-  }
-  for (let run = 0; run < aWindow.frames.length; run++) {
-    SwitchDocumentDirection(aWindow.frames[run]);
-  }
-}
-
-addMessageListener("SwitchDocumentDirection", () => {
-  SwitchDocumentDirection(content.window);
-});
+  startQuickFind(event, autostart = false) {
+    let mode = FIND_TYPEAHEAD;
+    if (event.charCode == "'".charAt(0) ||
+        autostart && RemoteFinder._typeAheadLinksOnly) {
+      mode = FIND_LINKS;
+    }
 
-var FindBar = {
-  /* Please keep in sync with toolkit/content/widgets/findbar.xml */
-  FIND_NORMAL: 0,
-  FIND_TYPEAHEAD: 1,
-  FIND_LINKS: 2,
-
-  _findMode: 0,
-
-  /**
-   * _findKey and _findModifiers are used to determine whether a keypress
-   * is a user attempting to use the find shortcut, after which we'll
-   * route keypresses to the parent until we know the findbar has focus
-   * there. To do this, we need shortcut data from the parent.
-   */
-  _findKey: null,
-  _findModifiers: null,
-
-  init() {
-    addMessageListener("Findbar:UpdateState", this);
-    Services.els.addSystemEventListener(global, "keypress", this, false);
-    Services.els.addSystemEventListener(global, "mouseup", this, false);
-    this._initShortcutData();
-    this.init = null;
-  },
+    // Set findMode immediately (without waiting for child->parent->child roundtrip)
+    // to ensure we pass any further keypresses, too.
+    this.findMode = mode;
+    this.passKeyToParent(event);
+  }
 
   receiveMessage(msg) {
     switch (msg.name) {
       case "Findbar:UpdateState":
-        this._findMode = msg.data.findMode;
-        this._quickFindTimeout = msg.data.hasQuickFindTimeout;
+        this.findMode = msg.data.findMode;
+        this.inQuickFind = msg.data.hasQuickFindTimeout;
         if (msg.data.isOpenAndFocused) {
-          this._keepPassingUntilToldOtherwise = false;
+          this.inPassThrough = false;
         }
         break;
-      case "Findbar:ShortcutData":
-        // Set us up to never need this again for the lifetime of this process,
-        // and remove the listener.
-        Services.cpmm.initialProcessData.findBarShortcutData = msg.data;
-        Services.cpmm.removeMessageListener("Findbar:ShortcutData", this);
-        this._initShortcutData(msg.data);
-        break;
     }
-  },
+  }
 
   handleEvent(event) {
     switch (event.type) {
       case "keypress":
-        this._onKeypress(event);
+        this.onKeypress(event);
         break;
       case "mouseup":
-        this._onMouseup(event);
+        this.onMouseup(event);
         break;
     }
-  },
-
-  /**
-   * Use initial process data for find key/modifier data if we have it.
-   * Otherwise, add a listener so we get the data when the parent process has
-   * it.
-   */
-  _initShortcutData(data = Services.cpmm.initialProcessData.findBarShortcutData) {
-    if (data) {
-      this._findKey = data.key;
-      this._findModifiers = data.modifiers;
-    } else {
-      Services.cpmm.addMessageListener("Findbar:ShortcutData", this);
-    }
-  },
-
-  /**
-   * Check whether this key event will start the findbar in the parent,
-   * in which case we should pass any further key events to the parent to avoid
-   * them being lost.
-   * @param aEvent the key event to check.
-   */
-  _eventMatchesFindShortcut(aEvent) {
-    let modifiers = this._findModifiers;
-    if (!modifiers) {
-      return false;
-    }
-    return aEvent.ctrlKey == modifiers.ctrlKey && aEvent.altKey == modifiers.altKey &&
-      aEvent.shiftKey == modifiers.shiftKey && aEvent.metaKey == modifiers.metaKey &&
-      aEvent.key == this._findKey;
-  },
-
-  /**
-   * Returns whether FAYT can be used for the given event in
-   * the current content state.
-   */
-  _canAndShouldFastFind() {
-    let should = false;
-    let can = BrowserUtils.canFastFind(content);
-    if (can) {
-      // XXXgijs: why all these shenanigans? Why not use the event's target?
-      let focusedWindow = {};
-      let elt = Services.focus.getFocusedElementForWindow(content, true, focusedWindow);
-      let win = focusedWindow.value;
-      should = BrowserUtils.shouldFastFind(elt, win);
-    }
-    return { can, should };
-  },
+  }
 
-  _onKeypress(event) {
-    const FAYT_LINKS_KEY = "'";
-    const FAYT_TEXT_KEY = "/";
-    if (this._eventMatchesFindShortcut(event)) {
-      this._keepPassingUntilToldOtherwise = true;
-    }
-    // Useless keys:
-    if (event.ctrlKey || event.altKey || event.metaKey || event.defaultPrevented) {
-      return;
-    }
-
-    // Check the focused element etc.
-    let fastFind = this._canAndShouldFastFind();
-
-    // Can we even use find in this page at all?
-    if (!fastFind.can) {
-      return;
-    }
-    if (this._keepPassingUntilToldOtherwise) {
-      this._passKeyToParent(event);
-      return;
+  onKeypress(event) {
+    if (this.inPassThrough) {
+      this.passKeyToParent(event);
+    } else if (this.findMode != FIND_NORMAL && this.inQuickFind && event.charCode) {
+      this.passKeyToParent(event);
     }
-    if (!fastFind.should) {
-      return;
-    }
+  }
 
-    let charCode = event.charCode;
-    // If the find bar is open and quick find is on, send the key to the parent.
-    if (this._findMode != this.FIND_NORMAL && this._quickFindTimeout) {
-      if (!charCode)
-        return;
-      this._passKeyToParent(event);
-    } else {
-      let key = charCode ? String.fromCharCode(charCode) : null;
-      let manualstartFAYT = (key == FAYT_LINKS_KEY || key == FAYT_TEXT_KEY) && RemoteFinder._manualFAYT;
-      let autostartFAYT = !manualstartFAYT && RemoteFinder._findAsYouType && key && key != " ";
-      if (manualstartFAYT || autostartFAYT) {
-        let mode = (key == FAYT_LINKS_KEY || (autostartFAYT && RemoteFinder._typeAheadLinksOnly)) ?
-          this.FIND_LINKS : this.FIND_TYPEAHEAD;
-        // Set _findMode immediately (without waiting for child->parent->child roundtrip)
-        // to ensure we pass any further keypresses, too.
-        this._findMode = mode;
-        this._passKeyToParent(event);
-      }
-    }
-  },
-
-  _passKeyToParent(event) {
+  passKeyToParent(event) {
     event.preventDefault();
     // These are the properties required to dispatch another 'real' event
     // to the findbar in the parent in _dispatchKeypressEvent in findbar.xml .
     // If you make changes here, verify that that method can still do its job.
     const kRequiredProps = [
       "type", "bubbles", "cancelable", "ctrlKey", "altKey", "shiftKey",
       "metaKey", "keyCode", "charCode",
     ];
     let fakeEvent = {};
     for (let prop of kRequiredProps) {
       fakeEvent[prop] = event[prop];
     }
-    sendAsyncMessage("Findbar:Keypress", fakeEvent);
-  },
-
-  _onMouseup(event) {
-    if (this._findMode != this.FIND_NORMAL)
-      sendAsyncMessage("Findbar:Mouseup");
-  },
-};
-FindBar.init();
-
-addEventListener("WebChannelMessageToChrome", WebChannelContent,
-                 true, true);
-addMessageListener("WebChannelMessageToContent", WebChannelContent);
-
-var AudioPlaybackListener = {
-  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
-
-  init() {
-    Services.obs.addObserver(this, "audio-playback");
-
-    addMessageListener("AudioPlayback", this);
-    addEventListener("unload", () => {
-      AudioPlaybackListener.uninit();
-    });
-    this.init = null;
-  },
-
-  uninit() {
-    Services.obs.removeObserver(this, "audio-playback");
-
-    removeMessageListener("AudioPlayback", this);
-  },
-
-  handleMediaControlMessage(msg) {
-    let utils = global.content.windowUtils;
-    let suspendTypes = Ci.nsISuspendedTypes;
-    switch (msg) {
-      case "mute":
-        utils.audioMuted = true;
-        break;
-      case "unmute":
-        utils.audioMuted = false;
-        break;
-      case "lostAudioFocus":
-        utils.mediaSuspend = suspendTypes.SUSPENDED_PAUSE_DISPOSABLE;
-        break;
-      case "lostAudioFocusTransiently":
-        utils.mediaSuspend = suspendTypes.SUSPENDED_PAUSE;
-        break;
-      case "gainAudioFocus":
-        utils.mediaSuspend = suspendTypes.NONE_SUSPENDED;
-        break;
-      case "mediaControlPaused":
-        utils.mediaSuspend = suspendTypes.SUSPENDED_PAUSE_DISPOSABLE;
-        break;
-      case "mediaControlStopped":
-        utils.mediaSuspend = suspendTypes.SUSPENDED_STOP_DISPOSABLE;
-        break;
-      case "resumeMedia":
-        // User has clicked the tab audio indicator to play a delayed
-        // media. That's clear user intent to play, so gesture activate
-        // the content document tree so that the block-autoplay logic
-        // allows the media to autoplay.
-        content.document.notifyUserGestureActivation();
-        utils.mediaSuspend = suspendTypes.NONE_SUSPENDED;
-        break;
-      default:
-        dump("Error : wrong media control msg!\n");
-        break;
-    }
-  },
-
-  observe(subject, topic, data) {
-    if (topic === "audio-playback") {
-      if (subject && subject.top == global.content) {
-        let name = "AudioPlayback:";
-        if (data === "activeMediaBlockStart") {
-          name += "ActiveMediaBlockStart";
-        } else if (data === "activeMediaBlockStop") {
-          name += "ActiveMediaBlockStop";
-        } else {
-          name += (data === "active") ? "Start" : "Stop";
-        }
-        sendAsyncMessage(name);
-      }
-    }
-  },
-
-  receiveMessage(msg) {
-    if (msg.name == "AudioPlayback") {
-      this.handleMediaControlMessage(msg.data.type);
-    }
-  },
-};
-AudioPlaybackListener.init();
-
-var UnselectedTabHoverObserver = {
-  init() {
-    addMessageListener("Browser:UnselectedTabHover", this);
-    addEventListener("UnselectedTabHover:Enable", this);
-    addEventListener("UnselectedTabHover:Disable", this);
-    this.init = null;
-  },
-  receiveMessage(message) {
-    Services.obs.notifyObservers(content.window, "unselected-tab-hover",
-                                 message.data.hovered);
-  },
-  handleEvent(event) {
-    sendAsyncMessage("UnselectedTabHover:Toggle",
-                     { enable: event.type == "UnselectedTabHover:Enable" });
-  }
-};
-UnselectedTabHoverObserver.init();
-
-addMessageListener("Browser:PurgeSessionHistory", function BrowserPurgeHistory() {
-  let sessionHistory = docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory;
-  if (!sessionHistory) {
-    return;
+    this.mm.sendAsyncMessage("Findbar:Keypress", fakeEvent);
   }
 
-  // place the entry at current index at the end of the history list, so it won't get removed
-  if (sessionHistory.index < sessionHistory.count - 1) {
-    let legacy = sessionHistory.legacySHistory;
-    legacy.QueryInterface(Ci.nsISHistoryInternal);
-    let indexEntry = legacy.getEntryAtIndex(sessionHistory.index, false);
-    indexEntry.QueryInterface(Ci.nsISHEntry);
-    legacy.addEntry(indexEntry, true);
-  }
-
-  let purge = sessionHistory.count;
-  if (global.content.location.href != "about:blank") {
-    --purge; // Don't remove the page the user's staring at from shistory
-  }
-
-  if (purge > 0) {
-    sessionHistory.legacySHistory.PurgeHistory(purge);
+  onMouseup(event) {
+    if (this.findMode != FIND_NORMAL)
+      this.mm.sendAsyncMessage("Findbar:Mouseup");
   }
-});
-
-addMessageListener("ViewSource:GetSelection", SelectionSourceContent);
-
-addEventListener("MozApplicationManifest", function(e) {
-  let doc = e.target;
-  let info = {
-    uri: doc.documentURI,
-    characterSet: doc.characterSet,
-    manifest: doc.documentElement.getAttribute("manifest"),
-    principal: doc.nodePrincipal,
-  };
-  sendAsyncMessage("MozApplicationManifest", info);
-}, false);
-
-let AutoComplete = {
-  _connected: false,
-
-  init() {
-    addEventListener("unload", this, {once: true});
-    addEventListener("DOMContentLoaded", this, {once: true});
-    // WebExtension browserAction is preloaded and does not receive DCL, wait
-    // on pageshow so we can hookup the formfill controller.
-    addEventListener("pageshow", this, {capture: true, once: true});
-
-    XPCOMUtils.defineLazyProxy(this, "popup", () => new AutoCompletePopup(global),
-                               {QueryInterface: null});
-    this.init = null;
-  },
-
-  handleEvent(event) {
-    switch (event.type) {
-    case "DOMContentLoaded":
-    case "pageshow":
-      // We need to wait for a content viewer to be available
-      // before we can attach our AutoCompletePopup handler,
-      // since nsFormFillController assumes one will exist
-      // when we call attachToBrowser.
-      if (!this._connected) {
-        formFill.attachToBrowser(docShell, this.popup);
-        this._connected = true;
-      }
-      break;
-
-    case "unload":
-      if (this._connected) {
-        formFill.detachFromBrowser(docShell);
-        this._connected = false;
-      }
-      break;
-    }
-  },
-};
-
-AutoComplete.init();
-
-addEventListener("mozshowdropdown", event => {
-  if (!event.isTrusted)
-    return;
-
-  if (!SelectContentHelper.open) {
-    new SelectContentHelper(event.target, {isOpenedViaTouch: false}, this);
-  }
-});
-
-addEventListener("mozshowdropdown-sourcetouch", event => {
-  if (!event.isTrusted)
-    return;
-
-  if (!SelectContentHelper.open) {
-    new SelectContentHelper(event.target, {isOpenedViaTouch: true}, this);
-  }
-});
-
-let ExtFind = {
-  init() {
-    addMessageListener("ext-Finder:CollectResults", this);
-    addMessageListener("ext-Finder:HighlightResults", this);
-    addMessageListener("ext-Finder:clearHighlighting", this);
-    this.init = null;
-  },
-
-  _findContent: null,
-
-  async receiveMessage(message) {
-    if (!this._findContent) {
-      this._findContent = new FindContent(docShell);
-    }
-
-    let data;
-    switch (message.name) {
-      case "ext-Finder:CollectResults":
-        this.finderInited = true;
-        data = await this._findContent.findRanges(message.data);
-        sendAsyncMessage("ext-Finder:CollectResultsFinished", data);
-        break;
-      case "ext-Finder:HighlightResults":
-        data = this._findContent.highlightResults(message.data);
-        sendAsyncMessage("ext-Finder:HighlightResultsFinished", data);
-        break;
-      case "ext-Finder:clearHighlighting":
-        this._findContent.highlighter.highlight(false);
-        break;
-    }
-  },
-};
-
-ExtFind.init();
-
-addEventListener("ShieldPageEvent", ShieldFrameListener, false, true);
-
-addEventListener("mozUITour", UITourListener, false, true);
+}
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -195,16 +195,17 @@ EXTRA_JS_MODULES += [
     'css-selector.js',
     'DateTimePickerContent.jsm',
     'DateTimePickerParent.jsm',
     'DeferredTask.jsm',
     'Deprecated.jsm',
     'E10SUtils.jsm',
     'EventEmitter.jsm',
     'FileUtils.jsm',
+    'FindBarChild.jsm',
     'Finder.jsm',
     'FinderHighlighter.jsm',
     'FinderIterator.jsm',
     'FormLikeFactory.jsm',
     'Geometry.jsm',
     'GMPExtractorWorker.js',
     'GMPInstallManager.jsm',
     'GMPUtils.jsm',