Bug 1460047 - 2. Add frame script support to ModuleManager; r?esawin
Make ModuleManager capable of loading frame scripts. This consolidates
more logic from GeckoViewModule into ModuleManager.
MozReview-Commit-ID: 6LoRJeTKzep
--- a/mobile/android/chrome/geckoview/geckoview.js
+++ b/mobile/android/chrome/geckoview/geckoview.js
@@ -44,21 +44,30 @@ var ModuleManager = {
enabled: !!initData.modules[module.name],
manager: self,
...module,
}),
];
}
})());
+ window.document.documentElement.appendChild(aBrowser);
+
WindowEventDispatcher.registerListener(this, [
"GeckoView:UpdateModuleState",
"GeckoView:UpdateInitData",
"GeckoView:UpdateSettings",
]);
+
+ this.messageManager.addMessageListener("GeckoView:ContentModuleLoaded",
+ this);
+
+ this.forEach(module => {
+ module.onInit();
+ });
},
get window() {
return window;
},
get browser() {
return this._browser;
@@ -90,16 +99,17 @@ var ModuleManager = {
}
});
this._browser.messageManager.sendAsyncMessage("GeckoView:UpdateSettings",
aSettings);
},
onEvent(aEvent, aData, aCallback) {
+ debug `onEvent ${aEvent} ${aData}`;
switch (aEvent) {
case "GeckoView:UpdateModuleState": {
const module = this._modules.get(aData.module);
if (module) {
module.enabled = aData.enabled;
}
break;
}
@@ -120,16 +130,29 @@ var ModuleManager = {
}
case "GeckoView:UpdateSettings": {
this._updateSettings(aData);
break;
}
}
},
+
+ receiveMessage(aMsg) {
+ debug `receiveMessage ${aMsg.name} ${aMsg.data}`;
+ switch (aMsg.name) {
+ case "GeckoView:ContentModuleLoaded": {
+ const module = this._modules.get(aMsg.data.module);
+ if (module) {
+ module.onContentModuleLoaded();
+ }
+ break;
+ }
+ }
+ },
};
/**
* ModuleInfo is the structure used by ModuleManager to represent individual
* modules. It is responsible for loading the module JSM file if necessary,
* and it acts as the intermediary between ModuleManager and the module
* object that extends GeckoViewModule.
*/
@@ -144,46 +167,65 @@ class ModuleInfo {
* @param onEnable Phase object for the enable phase, when the module is first
* enabled by setting a delegate in Java.
*/
constructor({manager, name, enabled, onInit, onEnable}) {
this._manager = manager;
this._name = name;
this._impl = null;
+ this._contentModuleLoaded = false;
this._enabled = false;
// Only enable once we performed initialization.
this._enabledOnInit = enabled;
- this._loadPhase(onInit);
+ // For init, load resource _before_ initializing browser to support the
+ // onInitBrowser() override. However, load content module after initializing
+ // browser, because we don't have a message manager before then.
+ this._loadPhase({
+ resource: onInit && onInit.resource,
+ });
+ this._onInitPhase = {
+ frameScript: onInit && onInit.frameScript,
+ };
this._onEnablePhase = onEnable;
}
onInit() {
this._impl.onInit();
+ this._loadPhase(this._onInitPhase);
+ this._onInitPhase = null;
+
this.enabled = this._enabledOnInit;
}
/**
* Load resources according to a phase object that contains possible keys,
*
* "resource": specify the JSM resource to load for this module.
+ * "frameScript": specify a content JS frame script to load for this module.
*/
_loadPhase(aPhase) {
if (!aPhase) {
return;
}
if (aPhase.resource && !this._impl) {
const scope = {};
const global = ChromeUtils.import(aPhase.resource, scope);
const tag = this._name.replace("GeckoView", "GeckoView.");
GeckoViewUtils.initLogging(tag, global);
this._impl = new scope[this._name](this);
}
+
+ if (aPhase.frameScript && !this._contentModuleLoaded) {
+ this._impl.onLoadContentModule();
+ this._manager.messageManager.loadFrameScript(aPhase.frameScript, true);
+ this._contentModuleLoaded = true;
+ }
}
get manager() {
return this._manager;
}
get name() {
return this._name;
@@ -210,20 +252,29 @@ class ModuleInfo {
if (aEnabled) {
this._loadPhase(this._onEnablePhase);
this._onEnablePhase = null;
this._impl.onEnable();
this._impl.onSettingsUpdate();
}
+ this._updateContentModuleState(/* includeSettings */ aEnabled);
+ }
+
+ onContentModuleLoaded() {
+ this._updateContentModuleState(/* includeSettings */ true);
+ this._impl.onContentModuleLoaded();
+ }
+
+ _updateContentModuleState(aIncludeSettings) {
this._manager.messageManager.sendAsyncMessage("GeckoView:UpdateModuleState", {
module: this._name,
- enabled: aEnabled,
- settings: aEnabled ? this._manager.settings : null,
+ enabled: this.enabled,
+ settings: aIncludeSettings ? this._manager.settings : null,
});
}
}
function createBrowser() {
const browser = window.browser = document.createElement("browser");
browser.setAttribute("type", "content");
browser.setAttribute("primary", "true");
@@ -239,56 +290,57 @@ function startup() {
name: "GeckoViewAccessibility",
onInit: {
resource: "resource://gre/modules/GeckoViewAccessibility.jsm",
},
}, {
name: "GeckoViewContent",
onInit: {
resource: "resource://gre/modules/GeckoViewContent.jsm",
+ frameScript: "chrome://geckoview/content/GeckoViewContent.js",
},
}, {
name: "GeckoViewNavigation",
onInit: {
resource: "resource://gre/modules/GeckoViewNavigation.jsm",
},
+ onEnable: {
+ frameScript: "chrome://geckoview/content/GeckoViewNavigationContent.js",
+ },
}, {
name: "GeckoViewProgress",
onEnable: {
resource: "resource://gre/modules/GeckoViewProgress.jsm",
},
}, {
name: "GeckoViewScroll",
onEnable: {
resource: "resource://gre/modules/GeckoViewScroll.jsm",
+ frameScript: "chrome://geckoview/content/GeckoViewScrollContent.js",
},
}, {
name: "GeckoViewSelectionAction",
onEnable: {
resource: "resource://gre/modules/GeckoViewSelectionAction.jsm",
+ frameScript: "chrome://geckoview/content/GeckoViewSelectionActionContent.js",
},
}, {
name: "GeckoViewSettings",
onInit: {
resource: "resource://gre/modules/GeckoViewSettings.jsm",
+ frameScript: "chrome://geckoview/content/GeckoViewContentSettings.js",
},
}, {
name: "GeckoViewTab",
onInit: {
resource: "resource://gre/modules/GeckoViewTab.jsm",
},
}, {
name: "GeckoViewTrackingProtection",
onEnable: {
resource: "resource://gre/modules/GeckoViewTrackingProtection.jsm",
},
}]);
- window.document.documentElement.appendChild(browser);
-
- ModuleManager.forEach(module => {
- module.onInit();
- });
-
// Move focus to the content window at the end of startup,
// so things like text selection can work properly.
browser.focus();
}
--- a/mobile/android/modules/geckoview/GeckoViewContent.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewContent.jsm
@@ -15,18 +15,16 @@ class GeckoViewContent extends GeckoView
"GeckoViewContent:ExitFullScreen",
"GeckoView:RestoreState",
"GeckoView:SaveState",
"GeckoView:SetActive",
"GeckoView:ZoomToInput",
]);
this.messageManager.addMessageListener("GeckoView:SaveStateFinish", this);
-
- this.registerContent("chrome://geckoview/content/GeckoViewContent.js");
}
onEnable() {
this.window.addEventListener("MozDOMFullScreen:Entered", this,
/* capture */ true, /* untrusted */ false);
this.window.addEventListener("MozDOMFullScreen:Exited", this,
/* capture */ true, /* untrusted */ false);
--- a/mobile/android/modules/geckoview/GeckoViewContentModule.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewContentModule.jsm
@@ -79,18 +79,19 @@ class GeckoViewContentModule {
if (settings && enabled) {
this.onSettingsUpdate();
}
}
);
this.onInit();
- this.messageManager.sendAsyncMessage(
- "GeckoView:ContentRegistered", { module: this.moduleName });
+ this.messageManager.sendAsyncMessage("GeckoView:ContentModuleLoaded", {
+ module: this.moduleName,
+ });
}
// Override to initialize module.
onInit() {}
// Override to detect settings change. Access settings via this.settings.
onSettingsUpdate() {}
--- a/mobile/android/modules/geckoview/GeckoViewModule.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewModule.jsm
@@ -59,37 +59,27 @@ class GeckoViewModule {
onSettingsUpdate() {}
// Override to enable module after setting a Java delegate.
onEnable() {}
// Override to disable module after clearing the Java delegate.
onDisable() {}
- registerContent(aUri) {
- if (this._isContentLoaded) {
- return;
- }
- this._isContentLoaded = true;
+ // Override to perform actions when content module has started loading;
+ // by default, pause events so events that depend on content modules can work.
+ onLoadContentModule() {
this._eventProxy.enableQueuing(true);
+ }
- let self = this;
- this.messageManager.addMessageListener("GeckoView:ContentRegistered",
- function listener(aMsg) {
- if (aMsg.data.module !== self.name) {
- return;
- }
- self.messageManager.removeMessageListener("GeckoView:ContentRegistered",
- listener);
- self.messageManager.sendAsyncMessage("GeckoView:UpdateSettings",
- self.settings);
- self._eventProxy.enableQueuing(false);
- self._eventProxy.dispatchQueuedEvents();
- });
- this.messageManager.loadFrameScript(aUri, true);
+ // Override to perform actions when content module has finished loading;
+ // by default, un-pause events and flush queued events.
+ onContentModuleLoaded() {
+ this._eventProxy.enableQueuing(false);
+ this._eventProxy.dispatchQueuedEvents();
}
registerListener(aEventList) {
this._eventProxy.registerListener(aEventList);
}
unregisterListener() {
this._eventProxy.unregisterListener();
--- a/mobile/android/modules/geckoview/GeckoViewNavigation.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewNavigation.jsm
@@ -245,19 +245,16 @@ class GeckoViewNavigation extends GeckoV
canClose() {
debug `canClose`;
return true;
}
onEnable() {
debug `onEnable`;
- this.registerContent(
- "chrome://geckoview/content/GeckoViewNavigationContent.js");
-
let flags = Ci.nsIWebProgress.NOTIFY_LOCATION;
this.progressFilter =
Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
.createInstance(Ci.nsIWebProgress);
this.progressFilter.addProgressListener(this, flags);
this.browser.addProgressListener(this.progressFilter, flags);
}
--- a/mobile/android/modules/geckoview/GeckoViewScroll.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewScroll.jsm
@@ -7,11 +7,10 @@
var EXPORTED_SYMBOLS = ["GeckoViewScroll"];
ChromeUtils.import("resource://gre/modules/GeckoViewModule.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
class GeckoViewScroll extends GeckoViewModule {
onEnable() {
debug `onEnable`;
- this.registerContent("chrome://geckoview/content/GeckoViewScrollContent.js");
}
}
--- a/mobile/android/modules/geckoview/GeckoViewSelectionAction.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewSelectionAction.jsm
@@ -8,11 +8,10 @@ var EXPORTED_SYMBOLS = ["GeckoViewSelect
ChromeUtils.import("resource://gre/modules/GeckoViewModule.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
// Handles inter-op between accessible carets and GeckoSession.
class GeckoViewSelectionAction extends GeckoViewModule {
onEnable() {
debug `onEnable`;
- this.registerContent("chrome://geckoview/content/GeckoViewSelectionActionContent.js");
}
}
--- a/mobile/android/modules/geckoview/GeckoViewSettings.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewSettings.jsm
@@ -37,19 +37,16 @@ class GeckoViewSettings extends GeckoVie
if (this.settings.useMultiprocess) {
this.browser.setAttribute("remote", "true");
}
}
onInit() {
this._useTrackingProtection = false;
this._useDesktopMode = false;
-
- this.registerContent(
- "chrome://geckoview/content/GeckoViewContentSettings.js");
}
onSettingsUpdate() {
const settings = this.settings;
debug `onSettingsUpdate: ${settings}`;
this.displayMode = settings.displayMode;
this.useTrackingProtection = !!settings.useTrackingProtection;