зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1479312: Move WebNavigation and WebProgress child listeners to JSMs. r=felipe
MozReview-Commit-ID: B2b4QXge7S4 --HG-- rename : toolkit/content/browser-child.js => toolkit/modules/WebNavigationChild.jsm rename : toolkit/content/browser-child.js => toolkit/modules/WebProgressChild.jsm extra : rebase_source : 5ea15ece35ca5bcfd2cd585ede5980e40b4e9f35
This commit is contained in:
Родитель
2cb03639b4
Коммит
e8b4457933
|
@ -53,6 +53,8 @@ const whitelist = {
|
|||
"resource://gre/modules/E10SUtils.jsm",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
"resource://gre/modules/ReaderMode.jsm",
|
||||
"resource://gre/modules/WebProgressChild.jsm",
|
||||
"resource://gre/modules/WebNavigationChild.jsm",
|
||||
|
||||
// Pocket
|
||||
"chrome://pocket/content/AboutPocket.jsm",
|
||||
|
|
|
@ -4,392 +4,18 @@
|
|||
|
||||
/* eslint-env mozilla/frame-script */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/BrowserUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/WebNavigationChild.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/WebProgressChild.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "PageThumbUtils",
|
||||
"resource://gre/modules/PageThumbUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Utils",
|
||||
"resource://gre/modules/sessionstore/Utils.jsm");
|
||||
this.WebProgress = new WebProgressChild(this);
|
||||
this.WebNavigation = new WebNavigationChild(this);
|
||||
|
||||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
|
||||
"@mozilla.org/xre/app-info;1",
|
||||
"nsICrashReporter");
|
||||
}
|
||||
|
||||
var WebProgressListener = {
|
||||
init() {
|
||||
this._filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
|
||||
.createInstance(Ci.nsIWebProgress);
|
||||
this._filter.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||
this._filter.target = tabEventTarget;
|
||||
|
||||
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress);
|
||||
webProgress.addProgressListener(this._filter, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||
this.init = null;
|
||||
},
|
||||
|
||||
uninit() {
|
||||
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress);
|
||||
webProgress.removeProgressListener(this._filter);
|
||||
|
||||
this._filter.removeProgressListener(this);
|
||||
this._filter = null;
|
||||
},
|
||||
|
||||
_requestSpec(aRequest, aPropertyName) {
|
||||
if (!aRequest || !(aRequest instanceof Ci.nsIChannel))
|
||||
return null;
|
||||
return aRequest.QueryInterface(Ci.nsIChannel)[aPropertyName].spec;
|
||||
},
|
||||
|
||||
_setupJSON: function setupJSON(aWebProgress, aRequest, aStateFlags) {
|
||||
// Avoid accessing content.document when being called from onStateChange
|
||||
// unless if we are in STATE_STOP, because otherwise the getter will
|
||||
// instantiate an about:blank document for us.
|
||||
let contentDocument = null;
|
||||
if (aStateFlags) {
|
||||
// We're being called from onStateChange
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
|
||||
contentDocument = content.document;
|
||||
}
|
||||
} else {
|
||||
contentDocument = content.document;
|
||||
}
|
||||
|
||||
let innerWindowID = null;
|
||||
if (aWebProgress) {
|
||||
let domWindowID = null;
|
||||
try {
|
||||
domWindowID = aWebProgress.DOMWindowID;
|
||||
innerWindowID = aWebProgress.innerDOMWindowID;
|
||||
} catch (e) {
|
||||
// The DOM Window ID getters above may throw if the inner or outer
|
||||
// windows aren't created yet or are destroyed at the time we're making
|
||||
// this call but that isn't fatal so ignore the exceptions here.
|
||||
}
|
||||
|
||||
aWebProgress = {
|
||||
isTopLevel: aWebProgress.isTopLevel,
|
||||
isLoadingDocument: aWebProgress.isLoadingDocument,
|
||||
loadType: aWebProgress.loadType,
|
||||
DOMWindowID: domWindowID
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
webProgress: aWebProgress || null,
|
||||
requestURI: this._requestSpec(aRequest, "URI"),
|
||||
originalRequestURI: this._requestSpec(aRequest, "originalURI"),
|
||||
documentContentType: contentDocument ? contentDocument.contentType : null,
|
||||
innerWindowID,
|
||||
};
|
||||
},
|
||||
|
||||
_setupObjects: function setupObjects(aWebProgress, aRequest) {
|
||||
let domWindow;
|
||||
try {
|
||||
domWindow = aWebProgress && aWebProgress.DOMWindow;
|
||||
} catch (e) {
|
||||
// If nsDocShell::Destroy has already been called, then we'll
|
||||
// get NS_NOINTERFACE when trying to get the DOM window. Ignore
|
||||
// that here.
|
||||
domWindow = null;
|
||||
}
|
||||
|
||||
return {
|
||||
contentWindow: content,
|
||||
contentDocument: content.document,
|
||||
// DOMWindow is not necessarily the content-window with subframes.
|
||||
DOMWindow: domWindow,
|
||||
webProgress: aWebProgress,
|
||||
request: aRequest,
|
||||
};
|
||||
},
|
||||
|
||||
_send(name, data, objects) {
|
||||
sendAsyncMessage(name, data, objects);
|
||||
},
|
||||
|
||||
onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest, aStateFlags);
|
||||
let objects = this._setupObjects(aWebProgress, aRequest);
|
||||
|
||||
json.stateFlags = aStateFlags;
|
||||
json.status = aStatus;
|
||||
|
||||
// It's possible that this state change was triggered by
|
||||
// loading an internal error page, for which the parent
|
||||
// will want to know some details, so we'll update it with
|
||||
// the documentURI.
|
||||
if (aWebProgress && aWebProgress.isTopLevel) {
|
||||
json.documentURI = content.document.documentURIObject.spec;
|
||||
json.charset = content.document.characterSet;
|
||||
json.mayEnableCharacterEncodingMenu = docShell.mayEnableCharacterEncodingMenu;
|
||||
json.inLoadURI = WebNavigation.inLoadURI;
|
||||
}
|
||||
|
||||
this._send("Content:StateChange", json, objects);
|
||||
},
|
||||
|
||||
// Note: Because the nsBrowserStatusFilter timeout runnable is
|
||||
// SystemGroup-labeled, this method should not modify content DOM or
|
||||
// run content JS.
|
||||
onProgressChange: function onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest);
|
||||
let objects = this._setupObjects(aWebProgress, aRequest);
|
||||
|
||||
json.curSelf = aCurSelf;
|
||||
json.maxSelf = aMaxSelf;
|
||||
json.curTotal = aCurTotal;
|
||||
json.maxTotal = aMaxTotal;
|
||||
|
||||
this._send("Content:ProgressChange", json, objects);
|
||||
},
|
||||
|
||||
onProgressChange64: function onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal) {
|
||||
this.onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal);
|
||||
},
|
||||
|
||||
onLocationChange: function onLocationChange(aWebProgress, aRequest, aLocationURI, aFlags) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest);
|
||||
let objects = this._setupObjects(aWebProgress, aRequest);
|
||||
|
||||
json.location = aLocationURI ? aLocationURI.spec : "";
|
||||
json.flags = aFlags;
|
||||
|
||||
// These properties can change even for a sub-frame navigation.
|
||||
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
|
||||
json.canGoBack = webNav.canGoBack;
|
||||
json.canGoForward = webNav.canGoForward;
|
||||
|
||||
if (aWebProgress && aWebProgress.isTopLevel) {
|
||||
json.documentURI = content.document.documentURIObject.spec;
|
||||
json.title = content.document.title;
|
||||
json.charset = content.document.characterSet;
|
||||
json.mayEnableCharacterEncodingMenu = docShell.mayEnableCharacterEncodingMenu;
|
||||
json.principal = content.document.nodePrincipal;
|
||||
json.synthetic = content.document.mozSyntheticDocument;
|
||||
json.inLoadURI = WebNavigation.inLoadURI;
|
||||
json.requestContextID = content.document.documentLoadGroup
|
||||
? content.document.documentLoadGroup.requestContextID
|
||||
: null;
|
||||
|
||||
if (AppConstants.MOZ_CRASHREPORTER && CrashReporter.enabled) {
|
||||
let uri = aLocationURI;
|
||||
try {
|
||||
// If the current URI contains a username/password, remove it.
|
||||
uri = uri.mutate()
|
||||
.setUserPass("")
|
||||
.finalize();
|
||||
} catch (ex) { /* Ignore failures on about: URIs. */ }
|
||||
CrashReporter.annotateCrashReport("URL", uri.spec);
|
||||
}
|
||||
}
|
||||
|
||||
this._send("Content:LocationChange", json, objects);
|
||||
},
|
||||
|
||||
// Note: Because the nsBrowserStatusFilter timeout runnable is
|
||||
// SystemGroup-labeled, this method should not modify content DOM or
|
||||
// run content JS.
|
||||
onStatusChange: function onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest);
|
||||
let objects = this._setupObjects(aWebProgress, aRequest);
|
||||
|
||||
json.status = aStatus;
|
||||
json.message = aMessage;
|
||||
|
||||
this._send("Content:StatusChange", json, objects);
|
||||
},
|
||||
|
||||
onSecurityChange: function onSecurityChange(aWebProgress, aRequest, aState) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest);
|
||||
let objects = this._setupObjects(aWebProgress, aRequest);
|
||||
|
||||
json.state = aState;
|
||||
json.secInfo = SecurityUI.getSecInfoAsString();
|
||||
|
||||
json.matchedList = null;
|
||||
if (aRequest && aRequest instanceof Ci.nsIClassifiedChannel) {
|
||||
json.matchedList = aRequest.matchedList;
|
||||
}
|
||||
|
||||
this._send("Content:SecurityChange", json, objects);
|
||||
},
|
||||
|
||||
onRefreshAttempted: function onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) {
|
||||
return true;
|
||||
},
|
||||
|
||||
sendLoadCallResult() {
|
||||
sendAsyncMessage("Content:LoadURIResult");
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
|
||||
"nsIWebProgressListener2",
|
||||
"nsISupportsWeakReference"]),
|
||||
};
|
||||
|
||||
WebProgressListener.init();
|
||||
addEventListener("unload", () => {
|
||||
WebProgressListener.uninit();
|
||||
});
|
||||
|
||||
var WebNavigation = {
|
||||
init() {
|
||||
addMessageListener("WebNavigation:GoBack", this);
|
||||
addMessageListener("WebNavigation:GoForward", this);
|
||||
addMessageListener("WebNavigation:GotoIndex", this);
|
||||
addMessageListener("WebNavigation:LoadURI", this);
|
||||
addMessageListener("WebNavigation:SetOriginAttributes", this);
|
||||
addMessageListener("WebNavigation:Reload", this);
|
||||
addMessageListener("WebNavigation:Stop", this);
|
||||
// This message is used for measuring content process startup performance.
|
||||
sendAsyncMessage("Content:BrowserChildReady", { time: Services.telemetry.msSystemNow() });
|
||||
this.init = null;
|
||||
},
|
||||
|
||||
get webNavigation() {
|
||||
return docShell.QueryInterface(Ci.nsIWebNavigation);
|
||||
},
|
||||
|
||||
_inLoadURI: false,
|
||||
|
||||
get inLoadURI() {
|
||||
return this._inLoadURI;
|
||||
},
|
||||
|
||||
receiveMessage(message) {
|
||||
switch (message.name) {
|
||||
case "WebNavigation:GoBack":
|
||||
this.goBack();
|
||||
break;
|
||||
case "WebNavigation:GoForward":
|
||||
this.goForward();
|
||||
break;
|
||||
case "WebNavigation:GotoIndex":
|
||||
this.gotoIndex(message.data.index);
|
||||
break;
|
||||
case "WebNavigation:LoadURI":
|
||||
let histogram = Services.telemetry.getKeyedHistogramById("FX_TAB_REMOTE_NAVIGATION_DELAY_MS");
|
||||
histogram.add("WebNavigation:LoadURI",
|
||||
Services.telemetry.msSystemNow() - message.data.requestTime);
|
||||
|
||||
this.loadURI(message.data.uri, message.data.flags,
|
||||
message.data.referrer, message.data.referrerPolicy,
|
||||
message.data.postData, message.data.headers,
|
||||
message.data.baseURI, message.data.triggeringPrincipal);
|
||||
break;
|
||||
case "WebNavigation:SetOriginAttributes":
|
||||
this.setOriginAttributes(message.data.originAttributes);
|
||||
break;
|
||||
case "WebNavigation:Reload":
|
||||
this.reload(message.data.flags);
|
||||
break;
|
||||
case "WebNavigation:Stop":
|
||||
this.stop(message.data.flags);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_wrapURIChangeCall(fn) {
|
||||
this._inLoadURI = true;
|
||||
try {
|
||||
fn();
|
||||
} finally {
|
||||
this._inLoadURI = false;
|
||||
WebProgressListener.sendLoadCallResult();
|
||||
}
|
||||
},
|
||||
|
||||
goBack() {
|
||||
if (this.webNavigation.canGoBack) {
|
||||
this._wrapURIChangeCall(() => this.webNavigation.goBack());
|
||||
}
|
||||
},
|
||||
|
||||
goForward() {
|
||||
if (this.webNavigation.canGoForward) {
|
||||
this._wrapURIChangeCall(() => this.webNavigation.goForward());
|
||||
}
|
||||
},
|
||||
|
||||
gotoIndex(index) {
|
||||
this._wrapURIChangeCall(() => this.webNavigation.gotoIndex(index));
|
||||
},
|
||||
|
||||
loadURI(uri, flags, referrer, referrerPolicy, postData, headers, baseURI, triggeringPrincipal) {
|
||||
if (AppConstants.MOZ_CRASHREPORTER && CrashReporter.enabled) {
|
||||
let annotation = uri;
|
||||
try {
|
||||
let url = Services.io.newURI(uri);
|
||||
// If the current URI contains a username/password, remove it.
|
||||
url = url.mutate()
|
||||
.setUserPass("")
|
||||
.finalize();
|
||||
annotation = url.spec;
|
||||
} catch (ex) { /* Ignore failures to parse and failures
|
||||
on about: URIs. */ }
|
||||
CrashReporter.annotateCrashReport("URL", annotation);
|
||||
}
|
||||
if (referrer)
|
||||
referrer = Services.io.newURI(referrer);
|
||||
if (postData)
|
||||
postData = Utils.makeInputStream(postData);
|
||||
if (headers)
|
||||
headers = Utils.makeInputStream(headers);
|
||||
if (baseURI)
|
||||
baseURI = Services.io.newURI(baseURI);
|
||||
if (triggeringPrincipal)
|
||||
triggeringPrincipal = Utils.deserializePrincipal(triggeringPrincipal);
|
||||
this._wrapURIChangeCall(() => {
|
||||
return this.webNavigation.loadURIWithOptions(uri, flags, referrer, referrerPolicy,
|
||||
postData, headers, baseURI, triggeringPrincipal);
|
||||
});
|
||||
},
|
||||
|
||||
setOriginAttributes(originAttributes) {
|
||||
if (originAttributes) {
|
||||
this.webNavigation.setOriginAttributesBeforeLoading(originAttributes);
|
||||
}
|
||||
},
|
||||
|
||||
reload(flags) {
|
||||
this.webNavigation.reload(flags);
|
||||
},
|
||||
|
||||
stop(flags) {
|
||||
this.webNavigation.stop(flags);
|
||||
}
|
||||
};
|
||||
|
||||
WebNavigation.init();
|
||||
|
||||
var SecurityUI = {
|
||||
getSecInfoAsString() {
|
||||
let secInfo = docShell.securityUI.secInfo;
|
||||
|
||||
if (secInfo) {
|
||||
if (secInfo) {
|
||||
let helper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
|
||||
secInfo.QueryInterface(Ci.nsISerializable);
|
||||
return helper.serializeToString(secInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
var ControllerCommands = {
|
||||
init() {
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
/* -*- 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/. */
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["WebNavigationChild"];
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Utils",
|
||||
"resource://gre/modules/sessionstore/Utils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
|
||||
"@mozilla.org/xre/app-info;1",
|
||||
"nsICrashReporter");
|
||||
|
||||
class WebNavigationChild {
|
||||
constructor(mm) {
|
||||
this.mm = mm;
|
||||
|
||||
this.mm.addMessageListener("WebNavigation:GoBack", this);
|
||||
this.mm.addMessageListener("WebNavigation:GoForward", this);
|
||||
this.mm.addMessageListener("WebNavigation:GotoIndex", this);
|
||||
this.mm.addMessageListener("WebNavigation:LoadURI", this);
|
||||
this.mm.addMessageListener("WebNavigation:SetOriginAttributes", this);
|
||||
this.mm.addMessageListener("WebNavigation:Reload", this);
|
||||
this.mm.addMessageListener("WebNavigation:Stop", this);
|
||||
// This message is used for measuring this.mm.content process startup performance.
|
||||
this.mm.sendAsyncMessage("Content:BrowserChildReady", { time: Services.telemetry.msSystemNow() });
|
||||
|
||||
this.inLoadURI = false;
|
||||
}
|
||||
|
||||
get webNavigation() {
|
||||
return this.mm.docShell.QueryInterface(Ci.nsIWebNavigation);
|
||||
}
|
||||
|
||||
receiveMessage(message) {
|
||||
switch (message.name) {
|
||||
case "WebNavigation:GoBack":
|
||||
this.goBack();
|
||||
break;
|
||||
case "WebNavigation:GoForward":
|
||||
this.goForward();
|
||||
break;
|
||||
case "WebNavigation:GotoIndex":
|
||||
this.gotoIndex(message.data.index);
|
||||
break;
|
||||
case "WebNavigation:LoadURI":
|
||||
let histogram = Services.telemetry.getKeyedHistogramById("FX_TAB_REMOTE_NAVIGATION_DELAY_MS");
|
||||
histogram.add("WebNavigation:LoadURI",
|
||||
Services.telemetry.msSystemNow() - message.data.requestTime);
|
||||
|
||||
this.loadURI(message.data.uri, message.data.flags,
|
||||
message.data.referrer, message.data.referrerPolicy,
|
||||
message.data.postData, message.data.headers,
|
||||
message.data.baseURI, message.data.triggeringPrincipal);
|
||||
break;
|
||||
case "WebNavigation:SetOriginAttributes":
|
||||
this.setOriginAttributes(message.data.originAttributes);
|
||||
break;
|
||||
case "WebNavigation:Reload":
|
||||
this.reload(message.data.flags);
|
||||
break;
|
||||
case "WebNavigation:Stop":
|
||||
this.stop(message.data.flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_wrapURIChangeCall(fn) {
|
||||
this.inLoadURI = true;
|
||||
try {
|
||||
fn();
|
||||
} finally {
|
||||
this.inLoadURI = false;
|
||||
this.mm.WebProgress.sendLoadCallResult();
|
||||
}
|
||||
}
|
||||
|
||||
goBack() {
|
||||
if (this.webNavigation.canGoBack) {
|
||||
this._wrapURIChangeCall(() => this.webNavigation.goBack());
|
||||
}
|
||||
}
|
||||
|
||||
goForward() {
|
||||
if (this.webNavigation.canGoForward) {
|
||||
this._wrapURIChangeCall(() => this.webNavigation.goForward());
|
||||
}
|
||||
}
|
||||
|
||||
gotoIndex(index) {
|
||||
this._wrapURIChangeCall(() => this.webNavigation.gotoIndex(index));
|
||||
}
|
||||
|
||||
loadURI(uri, flags, referrer, referrerPolicy, postData, headers, baseURI, triggeringPrincipal) {
|
||||
if (AppConstants.MOZ_CRASHREPORTER && CrashReporter.enabled) {
|
||||
let annotation = uri;
|
||||
try {
|
||||
let url = Services.io.newURI(uri);
|
||||
// If the current URI contains a username/password, remove it.
|
||||
url = url.mutate()
|
||||
.setUserPass("")
|
||||
.finalize();
|
||||
annotation = url.spec;
|
||||
} catch (ex) { /* Ignore failures to parse and failures
|
||||
on about: URIs. */ }
|
||||
CrashReporter.annotateCrashReport("URL", annotation);
|
||||
}
|
||||
if (referrer)
|
||||
referrer = Services.io.newURI(referrer);
|
||||
if (postData)
|
||||
postData = Utils.makeInputStream(postData);
|
||||
if (headers)
|
||||
headers = Utils.makeInputStream(headers);
|
||||
if (baseURI)
|
||||
baseURI = Services.io.newURI(baseURI);
|
||||
if (triggeringPrincipal)
|
||||
triggeringPrincipal = Utils.deserializePrincipal(triggeringPrincipal);
|
||||
this._wrapURIChangeCall(() => {
|
||||
return this.webNavigation.loadURIWithOptions(uri, flags, referrer, referrerPolicy,
|
||||
postData, headers, baseURI, triggeringPrincipal);
|
||||
});
|
||||
}
|
||||
|
||||
setOriginAttributes(originAttributes) {
|
||||
if (originAttributes) {
|
||||
this.webNavigation.setOriginAttributesBeforeLoading(originAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
reload(flags) {
|
||||
this.webNavigation.reload(flags);
|
||||
}
|
||||
|
||||
stop(flags) {
|
||||
this.webNavigation.stop(flags);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
/* -*- 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/. */
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["WebProgressChild"];
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
|
||||
"@mozilla.org/xre/app-info;1",
|
||||
"nsICrashReporter");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "serializationHelper",
|
||||
"@mozilla.org/network/serialization-helper;1",
|
||||
"nsISerializationHelper");
|
||||
|
||||
class WebProgressChild {
|
||||
constructor(mm) {
|
||||
this.mm = mm;
|
||||
|
||||
this._filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
|
||||
.createInstance(Ci.nsIWebProgress);
|
||||
this._filter.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||
this._filter.target = this.mm.tabEventTarget;
|
||||
|
||||
let webProgress = this.mm.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress);
|
||||
webProgress.addProgressListener(this._filter, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||
}
|
||||
|
||||
_requestSpec(aRequest, aPropertyName) {
|
||||
if (!aRequest || !(aRequest instanceof Ci.nsIChannel))
|
||||
return null;
|
||||
return aRequest[aPropertyName].spec;
|
||||
}
|
||||
|
||||
_setupJSON(aWebProgress, aRequest, aStateFlags) {
|
||||
// Avoid accessing this.mm.content.document when being called from onStateChange
|
||||
// unless if we are in STATE_STOP, because otherwise the getter will
|
||||
// instantiate an about:blank document for us.
|
||||
let contentDocument = null;
|
||||
if (aStateFlags) {
|
||||
// We're being called from onStateChange
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
|
||||
contentDocument = this.mm.content.document;
|
||||
}
|
||||
} else {
|
||||
contentDocument = this.mm.content.document;
|
||||
}
|
||||
|
||||
let innerWindowID = null;
|
||||
if (aWebProgress) {
|
||||
let domWindowID = null;
|
||||
try {
|
||||
domWindowID = aWebProgress.DOMWindowID;
|
||||
innerWindowID = aWebProgress.innerDOMWindowID;
|
||||
} catch (e) {
|
||||
// The DOM Window ID getters above may throw if the inner or outer
|
||||
// windows aren't created yet or are destroyed at the time we're making
|
||||
// this call but that isn't fatal so ignore the exceptions here.
|
||||
}
|
||||
|
||||
aWebProgress = {
|
||||
isTopLevel: aWebProgress.isTopLevel,
|
||||
isLoadingDocument: aWebProgress.isLoadingDocument,
|
||||
loadType: aWebProgress.loadType,
|
||||
DOMWindowID: domWindowID
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
webProgress: aWebProgress || null,
|
||||
requestURI: this._requestSpec(aRequest, "URI"),
|
||||
originalRequestURI: this._requestSpec(aRequest, "originalURI"),
|
||||
documentContentType: contentDocument ? contentDocument.contentType : null,
|
||||
innerWindowID,
|
||||
};
|
||||
}
|
||||
|
||||
_setupObjects(aWebProgress, aRequest) {
|
||||
let domWindow;
|
||||
try {
|
||||
domWindow = aWebProgress && aWebProgress.DOMWindow;
|
||||
} catch (e) {
|
||||
// If nsDocShell::Destroy has already been called, then we'll
|
||||
// get NS_NOINTERFACE when trying to get the DOM window. Ignore
|
||||
// that here.
|
||||
domWindow = null;
|
||||
}
|
||||
|
||||
return {
|
||||
contentWindow: this.mm.content,
|
||||
contentDocument: this.mm.content.document,
|
||||
// DOMWindow is not necessarily the this.mm.content-window with subframes.
|
||||
DOMWindow: domWindow,
|
||||
webProgress: aWebProgress,
|
||||
request: aRequest,
|
||||
};
|
||||
}
|
||||
|
||||
_send(name, data, objects) {
|
||||
this.mm.sendAsyncMessage(name, data, objects);
|
||||
}
|
||||
|
||||
onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest, aStateFlags);
|
||||
let objects = this._setupObjects(aWebProgress, aRequest);
|
||||
|
||||
json.stateFlags = aStateFlags;
|
||||
json.status = aStatus;
|
||||
|
||||
// It's possible that this state change was triggered by
|
||||
// loading an internal error page, for which the parent
|
||||
// will want to know some details, so we'll update it with
|
||||
// the documentURI.
|
||||
if (aWebProgress && aWebProgress.isTopLevel) {
|
||||
json.documentURI = this.mm.content.document.documentURIObject.spec;
|
||||
json.charset = this.mm.content.document.characterSet;
|
||||
json.mayEnableCharacterEncodingMenu = this.mm.docShell.mayEnableCharacterEncodingMenu;
|
||||
json.inLoadURI = this.mm.WebNavigation.inLoadURI;
|
||||
}
|
||||
|
||||
this._send("Content:StateChange", json, objects);
|
||||
}
|
||||
|
||||
// Note: Because the nsBrowserStatusFilter timeout runnable is
|
||||
// SystemGroup-labeled, this method should not modify this.mm.content DOM or
|
||||
// run this.mm.content JS.
|
||||
onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest);
|
||||
let objects = this._setupObjects(aWebProgress, aRequest);
|
||||
|
||||
json.curSelf = aCurSelf;
|
||||
json.maxSelf = aMaxSelf;
|
||||
json.curTotal = aCurTotal;
|
||||
json.maxTotal = aMaxTotal;
|
||||
|
||||
this._send("Content:ProgressChange", json, objects);
|
||||
}
|
||||
|
||||
onProgressChange64(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal) {
|
||||
this.onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal);
|
||||
}
|
||||
|
||||
onLocationChange(aWebProgress, aRequest, aLocationURI, aFlags) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest);
|
||||
let objects = this._setupObjects(aWebProgress, aRequest);
|
||||
|
||||
json.location = aLocationURI ? aLocationURI.spec : "";
|
||||
json.flags = aFlags;
|
||||
|
||||
// These properties can change even for a sub-frame navigation.
|
||||
let webNav = this.mm.docShell.QueryInterface(Ci.nsIWebNavigation);
|
||||
json.canGoBack = webNav.canGoBack;
|
||||
json.canGoForward = webNav.canGoForward;
|
||||
|
||||
if (aWebProgress && aWebProgress.isTopLevel) {
|
||||
json.documentURI = this.mm.content.document.documentURIObject.spec;
|
||||
json.title = this.mm.content.document.title;
|
||||
json.charset = this.mm.content.document.characterSet;
|
||||
json.mayEnableCharacterEncodingMenu = this.mm.docShell.mayEnableCharacterEncodingMenu;
|
||||
json.principal = this.mm.content.document.nodePrincipal;
|
||||
json.synthetic = this.mm.content.document.mozSyntheticDocument;
|
||||
json.inLoadURI = this.mm.WebNavigation.inLoadURI;
|
||||
json.requestContextID = this.mm.content.document.documentLoadGroup
|
||||
? this.mm.content.document.documentLoadGroup.requestContextID
|
||||
: null;
|
||||
|
||||
if (AppConstants.MOZ_CRASHREPORTER && CrashReporter.enabled) {
|
||||
let uri = aLocationURI;
|
||||
try {
|
||||
// If the current URI contains a username/password, remove it.
|
||||
uri = uri.mutate()
|
||||
.setUserPass("")
|
||||
.finalize();
|
||||
} catch (ex) { /* Ignore failures on about: URIs. */ }
|
||||
CrashReporter.annotateCrashReport("URL", uri.spec);
|
||||
}
|
||||
}
|
||||
|
||||
this._send("Content:LocationChange", json, objects);
|
||||
}
|
||||
|
||||
// Note: Because the nsBrowserStatusFilter timeout runnable is
|
||||
// SystemGroup-labeled, this method should not modify this.mm.content DOM or
|
||||
// run this.mm.content JS.
|
||||
onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest);
|
||||
let objects = this._setupObjects(aWebProgress, aRequest);
|
||||
|
||||
json.status = aStatus;
|
||||
json.message = aMessage;
|
||||
|
||||
this._send("Content:StatusChange", json, objects);
|
||||
}
|
||||
|
||||
getSecInfoAsString() {
|
||||
let secInfo = this.mm.docShell.securityUI.secInfo;
|
||||
if (secInfo) {
|
||||
return serializationHelper.serializeToString(secInfo);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
onSecurityChange(aWebProgress, aRequest, aState) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest);
|
||||
let objects = this._setupObjects(aWebProgress, aRequest);
|
||||
|
||||
json.state = aState;
|
||||
json.secInfo = this.getSecInfoAsString();
|
||||
|
||||
json.matchedList = null;
|
||||
if (aRequest && aRequest instanceof Ci.nsIClassifiedChannel) {
|
||||
json.matchedList = aRequest.matchedList;
|
||||
}
|
||||
|
||||
this._send("Content:SecurityChange", json, objects);
|
||||
}
|
||||
|
||||
onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) {
|
||||
return true;
|
||||
}
|
||||
|
||||
sendLoadCallResult() {
|
||||
this.mm.sendAsyncMessage("Content:LoadURIResult");
|
||||
}
|
||||
}
|
||||
|
||||
WebProgressChild.prototype.QueryInterface =
|
||||
ChromeUtils.generateQI(["nsIWebProgressListener",
|
||||
"nsIWebProgressListener2",
|
||||
"nsISupportsWeakReference"]);
|
|
@ -253,6 +253,8 @@ EXTRA_JS_MODULES += [
|
|||
'UpdateUtils.jsm',
|
||||
'WebChannel.jsm',
|
||||
'WebChannelContent.jsm',
|
||||
'WebNavigationChild.jsm',
|
||||
'WebProgressChild.jsm',
|
||||
'WindowDraggingUtils.jsm',
|
||||
'ZipUtils.jsm',
|
||||
]
|
||||
|
|
Загрузка…
Ссылка в новой задаче