Mypal/toolkit/content/widgets/remote-browser.xml
2019-03-11 13:26:37 +03:00

592 lines
21 KiB
XML

<?xml version="1.0"?>
<!-- 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/. -->
<bindings id="firefoxBrowserBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<binding id="remote-browser" extends="chrome://global/content/bindings/browser.xml#browser">
<implementation type="application/javascript"
implements="nsIObserver, nsIDOMEventListener, nsIMessageListener, nsIRemoteBrowser">
<field name="_securityUI">null</field>
<property name="securityUI"
readonly="true">
<getter><![CDATA[
if (!this._securityUI) {
// Don't attempt to create the remote web progress if the
// messageManager has already gone away
if (!this.messageManager)
return null;
let jsm = "resource://gre/modules/RemoteSecurityUI.jsm";
let RemoteSecurityUI = Components.utils.import(jsm, {}).RemoteSecurityUI;
this._securityUI = new RemoteSecurityUI();
}
// We want to double-wrap the JS implemented interface, so that QI and instanceof works.
var ptr = Components.classes["@mozilla.org/supports-interface-pointer;1"]
.createInstance(Components.interfaces.nsISupportsInterfacePointer);
ptr.data = this._securityUI;
return ptr.data.QueryInterface(Components.interfaces.nsISecureBrowserUI);
]]></getter>
</property>
<!-- increases or decreases the browser's network priority -->
<method name="adjustPriority">
<parameter name="adjustment"/>
<body><![CDATA[
this.messageManager.sendAsyncMessage("NetworkPrioritizer:AdjustPriority",
{adjustment});
]]></body>
</method>
<!-- sets the browser's network priority to a discrete value -->
<method name="setPriority">
<parameter name="priority"/>
<body><![CDATA[
this.messageManager.sendAsyncMessage("NetworkPrioritizer:SetPriority",
{priority});
]]></body>
</method>
<field name="_controller">null</field>
<field name="_selectParentHelper">null</field>
<field name="_remoteWebNavigation">null</field>
<property name="webNavigation"
onget="return this._remoteWebNavigation;"
readonly="true"/>
<field name="_remoteWebProgress">null</field>
<property name="webProgress" readonly="true">
<getter>
<![CDATA[
if (!this._remoteWebProgress) {
// Don't attempt to create the remote web progress if the
// messageManager has already gone away
if (!this.messageManager)
return null;
let jsm = "resource://gre/modules/RemoteWebProgress.jsm";
let { RemoteWebProgressManager } = Components.utils.import(jsm, {});
this._remoteWebProgressManager = new RemoteWebProgressManager(this);
this._remoteWebProgress = this._remoteWebProgressManager.topLevelWebProgress;
}
return this._remoteWebProgress;
]]>
</getter>
</property>
<field name="_remoteFinder">null</field>
<property name="finder" readonly="true">
<getter><![CDATA[
if (!this._remoteFinder) {
// Don't attempt to create the remote finder if the
// messageManager has already gone away
if (!this.messageManager)
return null;
let jsm = "resource://gre/modules/RemoteFinder.jsm";
let { RemoteFinder } = Components.utils.import(jsm, {});
this._remoteFinder = new RemoteFinder(this);
}
return this._remoteFinder;
]]></getter>
</property>
<field name="_documentURI">null</field>
<field name="_documentContentType">null</field>
<!--
Used by session restore to ensure that currentURI is set so
that switch-to-tab works before the tab is fully
restored. This function also invokes onLocationChanged
listeners in tabbrowser.xml.
-->
<method name="_setCurrentURI">
<parameter name="aURI"/>
<body><![CDATA[
this._remoteWebProgressManager.setCurrentURI(aURI);
]]></body>
</method>
<property name="documentURI"
onget="return this._documentURI;"
readonly="true"/>
<property name="documentContentType"
onget="return this._documentContentType;"
readonly="true"/>
<field name="_contentTitle">""</field>
<property name="contentTitle"
onget="return this._contentTitle"
readonly="true"/>
<field name="_characterSet">""</field>
<property name="characterSet"
onget="return this._characterSet">
<setter><![CDATA[
this.messageManager.sendAsyncMessage("UpdateCharacterSet", {value: val});
this._characterSet = val;
]]></setter>
</property>
<field name="_mayEnableCharacterEncodingMenu">null</field>
<property name="mayEnableCharacterEncodingMenu"
onget="return this._mayEnableCharacterEncodingMenu;"
readonly="true"/>
<field name="_contentWindow">null</field>
<property name="contentWindow"
onget="return null"
readonly="true"/>
<property name="contentWindowAsCPOW"
onget="return this._contentWindow"
readonly="true"/>
<property name="contentDocument"
onget="return null"
readonly="true"/>
<field name="_contentPrincipal">null</field>
<property name="contentPrincipal"
onget="return this._contentPrincipal"
readonly="true"/>
<property name="contentDocumentAsCPOW"
onget="return this.contentWindowAsCPOW ? this.contentWindowAsCPOW.document : null"
readonly="true"/>
<field name="_imageDocument">null</field>
<property name="imageDocument"
onget="return this._imageDocument"
readonly="true"/>
<field name="_fullZoom">1</field>
<property name="fullZoom">
<getter><![CDATA[
return this._fullZoom;
]]></getter>
<setter><![CDATA[
let changed = val.toFixed(2) != this._fullZoom.toFixed(2);
this._fullZoom = val;
this.messageManager.sendAsyncMessage("FullZoom", {value: val});
if (changed) {
let event = new Event("FullZoomChange", {bubbles: true});
this.dispatchEvent(event);
}
]]></setter>
</property>
<field name="_textZoom">1</field>
<property name="textZoom">
<getter><![CDATA[
return this._textZoom;
]]></getter>
<setter><![CDATA[
let changed = val.toFixed(2) != this._textZoom.toFixed(2);
this._textZoom = val;
this.messageManager.sendAsyncMessage("TextZoom", {value: val});
if (changed) {
let event = new Event("TextZoomChange", {bubbles: true});
this.dispatchEvent(event);
}
]]></setter>
</property>
<field name="_isSyntheticDocument">false</field>
<property name="isSyntheticDocument">
<getter><![CDATA[
return this._isSyntheticDocument;
]]></getter>
</property>
<property name="hasContentOpener">
<getter><![CDATA[
let {frameLoader} = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner);
return frameLoader.tabParent.hasContentOpener;
]]></getter>
</property>
<field name="_outerWindowID">null</field>
<property name="outerWindowID"
onget="return this._outerWindowID"
readonly="true"/>
<field name="_innerWindowID">null</field>
<property name="innerWindowID">
<getter><![CDATA[
return this._innerWindowID;
]]></getter>
</property>
<property name="docShellIsActive">
<getter>
<![CDATA[
let {frameLoader} = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner);
return frameLoader.tabParent.docShellIsActive;
]]>
</getter>
<setter>
<![CDATA[
let {frameLoader} = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner);
frameLoader.tabParent.docShellIsActive = val;
return val;
]]>
</setter>
</property>
<method name="preserveLayers">
<parameter name="preserve"/>
<body><![CDATA[
let {frameLoader} = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner);
if (frameLoader.tabParent) {
frameLoader.tabParent.preserveLayers(preserve);
}
]]></body>
</method>
<field name="_manifestURI"/>
<property name="manifestURI"
onget="return this._manifestURI"
readonly="true"/>
<field name="mDestroyed">false</field>
<field name="_permitUnloadId">0</field>
<method name="getInPermitUnload">
<parameter name="aCallback"/>
<body>
<![CDATA[
let id = this._permitUnloadId++;
let mm = this.messageManager;
mm.sendAsyncMessage("InPermitUnload", {id});
mm.addMessageListener("InPermitUnload", function listener(msg) {
if (msg.data.id != id) {
return;
}
aCallback(msg.data.inPermitUnload);
});
]]>
</body>
</method>
<method name="permitUnload">
<body>
<![CDATA[
const kTimeout = 5000;
let finished = false;
let responded = false;
let permitUnload;
let id = this._permitUnloadId++;
let mm = this.messageManager;
let Services = Components.utils.import("resource://gre/modules/Services.jsm", {}).Services;
let msgListener = msg => {
if (msg.data.id != id) {
return;
}
if (msg.data.kind == "start") {
responded = true;
return;
}
done(msg.data.permitUnload);
};
let observer = subject => {
if (subject == mm) {
done(true);
}
};
function done(result) {
finished = true;
permitUnload = result;
mm.removeMessageListener("PermitUnload", msgListener);
Services.obs.removeObserver(observer, "message-manager-close");
}
mm.sendAsyncMessage("PermitUnload", {id});
mm.addMessageListener("PermitUnload", msgListener);
Services.obs.addObserver(observer, "message-manager-close", false);
let timedOut = false;
function timeout() {
if (!responded) {
timedOut = true;
}
// Dispatch something to ensure that the main thread wakes up.
Services.tm.mainThread.dispatch(function() {}, Components.interfaces.nsIThread.DISPATCH_NORMAL);
}
let timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
timer.initWithCallback(timeout, kTimeout, timer.TYPE_ONE_SHOT);
while (!finished && !timedOut) {
Services.tm.currentThread.processNextEvent(true);
}
return {permitUnload, timedOut};
]]>
</body>
</method>
<constructor>
<![CDATA[
/*
* Don't try to send messages from this function. The message manager for
* the <browser> element may not be initialized yet.
*/
this._remoteWebNavigation = Components.classes["@mozilla.org/remote-web-navigation;1"]
.createInstance(Components.interfaces.nsIWebNavigation);
this._remoteWebNavigationImpl = this._remoteWebNavigation.wrappedJSObject;
this._remoteWebNavigationImpl.swapBrowser(this);
// Initialize contentPrincipal to the about:blank principal for this loadcontext
let {Services} = Components.utils.import("resource://gre/modules/Services.jsm", {});
let aboutBlank = Services.io.newURI("about:blank", null, null);
let ssm = Services.scriptSecurityManager;
this._contentPrincipal = ssm.getLoadContextCodebasePrincipal(aboutBlank, this.loadContext);
this.messageManager.addMessageListener("Browser:Init", this);
this.messageManager.addMessageListener("DOMTitleChanged", this);
this.messageManager.addMessageListener("ImageDocumentLoaded", this);
this.messageManager.addMessageListener("FullZoomChange", this);
this.messageManager.addMessageListener("TextZoomChange", this);
this.messageManager.addMessageListener("ZoomChangeUsingMouseWheel", this);
this.messageManager.addMessageListener("DOMFullscreen:RequestExit", this);
this.messageManager.addMessageListener("DOMFullscreen:RequestRollback", this);
this.messageManager.addMessageListener("MozApplicationManifest", this);
this.messageManager.loadFrameScript("chrome://global/content/browser-child.js", true);
if (this.hasAttribute("selectmenulist")) {
this.messageManager.addMessageListener("Forms:ShowDropDown", this);
this.messageManager.addMessageListener("Forms:HideDropDown", this);
this.messageManager.loadFrameScript("chrome://global/content/select-child.js", true);
}
if (!this.hasAttribute("disablehistory")) {
Services.obs.addObserver(this, "browser:purge-session-history", true);
}
let jsm = "resource://gre/modules/RemoteController.jsm";
let RemoteController = Components.utils.import(jsm, {}).RemoteController;
this._controller = new RemoteController(this);
this.controllers.appendController(this._controller);
]]>
</constructor>
<destructor>
<![CDATA[
this.destroy();
]]>
</destructor>
<!-- This is necessary because the destructor doesn't always get called when
we are removed from a tabbrowser. This will be explicitly called by tabbrowser.
Note: This overrides the destroy() method from browser.xml. -->
<method name="destroy">
<body><![CDATA[
// Make sure that any open select is closed.
if (this._selectParentHelper) {
let menulist = document.getElementById(this.getAttribute("selectmenulist"));
this._selectParentHelper.hide(menulist, this);
}
if (this.mDestroyed)
return;
this.mDestroyed = true;
try {
this.controllers.removeController(this._controller);
} catch (ex) {
// This can fail when this browser element is not attached to a
// BrowserDOMWindow.
}
if (!this.hasAttribute("disablehistory")) {
let Services = Components.utils.import("resource://gre/modules/Services.jsm", {}).Services;
try {
Services.obs.removeObserver(this, "browser:purge-session-history");
} catch (ex) {
// It's not clear why this sometimes throws an exception.
}
}
]]></body>
</method>
<method name="receiveMessage">
<parameter name="aMessage"/>
<body><![CDATA[
let data = aMessage.data;
switch (aMessage.name) {
case "Browser:Init":
this._outerWindowID = data.outerWindowID;
break;
case "DOMTitleChanged":
this._contentTitle = data.title;
break;
case "ImageDocumentLoaded":
this._imageDocument = {
width: data.width,
height: data.height
};
break;
case "Forms:ShowDropDown": {
if (!this._selectParentHelper) {
this._selectParentHelper =
Cu.import("resource://gre/modules/SelectParentHelper.jsm", {}).SelectParentHelper;
}
let menulist = document.getElementById(this.getAttribute("selectmenulist"));
menulist.menupopup.style.direction = data.direction;
let zoom = Services.prefs.getBoolPref("browser.zoom.full") ||
this.isSyntheticDocument ? this._fullZoom : this._textZoom;
this._selectParentHelper.populate(menulist, data.options, data.selectedIndex, zoom);
this._selectParentHelper.open(this, menulist, data.rect, data.isOpenedViaTouch);
break;
}
case "FullZoomChange": {
this._fullZoom = data.value;
let event = document.createEvent("Events");
event.initEvent("FullZoomChange", true, false);
this.dispatchEvent(event);
break;
}
case "TextZoomChange": {
this._textZoom = data.value;
let event = document.createEvent("Events");
event.initEvent("TextZoomChange", true, false);
this.dispatchEvent(event);
break;
}
case "ZoomChangeUsingMouseWheel": {
let event = document.createEvent("Events");
event.initEvent("ZoomChangeUsingMouseWheel", true, false);
this.dispatchEvent(event);
break;
}
case "Forms:HideDropDown": {
if (this._selectParentHelper) {
let menulist = document.getElementById(this.getAttribute("selectmenulist"));
this._selectParentHelper.hide(menulist, this);
}
break;
}
case "DOMFullscreen:RequestExit": {
let windowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
windowUtils.exitFullscreen();
break;
}
case "DOMFullscreen:RequestRollback": {
let windowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
windowUtils.remoteFrameFullscreenReverted();
break;
}
case "MozApplicationManifest":
this._manifestURI = aMessage.data.manifest;
break;
default:
// Delegate to browser.xml.
return this._receiveMessage(aMessage);
}
return undefined;
]]></body>
</method>
<method name="enableDisableCommands">
<parameter name="aAction"/>
<parameter name="aEnabledLength"/>
<parameter name="aEnabledCommands"/>
<parameter name="aDisabledLength"/>
<parameter name="aDisabledCommands"/>
<body>
if (this._controller) {
this._controller.enableDisableCommands(aAction,
aEnabledLength, aEnabledCommands,
aDisabledLength, aDisabledCommands);
}
</body>
</method>
<method name="purgeSessionHistory">
<body>
<![CDATA[
try {
this.messageManager.sendAsyncMessage("Browser:PurgeSessionHistory");
} catch (ex) {
// This can throw if the browser has started to go away.
if (ex.result != Components.results.NS_ERROR_NOT_INITIALIZED) {
throw ex;
}
}
this._remoteWebNavigationImpl.canGoBack = false;
this._remoteWebNavigationImpl.canGoForward = false;
]]>
</body>
</method>
<method name="createAboutBlankContentViewer">
<parameter name="aPrincipal"/>
<body>
<![CDATA[
this.messageManager.sendAsyncMessage("Browser:CreateAboutBlank", aPrincipal);
]]>
</body>
</method>
</implementation>
<handlers>
<handler event="dragstart">
<![CDATA[
// If we're a remote browser dealing with a dragstart, stop it
// from propagating up, since our content process should be dealing
// with the mouse movement.
event.stopPropagation();
]]>
</handler>
</handlers>
</binding>
</bindings>