mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 05:15:45 +00:00
Merge mozilla-central to inbound. a=merge CLOSED TREE
--HG-- rename : browser/components/payments/test/browser/browser_payments_onboarding_wizard.js => browser/components/payments/test/browser/browser_onboarding_wizard.js
This commit is contained in:
commit
516255f90e
@ -1519,15 +1519,11 @@ pref("browser.contentblocking.global-toggle.enabled", true);
|
||||
pref("browser.contentblocking.global-toggle.enabled", false);
|
||||
#endif
|
||||
|
||||
// Define a set of default features for the Content Blocking UI
|
||||
#ifdef EARLY_BETA_OR_EARLIER
|
||||
pref("browser.contentblocking.fastblock.ui.enabled", true);
|
||||
pref("browser.contentblocking.fastblock.control-center.ui.enabled", true);
|
||||
#else
|
||||
// Disable the UI for FastBlock in product.
|
||||
pref("browser.contentblocking.fastblock.ui.enabled", false);
|
||||
pref("browser.contentblocking.fastblock.control-center.ui.enabled", false);
|
||||
#endif
|
||||
|
||||
// Define a set of default features for the Content Blocking UI.
|
||||
pref("browser.contentblocking.trackingprotection.ui.enabled", true);
|
||||
pref("browser.contentblocking.trackingprotection.control-center.ui.enabled", true);
|
||||
pref("browser.contentblocking.rejecttrackers.ui.enabled", true);
|
||||
@ -1779,8 +1775,3 @@ pref("prio.publicKeyB", "26E6674E65425B823F1F1D5F96E3BB3EF9E406EC7FBA7DEF8B08A35
|
||||
#if defined(NIGHTLY_BUILD) && defined(MOZ_LIBPRIO)
|
||||
pref("prio.enabled", true);
|
||||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("browser.fastblock.enabled", true);
|
||||
#endif
|
||||
|
||||
|
@ -39,9 +39,10 @@ add_task(async function setup() {
|
||||
let scalars = Services.telemetry.snapshotScalars(
|
||||
Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT, false).parent;
|
||||
|
||||
is(scalars["contentblocking.enabled"], true, "CB was enabled at startup");
|
||||
is(scalars["contentblocking.fastblock_enabled"], AppConstants.NIGHTLY_BUILD,
|
||||
"FB is enabled in Nightly");
|
||||
is(scalars["contentblocking.enabled"], Services.prefs.getBoolPref("browser.contentblocking.enabled"),
|
||||
"CB enabled status was recorded at startup");
|
||||
is(scalars["contentblocking.fastblock_enabled"], Services.prefs.getBoolPref("browser.fastblock.enabled"),
|
||||
"FB enabled status was recorded at startup");
|
||||
is(scalars["contentblocking.exceptions"], 0, "no CB exceptions at startup");
|
||||
});
|
||||
|
||||
|
@ -34,13 +34,8 @@ var Pocket = {
|
||||
Pocket._initPanelView(window);
|
||||
},
|
||||
|
||||
onPanelViewShowing(event) {
|
||||
Pocket._initPanelView(event.target.ownerGlobal);
|
||||
},
|
||||
|
||||
_initPanelView(window) {
|
||||
let document = window.document;
|
||||
let iframe = window.pktUI.getPanelFrame();
|
||||
|
||||
let libraryButton = document.getElementById("library-button");
|
||||
if (libraryButton) {
|
||||
@ -59,36 +54,9 @@ var Pocket = {
|
||||
} else {
|
||||
window.pktUI.tryToSaveCurrentPage();
|
||||
}
|
||||
|
||||
// pocketPanelDidHide in main.js set iframe to about:blank when it was
|
||||
// hidden, make sure we're loading the save panel.
|
||||
if (iframe.contentDocument &&
|
||||
iframe.contentDocument.readyState == "complete" &&
|
||||
iframe.contentDocument.documentURI != "about:blank") {
|
||||
window.pktUI.pocketPanelDidShow();
|
||||
} else {
|
||||
// iframe didn't load yet. This seems to always be the case when in
|
||||
// the toolbar panel, but never the case for a subview.
|
||||
// XXX this only being fired when it's a _capturing_ listener!
|
||||
iframe.addEventListener("load", Pocket.onFrameLoaded, true);
|
||||
}
|
||||
}, 0);
|
||||
},
|
||||
|
||||
onFrameLoaded(event) {
|
||||
let document = event.currentTarget.ownerDocument;
|
||||
let window = document.defaultView;
|
||||
let iframe = window.pktUI.getPanelFrame();
|
||||
|
||||
iframe.removeEventListener("load", Pocket.onFrameLoaded, true);
|
||||
window.pktUI.pocketPanelDidShow();
|
||||
},
|
||||
|
||||
onPanelViewHiding(event) {
|
||||
let window = event.target.ownerGlobal;
|
||||
window.pktUI.pocketPanelDidHide(event);
|
||||
},
|
||||
|
||||
_urlToSave: null,
|
||||
_titleToSave: null,
|
||||
savePage(browser, url, title) {
|
||||
|
@ -55,8 +55,6 @@ ChromeUtils.defineModuleGetter(this, "pktApi",
|
||||
var pktUI = (function() {
|
||||
|
||||
// -- Initialization (on startup and new windows) -- //
|
||||
var _currentPanelDidShow;
|
||||
var _currentPanelDidHide;
|
||||
|
||||
// Init panel id at 0. The first actual panel id will have the number 1 so
|
||||
// in case at some point any panel has the id 0 we know there is something
|
||||
@ -68,56 +66,6 @@ var pktUI = (function() {
|
||||
var savePanelWidth = 350;
|
||||
var savePanelHeights = {collapsed: 153, expanded: 272};
|
||||
|
||||
var _lastAddSucceeded = false;
|
||||
|
||||
// -- Event Handling -- //
|
||||
|
||||
/**
|
||||
* Event handler when Pocket toolbar button is pressed
|
||||
*/
|
||||
|
||||
function pocketPanelDidShow(event) {
|
||||
if (_currentPanelDidShow) {
|
||||
_currentPanelDidShow(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function pocketPanelDidHide(event) {
|
||||
if (_currentPanelDidHide) {
|
||||
_currentPanelDidHide(event);
|
||||
}
|
||||
|
||||
// clear the panel
|
||||
getPanelFrame().setAttribute("src", "about:blank");
|
||||
|
||||
if (_lastAddSucceeded) {
|
||||
var libraryButton = document.getElementById("library-button");
|
||||
if (!Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled") ||
|
||||
!libraryButton ||
|
||||
libraryButton.getAttribute("cui-areatype") == "menu-panel" ||
|
||||
libraryButton.getAttribute("overflowedItem") == "true" ||
|
||||
!libraryButton.closest("#nav-bar")) {
|
||||
return;
|
||||
}
|
||||
libraryButton.removeAttribute("fade");
|
||||
libraryButton.setAttribute("animate", "pocket");
|
||||
libraryButton.addEventListener("animationend", onLibraryButtonAnimationEnd);
|
||||
}
|
||||
}
|
||||
|
||||
function onLibraryButtonAnimationEnd(event) {
|
||||
let doc = event.target.ownerDocument;
|
||||
let libraryButton = doc.getElementById("library-button");
|
||||
if (event.animationName.startsWith("library-pocket-animation")) {
|
||||
libraryButton.setAttribute("fade", "true");
|
||||
} else if (event.animationName == "library-pocket-fade") {
|
||||
libraryButton.removeEventListener("animationend", onLibraryButtonAnimationEnd);
|
||||
libraryButton.removeAttribute("animate");
|
||||
libraryButton.removeAttribute("fade");
|
||||
}
|
||||
}
|
||||
|
||||
// -- Communication to API -- //
|
||||
|
||||
/**
|
||||
@ -128,7 +76,6 @@ var pktUI = (function() {
|
||||
}
|
||||
|
||||
function tryToSaveUrl(url, title) {
|
||||
|
||||
// If the user is logged in, go ahead and save the current page
|
||||
if (pktApi.isUserLoggedIn()) {
|
||||
saveAndShowConfirmation(url, title);
|
||||
@ -195,9 +142,6 @@ var pktUI = (function() {
|
||||
+ inOverflowMenu
|
||||
+ "&locale="
|
||||
+ getUILocale(), {
|
||||
onShow() {
|
||||
},
|
||||
onHide: panelDidHide,
|
||||
width: inOverflowMenu ? overflowMenuWidth : 300,
|
||||
height: startheight,
|
||||
});
|
||||
@ -231,7 +175,6 @@ var pktUI = (function() {
|
||||
+ "&locale=" + getUILocale(), {
|
||||
onShow() {
|
||||
var saveLinkMessageId = "saveLink";
|
||||
_lastAddSucceeded = false;
|
||||
getPanelFrame().setAttribute("itemAdded", "false");
|
||||
|
||||
// Send error message for invalid url
|
||||
@ -270,7 +213,6 @@ var pktUI = (function() {
|
||||
ho2,
|
||||
};
|
||||
pktUIMessaging.sendMessageToPanel(panelId, saveLinkMessageId, successResponse);
|
||||
_lastAddSucceeded = true;
|
||||
getPanelFrame().setAttribute("itemAdded", "true");
|
||||
},
|
||||
error(error, request) {
|
||||
@ -298,7 +240,6 @@ var pktUI = (function() {
|
||||
// Send the link
|
||||
pktApi.addLink(url, options);
|
||||
},
|
||||
onHide: panelDidHide,
|
||||
width: inOverflowMenu ? overflowMenuWidth : savePanelWidth,
|
||||
height: startheight,
|
||||
});
|
||||
@ -309,7 +250,6 @@ var pktUI = (function() {
|
||||
* Open a generic panel
|
||||
*/
|
||||
function showPanel(url, options) {
|
||||
|
||||
// Add new panel id
|
||||
_panelId += 1;
|
||||
url += ("&panelId=" + _panelId);
|
||||
@ -318,6 +258,7 @@ var pktUI = (function() {
|
||||
// as if the user tries to click again on the toolbar button the overlay
|
||||
// will close instead of the button will be clicked
|
||||
var iframe = getPanelFrame();
|
||||
options.onShow = options.onShow || (() => {});
|
||||
|
||||
// Register event handlers
|
||||
registerEventMessages();
|
||||
@ -325,15 +266,16 @@ var pktUI = (function() {
|
||||
// Load the iframe
|
||||
iframe.setAttribute("src", url);
|
||||
|
||||
// Uncomment to leave panel open -- for debugging
|
||||
// panel.setAttribute('noautohide', true);
|
||||
// panel.setAttribute('consumeoutsideclicks', false);
|
||||
//
|
||||
|
||||
// For some reason setting onpopupshown and onpopuphidden on the panel directly didn't work, so
|
||||
// do it this hacky way for now
|
||||
_currentPanelDidShow = options.onShow;
|
||||
_currentPanelDidHide = options.onHide;
|
||||
if (iframe.contentDocument &&
|
||||
iframe.contentDocument.readyState == "complete" &&
|
||||
iframe.contentDocument.documentURI != "about:blank") {
|
||||
options.onShow();
|
||||
} else {
|
||||
// iframe didn't load yet. This seems to always be the case when in
|
||||
// the toolbar panel, but never the case for a subview.
|
||||
// XXX this only being fired when it's a _capturing_ listener!
|
||||
iframe.addEventListener("load", options.onShow, { once: true, capture: true });
|
||||
}
|
||||
|
||||
resizePanel({
|
||||
width: options.width,
|
||||
@ -358,15 +300,6 @@ var pktUI = (function() {
|
||||
iframe.style.height = options.height + "px";
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the signup and saved panel was hidden
|
||||
*/
|
||||
function panelDidHide() {
|
||||
// clear the onShow and onHide values
|
||||
_currentPanelDidShow = null;
|
||||
_currentPanelDidHide = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all of the messages needed for the panels
|
||||
*/
|
||||
@ -517,7 +450,6 @@ var pktUI = (function() {
|
||||
success(data, response) {
|
||||
var successResponse = {status: "success"};
|
||||
pktUIMessaging.sendResponseMessageToPanel(panelId, _deleteItemMessageId, successResponse);
|
||||
_lastAddSucceeded = false;
|
||||
getPanelFrame().setAttribute("itemAdded", "false");
|
||||
},
|
||||
error(error, response) {
|
||||
@ -636,9 +568,6 @@ var pktUI = (function() {
|
||||
|
||||
openTabWithUrl,
|
||||
|
||||
pocketPanelDidShow,
|
||||
pocketPanelDidHide,
|
||||
|
||||
tryToSaveUrl,
|
||||
tryToSaveCurrentPage,
|
||||
};
|
||||
|
@ -44,6 +44,7 @@ let extensionControlledContentIds = {
|
||||
"privacy.containers": "browserContainersExtensionContent",
|
||||
"homepage_override": "browserHomePageExtensionContent",
|
||||
"newTabURL": "browserNewTabExtensionContent",
|
||||
"webNotificationsDisabled": "browserNotificationsPermissionExtensionContent",
|
||||
"defaultSearch": "browserDefaultSearchExtensionContent",
|
||||
"proxy.settings": "proxyExtensionContent",
|
||||
get "websites.trackingProtectionMode"() {
|
||||
@ -61,6 +62,7 @@ let extensionControlledContentIds = {
|
||||
const extensionControlledL10nKeys = {
|
||||
"homepage_override": "homepage-override",
|
||||
"newTabURL": "new-tab-url",
|
||||
"webNotificationsDisabled": "web-notifications",
|
||||
"defaultSearch": "default-search",
|
||||
"privacy.containers": "privacy-containers",
|
||||
"websites.trackingProtectionMode": contentBlockingUiEnabled ?
|
||||
|
@ -11,6 +11,8 @@ XPCOMUtils.defineLazyPreferenceGetter(this, "proxyType", PROXY_PREF);
|
||||
|
||||
const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
const CHROME_URL_ROOT = TEST_DIR + "/";
|
||||
const PERMISSIONS_URL = "chrome://browser/content/preferences/sitePermissions.xul";
|
||||
let sitePermissionsDialog;
|
||||
|
||||
function getSupportsFile(path) {
|
||||
let cr = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
@ -68,6 +70,19 @@ function waitForMessageContent(messageId, l10nId, doc) {
|
||||
{ childList: true });
|
||||
}
|
||||
|
||||
async function openNotificationsPermissionDialog() {
|
||||
let dialogOpened = promiseLoadSubDialog(PERMISSIONS_URL);
|
||||
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
|
||||
let doc = content.document;
|
||||
let settingsButton = doc.getElementById("notificationSettingsButton");
|
||||
settingsButton.click();
|
||||
});
|
||||
|
||||
sitePermissionsDialog = await dialogOpened;
|
||||
await sitePermissionsDialog.document.mozSubdialogReady;
|
||||
}
|
||||
|
||||
add_task(async function testExtensionControlledHomepage() {
|
||||
await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
|
||||
// eslint-disable-next-line mozilla/no-cpows-in-tests
|
||||
@ -339,6 +354,75 @@ add_task(async function testExtensionControlledNewTab() {
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
||||
add_task(async function testExtensionControlledWebNotificationsPermission() {
|
||||
let manifest = {
|
||||
manifest_version: 2,
|
||||
name: "TestExtension",
|
||||
version: "1.0",
|
||||
description: "Testing WebNotificationsDisable",
|
||||
applications: {gecko: {id: "@web_notifications_disable"}},
|
||||
permissions: [
|
||||
"browserSettings",
|
||||
],
|
||||
browser_action: {
|
||||
default_title: "Testing",
|
||||
},
|
||||
};
|
||||
|
||||
await openPreferencesViaOpenPreferencesAPI("privacy", {leaveOpen: true});
|
||||
await openNotificationsPermissionDialog();
|
||||
|
||||
let doc = sitePermissionsDialog.document;
|
||||
let extensionControlledContent = doc.getElementById("browserNotificationsPermissionExtensionContent");
|
||||
|
||||
// Test that extension content is initially hidden.
|
||||
ok(extensionControlledContent.hidden, "Extension content is initially hidden");
|
||||
|
||||
// Install an extension that will disable web notifications permission.
|
||||
let messageShown = waitForMessageShown("browserNotificationsPermissionExtensionContent", doc);
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest,
|
||||
useAddonManager: "permanent",
|
||||
background() {
|
||||
browser.browserSettings.webNotificationsDisabled.set({value: true});
|
||||
browser.test.sendMessage("load-extension");
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("load-extension");
|
||||
await messageShown;
|
||||
|
||||
let controlledDesc = extensionControlledContent.querySelector("description");
|
||||
Assert.deepEqual(doc.l10n.getAttributes(controlledDesc), {
|
||||
id: "extension-controlled-web-notifications",
|
||||
args: {
|
||||
name: "TestExtension",
|
||||
},
|
||||
}, "The user is notified that an extension is controlling the web notifications permission");
|
||||
is(extensionControlledContent.hidden, false, "The extension controlled row is not hidden");
|
||||
|
||||
// Disable the extension.
|
||||
doc.getElementById("disableNotificationsPermissionExtension").click();
|
||||
|
||||
// Verify the user is notified how to enable the extension.
|
||||
await waitForEnableMessage(extensionControlledContent.id, doc);
|
||||
is(doc.l10n.getAttributes(controlledDesc.querySelector("label")).id,
|
||||
"extension-controlled-enable",
|
||||
"The user is notified of how to enable the extension again");
|
||||
|
||||
// Verify the enable message can be dismissed.
|
||||
let hidden = waitForMessageHidden(extensionControlledContent.id, doc);
|
||||
let dismissButton = controlledDesc.querySelector("image:last-of-type");
|
||||
dismissButton.click();
|
||||
await hidden;
|
||||
|
||||
// Verify that the extension controlled content in hidden again.
|
||||
is(extensionControlledContent.hidden, true, "The extension controlled row is now hidden");
|
||||
|
||||
await extension.unload();
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
add_task(async function testExtensionControlledDefaultSearch() {
|
||||
await openPreferencesViaOpenPreferencesAPI("paneSearch", {leaveOpen: true});
|
||||
let doc = gBrowser.contentDocument;
|
||||
|
@ -23,8 +23,12 @@
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
|
||||
#browserNotificationsPermissionExtensionContent,
|
||||
#permissionsDisableDescription {
|
||||
margin-inline-start: 32px;
|
||||
}
|
||||
|
||||
#permissionsDisableDescription {
|
||||
color: #737373;
|
||||
line-height: 110%;
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
* 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/. */
|
||||
|
||||
/* import-globals-from in-content/extensionControlled.js */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
ChromeUtils.import("resource:///modules/SitePermissions.jsm");
|
||||
@ -42,6 +44,8 @@ function Permission(principal, type, capability, l10nId) {
|
||||
}
|
||||
|
||||
const PERMISSION_STATES = [SitePermissions.ALLOW, SitePermissions.BLOCK, SitePermissions.PROMPT];
|
||||
const NOTIFICATIONS_PERMISSION_OVERRIDE_KEY = "webNotificationsDisabled";
|
||||
const NOTIFICATIONS_PERMISSION_PREF = "permissions.default.desktop-notification";
|
||||
|
||||
var gSitePermissionsManager = {
|
||||
_type: "",
|
||||
@ -74,42 +78,28 @@ var gSitePermissionsManager = {
|
||||
this._removeAllButton = document.getElementById("removeAllPermissions");
|
||||
this._searchBox = document.getElementById("searchBox");
|
||||
this._checkbox = document.getElementById("permissionsDisableCheckbox");
|
||||
this._disableExtensionButton = document.getElementById("disableNotificationsPermissionExtension");
|
||||
this._permissionsDisableDescription = document.getElementById("permissionsDisableDescription");
|
||||
|
||||
let permissionsDisableDescription = document.getElementById("permissionsDisableDescription");
|
||||
let permissionsText = document.getElementById("permissionsText");
|
||||
|
||||
let l10n = sitePermissionsL10n[this._type];
|
||||
document.l10n.setAttributes(permissionsText, l10n.description);
|
||||
document.l10n.setAttributes(this._checkbox, l10n.disableLabel);
|
||||
document.l10n.setAttributes(permissionsDisableDescription, l10n.disableDescription);
|
||||
document.l10n.setAttributes(this._permissionsDisableDescription, l10n.disableDescription);
|
||||
document.l10n.setAttributes(document.documentElement, l10n.window);
|
||||
|
||||
await document.l10n.translateElements([
|
||||
permissionsText,
|
||||
this._checkbox,
|
||||
permissionsDisableDescription,
|
||||
this._permissionsDisableDescription,
|
||||
document.documentElement,
|
||||
]);
|
||||
|
||||
// Initialize the checkbox state.
|
||||
// Initialize the checkbox state and handle showing notification permission UI
|
||||
// when it is disabled by an extension.
|
||||
this._defaultPermissionStatePrefName = "permissions.default." + this._type;
|
||||
let pref = Services.prefs.getPrefType(this._defaultPermissionStatePrefName);
|
||||
if (pref != Services.prefs.PREF_INVALID) {
|
||||
this._currentDefaultPermissionsState = Services.prefs.getIntPref(this._defaultPermissionStatePrefName);
|
||||
}
|
||||
|
||||
if (this._currentDefaultPermissionsState === null) {
|
||||
this._checkbox.setAttribute("hidden", true);
|
||||
permissionsDisableDescription.setAttribute("hidden", true);
|
||||
} else if (this._currentDefaultPermissionsState == SitePermissions.BLOCK) {
|
||||
this._checkbox.checked = true;
|
||||
} else {
|
||||
this._checkbox.checked = false;
|
||||
}
|
||||
|
||||
if (Services.prefs.prefIsLocked(this._defaultPermissionStatePrefName)) {
|
||||
this._checkbox.disabled = true;
|
||||
}
|
||||
this._watchPermissionPrefChange();
|
||||
|
||||
this._loadPermissions();
|
||||
this.buildPermissionsList();
|
||||
@ -155,6 +145,68 @@ var gSitePermissionsManager = {
|
||||
menulist.getElementsByAttribute("value", perm.capability)[0];
|
||||
},
|
||||
|
||||
_handleCheckboxUIUpdates() {
|
||||
let pref = Services.prefs.getPrefType(this._defaultPermissionStatePrefName);
|
||||
if (pref != Services.prefs.PREF_INVALID) {
|
||||
this._currentDefaultPermissionsState = Services.prefs.getIntPref(this._defaultPermissionStatePrefName);
|
||||
}
|
||||
|
||||
if (this._currentDefaultPermissionsState === null) {
|
||||
this._checkbox.setAttribute("hidden", true);
|
||||
this._permissionsDisableDescription.setAttribute("hidden", true);
|
||||
} else if (this._currentDefaultPermissionsState == SitePermissions.BLOCK) {
|
||||
this._checkbox.checked = true;
|
||||
} else {
|
||||
this._checkbox.checked = false;
|
||||
}
|
||||
|
||||
if (Services.prefs.prefIsLocked(this._defaultPermissionStatePrefName)) {
|
||||
this._checkbox.disabled = true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Listen for changes to the permissions.default.* pref and make
|
||||
* necessary changes to the UI.
|
||||
*/
|
||||
_watchPermissionPrefChange() {
|
||||
this._handleCheckboxUIUpdates();
|
||||
|
||||
if (this._type == "desktop-notification") {
|
||||
this._handleWebNotificationsDisable();
|
||||
|
||||
this._disableExtensionButton.addEventListener(
|
||||
"command",
|
||||
makeDisableControllingExtension(PREF_SETTING_TYPE, NOTIFICATIONS_PERMISSION_OVERRIDE_KEY)
|
||||
);
|
||||
}
|
||||
|
||||
let observer = () => {
|
||||
this._handleCheckboxUIUpdates();
|
||||
if (this._type == "desktop-notification") {
|
||||
this._handleWebNotificationsDisable();
|
||||
}
|
||||
};
|
||||
Services.prefs.addObserver(this._defaultPermissionStatePrefName, observer);
|
||||
window.addEventListener("unload", () => {
|
||||
Services.prefs.removeObserver(this._defaultPermissionStatePrefName, observer);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the UI update for web notifications disable by extensions.
|
||||
*/
|
||||
async _handleWebNotificationsDisable() {
|
||||
let prefLocked = Services.prefs.prefIsLocked(NOTIFICATIONS_PERMISSION_PREF);
|
||||
if (prefLocked) {
|
||||
// An extension can't control these settings if they're locked.
|
||||
hideControllingExtension(NOTIFICATIONS_PERMISSION_OVERRIDE_KEY);
|
||||
} else {
|
||||
let isControlled = await handleControllingExtension(PREF_SETTING_TYPE, NOTIFICATIONS_PERMISSION_OVERRIDE_KEY);
|
||||
this._checkbox.disabled = isControlled;
|
||||
}
|
||||
},
|
||||
|
||||
_getCapabilityString(capability) {
|
||||
let stringKey = null;
|
||||
switch (capability) {
|
||||
|
@ -19,10 +19,12 @@
|
||||
onkeypress="gSitePermissionsManager.onWindowKeyPress(event);">
|
||||
|
||||
<linkset>
|
||||
<link rel="localization" href="browser/preferences/preferences.ftl"/>
|
||||
<link rel="localization" href="browser/preferences/permissions.ftl"/>
|
||||
</linkset>
|
||||
|
||||
<script src="chrome://browser/content/preferences/sitePermissions.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/preferences/in-content/extensionControlled.js"/>
|
||||
|
||||
<keyset>
|
||||
<key data-l10n-id="permissions-close-key" modifiers="accel" oncommand="window.close();"/>
|
||||
@ -63,6 +65,13 @@
|
||||
<checkbox id="permissionsDisableCheckbox"/>
|
||||
<description id="permissionsDisableDescription"/>
|
||||
<spacer flex="1"/>
|
||||
<hbox id="browserNotificationsPermissionExtensionContent"
|
||||
class="extension-controlled" align="center" hidden="true">
|
||||
<description control="disableNotificationsPermissionExtension" flex="1"/>
|
||||
<button id="disableNotificationsPermissionExtension"
|
||||
class="extension-controlled-button accessory-button"
|
||||
data-l10n-id="disable-extension"/>
|
||||
</hbox>
|
||||
<hbox class="actionButtons" align="right" flex="1">
|
||||
<button oncommand="close();" icon="close" id="cancel"
|
||||
data-l10n-id="permissions-button-cancel" />
|
||||
|
@ -97,6 +97,10 @@ extension-controlled-homepage-override = An extension, <img data-l10n-name="icon
|
||||
# is being controlled by an extension.
|
||||
extension-controlled-new-tab-url = An extension, <img data-l10n-name="icon"/> { $name }, is controlling your New Tab page.
|
||||
|
||||
# This string is shown to notify the user that their notifications permission
|
||||
# is being controlled by an extension.
|
||||
extension-controlled-web-notifications= An extension, <img data-l10n-name="icon"/> { $name }, is controlling this setting.
|
||||
|
||||
# This string is shown to notify the user that the default search engine
|
||||
# is being controlled by an extension.
|
||||
extension-controlled-default-search = An extension, <img data-l10n-name="icon"/> { $name }, has set your default search engine.
|
||||
|
@ -38,24 +38,19 @@ NS_IMPL_CI_INTERFACE_GETTER(NullPrincipal,
|
||||
/* static */ already_AddRefed<NullPrincipal>
|
||||
NullPrincipal::CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom)
|
||||
{
|
||||
MOZ_ASSERT(aInheritFrom);
|
||||
return CreateWithInheritedAttributes(Cast(aInheritFrom)->OriginAttributesRef(), false);
|
||||
RefPtr<NullPrincipal> nullPrin = new NullPrincipal();
|
||||
nsresult rv = nullPrin->Init(Cast(aInheritFrom)->OriginAttributesRef());
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
return nullPrin.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<NullPrincipal>
|
||||
NullPrincipal::CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty)
|
||||
{
|
||||
MOZ_ASSERT(aDocShell);
|
||||
|
||||
OriginAttributes attrs = nsDocShell::Cast(aDocShell)->GetOriginAttributes();
|
||||
return CreateWithInheritedAttributes(attrs, aIsFirstParty);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<NullPrincipal>
|
||||
NullPrincipal::CreateWithInheritedAttributes(const OriginAttributes& aOriginAttributes, bool aIsFirstParty)
|
||||
{
|
||||
RefPtr<NullPrincipal> nullPrin = new NullPrincipal();
|
||||
nsresult rv = nullPrin->Init(aOriginAttributes, aIsFirstParty);
|
||||
nsresult rv = nullPrin->Init(attrs, aIsFirstParty);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
return nullPrin.forget();
|
||||
}
|
||||
|
@ -56,19 +56,14 @@ public:
|
||||
NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
|
||||
NS_IMETHOD GetAddonId(nsAString& aAddonId) override;
|
||||
|
||||
static already_AddRefed<NullPrincipal>
|
||||
CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom);
|
||||
static already_AddRefed<NullPrincipal> CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom);
|
||||
|
||||
// Create NullPrincipal with origin attributes from docshell.
|
||||
// If aIsFirstParty is true, and the pref 'privacy.firstparty.isolate' is also
|
||||
// enabled, the mFirstPartyDomain value of the origin attributes will be set
|
||||
// to an unique value.
|
||||
static already_AddRefed<NullPrincipal>
|
||||
CreateWithInheritedAttributes(nsIDocShell* aDocShell,
|
||||
bool aIsFirstParty = false);
|
||||
static already_AddRefed<NullPrincipal>
|
||||
CreateWithInheritedAttributes(const OriginAttributes& aOriginAttributes,
|
||||
bool aIsFirstParty = false);
|
||||
CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty = false);
|
||||
|
||||
static already_AddRefed<NullPrincipal>
|
||||
Create(const OriginAttributes& aOriginAttributes,
|
||||
@ -90,8 +85,7 @@ public:
|
||||
protected:
|
||||
virtual ~NullPrincipal() = default;
|
||||
|
||||
bool SubsumesInternal(nsIPrincipal* aOther,
|
||||
DocumentDomainConsideration aConsideration) override
|
||||
bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) override
|
||||
{
|
||||
return aOther == this;
|
||||
}
|
||||
|
@ -205,6 +205,7 @@ skip-if = verify
|
||||
[browser_jsterm_autocomplete_return_key.js]
|
||||
[browser_jsterm_autocomplete_width.js]
|
||||
[browser_jsterm_autocomplete-properties-with-non-alphanumeric-names.js]
|
||||
[browser_jsterm_await_concurrent.js]
|
||||
[browser_jsterm_await_error.js]
|
||||
[browser_jsterm_await_helper_dollar_underscore.js]
|
||||
[browser_jsterm_await_paused.js]
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that top-level await expression work as expected.
|
||||
// Test that top-level await expressions work as expected.
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -21,7 +21,6 @@ add_task(async function() {
|
||||
|
||||
async function performTests() {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
const {jsterm} = hud;
|
||||
|
||||
const executeAndWaitForResultMessage = (input, expectedOutput) =>
|
||||
executeAndWaitForMessage(hud, input, expectedOutput, ".result");
|
||||
@ -34,8 +33,8 @@ async function performTests() {
|
||||
);
|
||||
|
||||
// Check that the resulting promise of the async iife is not displayed.
|
||||
let messages = hud.ui.outputNode.querySelectorAll(".message .message-body");
|
||||
let messagesText = Array.from(messages).map(n => n.textContent).join(" - ");
|
||||
const messages = hud.ui.outputNode.querySelectorAll(".message .message-body");
|
||||
const messagesText = Array.from(messages).map(n => n.textContent).join(" - ");
|
||||
is(messagesText, `${simpleAwait} - Array [ "await1" ]`,
|
||||
"The output contains the the expected messages");
|
||||
|
||||
@ -62,31 +61,6 @@ async function performTests() {
|
||||
);
|
||||
ok(message.node, "`x` was assigned as expected");
|
||||
|
||||
info("Check that concurrent await expression work fine");
|
||||
hud.ui.clearOutput();
|
||||
const delays = [1000, 500, 2000, 1500];
|
||||
const inputs = delays.map(delay => `await new Promise(
|
||||
r => setTimeout(() => r("await-concurrent-" + ${delay}), ${delay}))`);
|
||||
|
||||
// Let's wait for the message that sould be displayed last.
|
||||
const onMessage = waitForMessage(hud, "await-concurrent-2000", ".message.result");
|
||||
for (const input of inputs) {
|
||||
jsterm.execute(input);
|
||||
}
|
||||
await onMessage;
|
||||
|
||||
messages = hud.ui.outputNode.querySelectorAll(".message .message-body");
|
||||
messagesText = Array.from(messages).map(n => n.textContent);
|
||||
const expectedMessages = [
|
||||
...inputs,
|
||||
`"await-concurrent-500"`,
|
||||
`"await-concurrent-1000"`,
|
||||
`"await-concurrent-1500"`,
|
||||
`"await-concurrent-2000"`,
|
||||
];
|
||||
is(JSON.stringify(messagesText, null, 2), JSON.stringify(expectedMessages, null, 2),
|
||||
"The output contains the the expected messages, in the expected order");
|
||||
|
||||
info("Check that a logged promise is still displayed as a promise");
|
||||
message = await executeAndWaitForResultMessage(
|
||||
`new Promise(r => setTimeout(() => r(1), 1000))`,
|
||||
|
@ -0,0 +1,49 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that multiple concurrent top-level await expressions work as expected.
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,Web Console test top-level await";
|
||||
|
||||
add_task(async function() {
|
||||
// Enable await mapping.
|
||||
await pushPref("devtools.debugger.features.map-await-expression", true);
|
||||
|
||||
// Run test with legacy JsTerm
|
||||
await pushPref("devtools.webconsole.jsterm.codeMirror", false);
|
||||
await performTests();
|
||||
// And then run it with the CodeMirror-powered one.
|
||||
await pushPref("devtools.webconsole.jsterm.codeMirror", true);
|
||||
await performTests();
|
||||
});
|
||||
|
||||
async function performTests() {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
const {jsterm} = hud;
|
||||
|
||||
hud.ui.clearOutput();
|
||||
const delays = [3000, 500, 9000, 6000];
|
||||
const inputs = delays.map(delay => `await new Promise(
|
||||
r => setTimeout(() => r("await-concurrent-" + ${delay}), ${delay}))`);
|
||||
|
||||
// Let's wait for the message that sould be displayed last.
|
||||
const onMessage = waitForMessage(hud, "await-concurrent-9000", ".message.result");
|
||||
for (const input of inputs) {
|
||||
jsterm.execute(input);
|
||||
}
|
||||
await onMessage;
|
||||
|
||||
const messages = hud.ui.outputNode.querySelectorAll(".message .message-body");
|
||||
const messagesText = Array.from(messages).map(n => n.textContent);
|
||||
const expectedMessages = [
|
||||
...inputs,
|
||||
`"await-concurrent-500"`,
|
||||
`"await-concurrent-3000"`,
|
||||
`"await-concurrent-6000"`,
|
||||
`"await-concurrent-9000"`,
|
||||
];
|
||||
is(JSON.stringify(messagesText, null, 2), JSON.stringify(expectedMessages, null, 2),
|
||||
"The output contains the the expected messages, in the expected order");
|
||||
}
|
@ -66,7 +66,7 @@ WebConsoleOutputWrapper.prototype = {
|
||||
hud.owner.openLink(url, e);
|
||||
},
|
||||
canRewind: () => {
|
||||
if (!hud.owner.target.activeTab) {
|
||||
if (!(hud.owner && hud.owner.target && hud.owner.target.activeTab)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ XPIDL_MODULE = 'docshell'
|
||||
EXPORTS += [
|
||||
'nsCTooltipTextProvider.h',
|
||||
'nsDocShell.h',
|
||||
'nsDocShellLoadState.h',
|
||||
'nsDocShellLoadInfo.h',
|
||||
'nsDocShellLoadTypes.h',
|
||||
'nsDocShellTreeOwner.h',
|
||||
'nsILinkHandler.h',
|
||||
@ -88,7 +88,7 @@ UNIFIED_SOURCES += [
|
||||
'nsDocShell.cpp',
|
||||
'nsDocShellEditorData.cpp',
|
||||
'nsDocShellEnumerator.cpp',
|
||||
'nsDocShellLoadState.cpp',
|
||||
'nsDocShellLoadInfo.cpp',
|
||||
'nsDocShellTreeOwner.cpp',
|
||||
'nsDSURIContentListener.cpp',
|
||||
'nsPingListener.cpp',
|
||||
|
@ -169,7 +169,7 @@
|
||||
#include "nsDocShellCID.h"
|
||||
#include "nsDocShellEditorData.h"
|
||||
#include "nsDocShellEnumerator.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
#include "nsDocShellLoadTypes.h"
|
||||
#include "nsDOMCID.h"
|
||||
#include "nsDOMNavigationTiming.h"
|
||||
@ -643,12 +643,14 @@ nsDocShell::GetInterface(const nsIID& aIID, void** aSink)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::LoadURI(nsDocShellLoadState* aLoadState)
|
||||
nsDocShell::LoadURI(nsIURI* aURI,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
uint32_t aLoadFlags,
|
||||
bool aFirstParty)
|
||||
{
|
||||
MOZ_ASSERT(aLoadState, "Must have a valid load state!");
|
||||
MOZ_ASSERT((aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0,
|
||||
"Should not have these flags set");
|
||||
MOZ_ASSERT(aLoadState->URI(), "Should have a valid URI to load");
|
||||
MOZ_ASSERT(aLoadInfo || (aLoadFlags & EXTRA_LOAD_FLAGS) == 0,
|
||||
"Unexpected flags");
|
||||
MOZ_ASSERT((aLoadFlags & 0xf) == 0, "Should not have these flags set");
|
||||
|
||||
// Note: we allow loads to get through here even if mFiredUnloadEvent is
|
||||
// true; that case will get handled in LoadInternal or LoadHistoryEntry,
|
||||
@ -660,121 +662,86 @@ nsDocShell::LoadURI(nsDocShellLoadState* aLoadState)
|
||||
return NS_OK; // JS may not handle returning of an error code
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> referrer;
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI;
|
||||
bool keepResultPrincipalURIIfSet = false;
|
||||
bool loadReplace = false;
|
||||
nsCOMPtr<nsIInputStream> postStream;
|
||||
nsCOMPtr<nsIInputStream> headersStream;
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal;
|
||||
bool inheritPrincipal = false;
|
||||
bool principalIsExplicit = false;
|
||||
bool sendReferrer = true;
|
||||
uint32_t referrerPolicy = RP_Unset;
|
||||
bool isSrcdoc = false;
|
||||
nsCOMPtr<nsISHEntry> shEntry;
|
||||
nsString target;
|
||||
nsAutoString srcdoc;
|
||||
bool forceAllowDataURI = false;
|
||||
bool originalFrameSrc = false;
|
||||
nsCOMPtr<nsIDocShell> sourceDocShell;
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
|
||||
uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
|
||||
|
||||
NS_ENSURE_ARG(aURI);
|
||||
|
||||
if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
|
||||
mItemType == typeContent && !NS_IsAboutBlank(aLoadState->URI())) {
|
||||
mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
|
||||
StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
|
||||
}
|
||||
|
||||
// Extract the info from the DocShellLoadInfo struct...
|
||||
if (aLoadInfo) {
|
||||
referrer = aLoadInfo->Referrer();
|
||||
originalURI = aLoadInfo->OriginalURI();
|
||||
aLoadInfo->GetMaybeResultPrincipalURI(resultPrincipalURI);
|
||||
keepResultPrincipalURIIfSet = aLoadInfo->KeepResultPrincipalURIIfSet();
|
||||
loadReplace = aLoadInfo->LoadReplace();
|
||||
// Get the appropriate loadType from nsIDocShellLoadInfo type
|
||||
loadType = aLoadInfo->LoadType();
|
||||
|
||||
triggeringPrincipal = aLoadInfo->TriggeringPrincipal();
|
||||
inheritPrincipal = aLoadInfo->InheritPrincipal();
|
||||
principalIsExplicit = aLoadInfo->PrincipalIsExplicit();
|
||||
shEntry = aLoadInfo->SHEntry();
|
||||
aLoadInfo->GetTarget(target);
|
||||
postStream = aLoadInfo->PostDataStream();
|
||||
headersStream = aLoadInfo->HeadersStream();
|
||||
sendReferrer = aLoadInfo->SendReferrer();
|
||||
referrerPolicy = aLoadInfo->ReferrerPolicy();
|
||||
isSrcdoc = aLoadInfo->IsSrcdocLoad();
|
||||
aLoadInfo->GetSrcdocData(srcdoc);
|
||||
sourceDocShell = aLoadInfo->SourceDocShell();
|
||||
baseURI = aLoadInfo->BaseURI();
|
||||
forceAllowDataURI = aLoadInfo->ForceAllowDataURI();
|
||||
originalFrameSrc = aLoadInfo->OriginalFrameSrc();
|
||||
}
|
||||
|
||||
MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
|
||||
("nsDocShell[%p]: loading %s with flags 0x%08x",
|
||||
this, aLoadState->URI()->GetSpecOrDefault().get(),
|
||||
aLoadState->LoadFlags()));
|
||||
this, aURI->GetSpecOrDefault().get(), aLoadFlags));
|
||||
|
||||
if (!aLoadState->SHEntry() &&
|
||||
!LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(),
|
||||
LOAD_FLAGS_REPLACE_HISTORY)) {
|
||||
// This is possibly a subframe, so handle it accordingly.
|
||||
//
|
||||
// If history exists, it will be loaded into the aLoadState object, and the
|
||||
// LoadType will be changed.
|
||||
MaybeHandleSubframeHistory(aLoadState);
|
||||
}
|
||||
|
||||
if (aLoadState->SHEntry()) {
|
||||
#ifdef DEBUG
|
||||
MOZ_LOG(gDocShellLog, LogLevel::Debug,
|
||||
("nsDocShell[%p]: loading from session history", this));
|
||||
#endif
|
||||
|
||||
return LoadHistoryEntry(aLoadState->SHEntry(), aLoadState->LoadType());
|
||||
}
|
||||
|
||||
// On history navigation via Back/Forward buttons, don't execute
|
||||
// automatic JavaScript redirection such as |location.href = ...| or
|
||||
// |window.open()|
|
||||
//
|
||||
// LOAD_NORMAL: window.open(...) etc.
|
||||
// LOAD_STOP_CONTENT: location.href = ..., location.assign(...)
|
||||
if ((aLoadState->LoadType() == LOAD_NORMAL ||
|
||||
aLoadState->LoadType() == LOAD_STOP_CONTENT) &&
|
||||
ShouldBlockLoadingForBackButton()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Set up the inheriting principal in LoadState.
|
||||
nsresult rv = aLoadState->SetupInheritingPrincipal(mItemType, mOriginAttributes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aLoadState->SetupTriggeringPrincipal(mOriginAttributes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aLoadState->CalculateDocShellInternalLoadFlags();
|
||||
|
||||
mozilla::Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI;
|
||||
aLoadState->GetMaybeResultPrincipalURI(resultPrincipalURI);
|
||||
|
||||
MOZ_ASSERT(aLoadState->TypeHint().IsVoid(),
|
||||
"Typehint should be null when calling InternalLoad from LoadURI");
|
||||
MOZ_ASSERT(aLoadState->FileName().IsVoid(),
|
||||
"FileName should be null when calling InternalLoad from LoadURI");
|
||||
MOZ_ASSERT(aLoadState->SHEntry() == nullptr,
|
||||
"SHEntry should be null when calling InternalLoad from LoadURI");
|
||||
|
||||
return InternalLoad(aLoadState->URI(),
|
||||
aLoadState->OriginalURI(),
|
||||
resultPrincipalURI,
|
||||
aLoadState->KeepResultPrincipalURIIfSet(),
|
||||
aLoadState->LoadReplace(),
|
||||
aLoadState->Referrer(),
|
||||
aLoadState->ReferrerPolicy(),
|
||||
aLoadState->TriggeringPrincipal(),
|
||||
aLoadState->PrincipalToInherit(),
|
||||
aLoadState->DocShellInternalLoadFlags(),
|
||||
aLoadState->Target(),
|
||||
aLoadState->TypeHint(),
|
||||
aLoadState->FileName(),
|
||||
aLoadState->PostDataStream(),
|
||||
aLoadState->HeadersStream(),
|
||||
aLoadState->LoadType(),
|
||||
aLoadState->SHEntry(),
|
||||
aLoadState->FirstParty(),
|
||||
aLoadState->SrcdocData(),
|
||||
aLoadState->SourceDocShell(),
|
||||
aLoadState->BaseURI(),
|
||||
nullptr, // no nsIDocShell
|
||||
nullptr); // no nsIRequest
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::MaybeHandleSubframeHistory(nsDocShellLoadState* aLoadState)
|
||||
{
|
||||
// First, verify if this is a subframe.
|
||||
if (!shEntry &&
|
||||
!LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) {
|
||||
// First verify if this is a subframe.
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
|
||||
GetSameTypeParent(getter_AddRefs(parentAsItem));
|
||||
nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
|
||||
uint32_t parentLoadType;
|
||||
|
||||
if (!parentDS || parentDS == static_cast<nsIDocShell*>(this)) {
|
||||
// This is the root docshell. If we got here while
|
||||
// executing an onLoad Handler,this load will not go
|
||||
// into session history.
|
||||
bool inOnLoadHandler = false;
|
||||
GetIsExecutingOnLoadHandler(&inOnLoadHandler);
|
||||
if (inOnLoadHandler) {
|
||||
aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* OK. It is a subframe. Checkout the parent's loadtype. If the parent was
|
||||
* loaded through a history mechanism, then get the SH entry for the child from
|
||||
* the parent. This is done to restore frameset navigation while going
|
||||
* back/forward. If the parent was loaded through any other loadType, set the
|
||||
* child's loadType too accordingly, so that session history does not get
|
||||
* confused.
|
||||
if (parentDS && parentDS != static_cast<nsIDocShell*>(this)) {
|
||||
/* OK. It is a subframe. Checkout the
|
||||
* parent's loadtype. If the parent was loaded thro' a history
|
||||
* mechanism, then get the SH entry for the child from the parent.
|
||||
* This is done to restore frameset navigation while going back/forward.
|
||||
* If the parent was loaded through any other loadType, set the
|
||||
* child's loadType too accordingly, so that session history does not
|
||||
* get confused.
|
||||
*/
|
||||
|
||||
// Get the parent's load type
|
||||
uint32_t parentLoadType;
|
||||
parentDS->GetLoadType(&parentLoadType);
|
||||
|
||||
// Get the ShEntry for the child from the parent
|
||||
@ -782,17 +749,13 @@ nsDocShell::MaybeHandleSubframeHistory(nsDocShellLoadState* aLoadState)
|
||||
bool oshe = false;
|
||||
parentDS->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
|
||||
bool dynamicallyAddedChild = mDynamicallyCreated;
|
||||
|
||||
if (!dynamicallyAddedChild && !oshe && currentSH) {
|
||||
currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
|
||||
}
|
||||
|
||||
if (!dynamicallyAddedChild) {
|
||||
// Only use the old SHEntry, if we're sure enough that
|
||||
// it wasn't originally for some other frame.
|
||||
nsCOMPtr<nsISHEntry> shEntry;
|
||||
parentDS->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
|
||||
aLoadState->SetSHEntry(shEntry);
|
||||
}
|
||||
|
||||
// Make some decisions on the child frame's loadType based on the
|
||||
@ -805,13 +768,58 @@ nsDocShell::MaybeHandleSubframeHistory(nsDocShellLoadState* aLoadState)
|
||||
// currentSHEntry is null.
|
||||
nsCOMPtr<nsISHEntry> currentChildEntry;
|
||||
GetCurrentSHEntry(getter_AddRefs(currentChildEntry), &oshe);
|
||||
|
||||
if (mCurrentURI && (!NS_IsAboutBlank(mCurrentURI) || currentChildEntry)) {
|
||||
if (!mCurrentURI || (NS_IsAboutBlank(mCurrentURI) && !currentChildEntry)) {
|
||||
// This is a newly created frame. Check for exception cases first.
|
||||
// By default the subframe will inherit the parent's loadType.
|
||||
if (shEntry && (parentLoadType == LOAD_NORMAL ||
|
||||
parentLoadType == LOAD_LINK ||
|
||||
parentLoadType == LOAD_NORMAL_EXTERNAL)) {
|
||||
// The parent was loaded normally. In this case, this *brand new*
|
||||
// child really shouldn't have a SHEntry. If it does, it could be
|
||||
// because the parent is replacing an existing frame with a new frame,
|
||||
// in the onLoadHandler. We don't want this url to get into session
|
||||
// history. Clear off shEntry, and set load type to
|
||||
// LOAD_BYPASS_HISTORY.
|
||||
bool inOnLoadHandler = false;
|
||||
parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
|
||||
if (inOnLoadHandler) {
|
||||
loadType = LOAD_NORMAL_REPLACE;
|
||||
shEntry = nullptr;
|
||||
}
|
||||
} else if (parentLoadType == LOAD_REFRESH) {
|
||||
// Clear shEntry. For refresh loads, we have to load
|
||||
// what comes thro' the pipe, not what's in history.
|
||||
shEntry = nullptr;
|
||||
} else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
|
||||
(shEntry &&
|
||||
((parentLoadType & LOAD_CMD_HISTORY) ||
|
||||
(parentLoadType == LOAD_RELOAD_NORMAL) ||
|
||||
(parentLoadType == LOAD_RELOAD_CHARSET_CHANGE) ||
|
||||
(parentLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE) ||
|
||||
(parentLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE)))) {
|
||||
// If the parent url, bypassed history or was loaded from
|
||||
// history, pass on the parent's loadType to the new child
|
||||
// frame too, so that the child frame will also
|
||||
// avoid getting into history.
|
||||
loadType = parentLoadType;
|
||||
} else if (parentLoadType == LOAD_ERROR_PAGE) {
|
||||
// If the parent document is an error page, we don't
|
||||
// want to update global/session history. However,
|
||||
// this child frame is not an error page.
|
||||
loadType = LOAD_BYPASS_HISTORY;
|
||||
} else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) ||
|
||||
(parentLoadType == LOAD_RELOAD_BYPASS_PROXY) ||
|
||||
(parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
|
||||
// the new frame should inherit the parent's load type so that it also
|
||||
// bypasses the cache and/or proxy
|
||||
loadType = parentLoadType;
|
||||
}
|
||||
} else {
|
||||
// This is a pre-existing subframe. If
|
||||
// 1. The load of this frame was not originally initiated by session
|
||||
// history directly (i.e. (!shEntry) condition succeeded, but it can
|
||||
// still be a history load on parent which causes this frame being
|
||||
// loaded), which we checked with the above assert, and
|
||||
// loaded), and
|
||||
// 2. mCurrentURI is not null, nor the initial about:blank,
|
||||
// it is possible that a parent's onLoadHandler or even self's
|
||||
// onLoadHandler is loading a new page in this child. Check parent's and
|
||||
@ -823,57 +831,187 @@ nsDocShell::MaybeHandleSubframeHistory(nsDocShellLoadState* aLoadState)
|
||||
GetBusyFlags(&selfBusy);
|
||||
if (parentBusy & BUSY_FLAGS_BUSY ||
|
||||
selfBusy & BUSY_FLAGS_BUSY) {
|
||||
aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
|
||||
aLoadState->SetSHEntry(nullptr);
|
||||
loadType = LOAD_NORMAL_REPLACE;
|
||||
shEntry = nullptr;
|
||||
}
|
||||
}
|
||||
} // parentDS
|
||||
else {
|
||||
// This is the root docshell. If we got here while
|
||||
// executing an onLoad Handler,this load will not go
|
||||
// into session history.
|
||||
bool inOnLoadHandler = false;
|
||||
GetIsExecutingOnLoadHandler(&inOnLoadHandler);
|
||||
if (inOnLoadHandler) {
|
||||
loadType = LOAD_NORMAL_REPLACE;
|
||||
}
|
||||
}
|
||||
return;
|
||||
} // !shEntry
|
||||
|
||||
if (shEntry) {
|
||||
#ifdef DEBUG
|
||||
MOZ_LOG(gDocShellLog, LogLevel::Debug,
|
||||
("nsDocShell[%p]: loading from session history", this));
|
||||
#endif
|
||||
|
||||
return LoadHistoryEntry(shEntry, loadType);
|
||||
}
|
||||
|
||||
// This is a newly created frame. Check for exception cases first.
|
||||
// By default the subframe will inherit the parent's loadType.
|
||||
if (aLoadState->SHEntry() && (parentLoadType == LOAD_NORMAL ||
|
||||
parentLoadType == LOAD_LINK ||
|
||||
parentLoadType == LOAD_NORMAL_EXTERNAL)) {
|
||||
// The parent was loaded normally. In this case, this *brand new*
|
||||
// child really shouldn't have a SHEntry. If it does, it could be
|
||||
// because the parent is replacing an existing frame with a new frame,
|
||||
// in the onLoadHandler. We don't want this url to get into session
|
||||
// history. Clear off shEntry, and set load type to
|
||||
// LOAD_BYPASS_HISTORY.
|
||||
bool inOnLoadHandler = false;
|
||||
parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
|
||||
if (inOnLoadHandler) {
|
||||
aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
|
||||
aLoadState->SetSHEntry(nullptr);
|
||||
}
|
||||
} else if (parentLoadType == LOAD_REFRESH) {
|
||||
// Clear shEntry. For refresh loads, we have to load
|
||||
// what comes through the pipe, not what's in history.
|
||||
aLoadState->SetSHEntry(nullptr);
|
||||
} else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
|
||||
(aLoadState->SHEntry() &&
|
||||
((parentLoadType & LOAD_CMD_HISTORY) ||
|
||||
(parentLoadType == LOAD_RELOAD_NORMAL) ||
|
||||
(parentLoadType == LOAD_RELOAD_CHARSET_CHANGE) ||
|
||||
(parentLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE) ||
|
||||
(parentLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE)))) {
|
||||
// If the parent url, bypassed history or was loaded from
|
||||
// history, pass on the parent's loadType to the new child
|
||||
// frame too, so that the child frame will also
|
||||
// avoid getting into history.
|
||||
aLoadState->SetLoadType(parentLoadType);
|
||||
} else if (parentLoadType == LOAD_ERROR_PAGE) {
|
||||
// If the parent document is an error page, we don't
|
||||
// want to update global/session history. However,
|
||||
// this child frame is not an error page.
|
||||
aLoadState->SetLoadType(LOAD_BYPASS_HISTORY);
|
||||
} else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) ||
|
||||
(parentLoadType == LOAD_RELOAD_BYPASS_PROXY) ||
|
||||
(parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
|
||||
// the new frame should inherit the parent's load type so that it also
|
||||
// bypasses the cache and/or proxy
|
||||
aLoadState->SetLoadType(parentLoadType);
|
||||
// On history navigation via Back/Forward buttons, don't execute
|
||||
// automatic JavaScript redirection such as |location.href = ...| or
|
||||
// |window.open()|
|
||||
//
|
||||
// LOAD_NORMAL: window.open(...) etc.
|
||||
// LOAD_STOP_CONTENT: location.href = ..., location.assign(...)
|
||||
if ((loadType == LOAD_NORMAL || loadType == LOAD_STOP_CONTENT) &&
|
||||
ShouldBlockLoadingForBackButton()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Perform the load...
|
||||
|
||||
// We need a principalToInherit.
|
||||
//
|
||||
// If principalIsExplicit is not set there are 4 possibilities:
|
||||
// (1) If the system principal or an expanded principal was passed
|
||||
// in and we're a typeContent docshell, inherit the principal
|
||||
// from the current document instead.
|
||||
// (2) In all other cases when the principal passed in is not null,
|
||||
// use that principal.
|
||||
// (3) If the caller has allowed inheriting from the current document,
|
||||
// or if we're being called from system code (eg chrome JS or pure
|
||||
// C++) then inheritPrincipal should be true and InternalLoad will get
|
||||
// a principal from the current document. If none of these things are
|
||||
// true, then
|
||||
// (4) we don't pass a principal into the channel, and a principal will be
|
||||
// created later from the channel's internal data.
|
||||
//
|
||||
// If principalIsExplicit *is* set, there are 4 possibilities
|
||||
// (1) If the system principal or an expanded principal was passed in
|
||||
// and we're a typeContent docshell, return an error.
|
||||
// (2) In all other cases when the principal passed in is not null,
|
||||
// use that principal.
|
||||
// (3) If the caller has allowed inheriting from the current document,
|
||||
// then inheritPrincipal should be true and InternalLoad will get
|
||||
// a principal from the current document. If none of these things are
|
||||
// true, then
|
||||
// (4) we dont' pass a principal into the channel, and a principal will be
|
||||
// created later from the channel's internal data.
|
||||
nsCOMPtr<nsIPrincipal> principalToInherit = triggeringPrincipal;
|
||||
if (principalToInherit && mItemType != typeChrome) {
|
||||
if (nsContentUtils::IsSystemPrincipal(principalToInherit)) {
|
||||
if (principalIsExplicit) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
principalToInherit = nullptr;
|
||||
inheritPrincipal = true;
|
||||
} else if (nsContentUtils::IsExpandedPrincipal(principalToInherit)) {
|
||||
if (principalIsExplicit) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
// Don't inherit from the current page. Just do the safe thing
|
||||
// and pretend that we were loaded by a nullprincipal.
|
||||
//
|
||||
// We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't
|
||||
// have origin attributes.
|
||||
principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this);
|
||||
inheritPrincipal = false;
|
||||
}
|
||||
}
|
||||
if (!principalToInherit && !inheritPrincipal && !principalIsExplicit) {
|
||||
// See if there's system or chrome JS code running
|
||||
inheritPrincipal = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
|
||||
}
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL) {
|
||||
inheritPrincipal = false;
|
||||
// If aFirstParty is true and the pref 'privacy.firstparty.isolate' is
|
||||
// enabled, we will set firstPartyDomain on the origin attributes.
|
||||
principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this, aFirstParty);
|
||||
}
|
||||
|
||||
// If the triggeringPrincipal is not passed explicitly, we first try to create
|
||||
// a principal from the referrer, since the referrer URI reflects the web origin
|
||||
// that triggered the load. If there is no referrer URI, we fall back to using
|
||||
// the SystemPrincipal. It's safe to assume that no provided triggeringPrincipal
|
||||
// and no referrer simulate a load that was triggered by the system.
|
||||
// It's important to note that this block of code needs to appear *after* the block
|
||||
// where we munge the principalToInherit, because otherwise we would never enter
|
||||
// code blocks checking if the principalToInherit is null and we will end up with
|
||||
// a wrong inheritPrincipal flag.
|
||||
if (!triggeringPrincipal) {
|
||||
if (referrer) {
|
||||
nsresult rv = CreatePrincipalFromReferrer(referrer,
|
||||
getter_AddRefs(triggeringPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (inheritPrincipal) {
|
||||
MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(principalToInherit), "Should not inherit SystemPrincipal");
|
||||
flags |= INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
|
||||
}
|
||||
|
||||
if (!sendReferrer) {
|
||||
flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
|
||||
}
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
|
||||
flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
|
||||
}
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) {
|
||||
flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
|
||||
}
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER) {
|
||||
flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
|
||||
}
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
|
||||
flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
|
||||
}
|
||||
|
||||
if (isSrcdoc) {
|
||||
flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
|
||||
}
|
||||
|
||||
if (forceAllowDataURI) {
|
||||
flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
|
||||
}
|
||||
|
||||
if (originalFrameSrc) {
|
||||
flags |= INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC;
|
||||
}
|
||||
|
||||
return InternalLoad(aURI,
|
||||
originalURI,
|
||||
resultPrincipalURI,
|
||||
keepResultPrincipalURIIfSet,
|
||||
loadReplace,
|
||||
referrer,
|
||||
referrerPolicy,
|
||||
triggeringPrincipal,
|
||||
principalToInherit,
|
||||
flags,
|
||||
target,
|
||||
nullptr, // No type hint
|
||||
VoidString(), // No forced download
|
||||
postStream,
|
||||
headersStream,
|
||||
loadType,
|
||||
nullptr, // No SHEntry
|
||||
aFirstParty,
|
||||
srcdoc,
|
||||
sourceDocShell,
|
||||
baseURI,
|
||||
nullptr, // No nsIDocShell
|
||||
nullptr); // No nsIRequest
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4088,7 +4226,7 @@ nsDocShell::LoadURIWithOptions(const nsAString& aURI,
|
||||
nsIURI* aBaseURI,
|
||||
nsIPrincipal* aTriggeringPrincipal)
|
||||
{
|
||||
NS_ASSERTION((aLoadFlags & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0, "Unexpected flags");
|
||||
NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags");
|
||||
|
||||
if (!IsNavigationAllowed()) {
|
||||
return NS_OK; // JS may not handle returning of an error code
|
||||
@ -4183,28 +4321,27 @@ nsDocShell::LoadURIWithOptions(const nsAString& aURI,
|
||||
uint32_t extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS);
|
||||
aLoadFlags &= ~EXTRA_LOAD_FLAGS;
|
||||
|
||||
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
|
||||
RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
|
||||
|
||||
/*
|
||||
* If the user "Disables Protection on This Page", we have to make sure to
|
||||
* remember the users decision when opening links in child tabs [Bug 906190]
|
||||
*/
|
||||
uint32_t loadType;
|
||||
if (aLoadFlags & LOAD_FLAGS_ALLOW_MIXED_CONTENT) {
|
||||
loadState->SetLoadType(MAKE_LOAD_TYPE(LOAD_NORMAL_ALLOW_MIXED_CONTENT, aLoadFlags));
|
||||
loadType = MAKE_LOAD_TYPE(LOAD_NORMAL_ALLOW_MIXED_CONTENT, aLoadFlags);
|
||||
} else {
|
||||
loadState->SetLoadType(MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags));
|
||||
loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
|
||||
}
|
||||
|
||||
loadState->SetURI(uri);
|
||||
loadState->SetLoadFlags(extraFlags);
|
||||
loadState->SetFirstParty(true);
|
||||
loadState->SetPostDataStream(postStream);
|
||||
loadState->SetReferrer(aReferringURI);
|
||||
loadState->SetReferrerPolicy((mozilla::net::ReferrerPolicy)aReferrerPolicy);
|
||||
loadState->SetHeadersStream(aHeaderStream);
|
||||
loadState->SetBaseURI(aBaseURI);
|
||||
loadState->SetTriggeringPrincipal(aTriggeringPrincipal);
|
||||
loadState->SetForceAllowDataURI(forceAllowDataURI);
|
||||
loadInfo->SetLoadType(loadType);
|
||||
loadInfo->SetPostDataStream(postStream);
|
||||
loadInfo->SetReferrer(aReferringURI);
|
||||
loadInfo->SetReferrerPolicy((mozilla::net::ReferrerPolicy)aReferrerPolicy);
|
||||
loadInfo->SetHeadersStream(aHeaderStream);
|
||||
loadInfo->SetBaseURI(aBaseURI);
|
||||
loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
|
||||
loadInfo->SetForceAllowDataURI(forceAllowDataURI);
|
||||
|
||||
if (fixupInfo) {
|
||||
nsAutoString searchProvider, keyword;
|
||||
@ -4213,7 +4350,7 @@ nsDocShell::LoadURIWithOptions(const nsAString& aURI,
|
||||
MaybeNotifyKeywordSearchLoading(searchProvider, keyword);
|
||||
}
|
||||
|
||||
rv = LoadURI(loadState);
|
||||
rv = LoadURI(uri, loadInfo, extraFlags, true);
|
||||
|
||||
// Save URI string in case it's needed later when
|
||||
// sending to search engine service in EndPageLoad()
|
||||
@ -4781,7 +4918,7 @@ nsDocShell::LoadErrorPage(nsIURI* aErrorURI, nsIURI* aFailedURI, nsIChannel* aFa
|
||||
return InternalLoad(aErrorURI, nullptr, Nothing(), false, false, nullptr, RP_Unset,
|
||||
nsContentUtils::GetSystemPrincipal(), nullptr,
|
||||
INTERNAL_LOAD_FLAGS_NONE, EmptyString(),
|
||||
VoidCString(), VoidString(), nullptr, nullptr,
|
||||
nullptr, VoidString(), nullptr, nullptr,
|
||||
LOAD_ERROR_PAGE, nullptr, true, VoidString(), this,
|
||||
nullptr, nullptr, nullptr);
|
||||
}
|
||||
@ -4793,7 +4930,7 @@ nsDocShell::Reload(uint32_t aReloadFlags)
|
||||
return NS_OK; // JS may not handle returning of an error code
|
||||
}
|
||||
nsresult rv;
|
||||
NS_ASSERTION(((aReloadFlags & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0),
|
||||
NS_ASSERTION(((aReloadFlags & 0xf) == 0),
|
||||
"Reload command not updated to use load flags!");
|
||||
NS_ASSERTION((aReloadFlags & EXTRA_LOAD_FLAGS) == 0,
|
||||
"Don't pass these flags to Reload");
|
||||
@ -4881,7 +5018,7 @@ nsDocShell::Reload(uint32_t aReloadFlags)
|
||||
triggeringPrincipal,
|
||||
flags,
|
||||
EmptyString(), // No window target
|
||||
NS_LossyConvertUTF16toASCII(contentTypeHint),
|
||||
NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
|
||||
VoidString(), // No forced download
|
||||
nullptr, // No post data
|
||||
nullptr, // No headers data
|
||||
@ -6133,22 +6270,22 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal, int32_t aDel
|
||||
{
|
||||
NS_ENSURE_ARG(aURI);
|
||||
|
||||
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
|
||||
RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
|
||||
|
||||
/* We do need to pass in a referrer, but we don't want it to
|
||||
* be sent to the server.
|
||||
*/
|
||||
loadState->SetSendReferrer(false);
|
||||
loadInfo->SetSendReferrer(false);
|
||||
|
||||
/* for most refreshes the current URI is an appropriate
|
||||
* internal referrer
|
||||
*/
|
||||
loadState->SetReferrer(mCurrentURI);
|
||||
loadInfo->SetReferrer(mCurrentURI);
|
||||
|
||||
loadState->SetOriginalURI(mCurrentURI);
|
||||
loadState->SetResultPrincipalURI(aURI);
|
||||
loadState->SetResultPrincipalURIIsSome(true);
|
||||
loadState->SetKeepResultPrincipalURIIfSet(true);
|
||||
loadInfo->SetOriginalURI(mCurrentURI);
|
||||
loadInfo->SetResultPrincipalURI(aURI);
|
||||
loadInfo->SetResultPrincipalURIIsSome(true);
|
||||
loadInfo->SetKeepResultPrincipalURIIfSet(true);
|
||||
|
||||
// Set the triggering pricipal to aPrincipal if available, or current
|
||||
// document's principal otherwise.
|
||||
@ -6160,8 +6297,8 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal, int32_t aDel
|
||||
}
|
||||
principal = doc->NodePrincipal();
|
||||
}
|
||||
loadState->SetTriggeringPrincipal(principal);
|
||||
loadState->SetPrincipalIsExplicit(true);
|
||||
loadInfo->SetTriggeringPrincipal(principal);
|
||||
loadInfo->SetPrincipalIsExplicit(true);
|
||||
|
||||
/* Check if this META refresh causes a redirection
|
||||
* to another site.
|
||||
@ -6174,7 +6311,7 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal, int32_t aDel
|
||||
* we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
|
||||
* Pass a REPLACE flag to LoadURI().
|
||||
*/
|
||||
loadState->SetLoadType(LOAD_NORMAL_REPLACE);
|
||||
loadInfo->SetLoadType(LOAD_NORMAL_REPLACE);
|
||||
|
||||
/* for redirects we mimic HTTP, which passes the
|
||||
* original referrer
|
||||
@ -6182,21 +6319,17 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal, int32_t aDel
|
||||
nsCOMPtr<nsIURI> internalReferrer;
|
||||
GetReferringURI(getter_AddRefs(internalReferrer));
|
||||
if (internalReferrer) {
|
||||
loadState->SetReferrer(internalReferrer);
|
||||
loadInfo->SetReferrer(internalReferrer);
|
||||
}
|
||||
} else {
|
||||
loadState->SetLoadType(LOAD_REFRESH);
|
||||
loadInfo->SetLoadType(LOAD_REFRESH);
|
||||
}
|
||||
|
||||
loadState->SetURI(aURI);
|
||||
loadState->SetLoadFlags(nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL);
|
||||
loadState->SetFirstParty(true);
|
||||
|
||||
/*
|
||||
* LoadURI(...) will cancel all refresh timers... This causes the
|
||||
* Timer and its refreshData instance to be released...
|
||||
*/
|
||||
LoadURI(loadState);
|
||||
LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL, true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -8962,7 +9095,7 @@ public:
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsIPrincipal* aPrincipalToInherit,
|
||||
uint32_t aFlags,
|
||||
const nsACString& aTypeHint,
|
||||
const char* aTypeHint,
|
||||
nsIInputStream* aPostData,
|
||||
nsIInputStream* aHeadersData,
|
||||
uint32_t aLoadType,
|
||||
@ -8972,7 +9105,6 @@ public:
|
||||
nsIDocShell* aSourceDocShell,
|
||||
nsIURI* aBaseURI)
|
||||
: mozilla::Runnable("InternalLoadEvent")
|
||||
, mTypeHint(aTypeHint)
|
||||
, mSrcdoc(aSrcdoc)
|
||||
, mDocShell(aDocShell)
|
||||
, mURI(aURI)
|
||||
@ -8993,6 +9125,12 @@ public:
|
||||
, mSourceDocShell(aSourceDocShell)
|
||||
, mBaseURI(aBaseURI)
|
||||
{
|
||||
// Make sure to keep null things null as needed
|
||||
if (aTypeHint) {
|
||||
mTypeHint = aTypeHint;
|
||||
} else {
|
||||
mTypeHint.SetIsVoid(true);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
@ -9005,7 +9143,8 @@ public:
|
||||
mReferrerPolicy,
|
||||
mTriggeringPrincipal, mPrincipalToInherit,
|
||||
mFlags, EmptyString(),
|
||||
mTypeHint,
|
||||
mTypeHint.IsVoid() ? nullptr
|
||||
: mTypeHint.get(),
|
||||
VoidString(), mPostData,
|
||||
mHeadersData, mLoadType, mSHEntry,
|
||||
mFirstParty, mSrcdoc, mSourceDocShell,
|
||||
@ -9076,7 +9215,7 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
||||
nsIPrincipal* aPrincipalToInherit,
|
||||
uint32_t aFlags,
|
||||
const nsAString& aWindowTarget,
|
||||
const nsACString& aTypeHint,
|
||||
const char* aTypeHint,
|
||||
const nsAString& aFileName,
|
||||
nsIInputStream* aPostData,
|
||||
nsIInputStream* aHeadersData,
|
||||
@ -9357,31 +9496,31 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
||||
MOZ_ASSERT(!aSHEntry);
|
||||
MOZ_ASSERT(aFirstParty); // Windowwatcher will assume this.
|
||||
|
||||
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
|
||||
RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
|
||||
|
||||
// Set up our loadinfo so it will do the load as much like we would have
|
||||
// as possible.
|
||||
loadState->SetReferrer(aReferrer);
|
||||
loadState->SetReferrerPolicy((mozilla::net::ReferrerPolicy)aReferrerPolicy);
|
||||
loadState->SetSendReferrer(!(aFlags &
|
||||
loadInfo->SetReferrer(aReferrer);
|
||||
loadInfo->SetReferrerPolicy((mozilla::net::ReferrerPolicy)aReferrerPolicy);
|
||||
loadInfo->SetSendReferrer(!(aFlags &
|
||||
INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
|
||||
loadState->SetOriginalURI(aOriginalURI);
|
||||
loadState->SetMaybeResultPrincipalURI(aResultPrincipalURI);
|
||||
loadState->SetKeepResultPrincipalURIIfSet(aKeepResultPrincipalURIIfSet);
|
||||
loadState->SetLoadReplace(aLoadReplace);
|
||||
loadState->SetTriggeringPrincipal(aTriggeringPrincipal);
|
||||
loadState->SetInheritPrincipal(
|
||||
loadInfo->SetOriginalURI(aOriginalURI);
|
||||
loadInfo->SetMaybeResultPrincipalURI(aResultPrincipalURI);
|
||||
loadInfo->SetKeepResultPrincipalURIIfSet(aKeepResultPrincipalURIIfSet);
|
||||
loadInfo->SetLoadReplace(aLoadReplace);
|
||||
loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
|
||||
loadInfo->SetInheritPrincipal(
|
||||
aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
|
||||
// Explicit principal because we do not want any guesses as to what the
|
||||
// principal to inherit is: it should be aTriggeringPrincipal.
|
||||
loadState->SetPrincipalIsExplicit(true);
|
||||
loadState->SetLoadType(LOAD_LINK);
|
||||
loadState->SetForceAllowDataURI(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI);
|
||||
loadInfo->SetPrincipalIsExplicit(true);
|
||||
loadInfo->SetLoadType(LOAD_LINK);
|
||||
loadInfo->SetForceAllowDataURI(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI);
|
||||
|
||||
rv = win->Open(NS_ConvertUTF8toUTF16(spec),
|
||||
aWindowTarget, // window name
|
||||
EmptyString(), // Features
|
||||
loadState,
|
||||
loadInfo,
|
||||
true, // aForceNoOpener
|
||||
getter_AddRefs(newWin));
|
||||
MOZ_ASSERT(!newWin);
|
||||
@ -10192,7 +10331,7 @@ nsDocShell::DoURILoad(nsIURI* aURI,
|
||||
uint32_t aReferrerPolicy,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsIPrincipal* aPrincipalToInherit,
|
||||
const nsACString& aTypeHint,
|
||||
const char* aTypeHint,
|
||||
const nsAString& aFileName,
|
||||
nsIInputStream* aPostData,
|
||||
nsIInputStream* aHeadersData,
|
||||
@ -10541,8 +10680,8 @@ nsDocShell::DoURILoad(nsIURI* aURI,
|
||||
loadInfo->SetResultPrincipalURI(aResultPrincipalURI.ref());
|
||||
}
|
||||
|
||||
if (!aTypeHint.IsVoid()) {
|
||||
channel->SetContentType(aTypeHint);
|
||||
if (aTypeHint && *aTypeHint) {
|
||||
channel->SetContentType(nsDependentCString(aTypeHint));
|
||||
mContentTypeHint = aTypeHint;
|
||||
} else {
|
||||
mContentTypeHint.Truncate();
|
||||
@ -12096,7 +12235,7 @@ nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType)
|
||||
principalToInherit,
|
||||
flags,
|
||||
EmptyString(), // No window target
|
||||
contentType, // Type hint
|
||||
contentType.get(), // Type hint
|
||||
VoidString(), // No forced file download
|
||||
postData, // Post data stream
|
||||
nullptr, // No headers stream
|
||||
@ -13284,7 +13423,7 @@ nsDocShell::OnLinkClickSync(nsIContent* aContent,
|
||||
aContent->NodePrincipal(),
|
||||
flags,
|
||||
target, // Window target
|
||||
NS_LossyConvertUTF16toASCII(typeHint),
|
||||
NS_LossyConvertUTF16toASCII(typeHint).get(),
|
||||
aFileName, // Download as file
|
||||
aPostDataStream, // Post data stream
|
||||
aHeadersDataStream, // Headers stream
|
||||
|
@ -534,7 +534,7 @@ private: // member functions
|
||||
uint32_t aReferrerPolicy,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsIPrincipal* aPrincipalToInherit,
|
||||
const nsACString& aTypeHint,
|
||||
const char* aTypeHint,
|
||||
const nsAString& aFileName,
|
||||
nsIInputStream* aPostData,
|
||||
nsIInputStream* aHeadersData,
|
||||
@ -905,14 +905,6 @@ private: // member functions
|
||||
return mCSSErrorReportingEnabled;
|
||||
}
|
||||
|
||||
// Handles retrieval of subframe session history for nsDocShell::LoadURI. If a
|
||||
// load is requested in a subframe of the current DocShell, the subframe
|
||||
// loadType may need to reflect the loadType of the parent document, or in
|
||||
// some cases (like reloads), the history load may need to be cancelled. See
|
||||
// function comments for in-depth logic descriptions.
|
||||
void
|
||||
MaybeHandleSubframeHistory(nsDocShellLoadState* aLoadState);
|
||||
|
||||
private: // data members
|
||||
static nsIURIFixup* sURIFixup;
|
||||
|
||||
|
318
docshell/base/nsDocShellLoadInfo.cpp
Normal file
318
docshell/base/nsDocShellLoadInfo.cpp
Normal file
@ -0,0 +1,318 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=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/. */
|
||||
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
#include "nsISHEntry.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
||||
} // mozilla
|
||||
|
||||
nsDocShellLoadInfo::nsDocShellLoadInfo()
|
||||
: mResultPrincipalURIIsSome(false)
|
||||
, mKeepResultPrincipalURIIfSet(false)
|
||||
, mLoadReplace(false)
|
||||
, mInheritPrincipal(false)
|
||||
, mPrincipalIsExplicit(false)
|
||||
, mForceAllowDataURI(false)
|
||||
, mOriginalFrameSrc(false)
|
||||
, mSendReferrer(true)
|
||||
, mReferrerPolicy(mozilla::net::RP_Unset)
|
||||
, mLoadType(LOAD_NORMAL)
|
||||
, mIsSrcdocLoad(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsDocShellLoadInfo::~nsDocShellLoadInfo()
|
||||
{
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
nsDocShellLoadInfo::Referrer() const
|
||||
{
|
||||
return mReferrer;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetReferrer(nsIURI* aReferrer)
|
||||
{
|
||||
mReferrer = aReferrer;
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
nsDocShellLoadInfo::OriginalURI() const
|
||||
{
|
||||
return mOriginalURI;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetOriginalURI(nsIURI* aOriginalURI)
|
||||
{
|
||||
mOriginalURI = aOriginalURI;
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
nsDocShellLoadInfo::ResultPrincipalURI() const
|
||||
{
|
||||
return mResultPrincipalURI;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetResultPrincipalURI(nsIURI* aResultPrincipalURI)
|
||||
{
|
||||
mResultPrincipalURI = aResultPrincipalURI;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadInfo::ResultPrincipalURIIsSome() const
|
||||
{
|
||||
return mResultPrincipalURIIsSome;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetResultPrincipalURIIsSome(bool aIsSome)
|
||||
{
|
||||
mResultPrincipalURIIsSome = aIsSome;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadInfo::KeepResultPrincipalURIIfSet() const
|
||||
{
|
||||
return mKeepResultPrincipalURIIfSet;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetKeepResultPrincipalURIIfSet(bool aKeep)
|
||||
{
|
||||
mKeepResultPrincipalURIIfSet = aKeep;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadInfo::LoadReplace() const
|
||||
{
|
||||
return mLoadReplace;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetLoadReplace(bool aLoadReplace)
|
||||
{
|
||||
mLoadReplace = aLoadReplace;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
nsDocShellLoadInfo::TriggeringPrincipal() const
|
||||
{
|
||||
return mTriggeringPrincipal;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal)
|
||||
{
|
||||
mTriggeringPrincipal = aTriggeringPrincipal;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadInfo::InheritPrincipal() const
|
||||
{
|
||||
return mInheritPrincipal;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetInheritPrincipal(bool aInheritPrincipal)
|
||||
{
|
||||
mInheritPrincipal = aInheritPrincipal;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadInfo::PrincipalIsExplicit() const
|
||||
{
|
||||
return mPrincipalIsExplicit;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetPrincipalIsExplicit(bool aPrincipalIsExplicit)
|
||||
{
|
||||
mPrincipalIsExplicit = aPrincipalIsExplicit;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadInfo::ForceAllowDataURI() const
|
||||
{
|
||||
return mForceAllowDataURI;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetForceAllowDataURI(bool aForceAllowDataURI)
|
||||
{
|
||||
mForceAllowDataURI = aForceAllowDataURI;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadInfo::OriginalFrameSrc() const
|
||||
{
|
||||
return mOriginalFrameSrc;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetOriginalFrameSrc(bool aOriginalFrameSrc)
|
||||
{
|
||||
mOriginalFrameSrc = aOriginalFrameSrc;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsDocShellLoadInfo::LoadType() const
|
||||
{
|
||||
return mLoadType;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetLoadType(uint32_t aLoadType)
|
||||
{
|
||||
mLoadType = aLoadType;
|
||||
}
|
||||
|
||||
nsISHEntry*
|
||||
nsDocShellLoadInfo::SHEntry() const
|
||||
{
|
||||
return mSHEntry;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetSHEntry(nsISHEntry* aSHEntry)
|
||||
{
|
||||
mSHEntry = aSHEntry;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::GetTarget(nsAString& aTarget) const
|
||||
{
|
||||
aTarget = mTarget;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetTarget(const nsAString& aTarget)
|
||||
{
|
||||
mTarget = aTarget;
|
||||
}
|
||||
|
||||
nsIInputStream*
|
||||
nsDocShellLoadInfo::PostDataStream() const
|
||||
{
|
||||
return mPostDataStream;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetPostDataStream(nsIInputStream* aStream)
|
||||
{
|
||||
mPostDataStream = aStream;
|
||||
}
|
||||
|
||||
nsIInputStream*
|
||||
nsDocShellLoadInfo::HeadersStream() const
|
||||
{
|
||||
return mHeadersStream;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetHeadersStream(nsIInputStream* aHeadersStream)
|
||||
{
|
||||
mHeadersStream = aHeadersStream;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadInfo::SendReferrer() const
|
||||
{
|
||||
return mSendReferrer;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetSendReferrer(bool aSendReferrer)
|
||||
{
|
||||
mSendReferrer = aSendReferrer;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsDocShellLoadInfo::ReferrerPolicy() const
|
||||
{
|
||||
return mReferrerPolicy;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetReferrerPolicy(mozilla::net::ReferrerPolicy aReferrerPolicy)
|
||||
{
|
||||
mReferrerPolicy = aReferrerPolicy;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadInfo::IsSrcdocLoad() const
|
||||
{
|
||||
return mIsSrcdocLoad;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::GetSrcdocData(nsAString& aSrcdocData) const
|
||||
{
|
||||
aSrcdocData = mSrcdocData;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetSrcdocData(const nsAString& aSrcdocData)
|
||||
{
|
||||
mSrcdocData = aSrcdocData;
|
||||
mIsSrcdocLoad = true;
|
||||
}
|
||||
|
||||
nsIDocShell*
|
||||
nsDocShellLoadInfo::SourceDocShell() const
|
||||
{
|
||||
return mSourceDocShell;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetSourceDocShell(nsIDocShell* aSourceDocShell)
|
||||
{
|
||||
mSourceDocShell = aSourceDocShell;
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
nsDocShellLoadInfo::BaseURI() const
|
||||
{
|
||||
return mBaseURI;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetBaseURI(nsIURI* aBaseURI)
|
||||
{
|
||||
mBaseURI = aBaseURI;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::GetMaybeResultPrincipalURI(mozilla::Maybe<nsCOMPtr<nsIURI>>& aRPURI) const
|
||||
{
|
||||
bool isSome = ResultPrincipalURIIsSome();
|
||||
aRPURI.reset();
|
||||
|
||||
if (!isSome) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = ResultPrincipalURI();
|
||||
aRPURI.emplace(std::move(uri));
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadInfo::SetMaybeResultPrincipalURI(mozilla::Maybe<nsCOMPtr<nsIURI>> const& aRPURI)
|
||||
{
|
||||
SetResultPrincipalURI(aRPURI.refOr(nullptr));
|
||||
SetResultPrincipalURIIsSome(aRPURI.isSome());
|
||||
}
|
@ -4,8 +4,8 @@
|
||||
* 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/. */
|
||||
|
||||
#ifndef nsDocShellLoadState_h__
|
||||
#define nsDocShellLoadState_h__
|
||||
#ifndef nsDocShellLoadInfo_h__
|
||||
#define nsDocShellLoadInfo_h__
|
||||
|
||||
// Helper Classes
|
||||
#include "nsCOMPtr.h"
|
||||
@ -17,29 +17,22 @@ class nsIInputStream;
|
||||
class nsISHEntry;
|
||||
class nsIURI;
|
||||
class nsIDocShell;
|
||||
class OriginAttibutes;
|
||||
|
||||
/**
|
||||
* nsDocShellLoadState contains setup information used in a nsIDocShell::loadURI
|
||||
* nsDocShellLoadInfo contains setup information used in a nsIDocShell::loadURI
|
||||
* call.
|
||||
*/
|
||||
class nsDocShellLoadState final
|
||||
class nsDocShellLoadInfo
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(nsDocShellLoadState);
|
||||
NS_INLINE_DECL_REFCOUNTING(nsDocShellLoadInfo);
|
||||
|
||||
nsDocShellLoadState();
|
||||
|
||||
// Getters and Setters
|
||||
nsDocShellLoadInfo();
|
||||
|
||||
nsIURI* Referrer() const;
|
||||
|
||||
void SetReferrer(nsIURI* aReferrer);
|
||||
|
||||
nsIURI* URI() const;
|
||||
|
||||
void SetURI(nsIURI* aURI);
|
||||
|
||||
nsIURI* OriginalURI() const;
|
||||
|
||||
void SetOriginalURI(nsIURI* aOriginalURI);
|
||||
@ -56,10 +49,6 @@ public:
|
||||
|
||||
void SetKeepResultPrincipalURIIfSet(bool aKeep);
|
||||
|
||||
nsIPrincipal* PrincipalToInherit() const;
|
||||
|
||||
void SetPrincipalToInherit(nsIPrincipal* aPrincipalToInherit);
|
||||
|
||||
bool LoadReplace() const;
|
||||
|
||||
void SetLoadReplace(bool aLoadReplace);
|
||||
@ -92,7 +81,7 @@ public:
|
||||
|
||||
void SetSHEntry(nsISHEntry* aSHEntry);
|
||||
|
||||
const nsString& Target() const;
|
||||
void GetTarget(nsAString& aTarget) const;
|
||||
|
||||
void SetTarget(const nsAString& aTarget);
|
||||
|
||||
@ -114,7 +103,7 @@ public:
|
||||
|
||||
bool IsSrcdocLoad() const;
|
||||
|
||||
const nsString& SrcdocData() const;
|
||||
void GetSrcdocData(nsAString& aSrcdocData) const;
|
||||
|
||||
void SetSrcdocData(const nsAString& aSrcdocData);
|
||||
|
||||
@ -134,54 +123,13 @@ public:
|
||||
void
|
||||
SetMaybeResultPrincipalURI(mozilla::Maybe<nsCOMPtr<nsIURI>> const& aRPURI);
|
||||
|
||||
uint32_t LoadFlags() const;
|
||||
|
||||
void SetLoadFlags(uint32_t aFlags);
|
||||
|
||||
bool FirstParty() const;
|
||||
|
||||
void SetFirstParty(bool aFirstParty);
|
||||
|
||||
const nsCString& TypeHint() const;
|
||||
|
||||
void SetTypeHint(const nsCString& aTypeHint);
|
||||
|
||||
const nsString& FileName() const;
|
||||
|
||||
void SetFileName(const nsAString& aFileName);
|
||||
|
||||
uint32_t DocShellInternalLoadFlags() const;
|
||||
|
||||
void SetDocShellInternalLoadFlags(uint32_t aFlags);
|
||||
|
||||
// Give the type of DocShell we're loading into (chrome/content/etc) and
|
||||
// origin attributes for the URI we're loading, figure out if we should
|
||||
// inherit our principal from the document the load was requested from, or
|
||||
// else if the principal should be set up later in the process (after loads).
|
||||
// See comments in function for more info on principal selection algorithm
|
||||
nsresult SetupInheritingPrincipal(uint32_t aItemType, const mozilla::OriginAttributes& aOriginAttributes);
|
||||
|
||||
// If no triggering principal exists at the moment, create one using referrer
|
||||
// information and origin attributes.
|
||||
nsresult SetupTriggeringPrincipal(const mozilla::OriginAttributes& aOriginAttributes);
|
||||
|
||||
// When loading a document through nsDocShell::LoadURI(), a special set of
|
||||
// flags needs to be set based on other values in nsDocShellLoadState. This
|
||||
// function calculates those flags, before the LoadState is passed to
|
||||
// nsDocShell::InternalLoad.
|
||||
void CalculateDocShellInternalLoadFlags();
|
||||
protected:
|
||||
// Destructor can't be defaulted or inlined, as header doesn't have all type
|
||||
// includes it needs to do so.
|
||||
~nsDocShellLoadState();
|
||||
virtual ~nsDocShellLoadInfo();
|
||||
|
||||
protected:
|
||||
// This is the referrer for the load.
|
||||
nsCOMPtr<nsIURI> mReferrer;
|
||||
|
||||
// The URI we are navigating to. Will not be null once set.
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
|
||||
// The originalURI to be passed to nsIDocShell.internalLoad. May be null.
|
||||
nsCOMPtr<nsIURI> mOriginalURI;
|
||||
|
||||
@ -214,12 +162,6 @@ protected:
|
||||
// for a content docshell the load fails.
|
||||
bool mPrincipalIsExplicit;
|
||||
|
||||
// Principal we're inheriting. If null, this means the principal should be
|
||||
// inherited from the current document. If set to NullPrincipal, the channel
|
||||
// will fill in principal information later in the load. See internal function
|
||||
// comments for more info.
|
||||
nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
|
||||
|
||||
// If this attribute is true, then a top-level navigation
|
||||
// to a data URI will be allowed.
|
||||
bool mForceAllowDataURI;
|
||||
@ -267,27 +209,6 @@ protected:
|
||||
// Used for srcdoc loads to give view-source knowledge of the load's base URI
|
||||
// as this information isn't embedded in the load's URI.
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
|
||||
// Set of Load Flags, taken from nsDocShellLoadTypes.h
|
||||
uint32_t mLoadFlags;
|
||||
|
||||
// Is this a First Party Load?
|
||||
bool mFirstParty;
|
||||
|
||||
// A hint as to the content-type of the resulting data. If no hint, IsVoid()
|
||||
// should return true.
|
||||
nsCString mTypeHint;
|
||||
|
||||
// Non-void when the link should be downloaded as the given filename.
|
||||
// mFileName being non-void but empty means that no filename hint was
|
||||
// specified, but link should still trigger a download. If not a download,
|
||||
// mFileName.IsVoid() should return true.
|
||||
nsString mFileName;
|
||||
|
||||
// LoadFlags calculated in nsDocShell::LoadURI and passed to
|
||||
// nsDocShell::InternalLoad, taken from the INTERNAL_LOAD consts in
|
||||
// nsIDocShell.idl
|
||||
uint32_t mDocShellInternalLoadFlags;
|
||||
};
|
||||
|
||||
#endif /* nsDocShellLoadState_h__ */
|
||||
#endif /* nsDocShellLoadInfo_h__ */
|
@ -1,554 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=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/. */
|
||||
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
|
||||
#include "mozilla/OriginAttributes.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
|
||||
nsDocShellLoadState::nsDocShellLoadState()
|
||||
: mResultPrincipalURIIsSome(false)
|
||||
, mKeepResultPrincipalURIIfSet(false)
|
||||
, mLoadReplace(false)
|
||||
, mInheritPrincipal(false)
|
||||
, mPrincipalIsExplicit(false)
|
||||
, mForceAllowDataURI(false)
|
||||
, mOriginalFrameSrc(false)
|
||||
, mSendReferrer(true)
|
||||
, mReferrerPolicy(mozilla::net::RP_Unset)
|
||||
, mLoadType(LOAD_NORMAL)
|
||||
, mIsSrcdocLoad(false)
|
||||
, mLoadFlags(0)
|
||||
, mFirstParty(false)
|
||||
, mTypeHint(VoidCString())
|
||||
, mFileName(VoidString())
|
||||
, mDocShellInternalLoadFlags(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsDocShellLoadState::~nsDocShellLoadState()
|
||||
{
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
nsDocShellLoadState::Referrer() const
|
||||
{
|
||||
return mReferrer;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetReferrer(nsIURI* aReferrer)
|
||||
{
|
||||
mReferrer = aReferrer;
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
nsDocShellLoadState::URI() const
|
||||
{
|
||||
return mURI;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetURI(nsIURI* aURI)
|
||||
{
|
||||
mURI = aURI;
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
nsDocShellLoadState::OriginalURI() const
|
||||
{
|
||||
return mOriginalURI;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetOriginalURI(nsIURI* aOriginalURI)
|
||||
{
|
||||
mOriginalURI = aOriginalURI;
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
nsDocShellLoadState::ResultPrincipalURI() const
|
||||
{
|
||||
return mResultPrincipalURI;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetResultPrincipalURI(nsIURI* aResultPrincipalURI)
|
||||
{
|
||||
mResultPrincipalURI = aResultPrincipalURI;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadState::ResultPrincipalURIIsSome() const
|
||||
{
|
||||
return mResultPrincipalURIIsSome;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetResultPrincipalURIIsSome(bool aIsSome)
|
||||
{
|
||||
mResultPrincipalURIIsSome = aIsSome;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadState::KeepResultPrincipalURIIfSet() const
|
||||
{
|
||||
return mKeepResultPrincipalURIIfSet;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetKeepResultPrincipalURIIfSet(bool aKeep)
|
||||
{
|
||||
mKeepResultPrincipalURIIfSet = aKeep;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadState::LoadReplace() const
|
||||
{
|
||||
return mLoadReplace;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetLoadReplace(bool aLoadReplace)
|
||||
{
|
||||
mLoadReplace = aLoadReplace;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
nsDocShellLoadState::TriggeringPrincipal() const
|
||||
{
|
||||
return mTriggeringPrincipal;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal)
|
||||
{
|
||||
mTriggeringPrincipal = aTriggeringPrincipal;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
nsDocShellLoadState::PrincipalToInherit() const
|
||||
{
|
||||
return mPrincipalToInherit;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetPrincipalToInherit(nsIPrincipal* aPrincipalToInherit)
|
||||
{
|
||||
mPrincipalToInherit = aPrincipalToInherit;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadState::InheritPrincipal() const
|
||||
{
|
||||
return mInheritPrincipal;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetInheritPrincipal(bool aInheritPrincipal)
|
||||
{
|
||||
mInheritPrincipal = aInheritPrincipal;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadState::PrincipalIsExplicit() const
|
||||
{
|
||||
return mPrincipalIsExplicit;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetPrincipalIsExplicit(bool aPrincipalIsExplicit)
|
||||
{
|
||||
mPrincipalIsExplicit = aPrincipalIsExplicit;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadState::ForceAllowDataURI() const
|
||||
{
|
||||
return mForceAllowDataURI;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetForceAllowDataURI(bool aForceAllowDataURI)
|
||||
{
|
||||
mForceAllowDataURI = aForceAllowDataURI;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadState::OriginalFrameSrc() const
|
||||
{
|
||||
return mOriginalFrameSrc;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetOriginalFrameSrc(bool aOriginalFrameSrc)
|
||||
{
|
||||
mOriginalFrameSrc = aOriginalFrameSrc;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsDocShellLoadState::LoadType() const
|
||||
{
|
||||
return mLoadType;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetLoadType(uint32_t aLoadType)
|
||||
{
|
||||
mLoadType = aLoadType;
|
||||
}
|
||||
|
||||
nsISHEntry*
|
||||
nsDocShellLoadState::SHEntry() const
|
||||
{
|
||||
return mSHEntry;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetSHEntry(nsISHEntry* aSHEntry)
|
||||
{
|
||||
mSHEntry = aSHEntry;
|
||||
}
|
||||
|
||||
const nsString&
|
||||
nsDocShellLoadState::Target() const
|
||||
{
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetTarget(const nsAString& aTarget)
|
||||
{
|
||||
mTarget = aTarget;
|
||||
}
|
||||
|
||||
nsIInputStream*
|
||||
nsDocShellLoadState::PostDataStream() const
|
||||
{
|
||||
return mPostDataStream;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetPostDataStream(nsIInputStream* aStream)
|
||||
{
|
||||
mPostDataStream = aStream;
|
||||
}
|
||||
|
||||
nsIInputStream*
|
||||
nsDocShellLoadState::HeadersStream() const
|
||||
{
|
||||
return mHeadersStream;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetHeadersStream(nsIInputStream* aHeadersStream)
|
||||
{
|
||||
mHeadersStream = aHeadersStream;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadState::SendReferrer() const
|
||||
{
|
||||
return mSendReferrer;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetSendReferrer(bool aSendReferrer)
|
||||
{
|
||||
mSendReferrer = aSendReferrer;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsDocShellLoadState::ReferrerPolicy() const
|
||||
{
|
||||
return mReferrerPolicy;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetReferrerPolicy(mozilla::net::ReferrerPolicy aReferrerPolicy)
|
||||
{
|
||||
mReferrerPolicy = aReferrerPolicy;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadState::IsSrcdocLoad() const
|
||||
{
|
||||
return mIsSrcdocLoad;
|
||||
}
|
||||
|
||||
const nsString&
|
||||
nsDocShellLoadState::SrcdocData() const
|
||||
{
|
||||
return mSrcdocData;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetSrcdocData(const nsAString& aSrcdocData)
|
||||
{
|
||||
mSrcdocData = aSrcdocData;
|
||||
mIsSrcdocLoad = true;
|
||||
}
|
||||
|
||||
nsIDocShell*
|
||||
nsDocShellLoadState::SourceDocShell() const
|
||||
{
|
||||
return mSourceDocShell;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetSourceDocShell(nsIDocShell* aSourceDocShell)
|
||||
{
|
||||
mSourceDocShell = aSourceDocShell;
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
nsDocShellLoadState::BaseURI() const
|
||||
{
|
||||
return mBaseURI;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetBaseURI(nsIURI* aBaseURI)
|
||||
{
|
||||
mBaseURI = aBaseURI;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::GetMaybeResultPrincipalURI(mozilla::Maybe<nsCOMPtr<nsIURI>>& aRPURI) const
|
||||
{
|
||||
bool isSome = ResultPrincipalURIIsSome();
|
||||
aRPURI.reset();
|
||||
|
||||
if (!isSome) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = ResultPrincipalURI();
|
||||
aRPURI.emplace(std::move(uri));
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetMaybeResultPrincipalURI(mozilla::Maybe<nsCOMPtr<nsIURI>> const& aRPURI)
|
||||
{
|
||||
SetResultPrincipalURI(aRPURI.refOr(nullptr));
|
||||
SetResultPrincipalURIIsSome(aRPURI.isSome());
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsDocShellLoadState::LoadFlags() const
|
||||
{
|
||||
return mLoadFlags;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetLoadFlags(uint32_t aLoadFlags)
|
||||
{
|
||||
mLoadFlags = aLoadFlags;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShellLoadState::FirstParty() const
|
||||
{
|
||||
return mFirstParty;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetFirstParty(bool aFirstParty)
|
||||
{
|
||||
mFirstParty = aFirstParty;
|
||||
}
|
||||
|
||||
const nsCString&
|
||||
nsDocShellLoadState::TypeHint() const
|
||||
{
|
||||
return mTypeHint;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetTypeHint(const nsCString& aTypeHint)
|
||||
{
|
||||
mTypeHint = aTypeHint;
|
||||
}
|
||||
|
||||
const nsString&
|
||||
nsDocShellLoadState::FileName() const
|
||||
{
|
||||
return mFileName;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetFileName(const nsAString& aFileName)
|
||||
{
|
||||
mFileName = aFileName;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsDocShellLoadState::DocShellInternalLoadFlags() const
|
||||
{
|
||||
return mDocShellInternalLoadFlags;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::SetDocShellInternalLoadFlags(uint32_t aFlags)
|
||||
{
|
||||
mDocShellInternalLoadFlags = aFlags;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDocShellLoadState::SetupInheritingPrincipal(uint32_t aItemType,
|
||||
const mozilla::OriginAttributes& aOriginAttributes)
|
||||
{
|
||||
// We need a principalToInherit.
|
||||
//
|
||||
// If principalIsExplicit is not set there are 4 possibilities:
|
||||
// (1) If the system principal or an expanded principal was passed
|
||||
// in and we're a typeContent docshell, inherit the principal
|
||||
// from the current document instead.
|
||||
// (2) In all other cases when the principal passed in is not null,
|
||||
// use that principal.
|
||||
// (3) If the caller has allowed inheriting from the current document,
|
||||
// or if we're being called from system code (eg chrome JS or pure
|
||||
// C++) then inheritPrincipal should be true and InternalLoad will get
|
||||
// a principal from the current document. If none of these things are
|
||||
// true, then
|
||||
// (4) we don't pass a principal into the channel, and a principal will be
|
||||
// created later from the channel's internal data.
|
||||
//
|
||||
// If principalIsExplicit *is* set, there are 4 possibilities
|
||||
// (1) If the system principal or an expanded principal was passed in
|
||||
// and we're a typeContent docshell, return an error.
|
||||
// (2) In all other cases when the principal passed in is not null,
|
||||
// use that principal.
|
||||
// (3) If the caller has allowed inheriting from the current document,
|
||||
// then inheritPrincipal should be true and InternalLoad will get
|
||||
// a principal from the current document. If none of these things are
|
||||
// true, then
|
||||
// (4) we dont' pass a principal into the channel, and a principal will be
|
||||
// created later from the channel's internal data.
|
||||
mPrincipalToInherit = mTriggeringPrincipal;
|
||||
if (mPrincipalToInherit && aItemType != nsIDocShellTreeItem::typeChrome) {
|
||||
if (nsContentUtils::IsSystemPrincipal(mPrincipalToInherit)) {
|
||||
if (mPrincipalIsExplicit) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
mPrincipalToInherit = nullptr;
|
||||
mInheritPrincipal = true;
|
||||
} else if (nsContentUtils::IsExpandedPrincipal(mPrincipalToInherit)) {
|
||||
if (mPrincipalIsExplicit) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
// Don't inherit from the current page. Just do the safe thing
|
||||
// and pretend that we were loaded by a nullprincipal.
|
||||
//
|
||||
// We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't
|
||||
// have origin attributes.
|
||||
mPrincipalToInherit =
|
||||
NullPrincipal::CreateWithInheritedAttributes(aOriginAttributes,
|
||||
false);
|
||||
mInheritPrincipal = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mPrincipalToInherit && !mInheritPrincipal && !mPrincipalIsExplicit) {
|
||||
// See if there's system or chrome JS code running
|
||||
mInheritPrincipal = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
|
||||
}
|
||||
|
||||
if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL) {
|
||||
mInheritPrincipal = false;
|
||||
// If mFirstParty is true and the pref 'privacy.firstparty.isolate' is
|
||||
// enabled, we will set firstPartyDomain on the origin attributes.
|
||||
mPrincipalToInherit =
|
||||
NullPrincipal::CreateWithInheritedAttributes(aOriginAttributes,
|
||||
mFirstParty);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocShellLoadState::SetupTriggeringPrincipal(const mozilla::OriginAttributes& aOriginAttributes)
|
||||
{
|
||||
// If the triggeringPrincipal is not set, we first try to create a principal
|
||||
// from the referrer, since the referrer URI reflects the web origin that
|
||||
// triggered the load. If there is no referrer URI, we fall back to using the
|
||||
// SystemPrincipal. It's safe to assume that no provided triggeringPrincipal
|
||||
// and no referrer simulate a load that was triggered by the system. It's
|
||||
// important to note that this block of code needs to appear *after* the block
|
||||
// where we munge the principalToInherit, because otherwise we would never
|
||||
// enter code blocks checking if the principalToInherit is null and we will
|
||||
// end up with a wrong inheritPrincipal flag.
|
||||
if (!mTriggeringPrincipal) {
|
||||
if (mReferrer) {
|
||||
mTriggeringPrincipal =
|
||||
BasePrincipal::CreateCodebasePrincipal(mReferrer, aOriginAttributes);
|
||||
|
||||
if (!mTriggeringPrincipal) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
mTriggeringPrincipal = nsContentUtils::GetSystemPrincipal();
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShellLoadState::CalculateDocShellInternalLoadFlags()
|
||||
{
|
||||
MOZ_ASSERT(mDocShellInternalLoadFlags == 0,
|
||||
"Shouldn't have any load flags set at this point.");
|
||||
|
||||
if (mInheritPrincipal) {
|
||||
MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(mPrincipalToInherit),
|
||||
"Should not inherit SystemPrincipal");
|
||||
mDocShellInternalLoadFlags |=
|
||||
nsIDocShell::INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
|
||||
}
|
||||
|
||||
if (!mSendReferrer) {
|
||||
mDocShellInternalLoadFlags |=
|
||||
nsIDocShell::INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
|
||||
}
|
||||
|
||||
if (mDocShellInternalLoadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
|
||||
mDocShellInternalLoadFlags |=
|
||||
nsIDocShell::INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
|
||||
}
|
||||
|
||||
if (mDocShellInternalLoadFlags & nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) {
|
||||
mDocShellInternalLoadFlags |= nsIDocShell::INTERNAL_LOAD_FLAGS_FIRST_LOAD;
|
||||
}
|
||||
|
||||
if (mDocShellInternalLoadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CLASSIFIER) {
|
||||
mDocShellInternalLoadFlags |=
|
||||
nsIDocShell::INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
|
||||
}
|
||||
|
||||
if (mDocShellInternalLoadFlags & nsIWebNavigation::LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
|
||||
mDocShellInternalLoadFlags |=
|
||||
nsIDocShell::INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
|
||||
}
|
||||
|
||||
if (mIsSrcdocLoad) {
|
||||
mDocShellInternalLoadFlags |= nsIDocShell::INTERNAL_LOAD_FLAGS_IS_SRCDOC;
|
||||
}
|
||||
|
||||
if (mForceAllowDataURI) {
|
||||
mDocShellInternalLoadFlags |=
|
||||
nsIDocShell::INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
|
||||
}
|
||||
|
||||
if (mOriginalFrameSrc) {
|
||||
mDocShellInternalLoadFlags |=
|
||||
nsIDocShell::INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC;
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "nsDOMNavigationTiming.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
|
||||
/**
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "nsIURI.h"
|
||||
class nsPresContext;
|
||||
class nsIPresShell;
|
||||
class nsDocShellLoadState;
|
||||
class nsDocShellLoadInfo;
|
||||
namespace mozilla {
|
||||
class Encoding;
|
||||
class HTMLEditor;
|
||||
@ -63,7 +63,7 @@ interface nsICommandManager;
|
||||
interface nsICommandParams;
|
||||
interface nsILoadURIDelegate;
|
||||
native TabChildRef(already_AddRefed<nsITabChild>);
|
||||
native nsDocShellLoadStatePtr(nsDocShellLoadState*);
|
||||
native nsDocShellLoadInfoPtr(nsDocShellLoadInfo*);
|
||||
|
||||
webidl BrowsingContext;
|
||||
webidl ContentFrameMessageManager;
|
||||
@ -78,9 +78,23 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
* however, the URL dispatcher will go through its normal process of content
|
||||
* loading.
|
||||
*
|
||||
* @param loadState - This is the extended load info for this load.
|
||||
* @param uri - The URI to load.
|
||||
* @param loadInfo - This is the extended load info for this load. This
|
||||
* most often will be null, but if you need to do
|
||||
* additional setup for this load you can get a loadInfo
|
||||
* object by calling createLoadInfo. Once you have this
|
||||
* object you can set the needed properties on it and
|
||||
* then pass it to loadURI.
|
||||
* @param aLoadFlags - Flags to modify load behaviour. Flags are defined in
|
||||
* nsIWebNavigation. Note that using flags outside
|
||||
* LOAD_FLAGS_MASK is only allowed if passing in a
|
||||
* non-null loadInfo. And even some of those might not
|
||||
* be allowed. Use at your own risk.
|
||||
*/
|
||||
[noscript]void loadURI(in nsDocShellLoadStatePtr loadState);
|
||||
[noscript]void loadURI(in nsIURI uri,
|
||||
in nsDocShellLoadInfoPtr loadInfo,
|
||||
in unsigned long aLoadFlags,
|
||||
in boolean firstParty);
|
||||
|
||||
const long INTERNAL_LOAD_FLAGS_NONE = 0x0;
|
||||
const long INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL = 0x1;
|
||||
@ -91,12 +105,6 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
// @see nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD
|
||||
const long INTERNAL_LOAD_FLAGS_FIRST_LOAD = 0x8;
|
||||
|
||||
|
||||
// The set of flags that should not be set before calling into
|
||||
// nsDocShell::LoadURI and other nsDocShell loading functions.
|
||||
const long INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS = 0xf;
|
||||
|
||||
|
||||
const long INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER = 0x10;
|
||||
const long INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES = 0x20;
|
||||
|
||||
@ -190,7 +198,7 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
in nsIPrincipal aPrincipalToInherit,
|
||||
in uint32_t aFlags,
|
||||
in AString aWindowTarget,
|
||||
in ACString aTypeHint,
|
||||
in string aTypeHint,
|
||||
in AString aFileName,
|
||||
in nsIInputStream aPostDataStream,
|
||||
in nsIInputStream aHeadersStream,
|
||||
|
@ -9,8 +9,8 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "nsDocShellEditorData.h"
|
||||
#include "nsDocShellLoadTypes.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsILayoutHistoryState.h"
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "nsDocShell.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsILayoutHistoryState.h"
|
||||
#include "nsIObserverService.h"
|
||||
@ -1575,7 +1575,7 @@ nsSHistory::InitiateLoad(nsISHEntry* aFrameEntry, nsIDocShell* aFrameDS,
|
||||
{
|
||||
NS_ENSURE_STATE(aFrameDS && aFrameEntry);
|
||||
|
||||
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
|
||||
RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
|
||||
|
||||
/* Set the loadType in the SHEntry too to what was passed on.
|
||||
* This will be passed on to child subframes later in nsDocShell,
|
||||
@ -1583,21 +1583,19 @@ nsSHistory::InitiateLoad(nsISHEntry* aFrameEntry, nsIDocShell* aFrameDS,
|
||||
*/
|
||||
aFrameEntry->SetLoadType(aLoadType);
|
||||
|
||||
loadState->SetLoadType(aLoadType);
|
||||
loadState->SetSHEntry(aFrameEntry);
|
||||
loadInfo->SetLoadType(aLoadType);
|
||||
loadInfo->SetSHEntry(aFrameEntry);
|
||||
|
||||
nsCOMPtr<nsIURI> originalURI = aFrameEntry->GetOriginalURI();
|
||||
loadState->SetOriginalURI(originalURI);
|
||||
loadInfo->SetOriginalURI(originalURI);
|
||||
|
||||
loadState->SetLoadReplace(aFrameEntry->GetLoadReplace());
|
||||
|
||||
nsCOMPtr<nsIURI> newURI = aFrameEntry->GetURI();
|
||||
loadState->SetURI(newURI);
|
||||
loadState->SetLoadFlags(nsIWebNavigation::LOAD_FLAGS_NONE);
|
||||
loadState->SetFirstParty(false);
|
||||
loadInfo->SetLoadReplace(aFrameEntry->GetLoadReplace());
|
||||
|
||||
nsCOMPtr<nsIURI> nextURI = aFrameEntry->GetURI();
|
||||
// Time to initiate a document load
|
||||
return aFrameDS->LoadURI(loadState);
|
||||
return aFrameDS->LoadURI(nextURI, loadInfo,
|
||||
nsIWebNavigation::LOAD_FLAGS_NONE, false);
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
|
@ -37,7 +37,7 @@ test(function(t) {
|
||||
interpolated_matrix,
|
||||
'the expected matrix from interpolatematrix(' +
|
||||
'translateX(100px), rotate(90deg), 0.5) to none at 50%');
|
||||
}, 'Test interpolation from interpolatmatrix to none at 50%');
|
||||
}, 'Test interpolation from interpolatematrix to none at 50%');
|
||||
|
||||
</script>
|
||||
</html>
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsCDefaultURIFixup.h"
|
||||
#include "nsIURIFixup.h"
|
||||
@ -61,7 +61,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Location, mInnerWindow)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(Location)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(Location)
|
||||
|
||||
already_AddRefed<nsDocShellLoadState>
|
||||
already_AddRefed<nsDocShellLoadInfo>
|
||||
Location::CheckURL(nsIURI* aURI, nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
@ -152,16 +152,16 @@ Location::CheckURL(nsIURI* aURI, nsIPrincipal& aSubjectPrincipal,
|
||||
}
|
||||
|
||||
// Create load info
|
||||
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
|
||||
RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
|
||||
|
||||
loadState->SetTriggeringPrincipal(triggeringPrincipal);
|
||||
loadInfo->SetTriggeringPrincipal(triggeringPrincipal);
|
||||
|
||||
if (sourceURI) {
|
||||
loadState->SetReferrer(sourceURI);
|
||||
loadState->SetReferrerPolicy(referrerPolicy);
|
||||
loadInfo->SetReferrer(sourceURI);
|
||||
loadInfo->SetReferrerPolicy(referrerPolicy);
|
||||
}
|
||||
|
||||
return loadState.forget();
|
||||
return loadInfo.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -212,31 +212,27 @@ Location::SetURI(nsIURI* aURI, nsIPrincipal& aSubjectPrincipal,
|
||||
{
|
||||
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
|
||||
if (docShell) {
|
||||
|
||||
RefPtr<nsDocShellLoadState> loadState =
|
||||
RefPtr<nsDocShellLoadInfo> loadInfo =
|
||||
CheckURL(aURI, aSubjectPrincipal, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aReplace) {
|
||||
loadState->SetLoadType(LOAD_STOP_CONTENT_AND_REPLACE);
|
||||
loadInfo->SetLoadType(LOAD_STOP_CONTENT_AND_REPLACE);
|
||||
} else {
|
||||
loadState->SetLoadType(LOAD_STOP_CONTENT);
|
||||
loadInfo->SetLoadType(LOAD_STOP_CONTENT);
|
||||
}
|
||||
|
||||
// Get the incumbent script's browsing context to set as source.
|
||||
nsCOMPtr<nsPIDOMWindowInner> sourceWindow =
|
||||
do_QueryInterface(mozilla::dom::GetIncumbentGlobal());
|
||||
if (sourceWindow) {
|
||||
loadState->SetSourceDocShell(sourceWindow->GetDocShell());
|
||||
loadInfo->SetSourceDocShell(sourceWindow->GetDocShell());
|
||||
}
|
||||
|
||||
loadState->SetURI(aURI);
|
||||
loadState->SetLoadFlags(nsIWebNavigation::LOAD_FLAGS_NONE);
|
||||
loadState->SetFirstParty(true);
|
||||
|
||||
nsresult rv = docShell->LoadURI(loadState);
|
||||
nsresult rv = docShell->LoadURI(aURI, loadInfo,
|
||||
nsIWebNavigation::LOAD_FLAGS_NONE, true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
class nsIDocShell;
|
||||
class nsIURI;
|
||||
class nsDocShellLoadState;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -168,7 +167,6 @@ protected:
|
||||
// Note, this method can return NS_OK with a null value for aURL. This happens
|
||||
// if the docShell is null.
|
||||
nsresult GetURI(nsIURI** aURL, bool aGetInnermostURI = false);
|
||||
|
||||
void SetURI(nsIURI* aURL, nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv, bool aReplace = false);
|
||||
void SetHrefWithBase(const nsAString& aHref, nsIURI* aBase,
|
||||
@ -186,7 +184,7 @@ protected:
|
||||
// Check whether it's OK to load the given url with the given subject
|
||||
// principal, and if so construct the right nsDocShellLoadInfo for the load
|
||||
// and return it.
|
||||
already_AddRefed<nsDocShellLoadState> CheckURL(nsIURI *url,
|
||||
already_AddRefed<nsDocShellLoadInfo> CheckURL(nsIURI *url,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv);
|
||||
|
||||
|
@ -258,6 +258,7 @@
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
#ifdef MOZ_XUL
|
||||
#include "mozilla/dom/XULBroadcastManager.h"
|
||||
#include "mozilla/dom/TreeBoxObject.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsXULCommandDispatcher.h"
|
||||
@ -1745,6 +1746,10 @@ nsDocument::~nsDocument()
|
||||
mStyleImageLoader->DropDocumentReference();
|
||||
}
|
||||
|
||||
if (mXULBroadcastManager) {
|
||||
mXULBroadcastManager->DropDocumentReference();
|
||||
}
|
||||
|
||||
delete mHeaderData;
|
||||
|
||||
ClearAllBoxObjects();
|
||||
@ -5113,6 +5118,9 @@ nsDocument::EndUpdate()
|
||||
MaybeEndOutermostXBLUpdate();
|
||||
|
||||
MaybeInitializeFinalizeFrameLoaders();
|
||||
if (mXULBroadcastManager) {
|
||||
mXULBroadcastManager->MaybeBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -10247,6 +10255,15 @@ nsIDocument::GetCommandDispatcher()
|
||||
return mCommandDispatcher;
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::InitializeXULBroadcastManager()
|
||||
{
|
||||
if (mXULBroadcastManager) {
|
||||
return;
|
||||
}
|
||||
mXULBroadcastManager = new XULBroadcastManager(this);
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
GetScopeObjectOfNode(nsINode* node)
|
||||
{
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "nsIWebProgress.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeOwner.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIBrowser.h"
|
||||
#include "nsContentUtils.h"
|
||||
@ -390,9 +390,9 @@ nsFrameLoader::ReallyStartLoadingInternal()
|
||||
rv = CheckURILoad(mURIToLoad, mTriggeringPrincipal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
|
||||
RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
|
||||
|
||||
loadState->SetOriginalFrameSrc(mLoadingOriginalSrc);
|
||||
loadInfo->SetOriginalFrameSrc(mLoadingOriginalSrc);
|
||||
mLoadingOriginalSrc = false;
|
||||
|
||||
// If this frame is sandboxed with respect to origin we will set it up with
|
||||
@ -403,9 +403,9 @@ nsFrameLoader::ReallyStartLoadingInternal()
|
||||
// is very important; needed to prevent XSS attacks on documents loaded in
|
||||
// subframes!
|
||||
if (mTriggeringPrincipal) {
|
||||
loadState->SetTriggeringPrincipal(mTriggeringPrincipal);
|
||||
loadInfo->SetTriggeringPrincipal(mTriggeringPrincipal);
|
||||
} else {
|
||||
loadState->SetTriggeringPrincipal(mOwnerContent->NodePrincipal());
|
||||
loadInfo->SetTriggeringPrincipal(mOwnerContent->NodePrincipal());
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> referrer;
|
||||
@ -420,9 +420,9 @@ nsFrameLoader::ReallyStartLoadingInternal()
|
||||
mOwnerContent->OwnerDoc()->GetReferrer(referrerStr);
|
||||
rv = NS_NewURI(getter_AddRefs(referrer), referrerStr);
|
||||
|
||||
loadState->SetSrcdocData(srcdoc);
|
||||
loadInfo->SetSrcdocData(srcdoc);
|
||||
nsCOMPtr<nsIURI> baseURI = mOwnerContent->GetBaseURI();
|
||||
loadState->SetBaseURI(baseURI);
|
||||
loadInfo->SetBaseURI(baseURI);
|
||||
}
|
||||
else {
|
||||
rv = mOwnerContent->NodePrincipal()->GetURI(getter_AddRefs(referrer));
|
||||
@ -437,7 +437,7 @@ nsFrameLoader::ReallyStartLoadingInternal()
|
||||
bool isNullPrincipalScheme;
|
||||
rv = referrer->SchemeIs(NS_NULLPRINCIPAL_SCHEME, &isNullPrincipalScheme);
|
||||
if (NS_SUCCEEDED(rv) && !isNullPrincipalScheme) {
|
||||
loadState->SetReferrer(referrer);
|
||||
loadInfo->SetReferrer(referrer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -453,7 +453,7 @@ nsFrameLoader::ReallyStartLoadingInternal()
|
||||
referrerPolicy = iframeReferrerPolicy;
|
||||
}
|
||||
}
|
||||
loadState->SetReferrerPolicy(referrerPolicy);
|
||||
loadInfo->SetReferrerPolicy(referrerPolicy);
|
||||
|
||||
// Default flags:
|
||||
int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE;
|
||||
@ -467,10 +467,8 @@ nsFrameLoader::ReallyStartLoadingInternal()
|
||||
// Kick off the load...
|
||||
bool tmpState = mNeedsAsyncDestroy;
|
||||
mNeedsAsyncDestroy = true;
|
||||
loadState->SetURI(mURIToLoad);
|
||||
loadState->SetLoadFlags(flags);
|
||||
loadState->SetFirstParty(false);
|
||||
rv = mDocShell->LoadURI(loadState);
|
||||
nsCOMPtr<nsIURI> uriToLoad = mURIToLoad;
|
||||
rv = mDocShell->LoadURI(uriToLoad, loadInfo, flags, false);
|
||||
mNeedsAsyncDestroy = tmpState;
|
||||
mURIToLoad = nullptr;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -65,7 +65,7 @@
|
||||
#include "nsPrintfCString.h"
|
||||
#include "mozilla/intl/LocaleService.h"
|
||||
#include "WindowDestroyedEvent.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
|
||||
// Helper Classes
|
||||
#include "nsJSUtils.h"
|
||||
@ -5520,7 +5520,7 @@ nsGlobalWindowOuter::OpenOuter(const nsAString& aUrl, const nsAString& aName,
|
||||
|
||||
nsresult
|
||||
nsGlobalWindowOuter::Open(const nsAString& aUrl, const nsAString& aName,
|
||||
const nsAString& aOptions, nsDocShellLoadState* aLoadState,
|
||||
const nsAString& aOptions, nsDocShellLoadInfo* aLoadInfo,
|
||||
bool aForceNoOpener, nsPIDOMWindowOuter **_retval)
|
||||
{
|
||||
return OpenInternal(aUrl, aName, aOptions,
|
||||
@ -5530,7 +5530,7 @@ nsGlobalWindowOuter::Open(const nsAString& aUrl, const nsAString& aName,
|
||||
false, // aDoJSFixups
|
||||
true, // aNavigate
|
||||
nullptr, nullptr, // No args
|
||||
aLoadState,
|
||||
aLoadInfo,
|
||||
aForceNoOpener,
|
||||
_retval);
|
||||
}
|
||||
@ -5546,7 +5546,7 @@ nsGlobalWindowOuter::OpenJS(const nsAString& aUrl, const nsAString& aName,
|
||||
true, // aDoJSFixups
|
||||
true, // aNavigate
|
||||
nullptr, nullptr, // No args
|
||||
nullptr, // aLoadState
|
||||
nullptr, // aLoadInfo
|
||||
false, // aForceNoOpener
|
||||
_retval);
|
||||
}
|
||||
@ -5566,7 +5566,7 @@ nsGlobalWindowOuter::OpenDialog(const nsAString& aUrl, const nsAString& aName,
|
||||
false, // aDoJSFixups
|
||||
true, // aNavigate
|
||||
nullptr, aExtraArgument, // Arguments
|
||||
nullptr, // aLoadState
|
||||
nullptr, // aLoadInfo
|
||||
false, // aForceNoOpener
|
||||
_retval);
|
||||
}
|
||||
@ -5585,7 +5585,7 @@ nsGlobalWindowOuter::OpenNoNavigate(const nsAString& aUrl,
|
||||
false, // aDoJSFixups
|
||||
false, // aNavigate
|
||||
nullptr, nullptr, // No args
|
||||
nullptr, // aLoadState
|
||||
nullptr, // aLoadInfo
|
||||
false, // aForceNoOpener
|
||||
_retval);
|
||||
|
||||
@ -5613,7 +5613,7 @@ nsGlobalWindowOuter::OpenDialogOuter(JSContext* aCx, const nsAString& aUrl,
|
||||
false, // aDoJSFixups
|
||||
true, // aNavigate
|
||||
argvArray, nullptr, // Arguments
|
||||
nullptr, // aLoadState
|
||||
nullptr, // aLoadInfo
|
||||
false, // aForceNoOpener
|
||||
getter_AddRefs(dialog));
|
||||
return dialog.forget();
|
||||
@ -6937,7 +6937,7 @@ nsGlobalWindowOuter::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
||||
bool aDoJSFixups, bool aNavigate,
|
||||
nsIArray *argv,
|
||||
nsISupports *aExtraArgument,
|
||||
nsDocShellLoadState* aLoadState,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
bool aForceNoOpener,
|
||||
nsPIDOMWindowOuter **aReturn)
|
||||
{
|
||||
@ -7086,7 +7086,7 @@ nsGlobalWindowOuter::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
||||
aDialog, aNavigate, argv,
|
||||
isPopupSpamWindow,
|
||||
forceNoOpener,
|
||||
aLoadState,
|
||||
aLoadInfo,
|
||||
getter_AddRefs(domReturn));
|
||||
} else {
|
||||
// Force a system caller here so that the window watcher won't screw us
|
||||
@ -7109,7 +7109,7 @@ nsGlobalWindowOuter::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
||||
aDialog, aNavigate, aExtraArgument,
|
||||
isPopupSpamWindow,
|
||||
forceNoOpener,
|
||||
aLoadState,
|
||||
aLoadInfo,
|
||||
getter_AddRefs(domReturn));
|
||||
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ class nsITimeoutHandler;
|
||||
class nsIWebBrowserChrome;
|
||||
class mozIDOMWindowProxy;
|
||||
|
||||
class nsDocShellLoadState;
|
||||
class nsDocShellLoadInfo;
|
||||
class nsDOMWindowList;
|
||||
class nsScreen;
|
||||
class nsHistory;
|
||||
@ -607,7 +607,7 @@ public:
|
||||
mozilla::ErrorResult& aError);
|
||||
nsresult Open(const nsAString& aUrl, const nsAString& aName,
|
||||
const nsAString& aOptions,
|
||||
nsDocShellLoadState* aLoadState,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
bool aForceNoOpener,
|
||||
nsPIDOMWindowOuter **_retval) override;
|
||||
mozilla::dom::Navigator* GetNavigator() override;
|
||||
@ -879,7 +879,7 @@ private:
|
||||
* @param aExtraArgument Another way to pass arguments in. This is mutually
|
||||
* exclusive with the argv approach.
|
||||
*
|
||||
* @param aLoadState to be passed on along to the windowwatcher.
|
||||
* @param aLoadInfo to be passed on along to the windowwatcher.
|
||||
*
|
||||
* @param aForceNoOpener if true, will act as if "noopener" were passed in
|
||||
* aOptions, but without affecting any other window
|
||||
@ -901,7 +901,7 @@ private:
|
||||
bool aNavigate,
|
||||
nsIArray *argv,
|
||||
nsISupports *aExtraArgument,
|
||||
nsDocShellLoadState* aLoadState,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
bool aForceNoOpener,
|
||||
nsPIDOMWindowOuter **aReturn);
|
||||
|
||||
|
@ -148,6 +148,7 @@ class Animation;
|
||||
class AnonymousContent;
|
||||
class Attr;
|
||||
class BoxObject;
|
||||
class XULBroadcastManager;
|
||||
class ClientInfo;
|
||||
class ClientState;
|
||||
class CDATASection;
|
||||
@ -3442,6 +3443,15 @@ public:
|
||||
mozilla::dom::Promise* GetDocumentReadyForIdle(mozilla::ErrorResult& aRv);
|
||||
|
||||
nsIDOMXULCommandDispatcher* GetCommandDispatcher();
|
||||
bool HasXULBroadcastManager() const
|
||||
{
|
||||
return mXULBroadcastManager;
|
||||
};
|
||||
void InitializeXULBroadcastManager();
|
||||
mozilla::dom::XULBroadcastManager* GetXULBroadcastManager() const
|
||||
{
|
||||
return mXULBroadcastManager;
|
||||
}
|
||||
already_AddRefed<nsINode> GetPopupNode();
|
||||
void SetPopupNode(nsINode* aNode);
|
||||
nsINode* GetPopupRangeParent(ErrorResult& aRv);
|
||||
@ -4739,6 +4749,8 @@ protected:
|
||||
|
||||
nsCOMPtr<nsIDOMXULCommandDispatcher> mCommandDispatcher; // [OWNER] of the focus tracker
|
||||
|
||||
RefPtr<mozilla::dom::XULBroadcastManager> mXULBroadcastManager;
|
||||
|
||||
// At the moment, trackers might be blocked by Tracking Protection or FastBlock.
|
||||
// In order to know the numbers of trackers detected and blocked, we add
|
||||
// these two values here and those are shared by TP and FB.
|
||||
|
@ -31,7 +31,7 @@ class nsIChannel;
|
||||
class nsIContent;
|
||||
class nsICSSDeclaration;
|
||||
class nsIDocShell;
|
||||
class nsDocShellLoadState;
|
||||
class nsDocShellLoadInfo;
|
||||
class nsIDocument;
|
||||
class nsIPrincipal;
|
||||
class nsIScriptTimeoutHandler;
|
||||
@ -1121,12 +1121,12 @@ public:
|
||||
|
||||
virtual nsDOMWindowList* GetFrames() = 0;
|
||||
|
||||
// aLoadState will be passed on through to the windowwatcher.
|
||||
// aLoadInfo will be passed on through to the windowwatcher.
|
||||
// aForceNoOpener will act just like a "noopener" feature in aOptions except
|
||||
// will not affect any other window features.
|
||||
virtual nsresult Open(const nsAString& aUrl, const nsAString& aName,
|
||||
const nsAString& aOptions,
|
||||
nsDocShellLoadState* aLoadState,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
bool aForceNoOpener,
|
||||
nsPIDOMWindowOuter **_retval) = 0;
|
||||
virtual nsresult OpenDialog(const nsAString& aUrl, const nsAString& aName,
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "ClientState.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsIWebProgress.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
@ -236,16 +236,13 @@ ClientNavigateOpChild::DoNavigate(const ClientNavigateOpConstructorArgs& aArgs)
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
|
||||
RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
|
||||
|
||||
loadState->SetTriggeringPrincipal(principal);
|
||||
loadState->SetReferrerPolicy(doc->GetReferrerPolicy());
|
||||
loadState->SetLoadType(LOAD_STOP_CONTENT);
|
||||
loadState->SetSourceDocShell(docShell);
|
||||
loadState->SetURI(url);
|
||||
loadState->SetLoadFlags(nsIWebNavigation::LOAD_FLAGS_NONE);
|
||||
loadState->SetFirstParty(true);
|
||||
rv = docShell->LoadURI(loadState);
|
||||
loadInfo->SetTriggeringPrincipal(principal);
|
||||
loadInfo->SetReferrerPolicy(doc->GetReferrerPolicy());
|
||||
loadInfo->SetLoadType(LOAD_STOP_CONTENT);
|
||||
loadInfo->SetSourceDocShell(docShell);
|
||||
rv = docShell->LoadURI(url, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true);
|
||||
if (NS_FAILED(rv)) {
|
||||
ref = ClientOpPromise::CreateAndReject(rv, __func__);
|
||||
return ref.forget();
|
||||
|
@ -9,9 +9,12 @@
|
||||
display: flex;
|
||||
background-color: grey;
|
||||
font: 14px sans-serif;
|
||||
width: 800px;
|
||||
height: 50px;
|
||||
}
|
||||
#flex-sanity {
|
||||
/* This just needs to be large enough so that no shrinking is required. */
|
||||
width: 1600px;
|
||||
}
|
||||
|
||||
.base { align-self: baseline; }
|
||||
.lastbase { align-self: last baseline; }
|
||||
@ -23,6 +26,7 @@
|
||||
.yellow { background: yellow; }
|
||||
.orange { background: orange; }
|
||||
.pink { background: pink; }
|
||||
.tan { background: tan; }
|
||||
.white { background: white; }
|
||||
|
||||
.crossMinMax { min-height: 40px;
|
||||
@ -32,6 +36,11 @@
|
||||
max-width: 500px; }
|
||||
|
||||
.flexGrow { flex-grow: 1; }
|
||||
.spacer150 { width: 150px;
|
||||
box-sizing: border-box;
|
||||
height: 10px;
|
||||
border: 1px solid teal; }
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@ -46,10 +55,6 @@ function testItemMatchesExpectedValues(item, values, index) {
|
||||
is(item.node, values.node, "Item index " + index + " has expected node.");
|
||||
}
|
||||
|
||||
if (typeof(values.node_todo) != "undefined") {
|
||||
todo_is(item.node, values.node_todo, "Item index " + index + " has expected node.");
|
||||
}
|
||||
|
||||
if (typeof(values.mainBaseSize) != "undefined") {
|
||||
is(item.mainBaseSize, values.mainBaseSize, "Item index " + index + " has expected mainBaseSize.");
|
||||
}
|
||||
@ -85,8 +90,9 @@ function testItemMatchesExpectedValues(item, values, index) {
|
||||
}
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
let container = document.getElementById("wrapper");
|
||||
// Test for items in "flex-sanity" flex container:
|
||||
function testFlexSanity() {
|
||||
let container = document.getElementById("flex-sanity");
|
||||
let flex = container.getAsFlexContainer();
|
||||
let lines = flex.getLines();
|
||||
is(lines.length, 1, "Container should have expected number of lines.");
|
||||
@ -118,7 +124,7 @@ function runTests() {
|
||||
|
||||
let expectedValues = [
|
||||
{ crossMinSize: 0 },
|
||||
{ mainBaseSize: lbElemBoundingRect.width,
|
||||
{ mainBaseSize: 100,
|
||||
mainDeltaSize: 0 },
|
||||
{ crossMinSize: 40,
|
||||
crossMaxSize: 120,
|
||||
@ -126,6 +132,18 @@ function runTests() {
|
||||
{ mainMinSize: 120,
|
||||
mainMaxSize: 500,
|
||||
mainDeltaSize: 0 },
|
||||
{ mainMinSize: 120,
|
||||
mainMaxSize: 500,
|
||||
mainBaseSize: 150,
|
||||
mainDeltaSize: 0 },
|
||||
{ mainBaseSize: 10,
|
||||
mainMaxSize: 5,
|
||||
mainDeltaSize: 0 },
|
||||
{ mainBaseSize: 10,
|
||||
mainMinSize: 15,
|
||||
mainDeltaSize: 0 },
|
||||
{ mainBaseSize: 50,
|
||||
mainMaxSize: 10 },
|
||||
{ mainDeltaSize: 0 },
|
||||
{ /* final item is anonymous flex item */ },
|
||||
];
|
||||
@ -161,22 +179,127 @@ function runTests() {
|
||||
// actual size minus the base size.
|
||||
isfuzzy(items[0].mainDeltaSize, firstRect.width - items[0].mainBaseSize, 1e-4,
|
||||
"flex-grow item should have expected mainDeltaSize.");
|
||||
}
|
||||
|
||||
// Test for items in "flex-growing" flex container:
|
||||
function testFlexGrowing() {
|
||||
let expectedValues = [
|
||||
{ mainBaseSize: 10,
|
||||
mainDeltaSize: 10,
|
||||
mainMinSize: 35 },
|
||||
{ mainBaseSize: 20,
|
||||
mainDeltaSize: 5,
|
||||
mainMinSize: 28 },
|
||||
{ mainBaseSize: 30,
|
||||
mainDeltaSize: 7 },
|
||||
{ mainBaseSize: 0,
|
||||
mainDeltaSize: 48,
|
||||
mainMaxSize: 20 },
|
||||
];
|
||||
|
||||
let container = document.getElementById("flex-growing");
|
||||
let items = container.getAsFlexContainer().getLines()[0].getItems();
|
||||
is(items.length, container.children.length,
|
||||
"Line should have as many items as the flex container has child elems");
|
||||
|
||||
for (let i = 0; i < items.length; ++i) {
|
||||
let item = items[i];
|
||||
let values = expectedValues[i];
|
||||
testItemMatchesExpectedValues(item, values, i);
|
||||
}
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
testFlexSanity();
|
||||
testFlexGrowing();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onLoad="runTests();">
|
||||
<div id="wrapper" class="container">
|
||||
<!-- First flex container to be tested: "flex-sanity".
|
||||
We test a few general things, e.g.:
|
||||
- accuracy of reported baselines.
|
||||
- accuracy of reported flex base size, min/max sizes, & trivial deltas.
|
||||
- flex items formation for display:contents subtrees & text nodes.
|
||||
-->
|
||||
<div id="flex-sanity" class="container">
|
||||
<div class="lime base flexGrow">one line (first)</div>
|
||||
<div class="yellow lastbase" style="width: 100px">one line (last)</div>
|
||||
<div class="orange offset lastbase crossMinMax">two<br/>lines and offset (last)</div>
|
||||
<div class="pink offset base mainMinMax">offset (first)</div>
|
||||
<!-- Inflexible item w/ content-derived flex base size, which has min/max
|
||||
but doesn't violate them: -->
|
||||
<div class="tan mainMinMax">
|
||||
<div class="spacer150"></div>
|
||||
</div>
|
||||
<!-- Inflexible item that is trivially clamped to smaller max-width: -->
|
||||
<div style="flex: 0 0 10px; max-width: 5px"></div>
|
||||
<!-- Inflexible item that is trivially clamped to larger min-width: -->
|
||||
<div style="flex: 0 0 10px; min-width: 15px"></div>
|
||||
<!-- Item that wants to grow but is trivially clamped to max-width
|
||||
below base size: -->
|
||||
<div style="flex: 1 1 50px; max-width: 10px"></div>
|
||||
<div style="display:contents">
|
||||
<div class="white">replaced</div>
|
||||
</div>
|
||||
anonymous text node
|
||||
anon item for text
|
||||
</div>
|
||||
|
||||
<!-- Second flex container to be tested, with items that grow by specific
|
||||
predictable amounts. This ends up triggering 4 passes of the main
|
||||
flexbox layout algorithm loop - and note that for each item, we only
|
||||
report (via 'mainDeltaSize') the delta that it wanted in the *last pass
|
||||
of the loop before that item was frozen*.
|
||||
|
||||
Here's what goes on in each pass (and the tentative deltas)
|
||||
* PASS 1
|
||||
- Available space = 120 - 10 - 20 - 30 - 0 = 60px.
|
||||
- Sum of flex values = 1+1+2+16 = 20. So 1 "share" is 60px/20 = 3px.
|
||||
- Deltas (space distributed): +3px, +3px, +6px, +48px
|
||||
VIOLATIONS:
|
||||
item0 is now 10+3 = 13px, which under its min
|
||||
item1 is now 20+3 = 23px, which under its min
|
||||
item3 is now 0+48 = 48px, which over its max
|
||||
- the magnitude of max-violations (how far we're out of bounds) exceeds
|
||||
magnitude of min-violations, so we prioritize the max-violations.
|
||||
- So we freeze item3 at its max-width, 20px, leaving its final "desired"
|
||||
mainDeltaSize at +48px from this pass.
|
||||
|
||||
* PASS 2
|
||||
- Available space = 120 - 10 - 20 - 30 - 20 = 40px.
|
||||
- Sum of flex values = 1+1+2 = 4. So 1 "share" is 40px/4 = 10px.
|
||||
- Deltas (space distributed): +10px, +10px, +20px, +0px.
|
||||
VIOLATIONS:
|
||||
item0 is now 10+10 = 20px, which is under its min
|
||||
- So we freeze item0 at its min-width, 35px, leaving its final "desired"
|
||||
mainDeltaSize at +10px from this pass.
|
||||
|
||||
* PASS 3
|
||||
- Available space = 120 - 35 - 20 - 30 - 20 = 15px.
|
||||
- Sum of flex values = 1+2 = 3. So 1 "share" is 15px/3 = 5px.
|
||||
- Deltas (space distributed): +0px, +5px, +10px, +0px.
|
||||
VIOLATIONS:
|
||||
item1 is now 20+5 = 25px, which is under its min
|
||||
- So we freeze item1 at its min-width, 28px, leaving its final "desired"
|
||||
mainDeltaSize at +5px from this pass.
|
||||
|
||||
* PASS 4
|
||||
- Available space = 120 - 35 - 28 - 30 - 20 = 7px.
|
||||
- Sum of flex values = 2. So 1 "share" is 7px/2 = 3.5px
|
||||
- Deltas (space distributed): +0px, +0px, +7px, +0px.
|
||||
VIOLATIONS:
|
||||
None! (So, we'll be done after this pass!)
|
||||
- So we freeze item2 (the only unfrozen item) at its flexed size, 37px,
|
||||
and set its final "desired" mainDeltaSize to +7px from this pass.
|
||||
- And we're done!
|
||||
-->
|
||||
<div id="flex-growing" class="container" style="width: 120px">
|
||||
<div style="flex: 1 10px; min-width: 35px"></div>
|
||||
<div style="flex: 1 20px; min-width: 28px"></div>
|
||||
<div style="flex: 2 30px; min-width: 0"></div>
|
||||
<div style="flex: 16 0px; max-width: 20px"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -119,7 +119,7 @@
|
||||
|
||||
#include "mozInlineSpellChecker.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
#include "nsIConsoleListener.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsICycleCollectorListener.h"
|
||||
@ -774,19 +774,19 @@ ContentChild::ProvideWindow(mozIDOMWindowProxy* aParent,
|
||||
const nsAString& aName,
|
||||
const nsACString& aFeatures,
|
||||
bool aForceNoOpener,
|
||||
nsDocShellLoadState* aLoadState,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
bool* aWindowIsNew,
|
||||
mozIDOMWindowProxy** aReturn)
|
||||
{
|
||||
return ProvideWindowCommon(nullptr, aParent, false, aChromeFlags,
|
||||
aCalledFromJS, aPositionSpecified,
|
||||
aSizeSpecified, aURI, aName, aFeatures,
|
||||
aForceNoOpener, aLoadState, aWindowIsNew, aReturn);
|
||||
aForceNoOpener, aLoadInfo, aWindowIsNew, aReturn);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
GetCreateWindowParams(mozIDOMWindowProxy* aParent,
|
||||
nsDocShellLoadState* aLoadState,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
nsACString& aBaseURIString, float* aFullZoom,
|
||||
uint32_t* aReferrerPolicy,
|
||||
nsIPrincipal** aTriggeringPrincipal)
|
||||
@ -814,11 +814,11 @@ GetCreateWindowParams(mozIDOMWindowProxy* aParent,
|
||||
|
||||
baseURI->GetSpec(aBaseURIString);
|
||||
|
||||
if (aLoadState) {
|
||||
if (!aLoadState->SendReferrer()) {
|
||||
if (aLoadInfo) {
|
||||
if (!aLoadInfo->SendReferrer()) {
|
||||
*aReferrerPolicy = mozilla::net::RP_No_Referrer;
|
||||
} else {
|
||||
*aReferrerPolicy = aLoadState->ReferrerPolicy();
|
||||
*aReferrerPolicy = aLoadInfo->ReferrerPolicy();
|
||||
}
|
||||
}
|
||||
|
||||
@ -849,7 +849,7 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
||||
const nsAString& aName,
|
||||
const nsACString& aFeatures,
|
||||
bool aForceNoOpener,
|
||||
nsDocShellLoadState* aLoadState,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
bool* aWindowIsNew,
|
||||
mozIDOMWindowProxy** aReturn)
|
||||
{
|
||||
@ -896,7 +896,7 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
||||
float fullZoom;
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal;
|
||||
uint32_t referrerPolicy = mozilla::net::RP_Unset;
|
||||
rv = GetCreateWindowParams(aParent, aLoadState, baseURIString, &fullZoom,
|
||||
rv = GetCreateWindowParams(aParent, aLoadInfo, baseURIString, &fullZoom,
|
||||
&referrerPolicy,
|
||||
getter_AddRefs(triggeringPrincipal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -1110,7 +1110,7 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
||||
float fullZoom;
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal;
|
||||
uint32_t referrerPolicy = mozilla::net::RP_Unset;
|
||||
rv = GetCreateWindowParams(aParent, aLoadState, baseURIString, &fullZoom,
|
||||
rv = GetCreateWindowParams(aParent, aLoadInfo, baseURIString, &fullZoom,
|
||||
&referrerPolicy,
|
||||
getter_AddRefs(triggeringPrincipal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -34,7 +34,7 @@ struct OverrideMapping;
|
||||
class nsIDomainPolicy;
|
||||
class nsIURIClassifierCallback;
|
||||
struct LookAndFeelInt;
|
||||
class nsDocShellLoadState;
|
||||
class nsDocShellLoadInfo;
|
||||
|
||||
namespace mozilla {
|
||||
class RemoteSpellcheckEngineChild;
|
||||
@ -119,7 +119,7 @@ public:
|
||||
const nsAString& aName,
|
||||
const nsACString& aFeatures,
|
||||
bool aForceNoOpener,
|
||||
nsDocShellLoadState* aLoadState,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
bool* aWindowIsNew,
|
||||
mozIDOMWindowProxy** aReturn);
|
||||
|
||||
|
@ -124,7 +124,7 @@
|
||||
#include "nsString.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
#include "nsWebBrowser.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
@ -960,7 +960,7 @@ TabChild::ProvideWindow(mozIDOMWindowProxy* aParent,
|
||||
bool aPositionSpecified, bool aSizeSpecified,
|
||||
nsIURI* aURI, const nsAString& aName,
|
||||
const nsACString& aFeatures, bool aForceNoOpener,
|
||||
nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
|
||||
nsDocShellLoadInfo* aLoadInfo, bool* aWindowIsNew,
|
||||
mozIDOMWindowProxy** aReturn)
|
||||
{
|
||||
*aReturn = nullptr;
|
||||
@ -1004,7 +1004,7 @@ TabChild::ProvideWindow(mozIDOMWindowProxy* aParent,
|
||||
aName,
|
||||
aFeatures,
|
||||
aForceNoOpener,
|
||||
aLoadState,
|
||||
aLoadInfo,
|
||||
aWindowIsNew,
|
||||
aReturn);
|
||||
}
|
||||
|
614
dom/xul/XULBroadcastManager.cpp
Normal file
614
dom/xul/XULBroadcastManager.cpp
Normal file
@ -0,0 +1,614 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=4 sw=4 et 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/. */
|
||||
|
||||
#include "XULBroadcastManager.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "nsXULElement.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
|
||||
struct BroadcastListener {
|
||||
nsWeakPtr mListener;
|
||||
RefPtr<nsAtom> mAttribute;
|
||||
};
|
||||
|
||||
struct BroadcasterMapEntry : public PLDHashEntryHdr
|
||||
{
|
||||
Element* mBroadcaster; // [WEAK]
|
||||
nsTArray<BroadcastListener*> mListeners; // [OWNING] of BroadcastListener objects
|
||||
};
|
||||
|
||||
struct nsAttrNameInfo
|
||||
{
|
||||
nsAttrNameInfo(int32_t aNamespaceID, nsAtom* aName, nsAtom* aPrefix) :
|
||||
mNamespaceID(aNamespaceID), mName(aName), mPrefix(aPrefix) {}
|
||||
nsAttrNameInfo(const nsAttrNameInfo& aOther) :
|
||||
mNamespaceID(aOther.mNamespaceID), mName(aOther.mName),
|
||||
mPrefix(aOther.mPrefix) {}
|
||||
int32_t mNamespaceID;
|
||||
RefPtr<nsAtom> mName;
|
||||
RefPtr<nsAtom> mPrefix;
|
||||
};
|
||||
|
||||
static void
|
||||
ClearBroadcasterMapEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
|
||||
{
|
||||
BroadcasterMapEntry* entry =
|
||||
static_cast<BroadcasterMapEntry*>(aEntry);
|
||||
for (size_t i = entry->mListeners.Length() - 1; i != (size_t)-1; --i) {
|
||||
delete entry->mListeners[i];
|
||||
}
|
||||
entry->mListeners.Clear();
|
||||
|
||||
// N.B. that we need to manually run the dtor because we
|
||||
// constructed the nsTArray object in-place.
|
||||
entry->mListeners.~nsTArray<BroadcastListener*>();
|
||||
}
|
||||
|
||||
static bool
|
||||
CanBroadcast(int32_t aNameSpaceID, nsAtom* aAttribute)
|
||||
{
|
||||
// Don't push changes to the |id|, |persist|, |command| or
|
||||
// |observes| attribute.
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
if ((aAttribute == nsGkAtoms::id) ||
|
||||
(aAttribute == nsGkAtoms::persist) ||
|
||||
(aAttribute == nsGkAtoms::command) ||
|
||||
(aAttribute == nsGkAtoms::observes)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
static LazyLogModule sXULBroadCastManager("XULBroadcastManager");
|
||||
|
||||
/* static */
|
||||
bool
|
||||
XULBroadcastManager::MayNeedListener(const Element& aElement) {
|
||||
if (aElement.NodeInfo()->Equals(nsGkAtoms::observes, kNameSpaceID_XUL)) {
|
||||
return true;
|
||||
}
|
||||
if (aElement.HasAttr(nsGkAtoms::observes)) {
|
||||
return true;
|
||||
}
|
||||
if (aElement.HasAttr(nsGkAtoms::command) &&
|
||||
!(aElement.NodeInfo()->Equals(nsGkAtoms::menuitem, kNameSpaceID_XUL) ||
|
||||
aElement.NodeInfo()->Equals(nsGkAtoms::key, kNameSpaceID_XUL))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
XULBroadcastManager::XULBroadcastManager(nsIDocument* aDocument)
|
||||
: mDocument(aDocument),
|
||||
mBroadcasterMap(nullptr),
|
||||
mHandlingDelayedAttrChange(false),
|
||||
mHandlingDelayedBroadcasters(false)
|
||||
{
|
||||
}
|
||||
|
||||
XULBroadcastManager::~XULBroadcastManager()
|
||||
{
|
||||
delete mBroadcasterMap;
|
||||
}
|
||||
|
||||
void
|
||||
XULBroadcastManager::DropDocumentReference(void)
|
||||
{
|
||||
mDocument = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
XULBroadcastManager::SynchronizeBroadcastListener(Element *aBroadcaster,
|
||||
Element *aListener,
|
||||
const nsAString &aAttr)
|
||||
{
|
||||
if (!nsContentUtils::IsSafeToRunScript()) {
|
||||
nsDelayedBroadcastUpdate delayedUpdate(aBroadcaster, aListener,
|
||||
aAttr);
|
||||
mDelayedBroadcasters.AppendElement(delayedUpdate);
|
||||
MaybeBroadcast();
|
||||
return;
|
||||
}
|
||||
bool notify = mHandlingDelayedBroadcasters;
|
||||
|
||||
if (aAttr.EqualsLiteral("*")) {
|
||||
uint32_t count = aBroadcaster->GetAttrCount();
|
||||
nsTArray<nsAttrNameInfo> attributes(count);
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
const nsAttrName* attrName = aBroadcaster->GetAttrNameAt(i);
|
||||
int32_t nameSpaceID = attrName->NamespaceID();
|
||||
nsAtom* name = attrName->LocalName();
|
||||
|
||||
// _Don't_ push the |id|, |ref|, or |persist| attribute's value!
|
||||
if (! CanBroadcast(nameSpaceID, name))
|
||||
continue;
|
||||
|
||||
attributes.AppendElement(nsAttrNameInfo(nameSpaceID, name,
|
||||
attrName->GetPrefix()));
|
||||
}
|
||||
|
||||
count = attributes.Length();
|
||||
while (count-- > 0) {
|
||||
int32_t nameSpaceID = attributes[count].mNamespaceID;
|
||||
nsAtom* name = attributes[count].mName;
|
||||
nsAutoString value;
|
||||
if (aBroadcaster->GetAttr(nameSpaceID, name, value)) {
|
||||
aListener->SetAttr(nameSpaceID, name, attributes[count].mPrefix,
|
||||
value, notify);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// XXX we don't fire the |onbroadcast| handler during
|
||||
// initial hookup: doing so would potentially run the
|
||||
// |onbroadcast| handler before the |onload| handler,
|
||||
// which could define JS properties that mask XBL
|
||||
// properties, etc.
|
||||
ExecuteOnBroadcastHandlerFor(aBroadcaster, aListener, name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Find out if the attribute is even present at all.
|
||||
RefPtr<nsAtom> name = NS_Atomize(aAttr);
|
||||
|
||||
nsAutoString value;
|
||||
if (aBroadcaster->GetAttr(kNameSpaceID_None, name, value)) {
|
||||
aListener->SetAttr(kNameSpaceID_None, name, value, notify);
|
||||
} else {
|
||||
aListener->UnsetAttr(kNameSpaceID_None, name, notify);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// XXX we don't fire the |onbroadcast| handler during initial
|
||||
// hookup: doing so would potentially run the |onbroadcast|
|
||||
// handler before the |onload| handler, which could define JS
|
||||
// properties that mask XBL properties, etc.
|
||||
ExecuteOnBroadcastHandlerFor(aBroadcaster, aListener, name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XULBroadcastManager::AddListenerFor(Element& aBroadcaster, Element& aListener,
|
||||
const nsAString& aAttr, ErrorResult& aRv)
|
||||
{
|
||||
if (!mDocument) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv =
|
||||
nsContentUtils::CheckSameOrigin(mDocument, &aBroadcaster);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = nsContentUtils::CheckSameOrigin(mDocument, &aListener);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
static const PLDHashTableOps gOps = {
|
||||
PLDHashTable::HashVoidPtrKeyStub,
|
||||
PLDHashTable::MatchEntryStub,
|
||||
PLDHashTable::MoveEntryStub,
|
||||
ClearBroadcasterMapEntry,
|
||||
nullptr
|
||||
};
|
||||
|
||||
if (! mBroadcasterMap) {
|
||||
mBroadcasterMap = new PLDHashTable(&gOps, sizeof(BroadcasterMapEntry));
|
||||
}
|
||||
|
||||
auto entry = static_cast<BroadcasterMapEntry*>
|
||||
(mBroadcasterMap->Search(&aBroadcaster));
|
||||
if (!entry) {
|
||||
entry = static_cast<BroadcasterMapEntry*>
|
||||
(mBroadcasterMap->Add(&aBroadcaster, fallible));
|
||||
|
||||
if (! entry) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
entry->mBroadcaster = &aBroadcaster;
|
||||
|
||||
// N.B. placement new to construct the nsTArray object in-place
|
||||
new (&entry->mListeners) nsTArray<BroadcastListener*>();
|
||||
}
|
||||
|
||||
// Only add the listener if it's not there already!
|
||||
RefPtr<nsAtom> attr = NS_Atomize(aAttr);
|
||||
|
||||
for (size_t i = entry->mListeners.Length() - 1; i != (size_t)-1; --i) {
|
||||
BroadcastListener* bl = entry->mListeners[i];
|
||||
nsCOMPtr<Element> blListener = do_QueryReferent(bl->mListener);
|
||||
|
||||
if (blListener == &aListener && bl->mAttribute == attr)
|
||||
return;
|
||||
}
|
||||
|
||||
BroadcastListener* bl = new BroadcastListener;
|
||||
bl->mListener = do_GetWeakReference(&aListener);
|
||||
bl->mAttribute = attr;
|
||||
|
||||
entry->mListeners.AppendElement(bl);
|
||||
|
||||
SynchronizeBroadcastListener(&aBroadcaster, &aListener, aAttr);
|
||||
}
|
||||
|
||||
void
|
||||
XULBroadcastManager::RemoveListenerFor(Element& aBroadcaster,
|
||||
Element& aListener,
|
||||
const nsAString& aAttr)
|
||||
{
|
||||
// If we haven't added any broadcast listeners, then there sure
|
||||
// aren't any to remove.
|
||||
if (! mBroadcasterMap)
|
||||
return;
|
||||
|
||||
auto entry = static_cast<BroadcasterMapEntry*>
|
||||
(mBroadcasterMap->Search(&aBroadcaster));
|
||||
if (entry) {
|
||||
RefPtr<nsAtom> attr = NS_Atomize(aAttr);
|
||||
for (size_t i = entry->mListeners.Length() - 1; i != (size_t)-1; --i) {
|
||||
BroadcastListener* bl = entry->mListeners[i];
|
||||
nsCOMPtr<Element> blListener = do_QueryReferent(bl->mListener);
|
||||
|
||||
if (blListener == &aListener && bl->mAttribute == attr) {
|
||||
entry->mListeners.RemoveElementAt(i);
|
||||
delete bl;
|
||||
|
||||
if (entry->mListeners.IsEmpty())
|
||||
mBroadcasterMap->RemoveEntry(entry);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULBroadcastManager::ExecuteOnBroadcastHandlerFor(Element* aBroadcaster,
|
||||
Element* aListener,
|
||||
nsAtom* aAttr)
|
||||
{
|
||||
if (!mDocument) {
|
||||
return NS_OK;
|
||||
}
|
||||
// Now we execute the onchange handler in the context of the
|
||||
// observer. We need to find the observer in order to
|
||||
// execute the handler.
|
||||
|
||||
for (nsIContent* child = aListener->GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
|
||||
// Look for an <observes> element beneath the listener. This
|
||||
// ought to have an |element| attribute that refers to
|
||||
// aBroadcaster, and an |attribute| element that tells us what
|
||||
// attriubtes we're listening for.
|
||||
if (!child->IsXULElement(nsGkAtoms::observes))
|
||||
continue;
|
||||
|
||||
// Is this the element that was listening to us?
|
||||
nsAutoString listeningToID;
|
||||
child->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::element, listeningToID);
|
||||
|
||||
nsAutoString broadcasterID;
|
||||
aBroadcaster->GetAttr(kNameSpaceID_None, nsGkAtoms::id, broadcasterID);
|
||||
|
||||
if (listeningToID != broadcasterID)
|
||||
continue;
|
||||
|
||||
// We are observing the broadcaster, but is this the right
|
||||
// attribute?
|
||||
nsAutoString listeningToAttribute;
|
||||
child->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::attribute,
|
||||
listeningToAttribute);
|
||||
|
||||
if (!aAttr->Equals(listeningToAttribute) &&
|
||||
!listeningToAttribute.EqualsLiteral("*")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is the right <observes> element. Execute the
|
||||
// |onbroadcast| event handler
|
||||
WidgetEvent event(true, eXULBroadcast);
|
||||
|
||||
RefPtr<nsPresContext> presContext = mDocument->GetPresContext();
|
||||
if (presContext) {
|
||||
// Handle the DOM event
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
EventDispatcher::Dispatch(child, presContext, &event, nullptr,
|
||||
&status);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
XULBroadcastManager::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute)
|
||||
{
|
||||
if (!mDocument) {
|
||||
return;
|
||||
}
|
||||
NS_ASSERTION(aElement->OwnerDoc() == mDocument, "unexpected doc");
|
||||
|
||||
// Synchronize broadcast listeners
|
||||
if (mBroadcasterMap &&
|
||||
CanBroadcast(aNameSpaceID, aAttribute)) {
|
||||
auto entry = static_cast<BroadcasterMapEntry*>
|
||||
(mBroadcasterMap->Search(aElement));
|
||||
|
||||
if (entry) {
|
||||
// We've got listeners: push the value.
|
||||
nsAutoString value;
|
||||
bool attrSet = aElement->GetAttr(kNameSpaceID_None, aAttribute, value);
|
||||
|
||||
for (size_t i = entry->mListeners.Length() - 1; i != (size_t)-1; --i) {
|
||||
BroadcastListener* bl = entry->mListeners[i];
|
||||
if ((bl->mAttribute == aAttribute) ||
|
||||
(bl->mAttribute == nsGkAtoms::_asterisk)) {
|
||||
nsCOMPtr<Element> listenerEl
|
||||
= do_QueryReferent(bl->mListener);
|
||||
if (listenerEl) {
|
||||
nsAutoString currentValue;
|
||||
bool hasAttr = listenerEl->GetAttr(kNameSpaceID_None,
|
||||
aAttribute,
|
||||
currentValue);
|
||||
// We need to update listener only if we're
|
||||
// (1) removing an existing attribute,
|
||||
// (2) adding a new attribute or
|
||||
// (3) changing the value of an attribute.
|
||||
bool needsAttrChange =
|
||||
attrSet != hasAttr || !value.Equals(currentValue);
|
||||
nsDelayedBroadcastUpdate delayedUpdate(aElement,
|
||||
listenerEl,
|
||||
aAttribute,
|
||||
value,
|
||||
attrSet,
|
||||
needsAttrChange);
|
||||
|
||||
size_t index =
|
||||
mDelayedAttrChangeBroadcasts.IndexOf(delayedUpdate,
|
||||
0, nsDelayedBroadcastUpdate::Comparator());
|
||||
if (index != mDelayedAttrChangeBroadcasts.NoIndex) {
|
||||
if (mHandlingDelayedAttrChange) {
|
||||
NS_WARNING("Broadcasting loop!");
|
||||
continue;
|
||||
}
|
||||
mDelayedAttrChangeBroadcasts.RemoveElementAt(index);
|
||||
}
|
||||
|
||||
mDelayedAttrChangeBroadcasts.AppendElement(delayedUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XULBroadcastManager::MaybeBroadcast()
|
||||
{
|
||||
// Only broadcast when not in an update and when safe to run scripts.
|
||||
if (mDocument && mDocument->UpdateNestingLevel() == 0 &&
|
||||
(mDelayedAttrChangeBroadcasts.Length() ||
|
||||
mDelayedBroadcasters.Length())) {
|
||||
if (!nsContentUtils::IsSafeToRunScript()) {
|
||||
if (mDocument) {
|
||||
nsContentUtils::AddScriptRunner(
|
||||
NewRunnableMethod("dom::XULBroadcastManager::MaybeBroadcast",
|
||||
this,
|
||||
&XULBroadcastManager::MaybeBroadcast));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!mHandlingDelayedAttrChange) {
|
||||
mHandlingDelayedAttrChange = true;
|
||||
for (uint32_t i = 0; i < mDelayedAttrChangeBroadcasts.Length(); ++i) {
|
||||
nsAtom* attrName = mDelayedAttrChangeBroadcasts[i].mAttrName;
|
||||
if (mDelayedAttrChangeBroadcasts[i].mNeedsAttrChange) {
|
||||
nsCOMPtr<Element> listener = mDelayedAttrChangeBroadcasts[i].mListener;
|
||||
const nsString& value = mDelayedAttrChangeBroadcasts[i].mAttr;
|
||||
if (mDelayedAttrChangeBroadcasts[i].mSetAttr) {
|
||||
listener->SetAttr(kNameSpaceID_None, attrName, value,
|
||||
true);
|
||||
} else {
|
||||
listener->UnsetAttr(kNameSpaceID_None, attrName,
|
||||
true);
|
||||
}
|
||||
}
|
||||
ExecuteOnBroadcastHandlerFor(mDelayedAttrChangeBroadcasts[i].mBroadcaster,
|
||||
mDelayedAttrChangeBroadcasts[i].mListener,
|
||||
attrName);
|
||||
}
|
||||
mDelayedAttrChangeBroadcasts.Clear();
|
||||
mHandlingDelayedAttrChange = false;
|
||||
}
|
||||
|
||||
uint32_t length = mDelayedBroadcasters.Length();
|
||||
if (length) {
|
||||
bool oldValue = mHandlingDelayedBroadcasters;
|
||||
mHandlingDelayedBroadcasters = true;
|
||||
nsTArray<nsDelayedBroadcastUpdate> delayedBroadcasters;
|
||||
mDelayedBroadcasters.SwapElements(delayedBroadcasters);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
SynchronizeBroadcastListener(delayedBroadcasters[i].mBroadcaster,
|
||||
delayedBroadcasters[i].mListener,
|
||||
delayedBroadcasters[i].mAttr);
|
||||
}
|
||||
mHandlingDelayedBroadcasters = oldValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULBroadcastManager::FindBroadcaster(Element* aElement,
|
||||
Element** aListener,
|
||||
nsString& aBroadcasterID,
|
||||
nsString& aAttribute,
|
||||
Element** aBroadcaster)
|
||||
{
|
||||
NodeInfo *ni = aElement->NodeInfo();
|
||||
*aListener = nullptr;
|
||||
*aBroadcaster = nullptr;
|
||||
|
||||
if (ni->Equals(nsGkAtoms::observes, kNameSpaceID_XUL)) {
|
||||
// It's an <observes> element, which means that the actual
|
||||
// listener is the _parent_ node. This element should have an
|
||||
// 'element' attribute that specifies the ID of the
|
||||
// broadcaster element, and an 'attribute' element, which
|
||||
// specifies the name of the attribute to observe.
|
||||
nsIContent* parent = aElement->GetParent();
|
||||
if (!parent) {
|
||||
// <observes> is the root element
|
||||
return NS_FINDBROADCASTER_NOT_FOUND;
|
||||
}
|
||||
|
||||
*aListener = Element::FromNode(parent);
|
||||
NS_IF_ADDREF(*aListener);
|
||||
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::element, aBroadcasterID);
|
||||
if (aBroadcasterID.IsEmpty()) {
|
||||
return NS_FINDBROADCASTER_NOT_FOUND;
|
||||
}
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::attribute, aAttribute);
|
||||
}
|
||||
else {
|
||||
// It's a generic element, which means that we'll use the
|
||||
// value of the 'observes' attribute to determine the ID of
|
||||
// the broadcaster element, and we'll watch _all_ of its
|
||||
// values.
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::observes, aBroadcasterID);
|
||||
|
||||
// Bail if there's no aBroadcasterID
|
||||
if (aBroadcasterID.IsEmpty()) {
|
||||
// Try the command attribute next.
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::command, aBroadcasterID);
|
||||
if (!aBroadcasterID.IsEmpty()) {
|
||||
// We've got something in the command attribute. We
|
||||
// only treat this as a normal broadcaster if we are
|
||||
// not a menuitem or a key.
|
||||
|
||||
if (ni->Equals(nsGkAtoms::menuitem, kNameSpaceID_XUL) ||
|
||||
ni->Equals(nsGkAtoms::key, kNameSpaceID_XUL)) {
|
||||
return NS_FINDBROADCASTER_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return NS_FINDBROADCASTER_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
*aListener = aElement;
|
||||
NS_ADDREF(*aListener);
|
||||
|
||||
aAttribute.Assign('*');
|
||||
}
|
||||
|
||||
// Make sure we got a valid listener.
|
||||
NS_ENSURE_TRUE(*aListener, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// Try to find the broadcaster element in the document.
|
||||
nsIDocument* doc = aElement->GetComposedDoc();
|
||||
if (doc) {
|
||||
*aBroadcaster = doc->GetElementById(aBroadcasterID);
|
||||
}
|
||||
|
||||
// The broadcaster element is missing.
|
||||
if (! *aBroadcaster) {
|
||||
return NS_FINDBROADCASTER_NOT_FOUND;
|
||||
}
|
||||
|
||||
NS_ADDREF(*aBroadcaster);
|
||||
|
||||
return NS_FINDBROADCASTER_FOUND;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULBroadcastManager::UpdateListenerHookup(Element* aElement, HookupAction aAction)
|
||||
{
|
||||
// Resolve a broadcaster hookup. Look at the element that we're
|
||||
// trying to resolve: it could be an '<observes>' element, or just
|
||||
// a vanilla element with an 'observes' attribute on it.
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<Element> listener;
|
||||
nsAutoString broadcasterID;
|
||||
nsAutoString attribute;
|
||||
nsCOMPtr<Element> broadcaster;
|
||||
|
||||
rv = FindBroadcaster(aElement, getter_AddRefs(listener),
|
||||
broadcasterID, attribute, getter_AddRefs(broadcaster));
|
||||
switch (rv) {
|
||||
case NS_FINDBROADCASTER_NOT_FOUND:
|
||||
return NS_OK;
|
||||
case NS_FINDBROADCASTER_FOUND:
|
||||
break;
|
||||
default:
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_ENSURE_ARG(broadcaster && listener);
|
||||
if (aAction == eHookupAdd) {
|
||||
ErrorResult domRv;
|
||||
AddListenerFor(*broadcaster, *listener, attribute, domRv);
|
||||
if (domRv.Failed()) {
|
||||
return domRv.StealNSResult();
|
||||
}
|
||||
} else {
|
||||
RemoveListenerFor(*broadcaster, *listener, attribute);
|
||||
}
|
||||
|
||||
// Tell the world we succeeded
|
||||
if (MOZ_LOG_TEST(sXULBroadCastManager, LogLevel::Debug)) {
|
||||
nsCOMPtr<nsIContent> content = listener;
|
||||
NS_ASSERTION(content != nullptr, "not an nsIContent");
|
||||
if (!content) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoCString attributeC,broadcasteridC;
|
||||
LossyCopyUTF16toASCII(attribute, attributeC);
|
||||
LossyCopyUTF16toASCII(broadcasterID, broadcasteridC);
|
||||
MOZ_LOG(sXULBroadCastManager, LogLevel::Debug,
|
||||
("xul: broadcaster hookup <%s attribute='%s'> to %s",
|
||||
nsAtomCString(content->NodeInfo()->NameAtom()).get(),
|
||||
attributeC.get(),
|
||||
broadcasteridC.get()));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULBroadcastManager::AddListener(Element* aElement)
|
||||
{
|
||||
return UpdateListenerHookup(aElement, eHookupAdd);
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULBroadcastManager::RemoveListener(Element* aElement)
|
||||
{
|
||||
return UpdateListenerHookup(aElement, eHookupRemove);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
140
dom/xul/XULBroadcastManager.h
Normal file
140
dom/xul/XULBroadcastManager.h
Normal file
@ -0,0 +1,140 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=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/. */
|
||||
|
||||
#ifndef mozilla_dom_XULBroadcastManager_h
|
||||
#define mozilla_dom_XULBroadcastManager_h
|
||||
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsAtom.h"
|
||||
|
||||
class nsXULElement;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class XULBroadcastManager final {
|
||||
|
||||
public:
|
||||
typedef mozilla::dom::Element Element;
|
||||
|
||||
explicit XULBroadcastManager(nsIDocument* aDocument);
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(XULBroadcastManager)
|
||||
|
||||
/**
|
||||
* Checks whether an element uses any of the special broadcaster attributes
|
||||
* or is an observes element. This mimics the logic in FindBroadcaster, but
|
||||
* is intended to be a lighter weight check and doesn't actually guarantee
|
||||
* that the element will need a listener.
|
||||
*/
|
||||
static bool MayNeedListener(const Element& aElement);
|
||||
|
||||
nsresult AddListener(Element* aElement);
|
||||
nsresult RemoveListener(Element* aElement);
|
||||
void AttributeChanged(Element* aElement, int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute);
|
||||
void MaybeBroadcast();
|
||||
void DropDocumentReference(); // notification that doc is going away
|
||||
protected:
|
||||
|
||||
enum HookupAction {
|
||||
eHookupAdd = 0,
|
||||
eHookupRemove
|
||||
};
|
||||
|
||||
nsresult UpdateListenerHookup(Element* aElement, HookupAction aAction);
|
||||
|
||||
void RemoveListenerFor(Element& aBroadcaster, Element& aListener,
|
||||
const nsAString& aAttr);
|
||||
void AddListenerFor(Element& aBroadcaster, Element& aListener,
|
||||
const nsAString& aAttr, ErrorResult& aRv);
|
||||
|
||||
nsresult
|
||||
ExecuteOnBroadcastHandlerFor(Element* aBroadcaster,
|
||||
Element* aListener,
|
||||
nsAtom* aAttr);
|
||||
// The out params of FindBroadcaster only have values that make sense when
|
||||
// the method returns NS_FINDBROADCASTER_FOUND. In all other cases, the
|
||||
// values of the out params should not be relied on (though *aListener and
|
||||
// *aBroadcaster do need to be released if non-null, of course).
|
||||
nsresult
|
||||
FindBroadcaster(Element* aElement,
|
||||
Element** aListener,
|
||||
nsString& aBroadcasterID,
|
||||
nsString& aAttribute,
|
||||
Element** aBroadcaster);
|
||||
|
||||
void
|
||||
SynchronizeBroadcastListener(Element *aBroadcaster,
|
||||
Element *aListener,
|
||||
const nsAString &aAttr);
|
||||
|
||||
|
||||
// This reference is nulled by the Document in it's destructor through
|
||||
// DropDocumentReference().
|
||||
nsIDocument* MOZ_NON_OWNING_REF mDocument;
|
||||
|
||||
/**
|
||||
* A map from a broadcaster element to a list of listener elements.
|
||||
*/
|
||||
PLDHashTable* mBroadcasterMap;
|
||||
|
||||
class nsDelayedBroadcastUpdate
|
||||
{
|
||||
public:
|
||||
nsDelayedBroadcastUpdate(Element* aBroadcaster,
|
||||
Element* aListener,
|
||||
const nsAString &aAttr)
|
||||
: mBroadcaster(aBroadcaster), mListener(aListener), mAttr(aAttr),
|
||||
mSetAttr(false), mNeedsAttrChange(false) {}
|
||||
|
||||
nsDelayedBroadcastUpdate(Element* aBroadcaster,
|
||||
Element* aListener,
|
||||
nsAtom* aAttrName,
|
||||
const nsAString &aAttr,
|
||||
bool aSetAttr,
|
||||
bool aNeedsAttrChange)
|
||||
: mBroadcaster(aBroadcaster), mListener(aListener), mAttr(aAttr),
|
||||
mAttrName(aAttrName), mSetAttr(aSetAttr),
|
||||
mNeedsAttrChange(aNeedsAttrChange) {}
|
||||
|
||||
nsDelayedBroadcastUpdate(const nsDelayedBroadcastUpdate& aOther)
|
||||
: mBroadcaster(aOther.mBroadcaster), mListener(aOther.mListener),
|
||||
mAttr(aOther.mAttr), mAttrName(aOther.mAttrName),
|
||||
mSetAttr(aOther.mSetAttr), mNeedsAttrChange(aOther.mNeedsAttrChange) {}
|
||||
|
||||
nsCOMPtr<Element> mBroadcaster;
|
||||
nsCOMPtr<Element> mListener;
|
||||
// Note if mAttrName isn't used, this is the name of the attr, otherwise
|
||||
// this is the value of the attribute.
|
||||
nsString mAttr;
|
||||
RefPtr<nsAtom> mAttrName;
|
||||
bool mSetAttr;
|
||||
bool mNeedsAttrChange;
|
||||
|
||||
class Comparator {
|
||||
public:
|
||||
static bool Equals(const nsDelayedBroadcastUpdate& a, const nsDelayedBroadcastUpdate& b) {
|
||||
return a.mBroadcaster == b.mBroadcaster && a.mListener == b.mListener && a.mAttrName == b.mAttrName;
|
||||
}
|
||||
};
|
||||
};
|
||||
nsTArray<nsDelayedBroadcastUpdate> mDelayedBroadcasters;
|
||||
nsTArray<nsDelayedBroadcastUpdate> mDelayedAttrChangeBroadcasts;
|
||||
bool mHandlingDelayedAttrChange;
|
||||
bool mHandlingDelayedBroadcasters;
|
||||
|
||||
private:
|
||||
~XULBroadcastManager();
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
#endif // mozilla_dom_XULBroadcastManager_h
|
@ -116,19 +116,6 @@ int32_t XULDocument::gRefCnt = 0;
|
||||
|
||||
LazyLogModule XULDocument::gXULLog("XULDocument");
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
struct BroadcastListener {
|
||||
nsWeakPtr mListener;
|
||||
RefPtr<nsAtom> mAttribute;
|
||||
};
|
||||
|
||||
struct BroadcasterMapEntry : public PLDHashEntryHdr
|
||||
{
|
||||
Element* mBroadcaster; // [WEAK]
|
||||
nsTArray<BroadcastListener*> mListeners; // [OWNING] of BroadcastListener objects
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// ctors & dtors
|
||||
@ -149,10 +136,7 @@ XULDocument::XULDocument(void)
|
||||
mOffThreadCompiling(false),
|
||||
mOffThreadCompileStringBuf(nullptr),
|
||||
mOffThreadCompileStringLength(0),
|
||||
mBroadcasterMap(nullptr),
|
||||
mInitialLayoutComplete(false),
|
||||
mHandlingDelayedAttrChange(false),
|
||||
mHandlingDelayedBroadcasters(false)
|
||||
mInitialLayoutComplete(false)
|
||||
{
|
||||
// Override the default in nsDocument
|
||||
mCharacterSet = UTF_8_ENCODING;
|
||||
@ -170,9 +154,6 @@ XULDocument::~XULDocument()
|
||||
NS_ASSERTION(mNextSrcLoadWaiter == nullptr,
|
||||
"unreferenced document still waiting for script source to load?");
|
||||
|
||||
// Destroy our broadcaster map.
|
||||
delete mBroadcasterMap;
|
||||
|
||||
Preferences::UnregisterCallback(XULDocument::DirectionChanged,
|
||||
"intl.uidirection", this);
|
||||
|
||||
@ -442,276 +423,6 @@ XULDocument::OnPrototypeLoadDone(bool aResumeWalk)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void
|
||||
ClearBroadcasterMapEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
|
||||
{
|
||||
BroadcasterMapEntry* entry =
|
||||
static_cast<BroadcasterMapEntry*>(aEntry);
|
||||
for (size_t i = entry->mListeners.Length() - 1; i != (size_t)-1; --i) {
|
||||
delete entry->mListeners[i];
|
||||
}
|
||||
entry->mListeners.Clear();
|
||||
|
||||
// N.B. that we need to manually run the dtor because we
|
||||
// constructed the nsTArray object in-place.
|
||||
entry->mListeners.~nsTArray<BroadcastListener*>();
|
||||
}
|
||||
|
||||
static bool
|
||||
CanBroadcast(int32_t aNameSpaceID, nsAtom* aAttribute)
|
||||
{
|
||||
// Don't push changes to the |id|, |persist|, |command| or
|
||||
// |observes| attribute.
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
if ((aAttribute == nsGkAtoms::id) ||
|
||||
(aAttribute == nsGkAtoms::persist) ||
|
||||
(aAttribute == nsGkAtoms::command) ||
|
||||
(aAttribute == nsGkAtoms::observes)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct nsAttrNameInfo
|
||||
{
|
||||
nsAttrNameInfo(int32_t aNamespaceID, nsAtom* aName, nsAtom* aPrefix) :
|
||||
mNamespaceID(aNamespaceID), mName(aName), mPrefix(aPrefix) {}
|
||||
nsAttrNameInfo(const nsAttrNameInfo& aOther) :
|
||||
mNamespaceID(aOther.mNamespaceID), mName(aOther.mName),
|
||||
mPrefix(aOther.mPrefix) {}
|
||||
int32_t mNamespaceID;
|
||||
RefPtr<nsAtom> mName;
|
||||
RefPtr<nsAtom> mPrefix;
|
||||
};
|
||||
|
||||
void
|
||||
XULDocument::SynchronizeBroadcastListener(Element *aBroadcaster,
|
||||
Element *aListener,
|
||||
const nsAString &aAttr)
|
||||
{
|
||||
if (!nsContentUtils::IsSafeToRunScript()) {
|
||||
nsDelayedBroadcastUpdate delayedUpdate(aBroadcaster, aListener,
|
||||
aAttr);
|
||||
mDelayedBroadcasters.AppendElement(delayedUpdate);
|
||||
MaybeBroadcast();
|
||||
return;
|
||||
}
|
||||
bool notify = mDocumentLoaded || mHandlingDelayedBroadcasters;
|
||||
|
||||
if (aAttr.EqualsLiteral("*")) {
|
||||
uint32_t count = aBroadcaster->GetAttrCount();
|
||||
nsTArray<nsAttrNameInfo> attributes(count);
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
const nsAttrName* attrName = aBroadcaster->GetAttrNameAt(i);
|
||||
int32_t nameSpaceID = attrName->NamespaceID();
|
||||
nsAtom* name = attrName->LocalName();
|
||||
|
||||
// _Don't_ push the |id|, |ref|, or |persist| attribute's value!
|
||||
if (! CanBroadcast(nameSpaceID, name))
|
||||
continue;
|
||||
|
||||
attributes.AppendElement(nsAttrNameInfo(nameSpaceID, name,
|
||||
attrName->GetPrefix()));
|
||||
}
|
||||
|
||||
count = attributes.Length();
|
||||
while (count-- > 0) {
|
||||
int32_t nameSpaceID = attributes[count].mNamespaceID;
|
||||
nsAtom* name = attributes[count].mName;
|
||||
nsAutoString value;
|
||||
if (aBroadcaster->GetAttr(nameSpaceID, name, value)) {
|
||||
aListener->SetAttr(nameSpaceID, name, attributes[count].mPrefix,
|
||||
value, notify);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// XXX we don't fire the |onbroadcast| handler during
|
||||
// initial hookup: doing so would potentially run the
|
||||
// |onbroadcast| handler before the |onload| handler,
|
||||
// which could define JS properties that mask XBL
|
||||
// properties, etc.
|
||||
ExecuteOnBroadcastHandlerFor(aBroadcaster, aListener, name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Find out if the attribute is even present at all.
|
||||
RefPtr<nsAtom> name = NS_Atomize(aAttr);
|
||||
|
||||
nsAutoString value;
|
||||
if (aBroadcaster->GetAttr(kNameSpaceID_None, name, value)) {
|
||||
aListener->SetAttr(kNameSpaceID_None, name, value, notify);
|
||||
} else {
|
||||
aListener->UnsetAttr(kNameSpaceID_None, name, notify);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// XXX we don't fire the |onbroadcast| handler during initial
|
||||
// hookup: doing so would potentially run the |onbroadcast|
|
||||
// handler before the |onload| handler, which could define JS
|
||||
// properties that mask XBL properties, etc.
|
||||
ExecuteOnBroadcastHandlerFor(aBroadcaster, aListener, name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XULDocument::AddBroadcastListenerFor(Element& aBroadcaster, Element& aListener,
|
||||
const nsAString& aAttr, ErrorResult& aRv)
|
||||
{
|
||||
nsresult rv =
|
||||
nsContentUtils::CheckSameOrigin(this, &aBroadcaster);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = nsContentUtils::CheckSameOrigin(this, &aListener);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
static const PLDHashTableOps gOps = {
|
||||
PLDHashTable::HashVoidPtrKeyStub,
|
||||
PLDHashTable::MatchEntryStub,
|
||||
PLDHashTable::MoveEntryStub,
|
||||
ClearBroadcasterMapEntry,
|
||||
nullptr
|
||||
};
|
||||
|
||||
if (! mBroadcasterMap) {
|
||||
mBroadcasterMap = new PLDHashTable(&gOps, sizeof(BroadcasterMapEntry));
|
||||
}
|
||||
|
||||
auto entry = static_cast<BroadcasterMapEntry*>
|
||||
(mBroadcasterMap->Search(&aBroadcaster));
|
||||
if (!entry) {
|
||||
entry = static_cast<BroadcasterMapEntry*>
|
||||
(mBroadcasterMap->Add(&aBroadcaster, fallible));
|
||||
|
||||
if (! entry) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
entry->mBroadcaster = &aBroadcaster;
|
||||
|
||||
// N.B. placement new to construct the nsTArray object in-place
|
||||
new (&entry->mListeners) nsTArray<BroadcastListener*>();
|
||||
}
|
||||
|
||||
// Only add the listener if it's not there already!
|
||||
RefPtr<nsAtom> attr = NS_Atomize(aAttr);
|
||||
|
||||
for (size_t i = entry->mListeners.Length() - 1; i != (size_t)-1; --i) {
|
||||
BroadcastListener* bl = entry->mListeners[i];
|
||||
nsCOMPtr<Element> blListener = do_QueryReferent(bl->mListener);
|
||||
|
||||
if (blListener == &aListener && bl->mAttribute == attr)
|
||||
return;
|
||||
}
|
||||
|
||||
BroadcastListener* bl = new BroadcastListener;
|
||||
bl->mListener = do_GetWeakReference(&aListener);
|
||||
bl->mAttribute = attr;
|
||||
|
||||
entry->mListeners.AppendElement(bl);
|
||||
|
||||
SynchronizeBroadcastListener(&aBroadcaster, &aListener, aAttr);
|
||||
}
|
||||
|
||||
void
|
||||
XULDocument::RemoveBroadcastListenerFor(Element& aBroadcaster,
|
||||
Element& aListener,
|
||||
const nsAString& aAttr)
|
||||
{
|
||||
// If we haven't added any broadcast listeners, then there sure
|
||||
// aren't any to remove.
|
||||
if (! mBroadcasterMap)
|
||||
return;
|
||||
|
||||
auto entry = static_cast<BroadcasterMapEntry*>
|
||||
(mBroadcasterMap->Search(&aBroadcaster));
|
||||
if (entry) {
|
||||
RefPtr<nsAtom> attr = NS_Atomize(aAttr);
|
||||
for (size_t i = entry->mListeners.Length() - 1; i != (size_t)-1; --i) {
|
||||
BroadcastListener* bl = entry->mListeners[i];
|
||||
nsCOMPtr<Element> blListener = do_QueryReferent(bl->mListener);
|
||||
|
||||
if (blListener == &aListener && bl->mAttribute == attr) {
|
||||
entry->mListeners.RemoveElementAt(i);
|
||||
delete bl;
|
||||
|
||||
if (entry->mListeners.IsEmpty())
|
||||
mBroadcasterMap->RemoveEntry(entry);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULDocument::ExecuteOnBroadcastHandlerFor(Element* aBroadcaster,
|
||||
Element* aListener,
|
||||
nsAtom* aAttr)
|
||||
{
|
||||
// Now we execute the onchange handler in the context of the
|
||||
// observer. We need to find the observer in order to
|
||||
// execute the handler.
|
||||
|
||||
for (nsIContent* child = aListener->GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
|
||||
// Look for an <observes> element beneath the listener. This
|
||||
// ought to have an |element| attribute that refers to
|
||||
// aBroadcaster, and an |attribute| element that tells us what
|
||||
// attriubtes we're listening for.
|
||||
if (!child->IsXULElement(nsGkAtoms::observes))
|
||||
continue;
|
||||
|
||||
// Is this the element that was listening to us?
|
||||
nsAutoString listeningToID;
|
||||
child->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::element, listeningToID);
|
||||
|
||||
nsAutoString broadcasterID;
|
||||
aBroadcaster->GetAttr(kNameSpaceID_None, nsGkAtoms::id, broadcasterID);
|
||||
|
||||
if (listeningToID != broadcasterID)
|
||||
continue;
|
||||
|
||||
// We are observing the broadcaster, but is this the right
|
||||
// attribute?
|
||||
nsAutoString listeningToAttribute;
|
||||
child->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::attribute,
|
||||
listeningToAttribute);
|
||||
|
||||
if (!aAttr->Equals(listeningToAttribute) &&
|
||||
!listeningToAttribute.EqualsLiteral("*")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is the right <observes> element. Execute the
|
||||
// |onbroadcast| event handler
|
||||
WidgetEvent event(true, eXULBroadcast);
|
||||
|
||||
RefPtr<nsPresContext> presContext = GetPresContext();
|
||||
if (presContext) {
|
||||
// Handle the DOM event
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
EventDispatcher::Dispatch(child, presContext, &event, nullptr,
|
||||
&status);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool
|
||||
ShouldPersistAttribute(Element* aElement, nsAtom* aAttribute)
|
||||
{
|
||||
@ -744,62 +455,6 @@ XULDocument::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
|
||||
// Might not need this, but be safe for now.
|
||||
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
|
||||
|
||||
// Synchronize broadcast listeners
|
||||
if (mBroadcasterMap &&
|
||||
CanBroadcast(aNameSpaceID, aAttribute)) {
|
||||
auto entry = static_cast<BroadcasterMapEntry*>
|
||||
(mBroadcasterMap->Search(aElement));
|
||||
|
||||
if (entry) {
|
||||
// We've got listeners: push the value.
|
||||
nsAutoString value;
|
||||
bool attrSet = aElement->GetAttr(kNameSpaceID_None, aAttribute, value);
|
||||
|
||||
for (size_t i = entry->mListeners.Length() - 1; i != (size_t)-1; --i) {
|
||||
BroadcastListener* bl = entry->mListeners[i];
|
||||
if ((bl->mAttribute == aAttribute) ||
|
||||
(bl->mAttribute == nsGkAtoms::_asterisk)) {
|
||||
nsCOMPtr<Element> listenerEl
|
||||
= do_QueryReferent(bl->mListener);
|
||||
if (listenerEl) {
|
||||
nsAutoString currentValue;
|
||||
bool hasAttr = listenerEl->GetAttr(kNameSpaceID_None,
|
||||
aAttribute,
|
||||
currentValue);
|
||||
// We need to update listener only if we're
|
||||
// (1) removing an existing attribute,
|
||||
// (2) adding a new attribute or
|
||||
// (3) changing the value of an attribute.
|
||||
bool needsAttrChange =
|
||||
attrSet != hasAttr || !value.Equals(currentValue);
|
||||
nsDelayedBroadcastUpdate delayedUpdate(aElement,
|
||||
listenerEl,
|
||||
aAttribute,
|
||||
value,
|
||||
attrSet,
|
||||
needsAttrChange);
|
||||
|
||||
size_t index =
|
||||
mDelayedAttrChangeBroadcasts.IndexOf(delayedUpdate,
|
||||
0, nsDelayedBroadcastUpdate::Comparator());
|
||||
if (index != mDelayedAttrChangeBroadcasts.NoIndex) {
|
||||
if (mHandlingDelayedAttrChange) {
|
||||
NS_WARNING("Broadcasting loop!");
|
||||
continue;
|
||||
}
|
||||
mDelayedAttrChangeBroadcasts.RemoveElementAt(index);
|
||||
}
|
||||
|
||||
mDelayedAttrChangeBroadcasts.AppendElement(delayedUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checks for modifications in broadcasters
|
||||
CheckBroadcasterHookup(aElement);
|
||||
|
||||
// See if there is anything we need to persist in the localstore.
|
||||
//
|
||||
// XXX Namespace handling broken :-(
|
||||
@ -920,7 +575,6 @@ XULDocument::AddElementToDocumentPre(Element* aElement)
|
||||
{
|
||||
// Do a bunch of work that's necessary when an element gets added
|
||||
// to the XUL Document.
|
||||
nsresult rv;
|
||||
|
||||
// 1. Add the element to the id map, since it seems this can be
|
||||
// called when creating elements from prototypes.
|
||||
@ -931,11 +585,6 @@ XULDocument::AddElementToDocumentPre(Element* aElement)
|
||||
AddToIdTable(aElement, id);
|
||||
}
|
||||
|
||||
// 2. Check for a broadcaster hookup attribute, in which case
|
||||
// we'll hook the node up as a listener on a broadcaster.
|
||||
rv = CheckBroadcasterHookup(aElement);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1015,16 +664,6 @@ XULDocument::RemoveSubtreeFromDocument(nsIContent* aContent)
|
||||
RemoveFromIdTable(aElement, id);
|
||||
}
|
||||
|
||||
// Remove the element from our broadcaster map, since it is no longer
|
||||
// in the document.
|
||||
nsCOMPtr<Element> broadcaster, listener;
|
||||
nsAutoString attribute, broadcasterID;
|
||||
rv = FindBroadcaster(aElement, getter_AddRefs(listener),
|
||||
broadcasterID, attribute, getter_AddRefs(broadcaster));
|
||||
if (rv == NS_FINDBROADCASTER_FOUND) {
|
||||
RemoveBroadcastListenerFor(*broadcaster, *listener, attribute);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1801,66 +1440,10 @@ XULDocument::StyleSheetLoaded(StyleSheet* aSheet,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
XULDocument::MaybeBroadcast()
|
||||
{
|
||||
// Only broadcast when not in an update and when safe to run scripts.
|
||||
if (mUpdateNestLevel == 0 &&
|
||||
(mDelayedAttrChangeBroadcasts.Length() ||
|
||||
mDelayedBroadcasters.Length())) {
|
||||
if (!nsContentUtils::IsSafeToRunScript()) {
|
||||
if (!mInDestructor) {
|
||||
nsContentUtils::AddScriptRunner(
|
||||
NewRunnableMethod("dom::XULDocument::MaybeBroadcast",
|
||||
this,
|
||||
&XULDocument::MaybeBroadcast));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!mHandlingDelayedAttrChange) {
|
||||
mHandlingDelayedAttrChange = true;
|
||||
for (uint32_t i = 0; i < mDelayedAttrChangeBroadcasts.Length(); ++i) {
|
||||
nsAtom* attrName = mDelayedAttrChangeBroadcasts[i].mAttrName;
|
||||
if (mDelayedAttrChangeBroadcasts[i].mNeedsAttrChange) {
|
||||
nsCOMPtr<Element> listener = mDelayedAttrChangeBroadcasts[i].mListener;
|
||||
const nsString& value = mDelayedAttrChangeBroadcasts[i].mAttr;
|
||||
if (mDelayedAttrChangeBroadcasts[i].mSetAttr) {
|
||||
listener->SetAttr(kNameSpaceID_None, attrName, value,
|
||||
true);
|
||||
} else {
|
||||
listener->UnsetAttr(kNameSpaceID_None, attrName,
|
||||
true);
|
||||
}
|
||||
}
|
||||
ExecuteOnBroadcastHandlerFor(mDelayedAttrChangeBroadcasts[i].mBroadcaster,
|
||||
mDelayedAttrChangeBroadcasts[i].mListener,
|
||||
attrName);
|
||||
}
|
||||
mDelayedAttrChangeBroadcasts.Clear();
|
||||
mHandlingDelayedAttrChange = false;
|
||||
}
|
||||
|
||||
uint32_t length = mDelayedBroadcasters.Length();
|
||||
if (length) {
|
||||
bool oldValue = mHandlingDelayedBroadcasters;
|
||||
mHandlingDelayedBroadcasters = true;
|
||||
nsTArray<nsDelayedBroadcastUpdate> delayedBroadcasters;
|
||||
mDelayedBroadcasters.SwapElements(delayedBroadcasters);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
SynchronizeBroadcastListener(delayedBroadcasters[i].mBroadcaster,
|
||||
delayedBroadcasters[i].mListener,
|
||||
delayedBroadcasters[i].mAttr);
|
||||
}
|
||||
mHandlingDelayedBroadcasters = oldValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XULDocument::EndUpdate()
|
||||
{
|
||||
XMLDocument::EndUpdate();
|
||||
MaybeBroadcast();
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -2248,141 +1831,6 @@ XULDocument::AddAttributes(nsXULPrototypeElement* aPrototype,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
XULDocument::FindBroadcaster(Element* aElement,
|
||||
Element** aListener,
|
||||
nsString& aBroadcasterID,
|
||||
nsString& aAttribute,
|
||||
Element** aBroadcaster)
|
||||
{
|
||||
mozilla::dom::NodeInfo *ni = aElement->NodeInfo();
|
||||
*aListener = nullptr;
|
||||
*aBroadcaster = nullptr;
|
||||
|
||||
if (ni->Equals(nsGkAtoms::observes, kNameSpaceID_XUL)) {
|
||||
// It's an <observes> element, which means that the actual
|
||||
// listener is the _parent_ node. This element should have an
|
||||
// 'element' attribute that specifies the ID of the
|
||||
// broadcaster element, and an 'attribute' element, which
|
||||
// specifies the name of the attribute to observe.
|
||||
nsIContent* parent = aElement->GetParent();
|
||||
if (!parent) {
|
||||
// <observes> is the root element
|
||||
return NS_FINDBROADCASTER_NOT_FOUND;
|
||||
}
|
||||
|
||||
*aListener = Element::FromNode(parent);
|
||||
NS_IF_ADDREF(*aListener);
|
||||
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::element, aBroadcasterID);
|
||||
if (aBroadcasterID.IsEmpty()) {
|
||||
return NS_FINDBROADCASTER_NOT_FOUND;
|
||||
}
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::attribute, aAttribute);
|
||||
}
|
||||
else {
|
||||
// It's a generic element, which means that we'll use the
|
||||
// value of the 'observes' attribute to determine the ID of
|
||||
// the broadcaster element, and we'll watch _all_ of its
|
||||
// values.
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::observes, aBroadcasterID);
|
||||
|
||||
// Bail if there's no aBroadcasterID
|
||||
if (aBroadcasterID.IsEmpty()) {
|
||||
// Try the command attribute next.
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::command, aBroadcasterID);
|
||||
if (!aBroadcasterID.IsEmpty()) {
|
||||
// We've got something in the command attribute. We
|
||||
// only treat this as a normal broadcaster if we are
|
||||
// not a menuitem or a key.
|
||||
|
||||
if (ni->Equals(nsGkAtoms::menuitem, kNameSpaceID_XUL) ||
|
||||
ni->Equals(nsGkAtoms::key, kNameSpaceID_XUL)) {
|
||||
return NS_FINDBROADCASTER_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return NS_FINDBROADCASTER_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
*aListener = aElement;
|
||||
NS_ADDREF(*aListener);
|
||||
|
||||
aAttribute.Assign('*');
|
||||
}
|
||||
|
||||
// Make sure we got a valid listener.
|
||||
NS_ENSURE_TRUE(*aListener, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// Try to find the broadcaster element in the document.
|
||||
*aBroadcaster = GetElementById(aBroadcasterID);
|
||||
|
||||
// The broadcaster element is missing.
|
||||
if (! *aBroadcaster) {
|
||||
return NS_FINDBROADCASTER_NOT_FOUND;
|
||||
}
|
||||
|
||||
NS_ADDREF(*aBroadcaster);
|
||||
|
||||
return NS_FINDBROADCASTER_FOUND;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULDocument::CheckBroadcasterHookup(Element* aElement)
|
||||
{
|
||||
// Resolve a broadcaster hookup. Look at the element that we're
|
||||
// trying to resolve: it could be an '<observes>' element, or just
|
||||
// a vanilla element with an 'observes' attribute on it.
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<Element> listener;
|
||||
nsAutoString broadcasterID;
|
||||
nsAutoString attribute;
|
||||
nsCOMPtr<Element> broadcaster;
|
||||
|
||||
rv = FindBroadcaster(aElement, getter_AddRefs(listener),
|
||||
broadcasterID, attribute, getter_AddRefs(broadcaster));
|
||||
switch (rv) {
|
||||
case NS_FINDBROADCASTER_NOT_FOUND:
|
||||
return NS_OK;
|
||||
case NS_FINDBROADCASTER_FOUND:
|
||||
break;
|
||||
default:
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_ENSURE_ARG(broadcaster && listener);
|
||||
ErrorResult domRv;
|
||||
AddBroadcastListenerFor(*broadcaster, *listener, attribute, domRv);
|
||||
if (domRv.Failed()) {
|
||||
return domRv.StealNSResult();
|
||||
}
|
||||
|
||||
// Tell the world we succeeded
|
||||
if (MOZ_LOG_TEST(gXULLog, LogLevel::Debug)) {
|
||||
nsCOMPtr<nsIContent> content = listener;
|
||||
NS_ASSERTION(content != nullptr, "not an nsIContent");
|
||||
if (!content) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoCString attributeC,broadcasteridC;
|
||||
LossyCopyUTF16toASCII(attribute, attributeC);
|
||||
LossyCopyUTF16toASCII(broadcasterID, broadcasteridC);
|
||||
MOZ_LOG(gXULLog, LogLevel::Debug,
|
||||
("xul: broadcaster hookup <%s attribute='%s'> to %s",
|
||||
nsAtomCString(content->NodeInfo()->NameAtom()).get(),
|
||||
attributeC.get(),
|
||||
broadcasteridC.get()));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// CachedChromeStreamListener
|
||||
|
@ -128,9 +128,6 @@ public:
|
||||
|
||||
void TraceProtos(JSTracer* aTrc);
|
||||
|
||||
void RemoveBroadcastListenerFor(Element& aBroadcaster, Element& aListener,
|
||||
const nsAString& aAttr);
|
||||
|
||||
protected:
|
||||
virtual ~XULDocument();
|
||||
|
||||
@ -164,14 +161,6 @@ protected:
|
||||
nsresult
|
||||
AddElementToDocumentPost(Element* aElement);
|
||||
|
||||
void AddBroadcastListenerFor(Element& aBroadcaster, Element& aListener,
|
||||
const nsAString& aAttr, ErrorResult& aRv);
|
||||
|
||||
nsresult
|
||||
ExecuteOnBroadcastHandlerFor(Element* aBroadcaster,
|
||||
Element* aListener,
|
||||
nsAtom* aAttr);
|
||||
|
||||
static void DirectionChanged(const char* aPrefName, XULDocument* aData);
|
||||
|
||||
// pseudo constants
|
||||
@ -292,25 +281,6 @@ protected:
|
||||
|
||||
|
||||
protected:
|
||||
// The out params of FindBroadcaster only have values that make sense when
|
||||
// the method returns NS_FINDBROADCASTER_FOUND. In all other cases, the
|
||||
// values of the out params should not be relied on (though *aListener and
|
||||
// *aBroadcaster do need to be released if non-null, of course).
|
||||
nsresult
|
||||
FindBroadcaster(Element* aElement,
|
||||
Element** aListener,
|
||||
nsString& aBroadcasterID,
|
||||
nsString& aAttribute,
|
||||
Element** aBroadcaster);
|
||||
|
||||
nsresult
|
||||
CheckBroadcasterHookup(Element* aElement);
|
||||
|
||||
void
|
||||
SynchronizeBroadcastListener(Element *aBroadcaster,
|
||||
Element *aListener,
|
||||
const nsAString &aAttr);
|
||||
|
||||
/**
|
||||
* The current prototype that we are walking to construct the
|
||||
* content model.
|
||||
@ -382,60 +352,8 @@ protected:
|
||||
|
||||
friend class CachedChromeStreamListener;
|
||||
|
||||
/**
|
||||
* A map from a broadcaster element to a list of listener elements.
|
||||
*/
|
||||
PLDHashTable* mBroadcasterMap;
|
||||
|
||||
bool mInitialLayoutComplete;
|
||||
|
||||
class nsDelayedBroadcastUpdate
|
||||
{
|
||||
public:
|
||||
nsDelayedBroadcastUpdate(Element* aBroadcaster,
|
||||
Element* aListener,
|
||||
const nsAString &aAttr)
|
||||
: mBroadcaster(aBroadcaster), mListener(aListener), mAttr(aAttr),
|
||||
mSetAttr(false), mNeedsAttrChange(false) {}
|
||||
|
||||
nsDelayedBroadcastUpdate(Element* aBroadcaster,
|
||||
Element* aListener,
|
||||
nsAtom* aAttrName,
|
||||
const nsAString &aAttr,
|
||||
bool aSetAttr,
|
||||
bool aNeedsAttrChange)
|
||||
: mBroadcaster(aBroadcaster), mListener(aListener), mAttr(aAttr),
|
||||
mAttrName(aAttrName), mSetAttr(aSetAttr),
|
||||
mNeedsAttrChange(aNeedsAttrChange) {}
|
||||
|
||||
nsDelayedBroadcastUpdate(const nsDelayedBroadcastUpdate& aOther)
|
||||
: mBroadcaster(aOther.mBroadcaster), mListener(aOther.mListener),
|
||||
mAttr(aOther.mAttr), mAttrName(aOther.mAttrName),
|
||||
mSetAttr(aOther.mSetAttr), mNeedsAttrChange(aOther.mNeedsAttrChange) {}
|
||||
|
||||
nsCOMPtr<Element> mBroadcaster;
|
||||
nsCOMPtr<Element> mListener;
|
||||
// Note if mAttrName isn't used, this is the name of the attr, otherwise
|
||||
// this is the value of the attribute.
|
||||
nsString mAttr;
|
||||
RefPtr<nsAtom> mAttrName;
|
||||
bool mSetAttr;
|
||||
bool mNeedsAttrChange;
|
||||
|
||||
class Comparator {
|
||||
public:
|
||||
static bool Equals(const nsDelayedBroadcastUpdate& a, const nsDelayedBroadcastUpdate& b) {
|
||||
return a.mBroadcaster == b.mBroadcaster && a.mListener == b.mListener && a.mAttrName == b.mAttrName;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
nsTArray<nsDelayedBroadcastUpdate> mDelayedBroadcasters;
|
||||
nsTArray<nsDelayedBroadcastUpdate> mDelayedAttrChangeBroadcasts;
|
||||
bool mHandlingDelayedAttrChange;
|
||||
bool mHandlingDelayedBroadcasters;
|
||||
|
||||
void MaybeBroadcast();
|
||||
private:
|
||||
// helpers
|
||||
|
||||
|
@ -22,6 +22,7 @@ if CONFIG['MOZ_XUL']:
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'XULBroadcastManager.h',
|
||||
'XULFrameElement.h',
|
||||
'XULMenuElement.h',
|
||||
'XULPopupElement.h',
|
||||
@ -39,6 +40,7 @@ if CONFIG['MOZ_XUL']:
|
||||
'nsXULPrototypeCache.cpp',
|
||||
'nsXULPrototypeDocument.cpp',
|
||||
'nsXULSortService.cpp',
|
||||
'XULBroadcastManager.cpp',
|
||||
'XULDocument.cpp',
|
||||
'XULFrameElement.cpp',
|
||||
'XULMenuElement.cpp',
|
||||
|
@ -81,6 +81,7 @@
|
||||
|
||||
#include "mozilla/dom/XULElementBinding.h"
|
||||
#include "mozilla/dom/BoxObject.h"
|
||||
#include "mozilla/dom/XULBroadcastManager.h"
|
||||
#include "mozilla/dom/MouseEventBinding.h"
|
||||
#include "mozilla/dom/MutationEventBinding.h"
|
||||
#include "mozilla/dom/XULCommandEvent.h"
|
||||
@ -754,6 +755,14 @@ nsXULElement::BindToTree(nsIDocument* aDocument,
|
||||
AddTooltipSupport();
|
||||
}
|
||||
|
||||
if (doc && XULBroadcastManager::MayNeedListener(*this)) {
|
||||
if (!doc->HasXULBroadcastManager()) {
|
||||
doc->InitializeXULBroadcastManager();
|
||||
}
|
||||
XULBroadcastManager* broadcastManager = doc->GetXULBroadcastManager();
|
||||
broadcastManager->AddListener(this);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -768,6 +777,13 @@ nsXULElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
RemoveTooltipSupport();
|
||||
}
|
||||
|
||||
nsIDocument* doc = GetComposedDoc();
|
||||
if (doc && doc->HasXULBroadcastManager() &&
|
||||
XULBroadcastManager::MayNeedListener(*this)) {
|
||||
RefPtr<XULBroadcastManager> broadcastManager = doc->GetXULBroadcastManager();
|
||||
broadcastManager->RemoveListener(this);
|
||||
}
|
||||
|
||||
// mControllers can own objects that are implemented
|
||||
// in JavaScript (such as some implementations of
|
||||
// nsIControllers. These objects prevent their global
|
||||
@ -830,14 +846,18 @@ nsXULElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||
(aName == nsGkAtoms::command || aName == nsGkAtoms::observes) &&
|
||||
IsInUncomposedDoc()) {
|
||||
// XXX sXBL/XBL2 issue! Owner or current document?
|
||||
// XXX Why does this not also remove broadcast listeners if the
|
||||
// "element" attribute was changed on an <observer>?
|
||||
nsAutoString oldValue;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::observes, oldValue);
|
||||
if (oldValue.IsEmpty()) {
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::command, oldValue);
|
||||
}
|
||||
|
||||
if (!oldValue.IsEmpty()) {
|
||||
RemoveBroadcaster(oldValue);
|
||||
nsIDocument* doc = GetUncomposedDoc();
|
||||
if (!oldValue.IsEmpty() && doc->HasXULBroadcastManager()) {
|
||||
RefPtr<XULBroadcastManager> broadcastManager = doc->GetXULBroadcastManager();
|
||||
broadcastManager->RemoveListener(this);
|
||||
}
|
||||
} else if (aNamespaceID == kNameSpaceID_None &&
|
||||
aValue &&
|
||||
@ -965,6 +985,19 @@ nsXULElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||
}
|
||||
}
|
||||
}
|
||||
nsIDocument* doc = GetComposedDoc();
|
||||
if (doc && doc->HasXULBroadcastManager()) {
|
||||
RefPtr<XULBroadcastManager> broadcastManager = doc->GetXULBroadcastManager();
|
||||
broadcastManager->AttributeChanged(this, aNamespaceID, aName);
|
||||
}
|
||||
if (doc && XULBroadcastManager::MayNeedListener(*this)) {
|
||||
if (!doc->HasXULBroadcastManager()) {
|
||||
doc->InitializeXULBroadcastManager();
|
||||
}
|
||||
XULBroadcastManager* broadcastManager = doc->GetXULBroadcastManager();
|
||||
broadcastManager->AddListener(this);
|
||||
}
|
||||
|
||||
// XXX need to check if they're changing an event handler: if
|
||||
// so, then we need to unhook the old one. Or something.
|
||||
}
|
||||
@ -1012,19 +1045,6 @@ nsXULElement::ParseAttribute(int32_t aNamespaceID,
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsXULElement::RemoveBroadcaster(const nsAString & broadcasterId)
|
||||
{
|
||||
nsIDocument* doc = OwnerDoc();
|
||||
if (!doc->IsXULDocument()) {
|
||||
return;
|
||||
}
|
||||
if (Element* broadcaster = doc->GetElementById(broadcasterId)) {
|
||||
doc->AsXULDocument()->RemoveBroadcastListenerFor(
|
||||
*broadcaster, *this, NS_LITERAL_STRING("*"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsXULElement::DestroyContent()
|
||||
{
|
||||
|
@ -693,8 +693,6 @@ protected:
|
||||
void SetDrawsTitle(bool aState);
|
||||
void UpdateBrightTitlebarForeground(nsIDocument* aDocument);
|
||||
|
||||
void RemoveBroadcaster(const nsAString & broadcasterId);
|
||||
|
||||
protected:
|
||||
void AddTooltipSupport();
|
||||
void RemoveTooltipSupport();
|
||||
|
@ -16,8 +16,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=445177
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=445177">Mozilla Bug 445177</a>
|
||||
|
||||
|
||||
<hbox id="b1" value="foo"/>
|
||||
<hbox id="o1" observes="b1"/>
|
||||
<xul:hbox id="b1" value="foo"/>
|
||||
<xul:hbox id="o1" observes="b1"/>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
@ -1079,7 +1079,8 @@ public:
|
||||
|
||||
private:
|
||||
// Helpers for ResolveFlexibleLengths():
|
||||
void FreezeItemsEarly(bool aIsUsingFlexGrow);
|
||||
void FreezeItemsEarly(bool aIsUsingFlexGrow,
|
||||
ComputedFlexLineInfo* aLineInfo);
|
||||
|
||||
void FreezeOrRestoreEachFlexibleSize(const nscoord aTotalViolation,
|
||||
bool aIsFinalIteration);
|
||||
@ -2503,7 +2504,8 @@ nsFlexContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
|
||||
void
|
||||
FlexLine::FreezeItemsEarly(bool aIsUsingFlexGrow)
|
||||
FlexLine::FreezeItemsEarly(bool aIsUsingFlexGrow,
|
||||
ComputedFlexLineInfo* aLineInfo)
|
||||
{
|
||||
// After we've established the type of flexing we're doing (growing vs.
|
||||
// shrinking), and before we try to flex any items, we freeze items that
|
||||
@ -2532,7 +2534,13 @@ FlexLine::FreezeItemsEarly(bool aIsUsingFlexGrow)
|
||||
if (!item->IsFrozen()) {
|
||||
numUnfrozenItemsToBeSeen--;
|
||||
bool shouldFreeze = (0.0f == item->GetFlexFactor(aIsUsingFlexGrow));
|
||||
if (!shouldFreeze) {
|
||||
// NOTE: We skip the "could flex but base size out of range"
|
||||
// early-freezing if flex devtools are active, so that we can let the
|
||||
// first run of the main flex layout loop compute how much this item
|
||||
// wants to flex. (This skipping shouldn't impact results, because
|
||||
// any affected items will just immediately be caught & frozen as min/max
|
||||
// violations in that first loop, and that'll trigger another loop.)
|
||||
if (!shouldFreeze && !aLineInfo) {
|
||||
if (aIsUsingFlexGrow) {
|
||||
if (item->GetFlexBaseSize() > item->GetMainSize()) {
|
||||
shouldFreeze = true;
|
||||
@ -2618,13 +2626,26 @@ FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize,
|
||||
{
|
||||
MOZ_LOG(gFlexContainerLog, LogLevel::Debug, ("ResolveFlexibleLengths\n"));
|
||||
|
||||
// Before we start resolving sizes: if we have an aLineInfo structure to fill
|
||||
// out, we inform it of each item's base size, and we initialize the "delta"
|
||||
// for each item to 0. (And if the flex algorithm wants to grow or shrink the
|
||||
// item, we'll update this delta further down.)
|
||||
if (aLineInfo) {
|
||||
uint32_t itemIndex = 0;
|
||||
for (FlexItem* item = mItems.getFirst(); item; item = item->getNext(),
|
||||
++itemIndex) {
|
||||
aLineInfo->mItems[itemIndex].mMainBaseSize = item->GetFlexBaseSize();
|
||||
aLineInfo->mItems[itemIndex].mMainDeltaSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine whether we're going to be growing or shrinking items.
|
||||
const bool isUsingFlexGrow =
|
||||
(mTotalOuterHypotheticalMainSize < aFlexContainerMainSize);
|
||||
|
||||
// Do an "early freeze" for flex items that obviously can't flex in the
|
||||
// direction we've chosen:
|
||||
FreezeItemsEarly(isUsingFlexGrow);
|
||||
FreezeItemsEarly(isUsingFlexGrow, aLineInfo);
|
||||
|
||||
if ((mNumFrozenItems == mNumItems) && !aLineInfo) {
|
||||
// All our items are frozen, so we have no flexible lengths to resolve,
|
||||
@ -2663,21 +2684,6 @@ FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize,
|
||||
availableFreeSpace -= item->GetMainSize();
|
||||
}
|
||||
|
||||
// If we have an aLineInfo structure to fill out, and this is the
|
||||
// first time through the loop, capture these sizes as mainBaseSizes.
|
||||
// We only care about the first iteration, because additional
|
||||
// iterations will only reset item base sizes to these values.
|
||||
// We also set a 0 mainDeltaSize. This will be modified later if
|
||||
// the item is stretched or shrunk.
|
||||
if (aLineInfo && (iterationCounter == 0)) {
|
||||
uint32_t itemIndex = 0;
|
||||
for (FlexItem* item = mItems.getFirst(); item; item = item->getNext(),
|
||||
++itemIndex) {
|
||||
aLineInfo->mItems[itemIndex].mMainBaseSize = item->GetMainSize();
|
||||
aLineInfo->mItems[itemIndex].mMainDeltaSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
|
||||
(" available free space = %d\n", availableFreeSpace));
|
||||
|
||||
@ -2852,37 +2858,44 @@ FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize,
|
||||
uint32_t itemIndex = 0;
|
||||
for (FlexItem* item = mItems.getFirst(); item; item = item->getNext(),
|
||||
++itemIndex) {
|
||||
// Calculate a deltaSize that represents how much the
|
||||
// flex sizing algorithm "wants" to stretch or shrink this
|
||||
// item during this pass through the algorithm. Later
|
||||
// passes through the algorithm may overwrite this value.
|
||||
// Also, this value may not reflect how much the size of
|
||||
// the item is actually changed, since the size of the
|
||||
// item will be clamped to min and max values later in
|
||||
// this pass. That's intentional, since we want to report
|
||||
// the value that the sizing algorithm tried to stretch
|
||||
// or shrink the item.
|
||||
nscoord deltaSize = item->GetMainSize() -
|
||||
aLineInfo->mItems[itemIndex].mMainBaseSize;
|
||||
if (!item->IsFrozen()) {
|
||||
// Calculate a deltaSize that represents how much the flex sizing
|
||||
// algorithm "wants" to stretch or shrink this item during this
|
||||
// pass through the algorithm. Later passes through the algorithm
|
||||
// may overwrite this, until this item is frozen. Note that this
|
||||
// value may not reflect how much the size of the item is
|
||||
// actually changed, since the size of the item will be clamped
|
||||
// to min and max values later in this pass. That's intentional,
|
||||
// since we want to report the value that the sizing algorithm
|
||||
// tried to stretch or shrink the item.
|
||||
nscoord deltaSize = item->GetMainSize() -
|
||||
aLineInfo->mItems[itemIndex].mMainBaseSize;
|
||||
|
||||
aLineInfo->mItems[itemIndex].mMainDeltaSize = deltaSize;
|
||||
// If any item on the line is growing, mark the aLineInfo
|
||||
// structure; likewise if any item is shrinking. Items in
|
||||
// a line can't be both growing and shrinking.
|
||||
if (deltaSize > 0) {
|
||||
MOZ_ASSERT(item->IsFrozen() || isUsingFlexGrow,
|
||||
"Unfrozen items shouldn't grow without isUsingFlexGrow.");
|
||||
MOZ_ASSERT(aLineInfo->mGrowthState !=
|
||||
ComputedFlexLineInfo::GrowthState::SHRINKING);
|
||||
aLineInfo->mGrowthState =
|
||||
ComputedFlexLineInfo::GrowthState::GROWING;
|
||||
} else if (deltaSize < 0) {
|
||||
MOZ_ASSERT(item->IsFrozen() || !isUsingFlexGrow,
|
||||
"Unfrozen items shouldn't shrink with isUsingFlexGrow.");
|
||||
MOZ_ASSERT(aLineInfo->mGrowthState !=
|
||||
ComputedFlexLineInfo::GrowthState::GROWING);
|
||||
aLineInfo->mGrowthState =
|
||||
ComputedFlexLineInfo::GrowthState::SHRINKING;
|
||||
aLineInfo->mItems[itemIndex].mMainDeltaSize = deltaSize;
|
||||
// If any (unfrozen) item on the line is growing, we mark the
|
||||
// aLineInfo structure; likewise if any item is shrinking.
|
||||
// (Note: a line can't contain a mix of items that are growing
|
||||
// and shrinking. Also, the sign of any delta should match the
|
||||
// type of flex factor we're using [grow vs shrink].)
|
||||
if (deltaSize > 0) {
|
||||
MOZ_ASSERT(isUsingFlexGrow,
|
||||
"Unfrozen items can only grow if we're "
|
||||
"distributing (positive) space with flex-grow");
|
||||
MOZ_ASSERT(aLineInfo->mGrowthState !=
|
||||
ComputedFlexLineInfo::GrowthState::SHRINKING,
|
||||
"shouldn't flip flop from shrinking to growing");
|
||||
aLineInfo->mGrowthState =
|
||||
ComputedFlexLineInfo::GrowthState::GROWING;
|
||||
} else if (deltaSize < 0) {
|
||||
MOZ_ASSERT(!isUsingFlexGrow,
|
||||
"Unfrozen items can only shrink if we're "
|
||||
"distributing (negative) space with flex-shrink");
|
||||
MOZ_ASSERT(aLineInfo->mGrowthState !=
|
||||
ComputedFlexLineInfo::GrowthState::GROWING,
|
||||
"shouldn't flip flop from growing to shrinking");
|
||||
aLineInfo->mGrowthState =
|
||||
ComputedFlexLineInfo::GrowthState::SHRINKING;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -458,11 +458,11 @@ var transformTests = [
|
||||
expected_uncomputed: 'rotate(-22.5deg) translate(5%, 5%) rotate(22.5deg)',
|
||||
round_error_ok: true },
|
||||
// test percent translation using matrix decomposition
|
||||
{ start: 'rotate(45deg) rotate(-45deg)',
|
||||
{ start: 'matrix(1, 0, 0, 1, 0, 0)',
|
||||
end: 'rotate(90deg) translate(20%, 20%) rotate(-90deg)',
|
||||
expected: 'matrix(1, 0, 0, 1, -2.5, 15)',
|
||||
round_error_ok: true },
|
||||
{ start: 'rotate(45deg) rotate(-45deg)',
|
||||
{ start: 'matrix(1, 0, 0, 1, 0, 0)',
|
||||
end: 'rotate(-90deg) translate(20%, 20%) rotate(90deg)',
|
||||
expected: 'matrix(1, 0, 0, 1, 2.5, -15)',
|
||||
round_error_ok: true },
|
||||
|
@ -5913,11 +5913,7 @@ pref("dom.event.default_to_passive_touch_listeners", true);
|
||||
pref("browser.fastblock.timeout", 5000);
|
||||
// The amount of time (ms) since navigation start after which
|
||||
// we'll stop blocking tracker connections (0 = no limit).
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("browser.fastblock.limit", 20000);
|
||||
#else
|
||||
pref("browser.fastblock.limit", 0);
|
||||
#endif
|
||||
|
||||
// Enable clipboard readText() and writeText() by default
|
||||
pref("dom.events.asyncClipboard", true);
|
||||
|
@ -1356,11 +1356,11 @@ fn is_matched_operation(first: &ComputedTransformOperation, second: &ComputedTra
|
||||
&TransformOperation::RotateZ(..)) |
|
||||
(&TransformOperation::Perspective(..),
|
||||
&TransformOperation::Perspective(..)) => true,
|
||||
// we animate scale and translate operations against each other
|
||||
// Match functions that have the same primitive transform function
|
||||
(a, b) if a.is_translate() && b.is_translate() => true,
|
||||
(a, b) if a.is_scale() && b.is_scale() => true,
|
||||
(a, b) if a.is_rotate() && b.is_rotate() => true,
|
||||
// InterpolateMatrix and AccumulateMatrix are for mismatched transform.
|
||||
// InterpolateMatrix and AccumulateMatrix are for mismatched transforms
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
@ -2468,79 +2468,112 @@ impl Animate for ComputedTransform {
|
||||
return Ok(Transform(result));
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-transforms-1/#transform-transform-neutral-extend-animation
|
||||
fn match_operations_if_possible<'a>(
|
||||
this: &mut Cow<'a, Vec<ComputedTransformOperation>>,
|
||||
other: &mut Cow<'a, Vec<ComputedTransformOperation>>,
|
||||
) -> bool {
|
||||
if !this.iter().zip(other.iter()).all(|(this, other)| is_matched_operation(this, other)) {
|
||||
return false;
|
||||
}
|
||||
let this = Cow::Borrowed(&self.0);
|
||||
let other = Cow::Borrowed(&other.0);
|
||||
|
||||
if this.len() == other.len() {
|
||||
return true;
|
||||
}
|
||||
// Interpolate the common prefix
|
||||
let mut result = this
|
||||
.iter()
|
||||
.zip(other.iter())
|
||||
.take_while(|(this, other)| is_matched_operation(this, other))
|
||||
.map(|(this, other)| this.animate(other, procedure))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let (shorter, longer) =
|
||||
if this.len() < other.len() {
|
||||
(this.to_mut(), other)
|
||||
} else {
|
||||
(other.to_mut(), this)
|
||||
};
|
||||
// Deal with the remainders
|
||||
let this_remainder = if this.len() > result.len() {
|
||||
Some(&this[result.len()..])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let other_remainder = if other.len() > result.len() {
|
||||
Some(&other[result.len()..])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
shorter.reserve(longer.len());
|
||||
for op in longer.iter().skip(shorter.len()) {
|
||||
shorter.push(op.to_animated_zero().unwrap());
|
||||
}
|
||||
|
||||
// The resulting operations won't be matched regardless if the
|
||||
// extended component is already InterpolateMatrix /
|
||||
// AccumulateMatrix.
|
||||
//
|
||||
// Otherwise they should be matching operations all the time.
|
||||
let already_mismatched = matches!(
|
||||
longer[0],
|
||||
TransformOperation::InterpolateMatrix { .. } |
|
||||
TransformOperation::AccumulateMatrix { .. }
|
||||
);
|
||||
|
||||
debug_assert_eq!(
|
||||
!already_mismatched,
|
||||
longer.iter().zip(shorter.iter()).all(|(this, other)| is_matched_operation(this, other)),
|
||||
"ToAnimatedZero should generate matched operations"
|
||||
);
|
||||
|
||||
!already_mismatched
|
||||
}
|
||||
|
||||
let mut this = Cow::Borrowed(&self.0);
|
||||
let mut other = Cow::Borrowed(&other.0);
|
||||
|
||||
if match_operations_if_possible(&mut this, &mut other) {
|
||||
return Ok(Transform(
|
||||
this.iter().zip(other.iter())
|
||||
.map(|(this, other)| this.animate(other, procedure))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
));
|
||||
}
|
||||
|
||||
match procedure {
|
||||
Procedure::Add => Err(()),
|
||||
Procedure::Interpolate { progress } => {
|
||||
Ok(Transform(vec![TransformOperation::InterpolateMatrix {
|
||||
from_list: Transform(this.into_owned()),
|
||||
to_list: Transform(other.into_owned()),
|
||||
progress: Percentage(progress as f32),
|
||||
}]))
|
||||
},
|
||||
Procedure::Accumulate { count } => {
|
||||
Ok(Transform(vec![TransformOperation::AccumulateMatrix {
|
||||
from_list: Transform(this.into_owned()),
|
||||
to_list: Transform(other.into_owned()),
|
||||
count: cmp::min(count, i32::max_value() as u64) as i32,
|
||||
}]))
|
||||
match (this_remainder, other_remainder) {
|
||||
// If there is a remainder from *both* lists we must have had mismatched functions.
|
||||
// => Add the remainders to a suitable ___Matrix function.
|
||||
(Some(this_remainder), Some(other_remainder)) => match procedure {
|
||||
Procedure::Add => {
|
||||
debug_assert!(false, "Should have already dealt with add by the point");
|
||||
return Err(());
|
||||
}
|
||||
Procedure::Interpolate { progress } => {
|
||||
result.push(TransformOperation::InterpolateMatrix {
|
||||
from_list: Transform(this_remainder.to_vec()),
|
||||
to_list: Transform(other_remainder.to_vec()),
|
||||
progress: Percentage(progress as f32),
|
||||
});
|
||||
}
|
||||
Procedure::Accumulate { count } => {
|
||||
result.push(TransformOperation::AccumulateMatrix {
|
||||
from_list: Transform(this_remainder.to_vec()),
|
||||
to_list: Transform(other_remainder.to_vec()),
|
||||
count: cmp::min(count, i32::max_value() as u64) as i32,
|
||||
});
|
||||
}
|
||||
},
|
||||
// If there is a remainder from just one list, then one list must be shorter but
|
||||
// completely match the type of the corresponding functions in the longer list.
|
||||
// => Interpolate the remainder with identity transforms.
|
||||
(Some(remainder), None) | (None, Some(remainder)) => {
|
||||
let fill_right = this_remainder.is_some();
|
||||
result.append(
|
||||
&mut remainder
|
||||
.iter()
|
||||
.map(|transform| {
|
||||
let identity = transform.to_animated_zero().unwrap();
|
||||
|
||||
match transform {
|
||||
// We can't interpolate/accumulate ___Matrix types directly with a
|
||||
// matrix. Instead we need to wrap it in another ___Matrix type.
|
||||
TransformOperation::AccumulateMatrix { .. }
|
||||
| TransformOperation::InterpolateMatrix { .. } => {
|
||||
let transform_list = Transform(vec![transform.clone()]);
|
||||
let identity_list = Transform(vec![identity]);
|
||||
let (from_list, to_list) = if fill_right {
|
||||
(transform_list, identity_list)
|
||||
} else {
|
||||
(identity_list, transform_list)
|
||||
};
|
||||
|
||||
match procedure {
|
||||
Procedure::Add => Err(()),
|
||||
Procedure::Interpolate { progress } => {
|
||||
Ok(TransformOperation::InterpolateMatrix {
|
||||
from_list,
|
||||
to_list,
|
||||
progress: Percentage(progress as f32),
|
||||
})
|
||||
}
|
||||
Procedure::Accumulate { count } => {
|
||||
Ok(TransformOperation::AccumulateMatrix {
|
||||
from_list,
|
||||
to_list,
|
||||
count: cmp::min(count, i32::max_value() as u64)
|
||||
as i32,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let (lhs, rhs) = if fill_right {
|
||||
(transform, &identity)
|
||||
} else {
|
||||
(&identity, transform)
|
||||
};
|
||||
lhs.animate(rhs, procedure)
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
);
|
||||
}
|
||||
(None, None) => {}
|
||||
}
|
||||
|
||||
Ok(Transform(result))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ config = {
|
||||
|
||||
"vcs_share_base": "/builds/hg-shared",
|
||||
"version_path": "browser/config/version.txt",
|
||||
"status_path": ".l10n_bumper_status",
|
||||
|
||||
"bump_configs": [{
|
||||
"path": "mobile/locales/l10n-changesets.json",
|
||||
|
@ -22,6 +22,7 @@ config = {
|
||||
|
||||
"vcs_share_base": "/builds/hg-shared",
|
||||
"version_path": "browser/config/version.txt",
|
||||
"status_path": ".l10n_bumper_status",
|
||||
|
||||
"bump_configs": [{
|
||||
"path": "mobile/locales/l10n-changesets.json",
|
||||
|
@ -22,6 +22,7 @@ config = {
|
||||
|
||||
"vcs_share_base": "/builds/hg-shared",
|
||||
"version_path": "browser/config/version.txt",
|
||||
"status_path": ".l10n_bumper_status",
|
||||
|
||||
"bump_configs": [{
|
||||
"path": "mobile/locales/l10n-changesets.json",
|
||||
|
@ -334,6 +334,11 @@ class L10nBumper(VCSScript):
|
||||
else:
|
||||
self.fatal("Didn't complete successfully (hit max_retries)")
|
||||
|
||||
# touch status file for nagios
|
||||
dirs = self.query_abs_dirs()
|
||||
status_path = os.path.join(dirs['base_work_dir'], self.config['status_path'])
|
||||
self._touch_file(status_path)
|
||||
|
||||
|
||||
# __main__ {{{1
|
||||
if __name__ == '__main__':
|
||||
|
@ -0,0 +1,120 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Transform list interpolation</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-transforms-1/#interpolation-of-transforms">
|
||||
<meta name="assert" content="Interpolation of transform function lists is performed as follows">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/interpolation-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
// none -> none
|
||||
test_interpolation(
|
||||
{
|
||||
property: 'transform',
|
||||
from: 'none',
|
||||
to: 'none',
|
||||
},
|
||||
[{ at: 0.25, expect: 'none' }]
|
||||
);
|
||||
|
||||
// none -> something
|
||||
test_interpolation(
|
||||
{
|
||||
property: 'transform',
|
||||
from: 'none',
|
||||
to: 'translate(200px) rotate(720deg)',
|
||||
},
|
||||
[{ at: 0.25, expect: 'translate(50px) rotate(180deg)' }]
|
||||
);
|
||||
|
||||
// something -> none
|
||||
test_interpolation(
|
||||
{
|
||||
property: 'transform',
|
||||
from: 'translate(200px) rotate(720deg)',
|
||||
to: 'none',
|
||||
},
|
||||
[{ at: 0.25, expect: 'translate(150px) rotate(540deg)' }]
|
||||
);
|
||||
|
||||
// Mismatched lengths (from is shorter), common part matches
|
||||
test_interpolation(
|
||||
{
|
||||
property: 'transform',
|
||||
from: 'translate(100px)',
|
||||
to: 'translate(200px) rotate(720deg)',
|
||||
},
|
||||
[{ at: 0.25, expect: 'translate(125px) rotate(180deg)' }]
|
||||
);
|
||||
|
||||
// Mismatched lengths (to is shorter), common part matches
|
||||
test_interpolation(
|
||||
{
|
||||
property: 'transform',
|
||||
from: 'translate(100px) rotate(720deg)',
|
||||
to: 'translate(200px)',
|
||||
},
|
||||
[{ at: 0.25, expect: 'translate(125px) rotate(540deg)' }]
|
||||
);
|
||||
|
||||
// Perfect match
|
||||
test_interpolation(
|
||||
{
|
||||
property: 'transform',
|
||||
from: 'scale(2) rotate(360deg) translate(100px) matrix(1, 0, 0, 1, 100, 0) skew(0deg)',
|
||||
to: 'scale(3) rotate(1080deg) translate(200px) matrix(1, 0, 0, 1, 0, 200) skew(720deg)',
|
||||
},
|
||||
[
|
||||
{
|
||||
at: 0.25,
|
||||
expect: 'scale(2.25) rotate(540deg) translate(125px) matrix(1, 0, 0, 1, 75, 50) skew(180deg)',
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// Matches on primitives
|
||||
test_interpolation(
|
||||
{
|
||||
property: 'transform',
|
||||
from: 'translateX(100px) scaleX(3) translate(500px) scale(2)',
|
||||
to: 'translateY(200px) scale(5) translateX(100px) scaleY(3)',
|
||||
},
|
||||
[{ at: 0.25, expect: 'translate(75px, 50px) scale(3.5, 2) translate(400px, 0px) scale(1.75, 2.25)' }]
|
||||
);
|
||||
|
||||
// Common prefix
|
||||
test_interpolation(
|
||||
{
|
||||
property: 'transform',
|
||||
from: 'rotate(0deg) translate(100px)',
|
||||
to: 'rotate(720deg) scale(2) translate(200px)',
|
||||
},
|
||||
[{ at: 0.25, expect: 'rotate(180deg) matrix(1.25, 0, 0, 1.25, 175, 0)' }]
|
||||
);
|
||||
|
||||
// Complete mismatch (except length)
|
||||
test_interpolation(
|
||||
{
|
||||
property: 'transform',
|
||||
from: 'scale(2) rotate(0deg) translate(100px)',
|
||||
to: 'rotate(720deg) scale(2) translate(200px)',
|
||||
},
|
||||
[{ at: 0.25, expect: 'matrix(2, 0, 0, 2, 250, 0)' }]
|
||||
);
|
||||
|
||||
// Complete mismatch including length
|
||||
test_interpolation(
|
||||
{
|
||||
property: 'transform',
|
||||
from: 'scale(2) rotate(0deg)',
|
||||
to: 'rotate(720deg) scale(2) translate(200px)',
|
||||
},
|
||||
[{ at: 0.25, expect: 'matrix(2, 0, 0, 2, 100, 0)' }]
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1473,7 +1473,7 @@ const transformListType = {
|
||||
Math.cos(Math.PI / 2),
|
||||
100 * Math.cos(Math.PI / 2),
|
||||
100 * Math.sin(Math.PI / 2) ] }]);
|
||||
}, `${property}: rotate on roate and translate`);
|
||||
}, `${property}: rotate on rotate and translate`);
|
||||
|
||||
test(t => {
|
||||
const idlName = propertyToIDL(property);
|
||||
|
@ -14,12 +14,12 @@
|
||||
#include "nsISupports.idl"
|
||||
|
||||
%{ C++
|
||||
class nsDocShellLoadState;
|
||||
class nsDocShellLoadInfo;
|
||||
%}
|
||||
|
||||
interface mozIDOMWindowProxy;
|
||||
interface nsIURI;
|
||||
native nsDocShellLoadStatePtr(nsDocShellLoadState*);
|
||||
native nsDocShellLoadInfoPtr(nsDocShellLoadInfo*);
|
||||
|
||||
/**
|
||||
* The nsIWindowProvider interface exists so that the window watcher's default
|
||||
@ -76,7 +76,7 @@ interface nsIWindowProvider : nsISupports
|
||||
* the feature string to the window it returns in any way it sees fit.
|
||||
* See the nsIWindowWatcher interface for details on feature strings.
|
||||
*
|
||||
* @param aLoadState Specify setup information of the load in the new window
|
||||
* @param aLoadInfo Specify setup information of the load in the new window
|
||||
*
|
||||
* @param aWindowIsNew [out] Whether the window being returned was just
|
||||
* created by the window provider implementation. This can be used by
|
||||
@ -106,6 +106,6 @@ interface nsIWindowProvider : nsISupports
|
||||
in AString aName,
|
||||
in AUTF8String aFeatures,
|
||||
in boolean aForceNoOpener,
|
||||
in nsDocShellLoadStatePtr aLoadState,
|
||||
in nsDocShellLoadInfoPtr aLoadInfo,
|
||||
out boolean aWindowIsNew);
|
||||
};
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "nsISupports.idl"
|
||||
|
||||
%{ C++
|
||||
class nsDocShellLoadState;
|
||||
class nsDocShellLoadInfo;
|
||||
%}
|
||||
|
||||
interface mozIDOMWindowProxy;
|
||||
@ -21,7 +21,7 @@ interface nsIWebBrowserChrome;
|
||||
interface nsIDocShellTreeItem;
|
||||
interface nsIArray;
|
||||
interface nsITabParent;
|
||||
native nsDocShellLoadStatePtr(nsDocShellLoadState*);
|
||||
native nsDocShellLoadInfoPtr(nsDocShellLoadInfo*);
|
||||
|
||||
[uuid(d162f9c4-19d5-4723-931f-f1e51bfa9f68)]
|
||||
|
||||
@ -66,8 +66,8 @@ interface nsPIWindowWatcher : nsISupports
|
||||
looking for existing windows with the given name,
|
||||
not setting an opener on the newly opened window,
|
||||
and returning null from this method.
|
||||
@param aLoadState if aNavigate is true, this allows the caller to pass in
|
||||
an nsIDocShellLoadState to use for the navigation.
|
||||
@param aLoadInfo if aNavigate is true, this allows the caller to pass in
|
||||
an nsIDocShellLoadInfo to use for the navigation.
|
||||
Callers can pass in null if they want the windowwatcher
|
||||
to just construct a loadinfo itself. If aNavigate is
|
||||
false, this argument is ignored.
|
||||
@ -90,7 +90,7 @@ interface nsPIWindowWatcher : nsISupports
|
||||
in nsISupports aArgs,
|
||||
in boolean aIsPopupSpam,
|
||||
in boolean aForceNoOpener,
|
||||
in nsDocShellLoadStatePtr aLoadState);
|
||||
in nsDocShellLoadInfoPtr aLoadInfo);
|
||||
|
||||
/**
|
||||
* Opens a new window so that the window that aOpeningTab belongs to
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIBrowserDOMWindow.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIDocShellTreeOwner.h"
|
||||
#include "nsIDocumentLoader.h"
|
||||
@ -325,7 +325,7 @@ nsWindowWatcher::OpenWindow(mozIDOMWindowProxy* aParent,
|
||||
/* navigate = */ true, argv,
|
||||
/* aIsPopupSpam = */ false,
|
||||
/* aForceNoOpener = */ false,
|
||||
/* aLoadState = */ nullptr,
|
||||
/* aLoadInfo = */ nullptr,
|
||||
aResult);
|
||||
}
|
||||
|
||||
@ -391,7 +391,7 @@ nsWindowWatcher::OpenWindow2(mozIDOMWindowProxy* aParent,
|
||||
nsISupports* aArguments,
|
||||
bool aIsPopupSpam,
|
||||
bool aForceNoOpener,
|
||||
nsDocShellLoadState* aLoadState,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
mozIDOMWindowProxy** aResult)
|
||||
{
|
||||
nsCOMPtr<nsIArray> argv = ConvertArgsToArray(aArguments);
|
||||
@ -412,7 +412,7 @@ nsWindowWatcher::OpenWindow2(mozIDOMWindowProxy* aParent,
|
||||
return OpenWindowInternal(aParent, aUrl, aName, aFeatures,
|
||||
aCalledFromScript, dialog,
|
||||
aNavigate, argv, aIsPopupSpam,
|
||||
aForceNoOpener, aLoadState, aResult);
|
||||
aForceNoOpener, aLoadInfo, aResult);
|
||||
}
|
||||
|
||||
// This static function checks if the aDocShell uses an UserContextId equal to
|
||||
@ -637,7 +637,7 @@ nsWindowWatcher::OpenWindowInternal(mozIDOMWindowProxy* aParent,
|
||||
nsIArray* aArgv,
|
||||
bool aIsPopupSpam,
|
||||
bool aForceNoOpener,
|
||||
nsDocShellLoadState* aLoadState,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
mozIDOMWindowProxy** aResult)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
@ -821,7 +821,7 @@ nsWindowWatcher::OpenWindowInternal(mozIDOMWindowProxy* aParent,
|
||||
sizeSpec.PositionSpecified(),
|
||||
sizeSpec.SizeSpecified(),
|
||||
uriToLoad, name, features, aForceNoOpener,
|
||||
aLoadState, &windowIsNew,
|
||||
aLoadInfo, &windowIsNew,
|
||||
getter_AddRefs(newWindow));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
@ -1118,12 +1118,12 @@ nsWindowWatcher::OpenWindowInternal(mozIDOMWindowProxy* aParent,
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<nsDocShellLoadState> loadState = aLoadState;
|
||||
if (uriToLoad && aNavigate && !loadState) {
|
||||
loadState = new nsDocShellLoadState();
|
||||
RefPtr<nsDocShellLoadInfo> loadInfo = aLoadInfo;
|
||||
if (uriToLoad && aNavigate && !loadInfo) {
|
||||
loadInfo = new nsDocShellLoadInfo();
|
||||
|
||||
if (subjectPrincipal) {
|
||||
loadState->SetTriggeringPrincipal(subjectPrincipal);
|
||||
loadInfo->SetTriggeringPrincipal(subjectPrincipal);
|
||||
}
|
||||
|
||||
/* use the URL from the *extant* document, if any. The usual accessor
|
||||
@ -1138,8 +1138,8 @@ nsWindowWatcher::OpenWindowInternal(mozIDOMWindowProxy* aParent,
|
||||
}
|
||||
if (doc) {
|
||||
// Set the referrer
|
||||
loadState->SetReferrer(doc->GetDocumentURI());
|
||||
loadState->SetReferrerPolicy(doc->GetReferrerPolicy());
|
||||
loadInfo->SetReferrer(doc->GetDocumentURI());
|
||||
loadInfo->SetReferrerPolicy(doc->GetReferrerPolicy());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1181,13 +1181,13 @@ nsWindowWatcher::OpenWindowInternal(mozIDOMWindowProxy* aParent,
|
||||
}
|
||||
|
||||
if (uriToLoad && aNavigate) {
|
||||
loadState->SetURI(uriToLoad);
|
||||
loadState->SetLoadFlags(windowIsNew ?
|
||||
newDocShell->LoadURI(
|
||||
uriToLoad,
|
||||
loadInfo,
|
||||
windowIsNew ?
|
||||
static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) :
|
||||
static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_NONE));
|
||||
loadState->SetFirstParty(true);
|
||||
// Should this pay attention to errors returned by LoadURI?
|
||||
newDocShell->LoadURI(loadState);
|
||||
static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_NONE),
|
||||
true);
|
||||
}
|
||||
|
||||
// Copy the current session storage for the current domain. Don't perform the
|
||||
|
@ -88,7 +88,7 @@ protected:
|
||||
nsIArray* aArgv,
|
||||
bool aIsPopupSpam,
|
||||
bool aForceNoOpener,
|
||||
nsDocShellLoadState* aLoadState,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
mozIDOMWindowProxy** aResult);
|
||||
|
||||
static nsresult URIfromURL(const char* aURL,
|
||||
|
@ -257,11 +257,14 @@ public:
|
||||
// null-terminated.
|
||||
bool NS_FASTCALL EqualsASCII(const char* aData) const;
|
||||
|
||||
// EqualsLiteral must ONLY be applied to an actual literal string, or
|
||||
// a char array *constant* declared without an explicit size.
|
||||
// Do not attempt to use it with a regular char* pointer, or with a
|
||||
// non-constant char array variable. Use EqualsASCII for them.
|
||||
// The template trick to acquire the array length at compile time without
|
||||
// EqualsLiteral must ONLY be called with an actual literal string, or
|
||||
// a char array *constant* declared without an explicit size and with an
|
||||
// initializer that is a string literal or is otherwise null-terminated.
|
||||
// Use EqualsASCII for other char array variables.
|
||||
// (Although this method may happen to produce expected results for other
|
||||
// char arrays that have bound one greater than the sequence of interest,
|
||||
// such use is discouraged for reasons of readability and maintainability.)
|
||||
// The template trick to acquire the array bound at compile time without
|
||||
// using a macro is due to Corey Kosak, with much thanks.
|
||||
template<int N>
|
||||
inline bool EqualsLiteral(const char (&aStr)[N]) const
|
||||
@ -279,11 +282,13 @@ public:
|
||||
size_type aLen) const;
|
||||
bool NS_FASTCALL LowerCaseEqualsASCII(const char* aData) const;
|
||||
|
||||
// LowerCaseEqualsLiteral must ONLY be applied to an actual
|
||||
// literal string, or a char array *constant* declared without an
|
||||
// explicit size. Do not attempt to use it with a regular char*
|
||||
// pointer, or with a non-constant char array variable. Use
|
||||
// LowerCaseEqualsASCII for them.
|
||||
// LowerCaseEqualsLiteral must ONLY be called with an actual literal string,
|
||||
// or a char array *constant* declared without an explicit size and with an
|
||||
// initializer that is a string literal or is otherwise null-terminated.
|
||||
// Use LowerCaseEqualsASCII for other char array variables.
|
||||
// (Although this method may happen to produce expected results for other
|
||||
// char arrays that have bound one greater than the sequence of interest,
|
||||
// such use is discouraged for reasons of readability and maintainability.)
|
||||
template<int N>
|
||||
bool LowerCaseEqualsLiteral(const char (&aStr)[N]) const
|
||||
{
|
||||
|
@ -473,10 +473,11 @@ public:
|
||||
aFallible);
|
||||
}
|
||||
|
||||
// AssignLiteral must ONLY be applied to an actual literal string, or
|
||||
// a character array *constant* declared without an explicit size.
|
||||
// Do not attempt to use it with a regular character pointer, or with a
|
||||
// non-constant chararacter array variable. Use AssignASCII for those.
|
||||
// AssignLiteral must ONLY be called with an actual literal string, or
|
||||
// a character array *constant* of static storage duration declared
|
||||
// without an explicit size and with an initializer that is a string
|
||||
// literal or is otherwise null-terminated.
|
||||
// Use Assign or AssignASCII for other character array variables.
|
||||
//
|
||||
// This method does not need a fallible version, because it uses the
|
||||
// POD buffer of the literal as the string's buffer without allocating.
|
||||
@ -489,10 +490,10 @@ public:
|
||||
AssignLiteral(aStr, N - 1);
|
||||
}
|
||||
|
||||
// AssignLiteral must ONLY be applied to an actual literal string, or
|
||||
// a character array *constant* declared without an explicit size.
|
||||
// Do not attempt to use it with a regular character pointer, or with a
|
||||
// non-constant chararacter array variable. Use AssignASCII for those.
|
||||
// AssignLiteral must ONLY be called with an actual literal string, or
|
||||
// a char array *constant* declared without an explicit size and with an
|
||||
// initializer that is a string literal or is otherwise null-terminated.
|
||||
// Use AssignASCII for other char array variables.
|
||||
//
|
||||
// This method takes an 8-bit (ASCII-only!) string that is expanded
|
||||
// into a 16-bit string at run time causing a run-time allocation.
|
||||
@ -592,9 +593,11 @@ public:
|
||||
size_type aLength,
|
||||
const fallible_t&);
|
||||
|
||||
// ReplaceLiteral must ONLY be applied to an actual literal string.
|
||||
// Do not attempt to use it with a regular char* pointer, or with a char
|
||||
// array variable. Use Replace or ReplaceASCII for those.
|
||||
// ReplaceLiteral must ONLY be called with an actual literal string, or
|
||||
// a character array *constant* of static storage duration declared
|
||||
// without an explicit size and with an initializer that is a string
|
||||
// literal or is otherwise null-terminated.
|
||||
// Use Replace or ReplaceASCII for other character array variables.
|
||||
template<int N>
|
||||
void ReplaceLiteral(index_type aCutStart, size_type aCutLength,
|
||||
const char_type (&aStr)[N])
|
||||
@ -640,9 +643,11 @@ public:
|
||||
// Appends a literal string ("" literal in the 8-bit case and u"" literal
|
||||
// in the 16-bit case) to the string.
|
||||
//
|
||||
// AppendLiteral must ONLY be applied to an actual literal string.
|
||||
// Do not attempt to use it with a regular character pointer, or with a
|
||||
// character array variable. Use Append or AppendASCII for those.
|
||||
// AppendLiteral must ONLY be called with an actual literal string, or
|
||||
// a character array *constant* of static storage duration declared
|
||||
// without an explicit size and with an initializer that is a string
|
||||
// literal or is otherwise null-terminated.
|
||||
// Use Append or AppendASCII for other character array variables.
|
||||
template<int N>
|
||||
void AppendLiteral(const char_type (&aStr)[N])
|
||||
{
|
||||
@ -801,9 +806,11 @@ public:
|
||||
Replace(aPos, 0, aTuple);
|
||||
}
|
||||
|
||||
// InsertLiteral must ONLY be applied to an actual literal string.
|
||||
// Do not attempt to use it with a regular char* pointer, or with a char
|
||||
// array variable. Use Insert for those.
|
||||
// InsertLiteral must ONLY be called with an actual literal string, or
|
||||
// a character array *constant* of static storage duration declared
|
||||
// without an explicit size and with an initializer that is a string
|
||||
// literal or is otherwise null-terminated.
|
||||
// Use Insert for other character array variables.
|
||||
template<int N>
|
||||
void InsertLiteral(const char_type (&aStr)[N], index_type aPos)
|
||||
{
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include "nsWindowWatcher.h"
|
||||
#include "mozilla/BrowserElementParent.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsDocShellLoadInfo.h"
|
||||
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIURI.h"
|
||||
@ -766,7 +766,7 @@ nsContentTreeOwner::ProvideWindow(mozIDOMWindowProxy* aParent,
|
||||
const nsAString& aName,
|
||||
const nsACString& aFeatures,
|
||||
bool aForceNoOpener,
|
||||
nsDocShellLoadState* aLoadState,
|
||||
nsDocShellLoadInfo* aLoadInfo,
|
||||
bool* aWindowIsNew,
|
||||
mozIDOMWindowProxy** aReturn)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user