зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
b24799980a
|
@ -1208,6 +1208,16 @@ pref("dom.ipc.shims.enabledWarnings", false);
|
|||
// content process is killed when all windows are closed, so a change will
|
||||
// take effect when the 1st window is opened.
|
||||
pref("security.sandbox.content.level", 3);
|
||||
|
||||
// Disconnect content processes from the window server. Depends on
|
||||
// out-of-process WebGL and non-native theming. i.e., both in-process WebGL
|
||||
// and native theming depend on content processes having a connection to the
|
||||
// window server. Window server disconnection is automatically disabled (and
|
||||
// this pref overridden) if OOP WebGL is disabled. OOP WebGL is disabled
|
||||
// for some tests.
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
pref("security.sandbox.content.mac.disconnect-windowserver", true);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||
|
|
|
@ -1349,15 +1349,6 @@ toolbarpaletteitem:not([place="palette"]) > #stop-reload-button {
|
|||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
/* This effectively simulates a focus outline. */
|
||||
#UITourHighlight[active="focus-outline"] {
|
||||
background-color: transparent;
|
||||
border: 2px solid var(--focus-outline-color);
|
||||
border-radius: 4px;
|
||||
|
||||
animation-name: none;
|
||||
}
|
||||
|
||||
/* Combined context-menu items */
|
||||
#context-navigation > .menuitem-iconic > .menu-iconic-text,
|
||||
#context-navigation > .menuitem-iconic > .menu-accel-container {
|
||||
|
|
|
@ -89,7 +89,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
TelemetryUtils: "resource://gre/modules/TelemetryUtils.jsm",
|
||||
TRRRacer: "resource:///modules/TRRPerformance.jsm",
|
||||
UIState: "resource://services-sync/UIState.jsm",
|
||||
UITour: "resource:///modules/UITour.jsm",
|
||||
UrlbarQuickSuggest: "resource:///modules/UrlbarQuickSuggest.jsm",
|
||||
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
|
||||
WebChannel: "resource://gre/modules/WebChannel.jsm",
|
||||
|
@ -2189,6 +2188,39 @@ BrowserGlue.prototype = {
|
|||
Services.wm.addListener(windowListener);
|
||||
},
|
||||
|
||||
_monitorGPCPref() {
|
||||
const FEATURE_PREF_ENABLED = "privacy.globalprivacycontrol.enabled";
|
||||
const FUNCTIONALITY_PREF_ENABLED =
|
||||
"privacy.globalprivacycontrol.functionality.enabled";
|
||||
const PREF_WAS_ENABLED = "privacy.globalprivacycontrol.was_ever_enabled";
|
||||
const _checkGPCPref = async () => {
|
||||
const feature_enabled = Services.prefs.getBoolPref(
|
||||
FEATURE_PREF_ENABLED,
|
||||
false
|
||||
);
|
||||
const functionality_enabled = Services.prefs.getBoolPref(
|
||||
FUNCTIONALITY_PREF_ENABLED,
|
||||
false
|
||||
);
|
||||
const was_enabled = Services.prefs.getBoolPref(PREF_WAS_ENABLED, false);
|
||||
let value = 0;
|
||||
if (feature_enabled && functionality_enabled) {
|
||||
value = 1;
|
||||
Services.prefs.setBoolPref(PREF_WAS_ENABLED, true);
|
||||
} else if (was_enabled) {
|
||||
value = 2;
|
||||
}
|
||||
Services.telemetry.scalarSet(
|
||||
"security.global_privacy_control_enabled",
|
||||
value
|
||||
);
|
||||
};
|
||||
|
||||
Services.prefs.addObserver(FEATURE_PREF_ENABLED, _checkGPCPref);
|
||||
Services.prefs.addObserver(FUNCTIONALITY_PREF_ENABLED, _checkGPCPref);
|
||||
_checkGPCPref();
|
||||
},
|
||||
|
||||
// All initial windows have opened.
|
||||
_onWindowsRestored: function BG__onWindowsRestored() {
|
||||
if (this._windowsWereRestored) {
|
||||
|
@ -2266,6 +2298,7 @@ BrowserGlue.prototype = {
|
|||
if (AppConstants.NIGHTLY_BUILD) {
|
||||
this._monitorTranslationsPref();
|
||||
}
|
||||
this._monitorGPCPref();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -4071,11 +4104,10 @@ BrowserGlue.prototype = {
|
|||
{
|
||||
"l10n-id": "restore-session-startup-suggestion-button",
|
||||
callback: () => {
|
||||
UITour.getTarget(win, "history").then(historyMenu => {
|
||||
UITour.showHighlight(win, historyMenu, "focus-outline", {
|
||||
autohide: true,
|
||||
});
|
||||
});
|
||||
win.PanelUI.selectAndMarkItem([
|
||||
"appMenu-history-button",
|
||||
"appMenu-restoreSession",
|
||||
]);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
@ -1216,7 +1216,11 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
currentView.keyNavigation(aEvent);
|
||||
break;
|
||||
case "mousemove":
|
||||
this.openViews.forEach(panelView => panelView.clearNavigation());
|
||||
this.openViews.forEach(panelView => {
|
||||
if (!panelView.ignoreMouseMove) {
|
||||
panelView.clearNavigation();
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "popupshowing": {
|
||||
this._viewContainer.setAttribute("panelopen", "true");
|
||||
|
@ -1807,6 +1811,8 @@ var PanelView = class extends AssociatedToNode {
|
|||
return popup && popup.state == "open";
|
||||
};
|
||||
|
||||
this.ignoreMouseMove = false;
|
||||
|
||||
let keyCode = event.code;
|
||||
switch (keyCode) {
|
||||
case "ArrowDown":
|
||||
|
|
|
@ -717,6 +717,87 @@ const PanelUI = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Selects and marks an item by id from the main view. The ids are an array,
|
||||
* the first in the main view and the later ids in subsequent subviews that
|
||||
* become marked when the user opens the subview. The subview marking is
|
||||
* cancelled if a different subview is opened.
|
||||
*/
|
||||
async selectAndMarkItem(itemIds) {
|
||||
// This shouldn't really occur, but return early just in case.
|
||||
if (document.documentElement.hasAttribute("customizing")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This function was triggered from a button while the menu was
|
||||
// already open, so the panel should be in the process of hiding.
|
||||
// Wait for the panel to hide first, then reopen it.
|
||||
if (this.panel.state == "hiding") {
|
||||
await new Promise(resolve => {
|
||||
this.panel.addEventListener("popuphidden", resolve, { once: true });
|
||||
});
|
||||
}
|
||||
|
||||
if (this.panel.state != "open") {
|
||||
await new Promise(resolve => {
|
||||
this.panel.addEventListener("ViewShown", resolve, { once: true });
|
||||
this.show();
|
||||
});
|
||||
}
|
||||
|
||||
let currentView;
|
||||
|
||||
let viewShownCB = event => {
|
||||
viewHidingCB();
|
||||
|
||||
if (itemIds.length) {
|
||||
let subItem = window.document.getElementById(itemIds[0]);
|
||||
if (event.target.id == subItem?.closest("panelview")?.id) {
|
||||
Services.tm.dispatchToMainThread(() => {
|
||||
markItem(event.target);
|
||||
});
|
||||
} else {
|
||||
itemIds = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let viewHidingCB = () => {
|
||||
if (currentView) {
|
||||
currentView.ignoreMouseMove = false;
|
||||
}
|
||||
currentView = null;
|
||||
};
|
||||
|
||||
let popupHiddenCB = () => {
|
||||
viewHidingCB();
|
||||
this.panel.removeEventListener("ViewShown", viewShownCB);
|
||||
};
|
||||
|
||||
let markItem = viewNode => {
|
||||
let id = itemIds.shift();
|
||||
let item = window.document.getElementById(id);
|
||||
item.setAttribute("tabindex", "-1");
|
||||
|
||||
currentView = PanelView.forNode(viewNode);
|
||||
currentView.selectedElement = item;
|
||||
currentView.focusSelectedElement(true);
|
||||
|
||||
// Prevent the mouse from changing the highlight temporarily.
|
||||
// This flag gets removed when the view is hidden or a key
|
||||
// is pressed.
|
||||
currentView.ignoreMouseMove = true;
|
||||
|
||||
if (itemIds.length) {
|
||||
this.panel.addEventListener("ViewShown", viewShownCB, { once: true });
|
||||
}
|
||||
this.panel.addEventListener("ViewHiding", viewHidingCB, { once: true });
|
||||
};
|
||||
|
||||
this.panel.addEventListener("popuphidden", popupHiddenCB, { once: true });
|
||||
markItem(this.mainView);
|
||||
},
|
||||
|
||||
updateNotifications(notificationsChanged) {
|
||||
let notifications = this._notifications;
|
||||
if (!notifications || !notifications.length) {
|
||||
|
|
|
@ -63,9 +63,9 @@ var gDownloadElementButtons = {
|
|||
},
|
||||
show: {
|
||||
commandName: "downloadsCmd_show",
|
||||
l10nId: "downloads-cmd-show-button",
|
||||
descriptionL10nId: "downloads-cmd-show-description",
|
||||
panelL10nId: "downloads-cmd-show-panel",
|
||||
l10nId: "downloads-cmd-show-button-2",
|
||||
descriptionL10nId: "downloads-cmd-show-description-2",
|
||||
panelL10nId: "downloads-cmd-show-panel-2",
|
||||
iconClass: "downloadIconShow",
|
||||
},
|
||||
subviewOpenOrRemoveFile: {
|
||||
|
|
|
@ -22,12 +22,7 @@
|
|||
data-l10n-id="downloads-cmd-always-use-system-default"/>
|
||||
<menuitem command="downloadsCmd_show"
|
||||
class="downloadShowMenuItem"
|
||||
#ifdef XP_MACOSX
|
||||
data-l10n-id="downloads-cmd-show-menuitem-mac"
|
||||
#else
|
||||
data-l10n-id="downloads-cmd-show-menuitem"
|
||||
#endif
|
||||
/>
|
||||
data-l10n-id="downloads-cmd-show-menuitem-2"/>
|
||||
|
||||
<menuseparator class="downloadCommandsSeparator"/>
|
||||
|
||||
|
|
|
@ -85,12 +85,7 @@
|
|||
data-l10n-id="downloads-cmd-always-use-system-default"/>
|
||||
<menuitem command="downloadsCmd_show"
|
||||
class="downloadShowMenuItem"
|
||||
#ifdef XP_MACOSX
|
||||
data-l10n-id="downloads-cmd-show-menuitem-mac"
|
||||
#else
|
||||
data-l10n-id="downloads-cmd-show-menuitem"
|
||||
#endif
|
||||
/>
|
||||
data-l10n-id="downloads-cmd-show-menuitem-2"/>
|
||||
|
||||
<menuseparator class="downloadCommandsSeparator"/>
|
||||
|
||||
|
|
|
@ -98,6 +98,8 @@ skip-if = (webrender && debug) # bug 1553577
|
|||
[browser_ext_contentscript_in_parent.js]
|
||||
[browser_ext_contentscript_incognito.js]
|
||||
[browser_ext_contentscript_nontab_connect.js]
|
||||
[browser_ext_contentscript_sender_url.js]
|
||||
skip-if = debug # The nature of the reduced STR test triggers an unrelated debug assertion in DOM IPC code, see bug 1736590.
|
||||
[browser_ext_contextMenus.js]
|
||||
support-files = !/browser/components/places/tests/browser/head.js
|
||||
[browser_ext_contextMenus_checkboxes.js]
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(async function test_sender_url() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
content_scripts: [
|
||||
{
|
||||
matches: ["http://mochi.test/*"],
|
||||
run_at: "document_start",
|
||||
js: ["script.js"],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
background() {
|
||||
browser.runtime.onMessage.addListener((msg, sender) => {
|
||||
browser.test.log("Message received.");
|
||||
browser.test.sendMessage("sender.url", sender.url);
|
||||
});
|
||||
},
|
||||
|
||||
files: {
|
||||
"script.js"() {
|
||||
browser.test.log("Content script loaded.");
|
||||
browser.runtime.sendMessage(0);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const image =
|
||||
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/ctxmenu-image.png";
|
||||
|
||||
// Bug is only visible and test only works without Fission,
|
||||
// or with Fission but without BFcache in parent.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["fission.bfcacheInParent", false]],
|
||||
});
|
||||
|
||||
function awaitNewTab() {
|
||||
return BrowserTestUtils.waitForLocationChange(gBrowser, "about:newtab");
|
||||
}
|
||||
|
||||
await extension.startup();
|
||||
|
||||
await BrowserTestUtils.withNewTab({ gBrowser }, async browser => {
|
||||
let newTab = awaitNewTab();
|
||||
BrowserTestUtils.loadURI(browser, "about:newtab");
|
||||
await newTab;
|
||||
|
||||
BrowserTestUtils.loadURI(browser, image);
|
||||
let url = await extension.awaitMessage("sender.url");
|
||||
is(url, image, `Correct sender.url: ${url}`);
|
||||
|
||||
let wentBack = awaitNewTab();
|
||||
await browser.goBack();
|
||||
await wentBack;
|
||||
|
||||
await browser.goForward();
|
||||
url = await extension.awaitMessage("sender.url");
|
||||
is(url, image, `Correct sender.url: ${url}`);
|
||||
});
|
||||
|
||||
await extension.unload();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -14,6 +14,7 @@ function openPermissionPopup() {
|
|||
event => event.target == gPermissionPanel._permissionPopup
|
||||
);
|
||||
gPermissionPanel._identityPermissionBox.click();
|
||||
info("Wait permission popup to be shown");
|
||||
return promise;
|
||||
}
|
||||
|
||||
|
@ -23,6 +24,7 @@ function closePermissionPopup() {
|
|||
"popuphidden"
|
||||
);
|
||||
gPermissionPanel._permissionPopup.hidePopup();
|
||||
info("Wait permission popup to be hidden");
|
||||
return promise;
|
||||
}
|
||||
|
||||
|
@ -67,21 +69,25 @@ async function testPermissionPopup({ expectPermissionHidden }) {
|
|||
add_task(async function testPersistentStoragePermissionHidden() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background() {
|
||||
browser.test.sendMessage("url", browser.runtime.getURL("icon.png"));
|
||||
browser.test.sendMessage("url", browser.runtime.getURL("testpage.html"));
|
||||
},
|
||||
manifest: {
|
||||
name: "Test Extension",
|
||||
permissions: ["unlimitedStorage"],
|
||||
},
|
||||
files: {
|
||||
"icon.png": "",
|
||||
"testpage.html": "<h1>Extension Test Page</h1>",
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
|
||||
let url = await extension.awaitMessage("url");
|
||||
await BrowserTestUtils.withNewTab({ gBrowser, url }, async function() {
|
||||
await BrowserTestUtils.withNewTab("about:blank", async browser => {
|
||||
// Wait the tab to be fully loade, then run the test on the permission prompt.
|
||||
let loaded = BrowserTestUtils.browserLoaded(browser, false, url);
|
||||
BrowserTestUtils.loadURI(browser, url);
|
||||
await loaded;
|
||||
await testPermissionPopup({ expectPermissionHidden: true });
|
||||
});
|
||||
|
||||
|
@ -91,13 +97,13 @@ add_task(async function testPersistentStoragePermissionHidden() {
|
|||
add_task(async function testPersistentStoragePermissionVisible() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background() {
|
||||
browser.test.sendMessage("url", browser.runtime.getURL("icon.png"));
|
||||
browser.test.sendMessage("url", browser.runtime.getURL("testpage.html"));
|
||||
},
|
||||
manifest: {
|
||||
name: "Test Extension",
|
||||
},
|
||||
files: {
|
||||
"icon.png": "",
|
||||
"testpage.html": "<h1>Extension Test Page</h1>",
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -113,7 +119,11 @@ add_task(async function testPersistentStoragePermissionVisible() {
|
|||
Services.perms.ALLOW_ACTION
|
||||
);
|
||||
|
||||
await BrowserTestUtils.withNewTab({ gBrowser, url }, async function() {
|
||||
await BrowserTestUtils.withNewTab("about:blank", async browser => {
|
||||
// Wait the tab to be fully loade, then run the test on the permission prompt.
|
||||
let loaded = BrowserTestUtils.browserLoaded(browser, false, url);
|
||||
BrowserTestUtils.loadURI(browser, url);
|
||||
await loaded;
|
||||
await testPermissionPopup({ expectPermissionHidden: false });
|
||||
});
|
||||
|
||||
|
|
|
@ -63,6 +63,16 @@
|
|||
"name": "prefval",
|
||||
"condition": "pref",
|
||||
"pref": "code"
|
||||
},
|
||||
{
|
||||
"name": "experimenter-1",
|
||||
"condition": "pref",
|
||||
"pref": "nimbus-key-1"
|
||||
},
|
||||
{
|
||||
"name": "experimenter-2",
|
||||
"condition": "pref",
|
||||
"pref": "nimbus-key-2"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
|
||||
const { SearchTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/SearchTestUtils.jsm"
|
||||
);
|
||||
const { NimbusFeatures } = ChromeUtils.import(
|
||||
"resource://nimbus/ExperimentAPI.jsm"
|
||||
);
|
||||
const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm");
|
||||
|
||||
AddonTestUtils.init(this);
|
||||
AddonTestUtils.overrideCertDB();
|
||||
|
@ -50,6 +53,8 @@ const params = [
|
|||
];
|
||||
|
||||
add_task(async function setup() {
|
||||
let readyStub = sinon.stub(NimbusFeatures.search, "ready").resolves();
|
||||
let updateStub = sinon.stub(NimbusFeatures.search, "onUpdate");
|
||||
await promiseStartupManager();
|
||||
await SearchTestUtils.useTestEngines("data", null, [
|
||||
{
|
||||
|
@ -67,6 +72,8 @@ add_task(async function setup() {
|
|||
await Services.search.init();
|
||||
registerCleanupFunction(async () => {
|
||||
await promiseShutdownManager();
|
||||
readyStub.restore();
|
||||
updateStub.restore();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -105,6 +112,81 @@ add_task(async function test_extension_setting_moz_params() {
|
|||
"search url is expected"
|
||||
);
|
||||
}
|
||||
|
||||
defaultBranch.setCharPref("param.code", "");
|
||||
});
|
||||
|
||||
add_task(async function test_nimbus_params() {
|
||||
let sandbox = sinon.createSandbox();
|
||||
let stub = sandbox.stub(NimbusFeatures.search, "getVariable");
|
||||
// These values should match the nimbusParams below and the data/test/manifest.json
|
||||
// search engine configuration
|
||||
stub.withArgs("extraParams").returns([
|
||||
{
|
||||
key: "nimbus-key-1",
|
||||
value: "nimbus-value-1",
|
||||
},
|
||||
{
|
||||
key: "nimbus-key-2",
|
||||
value: "nimbus-value-2",
|
||||
},
|
||||
]);
|
||||
|
||||
Assert.ok(
|
||||
NimbusFeatures.search.onUpdate.called,
|
||||
"Called to initialize the cache"
|
||||
);
|
||||
|
||||
// Populate the cache with the `getVariable` mock values
|
||||
NimbusFeatures.search.onUpdate.firstCall.args[0]();
|
||||
|
||||
let engine = Services.search.getEngineByName("MozParamsTest");
|
||||
|
||||
// Note: these lists should be kept in sync with the lists in
|
||||
// browser/components/extensions/test/xpcshell/data/test/manifest.json
|
||||
// These params are conditional based on how search is initiated.
|
||||
const nimbusParams = [
|
||||
{ name: "experimenter-1", condition: "pref", pref: "nimbus-key-1" },
|
||||
{ name: "experimenter-2", condition: "pref", pref: "nimbus-key-2" },
|
||||
];
|
||||
const experimentCache = {
|
||||
"nimbus-key-1": "nimbus-value-1",
|
||||
"nimbus-key-2": "nimbus-value-2",
|
||||
};
|
||||
|
||||
let extraParams = [];
|
||||
for (let p of params) {
|
||||
if (p.value == "{searchTerms}") {
|
||||
extraParams.push(`${p.name}=test`);
|
||||
} else if (p.value == "{language}") {
|
||||
extraParams.push(`${p.name}=${Services.locale.requestedLocale || "*"}`);
|
||||
} else if (p.value == "{moz:locale}") {
|
||||
extraParams.push(`${p.name}=${Services.locale.requestedLocale}`);
|
||||
} else if (p.condition !== "pref") {
|
||||
// Ignoring pref parameters
|
||||
extraParams.push(`${p.name}=${p.value}`);
|
||||
}
|
||||
}
|
||||
for (let p of nimbusParams) {
|
||||
if (p.condition == "pref") {
|
||||
extraParams.push(`${p.name}=${experimentCache[p.pref]}`);
|
||||
}
|
||||
}
|
||||
let paramStr = extraParams.join("&");
|
||||
for (let p of mozParams) {
|
||||
let expectedURL = engine.getSubmission(
|
||||
"test",
|
||||
null,
|
||||
p.condition == "purpose" ? p.purpose : null
|
||||
).uri.spec;
|
||||
equal(
|
||||
expectedURL,
|
||||
`https://example.com/?q=test&${p.name}=${p.value}&${paramStr}`,
|
||||
"search url is expected"
|
||||
);
|
||||
}
|
||||
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_extension_setting_moz_params_fail() {
|
||||
|
|
|
@ -16,7 +16,7 @@ const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm");
|
|||
|
||||
add_task(async function test_engines_reloaded_nimbus() {
|
||||
let reloadSpy = sinon.spy(SearchService.prototype, "_maybeReloadEngines");
|
||||
let variableSpy = sinon.spy(NimbusFeatures.search, "getVariable");
|
||||
let getVariableSpy = sinon.spy(NimbusFeatures.search, "getVariable");
|
||||
|
||||
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
|
||||
featureId: "search",
|
||||
|
@ -25,18 +25,21 @@ add_task(async function test_engines_reloaded_nimbus() {
|
|||
|
||||
Assert.equal(reloadSpy.callCount, 1, "Called by experiment enrollment");
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() => variableSpy.called,
|
||||
() => getVariableSpy.calledWith("experiment"),
|
||||
"Wait for SearchService update to run"
|
||||
);
|
||||
Assert.equal(
|
||||
variableSpy.callCount,
|
||||
1,
|
||||
"Called by update function to fetch engines"
|
||||
getVariableSpy.callCount,
|
||||
2,
|
||||
"Called by update function to fetch engines and by ParamPreferenceCache"
|
||||
);
|
||||
Assert.equal(
|
||||
variableSpy.firstCall.args[0],
|
||||
"experiment",
|
||||
"Got `experiment` variable value"
|
||||
Assert.ok(
|
||||
getVariableSpy.calledWith("extraParams"),
|
||||
"Called by ParamPreferenceCache listener"
|
||||
);
|
||||
Assert.ok(
|
||||
getVariableSpy.calledWith("experiment"),
|
||||
"Called by search service observer"
|
||||
);
|
||||
Assert.equal(
|
||||
NimbusFeatures.search.getVariable("experiment"),
|
||||
|
@ -49,5 +52,5 @@ add_task(async function test_engines_reloaded_nimbus() {
|
|||
Assert.equal(reloadSpy.callCount, 2, "Called by experiment unenrollment");
|
||||
|
||||
reloadSpy.restore();
|
||||
variableSpy.restore();
|
||||
getVariableSpy.restore();
|
||||
});
|
||||
|
|
|
@ -151,14 +151,6 @@ var UITour = {
|
|||
},
|
||||
],
|
||||
["help", { query: "#appMenu-help-button2" }],
|
||||
[
|
||||
"history",
|
||||
{
|
||||
query: "#appMenu-history-button",
|
||||
subItem: "restorePreviousSession",
|
||||
level: "top",
|
||||
},
|
||||
],
|
||||
["home", { query: "#home-button" }],
|
||||
[
|
||||
"logins",
|
||||
|
@ -186,7 +178,6 @@ var UITour = {
|
|||
},
|
||||
],
|
||||
["readerMode-urlBar", { query: "#reader-mode-button" }],
|
||||
["restorePreviousSession", { query: "#appMenu-restoreSession" }],
|
||||
[
|
||||
"search",
|
||||
{
|
||||
|
@ -836,7 +827,7 @@ var UITour = {
|
|||
this.hideHighlight(aWindow);
|
||||
this.hideInfo(aWindow);
|
||||
|
||||
await this.removePanelListeners(aWindow, true);
|
||||
await this.removePanelListeners(aWindow);
|
||||
|
||||
this.noautohideMenus.clear();
|
||||
|
||||
|
@ -849,7 +840,7 @@ var UITour = {
|
|||
/**
|
||||
* Remove the listeners to a panel when tearing the tour down.
|
||||
*/
|
||||
async removePanelListeners(aWindow, aHidePanels = false) {
|
||||
async removePanelListeners(aWindow) {
|
||||
let panels = [
|
||||
{
|
||||
name: "appMenu",
|
||||
|
@ -858,14 +849,12 @@ var UITour = {
|
|||
["popuphidden", this.onPanelHidden],
|
||||
["popuphiding", this.onAppMenuHiding],
|
||||
["ViewShowing", this.onAppMenuSubviewShowing],
|
||||
["ViewShown", this.onAppMenuSubviewShown],
|
||||
["ViewHiding", this.onAppMenuSubviewHiding],
|
||||
],
|
||||
},
|
||||
];
|
||||
for (let panel of panels) {
|
||||
// Ensure the menu panel is hidden and clean up panel listeners after calling hideMenu.
|
||||
if (aHidePanels && panel.node.state != "closed") {
|
||||
if (panel.node.state != "closed") {
|
||||
await new Promise(resolve => {
|
||||
panel.node.addEventListener("popuphidden", resolve, { once: true });
|
||||
this.hideMenu(aWindow, panel.name);
|
||||
|
@ -978,8 +967,6 @@ var UITour = {
|
|||
targetName: aTargetName,
|
||||
widgetName: targetObject.widgetName,
|
||||
allowAdd: targetObject.allowAdd,
|
||||
level: targetObject.level,
|
||||
subItem: targetObject.subItem,
|
||||
});
|
||||
})
|
||||
.catch(log.error);
|
||||
|
@ -1137,16 +1124,6 @@ var UITour = {
|
|||
highlighter.parentElement.setAttribute("targetName", aTarget.targetName);
|
||||
highlighter.parentElement.hidden = false;
|
||||
|
||||
if (aTarget.subItem) {
|
||||
// This is a subitem in the app menu, so mark it as one not to hide.
|
||||
this.noautohideMenus.add("appMenu");
|
||||
highlighter.parentElement.setAttribute("subitem", aTarget.subItem);
|
||||
}
|
||||
|
||||
if (aTarget.level) {
|
||||
highlighter.parentElement.setAttribute("level", aTarget.level);
|
||||
}
|
||||
|
||||
let highlightAnchor = aAnchorEl;
|
||||
let targetRect = highlightAnchor.getBoundingClientRect();
|
||||
let highlightHeight = targetRect.height;
|
||||
|
@ -1442,8 +1419,6 @@ var UITour = {
|
|||
menu.node = aWindow.PanelUI.panel;
|
||||
menu.onPopupHiding = this.onAppMenuHiding;
|
||||
menu.onViewShowing = this.onAppMenuSubviewShowing;
|
||||
menu.onViewShown = this.onAppMenuSubviewShown;
|
||||
menu.onViewHiding = this.onAppMenuSubviewHiding;
|
||||
menu.show = () => aWindow.PanelUI.show();
|
||||
|
||||
if (!aOptions.autohide) {
|
||||
|
@ -1459,8 +1434,6 @@ var UITour = {
|
|||
menu.node.addEventListener("popuphidden", menu.onPanelHidden);
|
||||
menu.node.addEventListener("popuphiding", menu.onPopupHiding);
|
||||
menu.node.addEventListener("ViewShowing", menu.onViewShowing);
|
||||
menu.node.addEventListener("ViewShown", menu.onViewShown);
|
||||
menu.node.addEventListener("ViewHiding", menu.onViewHiding);
|
||||
menu.show();
|
||||
} else if (aMenuName == "bookmarks") {
|
||||
let menuBtn = aWindow.document.getElementById("bookmarks-menu-button");
|
||||
|
@ -1589,80 +1562,12 @@ var UITour = {
|
|||
UITour._hideAnnotationsForPanel(aEvent, false, UITour.targetIsInAppMenu);
|
||||
},
|
||||
|
||||
onAppMenuSubviewShown(aEvent) {
|
||||
let win = aEvent.target.ownerGlobal;
|
||||
let subItemName = UITour.getSubItem(win);
|
||||
if (
|
||||
subItemName &&
|
||||
UITour.isSubItemToHighlight(win, subItemName, aEvent.target.id)
|
||||
) {
|
||||
let highlighter = UITour.getHighlightAndMaybeCreate(win.document);
|
||||
UITour.recreatePopup(highlighter.parentElement);
|
||||
|
||||
UITour.getTarget(win, subItemName).then(subItem => {
|
||||
if (!subItem.node.hidden) {
|
||||
UITour.showHighlight(win, subItem, "focus-outline", {
|
||||
autohide: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (subItemName && aEvent.target.id != "appMenu-protonMainView") {
|
||||
UITour.stopSubViewHandling(win);
|
||||
}
|
||||
},
|
||||
|
||||
onAppMenuSubviewHiding(aEvent) {
|
||||
let win = aEvent.target.ownerGlobal;
|
||||
|
||||
let subItem = UITour.getSubItem(win);
|
||||
if (subItem) {
|
||||
if (UITour.isSubItemToHighlight(win, subItem, aEvent.target.id)) {
|
||||
UITour.hideHighlight(win);
|
||||
UITour.stopSubViewHandling(win);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onPanelHidden(aEvent) {
|
||||
if (UITour.getSubItem(aEvent.target.ownerGlobal)) {
|
||||
UITour.stopSubViewHandling(aEvent.target.ownerGlobal);
|
||||
}
|
||||
|
||||
aEvent.target.removeAttribute("noautohide");
|
||||
UITour.recreatePopup(aEvent.target);
|
||||
UITour.clearAvailableTargetsCache();
|
||||
},
|
||||
|
||||
getSubItem(aWindow) {
|
||||
// Get the subitem that should be highlighted in the app menu's subview.
|
||||
let highlighter = UITour.getHighlightContainerAndMaybeCreate(
|
||||
aWindow.document
|
||||
);
|
||||
return highlighter.getAttribute("subitem");
|
||||
},
|
||||
|
||||
isSubItemToHighlight(aWindow, aSubItem, aExpectedId) {
|
||||
let targetObject = UITour.targets.get(aSubItem);
|
||||
if (targetObject) {
|
||||
let node = UITour.getNodeFromDocument(
|
||||
aWindow.document,
|
||||
targetObject.query
|
||||
);
|
||||
return aExpectedId == node?.closest("panelview")?.id;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
stopSubViewHandling(aWindow) {
|
||||
UITour.removePanelListeners(aWindow);
|
||||
UITour.noautohideMenus.delete("appMenu");
|
||||
|
||||
let highlighter = UITour.getHighlightAndMaybeCreate(aWindow.document);
|
||||
highlighter.parentElement.removeAttribute("level");
|
||||
highlighter.parentElement.removeAttribute("subitem");
|
||||
},
|
||||
|
||||
recreatePopup(aPanel) {
|
||||
// After changing popup attributes that relate to how the native widget is created
|
||||
// (e.g. @noautohide) we need to re-create the frame/widget for it to take effect.
|
||||
|
|
|
@ -15,14 +15,12 @@ function getExpectedTargets() {
|
|||
"appMenu",
|
||||
"backForward",
|
||||
"help",
|
||||
"history",
|
||||
"logins",
|
||||
"pageAction-bookmark",
|
||||
...(hasPocket ? ["pocket"] : []),
|
||||
"privateWindow",
|
||||
...(hasQuit ? ["quit"] : []),
|
||||
"readerMode-urlBar",
|
||||
"restorePreviousSession",
|
||||
"urlbar",
|
||||
];
|
||||
}
|
||||
|
|
|
@ -29,14 +29,11 @@ downloads-cmd-cancel =
|
|||
downloads-cmd-cancel-panel =
|
||||
.aria-label = Cancel
|
||||
|
||||
# This message is only displayed on Windows and Linux devices
|
||||
downloads-cmd-show-menuitem =
|
||||
.label = Open Containing Folder
|
||||
.accesskey = F
|
||||
|
||||
# This message is only displayed on macOS devices
|
||||
downloads-cmd-show-menuitem-mac =
|
||||
.label = Show In Finder
|
||||
downloads-cmd-show-menuitem-2 =
|
||||
.label = { PLATFORM() ->
|
||||
[macos] Show in Finder
|
||||
*[other] Show in Folder
|
||||
}
|
||||
.accesskey = F
|
||||
|
||||
downloads-cmd-use-system-default =
|
||||
|
@ -47,21 +44,21 @@ downloads-cmd-always-use-system-default =
|
|||
.label = Always Open In System Viewer
|
||||
.accesskey = w
|
||||
|
||||
downloads-cmd-show-button =
|
||||
downloads-cmd-show-button-2 =
|
||||
.tooltiptext = { PLATFORM() ->
|
||||
[macos] Show In Finder
|
||||
*[other] Open Containing Folder
|
||||
[macos] Show in Finder
|
||||
*[other] Show in Folder
|
||||
}
|
||||
|
||||
downloads-cmd-show-panel =
|
||||
downloads-cmd-show-panel-2 =
|
||||
.aria-label = { PLATFORM() ->
|
||||
[macos] Show In Finder
|
||||
*[other] Open Containing Folder
|
||||
[macos] Show in Finder
|
||||
*[other] Show in Folder
|
||||
}
|
||||
downloads-cmd-show-description =
|
||||
downloads-cmd-show-description-2 =
|
||||
.value = { PLATFORM() ->
|
||||
[macos] Show In Finder
|
||||
*[other] Open Containing Folder
|
||||
[macos] Show in Finder
|
||||
*[other] Show in Folder
|
||||
}
|
||||
|
||||
downloads-cmd-show-downloads =
|
||||
|
|
|
@ -82,17 +82,3 @@ statusSeparatorBeforeNumber=%1$S \u2014 %2$S
|
|||
# semi-colon list of plural forms.
|
||||
# See: http://developer.mozilla.org/en/Localization_and_Plurals
|
||||
otherDownloads3=%1$S file downloading;%1$S files downloading
|
||||
|
||||
# LOCALIZATION NOTE (showLabel, showMacLabel):
|
||||
# This is displayed when you hover a download item in the Library widget view.
|
||||
# showMacLabel is only shown on Mac OSX.
|
||||
showLabel=Open Containing Folder
|
||||
showMacLabel=Open In Finder
|
||||
# LOCALIZATION NOTE (openFileLabel):
|
||||
# Displayed when hovering a complete download, indicates that it's possible to
|
||||
# open the file using an app available in the system.
|
||||
openFileLabel=Open File
|
||||
# LOCALIZATION NOTE (retryLabel):
|
||||
# Displayed when hovering a download which is able to be retried by users,
|
||||
# indicates that it's possible to download this file again.
|
||||
retryLabel=Retry Download
|
||||
|
|
|
@ -20,8 +20,9 @@ add_task(async function() {
|
|||
const tabDescriptors = await mainRoot.listTabs();
|
||||
|
||||
await testGetTargetWithConcurrentCalls(tabDescriptors, tabTarget => {
|
||||
// Tab Target is attached when it has a console front.
|
||||
return !!tabTarget.getCachedFront("console");
|
||||
// We only call BrowsingContextTargetFront.attach and not TargetMixin.attachAndInitThread.
|
||||
// So very few things are done.
|
||||
return !!tabTarget.traits;
|
||||
});
|
||||
|
||||
await client.close();
|
||||
|
@ -40,8 +41,9 @@ add_task(async function() {
|
|||
// happens between the instantiation of ContentProcessTarget and its call to attach() from getTarget
|
||||
// function.
|
||||
await testGetTargetWithConcurrentCalls(processes, processTarget => {
|
||||
// Content Process Target is attached when it has a console front.
|
||||
return !!processTarget.getCachedFront("console");
|
||||
// We only call ContentProcessTargetFront.attach and not TargetMixin.attachAndInitThread.
|
||||
// So nothing is done for content process targets.
|
||||
return true;
|
||||
});
|
||||
|
||||
await client.close();
|
||||
|
|
|
@ -691,7 +691,8 @@ Toolbox.prototype = {
|
|||
// Attach to a new top-level target.
|
||||
// For now, register these event listeners only on the top level target
|
||||
targetFront.on("frame-update", this._updateFrames);
|
||||
targetFront.on("inspect-object", this._onInspectObject);
|
||||
const consoleFront = await targetFront.getFront("console");
|
||||
consoleFront.on("inspectObject", this._onInspectObject);
|
||||
}
|
||||
|
||||
// Walker listeners allow to monitor DOM Mutation breakpoint updates.
|
||||
|
@ -718,8 +719,9 @@ Toolbox.prototype = {
|
|||
|
||||
_onTargetDestroyed({ targetFront }) {
|
||||
if (targetFront.isTopLevel) {
|
||||
this.target.off("inspect-object", this._onInspectObject);
|
||||
this.target.off("frame-update", this._updateFrames);
|
||||
const consoleFront = targetFront.getCachedFront("console");
|
||||
consoleFront.off("inspectObject", this._onInspectObject);
|
||||
targetFront.off("frame-update", this._updateFrames);
|
||||
} else if (this.selection) {
|
||||
this.selection.onTargetDestroyed(targetFront);
|
||||
}
|
||||
|
@ -3611,10 +3613,6 @@ Toolbox.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
_onInspectObject: function(packet) {
|
||||
this.inspectObjectActor(packet.objectActor, packet.inspectFromAnnotation);
|
||||
},
|
||||
|
||||
_onToolSelected: function() {
|
||||
this._refreshHostTitle();
|
||||
|
||||
|
@ -3626,6 +3624,13 @@ Toolbox.prototype = {
|
|||
this.component.setToolboxButtons(this.toolbarButtons);
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener for "inspectObject" event on console top level target actor.
|
||||
*/
|
||||
_onInspectObject(packet) {
|
||||
this.inspectObjectActor(packet.objectActor, packet.inspectFromAnnotation);
|
||||
},
|
||||
|
||||
inspectObjectActor: async function(objectActor, inspectFromAnnotation) {
|
||||
const objectGrip = objectActor?.getGrip
|
||||
? objectActor.getGrip()
|
||||
|
|
|
@ -95,8 +95,7 @@ class WorkerDescriptorFront extends DescriptorMixin(
|
|||
|
||||
const workerTargetForm = await super.getTarget();
|
||||
|
||||
// Set the console actor ID on the form to expose it to Target.attachConsole
|
||||
// Set the ThreadActor on the target form so it is accessible by getFront
|
||||
// Set the console and thread actor IDs on the form so it is accessible by TargetMixin.getFront
|
||||
this.targetForm.consoleActor = workerTargetForm.consoleActor;
|
||||
this.targetForm.threadActor = workerTargetForm.threadActor;
|
||||
|
||||
|
@ -104,7 +103,6 @@ class WorkerDescriptorFront extends DescriptorMixin(
|
|||
return this;
|
||||
}
|
||||
|
||||
await this.attachConsole();
|
||||
return this;
|
||||
})();
|
||||
return this._attach;
|
||||
|
|
|
@ -44,11 +44,6 @@ class ContentProcessTargetFront extends TargetMixin(
|
|||
}
|
||||
|
||||
attach() {
|
||||
// All target actors have a console actor to attach.
|
||||
// All but xpcshell test actors... which is using a ContentProcessTargetActor
|
||||
if (this.targetForm.consoleActor) {
|
||||
return this.attachConsole();
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
|
|
|
@ -468,25 +468,6 @@ function TargetMixin(parentClass) {
|
|||
}
|
||||
}
|
||||
|
||||
// Attach the console actor
|
||||
async attachConsole() {
|
||||
const consoleFront = await this.getFront("console");
|
||||
|
||||
if (this.isDestroyedOrBeingDestroyed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calling startListeners will populate the traits as it's the first request we
|
||||
// make to the front.
|
||||
await consoleFront.startListeners([]);
|
||||
|
||||
this._onInspectObject = packet => this.emit("inspect-object", packet);
|
||||
this.removeOnInspectObjectListener = consoleFront.on(
|
||||
"inspectObject",
|
||||
this._onInspectObject
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method attaches the target and then attaches its related thread, sending it
|
||||
* the options it needs (e.g. breakpoints, pause on exception setting, …).
|
||||
|
@ -649,12 +630,6 @@ function TargetMixin(parentClass) {
|
|||
}
|
||||
this.fronts.clear();
|
||||
|
||||
// Remove listeners set in attachConsole
|
||||
if (this.removeOnInspectObjectListener) {
|
||||
this.removeOnInspectObjectListener();
|
||||
this.removeOnInspectObjectListener = null;
|
||||
}
|
||||
|
||||
this.threadFront = null;
|
||||
this._offResourceEvent = null;
|
||||
|
||||
|
|
|
@ -125,12 +125,6 @@ class WindowGlobalTargetFront extends TargetMixin(
|
|||
// @backward-compat { version 93 } Remove this. All the traits are on form and can be accessed
|
||||
// using getTraits.
|
||||
this.traits = response.traits || {};
|
||||
|
||||
// xpcshell tests from devtools/server/tests/xpcshell/ are implementing
|
||||
// fake WindowGlobalTargetActor which do not expose any console actor.
|
||||
if (this.targetForm.consoleActor) {
|
||||
await this.attachConsole();
|
||||
}
|
||||
})();
|
||||
return this._attach;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ class WebConsoleFront extends FrontClassWithSpec(webconsoleSpec) {
|
|||
constructor(client, targetFront, parentFront) {
|
||||
super(client, targetFront, parentFront);
|
||||
this._client = client;
|
||||
this.traits = {};
|
||||
this.events = [];
|
||||
|
||||
// Attribute name from which to retrieve the actorID out of the target actor's form
|
||||
|
@ -306,7 +305,6 @@ class WebConsoleFront extends FrontClassWithSpec(webconsoleSpec) {
|
|||
async startListeners(listeners) {
|
||||
const response = await super.startListeners(listeners);
|
||||
this.hasNativeConsoleAPI = response.nativeConsoleAPI;
|
||||
this.traits = response.traits;
|
||||
return response;
|
||||
}
|
||||
|
||||
|
|
|
@ -432,9 +432,6 @@ class Connector {
|
|||
if (this.hasResourceCommandSupport && this.networkFront) {
|
||||
return this.networkFront.getBlockedUrls();
|
||||
}
|
||||
if (!this.webConsoleFront.traits.blockedUrls) {
|
||||
return [];
|
||||
}
|
||||
return this.webConsoleFront.getBlockedUrls();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,98 +13,68 @@ var { DevToolsClient } = require("devtools/client/devtools-client");
|
|||
const TAB1_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
|
||||
const TAB2_URL = EXAMPLE_URL + "doc_empty-tab-02.html";
|
||||
|
||||
var gTab1, gTab1Front, gTab2, gTab2Front, gClient;
|
||||
|
||||
function test() {
|
||||
add_task(async function test() {
|
||||
DevToolsServer.init();
|
||||
DevToolsServer.registerAllActors();
|
||||
|
||||
const transport = DevToolsServer.connectPipe();
|
||||
gClient = new DevToolsClient(transport);
|
||||
gClient.connect().then(([aType, aTraits]) => {
|
||||
is(aType, "browser", "Root actor should identify itself as a browser.");
|
||||
const client = new DevToolsClient(transport);
|
||||
const [aType] = await client.connect();
|
||||
is(aType, "browser", "Root actor should identify itself as a browser.");
|
||||
|
||||
Promise.resolve(null)
|
||||
.then(testFirstTab)
|
||||
.then(testSecondTab)
|
||||
.then(testRemoveTab)
|
||||
.then(testAttachRemovedTab)
|
||||
.then(() => gClient.close())
|
||||
.then(finish)
|
||||
.catch(error => {
|
||||
ok(false, "Got an error: " + error.message + "\n" + error.stack);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testFirstTab() {
|
||||
return addTab(TAB1_URL).then(tab => {
|
||||
gTab1 = tab;
|
||||
|
||||
return getTargetActorForUrl(gClient, TAB1_URL).then(front => {
|
||||
ok(front, "Should find a target actor for the first tab.");
|
||||
gTab1Front = front;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testSecondTab() {
|
||||
return addTab(TAB2_URL).then(tab => {
|
||||
gTab2 = tab;
|
||||
|
||||
return getTargetActorForUrl(gClient, TAB1_URL).then(firstFront => {
|
||||
return getTargetActorForUrl(gClient, TAB2_URL).then(secondFront => {
|
||||
is(firstFront, gTab1Front, "First tab's actor shouldn't have changed.");
|
||||
ok(secondFront, "Should find a target actor for the second tab.");
|
||||
gTab2Front = secondFront;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testRemoveTab() {
|
||||
return removeTab(gTab1).then(() => {
|
||||
return getTargetActorForUrl(gClient, TAB1_URL).then(front => {
|
||||
ok(!front, "Shouldn't find a target actor for the first tab anymore.");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testAttachRemovedTab() {
|
||||
return removeTab(gTab2).then(() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
gClient.on("paused", () => {
|
||||
ok(
|
||||
false,
|
||||
"Attaching to an exited target actor shouldn't generate a pause."
|
||||
);
|
||||
reject();
|
||||
});
|
||||
|
||||
const { actorID } = gTab2Front;
|
||||
gTab2Front.reconfigure({}).then(null, error => {
|
||||
ok(
|
||||
error.message.includes(
|
||||
`Connection closed, pending request to ${actorID}, type reconfigure failed`
|
||||
),
|
||||
"Actor is gone since the tab was removed."
|
||||
);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gTab1 = null;
|
||||
gTab1Front = null;
|
||||
gTab2 = null;
|
||||
gTab2Front = null;
|
||||
gClient = null;
|
||||
const firstTab = await testFirstTab(client);
|
||||
const secondTab = await testSecondTab(client, firstTab.front);
|
||||
await testRemoveTab(client, firstTab.tab);
|
||||
await testAttachRemovedTab(secondTab.tab, secondTab.front);
|
||||
await client.close();
|
||||
});
|
||||
|
||||
async function getTargetActorForUrl(client, url) {
|
||||
async function testFirstTab(client) {
|
||||
const tab = await addTab(TAB1_URL);
|
||||
|
||||
const front = await getDescriptorActorForUrl(client, TAB1_URL);
|
||||
ok(front, "Should find a target actor for the first tab.");
|
||||
return { tab, front };
|
||||
}
|
||||
|
||||
async function testSecondTab(client, firstTabFront) {
|
||||
const tab = await addTab(TAB2_URL);
|
||||
|
||||
const firstFront = await getDescriptorActorForUrl(client, TAB1_URL);
|
||||
const secondFront = await getDescriptorActorForUrl(client, TAB2_URL);
|
||||
is(firstFront, firstTabFront, "First tab's actor shouldn't have changed.");
|
||||
ok(secondFront, "Should find a target actor for the second tab.");
|
||||
return { tab, front: secondFront };
|
||||
}
|
||||
|
||||
async function testRemoveTab(client, firstTab) {
|
||||
await removeTab(firstTab);
|
||||
const front = await getDescriptorActorForUrl(client, TAB1_URL);
|
||||
ok(!front, "Shouldn't find a target actor for the first tab anymore.");
|
||||
}
|
||||
|
||||
async function testAttachRemovedTab(secondTab, secondTabFront) {
|
||||
await removeTab(secondTab);
|
||||
|
||||
const { actorID } = secondTabFront;
|
||||
try {
|
||||
await secondTabFront.getFavicon({});
|
||||
ok(
|
||||
false,
|
||||
"any request made to the descriptor for a closed tab should have failed"
|
||||
);
|
||||
} catch (error) {
|
||||
ok(
|
||||
error.message.includes(
|
||||
`Connection closed, pending request to ${actorID}, type getFavicon failed`
|
||||
),
|
||||
"Actor is gone since the tab was removed."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function getDescriptorActorForUrl(client, url) {
|
||||
const tabDescriptors = await client.mainRoot.listTabs();
|
||||
const tabDescriptor = tabDescriptors.find(front => front.url == url);
|
||||
return tabDescriptor?.getTarget();
|
||||
return tabDescriptor;
|
||||
}
|
||||
|
|
|
@ -198,11 +198,6 @@ const WebConsoleActor = ActorClassWithSpec(webconsoleSpec, {
|
|||
"last-pb-context-exited"
|
||||
);
|
||||
}
|
||||
|
||||
this.traits = {
|
||||
// Supports retrieving blocked urls
|
||||
blockedUrls: true,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Debugger instance.
|
||||
|
@ -239,12 +234,6 @@ const WebConsoleActor = ActorClassWithSpec(webconsoleSpec, {
|
|||
*/
|
||||
conn: null,
|
||||
|
||||
/**
|
||||
* List of supported features by the console actor.
|
||||
* @type object
|
||||
*/
|
||||
traits: null,
|
||||
|
||||
/**
|
||||
* The global we work with (this can be a Window, a Worker global or even a Sandbox
|
||||
* for processes and addons).
|
||||
|
@ -794,7 +783,6 @@ const WebConsoleActor = ActorClassWithSpec(webconsoleSpec, {
|
|||
return {
|
||||
startedListeners: startedListeners,
|
||||
nativeConsoleAPI: this.hasNativeConsoleAPI(this.global),
|
||||
traits: this.traits,
|
||||
};
|
||||
},
|
||||
|
||||
|
|
|
@ -12,14 +12,9 @@ const {
|
|||
Arg,
|
||||
} = require("devtools/shared/protocol");
|
||||
|
||||
types.addDictType("console.traits", {
|
||||
evaluateJSAsync: "boolean",
|
||||
});
|
||||
|
||||
types.addDictType("console.startlisteners", {
|
||||
startedListeners: "array:string",
|
||||
nativeConsoleAPI: "nullable:boolean",
|
||||
traits: "console.traits",
|
||||
});
|
||||
|
||||
types.addDictType("console.stoplisteners", {
|
||||
|
|
|
@ -121,7 +121,7 @@ interface WindowGlobalParent : WindowContext {
|
|||
*/
|
||||
[Throws]
|
||||
JSWindowActorParent getActor(UTF8String name);
|
||||
JSWindowActorParent getExistingActor(UTF8String name);
|
||||
JSWindowActorParent? getExistingActor(UTF8String name);
|
||||
|
||||
/**
|
||||
* Renders a region of the frame into an image bitmap.
|
||||
|
@ -191,5 +191,5 @@ interface WindowGlobalChild {
|
|||
*/
|
||||
[Throws]
|
||||
JSWindowActorChild getActor(UTF8String name);
|
||||
JSWindowActorChild getExistingActor(UTF8String name);
|
||||
JSWindowActorChild? getExistingActor(UTF8String name);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<h3>Set <code>privacy.file_unique_origin</code> to false when testing this.</h3>
|
||||
<script>
|
||||
fetch("./url.url")
|
||||
</script>
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
load 1577196.html
|
||||
pref(privacy.file_unique_origin,false) load 1664514.html
|
||||
load 1664514.html
|
||||
|
|
|
@ -129,28 +129,6 @@ interface nsIBrowser : nsISupports
|
|||
in uint64_t aRequestContextID,
|
||||
in AString aContentType);
|
||||
|
||||
/**
|
||||
* Determine what process switching behavior this browser element should have.
|
||||
*/
|
||||
cenum ProcessBehavior : 8 {
|
||||
// Gecko won't automatically change which process this frame, or it's
|
||||
// subframes, are loaded in.
|
||||
PROCESS_BEHAVIOR_DISABLED,
|
||||
|
||||
// If `useRemoteTabs` is enabled, Gecko will change which process this frame
|
||||
// is loaded in automatically, without calling `performProcessSwitch`.
|
||||
// When `useRemoteSubframes` is enabled, subframes will change processes.
|
||||
PROCESS_BEHAVIOR_STANDARD,
|
||||
|
||||
// Gecko won't automatically change which process this frame is loaded, but
|
||||
// when `useRemoteSubframes` is enabled, subframes will change processes.
|
||||
//
|
||||
// NOTE: This configuration is included only for backwards compatibility,
|
||||
// and will be removed, as it can easily lead to invalid behavior.
|
||||
PROCESS_BEHAVIOR_SUBFRAME_ONLY,
|
||||
};
|
||||
readonly attribute nsIBrowser_ProcessBehavior processSwitchBehavior;
|
||||
|
||||
/**
|
||||
* Called to perform any async tasks which must be completed before changing
|
||||
* remoteness. Gecko will wait for the returned promise to resolve before
|
||||
|
|
|
@ -1680,12 +1680,14 @@ static void DisconnectWindowServer(bool aIsSandboxEnabled) {
|
|||
// is called.
|
||||
CGSShutdownServerConnections();
|
||||
|
||||
// Actual security benefits are only acheived when we additionally deny
|
||||
// future connections, however this currently breaks WebGL so it's not done
|
||||
// by default.
|
||||
// Actual security benefits are only achieved when we additionally deny
|
||||
// future connections using the sandbox policy. WebGL must be remoted if
|
||||
// the windowserver connections are blocked. WebGL remoting is disabled
|
||||
// for some tests.
|
||||
if (aIsSandboxEnabled &&
|
||||
Preferences::GetBool(
|
||||
"security.sandbox.content.mac.disconnect-windowserver")) {
|
||||
"security.sandbox.content.mac.disconnect-windowserver") &&
|
||||
Preferences::GetBool("webgl.out-of-process")) {
|
||||
CGError result = CGSSetDenyWindowServerConnections(true);
|
||||
MOZ_DIAGNOSTIC_ASSERT(result == kCGErrorSuccess);
|
||||
# if !MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
|
|
|
@ -2409,9 +2409,12 @@ static void CacheSandboxParams(std::vector<std::string>& aCachedParams) {
|
|||
info.hasAudio = true;
|
||||
}
|
||||
|
||||
// Windowserver access
|
||||
// Window server access. If the disconnect-windowserver pref is not
|
||||
// "true" or out-of-process WebGL is not enabled, allow window server
|
||||
// access in the sandbox policy.
|
||||
if (!Preferences::GetBool(
|
||||
"security.sandbox.content.mac.disconnect-windowserver")) {
|
||||
"security.sandbox.content.mac.disconnect-windowserver") ||
|
||||
!Preferences::GetBool("webgl.out-of-process")) {
|
||||
info.hasWindowServer = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,108 +3,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const WORKER_BODY = "postMessage(42);\n";
|
||||
|
||||
// file:// tests.
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.file_unique_origin", false]],
|
||||
});
|
||||
|
||||
info("Creating the tmp directory.");
|
||||
let parent = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIDirectoryService)
|
||||
.QueryInterface(Ci.nsIProperties)
|
||||
.get("TmpD", Ci.nsIFile);
|
||||
parent.append("worker-dir-test");
|
||||
parent.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o700);
|
||||
|
||||
let dir_a = parent.clone();
|
||||
dir_a.append("a");
|
||||
dir_a.create(Ci.nsIFile.DIRECTORY_TYPE, 0o700);
|
||||
|
||||
let page_a = dir_a.clone();
|
||||
page_a.append("empty.html");
|
||||
page_a.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
|
||||
|
||||
let url_a = Services.io.newFileURI(page_a);
|
||||
|
||||
let worker = dir_a.clone();
|
||||
worker.append("worker.js");
|
||||
|
||||
let stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(
|
||||
Ci.nsIFileOutputStream
|
||||
);
|
||||
stream.init(
|
||||
worker,
|
||||
0x02 | 0x08 | 0x20, // write, create, truncate
|
||||
0o666,
|
||||
0
|
||||
);
|
||||
stream.write(WORKER_BODY, WORKER_BODY.length);
|
||||
stream.close();
|
||||
|
||||
let url_worker = Services.io.newFileURI(worker);
|
||||
|
||||
let dir_b = parent.clone();
|
||||
dir_b.append("b");
|
||||
dir_b.create(Ci.nsIFile.DIRECTORY_TYPE, 0o700);
|
||||
|
||||
let page_b = dir_b.clone();
|
||||
page_b.append("empty.html");
|
||||
page_b.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
|
||||
|
||||
let url_b = Services.io.newFileURI(page_b);
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, url_a.spec);
|
||||
gBrowser.selectedTab = tab;
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
await SpecialPowers.spawn(browser, [url_worker.spec], function(spec) {
|
||||
return new content.Promise((resolve, reject) => {
|
||||
let w = new content.window.Worker(spec);
|
||||
w.onerror = _ => {
|
||||
reject();
|
||||
};
|
||||
w.onmessage = _ => {
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
});
|
||||
ok(true, "The worker is loaded when the script is on the same directory.");
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
tab = BrowserTestUtils.addTab(gBrowser, url_b.spec);
|
||||
gBrowser.selectedTab = tab;
|
||||
|
||||
browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
await SpecialPowers.spawn(browser, [url_worker.spec], function(spec) {
|
||||
return new content.Promise((resolve, reject) => {
|
||||
let w = new content.window.Worker(spec);
|
||||
w.onerror = _ => {
|
||||
resolve();
|
||||
};
|
||||
w.onmessage = _ => {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
});
|
||||
ok(
|
||||
true,
|
||||
"The worker is not loaded when the script is on a different directory."
|
||||
);
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
info("Removing the tmp directory.");
|
||||
parent.remove(true);
|
||||
});
|
||||
|
||||
const EMPTY_URL = "/browser/dom/workers/test/empty.html";
|
||||
const WORKER_URL = "/browser/dom/workers/test/empty_worker.js";
|
||||
|
||||
|
|
|
@ -97,11 +97,11 @@ already_AddRefed<MacIOSurface> MacIOSurface::CreateIOSurface(int aWidth,
|
|||
size_t CreatePlaneDictionary(CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
|
||||
const gfx::IntSize& aSize, size_t aOffset,
|
||||
size_t aBytesPerPixel) {
|
||||
size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow,
|
||||
size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfacePlaneBytesPerRow,
|
||||
aSize.width * aBytesPerPixel);
|
||||
// Add a SIMD register worth of extra bytes to the end of the allocation for
|
||||
// SWGL.
|
||||
size_t totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize,
|
||||
size_t totalBytes = IOSurfaceAlignProperty(kIOSurfacePlaneSize,
|
||||
aSize.height * bytesPerRow + 16);
|
||||
|
||||
aDict = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
|
||||
|
@ -114,7 +114,7 @@ size_t CreatePlaneDictionary(CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
|
|||
AddDictionaryInt(aDict, kIOSurfacePlaneBytesPerRow, bytesPerRow);
|
||||
AddDictionaryInt(aDict, kIOSurfacePlaneOffset, aOffset);
|
||||
AddDictionaryInt(aDict, kIOSurfacePlaneSize, totalBytes);
|
||||
AddDictionaryInt(aDict, kIOSurfaceBytesPerElement, aBytesPerPixel);
|
||||
AddDictionaryInt(aDict, kIOSurfacePlaneBytesPerElement, aBytesPerPixel);
|
||||
|
||||
return totalBytes;
|
||||
}
|
||||
|
@ -150,11 +150,15 @@ already_AddRefed<MacIOSurface> MacIOSurface::CreateNV12Surface(
|
|||
}
|
||||
|
||||
CFTypeRefPtr<CFMutableDictionaryRef> planeProps[2];
|
||||
size_t planeTotalBytes = CreatePlaneDictionary(planeProps[0], aYSize, 0, 1);
|
||||
planeTotalBytes +=
|
||||
CreatePlaneDictionary(planeProps[1], aCbCrSize, planeTotalBytes, 2);
|
||||
size_t yPlaneBytes = CreatePlaneDictionary(planeProps[0], aYSize, 0, 1);
|
||||
size_t cbCrOffset =
|
||||
IOSurfaceAlignProperty(kIOSurfacePlaneOffset, yPlaneBytes);
|
||||
size_t cbCrPlaneBytes =
|
||||
CreatePlaneDictionary(planeProps[1], aCbCrSize, cbCrOffset, 2);
|
||||
size_t totalBytes =
|
||||
IOSurfaceAlignProperty(kIOSurfaceAllocSize, cbCrOffset + cbCrPlaneBytes);
|
||||
|
||||
AddDictionaryInt(props, kIOSurfaceAllocSize, planeTotalBytes);
|
||||
AddDictionaryInt(props, kIOSurfaceAllocSize, totalBytes);
|
||||
|
||||
auto array = CFTypeRefPtr<CFArrayRef>::WrapUnderCreateRule(
|
||||
CFArrayCreate(kCFAllocatorDefault, (const void**)planeProps, 2,
|
||||
|
|
|
@ -62,6 +62,8 @@ class gfxVarReceiver;
|
|||
_(GREDirectory, nsString, nsString()) \
|
||||
_(ProfDirectory, nsString, nsString()) \
|
||||
_(AllowD3D11KeyedMutex, bool, false) \
|
||||
_(SwapIntervalGLX, bool, false) \
|
||||
_(SwapIntervalEGL, bool, false) \
|
||||
_(SystemTextQuality, int32_t, 5 /* CLEARTYPE_QUALITY */) \
|
||||
_(SystemTextClearTypeLevel, float, 1.0f) \
|
||||
_(SystemTextEnhancedContrast, float, 1.0f) \
|
||||
|
|
|
@ -310,12 +310,14 @@ already_AddRefed<GLContext> GLContextEGLFactory::CreateImpl(
|
|||
#ifdef MOZ_GTK_WAYLAND
|
||||
if (surface && GdkIsWaylandDisplay()) {
|
||||
// Make eglSwapBuffers() non-blocking on wayland
|
||||
egl->fSwapInterval(0);
|
||||
const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0;
|
||||
egl->fSwapInterval(interval);
|
||||
}
|
||||
#endif
|
||||
if (aHardwareWebRender && egl->mLib->IsANGLE()) {
|
||||
MOZ_ASSERT(doubleBuffered);
|
||||
egl->fSwapInterval(0);
|
||||
const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0;
|
||||
egl->fSwapInterval(interval);
|
||||
}
|
||||
return gl.forget();
|
||||
}
|
||||
|
@ -500,8 +502,10 @@ bool GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
|
|||
MOZ_ASSERT(ok);
|
||||
#ifdef MOZ_GTK_WAYLAND
|
||||
if (mSurface && GdkIsWaylandDisplay()) {
|
||||
// Make eglSwapBuffers() non-blocking on wayland
|
||||
mEgl->fSwapInterval(0);
|
||||
// The swap interval pref is false by default so that eglSwapBuffers()
|
||||
// is non-blocking on wayland.
|
||||
const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0;
|
||||
mEgl->fSwapInterval(interval);
|
||||
}
|
||||
#endif
|
||||
return ok;
|
||||
|
|
|
@ -482,8 +482,10 @@ bool GLContextGLX::MakeCurrentImpl() const {
|
|||
// Many GLX implementations default to blocking until the next
|
||||
// VBlank when calling glXSwapBuffers. We want to run unthrottled
|
||||
// in ASAP mode. See bug 1280744.
|
||||
const bool swapInterval = gfxVars::SwapIntervalGLX();
|
||||
const bool isASAP = (StaticPrefs::layout_frame_rate() == 0);
|
||||
mGLX->fSwapInterval(*mDisplay, mDrawable, isASAP ? 0 : 1);
|
||||
const int interval = (swapInterval && !isASAP) ? 1 : 0;
|
||||
mGLX->fSwapInterval(*mDisplay, mDrawable, interval);
|
||||
}
|
||||
return succeeded;
|
||||
}
|
||||
|
|
|
@ -775,14 +775,12 @@ async function injectScript(aScript, aWindow = window) {
|
|||
// each time this function is called.
|
||||
// The computed information is an object with three fields:
|
||||
// utils: the nsIDOMWindowUtils instance for this window
|
||||
// isWebRender: true if WebRender is enabled
|
||||
// isWindow: true if the platform is Windows
|
||||
// activateAllScrollFrames: true if prefs indicate all scroll frames are
|
||||
// activated with at least a minimal display port
|
||||
function getHitTestConfig() {
|
||||
if (!("hitTestConfig" in window)) {
|
||||
var utils = SpecialPowers.getDOMWindowUtils(window);
|
||||
var isWebRender = utils.layerManagerType.startsWith("WebRender");
|
||||
var isWindows = getPlatform() == "windows";
|
||||
let activateAllScrollFrames =
|
||||
SpecialPowers.getBoolPref("apz.wr.activate_all_scroll_frames") ||
|
||||
|
@ -793,7 +791,6 @@ function getHitTestConfig() {
|
|||
|
||||
window.hitTestConfig = {
|
||||
utils,
|
||||
isWebRender,
|
||||
isWindows,
|
||||
activateAllScrollFrames,
|
||||
};
|
||||
|
@ -941,27 +938,15 @@ function hitTestScrollbar(params) {
|
|||
// behaviour on different platforms which makes testing harder.
|
||||
var expectedHitInfo = APZHitResultFlags.VISIBLE | APZHitResultFlags.SCROLLBAR;
|
||||
if (params.expectThumb) {
|
||||
// The thumb has listeners which are APZ-aware. With WebRender we are able
|
||||
// to losslessly propagate this flag to APZ, but with non-WebRender the area
|
||||
// ends up in the mDispatchToContentRegion which we then convert back to
|
||||
// a IRREGULAR_AREA flag. This still works correctly since IRREGULAR_AREA
|
||||
// will fall back to the main thread for everything.
|
||||
if (config.isWebRender) {
|
||||
expectedHitInfo |= APZHitResultFlags.APZ_AWARE_LISTENERS;
|
||||
if (
|
||||
!config.activateAllScrollFrames &&
|
||||
params.layerState == LayerState.INACTIVE
|
||||
) {
|
||||
expectedHitInfo |= APZHitResultFlags.INACTIVE_SCROLLFRAME;
|
||||
}
|
||||
} else {
|
||||
expectedHitInfo |= APZHitResultFlags.IRREGULAR_AREA;
|
||||
// The thumb has listeners which are APZ-aware.
|
||||
expectedHitInfo |= APZHitResultFlags.APZ_AWARE_LISTENERS;
|
||||
var expectActive =
|
||||
config.activateAllScrollFrames || params.layerState == LayerState.ACTIVE;
|
||||
if (!expectActive) {
|
||||
expectedHitInfo |= APZHitResultFlags.INACTIVE_SCROLLFRAME;
|
||||
}
|
||||
// We do not generate the layers for thumbs on inactive scrollframes.
|
||||
if (
|
||||
params.layerState == LayerState.ACTIVE ||
|
||||
config.activateAllScrollFrames
|
||||
) {
|
||||
if (expectActive) {
|
||||
expectedHitInfo |= APZHitResultFlags.SCROLLBAR_THUMB;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,6 @@ add_task(async function test_main() {
|
|||
);
|
||||
}
|
||||
|
||||
var utils = SpecialPowers.getDOMWindowUtils(window);
|
||||
var isWebRender = utils.layerManagerType.startsWith("WebRender");
|
||||
|
||||
// Each of these subtests is a dictionary that contains:
|
||||
// file (required): filename of the subtest that will get opened in a new tab
|
||||
// in the top-level fission-enabled browser window.
|
||||
|
@ -64,26 +61,12 @@ add_task(async function test_main() {
|
|||
{ file: "helper_fission_initial_displayport.html" },
|
||||
{ file: "helper_fission_checkerboard_severity.html" },
|
||||
{ file: "helper_fission_setResolution.html" },
|
||||
{ file: "helper_fission_inactivescroller_positionedcontent.html" },
|
||||
{ file: "helper_fission_irregular_areas.html" },
|
||||
// Bug 1576514: On WebRender this test casues an assertion.
|
||||
// { file: "helper_fission_animation_styling_in_transformed_oopif.html", },
|
||||
// add additional tests here
|
||||
];
|
||||
// These tests are to ensure hit-testing works perfectly on the WR
|
||||
// codepath. The layers codepath may need a main-thread fallback to get
|
||||
// these working, but we can't use our synchronous hitTest(...) helpers
|
||||
// for those anyway.
|
||||
if (isWebRender) {
|
||||
subtests = subtests.concat([
|
||||
{ file: "helper_fission_inactivescroller_positionedcontent.html" },
|
||||
{ file: "helper_fission_irregular_areas.html" },
|
||||
// add WebRender-specific tests here
|
||||
]);
|
||||
} else {
|
||||
subtests = subtests.concat([
|
||||
// Bug 1576514: On WebRender this test casues an assertion.
|
||||
{
|
||||
file: "helper_fission_animation_styling_in_transformed_oopif.html",
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
// ccov builds run slower and need longer, so let's scale up the timeout
|
||||
// by the number of tests we're running.
|
||||
|
|
|
@ -100,13 +100,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1689492
|
|||
// but it gives a good idea that the good and bad values are far apart so
|
||||
// this test should be robust, and provides good context in the future if
|
||||
// this test starts failing.
|
||||
await testOne( 50, 5.2, "(height 50)"); // good wr 256 non-wr 256, bad wr 256 non-wr 384
|
||||
await testOne(128, 2.1, "(height128)"); // good wr 256 non-wr 256, bad wr 512 non-wr 640
|
||||
await testOne(200, 2.0, "(height200)"); // good wr 384 non-wr 384, bad wr 768 non-wr 896
|
||||
await testOne(256, 1.6, "(height256)"); // good wr 384 non-wr 384, bad wr 768 non-wr 1024
|
||||
await testOne(329, 1.6, "(height329)"); // good wr 512 non-wr 512, bad wr 896 non-wr 1280
|
||||
await testOne(500, 1.3, "(height500)"); // good wr 640 non-wr 640, bad wr 1280 non-wr 1920
|
||||
await testOne(640, getHitTestConfig().isWebRender ? 1.7 : 1.3, "(height640)"); // good wr 1024 non-wr 768, bad wr 1536 non-wr 2432
|
||||
await testOne( 50, 5.2, "(height 50)"); // good 256, bad 256
|
||||
await testOne(128, 2.1, "(height128)"); // good 256, bad 512
|
||||
await testOne(200, 2.0, "(height200)"); // good 384, bad 768
|
||||
await testOne(256, 1.6, "(height256)"); // good 384, bad 768
|
||||
await testOne(329, 1.6, "(height329)"); // good 512, bad 896
|
||||
await testOne(500, 1.3, "(height500)"); // good 640, bad 280
|
||||
await testOne(640, 1.7, "(height640)"); // good 1024, bad 1536
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -25,12 +25,8 @@ async function test() {
|
|||
var apzaware = document.getElementById("apzaware");
|
||||
|
||||
let expectedHitInfo = APZHitResultFlags.VISIBLE;
|
||||
if (config.isWebRender) {
|
||||
if (!config.activateAllScrollFrames) {
|
||||
expectedHitInfo |= APZHitResultFlags.INACTIVE_SCROLLFRAME;
|
||||
}
|
||||
} else {
|
||||
expectedHitInfo |= APZHitResultFlags.IRREGULAR_AREA;
|
||||
if (!config.activateAllScrollFrames) {
|
||||
expectedHitInfo |= APZHitResultFlags.INACTIVE_SCROLLFRAME;
|
||||
}
|
||||
checkHitResult(hitTest(centerOf(scroller)),
|
||||
expectedHitInfo,
|
||||
|
@ -66,13 +62,11 @@ async function test() {
|
|||
await promiseApzFlushedRepaints();
|
||||
var scrollY = scroller.scrollTopMax;
|
||||
utils.setAsyncScrollOffset(scroller, 0, scrollY);
|
||||
if (config.isWebRender) {
|
||||
// Tick the refresh driver once to make sure the compositor has applied the
|
||||
// async scroll offset (for APZ hit-testing this doesn't matter, but for
|
||||
// WebRender hit-testing we need to make sure WR has the latest info).
|
||||
utils.advanceTimeAndRefresh(16);
|
||||
utils.restoreNormalRefresh();
|
||||
}
|
||||
// Tick the refresh driver once to make sure the compositor has applied the
|
||||
// async scroll offset (for WebRender hit-testing we need to make sure WR has
|
||||
// the latest info).
|
||||
utils.advanceTimeAndRefresh(16);
|
||||
utils.restoreNormalRefresh();
|
||||
|
||||
var scrollerViewId = utils.getViewId(scroller);
|
||||
|
||||
|
@ -88,8 +82,7 @@ async function test() {
|
|||
apzawarePosition.y -= scrollY; // APZ position
|
||||
checkHitResult(hitTest(apzawarePosition),
|
||||
APZHitResultFlags.VISIBLE |
|
||||
(config.isWebRender ? APZHitResultFlags.APZ_AWARE_LISTENERS
|
||||
: APZHitResultFlags.IRREGULAR_AREA),
|
||||
APZHitResultFlags.APZ_AWARE_LISTENERS,
|
||||
scrollerViewId,
|
||||
utils.getLayersId(),
|
||||
"active scrollframe - apzaware block");
|
||||
|
|
|
@ -31,13 +31,11 @@ async function test() {
|
|||
await promiseApzFlushedRepaints();
|
||||
var scrollY = scroller.scrollTopMax;
|
||||
utils.setAsyncScrollOffset(scroller, 0, scrollY);
|
||||
if (config.isWebRender) {
|
||||
// Tick the refresh driver once to make sure the compositor has applied the
|
||||
// async scroll offset (for APZ hit-testing this doesn't matter, but for
|
||||
// WebRender hit-testing we need to make sure WR has the latest info).
|
||||
utils.advanceTimeAndRefresh(16);
|
||||
utils.restoreNormalRefresh();
|
||||
}
|
||||
// Tick the refresh driver once to make sure the compositor has applied the
|
||||
// async scroll offset (for WebRender hit-testing we need to make sure WR has
|
||||
// the latest info).
|
||||
utils.advanceTimeAndRefresh(16);
|
||||
utils.restoreNormalRefresh();
|
||||
|
||||
var scrollerViewId = utils.getViewId(scroller);
|
||||
|
||||
|
|
|
@ -35,8 +35,6 @@ async function test() {
|
|||
var config = getHitTestConfig();
|
||||
var utils = config.utils;
|
||||
|
||||
const wrTag = config.isWebRender ? "WebRender" : "Layers";
|
||||
|
||||
// layerize the iframe
|
||||
var subwindow = document.getElementById("sub").contentWindow;
|
||||
var subscroller = subwindow.document.scrollingElement;
|
||||
|
@ -53,29 +51,27 @@ async function test() {
|
|||
APZHitResultFlags.VISIBLE,
|
||||
iframeViewId,
|
||||
layersId,
|
||||
`${wrTag} (simple) uninteresting point inside the iframe`);
|
||||
`(simple) uninteresting point inside the iframe`);
|
||||
checkHitResult(hitTest({ x: 500, y: 10 }),
|
||||
APZHitResultFlags.VISIBLE,
|
||||
rootViewId,
|
||||
layersId,
|
||||
`${wrTag} (simple) uninteresting point in the root scroller`);
|
||||
`(simple) uninteresting point in the root scroller`);
|
||||
checkHitResult(hitTest({ x: 110, y: 110 }),
|
||||
APZHitResultFlags.VISIBLE,
|
||||
iframeViewId,
|
||||
layersId,
|
||||
`${wrTag} (simple) point in the iframe behind overlaying div, but outside the bounding box of the clip path`);
|
||||
`(simple) point in the iframe behind overlaying div, but outside the bounding box of the clip path`);
|
||||
checkHitResult(hitTest({ x: 160, y: 160 }),
|
||||
config.isWebRender ? APZHitResultFlags.VISIBLE
|
||||
: APZHitResultFlags.VISIBLE | APZHitResultFlags.IRREGULAR_AREA,
|
||||
config.isWebRender ? iframeViewId : rootViewId,
|
||||
APZHitResultFlags.VISIBLE,
|
||||
iframeViewId,
|
||||
layersId,
|
||||
`${wrTag} (simple) point in the iframe behind overlaying div, inside the bounding box of the clip path, but outside the actual clip shape`);
|
||||
`(simple) point in the iframe behind overlaying div, inside the bounding box of the clip path, but outside the actual clip shape`);
|
||||
checkHitResult(hitTest({ x: 300, y: 200 }),
|
||||
config.isWebRender ? APZHitResultFlags.VISIBLE
|
||||
: APZHitResultFlags.VISIBLE | APZHitResultFlags.IRREGULAR_AREA,
|
||||
APZHitResultFlags.VISIBLE,
|
||||
rootViewId,
|
||||
layersId,
|
||||
`${wrTag} (simple) point inside the clip shape of the overlaying div`);
|
||||
`(simple) point inside the clip shape of the overlaying div`);
|
||||
|
||||
// Now we turn the "simple" clip-path that WR can handle into a more complex
|
||||
// one that needs a mask. Then run the checks again; the expected results for
|
||||
|
@ -87,29 +83,27 @@ async function test() {
|
|||
APZHitResultFlags.VISIBLE,
|
||||
iframeViewId,
|
||||
layersId,
|
||||
`${wrTag} (complex) uninteresting point inside the iframe`);
|
||||
`(complex) uninteresting point inside the iframe`);
|
||||
checkHitResult(hitTest({ x: 500, y: 10 }),
|
||||
APZHitResultFlags.VISIBLE,
|
||||
rootViewId,
|
||||
layersId,
|
||||
`${wrTag} (complex) uninteresting point in the root scroller`);
|
||||
`(complex) uninteresting point in the root scroller`);
|
||||
checkHitResult(hitTest({ x: 110, y: 110 }),
|
||||
APZHitResultFlags.VISIBLE,
|
||||
iframeViewId,
|
||||
layersId,
|
||||
`${wrTag} (complex) point in the iframe behind overlaying div, but outside the bounding box of the clip path`);
|
||||
`(complex) point in the iframe behind overlaying div, but outside the bounding box of the clip path`);
|
||||
checkHitResult(hitTest({ x: 160, y: 160 }),
|
||||
config.isWebRender ? APZHitResultFlags.VISIBLE
|
||||
: APZHitResultFlags.VISIBLE | APZHitResultFlags.IRREGULAR_AREA,
|
||||
config.isWebRender ? iframeViewId : rootViewId,
|
||||
APZHitResultFlags.VISIBLE,
|
||||
iframeViewId,
|
||||
layersId,
|
||||
`${wrTag} (complex) point in the iframe behind overlaying div, inside the bounding box of the clip path, but outside the actual clip shape`);
|
||||
`(complex) point in the iframe behind overlaying div, inside the bounding box of the clip path, but outside the actual clip shape`);
|
||||
checkHitResult(hitTest({ x: 300, y: 200 }),
|
||||
config.isWebRender ? APZHitResultFlags.VISIBLE
|
||||
: APZHitResultFlags.VISIBLE | APZHitResultFlags.IRREGULAR_AREA,
|
||||
config.isWebRender ? iframeViewId : rootViewId,
|
||||
APZHitResultFlags.VISIBLE,
|
||||
iframeViewId,
|
||||
layersId,
|
||||
`${wrTag} (complex) point inside the clip shape of the overlaying div`);
|
||||
`(complex) point inside the clip shape of the overlaying div`);
|
||||
}
|
||||
|
||||
waitUntilApzStable()
|
||||
|
|
|
@ -64,11 +64,8 @@ async function test() {
|
|||
utils.setDisplayPortForElement(0, 0, 300, 500, scroller, 1);
|
||||
await promiseApzFlushedRepaints();
|
||||
|
||||
// Inactive scrollframe flags will round-trip through the dispatch-to-content
|
||||
// region and end up as IRREGULAR_AREA when WebRender is disabled.
|
||||
var expectedHitFlags = config.isWebRender
|
||||
? APZHitResultFlags.VISIBLE | APZHitResultFlags.INACTIVE_SCROLLFRAME
|
||||
: APZHitResultFlags.VISIBLE | APZHitResultFlags.IRREGULAR_AREA;
|
||||
var expectedHitFlags =
|
||||
APZHitResultFlags.VISIBLE | APZHitResultFlags.INACTIVE_SCROLLFRAME;
|
||||
checkHitResult(hitTest(centerOf(scroller)),
|
||||
expectedHitFlags,
|
||||
utils.getViewId(scroller),
|
||||
|
|
|
@ -41,9 +41,9 @@ async function test() {
|
|||
var config = getHitTestConfig();
|
||||
var utils = config.utils;
|
||||
|
||||
// Subframe hit testing of overscrolled APZCs does not yet work with WebRender,
|
||||
// so bail out early.
|
||||
if (config.isWebRender) {
|
||||
// Subframe hit testing of overscrolled APZCs does not yet work with WebRender
|
||||
// (bug 1701831), so bail out early.
|
||||
if (true) {
|
||||
SimpleTest.todo(false, "This test does not currently pass with WebRender");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -120,12 +120,6 @@ async function test() {
|
|||
var scrollId = config.utils.getViewId(document.scrollingElement);
|
||||
var layersId = config.utils.getLayersId();
|
||||
|
||||
// Elements with APZ aware listeners round-trip through the dispatch-to-content
|
||||
// region and end up as IRREGULAR_AREA when WebRender is disabled.
|
||||
var touchListenerFlag = config.isWebRender
|
||||
? APZHitResultFlags.APZ_AWARE_LISTENERS
|
||||
: APZHitResultFlags.IRREGULAR_AREA;
|
||||
|
||||
checkHitResult(
|
||||
hitTest(centerOf("taNone")),
|
||||
APZHitResultFlags.VISIBLE |
|
||||
|
@ -263,7 +257,7 @@ async function test() {
|
|||
checkHitResult(
|
||||
hitTest(centerOf("taInnerManipListener")),
|
||||
APZHitResultFlags.VISIBLE |
|
||||
touchListenerFlag |
|
||||
APZHitResultFlags.APZ_AWARE_LISTENERS |
|
||||
APZHitResultFlags.DOUBLE_TAP_ZOOM_DISABLED,
|
||||
scrollId,
|
||||
layersId,
|
||||
|
@ -272,14 +266,14 @@ async function test() {
|
|||
checkHitResult(
|
||||
hitTest(centerOf("taListener")),
|
||||
APZHitResultFlags.VISIBLE |
|
||||
touchListenerFlag,
|
||||
APZHitResultFlags.APZ_AWARE_LISTENERS,
|
||||
scrollId,
|
||||
layersId,
|
||||
"div with touch listener");
|
||||
checkHitResult(
|
||||
hitTest(centerOf("taInnerListenerPanX")),
|
||||
APZHitResultFlags.VISIBLE |
|
||||
touchListenerFlag |
|
||||
APZHitResultFlags.APZ_AWARE_LISTENERS |
|
||||
APZHitResultFlags.PAN_Y_DISABLED |
|
||||
APZHitResultFlags.PINCH_ZOOM_DISABLED |
|
||||
APZHitResultFlags.DOUBLE_TAP_ZOOM_DISABLED,
|
||||
|
@ -351,14 +345,9 @@ async function test() {
|
|||
"overflow:hidden div doesn't reset pan-x/pan-y from enclosing scroller");
|
||||
}
|
||||
|
||||
if (!config.isWebRender) {
|
||||
ok(true, "This test is WebRender-only because we get a bunch of dispatch-to-content regions without it and the test isn't very interesting.");
|
||||
subtestDone();
|
||||
} else {
|
||||
waitUntilApzStable()
|
||||
.then(test)
|
||||
.then(subtestDone, subtestFailed);
|
||||
}
|
||||
waitUntilApzStable()
|
||||
.then(test)
|
||||
.then(subtestDone, subtestFailed);
|
||||
|
||||
</script>
|
||||
</html>
|
||||
|
|
|
@ -55,13 +55,11 @@ async function test() {
|
|||
await promiseAllPaintsDone();
|
||||
var scrollY = 300;
|
||||
utils.setAsyncScrollOffset(subframe, 0, scrollY);
|
||||
if (config.isWebRender) {
|
||||
// Tick the refresh driver once to make sure the compositor has applied the
|
||||
// async scroll offset (for APZ hit-testing this doesn't matter, but for
|
||||
// WebRender hit-testing we need to make sure WR has the latest info).
|
||||
utils.advanceTimeAndRefresh(16);
|
||||
utils.restoreNormalRefresh();
|
||||
}
|
||||
// Tick the refresh driver once to make sure the compositor has applied the
|
||||
// async scroll offset (for WebRender hit-testing we need to make sure WR has
|
||||
// the latest info).
|
||||
utils.advanceTimeAndRefresh(16);
|
||||
utils.restoreNormalRefresh();
|
||||
|
||||
// Scroll over the subframe, and make sure that the page does not scroll,
|
||||
// i.e. overscroll-behavior is respected.
|
||||
|
|
|
@ -51,12 +51,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1151663
|
|||
let config = getHitTestConfig();
|
||||
|
||||
let heightMultiplier = SpecialPowers.getCharPref("apz.y_stationary_size_multiplier");
|
||||
if (config.isWebRender) {
|
||||
// With WebRender, the effective height multiplier can be reduced
|
||||
// for alignment reasons. The reduction should be no more than a
|
||||
// factor of two.
|
||||
heightMultiplier /= 2;
|
||||
}
|
||||
// With WebRender, the effective height multiplier can be reduced
|
||||
// for alignment reasons. The reduction should be no more than a
|
||||
// factor of two.
|
||||
heightMultiplier /= 2;
|
||||
info("effective displayport height multipler is " + heightMultiplier);
|
||||
|
||||
let rootDisplayPort = getLastContentDisplayportFor('root-element');
|
||||
|
|
|
@ -33,6 +33,7 @@ var overscroll_prefs = [...prefs,
|
|||
];
|
||||
|
||||
var subtests = [
|
||||
{"file": "helper_hittest_deep_scene_stack.html", "prefs": prefs},
|
||||
{"file": "helper_hittest_pointerevents_svg.html", "prefs": prefs},
|
||||
{"file": "helper_hittest_clippath.html", "prefs": prefs},
|
||||
{"file": "helper_hittest_hoisted_scrollinfo.html", "prefs": prefs},
|
||||
|
@ -47,26 +48,10 @@ var subtests = [
|
|||
{"file": "helper_hittest_spam.html", "prefs": prefs},
|
||||
];
|
||||
|
||||
function addConditionalTests(tests) {
|
||||
// Add some more tests only useful with WebRender. Note that we do this in
|
||||
// function run after loading, because trying to read layerManagerType can
|
||||
// throw an NS_ERROR_FAILURE if called too early.
|
||||
var utils = SpecialPowers.getDOMWindowUtils(window);
|
||||
var isWebRender = utils.layerManagerType.startsWith("WebRender");
|
||||
if (isWebRender) {
|
||||
// Add new tests at the beginning, to ensure the final test remains in
|
||||
// the final position.
|
||||
tests = [
|
||||
{"file": "helper_hittest_deep_scene_stack.html", "prefs": prefs},
|
||||
].concat(tests);
|
||||
}
|
||||
return tests;
|
||||
}
|
||||
|
||||
if (isApzEnabled()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.onload = function() {
|
||||
runSubtestsSeriallyInFreshWindows(addConditionalTests(subtests))
|
||||
runSubtestsSeriallyInFreshWindows(subtests)
|
||||
.then(SimpleTest.finish, SimpleTest.finishWithFailure);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -64,12 +64,10 @@ let config = getHitTestConfig();
|
|||
let activateAllScrollFrames = config.activateAllScrollFrames;
|
||||
|
||||
let heightMultiplier = SpecialPowers.getCharPref("apz.y_stationary_size_multiplier");
|
||||
if (config.isWebRender) {
|
||||
// With WebRender, the effective height multiplier can be reduced
|
||||
// for alignment reasons. The reduction should be no more than a
|
||||
// factor of two.
|
||||
heightMultiplier /= 2;
|
||||
}
|
||||
// With WebRender, the effective height multiplier can be reduced
|
||||
// for alignment reasons. The reduction should be no more than a
|
||||
// factor of two.
|
||||
heightMultiplier /= 2;
|
||||
info("effective displayport height multipler is " + heightMultiplier);
|
||||
|
||||
function hasNonZeroMarginDisplayPort(elementId, containingDoc = null) {
|
||||
|
|
|
@ -404,9 +404,7 @@ struct DIGroup {
|
|||
InvalidateRect(aData->mRect);
|
||||
aData->mInvalid = true;
|
||||
invalidated = true;
|
||||
} else if (aData->mInvalid ||
|
||||
/* XXX: handle image load invalidation */ (
|
||||
aItem->IsInvalid(invalid) && invalid.IsEmpty())) {
|
||||
} else if (aItem->IsInvalid(invalid) && invalid.IsEmpty()) {
|
||||
UniquePtr<nsDisplayItemGeometry> geometry(
|
||||
aItem->AllocateGeometry(aBuilder));
|
||||
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
|
||||
|
|
|
@ -481,6 +481,13 @@ void gfxPlatform::InitChild(const ContentDeviceData& aData) {
|
|||
|
||||
#define WR_DEBUG_PREF "gfx.webrender.debug"
|
||||
|
||||
static void SwapIntervalPrefChangeCallback(const char* aPrefName, void*) {
|
||||
bool egl = Preferences::GetBool("gfx.swap-interval.egl", false);
|
||||
bool glx = Preferences::GetBool("gfx.swap-interval.glx", false);
|
||||
gfxVars::SetSwapIntervalEGL(egl);
|
||||
gfxVars::SetSwapIntervalGLX(glx);
|
||||
}
|
||||
|
||||
static void WebRendeProfilerUIPrefChangeCallback(const char* aPrefName, void*) {
|
||||
nsCString uiString;
|
||||
if (NS_SUCCEEDED(Preferences::GetCString("gfx.webrender.debug.profiler-ui",
|
||||
|
@ -2571,6 +2578,9 @@ void gfxPlatform::InitWebRenderConfig() {
|
|||
|
||||
gfxVars::SetUseSoftwareWebRender(!hasHardware && hasSoftware);
|
||||
|
||||
Preferences::RegisterPrefixCallbackAndCall(SwapIntervalPrefChangeCallback,
|
||||
"gfx.swap-interval");
|
||||
|
||||
// gfxFeature is not usable in the GPU process, so we use gfxVars to transmit
|
||||
// this feature
|
||||
if (hasWebRender) {
|
||||
|
|
|
@ -191,8 +191,9 @@ bool RenderCompositorEGL::Resume() {
|
|||
const auto& gle = gl::GLContextEGL::Cast(gl());
|
||||
const auto& egl = gle->mEgl;
|
||||
MakeCurrent();
|
||||
// Make eglSwapBuffers() non-blocking on wayland.
|
||||
egl->fSwapInterval(0);
|
||||
|
||||
const int interval = gfx::gfxVars::SwapIntervalEGL() ? 1 : 0;
|
||||
egl->fSwapInterval(interval);
|
||||
} else {
|
||||
RenderThread::Get()->HandleWebRenderError(WebRenderError::NEW_SURFACE);
|
||||
return false;
|
||||
|
|
|
@ -370,11 +370,12 @@ static inline bool IS_HYPHEN(char16_t u) {
|
|||
return (u == U_HYPHEN || u == 0x2010 || // HYPHEN
|
||||
u == 0x2012 || // FIGURE DASH
|
||||
u == 0x2013 || // EN DASH
|
||||
#if ANDROID
|
||||
/* Bug 1647377: On Android, we don't have a "platform" backend
|
||||
* that supports Tibetan (nsRuleBreaker.cpp only knows about
|
||||
* Thai), so instead we just treat the TSHEG like a hyphen to
|
||||
* provide basic line-breaking possibilities.
|
||||
#if ANDROID || XP_WIN
|
||||
/* Bug 1647377: On Android and Windows, we don't have a "platform"
|
||||
* backend that supports Tibetan (nsRuleBreaker.cpp only knows about
|
||||
* Thai, and ScriptBreak doesn't handle Tibetan well either), so
|
||||
* instead we just treat the TSHEG like a hyphen to provide basic
|
||||
* line-breaking possibilities.
|
||||
*/
|
||||
u == 0x0F0B || // TIBETAN MARK INTERSYLLABIC TSHEG
|
||||
#endif
|
||||
|
|
|
@ -76,8 +76,8 @@ static inline bool NS_IsSpace(char16_t u) {
|
|||
|
||||
static inline bool NS_NeedsPlatformNativeHandling(char16_t aChar) {
|
||||
return
|
||||
#if ANDROID // Bug 1647377: no "platform native" support for Tibetan;
|
||||
// better to just use our class-based breaker.
|
||||
#if ANDROID || XP_WIN // Bug 1647377/1736393: no "platform native" support for
|
||||
// Tibetan; better to just use our class-based breaker.
|
||||
(0x0e01 <= aChar && aChar <= 0x0eff) || // Thai, Lao
|
||||
#else
|
||||
(0x0e01 <= aChar && aChar <= 0x0fff) || // Thai, Lao, Tibetan
|
||||
|
|
|
@ -79,12 +79,7 @@ class GCHashMap : public js::HashMap<Key, Value, HashPolicy, AllocPolicy> {
|
|||
}
|
||||
|
||||
void sweep() {
|
||||
typename Base::Enum e(*this);
|
||||
sweepEntries(e);
|
||||
}
|
||||
|
||||
void sweepEntries(typename Base::Enum& e) {
|
||||
for (; !e.empty(); e.popFront()) {
|
||||
for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
|
||||
if (MapSweepPolicy::needsSweep(&e.front().mutableKey(),
|
||||
&e.front().value())) {
|
||||
e.removeFront();
|
||||
|
@ -92,7 +87,13 @@ class GCHashMap : public js::HashMap<Key, Value, HashPolicy, AllocPolicy> {
|
|||
}
|
||||
}
|
||||
|
||||
void traceWeak(JSTracer* trc) {
|
||||
bool traceWeak(JSTracer* trc) {
|
||||
typename Base::Enum e(*this);
|
||||
traceWeakEntries(trc, e);
|
||||
return !this->empty();
|
||||
}
|
||||
|
||||
void traceWeakEntries(JSTracer* trc, typename Base::Enum& e) {
|
||||
for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
|
||||
if (!MapSweepPolicy::traceWeak(trc, &e.front().mutableKey(),
|
||||
&e.front().value())) {
|
||||
|
@ -149,7 +150,7 @@ class GCRekeyableHashMap : public JS::GCHashMap<Key, Value, HashPolicy,
|
|||
}
|
||||
}
|
||||
|
||||
void traceWeak(JSTracer* trc) {
|
||||
bool traceWeak(JSTracer* trc) {
|
||||
for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
|
||||
Key key(e.front().key());
|
||||
if (!MapSweepPolicy::traceWeak(trc, &key, &e.front().value())) {
|
||||
|
@ -158,6 +159,7 @@ class GCRekeyableHashMap : public JS::GCHashMap<Key, Value, HashPolicy,
|
|||
e.rekeyFront(key);
|
||||
}
|
||||
}
|
||||
return !this->empty();
|
||||
}
|
||||
|
||||
// GCRekeyableHashMap is movable
|
||||
|
@ -275,21 +277,14 @@ class GCHashSet : public js::HashSet<T, HashPolicy, AllocPolicy> {
|
|||
}
|
||||
}
|
||||
|
||||
void sweep() {
|
||||
bool traceWeak(JSTracer* trc) {
|
||||
typename Base::Enum e(*this);
|
||||
sweepEntries(e);
|
||||
traceWeakEntries(trc, e);
|
||||
return !this->empty();
|
||||
}
|
||||
|
||||
void sweepEntries(typename Base::Enum& e) {
|
||||
void traceWeakEntries(JSTracer* trc, typename Base::Enum& e) {
|
||||
for (; !e.empty(); e.popFront()) {
|
||||
if (GCPolicy<T>::needsSweep(&e.mutableFront())) {
|
||||
e.removeFront();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void traceWeak(JSTracer* trc) {
|
||||
for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
|
||||
if (!GCPolicy<T>::traceWeak(trc, &e.mutableFront())) {
|
||||
e.removeFront();
|
||||
}
|
||||
|
@ -404,35 +399,31 @@ namespace JS {
|
|||
template <typename Key, typename Value, typename HashPolicy,
|
||||
typename AllocPolicy, typename MapSweepPolicy>
|
||||
class WeakCache<GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>>
|
||||
: protected detail::WeakCacheBase {
|
||||
final : protected detail::WeakCacheBase {
|
||||
using Map = GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>;
|
||||
using Self = WeakCache<Map>;
|
||||
|
||||
Map map;
|
||||
bool needsBarrier;
|
||||
JSTracer* barrierTracer = nullptr;
|
||||
|
||||
public:
|
||||
template <typename... Args>
|
||||
explicit WeakCache(Zone* zone, Args&&... args)
|
||||
: WeakCacheBase(zone),
|
||||
map(std::forward<Args>(args)...),
|
||||
needsBarrier(false) {}
|
||||
: WeakCacheBase(zone), map(std::forward<Args>(args)...) {}
|
||||
template <typename... Args>
|
||||
explicit WeakCache(JSRuntime* rt, Args&&... args)
|
||||
: WeakCacheBase(rt),
|
||||
map(std::forward<Args>(args)...),
|
||||
needsBarrier(false) {}
|
||||
~WeakCache() { MOZ_ASSERT(!needsBarrier); }
|
||||
: WeakCacheBase(rt), map(std::forward<Args>(args)...) {}
|
||||
~WeakCache() { MOZ_ASSERT(!barrierTracer); }
|
||||
|
||||
bool empty() override { return map.empty(); }
|
||||
|
||||
size_t sweep(js::gc::StoreBuffer* sbToLock) override {
|
||||
size_t traceWeak(JSTracer* trc, js::gc::StoreBuffer* sbToLock) override {
|
||||
size_t steps = map.count();
|
||||
|
||||
// Create an Enum and sweep the table entries.
|
||||
mozilla::Maybe<typename Map::Enum> e;
|
||||
e.emplace(map);
|
||||
map.sweepEntries(e.ref());
|
||||
map.traceWeakEntries(trc, e.ref());
|
||||
|
||||
// Potentially take a lock while the Enum's destructor is called as this can
|
||||
// rehash/resize the table and access the store buffer.
|
||||
|
@ -445,24 +436,26 @@ class WeakCache<GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>>
|
|||
return steps;
|
||||
}
|
||||
|
||||
bool setNeedsIncrementalBarrier(bool needs) override {
|
||||
MOZ_ASSERT(needsBarrier != needs);
|
||||
needsBarrier = needs;
|
||||
bool setIncrementalBarrierTracer(JSTracer* trc) override {
|
||||
MOZ_ASSERT(bool(barrierTracer) != bool(trc));
|
||||
barrierTracer = trc;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool needsIncrementalBarrier() const override { return needsBarrier; }
|
||||
bool needsIncrementalBarrier() const override { return barrierTracer; }
|
||||
|
||||
private:
|
||||
using Entry = typename Map::Entry;
|
||||
|
||||
static bool entryNeedsSweep(const Entry& prior) {
|
||||
static bool entryNeedsSweep(JSTracer* barrierTracer, const Entry& prior) {
|
||||
Key key(prior.key());
|
||||
Value value(prior.value());
|
||||
bool result = MapSweepPolicy::needsSweep(&key, &value);
|
||||
MOZ_ASSERT(prior.key() == key); // We shouldn't update here.
|
||||
MOZ_ASSERT(prior.value() == value); // We shouldn't update here.
|
||||
return result;
|
||||
bool needsSweep = !MapSweepPolicy::traceWeak(barrierTracer, &key, &value);
|
||||
MOZ_ASSERT_IF(!needsSweep,
|
||||
prior.key() == key); // We shouldn't update here.
|
||||
MOZ_ASSERT_IF(!needsSweep,
|
||||
prior.value() == value); // We shouldn't update here.
|
||||
return needsSweep;
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -470,8 +463,11 @@ class WeakCache<GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>>
|
|||
using Ptr = typename Map::Ptr;
|
||||
using AddPtr = typename Map::AddPtr;
|
||||
|
||||
// Iterator over the whole collection.
|
||||
struct Range {
|
||||
explicit Range(const typename Map::Range& r) : range(r) { settle(); }
|
||||
explicit Range(Self& self) : cache(self), range(self.map.all()) {
|
||||
settle();
|
||||
}
|
||||
Range() = default;
|
||||
|
||||
bool empty() const { return range.empty(); }
|
||||
|
@ -483,11 +479,14 @@ class WeakCache<GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>>
|
|||
}
|
||||
|
||||
private:
|
||||
Self& cache;
|
||||
typename Map::Range range;
|
||||
|
||||
void settle() {
|
||||
while (!empty() && entryNeedsSweep(front())) {
|
||||
popFront();
|
||||
if (JSTracer* trc = cache.barrierTracer) {
|
||||
while (!empty() && entryNeedsSweep(trc, front())) {
|
||||
popFront();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -496,13 +495,13 @@ class WeakCache<GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>>
|
|||
explicit Enum(Self& cache) : Map::Enum(cache.map) {
|
||||
// This operation is not allowed while barriers are in place as we
|
||||
// may also need to enumerate the set for sweeping.
|
||||
MOZ_ASSERT(!cache.needsBarrier);
|
||||
MOZ_ASSERT(!cache.barrierTracer);
|
||||
}
|
||||
};
|
||||
|
||||
Ptr lookup(const Lookup& l) const {
|
||||
Ptr ptr = map.lookup(l);
|
||||
if (needsBarrier && ptr && entryNeedsSweep(*ptr)) {
|
||||
if (barrierTracer && ptr && entryNeedsSweep(barrierTracer, *ptr)) {
|
||||
const_cast<Map&>(map).remove(ptr);
|
||||
return Ptr();
|
||||
}
|
||||
|
@ -511,20 +510,20 @@ class WeakCache<GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>>
|
|||
|
||||
AddPtr lookupForAdd(const Lookup& l) {
|
||||
AddPtr ptr = map.lookupForAdd(l);
|
||||
if (needsBarrier && ptr && entryNeedsSweep(*ptr)) {
|
||||
if (barrierTracer && ptr && entryNeedsSweep(barrierTracer, *ptr)) {
|
||||
const_cast<Map&>(map).remove(ptr);
|
||||
return map.lookupForAdd(l);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
Range all() const { return Range(map.all()); }
|
||||
Range all() const { return Range(*const_cast<Self*>(this)); }
|
||||
|
||||
bool empty() const {
|
||||
// This operation is not currently allowed while barriers are in place
|
||||
// as it would require iterating the map and the caller expects a
|
||||
// constant time operation.
|
||||
MOZ_ASSERT(!needsBarrier);
|
||||
MOZ_ASSERT(!barrierTracer);
|
||||
return map.empty();
|
||||
}
|
||||
|
||||
|
@ -532,7 +531,7 @@ class WeakCache<GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>>
|
|||
// This operation is not currently allowed while barriers are in place
|
||||
// as it would require iterating the set and the caller expects a
|
||||
// constant time operation.
|
||||
MOZ_ASSERT(!needsBarrier);
|
||||
MOZ_ASSERT(!barrierTracer);
|
||||
return map.count();
|
||||
}
|
||||
|
||||
|
@ -550,14 +549,14 @@ class WeakCache<GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>>
|
|||
void clear() {
|
||||
// This operation is not currently allowed while barriers are in place
|
||||
// since it doesn't make sense to clear a cache while it is being swept.
|
||||
MOZ_ASSERT(!needsBarrier);
|
||||
MOZ_ASSERT(!barrierTracer);
|
||||
map.clear();
|
||||
}
|
||||
|
||||
void clearAndCompact() {
|
||||
// This operation is not currently allowed while barriers are in place
|
||||
// since it doesn't make sense to clear a cache while it is being swept.
|
||||
MOZ_ASSERT(!needsBarrier);
|
||||
MOZ_ASSERT(!barrierTracer);
|
||||
map.clearAndCompact();
|
||||
}
|
||||
|
||||
|
@ -600,36 +599,32 @@ class WeakCache<GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>>
|
|||
// Specialize WeakCache for GCHashSet to provide a barriered set that does not
|
||||
// need to be swept immediately.
|
||||
template <typename T, typename HashPolicy, typename AllocPolicy>
|
||||
class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>>
|
||||
class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>> final
|
||||
: protected detail::WeakCacheBase {
|
||||
using Set = GCHashSet<T, HashPolicy, AllocPolicy>;
|
||||
using Self = WeakCache<Set>;
|
||||
|
||||
Set set;
|
||||
bool needsBarrier;
|
||||
JSTracer* barrierTracer = nullptr;
|
||||
|
||||
public:
|
||||
using Entry = typename Set::Entry;
|
||||
|
||||
template <typename... Args>
|
||||
explicit WeakCache(Zone* zone, Args&&... args)
|
||||
: WeakCacheBase(zone),
|
||||
set(std::forward<Args>(args)...),
|
||||
needsBarrier(false) {}
|
||||
: WeakCacheBase(zone), set(std::forward<Args>(args)...) {}
|
||||
template <typename... Args>
|
||||
explicit WeakCache(JSRuntime* rt, Args&&... args)
|
||||
: WeakCacheBase(rt),
|
||||
set(std::forward<Args>(args)...),
|
||||
needsBarrier(false) {}
|
||||
: WeakCacheBase(rt), set(std::forward<Args>(args)...) {}
|
||||
|
||||
size_t sweep(js::gc::StoreBuffer* sbToLock) override {
|
||||
size_t traceWeak(JSTracer* trc, js::gc::StoreBuffer* sbToLock) override {
|
||||
size_t steps = set.count();
|
||||
|
||||
// Create an Enum and sweep the table entries. It's not necessary to take
|
||||
// the store buffer lock yet.
|
||||
mozilla::Maybe<typename Set::Enum> e;
|
||||
e.emplace(set);
|
||||
set.sweepEntries(e.ref());
|
||||
set.traceWeakEntries(trc, e.ref());
|
||||
|
||||
// Destroy the Enum, potentially rehashing or resizing the table. Since this
|
||||
// can access the store buffer, we need to take a lock for this if we're
|
||||
|
@ -645,20 +640,20 @@ class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>>
|
|||
|
||||
bool empty() override { return set.empty(); }
|
||||
|
||||
bool setNeedsIncrementalBarrier(bool needs) override {
|
||||
MOZ_ASSERT(needsBarrier != needs);
|
||||
needsBarrier = needs;
|
||||
bool setIncrementalBarrierTracer(JSTracer* trc) override {
|
||||
MOZ_ASSERT(bool(barrierTracer) != bool(trc));
|
||||
barrierTracer = trc;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool needsIncrementalBarrier() const override { return needsBarrier; }
|
||||
bool needsIncrementalBarrier() const override { return barrierTracer; }
|
||||
|
||||
private:
|
||||
static bool entryNeedsSweep(const Entry& prior) {
|
||||
static bool entryNeedsSweep(JSTracer* barrierTracer, const Entry& prior) {
|
||||
Entry entry(prior);
|
||||
bool result = GCPolicy<T>::needsSweep(&entry);
|
||||
MOZ_ASSERT(prior == entry); // We shouldn't update here.
|
||||
return result;
|
||||
bool needsSweep = !GCPolicy<T>::traceWeak(barrierTracer, &entry);
|
||||
MOZ_ASSERT_IF(!needsSweep, prior == entry); // We shouldn't update here.
|
||||
return needsSweep;
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -666,8 +661,11 @@ class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>>
|
|||
using Ptr = typename Set::Ptr;
|
||||
using AddPtr = typename Set::AddPtr;
|
||||
|
||||
// Iterator over the whole collection.
|
||||
struct Range {
|
||||
explicit Range(const typename Set::Range& r) : range(r) { settle(); }
|
||||
explicit Range(Self& self) : cache(self), range(self.set.all()) {
|
||||
settle();
|
||||
}
|
||||
Range() = default;
|
||||
|
||||
bool empty() const { return range.empty(); }
|
||||
|
@ -679,11 +677,14 @@ class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>>
|
|||
}
|
||||
|
||||
private:
|
||||
Self& cache;
|
||||
typename Set::Range range;
|
||||
|
||||
void settle() {
|
||||
while (!empty() && entryNeedsSweep(front())) {
|
||||
popFront();
|
||||
if (JSTracer* trc = cache.barrierTracer) {
|
||||
while (!empty() && entryNeedsSweep(trc, front())) {
|
||||
popFront();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -692,13 +693,13 @@ class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>>
|
|||
explicit Enum(Self& cache) : Set::Enum(cache.set) {
|
||||
// This operation is not allowed while barriers are in place as we
|
||||
// may also need to enumerate the set for sweeping.
|
||||
MOZ_ASSERT(!cache.needsBarrier);
|
||||
MOZ_ASSERT(!cache.barrierTracer);
|
||||
}
|
||||
};
|
||||
|
||||
Ptr lookup(const Lookup& l) const {
|
||||
Ptr ptr = set.lookup(l);
|
||||
if (needsBarrier && ptr && entryNeedsSweep(*ptr)) {
|
||||
if (barrierTracer && ptr && entryNeedsSweep(barrierTracer, *ptr)) {
|
||||
const_cast<Set&>(set).remove(ptr);
|
||||
return Ptr();
|
||||
}
|
||||
|
@ -707,20 +708,20 @@ class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>>
|
|||
|
||||
AddPtr lookupForAdd(const Lookup& l) {
|
||||
AddPtr ptr = set.lookupForAdd(l);
|
||||
if (needsBarrier && ptr && entryNeedsSweep(*ptr)) {
|
||||
if (barrierTracer && ptr && entryNeedsSweep(barrierTracer, *ptr)) {
|
||||
const_cast<Set&>(set).remove(ptr);
|
||||
return set.lookupForAdd(l);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
Range all() const { return Range(set.all()); }
|
||||
Range all() const { return Range(*const_cast<Self*>(this)); }
|
||||
|
||||
bool empty() const {
|
||||
// This operation is not currently allowed while barriers are in place
|
||||
// as it would require iterating the set and the caller expects a
|
||||
// constant time operation.
|
||||
MOZ_ASSERT(!needsBarrier);
|
||||
MOZ_ASSERT(!barrierTracer);
|
||||
return set.empty();
|
||||
}
|
||||
|
||||
|
@ -728,7 +729,7 @@ class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>>
|
|||
// This operation is not currently allowed while barriers are in place
|
||||
// as it would require iterating the set and the caller expects a
|
||||
// constant time operation.
|
||||
MOZ_ASSERT(!needsBarrier);
|
||||
MOZ_ASSERT(!barrierTracer);
|
||||
return set.count();
|
||||
}
|
||||
|
||||
|
@ -746,14 +747,14 @@ class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>>
|
|||
void clear() {
|
||||
// This operation is not currently allowed while barriers are in place
|
||||
// since it doesn't make sense to clear a cache while it is being swept.
|
||||
MOZ_ASSERT(!needsBarrier);
|
||||
MOZ_ASSERT(!barrierTracer);
|
||||
set.clear();
|
||||
}
|
||||
|
||||
void clearAndCompact() {
|
||||
// This operation is not currently allowed while barriers are in place
|
||||
// since it doesn't make sense to clear a cache while it is being swept.
|
||||
MOZ_ASSERT(!needsBarrier);
|
||||
MOZ_ASSERT(!barrierTracer);
|
||||
set.clearAndCompact();
|
||||
}
|
||||
|
||||
|
|
|
@ -60,12 +60,14 @@ class WeakCacheBase : public mozilla::LinkedListElement<WeakCacheBase> {
|
|||
WeakCacheBase(WeakCacheBase&& other) = default;
|
||||
virtual ~WeakCacheBase() = default;
|
||||
|
||||
virtual size_t sweep(js::gc::StoreBuffer* sbToLock) = 0;
|
||||
virtual size_t traceWeak(JSTracer* trc, js::gc::StoreBuffer* sbToLock) = 0;
|
||||
|
||||
// Sweeping will be skipped if the cache is empty already.
|
||||
virtual bool empty() = 0;
|
||||
|
||||
virtual bool setNeedsIncrementalBarrier(bool needs) {
|
||||
// Enable/disable read barrier during incremental sweeping and set the tracer
|
||||
// to use.
|
||||
virtual bool setIncrementalBarrierTracer(JSTracer* trc) {
|
||||
// Derived classes do not support incremental barriers by default.
|
||||
return false;
|
||||
}
|
||||
|
@ -98,7 +100,7 @@ class WeakCache : protected detail::WeakCacheBase,
|
|||
const T& get() const { return cache; }
|
||||
T& get() { return cache; }
|
||||
|
||||
size_t sweep(js::gc::StoreBuffer* sbToLock) override {
|
||||
size_t traceWeak(JSTracer* trc, js::gc::StoreBuffer* sbToLock) override {
|
||||
// Take the store buffer lock in case sweeping triggers any generational
|
||||
// post barriers. This is not always required and WeakCache specializations
|
||||
// may delay or skip taking the lock as appropriate.
|
||||
|
@ -107,7 +109,7 @@ class WeakCache : protected detail::WeakCacheBase,
|
|||
lock.emplace(sbToLock);
|
||||
}
|
||||
|
||||
GCPolicy<T>::sweep(&cache);
|
||||
GCPolicy<T>::traceWeak(trc, &cache);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -459,11 +459,10 @@ void GCRuntime::sweepZoneAfterCompacting(MovingTracer* trc, Zone* zone) {
|
|||
traceWeakFinalizationRegistryEdges(trc, zone);
|
||||
zone->weakRefMap().sweep(&storeBuffer());
|
||||
|
||||
{
|
||||
zone->sweepWeakMaps();
|
||||
for (auto* cache : zone->weakCaches()) {
|
||||
cache->sweep(nullptr);
|
||||
}
|
||||
zone->traceWeakMaps(trc);
|
||||
|
||||
for (auto* cache : zone->weakCaches()) {
|
||||
cache->traceWeak(trc, nullptr);
|
||||
}
|
||||
|
||||
if (jit::JitZone* jitZone = zone->jitZone()) {
|
||||
|
@ -656,7 +655,7 @@ void GCRuntime::updateRttValueObjects(MovingTracer* trc, Zone* zone) {
|
|||
// need to be updated. Do not update any non-reserved slots, since they might
|
||||
// point back to unprocessed descriptor objects.
|
||||
|
||||
zone->rttValueObjects().sweep(nullptr);
|
||||
zone->rttValueObjects().traceWeak(trc, nullptr);
|
||||
|
||||
for (auto r = zone->rttValueObjects().all(); !r.empty(); r.popFront()) {
|
||||
RttValue* obj = &MaybeForwardedObjectAs<RttValue>(r.front());
|
||||
|
@ -797,13 +796,6 @@ void GCRuntime::updateZonePointersToRelocatedCells(Zone* zone) {
|
|||
// as much as possible.
|
||||
updateAllCellPointers(&trc, zone);
|
||||
|
||||
// Mark roots to update them.
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
|
||||
|
||||
WeakMapBase::traceZone(zone, &trc);
|
||||
}
|
||||
|
||||
// Sweep everything to fix up weak pointers.
|
||||
sweepZoneAfterCompacting(&trc, zone);
|
||||
|
||||
|
@ -845,7 +837,7 @@ void GCRuntime::updateRuntimePointersToRelocatedCells(AutoGCSession& session) {
|
|||
// Sweep everything to fix up weak pointers.
|
||||
jit::JitRuntime::TraceWeakJitcodeGlobalTable(rt, &trc);
|
||||
for (JS::detail::WeakCacheBase* cache : rt->weakCaches()) {
|
||||
cache->sweep(nullptr);
|
||||
cache->traceWeak(&trc, nullptr);
|
||||
}
|
||||
|
||||
// Type inference may put more blocks here to free.
|
||||
|
|
|
@ -370,6 +370,7 @@ GCRuntime::GCRuntime(JSRuntime* rt)
|
|||
stats_(this),
|
||||
marker(rt),
|
||||
barrierTracer(rt),
|
||||
sweepingTracer(rt),
|
||||
heapSize(nullptr),
|
||||
helperThreadRatio(TuningDefaults::HelperThreadRatio),
|
||||
maxHelperThreads(TuningDefaults::MaxHelperThreads),
|
||||
|
|
|
@ -279,15 +279,6 @@ struct MovingTracer final : public GenericTracerImpl<MovingTracer> {
|
|||
friend class GenericTracerImpl<MovingTracer>;
|
||||
};
|
||||
|
||||
struct SweepingTracer final : public GenericTracerImpl<SweepingTracer> {
|
||||
explicit SweepingTracer(JSRuntime* rt);
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
T* onEdge(T* thingp);
|
||||
friend class GenericTracerImpl<SweepingTracer>;
|
||||
};
|
||||
|
||||
struct MinorSweepingTracer final
|
||||
: public GenericTracerImpl<MinorSweepingTracer> {
|
||||
explicit MinorSweepingTracer(JSRuntime* rt);
|
||||
|
|
|
@ -271,6 +271,15 @@ class BarrierTracer final : public GenericTracerImpl<BarrierTracer> {
|
|||
GCMarker& marker;
|
||||
};
|
||||
|
||||
struct SweepingTracer final : public GenericTracerImpl<SweepingTracer> {
|
||||
explicit SweepingTracer(JSRuntime* rt);
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
T* onEdge(T* thingp);
|
||||
friend class GenericTracerImpl<SweepingTracer>;
|
||||
};
|
||||
|
||||
class GCRuntime {
|
||||
friend GCMarker::MarkQueueProgress GCMarker::processMarkQueue();
|
||||
|
||||
|
@ -912,6 +921,7 @@ class GCRuntime {
|
|||
|
||||
GCMarker marker;
|
||||
BarrierTracer barrierTracer;
|
||||
SweepingTracer sweepingTracer;
|
||||
|
||||
Vector<JS::GCCellPtr, 0, SystemAllocPolicy> unmarkGrayStack;
|
||||
|
||||
|
|
|
@ -1177,7 +1177,8 @@ class ImmediateSweepWeakCacheTask : public GCParallelTask {
|
|||
void run(AutoLockHelperThreadState& lock) override {
|
||||
AutoUnlockHelperThreadState unlock(lock);
|
||||
AutoSetThreadIsSweeping threadIsSweeping(zone);
|
||||
cache.sweep(&gc->storeBuffer());
|
||||
SweepingTracer trc(gc->rt);
|
||||
cache.traceWeak(&trc, &gc->storeBuffer());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1237,6 +1238,7 @@ void GCRuntime::sweepCompressionTasks() {
|
|||
}
|
||||
|
||||
void GCRuntime::sweepWeakMaps() {
|
||||
SweepingTracer trc(rt);
|
||||
AutoSetThreadIsSweeping threadIsSweeping; // This may touch any zone.
|
||||
for (SweepGroupZonesIter zone(this); !zone.done(); zone.next()) {
|
||||
/* No need to look up any more weakmap keys from this sweep group. */
|
||||
|
@ -1248,7 +1250,7 @@ void GCRuntime::sweepWeakMaps() {
|
|||
// Lock the storebuffer since this may access it when rehashing or resizing
|
||||
// the tables.
|
||||
AutoLockStoreBuffer lock(&storeBuffer());
|
||||
zone->sweepWeakMaps();
|
||||
zone->sweepWeakMaps(&trc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1406,6 +1408,7 @@ static bool PrepareWeakCacheTasks(JSRuntime* rt,
|
|||
|
||||
MOZ_ASSERT(immediateTasks->empty());
|
||||
|
||||
GCRuntime* gc = &rt->gc;
|
||||
bool ok =
|
||||
IterateWeakCaches(rt, [&](JS::detail::WeakCacheBase* cache, Zone* zone) {
|
||||
if (cache->empty()) {
|
||||
|
@ -1413,11 +1416,11 @@ static bool PrepareWeakCacheTasks(JSRuntime* rt,
|
|||
}
|
||||
|
||||
// Caches that support incremental sweeping will be swept later.
|
||||
if (zone && cache->setNeedsIncrementalBarrier(true)) {
|
||||
if (zone && cache->setIncrementalBarrierTracer(&gc->sweepingTracer)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return immediateTasks->emplaceBack(&rt->gc, zone, *cache);
|
||||
return immediateTasks->emplaceBack(gc, zone, *cache);
|
||||
});
|
||||
|
||||
if (!ok) {
|
||||
|
@ -1430,11 +1433,12 @@ static bool PrepareWeakCacheTasks(JSRuntime* rt,
|
|||
static void SweepAllWeakCachesOnMainThread(JSRuntime* rt) {
|
||||
// If we ran out of memory, do all the work on the main thread.
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::SWEEP_WEAK_CACHES);
|
||||
SweepingTracer trc(rt);
|
||||
IterateWeakCaches(rt, [&](JS::detail::WeakCacheBase* cache, Zone* zone) {
|
||||
if (cache->needsIncrementalBarrier()) {
|
||||
cache->setNeedsIncrementalBarrier(false);
|
||||
cache->setIncrementalBarrierTracer(nullptr);
|
||||
}
|
||||
cache->sweep(&rt->gc.storeBuffer());
|
||||
cache->traceWeak(&trc, &rt->gc.storeBuffer());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
@ -1843,8 +1847,10 @@ static size_t IncrementalSweepWeakCache(GCRuntime* gc,
|
|||
|
||||
JS::detail::WeakCacheBase* cache = item.cache;
|
||||
MOZ_ASSERT(cache->needsIncrementalBarrier());
|
||||
size_t steps = cache->sweep(&gc->storeBuffer());
|
||||
cache->setNeedsIncrementalBarrier(false);
|
||||
|
||||
SweepingTracer trc(gc->rt);
|
||||
size_t steps = cache->traceWeak(&trc, &gc->storeBuffer());
|
||||
cache->setIncrementalBarrierTracer(nullptr);
|
||||
|
||||
return steps;
|
||||
}
|
||||
|
|
|
@ -336,10 +336,10 @@ bool WeakMap<K, V>::markEntries(GCMarker* marker) {
|
|||
}
|
||||
|
||||
template <class K, class V>
|
||||
void WeakMap<K, V>::sweep() {
|
||||
/* Remove all entries whose keys remain unmarked. */
|
||||
void WeakMap<K, V>::traceWeakEdges(JSTracer* trc) {
|
||||
// Remove all entries whose keys remain unmarked.
|
||||
for (Enum e(*this); !e.empty(); e.popFront()) {
|
||||
if (gc::IsAboutToBeFinalized(&e.front().mutableKey())) {
|
||||
if (!TraceWeakEdge(trc, &e.front().mutableKey(), "WeakMap key")) {
|
||||
e.removeFront();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,11 +41,11 @@ void WeakMapBase::unmarkZone(JS::Zone* zone) {
|
|||
}
|
||||
}
|
||||
|
||||
void WeakMapBase::traceZone(JS::Zone* zone, JSTracer* tracer) {
|
||||
MOZ_ASSERT(tracer->weakMapAction() != JS::WeakMapTraceAction::Skip);
|
||||
for (WeakMapBase* m : zone->gcWeakMapList()) {
|
||||
m->trace(tracer);
|
||||
TraceNullableEdge(tracer, &m->memberOf, "memberOf");
|
||||
void Zone::traceWeakMaps(JSTracer* trc) {
|
||||
MOZ_ASSERT(trc->weakMapAction() != JS::WeakMapTraceAction::Skip);
|
||||
for (WeakMapBase* m : gcWeakMapList()) {
|
||||
m->trace(trc);
|
||||
TraceNullableEdge(trc, &m->memberOf, "memberOf");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,20 +84,20 @@ bool WeakMapBase::findSweepGroupEdgesForZone(JS::Zone* zone) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void WeakMapBase::sweepZone(JS::Zone* zone) {
|
||||
for (WeakMapBase* m = zone->gcWeakMapList().getFirst(); m;) {
|
||||
void Zone::sweepWeakMaps(JSTracer* trc) {
|
||||
for (WeakMapBase* m = gcWeakMapList().getFirst(); m;) {
|
||||
WeakMapBase* next = m->getNext();
|
||||
if (m->mapColor) {
|
||||
m->sweep();
|
||||
m->traceWeakEdges(trc);
|
||||
} else {
|
||||
m->clearAndCompact();
|
||||
m->removeFrom(zone->gcWeakMapList());
|
||||
m->removeFrom(gcWeakMapList());
|
||||
}
|
||||
m = next;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
for (WeakMapBase* m : zone->gcWeakMapList()) {
|
||||
for (WeakMapBase* m : gcWeakMapList()) {
|
||||
MOZ_ASSERT(m->isInList() && m->mapColor);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -107,9 +107,6 @@ class WeakMapBase : public mozilla::LinkedListElement<WeakMapBase> {
|
|||
// Unmark all weak maps in a zone.
|
||||
static void unmarkZone(JS::Zone* zone);
|
||||
|
||||
// Trace all the weakmaps in a zone.
|
||||
static void traceZone(JS::Zone* zone, JSTracer* tracer);
|
||||
|
||||
// Check all weak maps in a zone that have been marked as live in this garbage
|
||||
// collection, and mark the values of all entries that have become strong
|
||||
// references to them. Return true if we marked any new values, indicating
|
||||
|
@ -120,10 +117,6 @@ class WeakMapBase : public mozilla::LinkedListElement<WeakMapBase> {
|
|||
// Add zone edges for weakmaps with key delegates in a different zone.
|
||||
[[nodiscard]] static bool findSweepGroupEdgesForZone(JS::Zone* zone);
|
||||
|
||||
// Sweep the weak maps in a zone, removing dead weak maps and removing
|
||||
// entries of live weak maps whose keys are dead.
|
||||
static void sweepZone(JS::Zone* zone);
|
||||
|
||||
// Sweep the marked weak maps in a zone, updating moved keys.
|
||||
static void sweepZoneAfterMinorGC(JS::Zone* zone);
|
||||
|
||||
|
@ -146,7 +139,7 @@ class WeakMapBase : public mozilla::LinkedListElement<WeakMapBase> {
|
|||
// override these with definitions appropriate for their Key and Value types.
|
||||
virtual void trace(JSTracer* tracer) = 0;
|
||||
virtual bool findSweepGroupEdges() = 0;
|
||||
virtual void sweep() = 0;
|
||||
virtual void traceWeakEdges(JSTracer* trc) = 0;
|
||||
virtual void traceMappings(WeakMapTracer* tracer) = 0;
|
||||
virtual void clearAndCompact() = 0;
|
||||
|
||||
|
@ -316,7 +309,7 @@ class WeakMap
|
|||
JS::ExposeObjectToActiveJS(obj);
|
||||
}
|
||||
|
||||
void sweep() override;
|
||||
void traceWeakEdges(JSTracer* trc) override;
|
||||
|
||||
void clearAndCompact() override {
|
||||
Base::clear();
|
||||
|
|
|
@ -392,11 +392,6 @@ void Zone::checkStringWrappersAfterMovingGC() {
|
|||
}
|
||||
#endif
|
||||
|
||||
void Zone::sweepWeakMaps() {
|
||||
/* Finalize unreachable (key,value) pairs in all weak maps. */
|
||||
WeakMapBase::sweepZone(this);
|
||||
}
|
||||
|
||||
void Zone::discardJitCode(JSFreeOp* fop, const DiscardOptions& options) {
|
||||
if (!jitZone()) {
|
||||
return;
|
||||
|
|
|
@ -480,9 +480,15 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase<JS::Zone> {
|
|||
|
||||
void sweepAfterMinorGC(JSTracer* trc);
|
||||
void sweepUniqueIds();
|
||||
void sweepWeakMaps();
|
||||
void sweepCompartments(JSFreeOp* fop, bool keepAtleastOne, bool lastGC);
|
||||
|
||||
// Remove dead weak maps from gcWeakMapList_ and remove entries from the
|
||||
// remaining weak maps whose keys are dead.
|
||||
void sweepWeakMaps(JSTracer* trc);
|
||||
|
||||
// Trace all weak maps in this zone. Used to update edges after a moving GC.
|
||||
void traceWeakMaps(JSTracer* trc);
|
||||
|
||||
js::gc::UniqueIdMap& uniqueIds() { return uniqueIds_.ref(); }
|
||||
|
||||
void notifyObservingDebuggers();
|
||||
|
|
|
@ -136,8 +136,9 @@ struct ObjectEntry {
|
|||
HeapPtr<JSObject*> obj;
|
||||
explicit ObjectEntry(JSObject* o) : obj(o) {}
|
||||
bool operator==(const ObjectEntry& other) const { return obj == other.obj; }
|
||||
bool needsSweep() {
|
||||
return JS::GCPolicy<HeapPtr<JSObject*>>::needsSweep(&obj);
|
||||
bool needsSweep() { return IsAboutToBeFinalized(&obj); }
|
||||
bool traceWeak(JSTracer* trc) {
|
||||
return TraceWeakEdge(trc, &obj, "ObjectEntry::obj");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -173,8 +174,9 @@ struct NumberAndObjectEntry {
|
|||
bool operator==(const NumberAndObjectEntry& other) const {
|
||||
return number == other.number && obj == other.obj;
|
||||
}
|
||||
bool needsSweep() {
|
||||
return JS::GCPolicy<HeapPtr<JSObject*>>::needsSweep(&obj);
|
||||
bool needsSweep() { return IsAboutToBeFinalized(&obj); }
|
||||
bool traceWeak(JSTracer* trc) {
|
||||
return TraceWeakEdge(trc, &obj, "NumberAndObjectEntry::obj");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -175,12 +175,11 @@ enum class ScriptKind { Script, ScriptStencil, DecodeScript, Module };
|
|||
class NonshrinkingGCObjectVector
|
||||
: public GCVector<HeapPtrObject, 0, SystemAllocPolicy> {
|
||||
public:
|
||||
void sweep() {
|
||||
bool traceWeak(JSTracer* trc) {
|
||||
for (HeapPtrObject& obj : *this) {
|
||||
if (JS::GCPolicy<HeapPtrObject>::needsSweep(&obj)) {
|
||||
obj = nullptr;
|
||||
}
|
||||
TraceWeakEdge(trc, &obj, "NonshrinkingGCObjectVector element");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1731,27 +1731,27 @@ void InnerViewTable::removeViews(ArrayBufferObject* buffer) {
|
|||
map.remove(p);
|
||||
}
|
||||
|
||||
void InnerViewTable::sweep() { map.sweep(); }
|
||||
bool InnerViewTable::traceWeak(JSTracer* trc) { return map.traceWeak(trc); }
|
||||
|
||||
void InnerViewTable::sweepAfterMinorGC() {
|
||||
void InnerViewTable::sweepAfterMinorGC(JSTracer* trc) {
|
||||
MOZ_ASSERT(needsSweepAfterMinorGC());
|
||||
|
||||
if (nurseryKeysValid) {
|
||||
for (size_t i = 0; i < nurseryKeys.length(); i++) {
|
||||
JSObject* buffer = MaybeForwarded(nurseryKeys[i]);
|
||||
Map::Ptr p = map.lookup(buffer);
|
||||
if (p && Map::SweepPolicy::needsSweep(&p->mutableKey(), &p->value())) {
|
||||
if (p &&
|
||||
!Map::SweepPolicy::traceWeak(trc, &p->mutableKey(), &p->value())) {
|
||||
map.remove(p);
|
||||
}
|
||||
}
|
||||
nurseryKeys.clear();
|
||||
} else {
|
||||
// Do the required sweeping by looking at every map entry.
|
||||
nurseryKeys.clear();
|
||||
sweep();
|
||||
|
||||
nurseryKeysValid = true;
|
||||
map.traceWeak(trc);
|
||||
}
|
||||
|
||||
nurseryKeys.clear();
|
||||
nurseryKeysValid = true;
|
||||
}
|
||||
|
||||
size_t InnerViewTable::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
|
||||
|
|
|
@ -564,8 +564,8 @@ class InnerViewTable {
|
|||
|
||||
// Remove references to dead objects in the table and update table entries
|
||||
// to reflect moved objects.
|
||||
void sweep();
|
||||
void sweepAfterMinorGC();
|
||||
bool traceWeak(JSTracer* trc);
|
||||
void sweepAfterMinorGC(JSTracer* trc);
|
||||
|
||||
bool empty() const { return map.empty(); }
|
||||
|
||||
|
|
|
@ -504,7 +504,7 @@ void Compartment::sweepAfterMinorGC(JSTracer* trc) {
|
|||
crossCompartmentObjectWrappers.sweepAfterMinorGC(trc);
|
||||
|
||||
for (RealmsInCompartmentIter r(this); !r.done(); r.next()) {
|
||||
r->sweepAfterMinorGC();
|
||||
r->sweepAfterMinorGC(trc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -326,17 +326,17 @@ void Realm::finishRoots() {
|
|||
objects_.finishRoots();
|
||||
}
|
||||
|
||||
void ObjectRealm::sweepAfterMinorGC() {
|
||||
void ObjectRealm::sweepAfterMinorGC(JSTracer* trc) {
|
||||
InnerViewTable& table = innerViews.get();
|
||||
if (table.needsSweepAfterMinorGC()) {
|
||||
table.sweepAfterMinorGC();
|
||||
table.sweepAfterMinorGC(trc);
|
||||
}
|
||||
}
|
||||
|
||||
void Realm::sweepAfterMinorGC() {
|
||||
void Realm::sweepAfterMinorGC(JSTracer* trc) {
|
||||
globalWriteBarriered = 0;
|
||||
dtoaCache.purge();
|
||||
objects_.sweepAfterMinorGC();
|
||||
objects_.sweepAfterMinorGC(trc);
|
||||
}
|
||||
|
||||
void Realm::traceWeakSavedStacks(JSTracer* trc) { savedStacks_.traceWeak(trc); }
|
||||
|
|
|
@ -265,7 +265,7 @@ class ObjectRealm {
|
|||
|
||||
void finishRoots();
|
||||
void trace(JSTracer* trc);
|
||||
void sweepAfterMinorGC();
|
||||
void sweepAfterMinorGC(JSTracer* trc);
|
||||
void traceWeakNativeIterators(JSTracer* trc);
|
||||
|
||||
void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
||||
|
@ -518,7 +518,7 @@ class JS::Realm : public JS::shadow::Realm {
|
|||
*/
|
||||
void finishRoots();
|
||||
|
||||
void sweepAfterMinorGC();
|
||||
void sweepAfterMinorGC(JSTracer* trc);
|
||||
void traceWeakDebugEnvironmentEdges(JSTracer* trc);
|
||||
void traceWeakObjectRealm(JSTracer* trc);
|
||||
void traceWeakRegExps(JSTracer* trc);
|
||||
|
|
|
@ -82,7 +82,7 @@ The 'column-rule-image-source' and 'row-rule-image-source' Properties {#column-r
|
|||
Animation type: discrete
|
||||
</pre>
|
||||
|
||||
These properties specifies an <<image>> to use in place of the rendering specified
|
||||
These properties specify an <<image>> to use in place of the rendering specified
|
||||
by the ''column-rule-style''/''row-rule-style'' properties.
|
||||
|
||||
As for borders, a rule image is not rendered when the corresponding ''column-rule-style''/''row-rule-style'' is ''column-rule-style/none''.
|
||||
|
@ -101,7 +101,7 @@ The 'column-rule-image-slice' and 'row-rule-image-slice' Properties {#column-rul
|
|||
Animation type: discrete
|
||||
</pre>
|
||||
|
||||
These properties specifies inward offsets from the top and bottom edges of the image,
|
||||
These properties specify inward offsets from the top and bottom edges of the image,
|
||||
dividing it into three regions: two edge areas and one middle area.
|
||||
|
||||
When two values are specified, they set the offsets on the top and bottom sides in
|
||||
|
@ -141,7 +141,7 @@ The 'column-rule-image-repeat' and 'row-rule-image-repeat' Properties {#column-r
|
|||
Animation type: discrete
|
||||
</pre>
|
||||
|
||||
These properties specifies how the middle part of a sliced rule image is scaled and tiled.
|
||||
These properties specify how the middle part of a sliced rule image is scaled and tiled.
|
||||
Values have the following meanings:
|
||||
|
||||
<dl dfn-for=column-rule-image-repeat dfn-type=value>
|
||||
|
@ -530,14 +530,14 @@ The 'column-rule-align' and 'row-rule-align' Properties {#column-rule-align}
|
|||
These properties specify the start/end attachment point of the [=rule containing rectangle=]
|
||||
in the [=longitudinal axis=]. The start value is specified first, the end value second.
|
||||
If only one value is specified it is used for both start and end.
|
||||
These properties are only used for interior the edges. The '*-rule-edge-align' properties
|
||||
described below specifies the alignment on the outer edges. The initial value, ''column-rule-align/gap'',
|
||||
These properties are only used for interior edges. The '*-rule-edge-align' properties
|
||||
described below specify the alignment on the outer edges. The initial value, ''column-rule-align/gap'',
|
||||
means that, by default, a rule will stretch its longitudinal size to fill the space
|
||||
from the end of the gap "above" to the start of the gap "below" ("above" meaning the gap
|
||||
in the orthogonal axis on the rule's start side).
|
||||
|
||||
<aside class=example>
|
||||
This <a href="examples/grid-align-001.html">example</a> illutrates a few alignment options.
|
||||
This <a href="examples/grid-align-001.html">example</a> illustrates a few alignment options.
|
||||
Note that the row rules all have a 1px longitudinal inset
|
||||
to separate the individual rule segments. (''column-rule-align/rule-center'',
|
||||
for example, would otherwise look like one long rule)
|
||||
|
@ -583,7 +583,7 @@ The 'column-rule-edge-align' and 'row-rule-edge-align' Properties {#column-rule-
|
|||
''column-rule-align'') since there are no rules in the edge gutters.
|
||||
|
||||
|
||||
Thge figure below illustrates the alignment values.
|
||||
The figure below illustrates the alignment values.
|
||||
The red values are used for the top column rule's start edge and the yellow
|
||||
values are used for its end edge. The yellow values are also used for the bottom
|
||||
column rule's start edge. However, in this
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
<link href="../csslogo.ico" rel="shortcut icon" type="image/x-icon">
|
||||
<link href="https://www.w3.org/StyleSheets/TR/2016/W3C-ED" rel="stylesheet" type="text/css">
|
||||
<meta content="Bikeshed version d7036035b, updated Fri Oct 8 17:07:11 2021 -0700" name="generator">
|
||||
<meta content="8e27fe76645b992566c8fe35bed8d6a37b0ecdb8" name="document-revision">
|
||||
<style>/* style-autolinks */
|
||||
|
||||
.css.css, .property.property, .descriptor.descriptor {
|
||||
|
@ -491,7 +490,7 @@ dd:not(:last-child) > .wpt-tests-block:not([open]):last-child {
|
|||
display: grid;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
grid-template-columns: 1fr max-content auto auto;
|
||||
grid-column-gap: .5em;
|
||||
}
|
||||
.wpt-tests-block hr:last-child {
|
||||
|
@ -505,8 +504,21 @@ dd:not(:last-child) > .wpt-tests-block:not([open]):last-child {
|
|||
border: none;
|
||||
}
|
||||
.wpt-test > .wpt-name { grid-column: 1; }
|
||||
.wpt-test > .wpt-live { grid-column: 2; }
|
||||
.wpt-test > .wpt-source { grid-column: 3; }
|
||||
.wpt-test > .wpt-results { grid-column: 2; }
|
||||
.wpt-test > .wpt-live { grid-column: 3; }
|
||||
.wpt-test > .wpt-source { grid-column: 4; }
|
||||
|
||||
.wpt-test > .wpt-results {
|
||||
display: flex;
|
||||
gap: .1em;
|
||||
}
|
||||
.wpt-test .wpt-result {
|
||||
display: inline-block;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
<style>/* style-darkmode */
|
||||
|
||||
|
@ -702,7 +714,7 @@ dd:not(:last-child) > .wpt-tests-block:not([open]):last-child {
|
|||
<div class="head">
|
||||
<p data-fill-with="logo"><a class="logo" href="https://www.w3.org/"> <img alt="W3C" height="48" src="https://www.w3.org/StyleSheets/TR/2016/logos/W3C" width="72"> </a> </p>
|
||||
<h1 class="p-name no-ref" id="title">CSS Gap Decorations</h1>
|
||||
<h2 class="no-num no-toc no-ref heading settled" id="profile-and-date"><span class="content">Editor’s Draft, <time class="dt-updated" datetime="2021-10-14">14 October 2021</time></span></h2>
|
||||
<h2 class="no-num no-toc no-ref heading settled" id="profile-and-date"><span class="content">Editor’s Draft, <time class="dt-updated" datetime="2021-10-19">19 October 2021</time></span></h2>
|
||||
<details>
|
||||
<summary>Specification Metadata</summary>
|
||||
<div data-fill-with="spec-metadata">
|
||||
|
@ -893,7 +905,7 @@ on screen, on paper, etc.
|
|||
<th><a href="https://www.w3.org/TR/web-animations/#animation-type">Animation type:</a>
|
||||
<td>discrete
|
||||
</table>
|
||||
<p>These properties specifies an <a class="production css" data-link-type="type" href="https://drafts.csswg.org/css-images-3/#typedef-image" id="ref-for-typedef-image②"><image></a> to use in place of the rendering specified
|
||||
<p>These properties specify an <a class="production css" data-link-type="type" href="https://drafts.csswg.org/css-images-3/#typedef-image" id="ref-for-typedef-image②"><image></a> to use in place of the rendering specified
|
||||
by the <span class="css">column-rule-style</span>/<span class="css">row-rule-style</span> properties.</p>
|
||||
<p>As for borders, a rule image is not rendered when the corresponding <span class="css">column-rule-style</span>/<span class="css">row-rule-style</span> is <span class="css">none</span>.</p>
|
||||
<h3 class="heading settled" data-level="2.2" id="column-rule-image-slice"><span class="secno">2.2. </span><span class="content">The <a class="property" data-link-type="propdesc" href="#propdef-column-rule-image-slice" id="ref-for-propdef-column-rule-image-slice">column-rule-image-slice</a> and <a class="property" data-link-type="propdesc" href="#propdef-row-rule-image-slice" id="ref-for-propdef-row-rule-image-slice">row-rule-image-slice</a> Properties</span><a class="self-link" href="#column-rule-image-slice"></a></h3>
|
||||
|
@ -927,7 +939,7 @@ on screen, on paper, etc.
|
|||
<th><a href="https://www.w3.org/TR/web-animations/#animation-type">Animation type:</a>
|
||||
<td>discrete
|
||||
</table>
|
||||
<p>These properties specifies inward offsets from the top and bottom edges of the image,
|
||||
<p>These properties specify inward offsets from the top and bottom edges of the image,
|
||||
dividing it into three regions: two edge areas and one middle area.</p>
|
||||
<p>When two values are specified, they set the offsets on the top and bottom sides in
|
||||
that order. If the bottom is missing, it is the same as the top.</p>
|
||||
|
@ -975,7 +987,7 @@ on screen, on paper, etc.
|
|||
<th><a href="https://www.w3.org/TR/web-animations/#animation-type">Animation type:</a>
|
||||
<td>discrete
|
||||
</table>
|
||||
<p>These properties specifies how the middle part of a sliced rule image is scaled and tiled.
|
||||
<p>These properties specify how the middle part of a sliced rule image is scaled and tiled.
|
||||
Values have the following meanings:</p>
|
||||
<dl>
|
||||
<dt><dfn class="css" data-dfn-for="column-rule-image-repeat" data-dfn-type="value" data-export id="valdef-column-rule-image-repeat-stretch">stretch<a class="self-link" href="#valdef-column-rule-image-repeat-stretch"></a></dfn>
|
||||
|
@ -1028,7 +1040,7 @@ on screen, on paper, etc.
|
|||
<a class="self-link" href="#example-c9ee9e2e"></a> This <a href="examples/grid-image-001.html">example</a> demonstrates the new
|
||||
rule image properties presented above in a grid layout with spanning elements.
|
||||
<figure>
|
||||
<img height="488" src="media/grid-image-001.png" width="608">
|
||||
<img src="media/grid-image-001.png">
|
||||
<figcaption> Example of image rules. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -1043,7 +1055,7 @@ on screen, on paper, etc.
|
|||
<aside class="example" id="example-746571da">
|
||||
<a class="self-link" href="#example-746571da"></a> This is a similar <a href="examples/grid-gradient-001.html">example</a> using gradients.
|
||||
<figure>
|
||||
<img height="489" src="media/grid-gradient-001.png" width="608">
|
||||
<img src="media/grid-gradient-001.png">
|
||||
<figcaption> Example of gradient rules. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -1052,7 +1064,7 @@ on screen, on paper, etc.
|
|||
support for a use case mentioned in <a href="https://github.com/w3c/csswg-drafts/issues/2748#issuecomment-621983931">issue #2748</a>.
|
||||
It’s a coupon with a perforation rendered by a semi-transparent rule image between two flex items.
|
||||
<figure>
|
||||
<img height="108" src="media/flexbox-coupon-rule.png" width="253">
|
||||
<img src="media/flexbox-coupon-rule.png">
|
||||
<figcaption> An example of a semi-transparent column rule image. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -1218,7 +1230,7 @@ on screen, on paper, etc.
|
|||
insets are greater than the <a data-link-type="dfn" href="#rule-containing-rectangle①" id="ref-for-rule-containing-rectangle①⑦">rule containing rectangle’s</a> size. There’s still
|
||||
a zero-sized column rule there, which the row rule (purple) aligns to.
|
||||
<figure>
|
||||
<img height="651" src="media/grid-lateral-001.png" width="997">
|
||||
<img src="media/grid-lateral-001.png">
|
||||
<figcaption> Examples of lateral rule sizing with various inset values. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -1325,7 +1337,7 @@ on screen, on paper, etc.
|
|||
<a class="self-link" href="#example-0ce2b88c"></a> Here’s a few simple <a href="examples/grid-longitudinal-001.html">examples</a> of
|
||||
the rule sizing and inset properties.
|
||||
<figure>
|
||||
<img height="648" src="media/grid-longitudinal-001.png" width="591">
|
||||
<img src="media/grid-longitudinal-001.png">
|
||||
<figcaption> Examples of rule sizing and inset values. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -1634,13 +1646,13 @@ on screen, on paper, etc.
|
|||
</table>
|
||||
<p>These properties specify the start/end attachment point of the <a data-link-type="dfn" href="#rule-containing-rectangle①" id="ref-for-rule-containing-rectangle①①②">rule containing rectangle</a> in the <a data-link-type="dfn" href="#longitudinal-axis" id="ref-for-longitudinal-axis④">longitudinal axis</a>. The start value is specified first, the end value second.
|
||||
If only one value is specified it is used for both start and end.
|
||||
These properties are only used for interior the edges. The <a class="property" data-link-type="propdesc">*-rule-edge-align</a> properties
|
||||
described below specifies the alignment on the outer edges. The initial value, <span class="css">gap</span>,
|
||||
These properties are only used for interior edges. The <a class="property" data-link-type="propdesc">*-rule-edge-align</a> properties
|
||||
described below specify the alignment on the outer edges. The initial value, <span class="css">gap</span>,
|
||||
means that, by default, a rule will stretch its longitudinal size to fill the space
|
||||
from the end of the gap "above" to the start of the gap "below" ("above" meaning the gap
|
||||
in the orthogonal axis on the rule’s start side).</p>
|
||||
<aside class="example" id="example-07730548">
|
||||
<a class="self-link" href="#example-07730548"></a> This <a href="examples/grid-align-001.html">example</a> illutrates a few alignment options.
|
||||
<aside class="example" id="example-d52ec54e">
|
||||
<a class="self-link" href="#example-d52ec54e"></a> This <a href="examples/grid-align-001.html">example</a> illustrates a few alignment options.
|
||||
Note that the row rules all have a 1px longitudinal inset
|
||||
to separate the individual rule segments. (<span class="css">rule-center</span>,
|
||||
for example, would otherwise look like one long rule)
|
||||
|
@ -1648,7 +1660,7 @@ on screen, on paper, etc.
|
|||
the gap (to separate the <span class="css">rule-center</span> position
|
||||
from the <span class="css">gap-center</span> position)</p>
|
||||
<figure>
|
||||
<img height="596" src="media/grid-align-001.png" width="692">
|
||||
<img src="media/grid-align-001.png">
|
||||
<figcaption> Example of <a class="property" data-link-type="propdesc" href="#propdef-row-rule-align" id="ref-for-propdef-row-rule-align①">row-rule-align</a> in a grid container. </figcaption>
|
||||
</figure>
|
||||
<p>You might be wondering if there’s a bug in the bottom-right example.
|
||||
|
@ -1692,7 +1704,7 @@ on screen, on paper, etc.
|
|||
is used for both start and end. (Attachment points for the interior rule edges are
|
||||
specified with the <a href="#column-rule-align"><a class="property" data-link-type="propdesc">*-rule-align</a></a> properties above.)</p>
|
||||
<p class="note" role="note"><span>Note:</span> The <span class="css">rule</span>/<span class="css">rule-center</span>/<span class="css">rule-over</span> keywords are omitted here (compared with <span class="css">column-rule-align</span>) since there are no rules in the edge gutters.</p>
|
||||
<p>Thge figure below illustrates the alignment values.
|
||||
<p>The figure below illustrates the alignment values.
|
||||
The red values are used for the top column rule’s start edge and the yellow
|
||||
values are used for its end edge. The yellow values are also used for the bottom
|
||||
column rule’s start edge. However, in this
|
||||
|
@ -1705,7 +1717,7 @@ on screen, on paper, etc.
|
|||
attachment points should be used. <span class="css">column-rule-edge-align</span> the yellow colored
|
||||
ones (and all other interior edges if there were more rows).</p>
|
||||
<figure>
|
||||
<img height="585" src="media/rule-alignment-values.png" width="621">
|
||||
<img src="media/rule-alignment-values.png">
|
||||
<figcaption> Illustration of rule alignment values. </figcaption>
|
||||
</figure>
|
||||
<p>Here’s the rule styling used for the above example:</p>
|
||||
|
@ -1775,7 +1787,7 @@ on screen, on paper, etc.
|
|||
<aside class="example" id="example-9ccc5773">
|
||||
<a class="self-link" href="#example-9ccc5773"></a>
|
||||
<figure>
|
||||
<img height="228" src="media/grid-segment-001.png" width="312">
|
||||
<img src="media/grid-segment-001.png">
|
||||
<figcaption> Example of column and row rules with <span class="css">segment</span> extent in a grid container. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -1787,7 +1799,7 @@ on screen, on paper, etc.
|
|||
<aside class="example" id="example-9818bbbb">
|
||||
<a class="self-link" href="#example-9818bbbb"></a>
|
||||
<figure>
|
||||
<img height="228" src="media/grid-segment-002.png" width="608">
|
||||
<img src="media/grid-segment-002.png">
|
||||
<figcaption> Example of column and row rules with in a grid container with <a data-link-type="dfn" href="https://drafts.csswg.org/css-grid-2/#collapsed-track" id="ref-for-collapsed-track①">collapsed tracks</a>. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -1852,7 +1864,7 @@ on screen, on paper, etc.
|
|||
They are both forced to span into the cell in row 2, column 4 to illustrate what happens
|
||||
when items span like this.
|
||||
<figure>
|
||||
<img height="811" src="media/grid-extent-001.png" width="805">
|
||||
<img src="media/grid-extent-001.png">
|
||||
<figcaption> Examples of <span class="css">row-rule-extent</span> in a grid container. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -1879,7 +1891,7 @@ on screen, on paper, etc.
|
|||
the <a class="css" data-link-type="propdesc" href="#propdef-row-rule-align" id="ref-for-propdef-row-rule-align②">row-rule-align: rule</a> in the subgrid. The subgrid is in fact completely
|
||||
unaware of any parent rules.</p>
|
||||
<figure>
|
||||
<img height="256" src="media/grid-subgrid-001.png" width="826">
|
||||
<img src="media/grid-subgrid-001.png">
|
||||
<figcaption> Example of gap rules in a subgrid. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -1896,7 +1908,7 @@ on screen, on paper, etc.
|
|||
variations of rules in a masonry grid layout. All the grids have <a class="css" data-link-type="propdesc" href="#propdef-column-rule-edge-align" id="ref-for-propdef-column-rule-edge-align①">column-rule-edge-align: gap-over</a> to extend the edge rules out to
|
||||
the content-box edge.
|
||||
<figure>
|
||||
<img height="785" src="media/grid-masonry-001.png" width="691">
|
||||
<img src="media/grid-masonry-001.png">
|
||||
<figcaption> Example of gap rules in a masonry grid. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -1904,12 +1916,12 @@ on screen, on paper, etc.
|
|||
<a class="self-link" href="#example-a0ffc13c"></a> This <a href="examples/grid-masonry-002.html">example</a> illustrates
|
||||
some of the <a class="css" data-link-type="propdesc" href="#propdef-column-rule-extent" id="ref-for-propdef-column-rule-extent①">column-rule-extent: all-*</a> values.
|
||||
<figure>
|
||||
<img height="772" src="media/grid-masonry-002.png" width="730">
|
||||
<img src="media/grid-masonry-002.png">
|
||||
<figcaption> Example of gap rules in a masonry grid. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
<p class="issue" id="issue-b6f1d65c"><a class="self-link" href="#issue-b6f1d65c"></a> TODO: add definition list and algorithm here...</p>
|
||||
<p class="issue" id="issue-3e9abc31"><a class="self-link" href="#issue-3e9abc31"></a> is it useful to be able to create a rule extent for the <i>intersection</i> or <i>union</i> between two tracks, like so: <img height="435" src="media/masonry-all-shorter.png" style="display:block" width="701">It’s pretty easy to implement, fwiw... (I accidently implemented <span class="css">short</span>/<span class="css">long</span> like that before I realized it was inconsistent with how they work elsewhere). I think it’s a case that is unique to a masonry axis though, at least <i>currently</i>...</p>
|
||||
<p class="issue" id="issue-3e9abc31"><a class="self-link" href="#issue-3e9abc31"></a> is it useful to be able to create a rule extent for the <i>intersection</i> or <i>union</i> between two tracks, like so: <img src="media/masonry-all-shorter.png" style="display:block">It’s pretty easy to implement, fwiw... (I accidently implemented <span class="css">short</span>/<span class="css">long</span> like that before I realized it was inconsistent with how they work elsewhere). I think it’s a case that is unique to a masonry axis though, at least <i>currently</i>...</p>
|
||||
<h4 class="heading settled" data-level="6.1.2" id="rule-extent-flexbox"><span class="secno">6.1.2. </span><span class="content">Flexbox Containers</span><a class="self-link" href="#rule-extent-flexbox"></a></h4>
|
||||
<p>In a <a href="https://drafts.csswg.org/css-flexbox/#valdef-flex-direction-row">row-oriented flexbox container</a>,
|
||||
the <span class="css">row-rule-*</span> properties creates rules between flex lines,
|
||||
|
@ -1981,23 +1993,23 @@ on screen, on paper, etc.
|
|||
<aside class="example" id="example-374fda56">
|
||||
<a class="self-link" href="#example-374fda56"></a> Here are a few examples to illustrate the <span class="css">row-rule-extent</span> values.
|
||||
<figure>
|
||||
<img height="194" src="media/flexbox-extent-start-001.png" width="314">
|
||||
<img src="media/flexbox-extent-start-001.png">
|
||||
<figcaption> A <a class="css" data-link-type="propdesc" href="#propdef-row-rule-extent" id="ref-for-propdef-row-rule-extent①">row-rule-extent: start</a> <a href="examples/flexbox-extent-start-001.html">example</a>. </figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img height="194" src="media/flexbox-extent-end-001.png" width="314">
|
||||
<img src="media/flexbox-extent-end-001.png">
|
||||
<figcaption> A <a class="css" data-link-type="propdesc" href="#propdef-row-rule-extent" id="ref-for-propdef-row-rule-extent②">row-rule-extent: end</a> <a href="examples/flexbox-extent-end-001.html">example</a>. </figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img height="194" src="media/flexbox-extent-long-001.png" width="314">
|
||||
<img src="media/flexbox-extent-long-001.png">
|
||||
<figcaption> A <a class="css" data-link-type="propdesc" href="#propdef-row-rule-extent" id="ref-for-propdef-row-rule-extent③">row-rule-extent: long</a> <a href="examples/flexbox-extent-long-001.html">example</a>. </figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img height="194" src="media/flexbox-extent-all-short-001.png" width="314">
|
||||
<img src="media/flexbox-extent-all-short-001.png">
|
||||
<figcaption> A <a class="css" data-link-type="propdesc" href="#propdef-row-rule-extent" id="ref-for-propdef-row-rule-extent④">row-rule-extent: all-short</a> <a href="examples/flexbox-extent-all-short-001.html">example</a>. </figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img height="194" src="media/flexbox-extent-all-long-001.png" width="314">
|
||||
<img src="media/flexbox-extent-all-long-001.png">
|
||||
<figcaption> A <a class="css" data-link-type="propdesc" href="#propdef-row-rule-extent" id="ref-for-propdef-row-rule-extent⑤">row-rule-extent: all-long</a> <a href="examples/flexbox-extent-all-long-001.html">example</a>. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -2007,7 +2019,7 @@ on screen, on paper, etc.
|
|||
used and the gaps aren’t aligned. (The flex items are semi-transparent
|
||||
to show the column rules underneath).
|
||||
<figure>
|
||||
<img height="194" src="media/flexbox-extent-all-long-allow-overlap-001.png" width="314">
|
||||
<img src="media/flexbox-extent-all-long-allow-overlap-001.png">
|
||||
<figcaption> A <a class="css" data-link-type="propdesc" href="#propdef-column-rule-extent" id="ref-for-propdef-column-rule-extent③">column-rule-extent: all-long allow-overlap</a> example. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -2022,7 +2034,7 @@ on screen, on paper, etc.
|
|||
<aside class="example" id="example-5015561d">
|
||||
<a class="self-link" href="#example-5015561d"></a> Note, column 2 is collapsed in this example.
|
||||
<figure>
|
||||
<img height="346" src="media/table-rules-001.png" width="818">
|
||||
<img src="media/table-rules-001.png">
|
||||
<figcaption> An <a href="examples/table-rules-001.html">example</a> of table rules. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -2040,7 +2052,7 @@ on screen, on paper, etc.
|
|||
table rows and cells. And also what happens when the table rules from
|
||||
the last example is also applied.
|
||||
<figure>
|
||||
<img height="784" src="media/table-row-group-rules-001.png" width="879">
|
||||
<img src="media/table-row-group-rules-001.png">
|
||||
<figcaption> Example of table row and cell rules. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -2058,7 +2070,7 @@ on screen, on paper, etc.
|
|||
<a class="self-link" href="#example-b0c3427d"></a> This <a href="examples/multicol-row-rule-001.html">example</a> illustrates rules in
|
||||
a multi-column container.
|
||||
<figure>
|
||||
<img height="854" src="media/multicol-row-rule-001.png" width="827">
|
||||
<img src="media/multicol-row-rule-001.png">
|
||||
<figcaption> Example of column and row rules in a multi-column. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -2067,7 +2079,7 @@ on screen, on paper, etc.
|
|||
'column-span: <a class="production css" data-link-type="type" href="https://drafts.csswg.org/css-values-4/#integer-value" id="ref-for-integer-value"><integer></a>' some time in the future,
|
||||
this is how row rules will work:
|
||||
<figure>
|
||||
<img height="195" src="media/multicol-colspan-2.png" width="808">
|
||||
<img src="media/multicol-colspan-2.png">
|
||||
<figcaption> Example of <a class="css" data-link-type="propdesc" href="https://drafts.csswg.org/css-multicol-2/#propdef-column-span" id="ref-for-propdef-column-span">column-span: 2</a> in a multi-column with column and row rules. </figcaption>
|
||||
</figure>
|
||||
</aside>
|
||||
|
@ -2089,7 +2101,7 @@ on screen, on paper, etc.
|
|||
<c- k>row-rule-lateral-inset-start</c-><c- p>:</c-> <c- m>20</c-><c- k>px</c-><c- p>;</c->
|
||||
</pre>
|
||||
<figure>
|
||||
<img height="584" src="media/rule-containing-rectangle.png" width="620">
|
||||
<img src="media/rule-containing-rectangle.png">
|
||||
<figcaption> The Rule Containing Rectangle </figcaption>
|
||||
</figure>
|
||||
<p>Note that the <a data-link-type="dfn" href="#rule-containing-rectangle①" id="ref-for-rule-containing-rectangle①①⑦">rule containing rectangle</a> extends to the start of the black horizontal rule, which has a <span class="css">20px</span> lateral inset (making it non-centered). We align to its start with <a class="css" data-link-type="propdesc" href="#propdef-column-rule-align" id="ref-for-propdef-column-rule-align②">column-rule-align: rule</a>. From there,
|
||||
|
@ -2787,7 +2799,7 @@ on screen, on paper, etc.
|
|||
<dt id="biblio-css-box-4">[CSS-BOX-4]
|
||||
<dd>Elika Etemad. <a href="https://www.w3.org/TR/css-box-4/"><cite>CSS Box Model Module Level 4</cite></a>. 21 April 2020. WD. URL: <a href="https://www.w3.org/TR/css-box-4/">https://www.w3.org/TR/css-box-4/</a>
|
||||
<dt id="biblio-css-cascade-5">[CSS-CASCADE-5]
|
||||
<dd>Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. <a href="https://www.w3.org/TR/css-cascade-5/"><cite>CSS Cascading and Inheritance Level 5</cite></a>. 29 August 2021. WD. URL: <a href="https://www.w3.org/TR/css-cascade-5/">https://www.w3.org/TR/css-cascade-5/</a>
|
||||
<dd>Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. <a href="https://www.w3.org/TR/css-cascade-5/"><cite>CSS Cascading and Inheritance Level 5</cite></a>. 15 October 2021. WD. URL: <a href="https://www.w3.org/TR/css-cascade-5/">https://www.w3.org/TR/css-cascade-5/</a>
|
||||
<dt id="biblio-css-color-4">[CSS-COLOR-4]
|
||||
<dd>Tab Atkins Jr.; Chris Lilley. <a href="https://www.w3.org/TR/css-color-4/"><cite>CSS Color Module Level 4</cite></a>. 1 June 2021. WD. URL: <a href="https://www.w3.org/TR/css-color-4/">https://www.w3.org/TR/css-color-4/</a>
|
||||
<dt id="biblio-css-display-3">[CSS-DISPLAY-3]
|
||||
|
@ -2811,7 +2823,7 @@ on screen, on paper, etc.
|
|||
<dt id="biblio-css-tables-3">[CSS-TABLES-3]
|
||||
<dd>François Remy; Greg Whitworth; David Baron. <a href="https://www.w3.org/TR/css-tables-3/"><cite>CSS Table Module Level 3</cite></a>. 27 July 2019. WD. URL: <a href="https://www.w3.org/TR/css-tables-3/">https://www.w3.org/TR/css-tables-3/</a>
|
||||
<dt id="biblio-css-values-4">[CSS-VALUES-4]
|
||||
<dd>Tab Atkins Jr.; Elika Etemad. <a href="https://www.w3.org/TR/css-values-4/"><cite>CSS Values and Units Module Level 4</cite></a>. 30 September 2021. WD. URL: <a href="https://www.w3.org/TR/css-values-4/">https://www.w3.org/TR/css-values-4/</a>
|
||||
<dd>Tab Atkins Jr.; Elika Etemad. <a href="https://www.w3.org/TR/css-values-4/"><cite>CSS Values and Units Module Level 4</cite></a>. 16 October 2021. WD. URL: <a href="https://www.w3.org/TR/css-values-4/">https://www.w3.org/TR/css-values-4/</a>
|
||||
<dt id="biblio-css-writing-modes-4">[CSS-WRITING-MODES-4]
|
||||
<dd>Elika Etemad; Koji Ishii. <a href="https://www.w3.org/TR/css-writing-modes-4/"><cite>CSS Writing Modes Level 4</cite></a>. 30 July 2019. CR. URL: <a href="https://www.w3.org/TR/css-writing-modes-4/">https://www.w3.org/TR/css-writing-modes-4/</a>
|
||||
<dt id="biblio-rfc2119">[RFC2119]
|
||||
|
@ -3231,7 +3243,7 @@ on screen, on paper, etc.
|
|||
e.g. 'padding | padding-center | padding-over | border...' <a class="issue-return" href="#issue-13842b6f" title="Jump to section">↵</a></div>
|
||||
<div class="issue"> perhaps make <a class="css" data-link-type="maybe" href="https://drafts.csswg.org/css-box-4/#valdef-margin-trim-all">all</a> a separate keyword? like so: <span class="css">[segment | [[start | end | short | long] all?] ] allow-overlap?</span> <a class="issue-return" href="#issue-70dc1ba4" title="Jump to section">↵</a></div>
|
||||
<div class="issue"> TODO: add definition list and algorithm here... <a class="issue-return" href="#issue-b6f1d65c" title="Jump to section">↵</a></div>
|
||||
<div class="issue"> is it useful to be able to create a rule extent for the <i>intersection</i> or <i>union</i> between two tracks, like so: <img height="435" src="media/masonry-all-shorter.png" style="display:block" width="701">It’s pretty easy to implement, fwiw... (I accidently implemented <span class="css">short</span>/<span class="css">long</span> like that before I realized it was inconsistent with how they work elsewhere). I think it’s a case that is unique to a masonry axis though, at least <i>currently</i>... <a class="issue-return" href="#issue-3e9abc31" title="Jump to section">↵</a></div>
|
||||
<div class="issue"> is it useful to be able to create a rule extent for the <i>intersection</i> or <i>union</i> between two tracks, like so: <img src="media/masonry-all-shorter.png" style="display:block">It’s pretty easy to implement, fwiw... (I accidently implemented <span class="css">short</span>/<span class="css">long</span> like that before I realized it was inconsistent with how they work elsewhere). I think it’s a case that is unique to a masonry axis though, at least <i>currently</i>... <a class="issue-return" href="#issue-3e9abc31" title="Jump to section">↵</a></div>
|
||||
<div class="issue"> sort out if non-collapsed column-groups that only contains collapsed columns should generate rules, ditto row-groups/rows <a class="issue-return" href="#issue-96acb267" title="Jump to section">↵</a></div>
|
||||
<div class="issue"> this proposal makes the assumption that the parallel proposal that <span class="css">row-gap</span> should apply to multi-column containers is also adopted (issue #XXX). <a class="issue-return" href="#issue-b4c69802" title="Jump to section">↵</a></div>
|
||||
</div>
|
||||
|
@ -3611,4 +3623,6 @@ document.body.addEventListener("click", function(e) {
|
|||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
<script>/* script-wpt */
|
||||
</script>
|
|
@ -274,6 +274,14 @@ void nsMenuPopupFrame::EnsureWidget(bool aRecreate) {
|
|||
}
|
||||
}
|
||||
|
||||
static Maybe<ColorScheme> GetWidgetColorScheme(const nsMenuPopupFrame* aFrame) {
|
||||
const auto& scheme = aFrame->StyleUI()->mColorScheme.bits;
|
||||
if (!scheme) {
|
||||
return Nothing();
|
||||
}
|
||||
return Some(LookAndFeel::ColorSchemeForFrame(aFrame));
|
||||
}
|
||||
|
||||
nsresult nsMenuPopupFrame::CreateWidgetForView(nsView* aView) {
|
||||
// Create a widget for ourselves.
|
||||
nsWidgetInitData widgetData;
|
||||
|
@ -357,7 +365,7 @@ nsresult nsMenuPopupFrame::CreateWidgetForView(nsView* aView) {
|
|||
widget->SetWindowShadowStyle(GetShadowStyle());
|
||||
widget->SetWindowOpacity(StyleUIReset()->mWindowOpacity);
|
||||
widget->SetWindowTransform(ComputeWidgetTransform());
|
||||
widget->SetColorScheme(LookAndFeel::ColorSchemeForFrame(this));
|
||||
widget->SetColorScheme(GetWidgetColorScheme(this));
|
||||
|
||||
// most popups don't have a title so avoid setting the title if there isn't
|
||||
// one
|
||||
|
@ -507,7 +515,7 @@ void nsMenuPopupFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
|
|||
|
||||
if (StyleUI()->mColorScheme != aOldStyle->StyleUI()->mColorScheme) {
|
||||
if (nsIWidget* widget = GetWidget()) {
|
||||
widget->SetColorScheme(LookAndFeel::ColorSchemeForFrame(this));
|
||||
widget->SetColorScheme(GetWidgetColorScheme(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5068,6 +5068,22 @@
|
|||
value: 0
|
||||
mirror: always
|
||||
|
||||
# SwapInterval
|
||||
- name: gfx.swap-interval.glx
|
||||
type: RelaxedAtomicBool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
- name: gfx.swap-interval.egl
|
||||
type: RelaxedAtomicBool
|
||||
mirror: always
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
value: true
|
||||
#else
|
||||
value: false
|
||||
#endif
|
||||
|
||||
|
||||
# Log severe performance warnings to the error console and profiles.
|
||||
# This should be use to quickly find which slow paths are used by test cases.
|
||||
- name: gfx.perf-warnings.enabled
|
||||
|
@ -6528,7 +6544,7 @@
|
|||
|
||||
- name: layers.iosurfaceimage.use-nv12
|
||||
type: bool
|
||||
value: false
|
||||
value: true
|
||||
mirror: once
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
@ -10258,11 +10274,6 @@
|
|||
# Prefs starting with "privacy."
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
- name: privacy.file_unique_origin
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
- name: privacy.fuzzyfox.clockgrainus
|
||||
type: RelaxedAtomicUint32
|
||||
value: 100
|
||||
|
|
|
@ -121,8 +121,7 @@ nsresult BackgroundFileSaver::Init() {
|
|||
NS_IMETHODIMP
|
||||
BackgroundFileSaver::GetObserver(nsIBackgroundFileSaverObserver** aObserver) {
|
||||
NS_ENSURE_ARG_POINTER(aObserver);
|
||||
*aObserver = mObserver;
|
||||
NS_IF_ADDREF(*aObserver);
|
||||
*aObserver = do_AddRef(mObserver).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -815,7 +815,7 @@ already_AddRefed<nsILoadInfo> LoadInfo::CloneForNewRequest() const {
|
|||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetLoadingPrincipal(nsIPrincipal** aLoadingPrincipal) {
|
||||
NS_IF_ADDREF(*aLoadingPrincipal = mLoadingPrincipal);
|
||||
*aLoadingPrincipal = do_AddRef(mLoadingPrincipal).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -833,7 +833,7 @@ nsIPrincipal* LoadInfo::TriggeringPrincipal() { return mTriggeringPrincipal; }
|
|||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetPrincipalToInherit(nsIPrincipal** aPrincipalToInherit) {
|
||||
NS_IF_ADDREF(*aPrincipalToInherit = mPrincipalToInherit);
|
||||
*aPrincipalToInherit = do_AddRef(mPrincipalToInherit).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1752,7 +1752,7 @@ LoadInfo::GetIsFromObjectOrEmbed(bool* aIsFromObjectOrEmbed) {
|
|||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetResultPrincipalURI(nsIURI** aURI) {
|
||||
NS_IF_ADDREF(*aURI = mResultPrincipalURI);
|
||||
*aURI = do_AddRef(mResultPrincipalURI).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1893,7 +1893,7 @@ PerformanceStorage* LoadInfo::GetPerformanceStorage() {
|
|||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetCspEventListener(nsICSPEventListener** aCSPEventListener) {
|
||||
NS_IF_ADDREF(*aCSPEventListener = mCSPEventListener);
|
||||
*aCSPEventListener = do_AddRef(mCSPEventListener).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -134,8 +134,7 @@ TLSServerSocket::GetServerCert(nsIX509Cert** aCert) {
|
|||
if (NS_WARN_IF(!aCert)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
*aCert = mServerCert;
|
||||
NS_IF_ADDREF(*aCert);
|
||||
*aCert = do_AddRef(mServerCert).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -305,8 +304,7 @@ TLSServerConnectionInfo::GetServerSocket(nsITLSServerSocket** aSocket) {
|
|||
if (NS_WARN_IF(!aSocket)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
*aSocket = mServerSocket;
|
||||
NS_IF_ADDREF(*aSocket);
|
||||
*aSocket = do_AddRef(mServerSocket).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -315,8 +313,7 @@ TLSServerConnectionInfo::GetStatus(nsITLSClientStatus** aStatus) {
|
|||
if (NS_WARN_IF(!aStatus)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
*aStatus = this;
|
||||
NS_IF_ADDREF(*aStatus);
|
||||
*aStatus = do_AddRef(this).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -325,8 +322,7 @@ TLSServerConnectionInfo::GetPeerCert(nsIX509Cert** aCert) {
|
|||
if (NS_WARN_IF(!aCert)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
*aCert = mPeerCert;
|
||||
NS_IF_ADDREF(*aCert);
|
||||
*aCert = do_AddRef(mPeerCert).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,19 +16,17 @@
|
|||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
static nsIDNSService* sDNSService = nullptr;
|
||||
static mozilla::StaticRefPtr<nsIDNSService> sDNSService;
|
||||
|
||||
nsresult nsDNSPrefetch::Initialize(nsIDNSService* aDNSService) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
NS_IF_RELEASE(sDNSService);
|
||||
sDNSService = aDNSService;
|
||||
NS_IF_ADDREF(sDNSService);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsDNSPrefetch::Shutdown() {
|
||||
NS_IF_RELEASE(sDNSService);
|
||||
sDNSService = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ nsIncrementalStreamLoader::GetNumBytesRead(uint32_t* aNumBytes) {
|
|||
/* readonly attribute nsIRequest request; */
|
||||
NS_IMETHODIMP
|
||||
nsIncrementalStreamLoader::GetRequest(nsIRequest** aRequest) {
|
||||
NS_IF_ADDREF(*aRequest = mRequest);
|
||||
*aRequest = do_AddRef(mRequest).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ nsInputStreamChannel::SetURI(nsIURI* uri) {
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsInputStreamChannel::GetContentStream(nsIInputStream** stream) {
|
||||
NS_IF_ADDREF(*stream = mContentStream);
|
||||
*stream = do_AddRef(mContentStream).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -87,8 +87,7 @@ nsInputStreamChannel::GetIsSrcdocChannel(bool* aIsSrcdocChannel) {
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsInputStreamChannel::GetBaseURI(nsIURI** aBaseURI) {
|
||||
*aBaseURI = mBaseURI;
|
||||
NS_IF_ADDREF(*aBaseURI);
|
||||
*aBaseURI = do_AddRef(mBaseURI).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -256,7 +256,7 @@ NS_IMETHODIMP
|
|||
nsInputStreamPump::GetLoadGroup(nsILoadGroup** aLoadGroup) {
|
||||
RecursiveMutexAutoLock lock(mMutex);
|
||||
|
||||
NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
|
||||
*aLoadGroup = do_AddRef(mLoadGroup).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -166,8 +166,7 @@ nsMIMEInputStream::SetData(nsIInputStream* aStream) {
|
|||
NS_IMETHODIMP
|
||||
nsMIMEInputStream::GetData(nsIInputStream** aStream) {
|
||||
NS_ENSURE_ARG_POINTER(aStream);
|
||||
*aStream = mStream;
|
||||
NS_IF_ADDREF(*aStream);
|
||||
*aStream = do_AddRef(mStream).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -2530,37 +2530,6 @@ bool NS_RelaxStrictFileOriginPolicy(nsIURI* aTargetURI, nsIURI* aSourceURI,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!StaticPrefs::privacy_file_unique_origin()) {
|
||||
//
|
||||
// If the file to be loaded is in a subdirectory of the source
|
||||
// (or same-dir if source is not a directory) then it will
|
||||
// inherit its source principal and be scriptable by that source.
|
||||
//
|
||||
bool sourceIsDir;
|
||||
bool allowed = false;
|
||||
nsresult rv = sourceFile->IsDirectory(&sourceIsDir);
|
||||
if (NS_SUCCEEDED(rv) && sourceIsDir) {
|
||||
rv = sourceFile->Contains(targetFile, &allowed);
|
||||
} else {
|
||||
nsCOMPtr<nsIFile> sourceParent;
|
||||
rv = sourceFile->GetParent(getter_AddRefs(sourceParent));
|
||||
if (NS_SUCCEEDED(rv) && sourceParent) {
|
||||
rv = sourceParent->Equals(targetFile, &allowed);
|
||||
if (NS_FAILED(rv) || !allowed) {
|
||||
rv = sourceParent->Contains(targetFile, &allowed);
|
||||
} else {
|
||||
MOZ_ASSERT(aAllowDirectoryTarget,
|
||||
"sourceFile->Parent == targetFile, but targetFile "
|
||||
"should've been disallowed if it is a directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv) && allowed) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,13 +29,13 @@ nsRedirectHistoryEntry::GetRemoteAddress(nsACString& result) {
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsRedirectHistoryEntry::GetReferrerURI(nsIURI** referrer) {
|
||||
NS_IF_ADDREF(*referrer = mReferrer);
|
||||
*referrer = do_AddRef(mReferrer).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsRedirectHistoryEntry::GetPrincipal(nsIPrincipal** principal) {
|
||||
NS_IF_ADDREF(*principal = mPrincipal);
|
||||
*principal = do_AddRef(mPrincipal).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -2371,14 +2371,14 @@ nsSocketTransport::Close(nsresult reason) {
|
|||
NS_IMETHODIMP
|
||||
nsSocketTransport::GetSecurityInfo(nsISupports** secinfo) {
|
||||
MutexAutoLock lock(mLock);
|
||||
NS_IF_ADDREF(*secinfo = mSecInfo);
|
||||
*secinfo = do_AddRef(mSecInfo).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::GetSecurityCallbacks(nsIInterfaceRequestor** callbacks) {
|
||||
MutexAutoLock lock(mLock);
|
||||
NS_IF_ADDREF(*callbacks = mCallbacks);
|
||||
*callbacks = do_AddRef(mCallbacks).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ nsUDPMessage::GetData(nsACString& aData) {
|
|||
NS_IMETHODIMP
|
||||
nsUDPMessage::GetOutputStream(nsIOutputStream** aOutputStream) {
|
||||
NS_ENSURE_ARG_POINTER(aOutputStream);
|
||||
NS_IF_ADDREF(*aOutputStream = mOutputStream);
|
||||
*aOutputStream = do_AddRef(mOutputStream).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -369,7 +369,7 @@ UDPMessageProxy::GetRawData(JSContext* cx, JS::MutableHandleValue aRawData) {
|
|||
NS_IMETHODIMP
|
||||
UDPMessageProxy::GetOutputStream(nsIOutputStream** aOutputStream) {
|
||||
NS_ENSURE_ARG_POINTER(aOutputStream);
|
||||
NS_IF_ADDREF(*aOutputStream = mOutputStream);
|
||||
*aOutputStream = do_AddRef(mOutputStream).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,9 +35,9 @@ using namespace mozilla;
|
|||
//----------------------------------------------------------------------------
|
||||
|
||||
static bool gInitialized = false;
|
||||
static nsIURLParser* gNoAuthURLParser = nullptr;
|
||||
static nsIURLParser* gAuthURLParser = nullptr;
|
||||
static nsIURLParser* gStdURLParser = nullptr;
|
||||
static StaticRefPtr<nsIURLParser> gNoAuthURLParser;
|
||||
static StaticRefPtr<nsIURLParser> gAuthURLParser;
|
||||
static StaticRefPtr<nsIURLParser> gStdURLParser;
|
||||
|
||||
static void InitGlobals() {
|
||||
nsCOMPtr<nsIURLParser> parser;
|
||||
|
@ -45,22 +45,19 @@ static void InitGlobals() {
|
|||
parser = do_GetService(NS_NOAUTHURLPARSER_CONTRACTID);
|
||||
NS_ASSERTION(parser, "failed getting 'noauth' url parser");
|
||||
if (parser) {
|
||||
gNoAuthURLParser = parser.get();
|
||||
NS_ADDREF(gNoAuthURLParser);
|
||||
gNoAuthURLParser = parser;
|
||||
}
|
||||
|
||||
parser = do_GetService(NS_AUTHURLPARSER_CONTRACTID);
|
||||
NS_ASSERTION(parser, "failed getting 'auth' url parser");
|
||||
if (parser) {
|
||||
gAuthURLParser = parser.get();
|
||||
NS_ADDREF(gAuthURLParser);
|
||||
gAuthURLParser = parser;
|
||||
}
|
||||
|
||||
parser = do_GetService(NS_STDURLPARSER_CONTRACTID);
|
||||
NS_ASSERTION(parser, "failed getting 'std' url parser");
|
||||
if (parser) {
|
||||
gStdURLParser = parser.get();
|
||||
NS_ADDREF(gStdURLParser);
|
||||
gStdURLParser = parser;
|
||||
}
|
||||
|
||||
gInitialized = true;
|
||||
|
@ -68,11 +65,11 @@ static void InitGlobals() {
|
|||
|
||||
void net_ShutdownURLHelper() {
|
||||
if (gInitialized) {
|
||||
NS_IF_RELEASE(gNoAuthURLParser);
|
||||
NS_IF_RELEASE(gAuthURLParser);
|
||||
NS_IF_RELEASE(gStdURLParser);
|
||||
gInitialized = false;
|
||||
}
|
||||
gNoAuthURLParser = nullptr;
|
||||
gAuthURLParser = nullptr;
|
||||
gStdURLParser = nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
|
@ -1325,7 +1325,7 @@ nsresult CacheEntry::GetSecurityInfo(nsISupports** aSecurityInfo) {
|
|||
{
|
||||
mozilla::MutexAutoLock lock(mLock);
|
||||
if (mSecurityInfoLoaded) {
|
||||
NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
|
||||
*aSecurityInfo = do_AddRef(mSecurityInfo).take();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -1350,7 +1350,7 @@ nsresult CacheEntry::GetSecurityInfo(nsISupports** aSecurityInfo) {
|
|||
mSecurityInfo.swap(secInfo);
|
||||
mSecurityInfoLoaded = true;
|
||||
|
||||
NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
|
||||
*aSecurityInfo = do_AddRef(mSecurityInfo).take();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -842,7 +842,13 @@ gov.cu
|
|||
inf.cu
|
||||
|
||||
// cv : https://en.wikipedia.org/wiki/.cv
|
||||
// cv : http://www.dns.cv/tldcv_portal/do?com=DS;5446457100;111;+PAGE(4000018)+K-CAT-CODIGO(RDOM)+RCNT(100); <- registration rules
|
||||
cv
|
||||
com.cv
|
||||
edu.cv
|
||||
int.cv
|
||||
nome.cv
|
||||
org.cv
|
||||
|
||||
// cw : http://www.una.cw/cw_registry/
|
||||
// Confirmed by registry <registry@una.net> 2013-03-26
|
||||
|
@ -1179,6 +1185,7 @@ org.gu
|
|||
web.gu
|
||||
|
||||
// gw : https://en.wikipedia.org/wiki/.gw
|
||||
// gw : https://nic.gw/regras/
|
||||
gw
|
||||
|
||||
// gy : https://en.wikipedia.org/wiki/.gy
|
||||
|
@ -5853,7 +5860,7 @@ com.ps
|
|||
org.ps
|
||||
net.ps
|
||||
|
||||
// pt : http://online.dns.pt/dns/start_dns
|
||||
// pt : https://www.dns.pt/en/domain/pt-terms-and-conditions-registration-rules/
|
||||
pt
|
||||
net.pt
|
||||
gov.pt
|
||||
|
@ -10791,6 +10798,10 @@ tele.amune.org
|
|||
// Submitted by Apigee Security Team <security@apigee.com>
|
||||
apigee.io
|
||||
|
||||
// Apphud : https://apphud.com
|
||||
// Submitted by Alexander Selivanov <alex@apphud.com>
|
||||
siiites.com
|
||||
|
||||
// Appspace : https://www.appspace.com
|
||||
// Submitted by Appspace Security Team <security@appspace.com>
|
||||
appspacehosted.com
|
||||
|
@ -11665,10 +11676,6 @@ tuleap-partners.com
|
|||
onred.one
|
||||
staging.onred.one
|
||||
|
||||
// One.com: https://www.one.com/
|
||||
// Submitted by Jacob Bunk Nielsen <jbn@one.com>
|
||||
service.one
|
||||
|
||||
// EU.org https://eu.org/
|
||||
// Submitted by Pierre Beyssac <hostmaster@eu.org>
|
||||
eu.org
|
||||
|
@ -12912,6 +12919,10 @@ cloudycluster.net
|
|||
// Submitted by Vicary Archangel <vicary@omniwe.com>
|
||||
omniwe.site
|
||||
|
||||
// One.com: https://www.one.com/
|
||||
// Submitted by Jacob Bunk Nielsen <jbn@one.com>
|
||||
service.one
|
||||
|
||||
// One Fold Media : http://www.onefoldmedia.com/
|
||||
// Submitted by Eddie Jones <eddie@onefoldmedia.com>
|
||||
nid.io
|
||||
|
@ -13466,6 +13477,11 @@ tabitorder.co.il
|
|||
// Submitted by Bjoern Henke <dev-server@taifun-software.de>
|
||||
taifun-dns.de
|
||||
|
||||
// Tailscale Inc. : https://www.tailscale.com
|
||||
// Submitted by David Anderson <danderson@tailscale.com>
|
||||
beta.tailscale.net
|
||||
ts.net
|
||||
|
||||
// TASK geographical domains (www.task.gda.pl/uslugi/dns)
|
||||
gda.pl
|
||||
gdansk.pl
|
||||
|
|
|
@ -1467,6 +1467,21 @@ void DocumentLoadListener::SerializeRedirectData(
|
|||
}
|
||||
}
|
||||
|
||||
DocumentLoadListener::ProcessBehavior GetProcessSwitchBehavior(
|
||||
Element* aBrowserElement) {
|
||||
if (aBrowserElement->HasAttribute(u"maychangeremoteness"_ns)) {
|
||||
return DocumentLoadListener::ProcessBehavior::PROCESS_BEHAVIOR_STANDARD;
|
||||
}
|
||||
nsCOMPtr<nsIBrowser> browser = aBrowserElement->AsBrowser();
|
||||
bool isRemoteBrowser = false;
|
||||
browser->GetIsRemoteBrowser(&isRemoteBrowser);
|
||||
if (isRemoteBrowser) {
|
||||
return DocumentLoadListener::ProcessBehavior::
|
||||
PROCESS_BEHAVIOR_SUBFRAME_ONLY;
|
||||
}
|
||||
return DocumentLoadListener::ProcessBehavior::PROCESS_BEHAVIOR_DISABLED;
|
||||
}
|
||||
|
||||
static bool ContextCanProcessSwitch(CanonicalBrowsingContext* aBrowsingContext,
|
||||
WindowGlobalParent* aParentWindow) {
|
||||
if (NS_WARN_IF(!aBrowsingContext)) {
|
||||
|
@ -1507,26 +1522,20 @@ static bool ContextCanProcessSwitch(CanonicalBrowsingContext* aBrowsingContext,
|
|||
return false;
|
||||
}
|
||||
|
||||
nsIBrowser::ProcessBehavior processBehavior =
|
||||
nsIBrowser::PROCESS_BEHAVIOR_DISABLED;
|
||||
nsresult rv = browser->GetProcessSwitchBehavior(&processBehavior);
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"nsIBrowser::GetProcessSwitchBehavior shouldn't fail");
|
||||
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
|
||||
("Process Switch Abort: failed to get process switch behavior"));
|
||||
return false;
|
||||
}
|
||||
DocumentLoadListener::ProcessBehavior processBehavior =
|
||||
GetProcessSwitchBehavior(browserElement);
|
||||
|
||||
// Check if the process switch we're considering is disabled by the
|
||||
// <browser>'s process behavior.
|
||||
if (processBehavior == nsIBrowser::PROCESS_BEHAVIOR_DISABLED) {
|
||||
if (processBehavior ==
|
||||
DocumentLoadListener::ProcessBehavior::PROCESS_BEHAVIOR_DISABLED) {
|
||||
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
|
||||
("Process Switch Abort: switch disabled by <browser>"));
|
||||
return false;
|
||||
}
|
||||
if (!aParentWindow &&
|
||||
processBehavior == nsIBrowser::PROCESS_BEHAVIOR_SUBFRAME_ONLY) {
|
||||
if (!aParentWindow && processBehavior ==
|
||||
DocumentLoadListener::ProcessBehavior::
|
||||
PROCESS_BEHAVIOR_SUBFRAME_ONLY) {
|
||||
MOZ_LOG(gProcessIsolationLog, LogLevel::Warning,
|
||||
("Process Switch Abort: toplevel switch disabled by <browser>"));
|
||||
return false;
|
||||
|
|
|
@ -289,6 +289,25 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
|
|||
|
||||
bool IsDocumentLoad() const { return mIsDocumentLoad; }
|
||||
|
||||
// Determine what process switching behavior a browser element should have.
|
||||
enum ProcessBehavior : uint8_t {
|
||||
// Gecko won't automatically change which process this frame, or it's
|
||||
// subframes, are loaded in.
|
||||
PROCESS_BEHAVIOR_DISABLED,
|
||||
|
||||
// If `useRemoteTabs` is enabled, Gecko will change which process this frame
|
||||
// is loaded in automatically, without calling `performProcessSwitch`.
|
||||
// When `useRemoteSubframes` is enabled, subframes will change processes.
|
||||
PROCESS_BEHAVIOR_STANDARD,
|
||||
|
||||
// Gecko won't automatically change which process this frame is loaded, but
|
||||
// when `useRemoteSubframes` is enabled, subframes will change processes.
|
||||
//
|
||||
// NOTE: This configuration is included only for backwards compatibility,
|
||||
// and will be removed, as it can easily lead to invalid behavior.
|
||||
PROCESS_BEHAVIOR_SUBFRAME_ONLY,
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual ~DocumentLoadListener();
|
||||
|
||||
|
|
|
@ -513,6 +513,6 @@ nsFileChannel::SetUploadStream(nsIInputStream* stream,
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::GetUploadStream(nsIInputStream** result) {
|
||||
NS_IF_ADDREF(*result = mUploadStream);
|
||||
*result = do_AddRef(mUploadStream).take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -164,18 +164,7 @@ class nsGIOInputStream final : public nsIInputStream {
|
|||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
|
||||
explicit nsGIOInputStream(const nsCString& uriSpec)
|
||||
: mSpec(uriSpec),
|
||||
mChannel(nullptr),
|
||||
mHandle(nullptr),
|
||||
mStream(nullptr),
|
||||
mBytesRemaining(UINT64_MAX),
|
||||
mStatus(NS_OK),
|
||||
mDirList(nullptr),
|
||||
mDirListPtr(nullptr),
|
||||
mDirBufCursor(0),
|
||||
mDirOpen(false),
|
||||
mMonitorMountInProgress("GIOInputStream::MountFinished") {}
|
||||
explicit nsGIOInputStream(const nsCString& uriSpec) : mSpec(uriSpec) {}
|
||||
|
||||
void SetChannel(nsIChannel* channel) {
|
||||
// We need to hold an owning reference to our channel. This is done
|
||||
|
@ -191,7 +180,7 @@ class nsGIOInputStream final : public nsIInputStream {
|
|||
// cycle since the channel likely owns this stream. This reference
|
||||
// cycle is broken in our Close method.
|
||||
|
||||
NS_ADDREF(mChannel = channel);
|
||||
mChannel = do_AddRef(channel).take();
|
||||
}
|
||||
void SetMountResult(MountOperationResult result, gint error_code);
|
||||
|
||||
|
@ -204,19 +193,19 @@ class nsGIOInputStream final : public nsIInputStream {
|
|||
nsresult DoOpenDirectory();
|
||||
nsresult DoOpenFile(GFileInfo* info);
|
||||
nsCString mSpec;
|
||||
nsIChannel* mChannel; // manually refcounted
|
||||
GFile* mHandle;
|
||||
GFileInputStream* mStream;
|
||||
uint64_t mBytesRemaining;
|
||||
nsresult mStatus;
|
||||
GList* mDirList;
|
||||
GList* mDirListPtr;
|
||||
nsIChannel* mChannel{nullptr}; // manually refcounted
|
||||
GFile* mHandle{nullptr};
|
||||
GFileInputStream* mStream{nullptr};
|
||||
uint64_t mBytesRemaining{UINT64_MAX};
|
||||
nsresult mStatus{NS_OK};
|
||||
GList* mDirList{nullptr};
|
||||
GList* mDirListPtr{nullptr};
|
||||
nsCString mDirBuf;
|
||||
uint32_t mDirBufCursor;
|
||||
bool mDirOpen;
|
||||
uint32_t mDirBufCursor{0};
|
||||
bool mDirOpen{false};
|
||||
MountOperationResult mMountRes =
|
||||
MountOperationResult::MOUNT_OPERATION_SUCCESS;
|
||||
mozilla::Monitor mMonitorMountInProgress;
|
||||
mozilla::Monitor mMonitorMountInProgress{"GIOInputStream::MountFinished"};
|
||||
gint mMountErrorCode{};
|
||||
};
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче