зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound
This commit is contained in:
Коммит
a3f6453363
|
@ -588,6 +588,7 @@ hbox.urlbar-input-box {
|
|||
html|input.urlbar-scheme {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
visibility: hidden;
|
||||
direction: ltr;
|
||||
pointer-events: none;
|
||||
|
|
|
@ -1319,7 +1319,9 @@ var gBrowserInit = {
|
|||
let mm = window.getGroupMessageManager("browsers");
|
||||
mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
|
||||
mm.loadFrameScript("chrome://browser/content/content.js", true);
|
||||
mm.loadFrameScript("chrome://browser/content/content-UITour.js", true);
|
||||
mm.loadFrameScript("chrome://global/content/content-HybridContentTelemetry.js", true);
|
||||
mm.loadFrameScript("chrome://global/content/manifestMessages.js", true);
|
||||
|
||||
window.messageManager.addMessageListener("Browser:LoadURI", RedirectLoad);
|
||||
|
||||
|
|
|
@ -90,12 +90,6 @@ addMessageListener("MixedContent:ReenableProtection", function() {
|
|||
XPCOMUtils.defineLazyProxy(this, "LightweightThemeChildHelper",
|
||||
"resource:///modules/LightweightThemeChildHelper.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyProxy(this, "ManifestMessages", () => {
|
||||
let tmp = {};
|
||||
ChromeUtils.import("resource://gre/modules/ManifestMessages.jsm", tmp);
|
||||
return new tmp.ManifestMessages(global);
|
||||
});
|
||||
|
||||
let themeablePagesWhitelist = new Set([
|
||||
"about:home",
|
||||
"about:newtab",
|
||||
|
@ -523,8 +517,3 @@ addEventListener("MozAfterPaint", function onFirstNonBlankPaint() {
|
|||
removeEventListener("MozAfterPaint", onFirstNonBlankPaint);
|
||||
sendAsyncMessage("Browser:FirstNonBlankPaint");
|
||||
});
|
||||
|
||||
addMessageListener("DOM:WebManifest:hasManifestLink", ManifestMessages);
|
||||
addMessageListener("DOM:ManifestObtainer:Obtain", ManifestMessages);
|
||||
addMessageListener("DOM:Manifest:FireAppInstalledEvent", ManifestMessages);
|
||||
addMessageListener("DOM:WebManifest:fetchIcon", ManifestMessages);
|
||||
|
|
|
@ -464,18 +464,22 @@ window._gBrowser = {
|
|||
|
||||
_setFindbarData() {
|
||||
// Ensure we know what the find bar key is in the content process:
|
||||
let {sharedData} = Services.ppmm;
|
||||
if (!sharedData.has("Findbar:Shortcut")) {
|
||||
let initialProcessData = Services.ppmm.initialProcessData;
|
||||
if (!initialProcessData.findBarShortcutData) {
|
||||
let keyEl = document.getElementById("key_find");
|
||||
let mods = keyEl.getAttribute("modifiers")
|
||||
.replace(/accel/i, AppConstants.platform == "macosx" ? "meta" : "control");
|
||||
sharedData.set("Findbar:Shortcut", {
|
||||
initialProcessData.findBarShortcutData = {
|
||||
key: keyEl.getAttribute("key"),
|
||||
shiftKey: mods.includes("shift"),
|
||||
ctrlKey: mods.includes("control"),
|
||||
altKey: mods.includes("alt"),
|
||||
metaKey: mods.includes("meta"),
|
||||
});
|
||||
modifiers: {
|
||||
shiftKey: mods.includes("shift"),
|
||||
ctrlKey: mods.includes("control"),
|
||||
altKey: mods.includes("alt"),
|
||||
metaKey: mods.includes("meta"),
|
||||
},
|
||||
};
|
||||
Services.ppmm.broadcastAsyncMessage("Findbar:ShortcutData",
|
||||
initialProcessData.findBarShortcutData);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ add_task(async function startup() {
|
|||
max: 650,
|
||||
},
|
||||
"extensions.getAddons.cache.enabled": {
|
||||
min: 8,
|
||||
min: 7,
|
||||
max: 55,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -23,12 +23,18 @@ const whitelist = {
|
|||
"extension-process-script.js",
|
||||
]),
|
||||
modules: new Set([
|
||||
// From the test harness
|
||||
"chrome://mochikit/content/ShutdownLeaksCollector.jsm",
|
||||
"resource://specialpowers/MockColorPicker.jsm",
|
||||
"resource://specialpowers/MockFilePicker.jsm",
|
||||
"resource://specialpowers/MockPermissionPrompt.jsm",
|
||||
|
||||
// General utilities
|
||||
"resource://gre/modules/AppConstants.jsm",
|
||||
"resource://gre/modules/AsyncShutdown.jsm",
|
||||
"resource://gre/modules/DeferredTask.jsm",
|
||||
"resource://gre/modules/FileUtils.jsm",
|
||||
"resource://gre/modules/NetUtil.jsm",
|
||||
"resource://gre/modules/PromiseUtils.jsm",
|
||||
"resource://gre/modules/Services.jsm", // bug 1464542
|
||||
"resource://gre/modules/Timer.jsm",
|
||||
|
@ -53,8 +59,6 @@ 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",
|
||||
|
@ -67,6 +71,12 @@ const whitelist = {
|
|||
// Extensions
|
||||
"resource://gre/modules/ExtensionUtils.jsm",
|
||||
"resource://gre/modules/MessageChannel.jsm",
|
||||
|
||||
// Service workers
|
||||
"resource://gre/modules/ServiceWorkerCleanUp.jsm",
|
||||
|
||||
// Shield
|
||||
"resource://normandy-content/AboutPages.jsm",
|
||||
]),
|
||||
};
|
||||
|
||||
|
|
|
@ -1805,7 +1805,7 @@ BrowserGlue.prototype = {
|
|||
_migrateUI: function BG__migrateUI() {
|
||||
// Use an increasing number to keep track of the current migration state.
|
||||
// Completely unrelated to the current Firefox release number.
|
||||
const UI_VERSION = 72;
|
||||
const UI_VERSION = 73;
|
||||
const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
|
||||
|
||||
let currentUIVersion;
|
||||
|
@ -2142,6 +2142,19 @@ BrowserGlue.prototype = {
|
|||
Services.prefs.setIntPref(pref, Services.prefs.getIntPref(pref, 1) * 1000);
|
||||
}
|
||||
|
||||
if (currentUIVersion < 73) {
|
||||
// Remove blocklist JSON local dumps in profile.
|
||||
OS.File.removeDir(OS.Path.join(OS.Constants.Path.profileDir, "blocklists"),
|
||||
{ ignoreAbsent: true });
|
||||
OS.File.removeDir(OS.Path.join(OS.Constants.Path.profileDir, "blocklists-preview"),
|
||||
{ ignoreAbsent: true });
|
||||
for (const filename of ["addons.json", "plugins.json", "gfx.json"]) {
|
||||
// Some old versions used to dump without subfolders. Clean them while we are at it.
|
||||
const path = OS.Path.join(OS.Constants.Path.profileDir, `blocklists-${filename}`);
|
||||
OS.File.remove(path, { ignoreAbsent: true });
|
||||
}
|
||||
}
|
||||
|
||||
// Update the migration version.
|
||||
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
|
||||
},
|
||||
|
|
|
@ -2,18 +2,14 @@
|
|||
* 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/. */
|
||||
|
||||
var EXPORTED_SYMBOLS = ["UITourListener"];
|
||||
/* eslint-env mozilla/frame-script */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const PREF_TEST_WHITELIST = "browser.uitour.testingOrigins";
|
||||
const UITOUR_PERMISSION = "uitour";
|
||||
|
||||
class UITourListener {
|
||||
constructor(mm) {
|
||||
this.mm = mm;
|
||||
}
|
||||
|
||||
var UITourListener = {
|
||||
handleEvent(event) {
|
||||
if (!Services.prefs.getBoolPref("browser.uitour.enabled")) {
|
||||
return;
|
||||
|
@ -21,14 +17,14 @@ class UITourListener {
|
|||
if (!this.ensureTrustedOrigin()) {
|
||||
return;
|
||||
}
|
||||
this.mm.addMessageListener("UITour:SendPageCallback", this);
|
||||
this.mm.addMessageListener("UITour:SendPageNotification", this);
|
||||
this.mm.sendAsyncMessage("UITour:onPageEvent", {
|
||||
addMessageListener("UITour:SendPageCallback", this);
|
||||
addMessageListener("UITour:SendPageNotification", this);
|
||||
sendAsyncMessage("UITour:onPageEvent", {
|
||||
detail: event.detail,
|
||||
type: event.type,
|
||||
pageVisibilityState: this.mm.content.document.visibilityState,
|
||||
pageVisibilityState: content.document.visibilityState,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
isTestingOrigin(aURI) {
|
||||
if (Services.prefs.getPrefType(PREF_TEST_WHITELIST) != Services.prefs.PREF_STRING) {
|
||||
|
@ -47,7 +43,7 @@ class UITourListener {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// This function is copied from UITour.jsm.
|
||||
isSafeScheme(aURI) {
|
||||
|
@ -59,11 +55,9 @@ class UITourListener {
|
|||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
ensureTrustedOrigin() {
|
||||
let {content} = this.mm;
|
||||
|
||||
if (content.top != content)
|
||||
return false;
|
||||
|
||||
|
@ -80,7 +74,7 @@ class UITourListener {
|
|||
return true;
|
||||
|
||||
return this.isTestingOrigin(uri);
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage(aMessage) {
|
||||
switch (aMessage.name) {
|
||||
|
@ -91,19 +85,21 @@ class UITourListener {
|
|||
this.sendPageEvent("Notification", aMessage.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
sendPageEvent(type, detail) {
|
||||
if (!this.ensureTrustedOrigin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let win = this.mm.content;
|
||||
let doc = content.document;
|
||||
let eventName = "mozUITour" + type;
|
||||
let event = new win.CustomEvent(eventName, {
|
||||
let event = new doc.defaultView.CustomEvent(eventName, {
|
||||
bubbles: true,
|
||||
detail: Cu.cloneInto(detail, win),
|
||||
detail: Cu.cloneInto(detail, doc.defaultView)
|
||||
});
|
||||
win.document.dispatchEvent(event);
|
||||
doc.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
addEventListener("mozUITour", UITourListener, false, true);
|
|
@ -0,0 +1,6 @@
|
|||
# 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/.
|
||||
|
||||
browser.jar:
|
||||
content/browser/content-UITour.js
|
|
@ -3,10 +3,11 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'ContentUITour.jsm',
|
||||
'UITour.jsm',
|
||||
]
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
'test/browser.ini',
|
||||
]
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
DIRS += [
|
||||
'aushelper',
|
||||
'followonsearch',
|
||||
'formautofill',
|
||||
'onboarding',
|
||||
'pdfjs',
|
||||
|
|
|
@ -370,10 +370,6 @@
|
|||
@RESPATH@/components/extension-process-script.js
|
||||
@RESPATH@/browser/components/extensions-browser.manifest
|
||||
|
||||
; [Normandy]
|
||||
@RESPATH@/components/shield.manifest
|
||||
@RESPATH@/components/shield-content-process.js
|
||||
|
||||
; [PDF Viewer]
|
||||
@RESPATH@/browser/components/pdfjs.manifest
|
||||
@RESPATH@/browser/components/pdfjs.js
|
||||
|
|
|
@ -13,10 +13,13 @@ var EXPORTED_SYMBOLS = [
|
|||
];
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URLSearchParams"]);
|
||||
|
||||
// The upper bound for the count of the visited unique domain names.
|
||||
const MAX_UNIQUE_VISITED_DOMAINS = 100;
|
||||
|
||||
|
@ -88,7 +91,6 @@ const URLBAR_SELECTED_RESULT_METHODS = {
|
|||
|
||||
const MINIMUM_TAB_COUNT_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes, in ms
|
||||
|
||||
|
||||
function getOpenTabsAndWinsCounts() {
|
||||
let tabCount = 0;
|
||||
let winCount = 0;
|
||||
|
@ -159,6 +161,10 @@ let URICountListener = {
|
|||
return;
|
||||
}
|
||||
|
||||
// Don't include URI and domain counts when in private mode.
|
||||
let shouldCountURI = !PrivateBrowsingUtils.isWindowPrivate(browser.ownerGlobal) ||
|
||||
Services.prefs.getBoolPref("browser.engagement.total_uri_count.pbm", false);
|
||||
|
||||
// Track URI loads, even if they're not http(s).
|
||||
let uriSpec = null;
|
||||
try {
|
||||
|
@ -166,7 +172,9 @@ let URICountListener = {
|
|||
} catch (e) {
|
||||
// If we have troubles parsing the spec, still count this as
|
||||
// an unfiltered URI.
|
||||
Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1);
|
||||
if (shouldCountURI) {
|
||||
Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -188,12 +196,42 @@ let URICountListener = {
|
|||
// The URI wasn't from a restored tab. Count it among the unfiltered URIs.
|
||||
// If this is an http(s) URI, this also gets counted by the "total_uri_count"
|
||||
// probe.
|
||||
Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1);
|
||||
if (shouldCountURI) {
|
||||
Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1);
|
||||
}
|
||||
|
||||
if (!this.isHttpURI(uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let parseURLResult = Services.search.parseSubmissionURL(uriSpec);
|
||||
if (parseURLResult.engine) {
|
||||
this._recordSearchTelemetry(uriSpec, parseURLResult);
|
||||
} else if (this._urlsQueuedForParsing) {
|
||||
if (Services.search.isInitialized) {
|
||||
this._urlsQueuedForParsing = null;
|
||||
} else {
|
||||
this._urlsQueuedForParsing.push(uriSpec);
|
||||
if (this._urlsQueuedForParsing.length == 1) {
|
||||
Services.search.init(rv => {
|
||||
if (Components.isSuccessCode(rv)) {
|
||||
for (let url of this._urlsQueuedForParsing) {
|
||||
let innerParseURLResult = Services.search.parseSubmissionURL(url);
|
||||
if (innerParseURLResult.engine) {
|
||||
this._recordSearchTelemetry(url, innerParseURLResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
this._urlsQueuedForParsing = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldCountURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the URI counts.
|
||||
Services.telemetry.scalarAdd(TOTAL_URI_COUNT_SCALAR_NAME, 1);
|
||||
|
||||
|
@ -226,6 +264,31 @@ let URICountListener = {
|
|||
this._domainSet.clear();
|
||||
},
|
||||
|
||||
_urlsQueuedForParsing: [],
|
||||
|
||||
_recordSearchTelemetry(url, parseURLResult) {
|
||||
switch (parseURLResult.engine.identifier) {
|
||||
case "google":
|
||||
case "google-2018":
|
||||
let type;
|
||||
let queries = new URLSearchParams(url.split("?")[1]);
|
||||
let code = queries.get("client");
|
||||
if (code) {
|
||||
// Detecting follow-on searches for sap is a little tricky.
|
||||
// There are a few parameters that only show up
|
||||
// with follow-ons, so we look for those. (oq/ved/ei)
|
||||
type = queries.has("oq") || queries.has("ved") || queries.has("ei") ? "sap-follow-on" : "sap";
|
||||
} else {
|
||||
type = "organic";
|
||||
}
|
||||
let payload = `google.in-content.${type}:${code || "none"}`;
|
||||
|
||||
let histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
|
||||
histogram.add(payload);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
};
|
||||
|
@ -614,11 +677,6 @@ let BrowserUsageTelemetry = {
|
|||
win.addEventListener("unload", this);
|
||||
win.addEventListener("TabOpen", this, true);
|
||||
|
||||
// Don't include URI and domain counts when in private mode.
|
||||
if (PrivateBrowsingUtils.isWindowPrivate(win) &&
|
||||
!Services.prefs.getBoolPref("browser.engagement.total_uri_count.pbm", false)) {
|
||||
return;
|
||||
}
|
||||
win.gBrowser.tabContainer.addEventListener(TAB_RESTORING_TOPIC, this);
|
||||
win.gBrowser.addTabsProgressListener(URICountListener);
|
||||
},
|
||||
|
@ -630,11 +688,6 @@ let BrowserUsageTelemetry = {
|
|||
win.removeEventListener("unload", this);
|
||||
win.removeEventListener("TabOpen", this, true);
|
||||
|
||||
// Don't include URI and domain counts when in private mode.
|
||||
if (PrivateBrowsingUtils.isWindowPrivate(win.defaultView) &&
|
||||
!Services.prefs.getBoolPref("browser.engagement.total_uri_count.pbm", false)) {
|
||||
return;
|
||||
}
|
||||
win.defaultView.gBrowser.tabContainer.removeEventListener(TAB_RESTORING_TOPIC, this);
|
||||
win.defaultView.gBrowser.removeTabsProgressListener(URICountListener);
|
||||
},
|
||||
|
|
|
@ -37,6 +37,7 @@ class AnimationListContainer extends PureComponent {
|
|||
setAnimationsCurrentTime: PropTypes.func.isRequired,
|
||||
setHighlightedNode: PropTypes.func.isRequired,
|
||||
setSelectedNode: PropTypes.func.isRequired,
|
||||
sidebarWidth: PropTypes.number.isRequired,
|
||||
simulateAnimation: PropTypes.func.isRequired,
|
||||
timeScale: PropTypes.object.isRequired,
|
||||
};
|
||||
|
@ -55,8 +56,17 @@ class AnimationListContainer extends PureComponent {
|
|||
this.updateState(this.props);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.updateState(nextProps);
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
timeScale,
|
||||
sidebarWidth
|
||||
} = this.props;
|
||||
|
||||
if (timeScale.getDuration() !== prevProps.timeScale.getDuration() ||
|
||||
timeScale.zeroPositionTime !== prevProps.timeScale.zeroPositionTime ||
|
||||
sidebarWidth !== prevProps.sidebarWidth) {
|
||||
this.updateState(this.props);
|
||||
}
|
||||
}
|
||||
|
||||
updateState(props) {
|
||||
|
@ -79,25 +89,16 @@ class AnimationListContainer extends PureComponent {
|
|||
// Need to display first graduation since position will be shifted.
|
||||
if (needToShift) {
|
||||
const label = timeScale.formatTime(timeScale.distanceToRelativeTime(0));
|
||||
ticks.push({ position: 0, label });
|
||||
ticks.push({ position: 0, label, width: shiftWidth });
|
||||
}
|
||||
|
||||
for (let i = 0; i <= tickCount; i++) {
|
||||
const position = ((i * intervalWidth) + shiftWidth) * 100 / width;
|
||||
const distance = timeScale.distanceToRelativeTime(position);
|
||||
let label = isAllDurationInfinity && i === tickCount
|
||||
? getStr("player.infiniteTimeLabel")
|
||||
: timeScale.formatTime(distance);
|
||||
// As result of shifting the label, first shifted label might overlap
|
||||
// to the most left label. So display empyt label in this case.
|
||||
// And prevent to skip displaying zero position label.
|
||||
if (i === 0 &&
|
||||
needToShift &&
|
||||
shiftWidth < intervalWidth &&
|
||||
Math.abs(distance) >= 0.001) {
|
||||
label = "";
|
||||
}
|
||||
ticks.push({ position, label });
|
||||
const label = isAllDurationInfinity && i === tickCount
|
||||
? getStr("player.infiniteTimeLabel")
|
||||
: timeScale.formatTime(distance);
|
||||
ticks.push({ position, label, width: intervalWidth });
|
||||
}
|
||||
|
||||
this.setState({ ticks });
|
||||
|
|
|
@ -29,7 +29,10 @@ class TickLabels extends PureComponent {
|
|||
dom.div(
|
||||
{
|
||||
className: "tick-label",
|
||||
style: { marginInlineStart: `${ tick.position }%` },
|
||||
style: {
|
||||
marginInlineStart: `${ tick.position }%`,
|
||||
maxWidth: `${ tick.width }px`
|
||||
},
|
||||
},
|
||||
tick.label
|
||||
)
|
||||
|
|
|
@ -646,6 +646,9 @@ select.playback-rate-selector.devtools-button:not(:empty):not(:disabled):not(.ch
|
|||
border-inline-start: var(--tick-line-style);
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.animated-property-list-container .tick-label:last-child {
|
||||
|
|
|
@ -307,6 +307,7 @@ class FilterBar extends Component {
|
|||
return (
|
||||
dom.div({
|
||||
className: "webconsole-filteringbar-wrapper",
|
||||
"aria-live": "off",
|
||||
ref: node => {
|
||||
this.wrapperNode = node;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ const TEST_URI = `data:text/html;charset=utf-8,<script>
|
|||
window.logStuff = function () {
|
||||
console.log("simple " + "text message");
|
||||
function wrapper() {
|
||||
console.log(new Error("error object"));
|
||||
console.trace();
|
||||
}
|
||||
wrapper();
|
||||
|
@ -100,6 +101,17 @@ add_task(async function() {
|
|||
ok(TRACE_FORMAT.test(lines[1]), "Stacktrace line has the right format:\n" + lines[1]);
|
||||
ok(TRACE_FORMAT.test(lines[2]), "Stacktrace line has the right format:\n" + lines[2]);
|
||||
|
||||
info("Test copy menu item for the error message");
|
||||
message = await waitFor(() => findMessage(hud, "Error:"));
|
||||
clipboardText = await copyMessageContent(hud, message);
|
||||
ok(true, "Clipboard text was found and saved");
|
||||
lines = clipboardText.split("\n");
|
||||
is(lines[0], `Error: "error object"`, "Error object first line has expected text");
|
||||
ok(lines[1].startsWith(`\twrapper data:text/html`),
|
||||
"Error stacktrace first line starts with expected value");
|
||||
ok(lines[2].startsWith(`\tlogStuff data:text/html`),
|
||||
"Error stacktrace second line starts with expected value");
|
||||
|
||||
observer.destroy();
|
||||
Services.prefs.clearUserPref(PREF_MESSAGE_TIMESTAMP);
|
||||
});
|
||||
|
|
|
@ -6245,13 +6245,13 @@ nsIDocument::SetTitle(const nsAString& aTitle, ErrorResult& aRv)
|
|||
}
|
||||
#endif
|
||||
|
||||
// Batch updates so that mutation events don't change "the title
|
||||
// element" under us
|
||||
mozAutoDocUpdate updateBatch(this, true);
|
||||
|
||||
Maybe<mozAutoDocUpdate> updateBatch;
|
||||
nsCOMPtr<Element> title = GetTitleElement();
|
||||
if (rootElement->IsSVGElement(nsGkAtoms::svg)) {
|
||||
if (!title) {
|
||||
// Batch updates so that mutation events don't change "the title
|
||||
// element" under us
|
||||
updateBatch.emplace(this, true);
|
||||
RefPtr<mozilla::dom::NodeInfo> titleInfo =
|
||||
mNodeInfoManager->GetNodeInfo(nsGkAtoms::title, nullptr,
|
||||
kNameSpaceID_SVG,
|
||||
|
@ -6265,6 +6265,9 @@ nsIDocument::SetTitle(const nsAString& aTitle, ErrorResult& aRv)
|
|||
}
|
||||
} else if (rootElement->IsHTMLElement()) {
|
||||
if (!title) {
|
||||
// Batch updates so that mutation events don't change "the title
|
||||
// element" under us
|
||||
updateBatch.emplace(this, true);
|
||||
Element* head = GetHeadElement();
|
||||
if (!head) {
|
||||
return;
|
||||
|
|
|
@ -144,6 +144,7 @@ support-files = bug1017086_inner.html
|
|||
[test_bug1017086_enable.html]
|
||||
support-files = bug1017086_inner.html
|
||||
[test_bug1079236.html]
|
||||
[test_bug1127588.html]
|
||||
[test_bug1145910.html]
|
||||
[test_bug1150308.html]
|
||||
skip-if = true # bug 1421545
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1127588
|
||||
-->
|
||||
<head>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1127588">Mozilla Bug 1127588</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1127588 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
window.onload = function () {
|
||||
let insertedEventCount = 0;
|
||||
let insertedListener = function() {
|
||||
insertedEventCount++;
|
||||
};
|
||||
|
||||
let removedEventCount = 0;
|
||||
let removedListener = function() {
|
||||
removedEventCount++;
|
||||
};
|
||||
|
||||
// Tests for no title element.
|
||||
document.addEventListener('DOMNodeRemoved', removedListener);
|
||||
document.addEventListener('DOMNodeInserted', insertedListener);
|
||||
document.title = "Test for Bug 1127588";
|
||||
document.removeEventListener('DOMNodeInserted', insertedListener);
|
||||
document.removeEventListener('DOMNodeRemoved', removedListener);
|
||||
|
||||
// Check result.
|
||||
is(insertedEventCount, 2, "Should get 'DOMNodeInserted' mutation event");
|
||||
is(removedEventCount, 0, "Should not get 'DOMNodeRemoved' mutation event");
|
||||
|
||||
// Test for updating title element.
|
||||
insertedEventCount = 0;
|
||||
removedEventCount = 0;
|
||||
document.addEventListener('DOMNodeRemoved', removedListener);
|
||||
document.addEventListener('DOMNodeInserted', insertedListener);
|
||||
document.title = document.title;
|
||||
document.removeEventListener('DOMNodeInserted', insertedListener);
|
||||
document.removeEventListener('DOMNodeRemoved', removedListener);
|
||||
|
||||
// Check result.
|
||||
is(insertedEventCount, 1, "Should get 'DOMNodeInserted' mutation event");
|
||||
is(removedEventCount, 1, "Should get 'DOMNodeRemoved' mutation event");
|
||||
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -8,3 +8,4 @@ toolkit.jar:
|
|||
content/global/BrowserElementChild.js (../browser-element/BrowserElementChild.js)
|
||||
content/global/BrowserElementChildPreload.js (../browser-element/BrowserElementChildPreload.js)
|
||||
content/global/BrowserElementCopyPaste.js (../browser-element/BrowserElementCopyPaste.js)
|
||||
content/global/manifestMessages.js (manifestMessages.js)
|
||||
|
|
|
@ -11,52 +11,54 @@
|
|||
*
|
||||
* BUG: https://bugzilla.mozilla.org/show_bug.cgi?id=1083410
|
||||
*/
|
||||
/*globals Task, ManifestObtainer, ManifestFinder, content, sendAsyncMessage, addMessageListener, Components*/
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["ManifestMessages"];
|
||||
|
||||
const {
|
||||
utils: Cu,
|
||||
} = Components;
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "ManifestObtainer",
|
||||
"resource://gre/modules/ManifestObtainer.jsm");
|
||||
"resource://gre/modules/ManifestObtainer.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "ManifestFinder",
|
||||
"resource://gre/modules/ManifestFinder.jsm");
|
||||
"resource://gre/modules/ManifestFinder.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "ManifestIcons",
|
||||
"resource://gre/modules/ManifestIcons.jsm");
|
||||
"resource://gre/modules/ManifestIcons.jsm");
|
||||
|
||||
class ManifestMessages {
|
||||
constructor(mm) {
|
||||
this.mm = mm;
|
||||
}
|
||||
|
||||
receiveMessage(message) {
|
||||
switch (message.name) {
|
||||
case "DOM:WebManifest:hasManifestLink":
|
||||
return this.hasManifestLink(message);
|
||||
case "DOM:ManifestObtainer:Obtain":
|
||||
return this.obtainManifest(message);
|
||||
case "DOM:Manifest:FireAppInstalledEvent":
|
||||
return this.fireAppInstalledEvent(message);
|
||||
case "DOM:WebManifest:fetchIcon":
|
||||
return this.fetchIcon(message);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
const MessageHandler = {
|
||||
registerListeners() {
|
||||
addMessageListener(
|
||||
"DOM:WebManifest:hasManifestLink",
|
||||
this.hasManifestLink.bind(this)
|
||||
);
|
||||
addMessageListener(
|
||||
"DOM:ManifestObtainer:Obtain",
|
||||
this.obtainManifest.bind(this)
|
||||
);
|
||||
addMessageListener(
|
||||
"DOM:Manifest:FireAppInstalledEvent",
|
||||
this.fireAppInstalledEvent.bind(this)
|
||||
);
|
||||
addMessageListener(
|
||||
"DOM:WebManifest:fetchIcon",
|
||||
this.fetchIcon.bind(this)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the this.mm.content document includes a link to a web manifest.
|
||||
* Check if the content document includes a link to a web manifest.
|
||||
* @param {Object} aMsg The IPC message, which is destructured to just
|
||||
* get the id.
|
||||
*/
|
||||
hasManifestLink({data: {id}}) {
|
||||
const response = makeMsgResponse(id);
|
||||
response.result = ManifestFinder.contentHasManifestLink(this.mm.content);
|
||||
response.result = ManifestFinder.contentHasManifestLink(content);
|
||||
response.success = true;
|
||||
this.mm.sendAsyncMessage("DOM:WebManifest:hasManifestLink", response);
|
||||
}
|
||||
sendAsyncMessage("DOM:WebManifest:hasManifestLink", response);
|
||||
},
|
||||
|
||||
/**
|
||||
* Asynchronously obtains a web manifest from this.mm.content by using the
|
||||
* Asynchronously obtains a web manifest from content by using the
|
||||
* ManifestObtainer and messages back the result.
|
||||
* @param {Object} aMsg The IPC message, which is destructured to just
|
||||
* get the id.
|
||||
|
@ -64,26 +66,26 @@ class ManifestMessages {
|
|||
async obtainManifest({data: {id}}) {
|
||||
const response = makeMsgResponse(id);
|
||||
try {
|
||||
response.result = await ManifestObtainer.contentObtainManifest(this.mm.content);
|
||||
response.result = await ManifestObtainer.contentObtainManifest(content);
|
||||
response.success = true;
|
||||
} catch (err) {
|
||||
response.result = serializeError(err);
|
||||
}
|
||||
this.mm.sendAsyncMessage("DOM:ManifestObtainer:Obtain", response);
|
||||
}
|
||||
sendAsyncMessage("DOM:ManifestObtainer:Obtain", response);
|
||||
},
|
||||
|
||||
fireAppInstalledEvent({data: {id}}) {
|
||||
fireAppInstalledEvent({data: {id}}){
|
||||
const ev = new Event("appinstalled");
|
||||
const response = makeMsgResponse(id);
|
||||
if (!this.mm.content || this.mm.content.top !== this.mm.content) {
|
||||
if (!content || content.top !== content) {
|
||||
const msg = "Can only dispatch install event on top-level browsing contexts.";
|
||||
response.result = serializeError(new Error(msg));
|
||||
} else {
|
||||
response.success = true;
|
||||
this.mm.content.dispatchEvent(ev);
|
||||
content.dispatchEvent(ev);
|
||||
}
|
||||
this.mm.sendAsyncMessage("DOM:Manifest:FireAppInstalledEvent", response);
|
||||
}
|
||||
sendAsyncMessage("DOM:Manifest:FireAppInstalledEvent", response);
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a manifest and an expected icon size, ask ManifestIcons
|
||||
|
@ -93,15 +95,15 @@ class ManifestMessages {
|
|||
const response = makeMsgResponse(id);
|
||||
try {
|
||||
response.result =
|
||||
await ManifestIcons.contentFetchIcon(this.mm.content, manifest, iconSize);
|
||||
await ManifestIcons.contentFetchIcon(content, manifest, iconSize);
|
||||
response.success = true;
|
||||
} catch (err) {
|
||||
response.result = serializeError(err);
|
||||
}
|
||||
this.mm.sendAsyncMessage("DOM:WebManifest:fetchIcon", response);
|
||||
}
|
||||
}
|
||||
sendAsyncMessage("DOM:WebManifest:fetchIcon", response);
|
||||
},
|
||||
|
||||
};
|
||||
/**
|
||||
* Utility function to Serializes an JS Error, so it can be transferred over
|
||||
* the message channel.
|
||||
|
@ -122,9 +124,11 @@ function serializeError(aError) {
|
|||
}
|
||||
|
||||
function makeMsgResponse(aId) {
|
||||
return {
|
||||
id: aId,
|
||||
success: false,
|
||||
result: undefined
|
||||
};
|
||||
}
|
||||
return {
|
||||
id: aId,
|
||||
success: false,
|
||||
result: undefined
|
||||
};
|
||||
}
|
||||
|
||||
MessageHandler.registerListeners();
|
|
@ -13,10 +13,6 @@ XPIDL_SOURCES += [
|
|||
|
||||
XPIDL_MODULE = 'dom'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'ManifestMessages.jsm',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom.ipc += [
|
||||
'IdType.h',
|
||||
'MemMapSnapshot.h',
|
||||
|
|
|
@ -496,7 +496,7 @@ RestyleManager::ContentRemoved(nsIContent* aOldChild,
|
|||
* This is called from both Restyle managers.
|
||||
*/
|
||||
void
|
||||
RestyleManager::ContentStateChangedInternal(Element* aElement,
|
||||
RestyleManager::ContentStateChangedInternal(const Element& aElement,
|
||||
EventStates aStateMask,
|
||||
nsChangeHint* aOutChangeHint)
|
||||
{
|
||||
|
@ -510,7 +510,7 @@ RestyleManager::ContentStateChangedInternal(Element* aElement,
|
|||
// based on content states, so if we already don't have a frame we don't
|
||||
// need to force a reframe -- if it's needed, the HasStateDependentStyle
|
||||
// call will handle things.
|
||||
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
|
||||
nsIFrame* primaryFrame = aElement.GetPrimaryFrame();
|
||||
if (primaryFrame) {
|
||||
// If it's generated content, ignore LOADING/etc state changes on it.
|
||||
if (!primaryFrame->IsGeneratedContentFrame() &&
|
||||
|
@ -2200,8 +2200,8 @@ ServoRestyleState::TableAwareParentFor(const nsIFrame* aChild)
|
|||
|
||||
void
|
||||
RestyleManager::PostRestyleEvent(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint)
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint)
|
||||
{
|
||||
MOZ_ASSERT(!(aMinChangeHint & nsChangeHint_NeutralChange),
|
||||
"Didn't expect explicit change hints to be neutral!");
|
||||
|
@ -2945,7 +2945,7 @@ RestyleManager::ClearSnapshots()
|
|||
}
|
||||
|
||||
ServoElementSnapshot&
|
||||
RestyleManager::SnapshotFor(Element* aElement)
|
||||
RestyleManager::SnapshotFor(Element& aElement)
|
||||
{
|
||||
MOZ_ASSERT(!mInStyleRefresh);
|
||||
|
||||
|
@ -2959,14 +2959,14 @@ RestyleManager::SnapshotFor(Element* aElement)
|
|||
//
|
||||
// Can't wait to make ProcessPendingRestyles the only entry-point for styling,
|
||||
// so this becomes much easier to reason about. Today is not that day though.
|
||||
MOZ_ASSERT(aElement->HasServoData());
|
||||
MOZ_ASSERT(!aElement->HasFlag(ELEMENT_HANDLED_SNAPSHOT));
|
||||
MOZ_ASSERT(aElement.HasServoData());
|
||||
MOZ_ASSERT(!aElement.HasFlag(ELEMENT_HANDLED_SNAPSHOT));
|
||||
|
||||
ServoElementSnapshot* snapshot = mSnapshots.LookupOrAdd(aElement, aElement);
|
||||
aElement->SetFlags(ELEMENT_HAS_SNAPSHOT);
|
||||
ServoElementSnapshot* snapshot = mSnapshots.LookupOrAdd(&aElement, aElement);
|
||||
aElement.SetFlags(ELEMENT_HAS_SNAPSHOT);
|
||||
|
||||
// Now that we have a snapshot, make sure a restyle is triggered.
|
||||
aElement->NoteDirtyForServo();
|
||||
aElement.NoteDirtyForServo();
|
||||
return *snapshot;
|
||||
}
|
||||
|
||||
|
@ -3177,30 +3177,33 @@ RestyleManager::ContentStateChanged(nsIContent* aContent,
|
|||
return;
|
||||
}
|
||||
|
||||
Element* aElement = aContent->AsElement();
|
||||
if (!aElement->HasServoData()) {
|
||||
Element& element = *aContent->AsElement();
|
||||
if (!element.HasServoData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsChangeHint changeHint;
|
||||
ContentStateChangedInternal(aElement, aChangedBits, &changeHint);
|
||||
ContentStateChangedInternal(element, aChangedBits, &changeHint);
|
||||
|
||||
// Don't bother taking a snapshot if no rules depend on these state bits.
|
||||
//
|
||||
// We always take a snapshot for the LTR/RTL event states, since Servo doesn't
|
||||
// track those bits in the same way, and we know that :dir() rules are always
|
||||
// present in UA style sheets.
|
||||
//
|
||||
// FIXME(emilio): Doesn't this early-return drop the change hint on the floor?
|
||||
// Should it?
|
||||
if (!aChangedBits.HasAtLeastOneOfStates(DIRECTION_STATES) &&
|
||||
!StyleSet()->HasStateDependency(*aElement, aChangedBits)) {
|
||||
!StyleSet()->HasStateDependency(element, aChangedBits)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServoElementSnapshot& snapshot = SnapshotFor(aElement);
|
||||
EventStates previousState = aElement->StyleState() ^ aChangedBits;
|
||||
ServoElementSnapshot& snapshot = SnapshotFor(element);
|
||||
EventStates previousState = element.StyleState() ^ aChangedBits;
|
||||
snapshot.AddState(previousState);
|
||||
|
||||
if (changeHint) {
|
||||
Servo_NoteExplicitHints(aElement, nsRestyleHint(0), changeHint);
|
||||
Servo_NoteExplicitHints(&element, nsRestyleHint(0), changeHint);
|
||||
}
|
||||
|
||||
// Assuming we need to invalidate cached style in getComputedStyle for
|
||||
|
@ -3271,30 +3274,30 @@ RestyleManager::AttributeWillChange(Element* aElement,
|
|||
int32_t aModType,
|
||||
const nsAttrValue* aNewValue)
|
||||
{
|
||||
TakeSnapshotForAttributeChange(aElement, aNameSpaceID, aAttribute);
|
||||
TakeSnapshotForAttributeChange(*aElement, aNameSpaceID, aAttribute);
|
||||
}
|
||||
|
||||
void
|
||||
RestyleManager::ClassAttributeWillBeChangedBySMIL(Element* aElement)
|
||||
{
|
||||
TakeSnapshotForAttributeChange(aElement, kNameSpaceID_None,
|
||||
TakeSnapshotForAttributeChange(*aElement, kNameSpaceID_None,
|
||||
nsGkAtoms::_class);
|
||||
}
|
||||
|
||||
void
|
||||
RestyleManager::TakeSnapshotForAttributeChange(Element* aElement,
|
||||
RestyleManager::TakeSnapshotForAttributeChange(Element& aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute)
|
||||
{
|
||||
MOZ_ASSERT(!mInStyleRefresh);
|
||||
|
||||
if (!aElement->HasServoData()) {
|
||||
if (!aElement.HasServoData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool influencesOtherPseudoClassState;
|
||||
if (!NeedToRecordAttrChange(*StyleSet(),
|
||||
*aElement,
|
||||
aElement,
|
||||
aNameSpaceID,
|
||||
aAttribute,
|
||||
&influencesOtherPseudoClassState)) {
|
||||
|
|
|
@ -472,7 +472,9 @@ protected:
|
|||
void RestyleForEmptyChange(Element* aContainer);
|
||||
void MaybeRestyleForEdgeChildChange(Element* aContainer, nsIContent* aChangedChild);
|
||||
|
||||
void ContentStateChangedInternal(Element* aElement,
|
||||
// TODO(emilio): there's no good reason this isn't part of ContentStateChanged
|
||||
// now, or the change hint isn't returned instead of via an out-param, really.
|
||||
void ContentStateChangedInternal(const Element&,
|
||||
EventStates aStateMask,
|
||||
nsChangeHint* aOutChangeHint);
|
||||
|
||||
|
@ -529,8 +531,8 @@ protected:
|
|||
|
||||
const SnapshotTable& Snapshots() const { return mSnapshots; }
|
||||
void ClearSnapshots();
|
||||
ServoElementSnapshot& SnapshotFor(mozilla::dom::Element* aElement);
|
||||
void TakeSnapshotForAttributeChange(mozilla::dom::Element* aElement,
|
||||
ServoElementSnapshot& SnapshotFor(Element&);
|
||||
void TakeSnapshotForAttributeChange(Element&,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute);
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
ServoElementSnapshot::ServoElementSnapshot(const Element* aElement)
|
||||
ServoElementSnapshot::ServoElementSnapshot(const Element& aElement)
|
||||
: mState(0)
|
||||
, mContains(Flags(0))
|
||||
, mIsTableBorderNonzero(false)
|
||||
|
@ -22,23 +22,22 @@ ServoElementSnapshot::ServoElementSnapshot(const Element* aElement)
|
|||
, mOtherAttributeChanged(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ServoElementSnapshot);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mIsHTMLElementInHTMLDocument =
|
||||
aElement->IsHTMLElement() && aElement->IsInHTMLDocument();
|
||||
mIsInChromeDocument = nsContentUtils::IsChromeDoc(aElement->OwnerDoc());
|
||||
mSupportsLangAttr = aElement->SupportsLangAttr();
|
||||
aElement.IsHTMLElement() && aElement.IsInHTMLDocument();
|
||||
mIsInChromeDocument = nsContentUtils::IsChromeDoc(aElement.OwnerDoc());
|
||||
mSupportsLangAttr = aElement.SupportsLangAttr();
|
||||
}
|
||||
|
||||
void
|
||||
ServoElementSnapshot::AddOtherPseudoClassState(Element* aElement)
|
||||
ServoElementSnapshot::AddOtherPseudoClassState(const Element& aElement)
|
||||
{
|
||||
MOZ_ASSERT(aElement);
|
||||
|
||||
if (HasOtherPseudoClassState()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsTableBorderNonzero = Gecko_IsTableBorderNonzero(aElement);
|
||||
mIsMozBrowserFrame = Gecko_IsBrowserFrame(aElement);
|
||||
mIsTableBorderNonzero = Gecko_IsTableBorderNonzero(&aElement);
|
||||
mIsMozBrowserFrame = Gecko_IsBrowserFrame(&aElement);
|
||||
|
||||
mContains |= Flags::OtherPseudoClassState;
|
||||
}
|
||||
|
|
|
@ -67,10 +67,11 @@ class ServoElementSnapshot
|
|||
public:
|
||||
typedef ServoElementSnapshotFlags Flags;
|
||||
|
||||
explicit ServoElementSnapshot(const Element* aElement);
|
||||
explicit ServoElementSnapshot(const Element&);
|
||||
|
||||
~ServoElementSnapshot()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_COUNT_DTOR(ServoElementSnapshot);
|
||||
}
|
||||
|
||||
|
@ -100,13 +101,13 @@ public:
|
|||
* The attribute name and namespace are used to note which kind of attribute
|
||||
* has changed.
|
||||
*/
|
||||
inline void AddAttrs(Element*, int32_t aNameSpaceID, nsAtom* aAttribute);
|
||||
inline void AddAttrs(const Element&, int32_t aNameSpaceID, nsAtom* aAttribute);
|
||||
|
||||
/**
|
||||
* Captures some other pseudo-class matching state not included in
|
||||
* EventStates.
|
||||
*/
|
||||
void AddOtherPseudoClassState(Element* aElement);
|
||||
void AddOtherPseudoClassState(const Element&);
|
||||
|
||||
/**
|
||||
* Needed methods for attribute matching.
|
||||
|
@ -194,7 +195,7 @@ private:
|
|||
|
||||
|
||||
inline void
|
||||
ServoElementSnapshot::AddAttrs(mozilla::dom::Element* aElement,
|
||||
ServoElementSnapshot::AddAttrs(const Element& aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute)
|
||||
{
|
||||
|
@ -214,20 +215,20 @@ ServoElementSnapshot::AddAttrs(mozilla::dom::Element* aElement,
|
|||
return;
|
||||
}
|
||||
|
||||
uint32_t attrCount = aElement->GetAttrCount();
|
||||
uint32_t attrCount = aElement.GetAttrCount();
|
||||
mAttrs.SetCapacity(attrCount);
|
||||
for (uint32_t i = 0; i < attrCount; ++i) {
|
||||
const BorrowedAttrInfo info = aElement->GetAttrInfoAt(i);
|
||||
const BorrowedAttrInfo info = aElement.GetAttrInfoAt(i);
|
||||
MOZ_ASSERT(info);
|
||||
mAttrs.AppendElement(ServoAttrSnapshot { *info.mName, *info.mValue });
|
||||
}
|
||||
|
||||
mContains |= Flags::Attributes;
|
||||
if (aElement->HasID()) {
|
||||
if (aElement.HasID()) {
|
||||
mContains |= Flags::Id;
|
||||
}
|
||||
|
||||
if (const nsAttrValue* classValue = aElement->GetClasses()) {
|
||||
if (const nsAttrValue* classValue = aElement.GetClasses()) {
|
||||
// FIXME(emilio): It's pretty unfortunate that this is only relevant for
|
||||
// SVG, yet it's a somewhat expensive copy. We should be able to do
|
||||
// better!
|
||||
|
|
|
@ -103,31 +103,6 @@ async function updatePinningList({ data: { current: records } }) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write list of records into JSON file, and notify nsBlocklistService.
|
||||
*
|
||||
* @param {Object} client RemoteSettingsClient instance
|
||||
* @param {Object} data Current records in the local db.
|
||||
*/
|
||||
async function updateJSONBlocklist(client, { data: { current: records } }) {
|
||||
// Write JSON dump for synchronous load at startup.
|
||||
const path = OS.Path.join(OS.Constants.Path.profileDir, client.filename);
|
||||
const blocklistFolder = OS.Path.dirname(path);
|
||||
|
||||
await OS.File.makeDir(blocklistFolder, {from: OS.Constants.Path.profileDir});
|
||||
|
||||
const serialized = JSON.stringify({data: records}, null, 2);
|
||||
try {
|
||||
await OS.File.writeAtomic(path, serialized, {tmpPath: path + ".tmp"});
|
||||
// Notify change to `nsBlocklistService`
|
||||
const eventData = {filename: client.filename};
|
||||
Services.cpmm.sendAsyncMessage("Blocklist:reload-from-disk", eventData);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This custom filter function is used to limit the entries returned
|
||||
* by `RemoteSettings("...").get()` depending on the target app information
|
||||
|
@ -211,7 +186,6 @@ function initialize() {
|
|||
signerName: Services.prefs.getCharPref(PREF_BLOCKLIST_ADDONS_SIGNER),
|
||||
filterFunc: targetAppFilter,
|
||||
});
|
||||
AddonBlocklistClient.on("sync", updateJSONBlocklist.bind(null, AddonBlocklistClient));
|
||||
|
||||
PluginBlocklistClient = RemoteSettings(Services.prefs.getCharPref(PREF_BLOCKLIST_PLUGINS_COLLECTION), {
|
||||
bucketName: Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET),
|
||||
|
@ -219,7 +193,6 @@ function initialize() {
|
|||
signerName: Services.prefs.getCharPref(PREF_BLOCKLIST_PLUGINS_SIGNER),
|
||||
filterFunc: targetAppFilter,
|
||||
});
|
||||
PluginBlocklistClient.on("sync", updateJSONBlocklist.bind(null, PluginBlocklistClient));
|
||||
|
||||
GfxBlocklistClient = RemoteSettings(Services.prefs.getCharPref(PREF_BLOCKLIST_GFX_COLLECTION), {
|
||||
bucketName: Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET),
|
||||
|
@ -227,7 +200,6 @@ function initialize() {
|
|||
signerName: Services.prefs.getCharPref(PREF_BLOCKLIST_GFX_SIGNER),
|
||||
filterFunc: targetAppFilter,
|
||||
});
|
||||
GfxBlocklistClient.on("sync", updateJSONBlocklist.bind(null, GfxBlocklistClient));
|
||||
|
||||
PinningBlocklistClient = RemoteSettings(Services.prefs.getCharPref(PREF_BLOCKLIST_PINNING_COLLECTION), {
|
||||
bucketName: Services.prefs.getCharPref(PREF_BLOCKLIST_PINNING_BUCKET),
|
||||
|
|
|
@ -4,7 +4,6 @@ ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
const { FileUtils } = ChromeUtils.import("resource://gre/modules/FileUtils.jsm", {});
|
||||
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm", {});
|
||||
|
||||
const { RemoteSettings } = ChromeUtils.import("resource://services-settings/remote-settings.js", {});
|
||||
const BlocklistClients = ChromeUtils.import("resource://services-common/blocklist-clients.js", {});
|
||||
|
@ -18,12 +17,6 @@ const IS_ANDROID = AppConstants.platform == "android";
|
|||
let gBlocklistClients;
|
||||
let server;
|
||||
|
||||
async function readJSON(filepath) {
|
||||
const binaryData = await OS.File.read(filepath);
|
||||
const textData = (new TextDecoder()).decode(binaryData);
|
||||
return Promise.resolve(JSON.parse(textData));
|
||||
}
|
||||
|
||||
async function clear_state() {
|
||||
for (let {client} of gBlocklistClients) {
|
||||
// Remove last server times.
|
||||
|
@ -32,11 +25,6 @@ async function clear_state() {
|
|||
// Clear local DB.
|
||||
const collection = await client.openCollection();
|
||||
await collection.clear();
|
||||
|
||||
// Remove JSON dumps folders in profile dir.
|
||||
const dumpFile = OS.Path.join(OS.Constants.Path.profileDir, client.filename);
|
||||
const folder = OS.Path.dirname(dumpFile);
|
||||
await OS.File.removeDir(folder, { ignoreAbsent: true });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,21 +134,6 @@ add_task(async function test_initial_dump_is_loaded_when_using_get_on_empty_coll
|
|||
});
|
||||
add_task(clear_state);
|
||||
|
||||
add_task(async function test_list_is_written_to_file_in_profile() {
|
||||
for (let {client, testData} of gBlocklistClients) {
|
||||
const filePath = OS.Path.join(OS.Constants.Path.profileDir, client.filename);
|
||||
const profFile = new FileUtils.File(filePath);
|
||||
strictEqual(profFile.exists(), false);
|
||||
|
||||
await client.maybeSync(2000, Date.now(), {loadDump: false});
|
||||
|
||||
strictEqual(profFile.exists(), true);
|
||||
const content = await readJSON(profFile.path);
|
||||
equal(content.data[0].blockID, testData[testData.length - 1]);
|
||||
}
|
||||
});
|
||||
add_task(clear_state);
|
||||
|
||||
add_task(async function test_current_server_time_is_saved_in_pref() {
|
||||
for (let {client} of gBlocklistClients) {
|
||||
// The lastCheckTimePref was customized:
|
||||
|
@ -174,42 +147,6 @@ add_task(async function test_current_server_time_is_saved_in_pref() {
|
|||
});
|
||||
add_task(clear_state);
|
||||
|
||||
add_task(async function test_update_json_file_when_addons_has_changes() {
|
||||
for (let {client, testData} of gBlocklistClients) {
|
||||
await client.maybeSync(2000, Date.now() - 1000, {loadDump: false});
|
||||
const filePath = OS.Path.join(OS.Constants.Path.profileDir, client.filename);
|
||||
const profFile = new FileUtils.File(filePath);
|
||||
const fileLastModified = profFile.lastModifiedTime = profFile.lastModifiedTime - 1000;
|
||||
const serverTime = Date.now();
|
||||
|
||||
await client.maybeSync(3001, serverTime);
|
||||
|
||||
// File was updated.
|
||||
notEqual(fileLastModified, profFile.lastModifiedTime);
|
||||
const content = await readJSON(profFile.path);
|
||||
deepEqual(content.data.map((r) => r.blockID), testData);
|
||||
// Server time was updated.
|
||||
const after = Services.prefs.getIntPref(client.lastCheckTimePref);
|
||||
equal(after, Math.round(serverTime / 1000));
|
||||
}
|
||||
});
|
||||
add_task(clear_state);
|
||||
|
||||
add_task(async function test_sends_reload_message_when_blocklist_has_changes() {
|
||||
for (let {client} of gBlocklistClients) {
|
||||
let received = await new Promise((resolve, reject) => {
|
||||
Services.ppmm.addMessageListener("Blocklist:reload-from-disk", {
|
||||
receiveMessage(aMsg) { resolve(aMsg); }
|
||||
});
|
||||
|
||||
client.maybeSync(2000, Date.now() - 1000, {loadDump: false});
|
||||
});
|
||||
|
||||
equal(received.data.filename, client.filename);
|
||||
}
|
||||
});
|
||||
add_task(clear_state);
|
||||
|
||||
add_task(async function test_sync_event_data_is_filtered_for_target() {
|
||||
// Here we will synchronize 4 times, the first two to initialize the local DB and
|
||||
// the last two about event filtered data.
|
||||
|
|
|
@ -192,11 +192,11 @@ async function fetchLatestChanges(url, lastEtag) {
|
|||
|
||||
/**
|
||||
* Load the the JSON file distributed with the release for this collection.
|
||||
* @param {String} bucket
|
||||
* @param {String} collection
|
||||
*/
|
||||
async function loadDumpFile(filename) {
|
||||
// Replace OS specific path separator by / for URI.
|
||||
const { components: folderFile } = OS.Path.split(filename);
|
||||
const fileURI = `resource://app/defaults/settings/${folderFile.join("/")}`;
|
||||
async function loadDumpFile(bucket, collection) {
|
||||
const fileURI = `resource://app/defaults/settings/${bucket}/${collection}.json`;
|
||||
const response = await fetch(fileURI);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Could not read from '${fileURI}'`);
|
||||
|
@ -225,12 +225,6 @@ class RemoteSettingsClient {
|
|||
return `${this.bucketName}/${this.collectionName}`;
|
||||
}
|
||||
|
||||
get filename() {
|
||||
// Replace slash by OS specific path separator (eg. Windows)
|
||||
const identifier = OS.Path.join(...this.identifier.split("/"));
|
||||
return `${identifier}.json`;
|
||||
}
|
||||
|
||||
get lastCheckTimePref() {
|
||||
return this._lastCheckTimePref || `services.settings.${this.bucketName}.${this.collectionName}.last_check`;
|
||||
}
|
||||
|
@ -302,7 +296,7 @@ class RemoteSettingsClient {
|
|||
// a packaged JSON dump.
|
||||
if (timestamp == null) {
|
||||
try {
|
||||
const { data } = await loadDumpFile(this.filename);
|
||||
const { data } = await loadDumpFile(this.bucketName, this.collectionName);
|
||||
await c.loadDump(data);
|
||||
} catch (e) {
|
||||
// Report but return an empty list since there will be no data anyway.
|
||||
|
@ -353,7 +347,7 @@ class RemoteSettingsClient {
|
|||
// cold start.
|
||||
if (!collectionLastModified && loadDump) {
|
||||
try {
|
||||
const initialData = await loadDumpFile(this.filename);
|
||||
const initialData = await loadDumpFile(this.bucketName, this.collectionName);
|
||||
await collection.loadDump(initialData.data);
|
||||
collectionLastModified = await collection.db.getLastModified();
|
||||
} catch (e) {
|
||||
|
@ -586,9 +580,8 @@ async function databaseExists(bucket, collection) {
|
|||
* @return {bool} Whether it is present or not.
|
||||
*/
|
||||
async function hasLocalDump(bucket, collection) {
|
||||
const filename = OS.Path.join(bucket, `${collection}.json`);
|
||||
try {
|
||||
await loadDumpFile(filename);
|
||||
await loadDumpFile(bucket, collection);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
|
|
|
@ -45,12 +45,6 @@ pub trait Element: Sized + Clone + Debug {
|
|||
self.parent_element()
|
||||
}
|
||||
|
||||
/// Skips non-element nodes
|
||||
fn first_child_element(&self) -> Option<Self>;
|
||||
|
||||
/// Skips non-element nodes
|
||||
fn last_child_element(&self) -> Option<Self>;
|
||||
|
||||
/// Skips non-element nodes
|
||||
fn prev_sibling_element(&self) -> Option<Self>;
|
||||
|
||||
|
|
|
@ -120,7 +120,6 @@ mod bindings {
|
|||
let mut file = File::open(&path).unwrap();
|
||||
let mut content = String::new();
|
||||
file.read_to_string(&mut content).unwrap();
|
||||
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
||||
added_paths.insert(path);
|
||||
// Find all includes and add them recursively
|
||||
for cap in INCLUDE_RE.captures_iter(&content) {
|
||||
|
@ -286,6 +285,7 @@ mod bindings {
|
|||
);
|
||||
},
|
||||
};
|
||||
|
||||
for fixup in fixups.iter() {
|
||||
result = Regex::new(&fixup.pat)
|
||||
.unwrap()
|
||||
|
@ -602,6 +602,10 @@ mod bindings {
|
|||
generate_bindings(),
|
||||
generate_atoms(),
|
||||
}
|
||||
|
||||
for path in ADDED_PATHS.lock().unwrap().iter() {
|
||||
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ use selector_parser::{PseudoElement, RestyleDamage, EAGER_PSEUDO_COUNT};
|
|||
use selectors::NthIndexCache;
|
||||
use servo_arc::Arc;
|
||||
use shared_lock::StylesheetGuards;
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
@ -273,16 +272,8 @@ impl ElementData {
|
|||
return InvalidationResult::empty();
|
||||
}
|
||||
|
||||
let mut non_document_styles = SmallVec::<[_; 3]>::new();
|
||||
let matches_doc_author_rules =
|
||||
element.each_applicable_non_document_style_rule_data(|data, quirks_mode, host| {
|
||||
non_document_styles.push((data, quirks_mode, host.map(|h| h.opaque())))
|
||||
});
|
||||
|
||||
let mut processor = StateAndAttrInvalidationProcessor::new(
|
||||
shared_context,
|
||||
&non_document_styles,
|
||||
matches_doc_author_rules,
|
||||
element,
|
||||
self,
|
||||
nth_index_cache,
|
||||
|
|
|
@ -1957,30 +1957,6 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
|||
unsafe { Some(GeckoElement(&slot.as_ref()?._base._base._base._base)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn first_child_element(&self) -> Option<Self> {
|
||||
let mut child = self.as_node().first_child();
|
||||
while let Some(child_node) = child {
|
||||
if let Some(el) = child_node.as_element() {
|
||||
return Some(el);
|
||||
}
|
||||
child = child_node.next_sibling();
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last_child_element(&self) -> Option<Self> {
|
||||
let mut child = self.as_node().last_child();
|
||||
while let Some(child_node) = child {
|
||||
if let Some(el) = child_node.as_element() {
|
||||
return Some(el);
|
||||
}
|
||||
child = child_node.prev_sibling();
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn prev_sibling_element(&self) -> Option<Self> {
|
||||
let mut sibling = self.as_node().prev_sibling();
|
||||
|
|
|
@ -283,16 +283,6 @@ where
|
|||
Some(Self::new(host, self.snapshot_map))
|
||||
}
|
||||
|
||||
fn first_child_element(&self) -> Option<Self> {
|
||||
let child = self.element.first_child_element()?;
|
||||
Some(Self::new(child, self.snapshot_map))
|
||||
}
|
||||
|
||||
fn last_child_element(&self) -> Option<Self> {
|
||||
let child = self.element.last_child_element()?;
|
||||
Some(Self::new(child, self.snapshot_map))
|
||||
}
|
||||
|
||||
fn prev_sibling_element(&self) -> Option<Self> {
|
||||
let sibling = self.element.prev_sibling_element()?;
|
||||
Some(Self::new(sibling, self.snapshot_map))
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//! changes.
|
||||
|
||||
use {Atom, WeakAtom};
|
||||
use context::{QuirksMode, SharedStyleContext};
|
||||
use context::SharedStyleContext;
|
||||
use data::ElementData;
|
||||
use dom::TElement;
|
||||
use element_state::ElementState;
|
||||
|
@ -18,13 +18,11 @@ use invalidation::element::restyle_hints::RestyleHint;
|
|||
use selector_map::SelectorMap;
|
||||
use selector_parser::Snapshot;
|
||||
use selectors::NthIndexCache;
|
||||
use selectors::OpaqueElement;
|
||||
use selectors::attr::CaseSensitivity;
|
||||
use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode};
|
||||
use selectors::matching::matches_selector;
|
||||
use smallvec::SmallVec;
|
||||
use stylesheets::origin::{Origin, OriginSet};
|
||||
use stylist::CascadeData;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum VisitedDependent {
|
||||
|
@ -56,19 +54,15 @@ where
|
|||
/// changes.
|
||||
pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
|
||||
shared_context: &'a SharedStyleContext<'b>,
|
||||
shadow_rule_datas: &'a [(&'b CascadeData, QuirksMode, Option<OpaqueElement>)],
|
||||
matches_document_author_rules: bool,
|
||||
element: E,
|
||||
data: &'a mut ElementData,
|
||||
matching_context: MatchingContext<'a, E::Impl>,
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
|
||||
impl<'a, 'b: 'a, E: TElement + 'b> StateAndAttrInvalidationProcessor<'a, 'b, E> {
|
||||
/// Creates a new StateAndAttrInvalidationProcessor.
|
||||
pub fn new(
|
||||
shared_context: &'a SharedStyleContext<'b>,
|
||||
shadow_rule_datas: &'a [(&'b CascadeData, QuirksMode, Option<OpaqueElement>)],
|
||||
matches_document_author_rules: bool,
|
||||
element: E,
|
||||
data: &'a mut ElementData,
|
||||
nth_index_cache: &'a mut NthIndexCache,
|
||||
|
@ -83,8 +77,6 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
|
|||
|
||||
Self {
|
||||
shared_context,
|
||||
shadow_rule_datas,
|
||||
matches_document_author_rules,
|
||||
element,
|
||||
data,
|
||||
matching_context,
|
||||
|
@ -157,6 +149,7 @@ where
|
|||
descendant_invalidations: &mut DescendantInvalidationLists<'a>,
|
||||
sibling_invalidations: &mut InvalidationVector<'a>,
|
||||
) -> bool {
|
||||
debug_assert_eq!(element, self.element);
|
||||
debug_assert!(element.has_snapshot(), "Why bothering?");
|
||||
|
||||
let wrapper = ElementWrapper::new(element, &*self.shared_context.snapshot_map);
|
||||
|
@ -241,6 +234,13 @@ where
|
|||
element
|
||||
};
|
||||
|
||||
let mut shadow_rule_datas = SmallVec::<[_; 3]>::new();
|
||||
let matches_document_author_rules =
|
||||
element.each_applicable_non_document_style_rule_data(|data, quirks_mode, host| {
|
||||
shadow_rule_datas.push((data, quirks_mode, host.map(|h| h.opaque())))
|
||||
});
|
||||
|
||||
|
||||
let invalidated_self = {
|
||||
let mut collector = Collector {
|
||||
wrapper,
|
||||
|
@ -258,7 +258,7 @@ where
|
|||
invalidates_self: false,
|
||||
};
|
||||
|
||||
let document_origins = if !self.matches_document_author_rules {
|
||||
let document_origins = if !matches_document_author_rules {
|
||||
Origin::UserAgent.into()
|
||||
} else {
|
||||
OriginSet::all()
|
||||
|
@ -271,7 +271,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
for &(ref data, quirks_mode, ref host) in self.shadow_rule_datas {
|
||||
for &(ref data, quirks_mode, ref host) in &shadow_rule_datas {
|
||||
// FIXME(emilio): Replace with assert / remove when we figure
|
||||
// out what to do with the quirks mode mismatches
|
||||
// (that is, when bug 1406875 is properly fixed).
|
||||
|
|
|
@ -305,10 +305,10 @@
|
|||
},
|
||||
"redo": {
|
||||
"hashes": [
|
||||
"sha256:69ea97e4d934806475fe86f93e4f74da2994acab20c2e3cfe0d3ca6380e3f907"
|
||||
"sha256:080e9eb34c42e2a09dbec48379b876ac1b64fd04483cef0a03af281cc9333bd3"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.6"
|
||||
"version": "==1.7"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
|
@ -366,18 +366,18 @@
|
|||
},
|
||||
"taskcluster": {
|
||||
"hashes": [
|
||||
"sha256:1c2b36928170ddb73ada7c5548b8ae8c9604d188d9feef79cdcb67eedd9829cc",
|
||||
"sha256:2574a01171704e71ab9e5b540ca176e6da44b033ba3a396856c24d11ab1e9bfc",
|
||||
"sha256:5866b8e89905fd75e9467291ee1acfbc81c61b5eda6a45aea5ac63602291ad70"
|
||||
"sha256:27256511044346ac71a495d3c636f2add95c102b9b09f90d6fb1ea3e9949d311",
|
||||
"sha256:99dd90bc1c566968868c8b07ede32f8e031cbccd52c7195a61e802679d461447",
|
||||
"sha256:d0360063c1a3fcaaa514bb31c03954ba573d2b671df40a2ecfdfd9339cc8e93e"
|
||||
],
|
||||
"version": "==4.0.0"
|
||||
"version": "==4.0.1"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
|
||||
"sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
|
||||
],
|
||||
"markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version < '4' and python_version >= '2.6'",
|
||||
"markers": "python_version != '3.1.*' and python_version != '3.0.*' and python_version < '4' and python_version != '3.2.*' and python_version != '3.3.*' and python_version >= '2.6'",
|
||||
"version": "==1.23"
|
||||
},
|
||||
"virtualenv": {
|
||||
|
@ -385,7 +385,7 @@
|
|||
"sha256:2ce32cd126117ce2c539f0134eb89de91a8413a29baac49cbab3eb50e2026669",
|
||||
"sha256:ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752"
|
||||
],
|
||||
"markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.0.*'",
|
||||
"markers": "python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*' and python_version >= '2.7'",
|
||||
"version": "==16.0.0"
|
||||
},
|
||||
"yarl": {
|
||||
|
@ -400,6 +400,7 @@
|
|||
"sha256:f17495e6fe3d377e3faac68121caef6f974fcb9e046bc075bcff40d8e5cc69a4",
|
||||
"sha256:f85900b9cca0c67767bb61b2b9bd53208aaa7373dae633dbe25d179b4bf38aa7"
|
||||
],
|
||||
"markers": "python_version >= '3.4.1'",
|
||||
"version": "==1.2.6"
|
||||
}
|
||||
},
|
||||
|
|
|
@ -8,8 +8,7 @@ const Cm = Components.manager;
|
|||
|
||||
const CONTRACT_ID = "@mozilla.org/filepicker;1";
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Allow stuff from this scope to be accessed from non-privileged scopes. This
|
||||
|
|
|
@ -12,23 +12,15 @@
|
|||
|
||||
var global = this;
|
||||
|
||||
ChromeUtils.import("resource://specialpowers/MockFilePicker.jsm");
|
||||
ChromeUtils.import("resource://specialpowers/MockColorPicker.jsm");
|
||||
ChromeUtils.import("resource://specialpowers/MockPermissionPrompt.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "MockFilePicker",
|
||||
"resource://specialpowers/MockFilePicker.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "MockColorPicker",
|
||||
"resource://specialpowers/MockColorPicker.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "MockPermissionPrompt",
|
||||
"resource://specialpowers/MockPermissionPrompt.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "ServiceWorkerCleanUp",
|
||||
"resource://gre/modules/ServiceWorkerCleanUp.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/ServiceWorkerCleanUp.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "PerTestCoverageUtils",
|
||||
"resource://testing-common/PerTestCoverageUtils.jsm");
|
||||
|
|
|
@ -1784,6 +1784,9 @@ class Extension extends ExtensionData {
|
|||
// If the extension has to migrate backend, ensure that the data migration
|
||||
// starts once Firefox is idle after the extension has been started.
|
||||
this.once("ready", () => ChromeUtils.idleDispatch(() => {
|
||||
if (this.hasShutdown) {
|
||||
return;
|
||||
}
|
||||
ExtensionStorageIDB.selectBackend({extension: this});
|
||||
}));
|
||||
}
|
||||
|
@ -1846,6 +1849,17 @@ class Extension extends ExtensionData {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.hasPermission("storage") && ExtensionStorageIDB.selectedBackendPromises.has(this)) {
|
||||
// Wait the data migration to complete.
|
||||
try {
|
||||
await ExtensionStorageIDB.selectedBackendPromises.get(this);
|
||||
} catch (err) {
|
||||
Cu.reportError(
|
||||
`Error while waiting for extension data migration on shutdown: ${this.policy.debugName} - ` +
|
||||
`${err.message}::${err.stack}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.rootURI instanceof Ci.nsIJARURI) {
|
||||
let file = this.rootURI.JARFile.QueryInterface(Ci.nsIFileURL).file;
|
||||
Services.ppmm.broadcastAsyncMessage("Extension:FlushJarCache", {path: file.path});
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const Cm = Components.manager;
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
|
@ -20,6 +21,15 @@ var EXPORTED_SYMBOLS = ["AboutPages"];
|
|||
|
||||
const SHIELD_LEARN_MORE_URL_PREF = "app.normandy.shieldLearnMoreUrl";
|
||||
|
||||
// Due to bug 1051238 frame scripts are cached forever, so we can't update them
|
||||
// as a restartless add-on. The Math.random() is the work around for this.
|
||||
const PROCESS_SCRIPT = (
|
||||
`resource://normandy-content/shield-content-process.js?${Math.random()}`
|
||||
);
|
||||
const FRAME_SCRIPT = (
|
||||
`resource://normandy-content/shield-content-frame.js?${Math.random()}`
|
||||
);
|
||||
|
||||
/**
|
||||
* Class for managing an about: page that Normandy provides. Adapted from
|
||||
* browser/extensions/pocket/content/AboutPocket.jsm.
|
||||
|
@ -28,10 +38,10 @@ const SHIELD_LEARN_MORE_URL_PREF = "app.normandy.shieldLearnMoreUrl";
|
|||
* @implements nsIAboutModule
|
||||
*/
|
||||
class AboutPage {
|
||||
constructor({chromeUrl, aboutHost, classID, description, uriFlags}) {
|
||||
constructor({chromeUrl, aboutHost, classId, description, uriFlags}) {
|
||||
this.chromeUrl = chromeUrl;
|
||||
this.aboutHost = aboutHost;
|
||||
this.classID = Components.ID(classID);
|
||||
this.classId = Components.ID(classId);
|
||||
this.description = description;
|
||||
this.uriFlags = uriFlags;
|
||||
}
|
||||
|
@ -51,6 +61,34 @@ class AboutPage {
|
|||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
createInstance(outer, iid) {
|
||||
if (outer !== null) {
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
return this.QueryInterface(iid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register this about: page with XPCOM. This must be called once in each
|
||||
* process (parent and content) to correctly initialize the page.
|
||||
*/
|
||||
register() {
|
||||
Cm.QueryInterface(Ci.nsIComponentRegistrar).registerFactory(
|
||||
this.classId,
|
||||
this.description,
|
||||
`@mozilla.org/network/protocol/about;1?what=${this.aboutHost}`,
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister this about: page with XPCOM. This must be called before the
|
||||
* add-on is cleaned up if the page has been registered.
|
||||
*/
|
||||
unregister() {
|
||||
Cm.QueryInterface(Ci.nsIComponentRegistrar).unregisterFactory(this.classId, this);
|
||||
}
|
||||
}
|
||||
AboutPage.prototype.QueryInterface = ChromeUtils.generateQI([Ci.nsIAboutModule]);
|
||||
|
||||
|
@ -60,17 +98,23 @@ AboutPage.prototype.QueryInterface = ChromeUtils.generateQI([Ci.nsIAboutModule])
|
|||
var AboutPages = {
|
||||
async init() {
|
||||
// Load scripts in content processes and tabs
|
||||
Services.ppmm.loadProcessScript(PROCESS_SCRIPT, true);
|
||||
Services.mm.loadFrameScript(FRAME_SCRIPT, true);
|
||||
|
||||
// Register about: pages and their listeners
|
||||
this.aboutStudies.register();
|
||||
this.aboutStudies.registerParentListeners();
|
||||
|
||||
CleanupManager.addCleanupHandler(() => {
|
||||
// Stop loading processs scripts and notify existing scripts to clean up.
|
||||
Services.ppmm.removeDelayedProcessScript(PROCESS_SCRIPT);
|
||||
Services.ppmm.broadcastAsyncMessage("Shield:ShuttingDown");
|
||||
Services.mm.removeDelayedFrameScript(FRAME_SCRIPT);
|
||||
Services.mm.broadcastAsyncMessage("Shield:ShuttingDown");
|
||||
|
||||
// Clean up about pages
|
||||
this.aboutStudies.unregisterParentListeners();
|
||||
this.aboutStudies.unregister();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
@ -84,7 +128,7 @@ XPCOMUtils.defineLazyGetter(this.AboutPages, "aboutStudies", () => {
|
|||
const aboutStudies = new AboutPage({
|
||||
chromeUrl: "resource://normandy-content/about-studies/about-studies.html",
|
||||
aboutHost: "studies",
|
||||
classID: "{6ab96943-a163-482c-9622-4faedc0e827f}",
|
||||
classId: "{6ab96943-a163-482c-9622-4faedc0e827f}",
|
||||
description: "Shield Study Listing",
|
||||
uriFlags: (
|
||||
Ci.nsIAboutModule.ALLOW_SCRIPT
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["ShieldFrameListener"];
|
||||
|
||||
/**
|
||||
* Listen for DOM events bubbling up from the about:studies page, and perform
|
||||
* privileged actions in response to them. If we need to do anything that the
|
||||
|
@ -15,8 +13,11 @@ var EXPORTED_SYMBOLS = ["ShieldFrameListener"];
|
|||
* is opened.
|
||||
*/
|
||||
|
||||
/* global content addMessageListener removeMessageListener sendAsyncMessage */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
const frameGlobal = {};
|
||||
ChromeUtils.defineModuleGetter(
|
||||
|
@ -37,10 +38,6 @@ XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
|
|||
* @implements EventListener
|
||||
*/
|
||||
class ShieldFrameListener {
|
||||
constructor(mm) {
|
||||
this.mm = mm;
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
// Abort if the current page isn't about:studies.
|
||||
if (!this.ensureTrustedOrigin()) {
|
||||
|
@ -49,23 +46,23 @@ class ShieldFrameListener {
|
|||
|
||||
// We waited until after we received an event to register message listeners
|
||||
// in order to save resources for tabs that don't ever load about:studies.
|
||||
this.mm.addMessageListener("Shield:ShuttingDown", this);
|
||||
this.mm.addMessageListener("Shield:ReceiveStudyList", this);
|
||||
this.mm.addMessageListener("Shield:ReceiveStudiesEnabled", this);
|
||||
addMessageListener("Shield:ShuttingDown", this);
|
||||
addMessageListener("Shield:ReceiveStudyList", this);
|
||||
addMessageListener("Shield:ReceiveStudiesEnabled", this);
|
||||
|
||||
switch (event.detail.action) {
|
||||
// Actions that require the parent process
|
||||
case "GetRemoteValue:StudyList":
|
||||
this.mm.sendAsyncMessage("Shield:GetStudyList");
|
||||
sendAsyncMessage("Shield:GetStudyList");
|
||||
break;
|
||||
case "RemoveStudy":
|
||||
this.mm.sendAsyncMessage("Shield:RemoveStudy", event.detail.data);
|
||||
sendAsyncMessage("Shield:RemoveStudy", event.detail.data);
|
||||
break;
|
||||
case "GetRemoteValue:StudiesEnabled":
|
||||
this.mm.sendAsyncMessage("Shield:GetStudiesEnabled");
|
||||
sendAsyncMessage("Shield:GetStudiesEnabled");
|
||||
break;
|
||||
case "NavigateToDataPreferences":
|
||||
this.mm.sendAsyncMessage("Shield:OpenDataPreferences");
|
||||
sendAsyncMessage("Shield:OpenDataPreferences");
|
||||
break;
|
||||
// Actions that can be performed in the content process
|
||||
case "GetRemoteValue:ShieldLearnMoreHref":
|
||||
|
@ -97,7 +94,7 @@ class ShieldFrameListener {
|
|||
* @return {Boolean}
|
||||
*/
|
||||
ensureTrustedOrigin() {
|
||||
return this.mm.content.document.documentURI.startsWith("about:studies");
|
||||
return content.document.documentURI.startsWith("about:studies");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,8 +127,6 @@ class ShieldFrameListener {
|
|||
return;
|
||||
}
|
||||
|
||||
let {content} = this.mm;
|
||||
|
||||
// Clone details and use the event class from the unprivileged context.
|
||||
const event = new content.document.defaultView.CustomEvent(type, {
|
||||
bubbles: true,
|
||||
|
@ -141,8 +136,10 @@ class ShieldFrameListener {
|
|||
}
|
||||
|
||||
onShutdown() {
|
||||
this.mm.removeMessageListener("Shield:SendStudyList", this);
|
||||
this.mm.removeMessageListener("Shield:ShuttingDown", this);
|
||||
this.mm.removeEventListener("Shield", this);
|
||||
removeMessageListener("Shield:SendStudyList", this);
|
||||
removeMessageListener("Shield:ShuttingDown", this);
|
||||
removeEventListener("Shield", this);
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener("ShieldPageEvent", new ShieldFrameListener(), false, true);
|
|
@ -0,0 +1,47 @@
|
|||
/* 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";
|
||||
|
||||
/**
|
||||
* Registers about: pages provided by Shield, and listens for a shutdown event
|
||||
* from the add-on before un-registering them.
|
||||
*
|
||||
* This file is loaded as a process script. It is executed once for each
|
||||
* process, including the parent one.
|
||||
*/
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://normandy-content/AboutPages.jsm");
|
||||
|
||||
class ShieldChildListener {
|
||||
onStartup() {
|
||||
Services.cpmm.addMessageListener("Shield:ShuttingDown", this, true);
|
||||
AboutPages.aboutStudies.register();
|
||||
}
|
||||
|
||||
onShutdown() {
|
||||
AboutPages.aboutStudies.unregister();
|
||||
Services.cpmm.removeMessageListener("Shield:ShuttingDown", this);
|
||||
|
||||
// Unload AboutPages.jsm in case the add-on is reinstalled and we need to
|
||||
// load a new version of it.
|
||||
Cu.unload("resource://normandy-content/AboutPages.jsm");
|
||||
}
|
||||
|
||||
receiveMessage(message) {
|
||||
switch (message.name) {
|
||||
case "Shield:ShuttingDown":
|
||||
this.onShutdown();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only register in content processes; the parent process handles registration
|
||||
// separately.
|
||||
if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
const listener = new ShieldChildListener();
|
||||
listener.onStartup();
|
||||
}
|
|
@ -9,11 +9,6 @@ with Files('**'):
|
|||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'shield-content-process.js',
|
||||
'shield.manifest',
|
||||
]
|
||||
|
||||
SPHINX_TREES['normandy'] = 'docs'
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
|
||||
|
|
|
@ -1,26 +0,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/. */
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Registers about: pages provided by Shield, and listens for a shutdown event
|
||||
* from the add-on before un-registering them.
|
||||
*
|
||||
* This file is loaded as a process script. It is executed once for each
|
||||
* process, including the parent one.
|
||||
*/
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://normandy-content/AboutPages.jsm");
|
||||
|
||||
// generateNSGetFactory only knows how to register factory classes, with
|
||||
// classID properties on their prototype, and a constructor that returns
|
||||
// an instance. It can't handle singletons directly. So wrap the
|
||||
// aboutStudies singleton in a trivial constructor function.
|
||||
function AboutStudies() {
|
||||
return AboutStudies.prototype;
|
||||
}
|
||||
AboutStudies.prototype = AboutPages.aboutStudies;
|
||||
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([AboutStudies]);
|
|
@ -1,3 +0,0 @@
|
|||
|
||||
component {6ab96943-a163-482c-9622-4faedc0e827f} shield-content-process.js
|
||||
contract @mozilla.org/network/protocol/about;1?what=studies {6ab96943-a163-482c-9622-4faedc0e827f}
|
|
@ -2352,8 +2352,6 @@ Engine.prototype = {
|
|||
let responseType = AppConstants.platform == "android" ? this._defaultMobileResponseType :
|
||||
URLTYPE_SEARCH_HTML;
|
||||
|
||||
LOG("getURLParsingInfo: responseType: \"" + responseType + "\"");
|
||||
|
||||
let url = this._getURLOfType(responseType);
|
||||
if (!url || url.method != "GET") {
|
||||
return null;
|
||||
|
@ -4218,7 +4216,6 @@ SearchService.prototype = {
|
|||
_parseSubmissionMap: null,
|
||||
|
||||
_buildParseSubmissionMap: function SRCH_SVC__buildParseSubmissionMap() {
|
||||
LOG("_buildParseSubmissionMap");
|
||||
this._parseSubmissionMap = new Map();
|
||||
|
||||
// Used only while building the map, indicates which entries do not refer to
|
||||
|
@ -4227,16 +4224,12 @@ SearchService.prototype = {
|
|||
let keysOfAlternates = new Set();
|
||||
|
||||
for (let engine of this._sortedEngines) {
|
||||
LOG("Processing engine: " + engine.name);
|
||||
|
||||
if (engine.hidden) {
|
||||
LOG("Engine is hidden.");
|
||||
continue;
|
||||
}
|
||||
|
||||
let urlParsingInfo = engine.getURLParsingInfo();
|
||||
if (!urlParsingInfo) {
|
||||
LOG("Engine does not support URL parsing.");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -4253,17 +4246,12 @@ SearchService.prototype = {
|
|||
// domains, even if they are found later in the ordered engine list.
|
||||
let existingEntry = this._parseSubmissionMap.get(key);
|
||||
if (!existingEntry) {
|
||||
LOG("Adding new entry: " + key);
|
||||
if (isAlternate) {
|
||||
keysOfAlternates.add(key);
|
||||
}
|
||||
} else if (!isAlternate && keysOfAlternates.has(key)) {
|
||||
LOG("Overriding alternate entry: " + key +
|
||||
" (" + existingEntry.engine.name + ")");
|
||||
keysOfAlternates.delete(key);
|
||||
} else {
|
||||
LOG("Keeping existing entry: " + key +
|
||||
" (" + existingEntry.engine.name + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4331,8 +4319,12 @@ SearchService.prototype = {
|
|||
},
|
||||
|
||||
parseSubmissionURL: function SRCH_SVC_parseSubmissionURL(aURL) {
|
||||
this._ensureInitialized();
|
||||
LOG("parseSubmissionURL: Parsing \"" + aURL + "\".");
|
||||
if (!gInitialized) {
|
||||
// If search is not initialized, do nothing.
|
||||
// This allows us to use this function early in telemetry.
|
||||
// The only other consumer of this (places) uses it much later.
|
||||
return gEmptyParseSubmissionResult;
|
||||
}
|
||||
|
||||
if (!this._parseSubmissionMap) {
|
||||
this._buildParseSubmissionMap();
|
||||
|
@ -4345,7 +4337,6 @@ SearchService.prototype = {
|
|||
|
||||
// Exclude any URL that is not HTTP or HTTPS from the beginning.
|
||||
if (soughtUrl.scheme != "http" && soughtUrl.scheme != "https") {
|
||||
LOG("The URL scheme is not HTTP or HTTPS.");
|
||||
return gEmptyParseSubmissionResult;
|
||||
}
|
||||
|
||||
|
@ -4354,14 +4345,12 @@ SearchService.prototype = {
|
|||
soughtQuery = soughtUrl.query;
|
||||
} catch (ex) {
|
||||
// Errors while parsing the URL or accessing the properties are not fatal.
|
||||
LOG("The value does not look like a structured URL.");
|
||||
return gEmptyParseSubmissionResult;
|
||||
}
|
||||
|
||||
// Look up the domain and path in the map to identify the search engine.
|
||||
let mapEntry = this._parseSubmissionMap.get(soughtKey);
|
||||
if (!mapEntry) {
|
||||
LOG("No engine associated with domain and path: " + soughtKey);
|
||||
return gEmptyParseSubmissionResult;
|
||||
}
|
||||
|
||||
|
@ -4378,7 +4367,6 @@ SearchService.prototype = {
|
|||
}
|
||||
}
|
||||
if (encodedTerms === null) {
|
||||
LOG("Missing terms parameter: " + mapEntry.termsParameterName);
|
||||
return gEmptyParseSubmissionResult;
|
||||
}
|
||||
|
||||
|
@ -4407,12 +4395,9 @@ SearchService.prototype = {
|
|||
encodedTerms.replace(/\+/g, " "));
|
||||
} catch (ex) {
|
||||
// Decoding errors will cause this match to be ignored.
|
||||
LOG("Parameter decoding failed. Charset: " +
|
||||
mapEntry.engine.queryCharset);
|
||||
return gEmptyParseSubmissionResult;
|
||||
}
|
||||
|
||||
LOG("Match found. Terms: " + terms);
|
||||
return new ParseSubmissionResult(mapEntry.engine, terms, offset, length);
|
||||
},
|
||||
|
||||
|
|
|
@ -7795,7 +7795,7 @@
|
|||
"kind": "count",
|
||||
"keyed": true,
|
||||
"releaseChannelCollection": "opt-out",
|
||||
"description": "Record the search counts for search engines"
|
||||
"description": "Records search counts for search access points and in content searches. For search access points, the format is: <engine-name>.<search-access-point> For in content searches, the format is <provider>.in-content:[sap|sap-follow-on|organic]:[code|none]"
|
||||
},
|
||||
"SEARCH_RESET_RESULT": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
classifiedAnnotatedPBFrame.html
|
||||
classifierCommon.js
|
||||
classifierFrame.html
|
||||
classifierHelper.js
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var mainWindow = window.docShell.rootTreeItem.domWindow;
|
||||
var contentPage = "http://www.itisatrap.org/tests/toolkit/components/url-classifier/tests/mochitest/classifiedAnnotatedPBFrame.html";
|
||||
var contentPage = "http://www.itisatrap.org/chrome/toolkit/components/url-classifier/tests/mochitest/classifiedAnnotatedPBFrame.html";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm");
|
||||
|
|
|
@ -4,18 +4,392 @@
|
|||
|
||||
/* 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");
|
||||
|
||||
this.WebProgress = new WebProgressChild(this);
|
||||
this.WebNavigation = new WebNavigationChild(this);
|
||||
ChromeUtils.defineModuleGetter(this, "Utils",
|
||||
"resource://gre/modules/sessionstore/Utils.jsm");
|
||||
|
||||
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() {
|
||||
|
|
|
@ -37,18 +37,6 @@ XPCOMUtils.defineLazyProxy(this, "PopupBlocking", () => {
|
|||
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);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyProxy(this, "SelectionSourceContent",
|
||||
"resource://gre/modules/SelectionSourceContent.jsm");
|
||||
|
||||
|
@ -61,12 +49,6 @@ XPCOMUtils.defineLazyProxy(this, "DateTimePickerContent", () => {
|
|||
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() {
|
||||
|
@ -135,6 +117,13 @@ addMessageListener("SwitchDocumentDirection", () => {
|
|||
});
|
||||
|
||||
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
|
||||
|
@ -142,59 +131,159 @@ var FindBar = {
|
|||
* there. To do this, we need shortcut data from the parent.
|
||||
*/
|
||||
_findKey: null,
|
||||
_findModifiers: null,
|
||||
|
||||
init() {
|
||||
Services.els.addSystemEventListener(global, "keypress",
|
||||
this.onKeypress.bind(this), false);
|
||||
addMessageListener("Findbar:UpdateState", this);
|
||||
Services.els.addSystemEventListener(global, "keypress", this, false);
|
||||
Services.els.addSystemEventListener(global, "mouseup", this, false);
|
||||
this._initShortcutData();
|
||||
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) {
|
||||
if (!this._findKey) {
|
||||
this._findKey = Services.cpmm.sharedData.get("Findbar:Shortcut");
|
||||
if (!this._findKey) {
|
||||
return false;
|
||||
}
|
||||
_eventMatchesFindShortcut(aEvent) {
|
||||
let modifiers = this._findModifiers;
|
||||
if (!modifiers) {
|
||||
return false;
|
||||
}
|
||||
for (let k in this._findKey) {
|
||||
if (this._findKey[k] != aEvent[k]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return aEvent.ctrlKey == modifiers.ctrlKey && aEvent.altKey == modifiers.altKey &&
|
||||
aEvent.shiftKey == modifiers.shiftKey && aEvent.metaKey == modifiers.metaKey &&
|
||||
aEvent.key == this._findKey;
|
||||
},
|
||||
|
||||
onKeypress(event) {
|
||||
if (!FindBarChild.inPassThrough &&
|
||||
this.eventMatchesFindShortcut(event)) {
|
||||
return FindBarChild.start(event);
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
if (event.ctrlKey || event.altKey || event.metaKey || event.defaultPrevented ||
|
||||
!BrowserUtils.canFastFind(content)) {
|
||||
return null;
|
||||
// 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;
|
||||
}
|
||||
if (!fastFind.should) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (FindBarChild.inPassThrough || FindBarChild.inQuickFind) {
|
||||
return FindBarChild.onKeypress(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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
_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();
|
||||
|
@ -445,7 +534,3 @@ let ExtFind = {
|
|||
};
|
||||
|
||||
ExtFind.init();
|
||||
|
||||
addEventListener("ShieldPageEvent", ShieldFrameListener, false, true);
|
||||
|
||||
addEventListener("mozUITour", UITourListener, false, true);
|
||||
|
|
|
@ -220,7 +220,7 @@
|
|||
</content>
|
||||
|
||||
<implementation>
|
||||
<!-- Please keep in sync with toolkit/modules/FindBarChild.jsm -->
|
||||
<!-- Please keep in sync with toolkit/content/browser-content.js -->
|
||||
<field name="FIND_NORMAL">0</field>
|
||||
<field name="FIND_TYPEAHEAD">1</field>
|
||||
<field name="FIND_LINKS">2</field>
|
||||
|
|
|
@ -290,10 +290,12 @@ var BrowserUtils = {
|
|||
*
|
||||
* @param elt
|
||||
* The element that is focused
|
||||
* @param win
|
||||
* The window that is focused
|
||||
*
|
||||
*/
|
||||
shouldFastFind(elt) {
|
||||
shouldFastFind(elt, win) {
|
||||
if (elt) {
|
||||
let win = elt.ownerGlobal;
|
||||
if (elt instanceof win.HTMLInputElement && elt.mozIsTextField(false))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
// 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";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["FindBarChild"];
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "RemoteFinder",
|
||||
"resource://gre/modules/RemoteFinder.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.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;
|
||||
|
||||
class FindBarChild {
|
||||
constructor(mm) {
|
||||
this.mm = mm;
|
||||
|
||||
this.findMode = 0;
|
||||
this.inQuickFind = false;
|
||||
|
||||
this.mm.addMessageListener("Findbar:UpdateState", this);
|
||||
|
||||
Services.els.addSystemEventListener(this.mm, "mouseup", this, false);
|
||||
}
|
||||
|
||||
start(event) {
|
||||
this.inPassThrough = true;
|
||||
}
|
||||
|
||||
startQuickFind(event, autostart = false) {
|
||||
let mode = FIND_TYPEAHEAD;
|
||||
if (event.charCode == "'".charAt(0) ||
|
||||
autostart && RemoteFinder._typeAheadLinksOnly) {
|
||||
mode = FIND_LINKS;
|
||||
}
|
||||
|
||||
// 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.inQuickFind = msg.data.hasQuickFindTimeout;
|
||||
if (msg.data.isOpenAndFocused) {
|
||||
this.inPassThrough = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case "keypress":
|
||||
this.onKeypress(event);
|
||||
break;
|
||||
case "mouseup":
|
||||
this.onMouseup(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onKeypress(event) {
|
||||
if (this.inPassThrough) {
|
||||
this.passKeyToParent(event);
|
||||
} else if (this.findMode != FIND_NORMAL && this.inQuickFind && event.charCode) {
|
||||
this.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];
|
||||
}
|
||||
this.mm.sendAsyncMessage("Findbar:Keypress", fakeEvent);
|
||||
}
|
||||
|
||||
onMouseup(event) {
|
||||
if (this.findMode != FIND_NORMAL)
|
||||
this.mm.sendAsyncMessage("Findbar:Mouseup");
|
||||
}
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
/* -*- 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);
|
||||
}
|
||||
}
|
|
@ -1,237 +0,0 @@
|
|||
/* -*- 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/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"]);
|
|
@ -200,7 +200,6 @@ EXTRA_JS_MODULES += [
|
|||
'E10SUtils.jsm',
|
||||
'EventEmitter.jsm',
|
||||
'FileUtils.jsm',
|
||||
'FindBarChild.jsm',
|
||||
'Finder.jsm',
|
||||
'FinderHighlighter.jsm',
|
||||
'FinderIterator.jsm',
|
||||
|
@ -254,8 +253,6 @@ EXTRA_JS_MODULES += [
|
|||
'UpdateUtils.jsm',
|
||||
'WebChannel.jsm',
|
||||
'WebChannelContent.jsm',
|
||||
'WebNavigationChild.jsm',
|
||||
'WebProgressChild.jsm',
|
||||
'WindowDraggingUtils.jsm',
|
||||
'ZipUtils.jsm',
|
||||
]
|
||||
|
|
|
@ -46,8 +46,16 @@ struct ManifestDirective
|
|||
const char* directive;
|
||||
int argc;
|
||||
|
||||
// Binary components are only allowed for APP locations.
|
||||
bool apponly;
|
||||
|
||||
// Some directives should only be delivered for APP or EXTENSION locations.
|
||||
bool componentonly;
|
||||
|
||||
bool ischrome;
|
||||
|
||||
bool allowbootstrap;
|
||||
|
||||
// The contentaccessible flags only apply to content/resource directives.
|
||||
bool contentflags;
|
||||
|
||||
|
@ -59,44 +67,50 @@ struct ManifestDirective
|
|||
void (nsChromeRegistry::*regfunc)(
|
||||
nsChromeRegistry::ManifestProcessingContext& aCx,
|
||||
int aLineNo, char* const* aArgv, int aFlags);
|
||||
|
||||
bool isContract;
|
||||
};
|
||||
static const ManifestDirective kParsingTable[] = {
|
||||
{
|
||||
"manifest", 1, true, false,
|
||||
"manifest", 1, false, false, true, true, false,
|
||||
&nsComponentManagerImpl::ManifestManifest, nullptr,
|
||||
},
|
||||
{
|
||||
"component", 2, false, false,
|
||||
"binary-component", 1, true, true, false, false, false,
|
||||
&nsComponentManagerImpl::ManifestBinaryComponent, nullptr,
|
||||
},
|
||||
{
|
||||
"component", 2, false, true, false, false, false,
|
||||
&nsComponentManagerImpl::ManifestComponent, nullptr,
|
||||
},
|
||||
{
|
||||
"contract", 2, false, false,
|
||||
"contract", 2, false, true, false, false, false,
|
||||
&nsComponentManagerImpl::ManifestContract, nullptr,
|
||||
},
|
||||
{
|
||||
"category", 3, false, false,
|
||||
"category", 3, false, true, false, false, false,
|
||||
&nsComponentManagerImpl::ManifestCategory, nullptr,
|
||||
},
|
||||
{
|
||||
"content", 2, true, true,
|
||||
"content", 2, false, true, true, true, true,
|
||||
nullptr, &nsChromeRegistry::ManifestContent,
|
||||
},
|
||||
{
|
||||
"locale", 3, true, false,
|
||||
"locale", 3, false, true, true, true, false,
|
||||
nullptr, &nsChromeRegistry::ManifestLocale,
|
||||
},
|
||||
{
|
||||
"skin", 3, true, false,
|
||||
"skin", 3, false, false, true, true, false,
|
||||
nullptr, &nsChromeRegistry::ManifestSkin,
|
||||
},
|
||||
{
|
||||
// NB: note that while skin manifests can use this, they are only allowed
|
||||
// to use it for chrome://../skin/ URLs
|
||||
"override", 2, true, false,
|
||||
"override", 2, false, false, true, true, false,
|
||||
nullptr, &nsChromeRegistry::ManifestOverride,
|
||||
},
|
||||
{
|
||||
"resource", 2, false, true,
|
||||
"resource", 2, false, true, true, false, true,
|
||||
nullptr, &nsChromeRegistry::ManifestResource,
|
||||
}
|
||||
};
|
||||
|
@ -571,13 +585,28 @@ ParseManifest(NSLocationType aType, FileLocation& aFile, char* aBuf,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!directive->ischrome && NS_BOOTSTRAPPED_LOCATION == aType) {
|
||||
if (!directive->allowbootstrap && NS_BOOTSTRAPPED_LOCATION == aType) {
|
||||
LogMessageWithContext(aFile, line,
|
||||
"Bootstrapped manifest not allowed to use '%s' directive.",
|
||||
token);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifndef MOZ_BINARY_EXTENSIONS
|
||||
if (directive->apponly && NS_APP_LOCATION != aType) {
|
||||
LogMessageWithContext(aFile, line,
|
||||
"Only application manifests may use the '%s' directive.", token);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (directive->componentonly && NS_SKIN_LOCATION == aType) {
|
||||
LogMessageWithContext(aFile, line,
|
||||
"Skin manifest not allowed to use '%s' directive.",
|
||||
token);
|
||||
continue;
|
||||
}
|
||||
|
||||
NS_ASSERTION(directive->argc < 4, "Need to reset argv array length");
|
||||
char* argv[4];
|
||||
for (int i = 0; i < directive->argc; ++i) {
|
||||
|
@ -692,8 +721,15 @@ ParseManifest(NSLocationType aType, FileLocation& aFile, char* aBuf,
|
|||
(nsChromeRegistry::gChromeRegistry->*(directive->regfunc))(
|
||||
chromecx, line, argv, flags);
|
||||
} else if (directive->ischrome || !aChromeOnly) {
|
||||
(nsComponentManagerImpl::gComponentManager->*(directive->mgrfunc))(
|
||||
mgrcx, line, argv);
|
||||
if (directive->isContract) {
|
||||
CachedDirective* cd = contracts.AppendElement();
|
||||
cd->lineno = line;
|
||||
cd->argv[0] = argv[0];
|
||||
cd->argv[1] = argv[1];
|
||||
} else {
|
||||
(nsComponentManagerImpl::gComponentManager->*(directive->mgrfunc))(
|
||||
mgrcx, line, argv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -665,6 +665,15 @@ nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& aCx,
|
|||
RegisterManifest(aCx.mType, f, aCx.mChromeOnly);
|
||||
}
|
||||
|
||||
void
|
||||
nsComponentManagerImpl::ManifestBinaryComponent(ManifestProcessingContext& aCx,
|
||||
int aLineNo,
|
||||
char* const* aArgv)
|
||||
{
|
||||
LogMessageWithContext(aCx.mFile, aLineNo,
|
||||
"Binary XPCOM components are no longer supported.");
|
||||
}
|
||||
|
||||
void
|
||||
nsComponentManagerImpl::ManifestComponent(ManifestProcessingContext& aCx,
|
||||
int aLineNo, char* const* aArgv)
|
||||
|
|
|
@ -287,6 +287,8 @@ public:
|
|||
|
||||
void ManifestManifest(ManifestProcessingContext& aCx, int aLineNo,
|
||||
char* const* aArgv);
|
||||
void ManifestBinaryComponent(ManifestProcessingContext& aCx, int aLineNo,
|
||||
char* const* aArgv);
|
||||
void ManifestComponent(ManifestProcessingContext& aCx, int aLineNo,
|
||||
char* const* aArgv);
|
||||
void ManifestContract(ManifestProcessingContext& aCx, int aLineNo,
|
||||
|
|
Загрузка…
Ссылка в новой задаче