зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
5a948a4c8d
|
@ -150,6 +150,11 @@ add_task(async function test_preferences_page() {
|
|||
openPreferences("search");
|
||||
let popupEvent = await openHistoryMenu(true);
|
||||
|
||||
// Wait for the session data to be flushed before continuing the test
|
||||
await new Promise(resolve =>
|
||||
SessionStore.getSessionHistory(gBrowser.selectedTab, resolve)
|
||||
);
|
||||
|
||||
is(popupEvent.target.children.length, 2, "Correct number of history items");
|
||||
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(
|
||||
|
|
|
@ -75,12 +75,11 @@ this.LoginBreaches = {
|
|||
// they were changed. It's important to note here that we are NOT considering the
|
||||
// username and password of that login.
|
||||
for (const login of logins) {
|
||||
const loginURI = Services.io.newURI(login.origin);
|
||||
let loginHost;
|
||||
try {
|
||||
// nsIURI.host can throw if the URI scheme doesn't have a host.
|
||||
loginHost = loginURI.host;
|
||||
} catch (ex) {
|
||||
loginHost = Services.io.newURI(login.origin).host;
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
for (const breach of breaches) {
|
||||
|
|
|
@ -54,10 +54,10 @@
|
|||
<div class="overlay">
|
||||
<div class="container" role="dialog" aria-labelledby="title" aria-describedby="message">
|
||||
<button class="dismiss-button ghost-button" data-l10n-id="confirmation-dialog-dismiss-button">
|
||||
<img class="dismiss-icon" src="chrome://global/skin/icons/close.svg"/>
|
||||
<img class="dismiss-icon" src="chrome://global/skin/icons/close.svg" draggable="false"/>
|
||||
</button>
|
||||
<div class="content">
|
||||
<img class="warning-icon" src="chrome://global/skin/icons/warning.svg"/>
|
||||
<img class="warning-icon" src="chrome://global/skin/icons/warning.svg" draggable="false"/>
|
||||
<h1 class="title" id="title"></h1>
|
||||
<p class="message" id="message"></p>
|
||||
</div>
|
||||
|
@ -119,7 +119,7 @@
|
|||
<link rel="stylesheet" href="chrome://browser/content/aboutlogins/components/import-error-dialog.css">
|
||||
<generic-dialog>
|
||||
<span slot="dialog-title" data-l10n-id="about-logins-import-dialog-error-title"></span>
|
||||
<img slot="dialog-icon" part="dialog-icon" class="warning-icon" src="chrome://global/skin/icons/warning.svg"/>
|
||||
<img slot="dialog-icon" part="dialog-icon" class="warning-icon" src="chrome://global/skin/icons/warning.svg"/ draggable="false">
|
||||
<div slot="content" class="content">
|
||||
<span class="error-title" data-l10n-id="about-logins-import-dialog-error-unable-to-read-title"></span>
|
||||
<span class="error-description" data-l10n-id="about-logins-import-dialog-error-unable-to-read-description"></span>
|
||||
|
|
|
@ -61,6 +61,13 @@ const TEST_BREACHES = [
|
|||
},
|
||||
];
|
||||
|
||||
const CRASHING_URI_LOGIN = LoginTestUtils.testData.formLogin({
|
||||
origin: "chrome://grwatcher",
|
||||
formActionOrigin: "https://www.example.com",
|
||||
username: "username",
|
||||
password: "password",
|
||||
timePasswordChanged: new Date("2018-12-15").getTime(),
|
||||
});
|
||||
const NOT_BREACHED_LOGIN = LoginTestUtils.testData.formLogin({
|
||||
origin: "https://www.example.com",
|
||||
formActionOrigin: "https://www.example.com",
|
||||
|
@ -107,7 +114,6 @@ const LOGIN_WITH_NON_STANDARD_URI = LoginTestUtils.testData.formLogin({
|
|||
|
||||
add_task(async function test_notBreachedLogin() {
|
||||
Services.logins.addLogin(NOT_BREACHED_LOGIN);
|
||||
|
||||
const breachesByLoginGUID = await LoginBreaches.getPotentialBreachesByLoginGUID(
|
||||
[NOT_BREACHED_LOGIN],
|
||||
TEST_BREACHES
|
||||
|
@ -137,6 +143,25 @@ add_task(async function test_breachedLogin() {
|
|||
);
|
||||
});
|
||||
|
||||
add_task(async function test_breachedLoginAfterCrashingUriLogin() {
|
||||
Services.logins.addLogin(CRASHING_URI_LOGIN);
|
||||
|
||||
const breachesByLoginGUID = await LoginBreaches.getPotentialBreachesByLoginGUID(
|
||||
[CRASHING_URI_LOGIN, BREACHED_LOGIN],
|
||||
TEST_BREACHES
|
||||
);
|
||||
Assert.strictEqual(
|
||||
breachesByLoginGUID.size,
|
||||
1,
|
||||
"Should be 1 breached login: " + BREACHED_LOGIN.origin
|
||||
);
|
||||
Assert.strictEqual(
|
||||
breachesByLoginGUID.get(BREACHED_LOGIN.guid).breachAlertURL,
|
||||
"https://monitor.firefox.com/breach-details/Breached?utm_source=firefox-desktop&utm_medium=referral&utm_campaign=about-logins&utm_content=about-logins",
|
||||
"Breach alert link should be equal to the breachAlertURL"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_notBreachedSubdomain() {
|
||||
Services.logins.addLogin(NOT_BREACHED_SUBDOMAIN_LOGIN);
|
||||
|
||||
|
|
|
@ -4,10 +4,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Ajv",
|
||||
"resource://testing-common/ajv-6.12.6.js"
|
||||
const { JsonSchema } = ChromeUtils.import(
|
||||
"resource://gre/modules/JsonSchema.jsm"
|
||||
);
|
||||
|
||||
const { TelemetryArchive } = ChromeUtils.import(
|
||||
|
@ -312,13 +310,12 @@ add_task(async function testMockSchema() {
|
|||
throw new Error(`Failed to load ${schemaName}`);
|
||||
}
|
||||
|
||||
const ajv = new Ajv({ allErrors: true });
|
||||
const validate = ajv.compile(schema);
|
||||
const validator = new JsonSchema.Validator(schema, { shortCircuit: false });
|
||||
|
||||
for (const entry of values) {
|
||||
const valid = validate(entry);
|
||||
if (!valid) {
|
||||
throw new Error(JSON.stringify(validate.errors));
|
||||
const result = validator.validate(entry);
|
||||
if (!result.valid) {
|
||||
throw new Error(JSON.stringify(result.errors));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -439,13 +439,11 @@ class TestFirefoxRefresh(MarionetteTestCase):
|
|||
let resolve = arguments[arguments.length - 1]
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
let {TabStateFlusher} = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
|
||||
window.addEventListener("SSWindowStateReady", function testSSPostReset() {
|
||||
window.removeEventListener("SSWindowStateReady", testSSPostReset, false);
|
||||
Promise.all(gBrowser.browsers.map(b => TabStateFlusher.flush(b))).then(function() {
|
||||
resolve([... gBrowser.browsers].map(b => b.currentURI && b.currentURI.spec));
|
||||
});
|
||||
}, false);
|
||||
window.addEventListener("SSWindowStateReady", function() {
|
||||
window.addEventListener("SSTabRestored", function() {
|
||||
resolve(Array.from(gBrowser.browsers, b => b.currentURI?.spec));
|
||||
}, { capture: false, once: true });
|
||||
}, { capture: false, once: true });
|
||||
|
||||
let fs = function() {
|
||||
if (content.document.readyState === "complete") {
|
||||
|
|
|
@ -149,6 +149,9 @@ add_task(async function test_bookmark_contextmenu_contents() {
|
|||
return contextMenu;
|
||||
}, optionItems);
|
||||
|
||||
let tab;
|
||||
let contextMenuOnContent;
|
||||
|
||||
await checkContextMenu(async function() {
|
||||
info("Check context menu after opening context menu on content");
|
||||
const toolbarBookmark = await PlacesUtils.bookmarks.insert({
|
||||
|
@ -158,13 +161,8 @@ add_task(async function test_bookmark_contextmenu_contents() {
|
|||
});
|
||||
|
||||
info("Open context menu on about:config");
|
||||
const tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
"about:config"
|
||||
);
|
||||
const contextMenuOnContent = document.getElementById(
|
||||
"contentAreaContextMenu"
|
||||
);
|
||||
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:config");
|
||||
contextMenuOnContent = document.getElementById("contentAreaContextMenu");
|
||||
const popupShownPromiseOnContent = BrowserTestUtils.waitForEvent(
|
||||
contextMenuOnContent,
|
||||
"popupshown"
|
||||
|
@ -189,10 +187,15 @@ add_task(async function test_bookmark_contextmenu_contents() {
|
|||
});
|
||||
await popupShownPromise;
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
return contextMenu;
|
||||
}, optionItems);
|
||||
|
||||
// We need to do a thorough cleanup to avoid leaking the window of
|
||||
// 'about:config'.
|
||||
const tabClosed = BrowserTestUtils.waitForTabClosing(tab);
|
||||
contextMenuOnContent.hidePopup();
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
await tabClosed;
|
||||
});
|
||||
|
||||
add_task(async function test_empty_contextmenu_contents() {
|
||||
|
|
|
@ -1376,8 +1376,11 @@ var SessionStoreInternal = {
|
|||
|
||||
this.onTabStateUpdate(browser.permanentKey, browser.ownerGlobal, data);
|
||||
|
||||
// SHIP code will call this when it receives "browser-shutdown-tabstate-updated"
|
||||
if (data.isFinal) {
|
||||
this.onFinalTabStateUpdateComplete(browser);
|
||||
if (!Services.appinfo.sessionHistoryInParent) {
|
||||
this.onFinalTabStateUpdateComplete(browser);
|
||||
}
|
||||
} else if (data.flushID) {
|
||||
// This is an update kicked off by an async flush request. Notify the
|
||||
// TabStateFlusher so that it can finish the request and notify its
|
||||
|
|
|
@ -139,77 +139,6 @@ var TabStateCacheInternal = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper function used by update (see below). To be fission compatible
|
||||
* we need to be able to update scroll and formdata per entry in the
|
||||
* cache. This is done by looking up the desired position and applying
|
||||
* the update for that node only.
|
||||
*
|
||||
* @param data (object)
|
||||
* The cached data where we want to update the changes.
|
||||
* @param path (object)
|
||||
* The path to the node to update specified by a list of indices
|
||||
* to follow from the root downwards.
|
||||
* @param includeChildren (booelan)
|
||||
* Determines if the children of the changed node should be kept
|
||||
* or not.
|
||||
* @param change (object)
|
||||
* Object containing the optional formdata and optional scroll
|
||||
* position to be updated as well as information if the node
|
||||
* should keep the data for its children.
|
||||
*/
|
||||
updatePartialWindowStateChange(data, path, includeChildren, change) {
|
||||
if (!path.length) {
|
||||
for (let key of Object.keys(change)) {
|
||||
let children = includeChildren ? data[key]?.children : null;
|
||||
|
||||
if (!Object.keys(change[key]).length) {
|
||||
data[key] = null;
|
||||
} else {
|
||||
data[key] = change[key];
|
||||
}
|
||||
|
||||
if (children) {
|
||||
data[key] = { ...data[key], children };
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
let index = path.pop();
|
||||
let scroll = data?.scroll?.children?.[index];
|
||||
let formdata = data?.formdata?.children?.[index];
|
||||
change = this.updatePartialWindowStateChange(
|
||||
{ scroll, formdata },
|
||||
path,
|
||||
includeChildren,
|
||||
change
|
||||
);
|
||||
|
||||
for (let key of Object.keys(change)) {
|
||||
let value = change[key];
|
||||
let children = data[key]?.children;
|
||||
|
||||
if (children) {
|
||||
if (value) {
|
||||
children[index] = value;
|
||||
} else {
|
||||
delete children[index];
|
||||
}
|
||||
|
||||
if (!children.some(e => e)) {
|
||||
data[key] = null;
|
||||
}
|
||||
} else if (value) {
|
||||
children = new Array(index + 1);
|
||||
children[index] = value;
|
||||
data[key] = { ...data[key], children };
|
||||
}
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates cached data for a given |tab| or associated |browser|.
|
||||
*
|
||||
|
@ -233,22 +162,6 @@ var TabStateCacheInternal = {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (key == "windowstatechange") {
|
||||
let { path, hasChildren, ...change } = newData.windowstatechange;
|
||||
this.updatePartialWindowStateChange(data, path, hasChildren, change);
|
||||
|
||||
for (key of Object.keys(change)) {
|
||||
let value = data[key];
|
||||
if (value === null) {
|
||||
delete data[key];
|
||||
} else {
|
||||
data[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = newData[key];
|
||||
if (value === null) {
|
||||
delete data[key];
|
||||
|
|
|
@ -92,6 +92,10 @@ async function test_restore_text_data_subframes(aURL) {
|
|||
}
|
||||
);
|
||||
Assert.equal(out2Val, "", "id prefixes can't be faked");
|
||||
|
||||
// Bug 588077
|
||||
// XXX(farre): disabling this, because it started passing more heavily on Windows.
|
||||
/*
|
||||
let in1ValFrame0_1 = await SpecialPowers.spawn(
|
||||
content.frames[0],
|
||||
[],
|
||||
|
@ -101,8 +105,8 @@ async function test_restore_text_data_subframes(aURL) {
|
|||
});
|
||||
}
|
||||
);
|
||||
// Bug 588077
|
||||
todo_is(in1ValFrame0_1, "", "id prefixes aren't mixed up");
|
||||
*/
|
||||
|
||||
let in1ValFrame1_0 = await SpecialPowers.spawn(
|
||||
content.frames[1],
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
async function test() {
|
||||
let assertNumberOfTabs = function(num, msg) {
|
||||
is(gBrowser.tabs.length, num, msg);
|
||||
};
|
||||
|
@ -18,38 +18,26 @@ function test() {
|
|||
// setup
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:mozilla");
|
||||
|
||||
whenTabIsLoaded(tab, function() {
|
||||
// hide the newly created tab
|
||||
assertNumberOfVisibleTabs(2, "there are two visible tabs");
|
||||
gBrowser.showOnlyTheseTabs([gBrowser.tabs[0]]);
|
||||
assertNumberOfVisibleTabs(1, "there is one visible tab");
|
||||
ok(tab.hidden, "newly created tab is now hidden");
|
||||
await promiseBrowserLoaded(tab.linkedBrowser);
|
||||
|
||||
// close and restore hidden tab
|
||||
promiseRemoveTabAndSessionState(tab).then(() => {
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
// hide the newly created tab
|
||||
assertNumberOfVisibleTabs(2, "there are two visible tabs");
|
||||
gBrowser.showOnlyTheseTabs([gBrowser.tabs[0]]);
|
||||
assertNumberOfVisibleTabs(1, "there is one visible tab");
|
||||
ok(tab.hidden, "newly created tab is now hidden");
|
||||
|
||||
// check that everything was restored correctly, clean up and finish
|
||||
whenTabIsLoaded(tab, function() {
|
||||
is(
|
||||
tab.linkedBrowser.currentURI.spec,
|
||||
"about:mozilla",
|
||||
"restored tab has correct url"
|
||||
);
|
||||
// close and restore hidden tab
|
||||
await promiseRemoveTabAndSessionState(tab);
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function whenTabIsLoaded(tab, callback) {
|
||||
tab.linkedBrowser.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
callback();
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
// check that everything was restored correctly, clean up and finish
|
||||
await promiseBrowserLoaded(tab.linkedBrowser);
|
||||
is(
|
||||
tab.linkedBrowser.currentURI.spec,
|
||||
"about:mozilla",
|
||||
"restored tab has correct url"
|
||||
);
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
}
|
||||
|
|
|
@ -22,12 +22,16 @@ add_task(async function() {
|
|||
|
||||
// Change the "multiple" attribute of the <select> element and select some
|
||||
// options.
|
||||
await SpecialPowers.spawn(tab.linkedBrowser, [VALUES], values => {
|
||||
content.document.querySelector("select").multiple = true;
|
||||
for (let v of values) {
|
||||
content.document.querySelector(`option[value="${v}"]`).selected = true;
|
||||
}
|
||||
});
|
||||
await setPropertyOfFormField(tab.linkedBrowser, "select", "multiple", true);
|
||||
|
||||
for (let v of VALUES) {
|
||||
await setPropertyOfFormField(
|
||||
tab.linkedBrowser,
|
||||
`option[value="${v}"]`,
|
||||
"selected",
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
// Remove the tab.
|
||||
await promiseRemoveTabAndSessionState(tab);
|
||||
|
|
|
@ -211,7 +211,7 @@ toolbarseparator + .panel-subview-body,
|
|||
|
||||
#wrapper-edit-controls:is([place="palette"],[place="menu-panel"]) > #edit-controls,
|
||||
#wrapper-zoom-controls:is([place="palette"],[place="menu-panel"]) > #zoom-controls,
|
||||
.toolbaritem-combined-buttons:is([cui-areatype="menu-panel"], [overflowedItem=true]) {
|
||||
:is(panelview, #widget-overflow-fixed-list) .toolbaritem-combined-buttons {
|
||||
margin: var(--arrowpanel-menuitem-margin);
|
||||
}
|
||||
|
||||
|
@ -385,7 +385,10 @@ panelview[id^=PanelUI-webext-] {
|
|||
min-width: calc(var(--menu-panel-width) + 32px);
|
||||
}
|
||||
|
||||
.toolbaritem-combined-buttons:is([cui-areatype="menu-panel"], [overflowedItem=true]) > toolbarbutton > .toolbarbutton-icon {
|
||||
.toolbaritem-combined-buttons:is(
|
||||
:not([cui-areatype="toolbar"]),
|
||||
[overflowedItem=true]
|
||||
) > toolbarbutton > .toolbarbutton-icon {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
|
@ -1225,8 +1228,10 @@ panelview .toolbarbutton-1 {
|
|||
panelview .toolbarbutton-1,
|
||||
toolbarbutton.subviewbutton,
|
||||
.widget-overflow-list .toolbarbutton-1,
|
||||
.toolbaritem-combined-buttons[cui-areatype="menu-panel"] > toolbarbutton,
|
||||
.toolbaritem-combined-buttons[overflowedItem=true] > toolbarbutton
|
||||
.toolbaritem-combined-buttons:is(
|
||||
:not([cui-areatype="toolbar"]),
|
||||
[overflowedItem=true]
|
||||
) > toolbarbutton
|
||||
):focus-visible {
|
||||
outline: var(--focus-outline);
|
||||
outline-offset: var(--focus-outline-inset);
|
||||
|
@ -1237,8 +1242,10 @@ panelview .toolbarbutton-1 {
|
|||
panelview .toolbarbutton-1,
|
||||
toolbarbutton.subviewbutton,
|
||||
.widget-overflow-list .toolbarbutton-1,
|
||||
.toolbaritem-combined-buttons[cui-areatype="menu-panel"] > toolbarbutton,
|
||||
.toolbaritem-combined-buttons[overflowedItem=true] > toolbarbutton
|
||||
.toolbaritem-combined-buttons:is(
|
||||
:not([cui-areatype="toolbar"]),
|
||||
[overflowedItem=true]
|
||||
) > toolbarbutton
|
||||
):not([disabled]):hover {
|
||||
color: inherit;
|
||||
background-color: var(--panel-item-hover-bgcolor);
|
||||
|
@ -1249,8 +1256,10 @@ panelview .toolbarbutton-1 {
|
|||
panelview .toolbarbutton-1,
|
||||
toolbarbutton.subviewbutton,
|
||||
.widget-overflow-list .toolbarbutton-1,
|
||||
.toolbaritem-combined-buttons[cui-areatype="menu-panel"] > toolbarbutton,
|
||||
.toolbaritem-combined-buttons[overflowedItem=true] > toolbarbutton
|
||||
.toolbaritem-combined-buttons:is(
|
||||
:not([cui-areatype="toolbar"]),
|
||||
[overflowedItem=true]
|
||||
) > toolbarbutton
|
||||
):not([disabled]):hover:active {
|
||||
color: inherit;
|
||||
background-color: var(--panel-item-active-bgcolor);
|
||||
|
@ -1389,7 +1398,10 @@ toolbarpaletteitem[place="palette"] > #search-container {
|
|||
max-height: 37px;
|
||||
}
|
||||
|
||||
.toolbaritem-combined-buttons:is([cui-areatype="menu-panel"], [overflowedItem=true]) > toolbarbutton {
|
||||
.toolbaritem-combined-buttons:is(
|
||||
:not([cui-areatype="toolbar"]),
|
||||
[overflowedItem=true]
|
||||
) > toolbarbutton {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
-moz-box-flex: 1;
|
||||
|
@ -1407,7 +1419,10 @@ toolbarpaletteitem[place="menu-panel"] > toolbaritem {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.toolbaritem-combined-buttons:is([cui-areatype="menu-panel"], [overflowedItem=true]) > toolbarbutton:not(.toolbarbutton-1)[disabled] {
|
||||
.toolbaritem-combined-buttons:is(
|
||||
:not([cui-areatype="toolbar"]),
|
||||
[overflowedItem=true]
|
||||
) > toolbarbutton:not(.toolbarbutton-1)[disabled] {
|
||||
opacity: 0.4;
|
||||
/* Override toolbarbutton.css which sets the color to GrayText */
|
||||
color: inherit;
|
||||
|
@ -1418,7 +1433,10 @@ toolbarpaletteitem[place="menu-panel"] > toolbaritem {
|
|||
min-width: calc(5ch + var(--toolbarbutton-inner-padding) * 2);
|
||||
}
|
||||
|
||||
.toolbaritem-combined-buttons:is([cui-areatype="menu-panel"], [overflowedItem=true]) > separator {
|
||||
.toolbaritem-combined-buttons:is(
|
||||
:not([cui-areatype="toolbar"]),
|
||||
[overflowedItem=true]
|
||||
) > separator {
|
||||
appearance: none;
|
||||
-moz-box-align: stretch;
|
||||
margin: .5em 0;
|
||||
|
@ -1430,7 +1448,10 @@ toolbarpaletteitem[place="menu-panel"] > toolbaritem {
|
|||
transition-timing-function: ease;
|
||||
}
|
||||
|
||||
.toolbaritem-combined-buttons:is([cui-areatype="menu-panel"], [overflowedItem=true]):hover > separator {
|
||||
.toolbaritem-combined-buttons:is(
|
||||
:not([cui-areatype="toolbar"]),
|
||||
[overflowedItem=true]
|
||||
):hover > separator {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1406,11 +1406,10 @@ const windowGlobalTargetPrototype = {
|
|||
* DebuggerProgressListener.
|
||||
*/
|
||||
_windowReady(window, { isFrameSwitching, isBFCache } = {}) {
|
||||
const isTopLevel = window == this.window;
|
||||
|
||||
if (this.ignoreSubFrames && !this.isTopLevel) {
|
||||
if (this.ignoreSubFrames) {
|
||||
return;
|
||||
}
|
||||
const isTopLevel = window == this.window;
|
||||
|
||||
// We just reset iframe list on WillNavigate, so we now list all existing
|
||||
// frames when we load a new document in the original window
|
||||
|
@ -1440,11 +1439,10 @@ const windowGlobalTargetPrototype = {
|
|||
window,
|
||||
{ id = null, isFrozen = false, isFrameSwitching = false }
|
||||
) {
|
||||
const isTopLevel = window == this.window;
|
||||
|
||||
if (this.ignoreSubFrames && !this.isTopLevel) {
|
||||
if (this.ignoreSubFrames) {
|
||||
return;
|
||||
}
|
||||
const isTopLevel = window == this.window;
|
||||
|
||||
// If this follows WindowGlobal lifecycle, this target will be destroyed, alongside its top level document.
|
||||
// Only notify about in-process iframes.
|
||||
|
@ -1474,11 +1472,10 @@ const windowGlobalTargetPrototype = {
|
|||
isFrameSwitching = false,
|
||||
navigationStart,
|
||||
}) {
|
||||
let isTopLevel = window == this.window;
|
||||
|
||||
if (this.ignoreSubFrames && !this.isTopLevel) {
|
||||
if (this.ignoreSubFrames) {
|
||||
return;
|
||||
}
|
||||
let isTopLevel = window == this.window;
|
||||
|
||||
let reset = false;
|
||||
if (window == this._originalWindow && !isFrameSwitching) {
|
||||
|
@ -1533,11 +1530,10 @@ const windowGlobalTargetPrototype = {
|
|||
* targeted window global.
|
||||
*/
|
||||
_navigate(window, isFrameSwitching = false) {
|
||||
const isTopLevel = window == this.window;
|
||||
|
||||
if (this.ignoreSubFrames && !this.isTopLevel) {
|
||||
if (this.ignoreSubFrames) {
|
||||
return;
|
||||
}
|
||||
const isTopLevel = window == this.window;
|
||||
|
||||
// navigate event needs to be dispatched synchronously,
|
||||
// by calling the listeners in the order or registration.
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
"use strict";
|
||||
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { Ci } = require("chrome");
|
||||
const ChromeUtils = require("ChromeUtils");
|
||||
|
||||
/**
|
||||
* About "navigationStart - ${WILL_NAVIGATE_TIME_SHIFT}ms":
|
||||
|
@ -54,11 +56,32 @@ exports.DocumentEventsListener = DocumentEventsListener;
|
|||
|
||||
DocumentEventsListener.prototype = {
|
||||
listen() {
|
||||
// Listen to will-navigate and do not emit a fake one as we only care about upcoming navigation
|
||||
this.targetActor.on("will-navigate", this.onWillNavigate);
|
||||
// When EFT is enabled, the Target Actor won't dispatch any will-navigate/window-ready event
|
||||
// Instead listen to WebProgressListener interface directly, so that we can later drop the whole
|
||||
// DebuggerProgressListener interface in favor of this class.
|
||||
// Also, do not wait for "load" event as it can be blocked in case of error during the load
|
||||
// or when calling window.stop(). We still want to emit "dom-complete" in these scenarios.
|
||||
if (this.targetActor.ignoreSubFrames) {
|
||||
// Ignore listening to anything if the page is already fully loaded.
|
||||
// This can be the case when opening DevTools against an already loaded page
|
||||
// or when doing bfcache navigations.
|
||||
if (this.targetActor.window.document.readyState != "complete") {
|
||||
this.webProgress = this.targetActor.docShell
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress);
|
||||
this.webProgress.addProgressListener(
|
||||
this,
|
||||
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
|
||||
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Listen to will-navigate and do not emit a fake one as we only care about upcoming navigation
|
||||
this.targetActor.on("will-navigate", this.onWillNavigate);
|
||||
|
||||
// Listen to window-ready and then fake one in order to notify about dom-loading for the existing document
|
||||
this.targetActor.on("window-ready", this.onWindowReady);
|
||||
// Listen to window-ready and then fake one in order to notify about dom-loading for the existing document
|
||||
this.targetActor.on("window-ready", this.onWindowReady);
|
||||
}
|
||||
// The target actor already emitted a window-ready for the top document when instantiating.
|
||||
// So fake one for the top document right away.
|
||||
this.onWindowReady({
|
||||
|
@ -101,20 +124,26 @@ DocumentEventsListener.prototype = {
|
|||
|
||||
const { readyState } = window.document;
|
||||
if (readyState != "interactive" && readyState != "complete") {
|
||||
window.addEventListener(
|
||||
"DOMContentLoaded",
|
||||
e => this.onContentLoaded(e, isFrameSwitching),
|
||||
{
|
||||
once: true,
|
||||
}
|
||||
);
|
||||
// When EFT is enabled, we track this event via the WebProgressListener interface.
|
||||
if (!this.targetActor.ignoreSubFrames) {
|
||||
window.addEventListener(
|
||||
"DOMContentLoaded",
|
||||
e => this.onContentLoaded(e, isFrameSwitching),
|
||||
{
|
||||
once: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.onContentLoaded({ target: window.document }, isFrameSwitching);
|
||||
}
|
||||
if (readyState != "complete") {
|
||||
window.addEventListener("load", e => this.onLoad(e, isFrameSwitching), {
|
||||
once: true,
|
||||
});
|
||||
// When EFT is enabled, we track the load event via the WebProgressListener interface.
|
||||
if (!this.targetActor.ignoreSubFrames) {
|
||||
window.addEventListener("load", e => this.onLoad(e, isFrameSwitching), {
|
||||
once: true,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.onLoad({ target: window.document }, isFrameSwitching);
|
||||
}
|
||||
|
@ -148,6 +177,29 @@ DocumentEventsListener.prototype = {
|
|||
});
|
||||
},
|
||||
|
||||
onStateChange(progress, request, flag, status) {
|
||||
progress.QueryInterface(Ci.nsIDocShell);
|
||||
// Ignore destroyed, or progress for same-process iframes
|
||||
if (progress.isBeingDestroyed() || progress != this.webProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isStop = flag & Ci.nsIWebProgressListener.STATE_STOP;
|
||||
const isDocument = flag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
|
||||
const isWindow = flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
|
||||
const window = progress.DOMWindow;
|
||||
if (isDocument && isStop) {
|
||||
const time = window.performance.timing.domInteractive;
|
||||
this.emit("dom-interactive", { time });
|
||||
} else if (isWindow && isStop) {
|
||||
const time = window.performance.timing.domComplete;
|
||||
this.emit("dom-complete", {
|
||||
time,
|
||||
hasNativeConsoleAPI: this.hasNativeConsoleAPI(window),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Tells if the window.console object is native or overwritten by script in
|
||||
* the page.
|
||||
|
@ -179,5 +231,17 @@ DocumentEventsListener.prototype = {
|
|||
this.destroyed = true;
|
||||
this.targetActor.off("will-navigate", this.onWillNavigate);
|
||||
this.targetActor.off("window-ready", this.onWindowReady);
|
||||
if (this.webProgress) {
|
||||
this.webProgress.removeProgressListener(
|
||||
this,
|
||||
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
|
||||
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
"nsIWebProgressListener",
|
||||
"nsISupportsWeakReference",
|
||||
]),
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@ add_task(async function() {
|
|||
await testDomCompleteWithOverloadedConsole();
|
||||
await testIframeNavigation();
|
||||
await testBfCacheNavigation();
|
||||
await testDomCompleteWithWindowStop();
|
||||
|
||||
// Enable server side target switching for next test
|
||||
// as the regression it tracks only occurs with server side target switching enabled
|
||||
|
@ -540,6 +541,47 @@ async function testDomCompleteWithOverloadedConsole() {
|
|||
await client.close();
|
||||
}
|
||||
|
||||
async function testDomCompleteWithWindowStop() {
|
||||
info("Test dom-complete with a page calling window.stop()");
|
||||
|
||||
const tab = await addTab("data:text/html,foo");
|
||||
|
||||
const {
|
||||
commands,
|
||||
client,
|
||||
resourceCommand,
|
||||
targetCommand,
|
||||
} = await initResourceCommand(tab);
|
||||
|
||||
info("Check that all DOCUMENT_EVENTS are fired for the already loaded page");
|
||||
let documentEvents = [];
|
||||
await resourceCommand.watchResources([resourceCommand.TYPES.DOCUMENT_EVENT], {
|
||||
onAvailable: resources => documentEvents.push(...resources),
|
||||
});
|
||||
is(documentEvents.length, 3, "Existing document events are fired");
|
||||
documentEvents = [];
|
||||
|
||||
const html = `<!DOCTYPE html><html>
|
||||
<head>
|
||||
<title>stopped page</title>
|
||||
<script>window.stop();</script>
|
||||
</head>
|
||||
<body>Page content that shouldn't be displayed</body>
|
||||
</html>`;
|
||||
const secondLocation = "data:text/html," + encodeURIComponent(html);
|
||||
const targetBeforeNavigation = commands.targetCommand.targetFront;
|
||||
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, secondLocation);
|
||||
info(
|
||||
"Wait for will-navigate, dom-loading, dom-interactive and dom-complete events"
|
||||
);
|
||||
await waitFor(() => documentEvents.length === 4);
|
||||
|
||||
assertEvents({ commands, targetBeforeNavigation, documentEvents });
|
||||
|
||||
targetCommand.destroy();
|
||||
await client.close();
|
||||
}
|
||||
|
||||
async function assertPromises(
|
||||
commands,
|
||||
targetBeforeNavigation,
|
||||
|
|
|
@ -36,11 +36,12 @@
|
|||
#include "mozilla/dom/MediaDevices.h"
|
||||
#include "mozilla/dom/PopupBlocker.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/SessionStoreChild.h"
|
||||
#include "mozilla/dom/SessionStorageManager.h"
|
||||
#include "mozilla/dom/SessionStoreDataCollector.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/UserActivationIPCUtils.h"
|
||||
#include "mozilla/dom/WindowBinding.h"
|
||||
#include "mozilla/dom/WindowContext.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/dom/WindowProxyHolder.h"
|
||||
|
@ -2277,44 +2278,6 @@ void BrowsingContext::IncrementHistoryEntryCountForBrowsingContext() {
|
|||
Unused << SetHistoryEntryCount(GetHistoryEntryCount() + 1);
|
||||
}
|
||||
|
||||
void BrowsingContext::FlushSessionStore() {
|
||||
nsTArray<RefPtr<BrowserChild>> nestedBrowserChilds;
|
||||
|
||||
PreOrderWalk([&](BrowsingContext* aContext) {
|
||||
BrowserChild* browserChild = BrowserChild::GetFrom(aContext->GetDocShell());
|
||||
if (browserChild && browserChild->GetBrowsingContext() == aContext) {
|
||||
nestedBrowserChilds.AppendElement(browserChild);
|
||||
}
|
||||
|
||||
if (aContext->CreatedDynamically()) {
|
||||
return WalkFlag::Skip;
|
||||
}
|
||||
|
||||
WindowContext* windowContext = aContext->GetCurrentWindowContext();
|
||||
if (!windowContext) {
|
||||
return WalkFlag::Skip;
|
||||
}
|
||||
|
||||
WindowGlobalChild* windowChild = windowContext->GetWindowGlobalChild();
|
||||
if (!windowChild) {
|
||||
return WalkFlag::Next;
|
||||
}
|
||||
|
||||
RefPtr<SessionStoreDataCollector> collector =
|
||||
windowChild->GetSessionStoreDataCollector();
|
||||
if (!collector) {
|
||||
return WalkFlag::Next;
|
||||
}
|
||||
|
||||
collector->Flush();
|
||||
return WalkFlag::Next;
|
||||
});
|
||||
|
||||
for (auto& child : nestedBrowserChilds) {
|
||||
child->UpdateSessionStore();
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<bool, bool> BrowsingContext::CanFocusCheck(CallerType aCallerType) {
|
||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
if (!fm) {
|
||||
|
@ -2635,6 +2598,20 @@ nsresult BrowsingContext::ResetGVAutoplayRequestStatus() {
|
|||
return txn.Commit(this);
|
||||
}
|
||||
|
||||
void BrowsingContext::DidSet(FieldIndex<IDX_SessionStoreEpoch>,
|
||||
uint32_t aOldValue) {
|
||||
if (!mCurrentWindowContext) {
|
||||
return;
|
||||
}
|
||||
SessionStoreChild* sessionStoreChild =
|
||||
SessionStoreChild::From(mCurrentWindowContext->GetWindowGlobalChild());
|
||||
if (!sessionStoreChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
sessionStoreChild->SetEpoch(GetSessionStoreEpoch());
|
||||
}
|
||||
|
||||
void BrowsingContext::DidSet(FieldIndex<IDX_GVAudibleAutoplayRequestStatus>) {
|
||||
MOZ_ASSERT(IsTop(),
|
||||
"Should only set GVAudibleAutoplayRequestStatus in the top-level "
|
||||
|
@ -3407,6 +3384,17 @@ void BrowsingContext::AddDeprioritizedLoadRunner(nsIRunnable* aRunner) {
|
|||
EventQueuePriority::Idle);
|
||||
}
|
||||
|
||||
bool BrowsingContext::IsDynamic() const {
|
||||
const BrowsingContext* current = this;
|
||||
do {
|
||||
if (current->CreatedDynamically()) {
|
||||
return true;
|
||||
}
|
||||
} while ((current = current->GetParent()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BrowsingContext::GetOffsetPath(nsTArray<uint32_t>& aPath) const {
|
||||
for (const BrowsingContext* current = this; current && current->GetParent();
|
||||
current = current->GetParent()) {
|
||||
|
|
|
@ -784,6 +784,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
|
||||
bool CreatedDynamically() const { return mCreatedDynamically; }
|
||||
|
||||
// Returns true if this browsing context, or any ancestor to this browsing
|
||||
// context was created dynamically. See also `CreatedDynamically`.
|
||||
bool IsDynamic() const;
|
||||
|
||||
int32_t ChildOffset() const { return mChildOffset; }
|
||||
|
||||
bool GetOffsetPath(nsTArray<uint32_t>& aPath) const;
|
||||
|
@ -889,8 +893,6 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
return GetPrefersColorSchemeOverride();
|
||||
}
|
||||
|
||||
void FlushSessionStore();
|
||||
|
||||
bool IsInBFCache() const;
|
||||
|
||||
bool AllowJavascript() const { return GetAllowJavascript(); }
|
||||
|
@ -1002,6 +1004,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
return IsTop() && !aSource;
|
||||
}
|
||||
|
||||
void DidSet(FieldIndex<IDX_SessionStoreEpoch>, uint32_t aOldValue);
|
||||
|
||||
using CanSetResult = syncedcontext::CanSetResult;
|
||||
|
||||
// Ensure that opener is in the same BrowsingContextGroup.
|
||||
|
|
|
@ -2367,7 +2367,7 @@ void CanonicalBrowsingContext::UpdateSessionStoreSessionStorage(
|
|||
using DataPromise = BackgroundSessionStorageManager::DataPromise;
|
||||
BackgroundSessionStorageManager::GetData(
|
||||
this, StaticPrefs::browser_sessionstore_dom_storage_limit(),
|
||||
/* aCancelSessionStoreTiemr = */ true)
|
||||
/* aClearSessionStoreTimer = */ true)
|
||||
->Then(GetCurrentSerialEventTarget(), __func__,
|
||||
[self = RefPtr{this}, aDone, epoch = GetSessionStoreEpoch()](
|
||||
const DataPromise::ResolveOrRejectValue& valueList) {
|
||||
|
|
|
@ -55,6 +55,8 @@ class MediaController;
|
|||
struct LoadingSessionHistoryInfo;
|
||||
class SSCacheCopy;
|
||||
class WindowGlobalParent;
|
||||
class SessionStoreFormData;
|
||||
class SessionStoreScrollData;
|
||||
|
||||
// CanonicalBrowsingContext is a BrowsingContext living in the parent
|
||||
// process, with whatever extra data that a BrowsingContext in the
|
||||
|
@ -524,6 +526,17 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
|||
|
||||
RefPtr<FeaturePolicy> mContainerFeaturePolicy;
|
||||
|
||||
friend class BrowserSessionStore;
|
||||
WeakPtr<SessionStoreFormData>& GetSessionStoreFormDataRef() {
|
||||
return mFormdata;
|
||||
}
|
||||
WeakPtr<SessionStoreScrollData>& GetSessionStoreScrollDataRef() {
|
||||
return mScroll;
|
||||
}
|
||||
|
||||
WeakPtr<SessionStoreFormData> mFormdata;
|
||||
WeakPtr<SessionStoreScrollData> mScroll;
|
||||
|
||||
RefPtr<RestoreState> mRestoreState;
|
||||
|
||||
// If this is a top level context, this is true if our browser ID is marked as
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
#include "mozilla/dom/SessionHistoryEntry.h"
|
||||
#include "mozilla/dom/SessionStorageManager.h"
|
||||
#include "mozilla/dom/SessionStoreChangeListener.h"
|
||||
#include "mozilla/dom/SessionStoreDataCollector.h"
|
||||
#include "mozilla/dom/SessionStoreChild.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
|
@ -1325,7 +1325,10 @@ void nsDocShell::FirePageHideShowNonRecursive(bool aShow) {
|
|||
// performance.navigation.type is 2.
|
||||
// Traditionally this type change has been done to the top level page
|
||||
// only.
|
||||
inner->GetPerformance()->GetDOMTiming()->NotifyRestoreStart();
|
||||
Performance* performance = inner->GetPerformance();
|
||||
if (performance) {
|
||||
performance->GetDOMTiming()->NotifyRestoreStart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5813,7 +5816,12 @@ nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
|
|||
|
||||
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
|
||||
if (IsForceReloadType(mLoadType)) {
|
||||
SessionStoreUtils::ResetSessionStore(mBrowsingContext);
|
||||
if (WindowContext* windowContext =
|
||||
mBrowsingContext->GetCurrentWindowContext()) {
|
||||
SessionStoreChild::From(windowContext->GetWindowGlobalChild())
|
||||
->SendResetSessionStore(
|
||||
mBrowsingContext, mBrowsingContext->GetSessionStoreEpoch());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6554,13 +6562,13 @@ nsresult nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
|
|||
return NS_OK;
|
||||
}
|
||||
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
|
||||
if (Document* document = GetDocument()) {
|
||||
if (WindowGlobalChild* windowChild = document->GetWindowGlobalChild()) {
|
||||
RefPtr<SessionStoreDataCollector> collector =
|
||||
SessionStoreDataCollector::CollectSessionStoreData(windowChild);
|
||||
collector->RecordInputChange();
|
||||
collector->RecordScrollChange();
|
||||
}
|
||||
if (WindowContext* windowContext =
|
||||
mBrowsingContext->GetCurrentWindowContext()) {
|
||||
// TODO(farre): File bug: From a user perspective this would probably be
|
||||
// just fine to run off the change listener timer. Turns out that a flush
|
||||
// is needed. Several tests depend on this behaviour. Could potentially be
|
||||
// an optimization for later. See Bug 1756995.
|
||||
SessionStoreChangeListener::FlushAllSessionStoreData(windowContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7755,7 +7763,10 @@ nsresult nsDocShell::RestoreFromHistory() {
|
|||
// Now that we have found the inner window of the page restored
|
||||
// from the history, we have to make sure that
|
||||
// performance.navigation.type is 2.
|
||||
privWinInner->GetPerformance()->GetDOMTiming()->NotifyRestoreStart();
|
||||
Performance* performance = privWinInner->GetPerformance();
|
||||
if (performance) {
|
||||
performance->GetDOMTiming()->NotifyRestoreStart();
|
||||
}
|
||||
|
||||
// Restore the refresh URI list. The refresh timers will be restarted
|
||||
// when EndPageLoad() is called.
|
||||
|
@ -11175,27 +11186,35 @@ bool nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
|
|||
return onLocationChangeNeeded;
|
||||
}
|
||||
|
||||
void nsDocShell::CollectWireframe() {
|
||||
if (mozilla::SessionHistoryInParent() &&
|
||||
bool nsDocShell::CollectWireframe() {
|
||||
const bool collectWireFrame =
|
||||
mozilla::SessionHistoryInParent() &&
|
||||
StaticPrefs::browser_history_collectWireframes() &&
|
||||
mBrowsingContext->IsTopContent() && mActiveEntry) {
|
||||
RefPtr<Document> doc = mContentViewer->GetDocument();
|
||||
Nullable<Wireframe> wireframe;
|
||||
doc->GetWireframeWithoutFlushing(false, wireframe);
|
||||
if (!wireframe.IsNull()) {
|
||||
if (XRE_IsParentProcess()) {
|
||||
SessionHistoryEntry* entry =
|
||||
mBrowsingContext->Canonical()->GetActiveSessionHistoryEntry();
|
||||
if (entry) {
|
||||
entry->SetWireframe(Some(wireframe.Value()));
|
||||
}
|
||||
} else {
|
||||
mozilla::Unused
|
||||
<< ContentChild::GetSingleton()->SendSessionHistoryEntryWireframe(
|
||||
mBrowsingContext, wireframe.Value());
|
||||
}
|
||||
}
|
||||
mBrowsingContext->IsTopContent() && mActiveEntry;
|
||||
|
||||
if (!collectWireFrame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<Document> doc = mContentViewer->GetDocument();
|
||||
Nullable<Wireframe> wireframe;
|
||||
doc->GetWireframeWithoutFlushing(false, wireframe);
|
||||
if (wireframe.IsNull()) {
|
||||
return false;
|
||||
}
|
||||
if (XRE_IsParentProcess()) {
|
||||
SessionHistoryEntry* entry =
|
||||
mBrowsingContext->Canonical()->GetActiveSessionHistoryEntry();
|
||||
if (entry) {
|
||||
entry->SetWireframe(Some(wireframe.Value()));
|
||||
}
|
||||
} else {
|
||||
mozilla::Unused
|
||||
<< ContentChild::GetSingleton()->SendSessionHistoryEntryWireframe(
|
||||
mBrowsingContext, wireframe.Value());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
|
|
|
@ -742,8 +742,8 @@ class nsDocShell final : public nsDocLoader,
|
|||
public:
|
||||
// If wireframe collection is enabled, will attempt to gather the
|
||||
// wireframe for the document and stash it inside of the active history
|
||||
// entry.
|
||||
void CollectWireframe();
|
||||
// entry. Returns true if wireframes were collected.
|
||||
bool CollectWireframe();
|
||||
|
||||
// Helper method that is called when a new document (including any
|
||||
// sub-documents - ie. frames) has been completely loaded.
|
||||
|
|
|
@ -54,9 +54,12 @@ static nsSize GetContentRectSize(const nsIFrame& aFrame) {
|
|||
nsMargin padding =
|
||||
aFrame.GetUsedPadding().ApplySkipSides(aFrame.GetSkipSides());
|
||||
scrollPort.Deflate(padding);
|
||||
MOZ_ASSERT(!aFrame.PresContext()->UseOverlayScrollbars() ||
|
||||
scrollPort.Size() ==
|
||||
aFrame.GetContentRectRelativeToSelf().Size());
|
||||
// This can break in some edge cases like when layout overflows sizes or
|
||||
// what not.
|
||||
NS_ASSERTION(
|
||||
!aFrame.PresContext()->UseOverlayScrollbars() ||
|
||||
scrollPort.Size() == aFrame.GetContentRectRelativeToSelf().Size(),
|
||||
"Wrong scrollport?");
|
||||
return scrollPort.Size();
|
||||
}
|
||||
return aFrame.GetContentRectRelativeToSelf().Size();
|
||||
|
|
|
@ -86,15 +86,17 @@
|
|||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/StaticPrefs_fission.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/ChromeMessageSender.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/FrameCrashedEvent.h"
|
||||
#include "mozilla/dom/FrameLoaderBinding.h"
|
||||
#include "mozilla/dom/InProcessChild.h"
|
||||
#include "mozilla/dom/MozFrameLoaderOwnerBinding.h"
|
||||
#include "mozilla/dom/PBrowser.h"
|
||||
#include "mozilla/dom/SessionHistoryEntry.h"
|
||||
#include "mozilla/dom/SessionStoreChangeListener.h"
|
||||
#include "mozilla/dom/SessionStoreListener.h"
|
||||
#include "mozilla/dom/SessionStoreChild.h"
|
||||
#include "mozilla/dom/SessionStoreParent.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/dom/XULFrameElement.h"
|
||||
|
@ -164,8 +166,7 @@ using PrintPreviewResolver = std::function<void(const PrintPreviewResultInfo&)>;
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsFrameLoader, mPendingBrowsingContext,
|
||||
mMessageManager, mChildMessageManager,
|
||||
mRemoteBrowser,
|
||||
mSessionStoreChangeListener)
|
||||
mRemoteBrowser, mSessionStoreChild)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
|
||||
|
||||
|
@ -2041,14 +2042,9 @@ void nsFrameLoader::DestroyDocShell() {
|
|||
mChildMessageManager->FireUnloadEvent();
|
||||
}
|
||||
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->RemoveListeners();
|
||||
mSessionStoreListener = nullptr;
|
||||
}
|
||||
|
||||
if (mSessionStoreChangeListener) {
|
||||
mSessionStoreChangeListener->Stop();
|
||||
mSessionStoreChangeListener = nullptr;
|
||||
if (mSessionStoreChild) {
|
||||
mSessionStoreChild->Stop();
|
||||
mSessionStoreChild = nullptr;
|
||||
}
|
||||
|
||||
// Destroy the docshell.
|
||||
|
@ -2141,22 +2137,22 @@ void nsFrameLoader::SetOwnerContent(Element* aContent) {
|
|||
#endif
|
||||
}
|
||||
|
||||
if (mSessionStoreListener && mOwnerContent) {
|
||||
if (mSessionStoreChild && mOwnerContent) {
|
||||
// mOwnerContent will only be null when the frame loader is being destroyed,
|
||||
// so the session store listener will be destroyed along with it.
|
||||
// XXX(farre): This probably needs to update the cache. See bug 1698497.
|
||||
mSessionStoreListener->SetOwnerContent(mOwnerContent);
|
||||
mSessionStoreChild->SetOwnerContent(mOwnerContent);
|
||||
}
|
||||
|
||||
if (RefPtr<BrowsingContext> browsingContext = GetExtantBrowsingContext()) {
|
||||
browsingContext->SetEmbedderElement(mOwnerContent);
|
||||
}
|
||||
|
||||
if (mSessionStoreChangeListener) {
|
||||
if (mSessionStoreChild) {
|
||||
// UpdateEventTargets will requery its browser contexts for event
|
||||
// targets, so this call needs to happen after the call to
|
||||
// SetEmbedderElement above.
|
||||
mSessionStoreChangeListener->UpdateEventTargets();
|
||||
mSessionStoreChild->UpdateEventTargets();
|
||||
}
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
|
@ -3101,15 +3097,11 @@ nsresult nsFrameLoader::EnsureMessageManager() {
|
|||
GetDocShell(), mOwnerContent, mMessageManager);
|
||||
NS_ENSURE_TRUE(mChildMessageManager, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// Set up a TabListener for sessionStore
|
||||
// Set up session store
|
||||
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
|
||||
if (XRE_IsParentProcess()) {
|
||||
mSessionStoreListener = new TabListener(GetDocShell(), mOwnerContent);
|
||||
rv = mSessionStoreListener->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSessionStoreChangeListener =
|
||||
SessionStoreChangeListener::Create(GetExtantBrowsingContext());
|
||||
if (XRE_IsParentProcess() && mIsTopLevelContent) {
|
||||
mSessionStoreChild = SessionStoreChild::GetOrCreate(
|
||||
GetExtantBrowsingContext(), mOwnerContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3237,6 +3229,21 @@ void nsFrameLoader::RequestUpdatePosition(ErrorResult& aRv) {
|
|||
}
|
||||
}
|
||||
|
||||
SessionStoreParent* nsFrameLoader::GetSessionStoreParent() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
|
||||
if (mSessionStoreChild) {
|
||||
return static_cast<SessionStoreParent*>(
|
||||
InProcessChild::ParentActorFor(mSessionStoreChild));
|
||||
}
|
||||
|
||||
if (BrowserParent* browserParent = GetBrowserParent()) {
|
||||
return static_cast<SessionStoreParent*>(
|
||||
SingleManagedOrNull(browserParent->ManagedPSessionStoreParent()));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise> nsFrameLoader::RequestTabStateFlush(
|
||||
ErrorResult& aRv) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
|
||||
|
@ -3247,42 +3254,24 @@ already_AddRefed<Promise> nsFrameLoader::RequestTabStateFlush(
|
|||
}
|
||||
|
||||
RefPtr<Promise> promise = Promise::Create(ownerDoc->GetOwnerGlobal(), aRv);
|
||||
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<BrowsingContext> context = GetExtantBrowsingContext();
|
||||
if (!context) {
|
||||
BrowsingContext* browsingContext = GetExtantBrowsingContext();
|
||||
if (!browsingContext) {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
if (mSessionStoreListener) {
|
||||
context->FlushSessionStore();
|
||||
mSessionStoreListener->ForceFlushFromParent();
|
||||
context->Canonical()->UpdateSessionStoreSessionStorage(
|
||||
[promise]() { promise->MaybeResolveWithUndefined(); });
|
||||
|
||||
SessionStoreParent* sessionStoreParent = GetSessionStoreParent();
|
||||
if (!sessionStoreParent) {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
using FlushPromise = ContentParent::FlushTabStatePromise;
|
||||
nsTArray<RefPtr<FlushPromise>> flushPromises;
|
||||
context->Group()->EachParent([&](ContentParent* aParent) {
|
||||
if (aParent->CanSend()) {
|
||||
flushPromises.AppendElement(aParent->SendFlushTabState(context));
|
||||
}
|
||||
});
|
||||
|
||||
RefPtr<FlushPromise::AllPromiseType> flushPromise =
|
||||
FlushPromise::All(GetCurrentSerialEventTarget(), flushPromises);
|
||||
|
||||
context->Canonical()->UpdateSessionStoreSessionStorage([flushPromise,
|
||||
promise]() {
|
||||
flushPromise->Then(GetCurrentSerialEventTarget(), __func__,
|
||||
[promise]() { promise->MaybeResolveWithUndefined(); });
|
||||
});
|
||||
sessionStoreParent->FlushAllSessionStoreChildren(
|
||||
[promise]() { promise->MaybeResolveWithUndefined(); });
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -3297,10 +3286,8 @@ void nsFrameLoader::RequestFinalTabStateFlush() {
|
|||
RefPtr<WindowGlobalParent> wgp = canonical->GetCurrentWindowGlobal();
|
||||
RefPtr<Element> embedder = context->GetEmbedderElement();
|
||||
|
||||
if (mSessionStoreListener) {
|
||||
context->FlushSessionStore();
|
||||
mSessionStoreListener->ForceFlushFromParent();
|
||||
|
||||
RefPtr<SessionStoreParent> sessionStoreParent = GetSessionStoreParent();
|
||||
if (!sessionStoreParent) {
|
||||
canonical->ClearPermanentKey();
|
||||
if (wgp) {
|
||||
wgp->NotifySessionStoreUpdatesComplete(embedder);
|
||||
|
@ -3309,24 +3296,15 @@ void nsFrameLoader::RequestFinalTabStateFlush() {
|
|||
return;
|
||||
}
|
||||
|
||||
using FlushPromise = ContentParent::FlushTabStatePromise;
|
||||
nsTArray<RefPtr<FlushPromise>> flushPromises;
|
||||
context->Group()->EachParent([&](ContentParent* aParent) {
|
||||
if (aParent->CanSend()) {
|
||||
flushPromises.AppendElement(aParent->SendFlushTabState(context));
|
||||
}
|
||||
});
|
||||
|
||||
FlushPromise::All(GetCurrentSerialEventTarget(), flushPromises)
|
||||
->Then(GetCurrentSerialEventTarget(), __func__,
|
||||
[canonical = RefPtr{canonical}, wgp, embedder]() {
|
||||
if (canonical) {
|
||||
canonical->ClearPermanentKey();
|
||||
}
|
||||
if (wgp) {
|
||||
wgp->NotifySessionStoreUpdatesComplete(embedder);
|
||||
}
|
||||
});
|
||||
sessionStoreParent->FinalFlushAllSessionStoreChildren(
|
||||
[canonical, wgp, embedder]() {
|
||||
if (canonical) {
|
||||
canonical->ClearPermanentKey();
|
||||
}
|
||||
if (wgp) {
|
||||
wgp->NotifySessionStoreUpdatesComplete(embedder);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void nsFrameLoader::RequestEpochUpdate(uint32_t aEpoch) {
|
||||
|
@ -3335,21 +3313,11 @@ void nsFrameLoader::RequestEpochUpdate(uint32_t aEpoch) {
|
|||
BrowsingContext* top = context->Top();
|
||||
Unused << top->SetSessionStoreEpoch(aEpoch);
|
||||
}
|
||||
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->SetEpoch(aEpoch);
|
||||
return;
|
||||
}
|
||||
|
||||
// If remote browsing (e10s), handle this with the BrowserParent.
|
||||
if (auto* browserParent = GetBrowserParent()) {
|
||||
Unused << browserParent->SendUpdateEpoch(aEpoch);
|
||||
}
|
||||
}
|
||||
|
||||
void nsFrameLoader::RequestSHistoryUpdate() {
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->UpdateSHistoryChanges();
|
||||
if (mSessionStoreChild) {
|
||||
mSessionStoreChild->UpdateSHistoryChanges();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ class ChromeMessageSender;
|
|||
class ContentParent;
|
||||
class Document;
|
||||
class Element;
|
||||
class TabListener;
|
||||
class InProcessBrowserChildMessageManager;
|
||||
class MessageSender;
|
||||
class ProcessMessageManager;
|
||||
|
@ -73,7 +72,8 @@ class BrowserBridgeChild;
|
|||
class RemoteBrowser;
|
||||
struct RemotenessOptions;
|
||||
struct NavigationIsolationOptions;
|
||||
class SessionStoreChangeListener;
|
||||
class SessionStoreChild;
|
||||
class SessionStoreParent;
|
||||
|
||||
namespace ipc {
|
||||
class StructuredCloneData;
|
||||
|
@ -411,6 +411,12 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
|||
|
||||
void FireErrorEvent();
|
||||
|
||||
mozilla::dom::SessionStoreChild* GetSessionStoreChild() {
|
||||
return mSessionStoreChild;
|
||||
}
|
||||
|
||||
mozilla::dom::SessionStoreParent* GetSessionStoreParent();
|
||||
|
||||
private:
|
||||
nsFrameLoader(mozilla::dom::Element* aOwner,
|
||||
mozilla::dom::BrowsingContext* aBrowsingContext, bool aIsRemote,
|
||||
|
@ -520,9 +526,10 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
|||
// Holds the last known size of the frame.
|
||||
mozilla::ScreenIntSize mLazySize;
|
||||
|
||||
RefPtr<mozilla::dom::TabListener> mSessionStoreListener;
|
||||
|
||||
RefPtr<mozilla::dom::SessionStoreChangeListener> mSessionStoreChangeListener;
|
||||
// Actor for collecting session store data from content children. This will be
|
||||
// cleared and set to null eagerly when taking down the frameloader to break
|
||||
// refcounted cycles early.
|
||||
RefPtr<mozilla::dom::SessionStoreChild> mSessionStoreChild;
|
||||
|
||||
nsCString mRemoteType;
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// object contains either a CollectedFileListValue or a CollectedNonMultipleSelectValue or Sequence<DOMString>
|
||||
typedef (DOMString or boolean or object) FormDataValue;
|
||||
|
||||
[ChromeOnly, Exposed=Window]
|
||||
interface SessionStoreFormData {
|
||||
[Cached, Pure]
|
||||
readonly attribute ByteString? url;
|
||||
|
||||
[Cached, Pure]
|
||||
readonly attribute record<DOMString, FormDataValue>? id;
|
||||
|
||||
[Cached, Pure]
|
||||
readonly attribute record<DOMString, FormDataValue>? xpath;
|
||||
|
||||
[Cached, Pure]
|
||||
readonly attribute DOMString? innerHTML;
|
||||
|
||||
[Cached, Frozen, Pure]
|
||||
readonly attribute sequence<SessionStoreFormData?>? children;
|
||||
|
||||
object toJSON();
|
||||
};
|
||||
|
||||
[ChromeOnly, Exposed=Window]
|
||||
interface SessionStoreScrollData {
|
||||
[Cached, Pure]
|
||||
readonly attribute ByteString? scroll;
|
||||
|
||||
[Cached, Pure]
|
||||
readonly attribute sequence<SessionStoreScrollData?>? children;
|
||||
|
||||
object toJSON();
|
||||
};
|
||||
|
||||
[GenerateConversionToJS]
|
||||
dictionary UpdateSessionStoreData {
|
||||
// This is docshell caps, but on-disk format uses the disallow property name.
|
||||
ByteString? disallow;
|
||||
boolean isPrivate;
|
||||
SessionStoreFormData? formdata;
|
||||
SessionStoreScrollData? scroll;
|
||||
};
|
|
@ -167,28 +167,3 @@ dictionary InputElementData {
|
|||
sequence<DOMString> strVal;
|
||||
sequence<boolean> boolVal;
|
||||
};
|
||||
|
||||
[GenerateConversionToJS]
|
||||
dictionary UpdateSessionStoreData {
|
||||
ByteString docShellCaps;
|
||||
boolean isPrivate;
|
||||
};
|
||||
|
||||
[GenerateConversionToJS]
|
||||
dictionary SessionStoreWindowStateChange {
|
||||
SessionStoreFormData formdata;
|
||||
SessionStoreScroll scroll;
|
||||
boolean hasChildren;
|
||||
required sequence<unsigned long> path;
|
||||
};
|
||||
|
||||
dictionary SessionStoreFormData {
|
||||
ByteString url;
|
||||
record<DOMString, CollectedFormDataValue> id;
|
||||
record<DOMString, CollectedFormDataValue> xpath;
|
||||
DOMString innerHTML;
|
||||
};
|
||||
|
||||
dictionary SessionStoreScroll {
|
||||
ByteString scroll;
|
||||
};
|
||||
|
|
|
@ -37,6 +37,7 @@ PREPROCESSED_WEBIDL_FILES = [
|
|||
]
|
||||
|
||||
WEBIDL_FILES = [
|
||||
"BrowserSessionStore.webidl",
|
||||
"BrowsingContext.webidl",
|
||||
"ChannelWrapper.webidl",
|
||||
"ClonedErrorHolder.webidl",
|
||||
|
|
|
@ -362,7 +362,9 @@ GetStructuredCloneReadInfoFromBlob(const uint8_t* aBlobData,
|
|||
&uncompressedLength)),
|
||||
Err(NS_ERROR_FILE_CORRUPTED));
|
||||
|
||||
AutoTArray<uint8_t, 512> uncompressed;
|
||||
// `data` (JSStructuredCloneData) currently uses 4k buffer internally.
|
||||
// For performance reasons, it's better to align `uncompressed` with that.
|
||||
AutoTArray<uint8_t, 4096> uncompressed;
|
||||
QM_TRY(OkIf(uncompressed.SetLength(uncompressedLength, fallible)),
|
||||
Err(NS_ERROR_OUT_OF_MEMORY));
|
||||
|
||||
|
|
|
@ -69,10 +69,8 @@
|
|||
#include "mozilla/dom/PBrowser.h"
|
||||
#include "mozilla/dom/PaymentRequestChild.h"
|
||||
#include "mozilla/dom/PointerEventHandler.h"
|
||||
#include "mozilla/dom/SessionStoreChangeListener.h"
|
||||
#include "mozilla/dom/SessionStoreDataCollector.h"
|
||||
#include "mozilla/dom/SessionStoreListener.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/SessionStoreChild.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "mozilla/dom/WindowProxyHolder.h"
|
||||
#include "mozilla/gfx/CrossProcessPaint.h"
|
||||
|
@ -522,12 +520,7 @@ nsresult BrowserChild::Init(mozIDOMWindowProxy* aParent,
|
|||
mIPCOpen = true;
|
||||
|
||||
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
|
||||
mSessionStoreListener = new TabListener(docShell, nullptr);
|
||||
rv = mSessionStoreListener->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSessionStoreChangeListener =
|
||||
SessionStoreChangeListener::Create(mBrowsingContext);
|
||||
mSessionStoreChild = SessionStoreChild::GetOrCreate(mBrowsingContext);
|
||||
}
|
||||
|
||||
// We've all set up, make sure our visibility state is consistent. This is
|
||||
|
@ -545,8 +538,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowserChild)
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusFilter)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebNav)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStoreListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStoreChangeListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStoreChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
@ -555,8 +547,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowserChild)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusFilter)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebNav)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStoreListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStoreChangeListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStoreChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(BrowserChild)
|
||||
|
@ -849,14 +840,9 @@ void BrowserChild::DestroyWindow() {
|
|||
mCoalescedTouchMoveEventFlusher = nullptr;
|
||||
}
|
||||
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->RemoveListeners();
|
||||
mSessionStoreListener = nullptr;
|
||||
}
|
||||
|
||||
if (mSessionStoreChangeListener) {
|
||||
mSessionStoreChangeListener->Stop();
|
||||
mSessionStoreChangeListener = nullptr;
|
||||
if (mSessionStoreChild) {
|
||||
mSessionStoreChild->Stop();
|
||||
mSessionStoreChild = nullptr;
|
||||
}
|
||||
|
||||
// In case we don't have chance to process all entries, clean all data in
|
||||
|
@ -2060,16 +2046,9 @@ mozilla::ipc::IPCResult BrowserChild::RecvNativeSynthesisResponse(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserChild::RecvUpdateEpoch(const uint32_t& aEpoch) {
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->SetEpoch(aEpoch);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserChild::RecvUpdateSHistory() {
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->UpdateSHistoryChanges();
|
||||
if (mSessionStoreChild) {
|
||||
mSessionStoreChild->UpdateSHistoryChanges();
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
@ -3809,26 +3788,10 @@ nsresult BrowserChild::PrepareProgressListenerData(
|
|||
return PrepareRequestData(aRequest, aRequestData);
|
||||
}
|
||||
|
||||
bool BrowserChild::UpdateSessionStore() {
|
||||
if (!mSessionStoreListener) {
|
||||
return false;
|
||||
void BrowserChild::UpdateSessionStore() {
|
||||
if (mSessionStoreChild) {
|
||||
mSessionStoreChild->UpdateSessionStore();
|
||||
}
|
||||
RefPtr<ContentSessionStore> store = mSessionStoreListener->GetSessionStore();
|
||||
|
||||
Maybe<nsCString> docShellCaps;
|
||||
if (store->IsDocCapChanged()) {
|
||||
docShellCaps.emplace(store->GetDocShellCaps());
|
||||
}
|
||||
|
||||
Maybe<bool> privatedMode;
|
||||
if (store->IsPrivateChanged()) {
|
||||
privatedMode.emplace(store->GetPrivateModeEnabled());
|
||||
}
|
||||
|
||||
Unused << SendSessionStoreUpdate(docShellCaps, privatedMode,
|
||||
store->GetAndClearSHistoryChanged(),
|
||||
mSessionStoreListener->GetEpoch());
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
|
|
@ -86,9 +86,7 @@ class TabGroup;
|
|||
class ClonedMessageData;
|
||||
class CoalescedMouseData;
|
||||
class CoalescedWheelData;
|
||||
class ContentSessionStore;
|
||||
class SessionStoreChangeListener;
|
||||
class TabListener;
|
||||
class SessionStoreChild;
|
||||
class RequestData;
|
||||
class WebProgressData;
|
||||
|
||||
|
@ -396,8 +394,6 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
aApzResponse);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateEpoch(const uint32_t& aEpoch);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateSHistory();
|
||||
|
||||
mozilla::ipc::IPCResult RecvNativeSynthesisResponse(
|
||||
|
@ -673,7 +669,11 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
mCancelContentJSEpoch = aEpoch;
|
||||
}
|
||||
|
||||
bool UpdateSessionStore();
|
||||
void UpdateSessionStore();
|
||||
|
||||
mozilla::dom::SessionStoreChild* GetSessionStoreChild() {
|
||||
return mSessionStoreChild;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Check if the window this BrowserChild is associated with supports
|
||||
|
@ -892,8 +892,7 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
RefPtr<CoalescedTouchMoveFlusher> mCoalescedTouchMoveEventFlusher;
|
||||
|
||||
RefPtr<layers::IAPZCTreeManager> mApzcTreeManager;
|
||||
RefPtr<TabListener> mSessionStoreListener;
|
||||
RefPtr<SessionStoreChangeListener> mSessionStoreChangeListener;
|
||||
RefPtr<SessionStoreChild> mSessionStoreChild;
|
||||
|
||||
// The most recently seen layer observer epoch in RecvSetDocShellIsActive.
|
||||
layers::LayersObserverEpoch mLayersObserverEpoch;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#endif
|
||||
#include "mozilla/Components.h"
|
||||
#include "mozilla/dom/BrowserHost.h"
|
||||
#include "mozilla/dom/BrowserSessionStore.h"
|
||||
#include "mozilla/dom/BrowsingContextGroup.h"
|
||||
#include "mozilla/dom/CancelContentJSOptionsBinding.h"
|
||||
#include "mozilla/dom/ChromeMessageSender.h"
|
||||
|
@ -32,8 +33,7 @@
|
|||
#include "mozilla/dom/RemoteDragStartData.h"
|
||||
#include "mozilla/dom/RemoteWebProgressRequest.h"
|
||||
#include "mozilla/dom/SessionHistoryEntry.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/SessionStoreUtilsBinding.h"
|
||||
#include "mozilla/dom/SessionStoreParent.h"
|
||||
#include "mozilla/dom/UserActivation.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
@ -53,6 +53,7 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/ProcessHangMonitor.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/StaticPrefs_accessibility.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include "mozilla/TextEventDispatcher.h"
|
||||
|
@ -128,7 +129,6 @@
|
|||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/ProfilerLabels.h"
|
||||
#include "MMPrinter.h"
|
||||
#include "SessionStoreFunctions.h"
|
||||
#include "mozilla/dom/CrashReport.h"
|
||||
#include "nsISecureBrowserUI.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
|
@ -1372,6 +1372,17 @@ IPCResult BrowserParent::RecvIndexedDBPermissionRequest(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
already_AddRefed<PSessionStoreParent>
|
||||
BrowserParent::AllocPSessionStoreParent() {
|
||||
RefPtr<BrowserSessionStore> sessionStore =
|
||||
BrowserSessionStore::GetOrCreate(mBrowsingContext->Top());
|
||||
if (!sessionStore) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return do_AddRef(new SessionStoreParent(mBrowsingContext, sessionStore));
|
||||
}
|
||||
|
||||
IPCResult BrowserParent::RecvNewWindowGlobal(
|
||||
ManagedEndpoint<PWindowGlobalParent>&& aEndpoint,
|
||||
const WindowGlobalInit& aInit) {
|
||||
|
@ -3008,41 +3019,6 @@ BrowserParent::BrowsingContextForWebProgress(
|
|||
return browsingContext.forget();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserParent::RecvSessionStoreUpdate(
|
||||
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
|
||||
const bool aNeedCollectSHistory, const uint32_t& aEpoch) {
|
||||
UpdateSessionStoreData data;
|
||||
if (aDocShellCaps.isSome()) {
|
||||
data.mDocShellCaps.Construct() = aDocShellCaps.value();
|
||||
}
|
||||
if (aPrivatedMode.isSome()) {
|
||||
data.mIsPrivate.Construct() = aPrivatedMode.value();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISessionStoreFunctions> funcs = do_ImportModule(
|
||||
"resource://gre/modules/SessionStoreFunctions.jsm", fallible);
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(funcs);
|
||||
NS_ENSURE_TRUE(wrapped, IPC_OK());
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(wrapped->GetJSObjectGlobal())) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> update(jsapi.cx());
|
||||
if (!ToJSValue(jsapi.cx(), data, &update)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
JS::RootedValue key(jsapi.cx(),
|
||||
mBrowsingContext->Canonical()->Top()->PermanentKey());
|
||||
|
||||
Unused << funcs->UpdateSessionStore(mFrameElement, mBrowsingContext, key,
|
||||
aEpoch, aNeedCollectSHistory, update);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserParent::RecvIntrinsicSizeOrRatioChanged(
|
||||
const Maybe<IntrinsicSize>& aIntrinsicSize,
|
||||
const Maybe<AspectRatio>& aIntrinsicRatio) {
|
||||
|
|
|
@ -317,10 +317,6 @@ class BrowserParent final : public PBrowserParent,
|
|||
already_AddRefed<CanonicalBrowsingContext> BrowsingContextForWebProgress(
|
||||
const WebProgressData& aWebProgressData);
|
||||
|
||||
mozilla::ipc::IPCResult RecvSessionStoreUpdate(
|
||||
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
|
||||
const bool aNeedCollectSHistory, const uint32_t& aEpoch);
|
||||
|
||||
mozilla::ipc::IPCResult RecvIntrinsicSizeOrRatioChanged(
|
||||
const Maybe<IntrinsicSize>& aIntrinsicSize,
|
||||
const Maybe<AspectRatio>& aIntrinsicRatio);
|
||||
|
@ -445,6 +441,8 @@ class BrowserParent final : public PBrowserParent,
|
|||
const IAccessibleHolder& aDocCOMProxy) override;
|
||||
#endif
|
||||
|
||||
already_AddRefed<PSessionStoreParent> AllocPSessionStoreParent();
|
||||
|
||||
mozilla::ipc::IPCResult RecvNewWindowGlobal(
|
||||
ManagedEndpoint<PWindowGlobalParent>&& aEndpoint,
|
||||
const WindowGlobalInit& aInit);
|
||||
|
|
|
@ -4524,25 +4524,6 @@ mozilla::ipc::IPCResult ContentChild::RecvInitNextGenLocalStorageEnabled(
|
|||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvFlushTabState(
|
||||
const MaybeDiscarded<BrowsingContext>& aContext,
|
||||
FlushTabStateResolver&& aResolver) {
|
||||
if (aContext.IsNullOrDiscarded()) {
|
||||
aResolver(false);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (auto* docShell = nsDocShell::Cast(aContext->GetDocShell())) {
|
||||
docShell->CollectWireframe();
|
||||
}
|
||||
|
||||
aContext->FlushSessionStore();
|
||||
|
||||
aResolver(true);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvGoBack(
|
||||
const MaybeDiscarded<BrowsingContext>& aContext,
|
||||
const Maybe<int32_t>& aCancelContentJSEpoch, bool aRequireUserInteraction,
|
||||
|
|
|
@ -812,10 +812,6 @@ class ContentChild final : public PContentChild,
|
|||
const MaybeDiscarded<BrowsingContext>& aStartingAt,
|
||||
DispatchBeforeUnloadToSubtreeResolver&& aResolver);
|
||||
|
||||
mozilla::ipc::IPCResult RecvFlushTabState(
|
||||
const MaybeDiscarded<BrowsingContext>& aContext,
|
||||
FlushTabStateResolver&& aResolver);
|
||||
|
||||
mozilla::ipc::IPCResult RecvDecoderSupportedMimeTypes(
|
||||
nsTArray<nsCString>&& aSupportedTypes);
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ include protocol PParentToChildStream;
|
|||
include protocol PFileDescriptorSet;
|
||||
include protocol PRemoteLazyInputStream;
|
||||
include protocol PPaymentRequest;
|
||||
include protocol PSessionStore;
|
||||
include protocol PWindowGlobal;
|
||||
include protocol PBrowserBridge;
|
||||
include protocol PVsync;
|
||||
|
@ -190,6 +191,7 @@ struct PrintPreviewResultInfo
|
|||
|
||||
manages PFilePicker;
|
||||
manages PPaymentRequest;
|
||||
manages PSessionStore;
|
||||
manages PWindowGlobal;
|
||||
manages PBrowserBridge;
|
||||
manages PVsync;
|
||||
|
@ -575,9 +577,6 @@ parent:
|
|||
|
||||
async NavigationFinished();
|
||||
|
||||
async SessionStoreUpdate(nsCString? aDocShellCaps, bool? aPrivatedMode,
|
||||
bool aNeedCollectSHistory, uint32_t aEpoch);
|
||||
|
||||
async IntrinsicSizeOrRatioChanged(IntrinsicSize? aIntrinsicSize,
|
||||
AspectRatio? aIntrinsicRatio);
|
||||
|
||||
|
@ -595,7 +594,6 @@ parent:
|
|||
|
||||
child:
|
||||
async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
|
||||
async UpdateEpoch(uint32_t aEpoch);
|
||||
async UpdateSHistory();
|
||||
async CloneDocumentTreeIntoSelf(MaybeDiscardedBrowsingContext aBc, PrintData aPrintData) returns(bool aSuccess);
|
||||
async UpdateRemotePrintSettings(PrintData aPrintData);
|
||||
|
@ -1016,6 +1014,9 @@ parent:
|
|||
/** Fetches the visited status for an array of URIs (Android-only). */
|
||||
async QueryVisitedState(nsIURI[] aURIs);
|
||||
|
||||
/** Create a session store for a browser child. */
|
||||
async PSessionStore();
|
||||
|
||||
/**
|
||||
* Construct a new WindowGlobal for an existing global in the content process
|
||||
*/
|
||||
|
|
|
@ -1027,9 +1027,6 @@ child:
|
|||
// Update the cached list of codec supported in the given process.
|
||||
async UpdateMediaCodecsSupported(RemoteDecodeIn aLocation, MediaCodecsSupported aSupported);
|
||||
|
||||
async FlushTabState(MaybeDiscardedBrowsingContext aBrowsingContext)
|
||||
returns(bool aHadContext);
|
||||
|
||||
// Send the list of the supported mimetypes in the given process. GeckoView-specific
|
||||
async DecoderSupportedMimeTypes(nsCString[] supportedTypes);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PExtensions;
|
||||
include protocol PSessionStore;
|
||||
include protocol PWindowGlobal;
|
||||
|
||||
include DOMTypes;
|
||||
|
@ -23,6 +24,7 @@ namespace dom {
|
|||
async protocol PInProcess
|
||||
{
|
||||
manages PExtensions;
|
||||
manages PSessionStore;
|
||||
manages PWindowGlobal;
|
||||
};
|
||||
|
||||
|
|
|
@ -180,11 +180,6 @@ parent:
|
|||
|
||||
async RequestRestoreTabContent();
|
||||
|
||||
async UpdateSessionStore(FormData? aFormData, nsPoint? aScrollPosition,
|
||||
uint32_t aEpoch);
|
||||
|
||||
async ResetSessionStore(uint32_t aEpoch);
|
||||
|
||||
// Add the flags in aOnFlags to the current BFCache status and remove the
|
||||
// flags in aOffFlags from the current BFCache status. See the BFCacheStatus
|
||||
// enum for the valid flags.
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/SecurityPolicyViolationEvent.h"
|
||||
#include "mozilla/dom/SessionStoreRestoreData.h"
|
||||
#include "mozilla/dom/SessionStoreDataCollector.h"
|
||||
#include "mozilla/dom/WindowGlobalActorsBinding.h"
|
||||
#include "mozilla/dom/WindowContext.h"
|
||||
#include "mozilla/dom/InProcessChild.h"
|
||||
|
@ -327,11 +326,6 @@ void WindowGlobalChild::Destroy() {
|
|||
if (!browserChild || !browserChild->IsDestroyed()) {
|
||||
SendDestroy();
|
||||
}
|
||||
|
||||
if (mSessionStoreDataCollector) {
|
||||
mSessionStoreDataCollector->Cancel();
|
||||
mSessionStoreDataCollector = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult WindowGlobalChild::RecvMakeFrameLocal(
|
||||
|
@ -703,20 +697,9 @@ nsISupports* WindowGlobalChild::GetParentObject() {
|
|||
return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
|
||||
}
|
||||
|
||||
void WindowGlobalChild::SetSessionStoreDataCollector(
|
||||
SessionStoreDataCollector* aCollector) {
|
||||
mSessionStoreDataCollector = aCollector;
|
||||
}
|
||||
|
||||
SessionStoreDataCollector* WindowGlobalChild::GetSessionStoreDataCollector()
|
||||
const {
|
||||
return mSessionStoreDataCollector;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_WEAK_PTR(WindowGlobalChild, mWindowGlobal,
|
||||
mContainerFeaturePolicy,
|
||||
mWindowContext,
|
||||
mSessionStoreDataCollector)
|
||||
mWindowContext)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowGlobalChild)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
|
|
|
@ -28,7 +28,6 @@ class WindowGlobalParent;
|
|||
class JSWindowActorChild;
|
||||
class JSActorMessageMeta;
|
||||
class BrowserChild;
|
||||
class SessionStoreDataCollector;
|
||||
|
||||
/**
|
||||
* Actor for a single nsGlobalWindowInner. This actor is used to communicate
|
||||
|
@ -133,9 +132,6 @@ class WindowGlobalChild final : public WindowGlobalActor,
|
|||
return mContainerFeaturePolicy;
|
||||
}
|
||||
|
||||
void SetSessionStoreDataCollector(SessionStoreDataCollector* aCollector);
|
||||
SessionStoreDataCollector* GetSessionStoreDataCollector() const;
|
||||
|
||||
void UnblockBFCacheFor(BFCacheStatus aStatus);
|
||||
void BlockBFCacheFor(BFCacheStatus aStatus);
|
||||
|
||||
|
@ -205,7 +201,6 @@ class WindowGlobalChild final : public WindowGlobalActor,
|
|||
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
|
||||
RefPtr<dom::FeaturePolicy> mContainerFeaturePolicy;
|
||||
nsCOMPtr<nsIURI> mDocumentURI;
|
||||
RefPtr<SessionStoreDataCollector> mSessionStoreDataCollector;
|
||||
int64_t mBeforeUnloadListeners = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -26,9 +26,6 @@
|
|||
#include "mozilla/dom/ChromeUtils.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/dom/ipc/StructuredCloneData.h"
|
||||
#include "mozilla/dom/sessionstore/SessionStoreTypes.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/SessionStoreUtilsBinding.h"
|
||||
#include "mozilla/Components.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/ServoCSSParser.h"
|
||||
|
@ -535,16 +532,6 @@ const nsACString& WindowGlobalParent::GetRemoteType() {
|
|||
return NOT_REMOTE_TYPE;
|
||||
}
|
||||
|
||||
static nsCString PointToString(const nsPoint& aPoint) {
|
||||
int scrollX = nsPresContext::AppUnitsToIntCSSPixels(aPoint.x);
|
||||
int scrollY = nsPresContext::AppUnitsToIntCSSPixels(aPoint.y);
|
||||
if ((scrollX != 0) || (scrollY != 0)) {
|
||||
return nsPrintfCString("%d,%d", scrollX, scrollY);
|
||||
}
|
||||
|
||||
return ""_ns;
|
||||
}
|
||||
|
||||
void WindowGlobalParent::NotifyContentBlockingEvent(
|
||||
uint32_t aEvent, nsIRequest* aRequest, bool aBlocked,
|
||||
const nsACString& aTrackingOrigin,
|
||||
|
@ -1166,44 +1153,6 @@ void WindowGlobalParent::FinishAccumulatingPageUseCounters() {
|
|||
mPageUseCounters = nullptr;
|
||||
}
|
||||
|
||||
static void GetFormData(JSContext* aCx, const sessionstore::FormData& aFormData,
|
||||
nsIURI* aDocumentURI, SessionStoreFormData& aUpdate) {
|
||||
if (!aFormData.hasData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool parseSessionData = false;
|
||||
if (aDocumentURI) {
|
||||
nsCString& url = aUpdate.mUrl.Construct();
|
||||
aDocumentURI->GetSpecIgnoringRef(url);
|
||||
// We want to avoid saving data for about:sessionrestore as a string.
|
||||
// Since it's stored in the form as stringified JSON, stringifying
|
||||
// further causes an explosion of escape characters. cf. bug 467409
|
||||
parseSessionData =
|
||||
url == "about:sessionrestore"_ns || url == "about:welcomeback"_ns;
|
||||
}
|
||||
|
||||
if (!aFormData.innerHTML().IsEmpty()) {
|
||||
aUpdate.mInnerHTML.Construct(aFormData.innerHTML());
|
||||
}
|
||||
|
||||
if (!aFormData.id().IsEmpty()) {
|
||||
auto& id = aUpdate.mId.Construct();
|
||||
if (NS_FAILED(SessionStoreUtils::ConstructFormDataValues(
|
||||
aCx, aFormData.id(), id.Entries(), parseSessionData))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!aFormData.xpath().IsEmpty()) {
|
||||
auto& xpath = aUpdate.mXpath.Construct();
|
||||
if (NS_FAILED(SessionStoreUtils::ConstructFormDataValues(
|
||||
aCx, aFormData.xpath(), xpath.Entries()))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Element* WindowGlobalParent::GetRootOwnerElement() {
|
||||
WindowGlobalParent* top = TopWindowContext();
|
||||
if (!top) {
|
||||
|
@ -1221,104 +1170,6 @@ Element* WindowGlobalParent::GetRootOwnerElement() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult WindowGlobalParent::WriteFormDataAndScrollToSessionStore(
|
||||
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
|
||||
uint32_t aEpoch) {
|
||||
if (!aFormData && !aScrollPosition) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<CanonicalBrowsingContext> context = BrowsingContext();
|
||||
if (!context) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISessionStoreFunctions> funcs = do_ImportModule(
|
||||
"resource://gre/modules/SessionStoreFunctions.jsm", fallible);
|
||||
if (!funcs) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(funcs);
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(wrapped->GetJSObjectGlobal())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RootedDictionary<SessionStoreWindowStateChange> windowState(jsapi.cx());
|
||||
|
||||
if (aFormData) {
|
||||
GetFormData(jsapi.cx(), *aFormData, mDocumentURI,
|
||||
windowState.mFormdata.Construct());
|
||||
}
|
||||
|
||||
if (aScrollPosition) {
|
||||
auto& update = windowState.mScroll.Construct();
|
||||
if (*aScrollPosition != nsPoint(0, 0)) {
|
||||
update.mScroll.Construct() = PointToString(*aScrollPosition);
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray<uint32_t> path;
|
||||
if (!context->GetOffsetPath(path)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
windowState.mPath = std::move(path);
|
||||
windowState.mHasChildren.Construct() = !context->Children().IsEmpty();
|
||||
|
||||
JS::RootedValue update(jsapi.cx());
|
||||
if (!ToJSValue(jsapi.cx(), windowState, &update)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JS::RootedValue key(jsapi.cx(), context->Top()->PermanentKey());
|
||||
|
||||
return funcs->UpdateSessionStoreForWindow(GetRootOwnerElement(), context, key,
|
||||
aEpoch, update);
|
||||
}
|
||||
|
||||
nsresult WindowGlobalParent::ResetSessionStore(uint32_t aEpoch) {
|
||||
RefPtr<CanonicalBrowsingContext> context = BrowsingContext();
|
||||
if (!context) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISessionStoreFunctions> funcs = do_ImportModule(
|
||||
"resource://gre/modules/SessionStoreFunctions.jsm", fallible);
|
||||
if (!funcs) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(funcs);
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(wrapped->GetJSObjectGlobal())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RootedDictionary<SessionStoreWindowStateChange> windowState(jsapi.cx());
|
||||
|
||||
nsTArray<uint32_t> path;
|
||||
if (!context->GetOffsetPath(path)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
windowState.mPath = std::move(path);
|
||||
windowState.mHasChildren.Construct() = false;
|
||||
windowState.mFormdata.Construct();
|
||||
windowState.mScroll.Construct();
|
||||
|
||||
JS::RootedValue update(jsapi.cx());
|
||||
if (!ToJSValue(jsapi.cx(), windowState, &update)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JS::RootedValue key(jsapi.cx(), context->Top()->PermanentKey());
|
||||
|
||||
return funcs->UpdateSessionStoreForWindow(GetRootOwnerElement(), context, key,
|
||||
aEpoch, update);
|
||||
}
|
||||
|
||||
void WindowGlobalParent::NotifySessionStoreUpdatesComplete(Element* aEmbedder) {
|
||||
if (!aEmbedder) {
|
||||
aEmbedder = GetRootOwnerElement();
|
||||
|
@ -1331,27 +1182,6 @@ void WindowGlobalParent::NotifySessionStoreUpdatesComplete(Element* aEmbedder) {
|
|||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult WindowGlobalParent::RecvUpdateSessionStore(
|
||||
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
|
||||
uint32_t aEpoch) {
|
||||
if (NS_FAILED(WriteFormDataAndScrollToSessionStore(aFormData, aScrollPosition,
|
||||
aEpoch))) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Failed to update session store entry."));
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult WindowGlobalParent::RecvResetSessionStore(
|
||||
uint32_t aEpoch) {
|
||||
if (NS_FAILED(ResetSessionStore(aEpoch))) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Failed to reset session store entry."));
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult WindowGlobalParent::RecvRequestRestoreTabContent() {
|
||||
CanonicalBrowsingContext* bc = BrowsingContext();
|
||||
if (bc && bc->AncestorsAreCurrent()) {
|
||||
|
|
|
@ -80,7 +80,7 @@ class WindowGlobalParent final : public WindowContext,
|
|||
WindowGlobalParent* TopWindowContext() {
|
||||
return static_cast<WindowGlobalParent*>(WindowContext::TopWindowContext());
|
||||
}
|
||||
CanonicalBrowsingContext* GetBrowsingContext() {
|
||||
CanonicalBrowsingContext* GetBrowsingContext() const {
|
||||
return CanonicalBrowsingContext::Cast(WindowContext::GetBrowsingContext());
|
||||
}
|
||||
|
||||
|
@ -214,10 +214,6 @@ class WindowGlobalParent final : public WindowContext,
|
|||
|
||||
const nsACString& GetRemoteType() override;
|
||||
|
||||
nsresult WriteFormDataAndScrollToSessionStore(
|
||||
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
|
||||
uint32_t aEpoch);
|
||||
|
||||
void NotifySessionStoreUpdatesComplete(Element* aEmbedder);
|
||||
|
||||
Maybe<uint64_t> GetSingleChannelId() { return mSingleChannelId; }
|
||||
|
@ -288,12 +284,6 @@ class WindowGlobalParent final : public WindowContext,
|
|||
|
||||
mozilla::ipc::IPCResult RecvRequestRestoreTabContent();
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateSessionStore(
|
||||
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
|
||||
uint32_t aEpoch);
|
||||
|
||||
mozilla::ipc::IPCResult RecvResetSessionStore(uint32_t aEpoch);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateBFCacheStatus(const uint32_t& aOnFlags,
|
||||
const uint32_t& aOffFlags);
|
||||
|
||||
|
@ -320,8 +310,6 @@ class WindowGlobalParent final : public WindowContext,
|
|||
bool ShouldTrackSiteOriginTelemetry();
|
||||
void FinishAccumulatingPageUseCounters();
|
||||
|
||||
nsresult ResetSessionStore(uint32_t aEpoch);
|
||||
|
||||
// Returns failure if the new storage principal cannot be validated
|
||||
// against the current document principle.
|
||||
nsresult SetDocumentStoragePrincipal(
|
||||
|
|
|
@ -132,11 +132,13 @@ static HRESULT GetDirectWriteFaceName(IDWriteFont* aFont,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
void gfxDWriteFontFamily::FindStyleVariations(FontInfoData* aFontInfoData) {
|
||||
void gfxDWriteFontFamily::FindStyleVariationsLocked(
|
||||
FontInfoData* aFontInfoData) {
|
||||
HRESULT hr;
|
||||
if (mHasStyles) {
|
||||
return;
|
||||
}
|
||||
|
||||
mHasStyles = true;
|
||||
|
||||
gfxPlatformFontList* fp = gfxPlatformFontList::PlatformFontList();
|
||||
|
@ -188,7 +190,7 @@ void gfxDWriteFontFamily::FindStyleVariations(FontInfoData* aFontInfoData) {
|
|||
|
||||
fe->SetupVariationRanges();
|
||||
|
||||
AddFontEntry(fe);
|
||||
AddFontEntryLocked(fe);
|
||||
|
||||
// postscript/fullname if needed
|
||||
nsAutoCString psname, fullname;
|
||||
|
@ -1839,7 +1841,7 @@ void gfxDWriteFontList::GetFontsFromCollection(
|
|||
// if this fails/doesn't exist, we'll have used name index 0,
|
||||
// so that's the one we'll want to skip here
|
||||
names->FindLocaleName(L"en-us", &englishIdx, &exists);
|
||||
|
||||
AutoTArray<nsCString, 4> otherFamilyNames;
|
||||
for (nameIndex = 0; nameIndex < nameCount; nameIndex++) {
|
||||
UINT32 nameLen;
|
||||
AutoTArray<WCHAR, 32> localizedName;
|
||||
|
@ -1866,9 +1868,12 @@ void gfxDWriteFontList::GetFontsFromCollection(
|
|||
NS_ConvertUTF16toUTF8 locName(localizedName.Elements());
|
||||
|
||||
if (!familyName.Equals(locName)) {
|
||||
AddOtherFamilyName(fam, locName);
|
||||
otherFamilyNames.AppendElement(locName);
|
||||
}
|
||||
}
|
||||
if (!otherFamilyNames.IsEmpty()) {
|
||||
AddOtherFamilyNames(fam, otherFamilyNames);
|
||||
}
|
||||
}
|
||||
|
||||
// at this point, all family names have been read in
|
||||
|
@ -2010,7 +2015,7 @@ void gfxDWriteFontList::GetDirectWriteSubstitutes() {
|
|||
}
|
||||
}
|
||||
|
||||
bool gfxDWriteFontList::FindAndAddFamilies(
|
||||
bool gfxDWriteFontList::FindAndAddFamiliesLocked(
|
||||
nsPresContext* aPresContext, StyleGenericFontFamily aGeneric,
|
||||
const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
|
||||
FindFamiliesFlags aFlags, gfxFontStyle* aStyle, nsAtom* aLanguage,
|
||||
|
@ -2037,7 +2042,7 @@ bool gfxDWriteFontList::FindAndAddFamilies(
|
|||
return false;
|
||||
}
|
||||
|
||||
return gfxPlatformFontList::FindAndAddFamilies(
|
||||
return gfxPlatformFontList::FindAndAddFamiliesLocked(
|
||||
aPresContext, aGeneric, keyName, aOutput, aFlags, aStyle, aLanguage,
|
||||
aDevToCssSize);
|
||||
}
|
||||
|
@ -2046,6 +2051,8 @@ void gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
|||
FontListSizes* aSizes) const {
|
||||
gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
||||
|
||||
AutoLock lock(mLock);
|
||||
|
||||
// We are a singleton, so include the font loader singleton's memory.
|
||||
MOZ_ASSERT(static_cast<const gfxPlatformFontList*>(this) ==
|
||||
gfxPlatformFontList::PlatformFontList());
|
||||
|
|
|
@ -63,7 +63,7 @@ class gfxDWriteFontFamily final : public gfxFontFamily {
|
|||
mForceGDIClassic(false) {}
|
||||
virtual ~gfxDWriteFontFamily();
|
||||
|
||||
void FindStyleVariations(FontInfoData* aFontInfoData = nullptr) final;
|
||||
void FindStyleVariationsLocked(FontInfoData* aFontInfoData = nullptr) final;
|
||||
|
||||
void LocalizedName(nsACString& aLocalizedName) final;
|
||||
|
||||
|
@ -194,7 +194,7 @@ class gfxDWriteFontEntry final : public gfxFontEntry {
|
|||
|
||||
hb_blob_t* GetFontTable(uint32_t aTableTag) override;
|
||||
|
||||
nsresult ReadCMAP(FontInfoData* aFontInfoData = nullptr);
|
||||
nsresult ReadCMAP(FontInfoData* aFontInfoData = nullptr) override;
|
||||
|
||||
bool IsCJKFont();
|
||||
|
||||
|
@ -387,7 +387,8 @@ class gfxDWriteFontList final : public gfxPlatformFontList {
|
|||
const mozilla::fontlist::Family* aFamily) override;
|
||||
|
||||
void ReadFaceNamesForFamily(mozilla::fontlist::Family* aFamily,
|
||||
bool aNeedFullnamePostscriptNames) override;
|
||||
bool aNeedFullnamePostscriptNames)
|
||||
REQUIRES(mLock) override;
|
||||
|
||||
bool ReadFaceNames(mozilla::fontlist::Family* aFamily,
|
||||
mozilla::fontlist::Face* aFace, nsCString& aPSName,
|
||||
|
@ -414,7 +415,7 @@ class gfxDWriteFontList final : public gfxPlatformFontList {
|
|||
IDWriteGdiInterop* GetGDIInterop() { return mGDIInterop; }
|
||||
bool UseGDIFontTableAccess() const;
|
||||
|
||||
bool FindAndAddFamilies(
|
||||
bool FindAndAddFamiliesLocked(
|
||||
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGeneric,
|
||||
const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
|
||||
FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr,
|
||||
|
|
|
@ -618,6 +618,7 @@ void FT2FontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
|||
*/
|
||||
|
||||
void FT2FontFamily::AddFacesToFontList(nsTArray<FontListEntry>* aFontList) {
|
||||
AutoReadLock lock(mLock);
|
||||
for (int i = 0, n = mAvailableFonts.Length(); i < n; ++i) {
|
||||
const FT2FontEntry* fe =
|
||||
static_cast<const FT2FontEntry*>(mAvailableFonts[i].get());
|
||||
|
@ -1168,7 +1169,9 @@ void gfxFT2FontList::AppendFacesFromFontFile(const nsCString& aFileName,
|
|||
CollectFunc unshared =
|
||||
[](const FontListEntry& aFLE, const nsCString& aPSName,
|
||||
const nsCString& aFullName, StandardFile aStdFile) {
|
||||
PlatformFontList()->AppendFaceFromFontListEntry(aFLE, aStdFile);
|
||||
auto* pfl = PlatformFontList();
|
||||
pfl->mLock.AssertCurrentThreadIn();
|
||||
pfl->AppendFaceFromFontListEntry(aFLE, aStdFile);
|
||||
};
|
||||
CollectFunc shared = [](const FontListEntry& aFLE, const nsCString& aPSName,
|
||||
const nsCString& aFullName, StandardFile aStdFile) {
|
||||
|
@ -1339,7 +1342,9 @@ void gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
|
|||
CollectFunc unshared =
|
||||
[](const FontListEntry& aFLE, const nsCString& aPSName,
|
||||
const nsCString& aFullName, StandardFile aStdFile) {
|
||||
PlatformFontList()->AppendFaceFromFontListEntry(aFLE, aStdFile);
|
||||
auto* pfl = PlatformFontList();
|
||||
pfl->mLock.AssertCurrentThreadIn();
|
||||
pfl->AppendFaceFromFontListEntry(aFLE, aStdFile);
|
||||
};
|
||||
CollectFunc shared = [](const FontListEntry& aFLE,
|
||||
const nsCString& aPSName,
|
||||
|
@ -1382,17 +1387,15 @@ void gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
|
|||
// Called on each family after all fonts are added to the list;
|
||||
// if aSortFaces is true this will sort faces to give priority to "standard"
|
||||
// font files.
|
||||
static void FinalizeFamilyMemberList(nsCStringHashKey::KeyType aKey,
|
||||
const RefPtr<gfxFontFamily>& aFamily,
|
||||
bool aSortFaces) {
|
||||
gfxFontFamily* family = aFamily.get();
|
||||
void FT2FontFamily::FinalizeMemberList(bool aSortFaces) {
|
||||
AutoWriteLock lock(mLock);
|
||||
|
||||
family->SetHasStyles(true);
|
||||
SetHasStyles(true);
|
||||
|
||||
if (aSortFaces) {
|
||||
family->SortAvailableFonts();
|
||||
SortAvailableFonts();
|
||||
}
|
||||
family->CheckForSimpleFamily();
|
||||
CheckForSimpleFamily();
|
||||
}
|
||||
|
||||
void gfxFT2FontList::FindFonts() {
|
||||
|
@ -1640,6 +1643,7 @@ void gfxFT2FontList::AppendFaceFromFontListEntry(const FontListEntry& aFLE,
|
|||
}
|
||||
|
||||
void gfxFT2FontList::ReadSystemFontList(dom::SystemFontList* aList) {
|
||||
AutoLock lock(mLock);
|
||||
for (const auto& entry : mFontFamilies) {
|
||||
auto family = static_cast<FT2FontFamily*>(entry.GetData().get());
|
||||
family->AddFacesToFontList(&aList->entries());
|
||||
|
@ -1669,9 +1673,8 @@ nsresult gfxFT2FontList::InitFontListForPlatform() {
|
|||
// Finalize the families by sorting faces into standard order
|
||||
// and marking "simple" families.
|
||||
for (const auto& entry : mFontFamilies) {
|
||||
nsCStringHashKey::KeyType key = entry.GetKey();
|
||||
const RefPtr<gfxFontFamily>& family = entry.GetData();
|
||||
FinalizeFamilyMemberList(key, family, /* aSortFaces */ true);
|
||||
auto* family = static_cast<FT2FontFamily*>(entry.GetData().get());
|
||||
family->FinalizeMemberList(/* aSortFaces */ true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1689,9 +1692,8 @@ nsresult gfxFT2FontList::InitFontListForPlatform() {
|
|||
// We don't need to sort faces (because they were already sorted by the
|
||||
// chrome process, so we just maintain the existing order)
|
||||
for (const auto& entry : mFontFamilies) {
|
||||
nsCStringHashKey::KeyType key = entry.GetKey();
|
||||
const RefPtr<gfxFontFamily>& family = entry.GetData();
|
||||
FinalizeFamilyMemberList(key, family, /* aSortFaces */ false);
|
||||
auto* family = static_cast<FT2FontFamily*>(entry.GetData().get());
|
||||
family->FinalizeMemberList(/* aSortFaces */ false);
|
||||
}
|
||||
|
||||
LOG(("got font list from chrome process: %" PRIdPTR " faces in %" PRIu32
|
||||
|
@ -1747,10 +1749,13 @@ gfxFontEntry* gfxFT2FontList::LookupLocalFont(nsPresContext* aPresContext,
|
|||
WeightRange aWeightForEntry,
|
||||
StretchRange aStretchForEntry,
|
||||
SlantStyleRange aStyleForEntry) {
|
||||
AutoLock lock(mLock);
|
||||
|
||||
if (SharedFontList()) {
|
||||
return LookupInSharedFaceNameList(aPresContext, aFontName, aWeightForEntry,
|
||||
aStretchForEntry, aStyleForEntry);
|
||||
}
|
||||
|
||||
// walk over list of names
|
||||
FT2FontEntry* fontEntry = nullptr;
|
||||
FontVisibility level =
|
||||
|
|
|
@ -128,6 +128,8 @@ class FT2FontFamily final : public gfxFontFamily {
|
|||
|
||||
// Append this family's faces to the IPC fontlist
|
||||
void AddFacesToFontList(nsTArray<FontListEntry>* aFontList);
|
||||
|
||||
void FinalizeMemberList(bool aSortFaces);
|
||||
};
|
||||
|
||||
class gfxFT2FontList final : public gfxPlatformFontList {
|
||||
|
@ -172,23 +174,26 @@ class gfxFT2FontList final : public gfxPlatformFontList {
|
|||
typedef enum { kUnknown, kStandard } StandardFile;
|
||||
|
||||
// initialize font lists
|
||||
nsresult InitFontListForPlatform() override;
|
||||
nsresult InitFontListForPlatform() REQUIRES(mLock) override;
|
||||
|
||||
void AppendFaceFromFontListEntry(const FontListEntry& aFLE,
|
||||
StandardFile aStdFile);
|
||||
StandardFile aStdFile) REQUIRES(mLock);
|
||||
|
||||
void AppendFacesFromBlob(const nsCString& aFileName, StandardFile aStdFile,
|
||||
hb_blob_t* aBlob, FontNameCache* aCache,
|
||||
uint32_t aTimestamp, uint32_t aFilesize);
|
||||
uint32_t aTimestamp, uint32_t aFilesize)
|
||||
REQUIRES(mLock);
|
||||
|
||||
void AppendFacesFromFontFile(const nsCString& aFileName,
|
||||
FontNameCache* aCache, StandardFile aStdFile);
|
||||
FontNameCache* aCache, StandardFile aStdFile)
|
||||
REQUIRES(mLock);
|
||||
|
||||
void AppendFacesFromOmnijarEntry(nsZipArchive* aReader,
|
||||
const nsCString& aEntryName,
|
||||
FontNameCache* aCache, bool aJarChanged);
|
||||
FontNameCache* aCache, bool aJarChanged)
|
||||
REQUIRES(mLock);
|
||||
|
||||
void InitSharedFontListForPlatform() override;
|
||||
void InitSharedFontListForPlatform() REQUIRES(mLock) override;
|
||||
void CollectInitData(const FontListEntry& aFLE, const nsCString& aPSName,
|
||||
const nsCString& aFullName, StandardFile aStdFile);
|
||||
|
||||
|
@ -212,21 +217,23 @@ class gfxFT2FontList final : public gfxPlatformFontList {
|
|||
bool AppendFacesFromCachedFaceList(CollectFunc aCollectFace,
|
||||
const nsCString& aFileName,
|
||||
const nsCString& aFaceList,
|
||||
StandardFile aStdFile);
|
||||
StandardFile aStdFile) REQUIRES(mLock);
|
||||
|
||||
void AddFaceToList(const nsCString& aEntryName, uint32_t aIndex,
|
||||
StandardFile aStdFile, hb_face_t* aFace,
|
||||
nsCString& aFaceList);
|
||||
nsCString& aFaceList) REQUIRES(mLock);
|
||||
|
||||
void FindFonts();
|
||||
void FindFonts() REQUIRES(mLock);
|
||||
|
||||
void FindFontsInOmnijar(FontNameCache* aCache);
|
||||
void FindFontsInOmnijar(FontNameCache* aCache) REQUIRES(mLock);
|
||||
|
||||
void FindFontsInDir(const nsCString& aDir, FontNameCache* aFNC);
|
||||
void FindFontsInDir(const nsCString& aDir, FontNameCache* aFNC)
|
||||
REQUIRES(mLock);
|
||||
|
||||
FontFamily GetDefaultFontForPlatform(nsPresContext* aPresContext,
|
||||
const gfxFontStyle* aStyle,
|
||||
nsAtom* aLanguage = nullptr) override;
|
||||
nsAtom* aLanguage = nullptr)
|
||||
REQUIRES(mLock) override;
|
||||
|
||||
nsTHashSet<nsCString> mSkipSpaceLookupCheckFamilies;
|
||||
|
||||
|
|
|
@ -1015,7 +1015,8 @@ nsresult gfxFontconfigFontEntry::CopyFontTable(uint32_t aTableTag,
|
|||
return gfxFT2FontEntryBase::CopyFaceTable(GetFTFace(), aTableTag, aBuffer);
|
||||
}
|
||||
|
||||
void gfxFontconfigFontFamily::FindStyleVariations(FontInfoData* aFontInfoData) {
|
||||
void gfxFontconfigFontFamily::FindStyleVariationsLocked(
|
||||
FontInfoData* aFontInfoData) {
|
||||
if (mHasStyles) {
|
||||
return;
|
||||
}
|
||||
|
@ -1039,7 +1040,7 @@ void gfxFontconfigFontFamily::FindStyleVariations(FontInfoData* aFontInfoData) {
|
|||
fontEntry->SetupVariationRanges();
|
||||
}
|
||||
|
||||
AddFontEntry(fontEntry);
|
||||
AddFontEntryLocked(fontEntry);
|
||||
|
||||
if (fontEntry->IsNormalStyle()) {
|
||||
numRegularFaces++;
|
||||
|
@ -1226,6 +1227,7 @@ bool gfxFontconfigFontFamily::SupportsLangGroup(nsAtom* aLangGroup) const {
|
|||
// will contain the font entries, each of which holds a reference to its
|
||||
// pattern. We only check the first pattern in each list, because support
|
||||
// for langs is considered to be consistent across all faces in a family.
|
||||
AutoReadLock lock(mLock);
|
||||
FcPattern* fontPattern;
|
||||
if (mFontPatterns.Length()) {
|
||||
fontPattern = mFontPatterns[0];
|
||||
|
@ -1248,6 +1250,7 @@ gfxFontconfigFontFamily::~gfxFontconfigFontFamily() {
|
|||
|
||||
template <typename Func>
|
||||
void gfxFontconfigFontFamily::AddFacesToFontList(Func aAddPatternFunc) {
|
||||
AutoReadLock lock(mLock);
|
||||
if (HasStyles()) {
|
||||
for (auto& fe : mAvailableFonts) {
|
||||
if (!fe) {
|
||||
|
@ -1431,14 +1434,17 @@ void gfxFcPlatformFontList::AddPatternToFontList(
|
|||
// will usually not match
|
||||
FcChar8* otherName;
|
||||
int n = (cIndex == 0 ? 1 : 0);
|
||||
AutoTArray<nsCString, 4> otherFamilyNames;
|
||||
while (FcPatternGetString(aFont, FC_FAMILY, n, &otherName) == FcResultMatch) {
|
||||
nsAutoCString otherFamilyName(ToCharPtr(otherName));
|
||||
AddOtherFamilyName(aFontFamily, otherFamilyName);
|
||||
otherFamilyNames.AppendElement(nsCString(ToCharPtr(otherName)));
|
||||
n++;
|
||||
if (n == int(cIndex)) {
|
||||
n++; // skip over canonical name
|
||||
}
|
||||
}
|
||||
if (!otherFamilyNames.IsEmpty()) {
|
||||
AddOtherFamilyNames(aFontFamily, otherFamilyNames);
|
||||
}
|
||||
|
||||
const bool singleName = n == 1;
|
||||
|
||||
|
@ -1576,6 +1582,8 @@ nsresult gfxFcPlatformFontList::InitFontListForPlatform() {
|
|||
}
|
||||
|
||||
void gfxFcPlatformFontList::ReadSystemFontList(dom::SystemFontList* retValue) {
|
||||
AutoLock lock(mLock);
|
||||
|
||||
// Fontconfig versions below 2.9 drop the FC_FILE element in FcNameUnparse
|
||||
// (see https://bugs.freedesktop.org/show_bug.cgi?id=26718), so when using
|
||||
// an older version, we manually append it to the unparsed pattern.
|
||||
|
@ -2039,6 +2047,8 @@ gfxFontEntry* gfxFcPlatformFontList::LookupLocalFont(
|
|||
nsPresContext* aPresContext, const nsACString& aFontName,
|
||||
WeightRange aWeightForEntry, StretchRange aStretchForEntry,
|
||||
SlantStyleRange aStyleForEntry) {
|
||||
AutoLock lock(mLock);
|
||||
|
||||
nsAutoCString keyName(aFontName);
|
||||
ToLowerCase(keyName);
|
||||
|
||||
|
@ -2071,7 +2081,7 @@ gfxFontEntry* gfxFcPlatformFontList::MakePlatformFont(
|
|||
std::move(face));
|
||||
}
|
||||
|
||||
bool gfxFcPlatformFontList::FindAndAddFamilies(
|
||||
bool gfxFcPlatformFontList::FindAndAddFamiliesLocked(
|
||||
nsPresContext* aPresContext, StyleGenericFontFamily aGeneric,
|
||||
const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
|
||||
FindFamiliesFlags aFlags, gfxFontStyle* aStyle, nsAtom* aLanguage,
|
||||
|
@ -2184,7 +2194,7 @@ bool gfxFcPlatformFontList::FindAndAddFamilies(
|
|||
if (terminator && FcStrCmp(substName, terminator) == 0) {
|
||||
break;
|
||||
}
|
||||
gfxPlatformFontList::FindAndAddFamilies(
|
||||
gfxPlatformFontList::FindAndAddFamiliesLocked(
|
||||
aPresContext, aGeneric, nsDependentCString(ToCharPtr(substName)),
|
||||
&cachedFamilies, aFlags, aStyle, aLanguage);
|
||||
}
|
||||
|
@ -2340,6 +2350,7 @@ void gfxFcPlatformFontList::AddGenericFonts(
|
|||
}
|
||||
}
|
||||
|
||||
AutoLock lock(mLock);
|
||||
PrefFontList* prefFonts =
|
||||
FindGenericFamilies(aPresContext, genericToLookup, aLanguage);
|
||||
NS_ASSERTION(prefFonts, "null generic font list");
|
||||
|
@ -2349,9 +2360,9 @@ void gfxFcPlatformFontList::AddGenericFonts(
|
|||
}
|
||||
}
|
||||
|
||||
void gfxFcPlatformFontList::ClearLangGroupPrefFonts() {
|
||||
ClearGenericMappings();
|
||||
gfxPlatformFontList::ClearLangGroupPrefFonts();
|
||||
void gfxFcPlatformFontList::ClearLangGroupPrefFontsLocked() {
|
||||
ClearGenericMappingsLocked();
|
||||
gfxPlatformFontList::ClearLangGroupPrefFontsLocked();
|
||||
mAlwaysUseFontconfigGenerics = PrefFontListsUseOnlyGenerics();
|
||||
}
|
||||
|
||||
|
@ -2411,9 +2422,10 @@ gfxPlatformFontList::PrefFontList* gfxFcPlatformFontList::FindGenericFamilies(
|
|||
|
||||
FcPatternGetString(font, FC_FAMILY, 0, &mappedGeneric);
|
||||
if (mappedGeneric) {
|
||||
mLock.AssertCurrentThreadIn();
|
||||
nsAutoCString mappedGenericName(ToCharPtr(mappedGeneric));
|
||||
AutoTArray<FamilyAndGeneric, 1> genericFamilies;
|
||||
if (gfxPlatformFontList::FindAndAddFamilies(
|
||||
if (gfxPlatformFontList::FindAndAddFamiliesLocked(
|
||||
aPresContext, StyleGenericFontFamily::None,
|
||||
mappedGenericName, &genericFamilies,
|
||||
FindFamiliesFlags(0))) {
|
||||
|
|
|
@ -175,7 +175,8 @@ class gfxFontconfigFontFamily final : public gfxFontFamily {
|
|||
template <typename Func>
|
||||
void AddFacesToFontList(Func aAddPatternFunc);
|
||||
|
||||
void FindStyleVariations(FontInfoData* aFontInfoData = nullptr) override;
|
||||
void FindStyleVariationsLocked(FontInfoData* aFontInfoData = nullptr)
|
||||
REQUIRES(mLock) override;
|
||||
|
||||
// Families are constructed initially with just references to patterns.
|
||||
// When necessary, these are enumerated within FindStyleVariations.
|
||||
|
@ -244,8 +245,8 @@ class gfxFcPlatformFontList final : public gfxPlatformFontList {
|
|||
}
|
||||
|
||||
// initialize font lists
|
||||
nsresult InitFontListForPlatform() override;
|
||||
void InitSharedFontListForPlatform() override;
|
||||
nsresult InitFontListForPlatform() REQUIRES(mLock) override;
|
||||
void InitSharedFontListForPlatform() REQUIRES(mLock) override;
|
||||
|
||||
void GetFontList(nsAtom* aLangGroup, const nsACString& aGenericFamily,
|
||||
nsTArray<nsString>& aListOfFonts) override;
|
||||
|
@ -269,11 +270,12 @@ class gfxFcPlatformFontList final : public gfxPlatformFontList {
|
|||
const uint8_t* aFontData,
|
||||
uint32_t aLength) override;
|
||||
|
||||
bool FindAndAddFamilies(
|
||||
bool FindAndAddFamiliesLocked(
|
||||
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGeneric,
|
||||
const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
|
||||
FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr,
|
||||
nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0) override;
|
||||
nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0)
|
||||
REQUIRES(mLock) override;
|
||||
|
||||
bool GetStandardFamilyName(const nsCString& aFontName,
|
||||
nsACString& aFamilyName) override;
|
||||
|
@ -285,10 +287,16 @@ class gfxFcPlatformFontList final : public gfxPlatformFontList {
|
|||
mozilla::StyleGenericFontFamily, nsAtom* aLanguage,
|
||||
nsTArray<FamilyAndGeneric>& aFamilyList) override;
|
||||
|
||||
void ClearLangGroupPrefFonts() override;
|
||||
void ClearLangGroupPrefFontsLocked() REQUIRES(mLock) override;
|
||||
|
||||
// clear out cached generic-lang ==> family-list mappings
|
||||
void ClearGenericMappings() { mGenericMappings.Clear(); }
|
||||
void ClearGenericMappings() {
|
||||
AutoLock lock(mLock);
|
||||
ClearGenericMappingsLocked();
|
||||
}
|
||||
void ClearGenericMappingsLocked() REQUIRES(mLock) {
|
||||
mGenericMappings.Clear();
|
||||
}
|
||||
|
||||
// map lang group ==> lang string
|
||||
// When aForFontEnumerationThread is true, this method will avoid using
|
||||
|
@ -310,28 +318,29 @@ class gfxFcPlatformFontList final : public gfxPlatformFontList {
|
|||
// Add all the font families found in a font set.
|
||||
// aAppFonts indicates whether this is the system or application fontset.
|
||||
void AddFontSetFamilies(FcFontSet* aFontSet, const SandboxPolicy* aPolicy,
|
||||
bool aAppFonts);
|
||||
bool aAppFonts) REQUIRES(mLock);
|
||||
|
||||
// Helper for above, to add a single font pattern.
|
||||
void AddPatternToFontList(FcPattern* aFont, FcChar8*& aLastFamilyName,
|
||||
nsACString& aFamilyName,
|
||||
RefPtr<gfxFontconfigFontFamily>& aFontFamily,
|
||||
bool aAppFonts);
|
||||
bool aAppFonts) REQUIRES(mLock);
|
||||
|
||||
// figure out which families fontconfig maps a generic to
|
||||
// (aGeneric assumed already lowercase)
|
||||
PrefFontList* FindGenericFamilies(nsPresContext* aPresContext,
|
||||
const nsCString& aGeneric,
|
||||
nsAtom* aLanguage);
|
||||
nsAtom* aLanguage) REQUIRES(mLock);
|
||||
|
||||
// are all pref font settings set to use fontconfig generics?
|
||||
bool PrefFontListsUseOnlyGenerics();
|
||||
bool PrefFontListsUseOnlyGenerics() REQUIRES(mLock);
|
||||
|
||||
static void CheckFontUpdates(nsITimer* aTimer, void* aThis);
|
||||
|
||||
FontFamily GetDefaultFontForPlatform(nsPresContext* aPresContext,
|
||||
const gfxFontStyle* aStyle,
|
||||
nsAtom* aLanguage = nullptr) override;
|
||||
nsAtom* aLanguage = nullptr)
|
||||
REQUIRES(mLock) override;
|
||||
|
||||
enum class DistroID : int8_t {
|
||||
Unknown = 0,
|
||||
|
|
|
@ -234,7 +234,7 @@ bool gfxFontCache::HashEntry::KeyEquals(const KeyTypePointer aKey) const {
|
|||
gfxFont* gfxFontCache::Lookup(const gfxFontEntry* aFontEntry,
|
||||
const gfxFontStyle* aStyle,
|
||||
const gfxCharacterMap* aUnicodeRangeMap) {
|
||||
AutoReadLock lock(mCacheLock);
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
Key key(aFontEntry, aStyle, aUnicodeRangeMap);
|
||||
HashEntry* entry = mFonts.GetEntry(key);
|
||||
|
@ -247,7 +247,7 @@ gfxFont* gfxFontCache::Lookup(const gfxFontEntry* aFontEntry,
|
|||
void gfxFontCache::AddNew(gfxFont* aFont) {
|
||||
gfxFont* oldFont;
|
||||
{
|
||||
AutoWriteLock lock(mCacheLock);
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
Key key(aFont->GetFontEntry(), aFont->GetStyle(),
|
||||
aFont->GetUnicodeRangeMap());
|
||||
|
@ -287,7 +287,7 @@ void gfxFontCache::NotifyReleased(gfxFont* aFont) {
|
|||
void gfxFontCache::NotifyExpiredLocked(gfxFont* aFont, const AutoLock& aLock) {
|
||||
aFont->ClearCachedWords();
|
||||
RemoveObjectLocked(aFont, aLock);
|
||||
DestroyFont(aFont);
|
||||
DestroyFontLocked(aFont);
|
||||
}
|
||||
|
||||
void gfxFontCache::NotifyExpired(gfxFont* aFont) {
|
||||
|
@ -296,14 +296,29 @@ void gfxFontCache::NotifyExpired(gfxFont* aFont) {
|
|||
DestroyFont(aFont);
|
||||
}
|
||||
|
||||
void gfxFontCache::DestroyFont(gfxFont* aFont) {
|
||||
AutoWriteLock lock(mCacheLock);
|
||||
void gfxFontCache::DestroyFontLocked(gfxFont* aFont) {
|
||||
Key key(aFont->GetFontEntry(), aFont->GetStyle(),
|
||||
aFont->GetUnicodeRangeMap());
|
||||
HashEntry* entry = mFonts.GetEntry(key);
|
||||
if (entry && entry->mFont == aFont) {
|
||||
mFonts.RemoveEntry(entry);
|
||||
}
|
||||
NS_ASSERTION(aFont->GetRefCount() == 0,
|
||||
"Destroying with non-zero ref count!");
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
delete aFont;
|
||||
}
|
||||
|
||||
void gfxFontCache::DestroyFont(gfxFont* aFont) {
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
Key key(aFont->GetFontEntry(), aFont->GetStyle(),
|
||||
aFont->GetUnicodeRangeMap());
|
||||
HashEntry* entry = mFonts.GetEntry(key);
|
||||
if (entry && entry->mFont == aFont) {
|
||||
mFonts.RemoveEntry(entry);
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(aFont->GetRefCount() == 0,
|
||||
"Destroying with non-zero ref count!");
|
||||
delete aFont;
|
||||
|
@ -319,7 +334,7 @@ void gfxFontCache::WordCacheExpirationTimerCallback(nsITimer* aTimer,
|
|||
void gfxFontCache::AgeCachedWords() {
|
||||
bool allEmpty = true;
|
||||
{
|
||||
AutoReadLock lock(mCacheLock);
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (const auto& entry : mFonts) {
|
||||
allEmpty = entry.mFont->AgeCachedWords() && allEmpty;
|
||||
}
|
||||
|
@ -331,7 +346,7 @@ void gfxFontCache::AgeCachedWords() {
|
|||
|
||||
void gfxFontCache::FlushShapedWordCaches() {
|
||||
{
|
||||
AutoReadLock lock(mCacheLock);
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (const auto& entry : mFonts) {
|
||||
entry.mFont->ClearCachedWords();
|
||||
}
|
||||
|
@ -340,7 +355,7 @@ void gfxFontCache::FlushShapedWordCaches() {
|
|||
}
|
||||
|
||||
void gfxFontCache::NotifyGlyphsChanged() {
|
||||
AutoReadLock lock(mCacheLock);
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (const auto& entry : mFonts) {
|
||||
entry.mFont->NotifyGlyphsChanged();
|
||||
}
|
||||
|
@ -350,7 +365,7 @@ void gfxFontCache::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
|||
FontCacheSizes* aSizes) const {
|
||||
// TODO: add the overhead of the expiration tracker (generation arrays)
|
||||
|
||||
AutoReadLock lock(mCacheLock);
|
||||
MutexAutoLock lock(*const_cast<Mutex*>(&mMutex));
|
||||
aSizes->mFontInstances += mFonts.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
for (const auto& entry : mFonts) {
|
||||
entry.mFont->AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
||||
|
|
|
@ -348,7 +348,7 @@ class gfxFontCache final
|
|||
// into the expiration queues and removed.
|
||||
void Flush() {
|
||||
{
|
||||
mozilla::AutoWriteLock lock(mCacheLock);
|
||||
mozilla::MutexAutoLock lock(mMutex);
|
||||
mFonts.Clear();
|
||||
}
|
||||
AgeAllGenerations();
|
||||
|
@ -361,7 +361,7 @@ class gfxFontCache final
|
|||
|
||||
void RunWordCacheExpirationTimer() {
|
||||
if (!mTimerRunning) {
|
||||
mozilla::AutoWriteLock lock(mCacheLock);
|
||||
mozilla::MutexAutoLock lock(mMutex);
|
||||
if (!mTimerRunning && mWordCacheExpirationTimer) {
|
||||
mWordCacheExpirationTimer->InitWithNamedFuncCallback(
|
||||
WordCacheExpirationTimerCallback, this,
|
||||
|
@ -373,7 +373,7 @@ class gfxFontCache final
|
|||
}
|
||||
void PauseWordCacheExpirationTimer() {
|
||||
if (mTimerRunning) {
|
||||
mozilla::AutoWriteLock lock(mCacheLock);
|
||||
mozilla::MutexAutoLock lock(mMutex);
|
||||
if (mTimerRunning && mWordCacheExpirationTimer) {
|
||||
mWordCacheExpirationTimer->Cancel();
|
||||
mTimerRunning = false;
|
||||
|
@ -396,13 +396,7 @@ class gfxFontCache final
|
|||
RemoveObjectLocked(aFont, lock);
|
||||
}
|
||||
|
||||
mozilla::RWLock& GetCacheLock() { return mCacheLock; }
|
||||
|
||||
protected:
|
||||
// Guards the global font hashtable, separately from the expiration-tracker
|
||||
// records.
|
||||
mutable mozilla::RWLock mCacheLock = mozilla::RWLock("fontCacheLock");
|
||||
|
||||
class MemoryReporter final : public nsIMemoryReporter {
|
||||
~MemoryReporter() = default;
|
||||
|
||||
|
@ -427,10 +421,12 @@ class gfxFontCache final
|
|||
|
||||
// This gets called when the timeout has expired on a zero-refcount
|
||||
// font; we just delete it.
|
||||
void NotifyExpiredLocked(gfxFont* aFont, const AutoLock&) override;
|
||||
void NotifyExpiredLocked(gfxFont* aFont, const AutoLock&)
|
||||
REQUIRES(mMutex) override;
|
||||
void NotifyExpired(gfxFont* aFont);
|
||||
|
||||
void DestroyFont(gfxFont* aFont);
|
||||
void DestroyFontLocked(gfxFont* aFont) REQUIRES(mMutex);
|
||||
|
||||
static gfxFontCache* gGlobalCache;
|
||||
|
||||
|
@ -469,11 +465,11 @@ class gfxFontCache final
|
|||
gfxFont* MOZ_UNSAFE_REF("tracking for deferred deletion") mFont;
|
||||
};
|
||||
|
||||
nsTHashtable<HashEntry> mFonts GUARDED_BY(mCacheLock);
|
||||
nsTHashtable<HashEntry> mFonts GUARDED_BY(mMutex);
|
||||
|
||||
static void WordCacheExpirationTimerCallback(nsITimer* aTimer, void* aCache);
|
||||
|
||||
nsCOMPtr<nsITimer> mWordCacheExpirationTimer GUARDED_BY(mCacheLock);
|
||||
nsCOMPtr<nsITimer> mWordCacheExpirationTimer GUARDED_BY(mMutex);
|
||||
std::atomic<bool> mTimerRunning = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -56,9 +56,8 @@ using namespace mozilla::unicode;
|
|||
using mozilla::services::GetObserverService;
|
||||
|
||||
void gfxCharacterMap::NotifyReleased() {
|
||||
gfxPlatformFontList* fontlist = gfxPlatformFontList::PlatformFontList();
|
||||
if (mShared) {
|
||||
fontlist->RemoveCmap(this);
|
||||
gfxPlatformFontList::PlatformFontList()->RemoveCmap(this);
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
|
@ -1541,12 +1540,14 @@ class FontEntryStandardFaceComparator {
|
|||
};
|
||||
|
||||
void gfxFontFamily::SortAvailableFonts() {
|
||||
MOZ_ASSERT(mLock.LockedForWritingByCurrentThread());
|
||||
mAvailableFonts.Sort(FontEntryStandardFaceComparator());
|
||||
}
|
||||
|
||||
bool gfxFontFamily::HasOtherFamilyNames() {
|
||||
// need to read in other family names to determine this
|
||||
if (!mOtherFamilyNamesInitialized) {
|
||||
AutoWriteLock lock(mLock);
|
||||
ReadOtherFamilyNames(
|
||||
gfxPlatformFontList::PlatformFontList()); // sets mHasOtherFamilyNames
|
||||
}
|
||||
|
@ -1588,9 +1589,12 @@ void gfxFontFamily::FindAllFontsForStyle(
|
|||
const gfxFontStyle& aFontStyle, nsTArray<gfxFontEntry*>& aFontEntryList,
|
||||
bool aIgnoreSizeTolerance) {
|
||||
if (!mHasStyles) {
|
||||
FindStyleVariations(); // collect faces for the family, if not already done
|
||||
FindStyleVariations(); // collect faces for the family, if not already
|
||||
// done
|
||||
}
|
||||
|
||||
AutoReadLock lock(mLock);
|
||||
|
||||
NS_ASSERTION(mAvailableFonts.Length() > 0, "font family with no faces!");
|
||||
NS_ASSERTION(aFontEntryList.IsEmpty(), "non-empty fontlist passed in");
|
||||
|
||||
|
@ -1696,6 +1700,7 @@ void gfxFontFamily::FindAllFontsForStyle(
|
|||
}
|
||||
|
||||
void gfxFontFamily::CheckForSimpleFamily() {
|
||||
MOZ_ASSERT(mLock.LockedForWritingByCurrentThread());
|
||||
// already checked this family
|
||||
if (mIsSimpleFamily) {
|
||||
return;
|
||||
|
@ -1749,6 +1754,8 @@ void gfxFontFamily::CheckForSimpleFamily() {
|
|||
|
||||
#ifdef DEBUG
|
||||
bool gfxFontFamily::ContainsFace(gfxFontEntry* aFontEntry) {
|
||||
AutoReadLock lock(mLock);
|
||||
|
||||
uint32_t i, numFonts = mAvailableFonts.Length();
|
||||
for (i = 0; i < numFonts; i++) {
|
||||
if (mAvailableFonts[i] == aFontEntry) {
|
||||
|
@ -1773,10 +1780,15 @@ void gfxFontFamily::LocalizedName(nsACString& aLocalizedName) {
|
|||
}
|
||||
|
||||
void gfxFontFamily::FindFontForChar(GlobalFontMatch* aMatchData) {
|
||||
if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
|
||||
// none of the faces in the family support the required char,
|
||||
// so bail out immediately
|
||||
return;
|
||||
gfxPlatformFontList::PlatformFontList()->mLock.AssertCurrentThreadIn();
|
||||
|
||||
{
|
||||
AutoReadLock lock(mLock);
|
||||
if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
|
||||
// none of the faces in the family support the required char,
|
||||
// so bail out immediately
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsCString charAndName;
|
||||
|
@ -1866,6 +1878,7 @@ void gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch* aMatchData) {
|
|||
if (!mFamilyCharacterMapInitialized) {
|
||||
ReadAllCMAPs();
|
||||
}
|
||||
AutoReadLock lock(mLock);
|
||||
if (!mFamilyCharacterMap.test(aMatchData->mCh)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1914,20 +1927,27 @@ bool gfxFontFamily::ReadOtherFamilyNamesForFace(
|
|||
gfxFontUtils::ReadOtherFamilyNamesForFace(mName, nameData, dataLength,
|
||||
otherFamilyNames, useFullName);
|
||||
|
||||
uint32_t n = otherFamilyNames.Length();
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
|
||||
if (!otherFamilyNames.IsEmpty()) {
|
||||
aPlatformFontList->AddOtherFamilyNames(this, otherFamilyNames);
|
||||
}
|
||||
|
||||
return n != 0;
|
||||
return !otherFamilyNames.IsEmpty();
|
||||
}
|
||||
|
||||
void gfxFontFamily::ReadOtherFamilyNames(
|
||||
gfxPlatformFontList* aPlatformFontList) {
|
||||
if (mOtherFamilyNamesInitialized) return;
|
||||
if (mOtherFamilyNamesInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoWriteLock lock(mLock);
|
||||
if (mOtherFamilyNamesInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
mOtherFamilyNamesInitialized = true;
|
||||
|
||||
FindStyleVariations();
|
||||
FindStyleVariationsLocked();
|
||||
|
||||
// read in other family names for the first face in the list
|
||||
uint32_t i, numFonts = mAvailableFonts.Length();
|
||||
|
@ -1950,7 +1970,9 @@ void gfxFontFamily::ReadOtherFamilyNames(
|
|||
// read in other names for the first face in the list with the assumption
|
||||
// that if extra names don't exist in that face then they don't exist in
|
||||
// other faces for the same font
|
||||
if (!mHasOtherFamilyNames) return;
|
||||
if (!mHasOtherFamilyNames) {
|
||||
return;
|
||||
}
|
||||
|
||||
// read in names for all faces, needed to catch cases where fonts have
|
||||
// family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
|
||||
|
@ -2012,6 +2034,8 @@ bool gfxFontFamily::CheckForLegacyFamilyNames(gfxPlatformFontList* aFontList) {
|
|||
// we already did this, so there's nothing more to add
|
||||
return false;
|
||||
}
|
||||
aFontList->mLock.AssertCurrentThreadIn();
|
||||
AutoWriteLock lock(mLock);
|
||||
mCheckedForLegacyFamilyNames = true;
|
||||
bool added = false;
|
||||
const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
|
||||
|
@ -2041,22 +2065,23 @@ bool gfxFontFamily::CheckForLegacyFamilyNames(gfxPlatformFontList* aFontList) {
|
|||
void gfxFontFamily::ReadFaceNames(gfxPlatformFontList* aPlatformFontList,
|
||||
bool aNeedFullnamePostscriptNames,
|
||||
FontInfoData* aFontInfoData) {
|
||||
aPlatformFontList->mLock.AssertCurrentThreadIn();
|
||||
|
||||
// if all needed names have already been read, skip
|
||||
if (mOtherFamilyNamesInitialized &&
|
||||
(mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoWriteLock lock(mLock);
|
||||
|
||||
bool asyncFontLoaderDisabled = false;
|
||||
|
||||
if (!mOtherFamilyNamesInitialized && aFontInfoData &&
|
||||
aFontInfoData->mLoadOtherNames && !asyncFontLoaderDisabled) {
|
||||
const auto* otherFamilyNames = aFontInfoData->GetOtherFamilyNames(mName);
|
||||
if (otherFamilyNames) {
|
||||
uint32_t i, n = otherFamilyNames->Length();
|
||||
for (i = 0; i < n; i++) {
|
||||
aPlatformFontList->AddOtherFamilyName(this, (*otherFamilyNames)[i]);
|
||||
}
|
||||
if (otherFamilyNames && otherFamilyNames->Length()) {
|
||||
aPlatformFontList->AddOtherFamilyNames(this, *otherFamilyNames);
|
||||
}
|
||||
mOtherFamilyNamesInitialized = true;
|
||||
}
|
||||
|
@ -2067,7 +2092,7 @@ void gfxFontFamily::ReadFaceNames(gfxPlatformFontList* aPlatformFontList,
|
|||
return;
|
||||
}
|
||||
|
||||
FindStyleVariations(aFontInfoData);
|
||||
FindStyleVariationsLocked(aFontInfoData);
|
||||
|
||||
// check again, as style enumeration code may have loaded names
|
||||
if (mOtherFamilyNamesInitialized &&
|
||||
|
@ -2091,10 +2116,10 @@ void gfxFontFamily::ReadFaceNames(gfxPlatformFontList* aPlatformFontList,
|
|||
aFontInfoData && aFontInfoData->mLoadFaceNames) {
|
||||
aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
|
||||
if (!fullname.IsEmpty()) {
|
||||
aPlatformFontList->AddFullname(fe, fullname);
|
||||
aPlatformFontList->AddFullnameLocked(fe, fullname);
|
||||
}
|
||||
if (!psname.IsEmpty()) {
|
||||
aPlatformFontList->AddPostscriptName(fe, psname);
|
||||
aPlatformFontList->AddPostscriptNameLocked(fe, psname);
|
||||
}
|
||||
foundFaceNames = true;
|
||||
|
||||
|
@ -2113,12 +2138,12 @@ void gfxFontFamily::ReadFaceNames(gfxPlatformFontList* aPlatformFontList,
|
|||
if (aNeedFullnamePostscriptNames && !foundFaceNames) {
|
||||
if (gfxFontUtils::ReadCanonicalName(nameTable, gfxFontUtils::NAME_ID_FULL,
|
||||
fullname) == NS_OK) {
|
||||
aPlatformFontList->AddFullname(fe, fullname);
|
||||
aPlatformFontList->AddFullnameLocked(fe, fullname);
|
||||
}
|
||||
|
||||
if (gfxFontUtils::ReadCanonicalName(
|
||||
nameTable, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK) {
|
||||
aPlatformFontList->AddPostscriptName(fe, psname);
|
||||
aPlatformFontList->AddPostscriptNameLocked(fe, psname);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2147,16 +2172,20 @@ void gfxFontFamily::ReadFaceNames(gfxPlatformFontList* aPlatformFontList,
|
|||
|
||||
gfxFontEntry* gfxFontFamily::FindFont(const nsACString& aPostscriptName) {
|
||||
// find the font using a simple linear search
|
||||
AutoReadLock lock(mLock);
|
||||
uint32_t numFonts = mAvailableFonts.Length();
|
||||
for (uint32_t i = 0; i < numFonts; i++) {
|
||||
gfxFontEntry* fe = mAvailableFonts[i].get();
|
||||
if (fe && fe->Name() == aPostscriptName) return fe;
|
||||
if (fe && fe->Name() == aPostscriptName) {
|
||||
return fe;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void gfxFontFamily::ReadAllCMAPs(FontInfoData* aFontInfoData) {
|
||||
FindStyleVariations(aFontInfoData);
|
||||
AutoWriteLock lock(mLock);
|
||||
FindStyleVariationsLocked(aFontInfoData);
|
||||
|
||||
uint32_t i, numFonts = mAvailableFonts.Length();
|
||||
for (i = 0; i < numFonts; i++) {
|
||||
|
@ -2174,6 +2203,7 @@ void gfxFontFamily::ReadAllCMAPs(FontInfoData* aFontInfoData) {
|
|||
|
||||
void gfxFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
||||
FontListSizes* aSizes) const {
|
||||
AutoReadLock lock(mLock);
|
||||
aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
||||
aSizes->mCharMapsSize +=
|
||||
mFamilyCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
|
||||
|
|
|
@ -790,10 +790,8 @@ class gfxFontEntry {
|
|||
};
|
||||
|
||||
using FontTableCache = nsTHashtable<FontTableHashEntry>;
|
||||
mozilla::Atomic<FontTableCache*> mFontTableCache GUARDED_BY(mLock);
|
||||
FontTableCache* GetFontTableCache() const NO_THREAD_SAFETY_ANALYSIS {
|
||||
return mFontTableCache;
|
||||
}
|
||||
mozilla::Atomic<FontTableCache*> mFontTableCache;
|
||||
FontTableCache* GetFontTableCache() const { return mFontTableCache; }
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(gfxFontEntry::RangeFlags)
|
||||
|
@ -851,17 +849,12 @@ class gfxFontFamily {
|
|||
|
||||
gfxFontFamily(const nsACString& aName, FontVisibility aVisibility)
|
||||
: mName(aName),
|
||||
mLock("gfxFontFamily lock"),
|
||||
mVisibility(aVisibility),
|
||||
mOtherFamilyNamesInitialized(false),
|
||||
mHasOtherFamilyNames(false),
|
||||
mFaceNamesInitialized(false),
|
||||
mHasStyles(false),
|
||||
mIsSimpleFamily(false),
|
||||
mIsBadUnderlineFamily(false),
|
||||
mFamilyCharacterMapInitialized(false),
|
||||
mSkipDefaultFeatureSpaceCheck(false),
|
||||
mCheckForFallbackFaces(false),
|
||||
mCheckedForLegacyFamilyNames(false) {}
|
||||
mCheckForFallbackFaces(false) {}
|
||||
|
||||
const nsCString& Name() const { return mName; }
|
||||
|
||||
|
@ -874,11 +867,20 @@ class gfxFontFamily {
|
|||
// faces in a large family into separate "styled families" because of
|
||||
// GDI's 4-faces-per-family limitation). If found, the styled family
|
||||
// name will be added to the font list's "other family names" table.
|
||||
// Note that the caller must already hold the gfxPlatformFontList lock.
|
||||
bool CheckForLegacyFamilyNames(gfxPlatformFontList* aFontList);
|
||||
|
||||
nsTArray<RefPtr<gfxFontEntry>>& GetFontList() { return mAvailableFonts; }
|
||||
nsTArray<RefPtr<gfxFontEntry>>& GetFontList() {
|
||||
mozilla::AutoReadLock lock(mLock);
|
||||
return mAvailableFonts;
|
||||
}
|
||||
|
||||
void AddFontEntry(RefPtr<gfxFontEntry> aFontEntry) {
|
||||
mozilla::AutoWriteLock lock(mLock);
|
||||
AddFontEntryLocked(aFontEntry);
|
||||
}
|
||||
|
||||
void AddFontEntryLocked(RefPtr<gfxFontEntry> aFontEntry) REQUIRES(mLock) {
|
||||
// bug 589682 - set the IgnoreGDEF flag on entries for Italic faces
|
||||
// of Times New Roman, because of buggy table in those fonts
|
||||
if (aFontEntry->IsItalic() && !aFontEntry->IsUserFont() &&
|
||||
|
@ -916,8 +918,10 @@ class gfxFontFamily {
|
|||
nsTArray<gfxFontEntry*>& aFontEntryList,
|
||||
bool aIgnoreSizeTolerance = false);
|
||||
|
||||
// checks for a matching font within the family
|
||||
// used as part of the font fallback process
|
||||
// Checks for a matching font within the family; used as part of the font
|
||||
// fallback process.
|
||||
// Note that when this is called, the caller must already be holding the
|
||||
// gfxPlatformFontList lock.
|
||||
void FindFontForChar(GlobalFontMatch* aMatchData);
|
||||
|
||||
// checks all fonts for a matching font within the family
|
||||
|
@ -929,36 +933,51 @@ class gfxFontFamily {
|
|||
// set when other family names have been read in
|
||||
void SetOtherFamilyNamesInitialized() { mOtherFamilyNamesInitialized = true; }
|
||||
|
||||
// read in other localized family names, fullnames and Postscript names
|
||||
// for all faces and append to lookup tables
|
||||
// Read in other localized family names, fullnames and Postscript names
|
||||
// for all faces and append to lookup tables.
|
||||
// Note that when this is called, the caller must already be holding the
|
||||
// gfxPlatformFontList lock.
|
||||
virtual void ReadFaceNames(gfxPlatformFontList* aPlatformFontList,
|
||||
bool aNeedFullnamePostscriptNames,
|
||||
FontInfoData* aFontInfoData = nullptr);
|
||||
|
||||
// find faces belonging to this family (platform implementations override
|
||||
// this; should be made pure virtual once all subclasses have been updated)
|
||||
virtual void FindStyleVariations(FontInfoData* aFontInfoData = nullptr) {}
|
||||
// Find faces belonging to this family (platform implementations override).
|
||||
// This is a no-op in cases where the family is explicitly populated by other
|
||||
// means, rather than being asked to find its faces via system API.
|
||||
virtual void FindStyleVariationsLocked(FontInfoData* aFontInfoData = nullptr)
|
||||
REQUIRES(mLock){};
|
||||
void FindStyleVariations(FontInfoData* aFontInfoData = nullptr) {
|
||||
if (mHasStyles) {
|
||||
return;
|
||||
}
|
||||
mozilla::AutoWriteLock lock(mLock);
|
||||
FindStyleVariationsLocked(aFontInfoData);
|
||||
}
|
||||
|
||||
// search for a specific face using the Postscript name
|
||||
gfxFontEntry* FindFont(const nsACString& aPostscriptName);
|
||||
|
||||
// read in cmaps for all the faces
|
||||
// Read in cmaps for all the faces.
|
||||
// Note that when this is called, the caller must already be holding the
|
||||
// gfxPlatformFontList lock.
|
||||
void ReadAllCMAPs(FontInfoData* aFontInfoData = nullptr);
|
||||
|
||||
bool TestCharacterMap(uint32_t aCh) {
|
||||
if (!mFamilyCharacterMapInitialized) {
|
||||
ReadAllCMAPs();
|
||||
}
|
||||
mozilla::AutoReadLock lock(mLock);
|
||||
return mFamilyCharacterMap.test(aCh);
|
||||
}
|
||||
|
||||
void ResetCharacterMap() {
|
||||
void ResetCharacterMap() REQUIRES(mLock) {
|
||||
mFamilyCharacterMap.reset();
|
||||
mFamilyCharacterMapInitialized = false;
|
||||
}
|
||||
|
||||
// mark this family as being in the "bad" underline offset blocklist
|
||||
void SetBadUnderlineFamily() {
|
||||
mozilla::AutoWriteLock lock(mLock);
|
||||
mIsBadUnderlineFamily = true;
|
||||
if (mHasStyles) {
|
||||
SetBadUnderlineFonts();
|
||||
|
@ -971,12 +990,12 @@ class gfxFontFamily {
|
|||
bool CheckForFallbackFaces() const { return mCheckForFallbackFaces; }
|
||||
|
||||
// sort available fonts to put preferred (standard) faces towards the end
|
||||
void SortAvailableFonts();
|
||||
void SortAvailableFonts() REQUIRES(mLock);
|
||||
|
||||
// check whether the family fits into the simple 4-face model,
|
||||
// so we can use simplified style-matching;
|
||||
// if so set the mIsSimpleFamily flag (defaults to False before we've checked)
|
||||
void CheckForSimpleFamily();
|
||||
void CheckForSimpleFamily() REQUIRES(mLock);
|
||||
|
||||
// For memory reporter
|
||||
virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
|
@ -1019,31 +1038,33 @@ class gfxFontFamily {
|
|||
bool useFullName = false);
|
||||
|
||||
// set whether this font family is in "bad" underline offset blocklist.
|
||||
void SetBadUnderlineFonts() {
|
||||
uint32_t i, numFonts = mAvailableFonts.Length();
|
||||
for (i = 0; i < numFonts; i++) {
|
||||
if (mAvailableFonts[i]) {
|
||||
mAvailableFonts[i]->mIsBadUnderlineFont = true;
|
||||
void SetBadUnderlineFonts() REQUIRES(mLock) {
|
||||
for (auto& f : mAvailableFonts) {
|
||||
if (f) {
|
||||
f->mIsBadUnderlineFont = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsCString mName;
|
||||
nsTArray<RefPtr<gfxFontEntry>> mAvailableFonts;
|
||||
gfxSparseBitSet mFamilyCharacterMap;
|
||||
nsTArray<RefPtr<gfxFontEntry>> mAvailableFonts GUARDED_BY(mLock);
|
||||
gfxSparseBitSet mFamilyCharacterMap GUARDED_BY(mLock);
|
||||
|
||||
mutable mozilla::RWLock mLock;
|
||||
|
||||
FontVisibility mVisibility;
|
||||
|
||||
bool mOtherFamilyNamesInitialized : 1;
|
||||
bool mHasOtherFamilyNames : 1;
|
||||
bool mFaceNamesInitialized : 1;
|
||||
bool mHasStyles : 1;
|
||||
bool mIsSimpleFamily : 1;
|
||||
mozilla::Atomic<bool> mOtherFamilyNamesInitialized;
|
||||
mozilla::Atomic<bool> mFaceNamesInitialized;
|
||||
mozilla::Atomic<bool> mHasStyles;
|
||||
mozilla::Atomic<bool> mFamilyCharacterMapInitialized;
|
||||
mozilla::Atomic<bool> mCheckedForLegacyFamilyNames;
|
||||
mozilla::Atomic<bool> mHasOtherFamilyNames;
|
||||
|
||||
bool mIsSimpleFamily : 1 GUARDED_BY(mLock);
|
||||
bool mIsBadUnderlineFamily : 1;
|
||||
bool mFamilyCharacterMapInitialized : 1;
|
||||
bool mSkipDefaultFeatureSpaceCheck : 1;
|
||||
bool mCheckForFallbackFaces : 1; // check other faces for character
|
||||
bool mCheckedForLegacyFamilyNames : 1;
|
||||
|
||||
enum {
|
||||
// for "simple" families, the faces are stored in mAvailableFonts
|
||||
|
|
|
@ -143,14 +143,24 @@ void gfxFontInfoLoader::StartLoader(uint32_t aDelay) {
|
|||
return;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!mFontInfo, "fontinfo should be null when starting font loader");
|
||||
|
||||
// sanity check
|
||||
if (mState != stateInitial && mState != stateTimerOff &&
|
||||
mState != stateTimerOnDelay) {
|
||||
CancelLoader();
|
||||
}
|
||||
|
||||
// Create mFontInfo when we're initially called to set up the delay, rather
|
||||
// than when called by the DelayedStartCallback, because on the initial call
|
||||
// we know we'll be holding the gfxPlatformFontList lock.
|
||||
if (!mFontInfo) {
|
||||
mFontInfo = CreateFontInfoData();
|
||||
if (!mFontInfo) {
|
||||
// The platform doesn't want anything loaded, so just bail out.
|
||||
mState = stateTimerOff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AddShutdownObserver();
|
||||
|
||||
// Caller asked for a delay? ==> start async thread after a delay
|
||||
|
@ -195,13 +205,6 @@ void gfxFontInfoLoader::StartLoader(uint32_t aDelay) {
|
|||
"Bug 1508626 - Initializing font loader after shutdown but "
|
||||
"before observer");
|
||||
|
||||
mFontInfo = CreateFontInfoData();
|
||||
if (!mFontInfo) {
|
||||
// The platform doesn't want anything loaded, so just bail out.
|
||||
mState = stateTimerOff;
|
||||
return;
|
||||
}
|
||||
|
||||
// initialize
|
||||
InitLoader();
|
||||
|
||||
|
|
|
@ -119,7 +119,9 @@ GDIFontEntry::GDIFontEntry(const nsACString& aFaceName,
|
|||
mStyleRange = aStyle;
|
||||
mWeightRange = aWeight;
|
||||
mStretchRange = aStretch;
|
||||
if (IsType1()) mForceGDI = true;
|
||||
if (IsType1()) {
|
||||
mForceGDI = true;
|
||||
}
|
||||
mIsDataUserFont = aUserFontData != nullptr;
|
||||
|
||||
InitLogFont(aFaceName, aFontType);
|
||||
|
@ -372,10 +374,8 @@ GDIFontEntry* GDIFontEntry::CreateFontEntry(const nsACString& aName,
|
|||
gfxUserFontData* aUserFontData) {
|
||||
// jtdfix - need to set charset, unicode ranges, pitch/family
|
||||
|
||||
GDIFontEntry* fe = new GDIFontEntry(aName, aFontType, aStyle, aWeight,
|
||||
aStretch, aUserFontData);
|
||||
|
||||
return fe;
|
||||
return new GDIFontEntry(aName, aFontType, aStyle, aWeight, aStretch,
|
||||
aUserFontData);
|
||||
}
|
||||
|
||||
void GDIFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
||||
|
@ -454,9 +454,12 @@ int CALLBACK GDIFontFamily::FamilyAddStylesProc(
|
|||
SlantStyleRange(italicStyle),
|
||||
WeightRange(FontWeight(int32_t(logFont.lfWeight))),
|
||||
StretchRange(FontStretch::Normal()), nullptr);
|
||||
if (!fe) return 1;
|
||||
if (!fe) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ff->AddFontEntry(fe);
|
||||
MOZ_ASSERT(ff->mLock.LockedForWritingByCurrentThread());
|
||||
ff->AddFontEntryLocked(fe);
|
||||
|
||||
if (nmetrics->ntmFontSig.fsUsb[0] != 0x00000000 &&
|
||||
nmetrics->ntmFontSig.fsUsb[1] != 0x00000000 &&
|
||||
|
@ -482,8 +485,10 @@ int CALLBACK GDIFontFamily::FamilyAddStylesProc(
|
|||
return 1;
|
||||
}
|
||||
|
||||
void GDIFontFamily::FindStyleVariations(FontInfoData* aFontInfoData) {
|
||||
if (mHasStyles) return;
|
||||
void GDIFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
|
||||
if (mHasStyles) {
|
||||
return;
|
||||
}
|
||||
mHasStyles = true;
|
||||
|
||||
HDC hdc = GetDC(nullptr);
|
||||
|
@ -838,13 +843,11 @@ gfxFontEntry* gfxGDIFontList::MakePlatformFont(const nsACString& aFontName,
|
|||
return fe;
|
||||
}
|
||||
|
||||
bool gfxGDIFontList::FindAndAddFamilies(nsPresContext* aPresContext,
|
||||
StyleGenericFontFamily aGeneric,
|
||||
const nsACString& aFamily,
|
||||
nsTArray<FamilyAndGeneric>* aOutput,
|
||||
FindFamiliesFlags aFlags,
|
||||
gfxFontStyle* aStyle, nsAtom* aLanguage,
|
||||
gfxFloat aDevToCssSize) {
|
||||
bool gfxGDIFontList::FindAndAddFamiliesLocked(
|
||||
nsPresContext* aPresContext, StyleGenericFontFamily aGeneric,
|
||||
const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
|
||||
FindFamiliesFlags aFlags, gfxFontStyle* aStyle, nsAtom* aLanguage,
|
||||
gfxFloat aDevToCssSize) {
|
||||
NS_ConvertUTF8toUTF16 key16(aFamily);
|
||||
BuildKeyNameFromFontName(key16);
|
||||
NS_ConvertUTF16toUTF8 keyName(key16);
|
||||
|
@ -861,7 +864,7 @@ bool gfxGDIFontList::FindAndAddFamilies(nsPresContext* aPresContext,
|
|||
return false;
|
||||
}
|
||||
|
||||
return gfxPlatformFontList::FindAndAddFamilies(
|
||||
return gfxPlatformFontList::FindAndAddFamiliesLocked(
|
||||
aPresContext, aGeneric, aFamily, aOutput, aFlags, aStyle, aLanguage,
|
||||
aDevToCssSize);
|
||||
}
|
||||
|
@ -897,6 +900,9 @@ FontFamily gfxGDIFontList::GetDefaultFontForPlatform(
|
|||
void gfxGDIFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
||||
FontListSizes* aSizes) const {
|
||||
gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
||||
|
||||
AutoLock lock(mLock);
|
||||
|
||||
aSizes->mFontListSize +=
|
||||
SizeOfFontFamilyTableExcludingThis(mFontSubstitutes, aMallocSizeOf);
|
||||
aSizes->mFontListSize +=
|
||||
|
|
|
@ -193,7 +193,8 @@ class GDIFontFamily final : public gfxFontFamily {
|
|||
mWindowsPitch(0),
|
||||
mCharset() {}
|
||||
|
||||
virtual void FindStyleVariations(FontInfoData* aFontInfoData = nullptr);
|
||||
void FindStyleVariationsLocked(
|
||||
FontInfoData* aFontInfoData = nullptr) override;
|
||||
|
||||
bool FilterForFontList(nsAtom* aLangGroup,
|
||||
const nsACString& aGeneric) const final {
|
||||
|
@ -304,7 +305,7 @@ class gfxGDIFontList final : public gfxPlatformFontList {
|
|||
gfxFontFamily* CreateFontFamily(const nsACString& aName,
|
||||
FontVisibility aVisibility) const override;
|
||||
|
||||
bool FindAndAddFamilies(
|
||||
bool FindAndAddFamiliesLocked(
|
||||
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGeneric,
|
||||
const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
|
||||
FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr,
|
||||
|
|
|
@ -140,11 +140,12 @@ class gfxMacPlatformFontList final : public gfxPlatformFontList {
|
|||
const uint8_t* aFontData,
|
||||
uint32_t aLength) override;
|
||||
|
||||
bool FindAndAddFamilies(
|
||||
bool FindAndAddFamiliesLocked(
|
||||
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGeneric,
|
||||
const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
|
||||
FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr,
|
||||
nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0) override;
|
||||
nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0)
|
||||
REQUIRES(mLock) override;
|
||||
|
||||
// lookup the system font for a particular system font type and set
|
||||
// the name and style characteristics
|
||||
|
@ -163,7 +164,8 @@ class gfxMacPlatformFontList final : public gfxPlatformFontList {
|
|||
protected:
|
||||
FontFamily GetDefaultFontForPlatform(nsPresContext* aPresContext,
|
||||
const gfxFontStyle* aStyle,
|
||||
nsAtom* aLanguage = nullptr) override;
|
||||
nsAtom* aLanguage = nullptr)
|
||||
REQUIRES(mLock) override;
|
||||
|
||||
private:
|
||||
friend class gfxPlatformMac;
|
||||
|
@ -172,22 +174,23 @@ class gfxMacPlatformFontList final : public gfxPlatformFontList {
|
|||
virtual ~gfxMacPlatformFontList();
|
||||
|
||||
// initialize font lists
|
||||
nsresult InitFontListForPlatform() override;
|
||||
void InitSharedFontListForPlatform() override;
|
||||
nsresult InitFontListForPlatform() REQUIRES(mLock) override;
|
||||
void InitSharedFontListForPlatform() REQUIRES(mLock) override;
|
||||
|
||||
// handle commonly used fonts for which the name table should be loaded at
|
||||
// startup
|
||||
void PreloadNamesList();
|
||||
void PreloadNamesList() REQUIRES(mLock);
|
||||
|
||||
// special case font faces treated as font families (set via prefs)
|
||||
void InitSingleFaceList();
|
||||
void InitAliasesForSingleFaceList();
|
||||
void InitSingleFaceList() REQUIRES(mLock);
|
||||
void InitAliasesForSingleFaceList() REQUIRES(mLock);
|
||||
|
||||
// initialize system fonts
|
||||
void InitSystemFontNames();
|
||||
void InitSystemFontNames() REQUIRES(mLock);
|
||||
|
||||
// helper function to lookup in both hidden system fonts and normal fonts
|
||||
gfxFontFamily* FindSystemFontFamily(const nsACString& aFamily);
|
||||
gfxFontFamily* FindSystemFontFamily(const nsACString& aFamily)
|
||||
REQUIRES(mLock);
|
||||
|
||||
FontVisibility GetVisibilityForFamily(const nsACString& aName) const;
|
||||
|
||||
|
@ -201,7 +204,8 @@ class gfxMacPlatformFontList final : public gfxPlatformFontList {
|
|||
const uint32_t aCh,
|
||||
Script aRunScript,
|
||||
const gfxFontStyle* aMatchStyle,
|
||||
FontFamily& aMatchedFamily) override;
|
||||
FontFamily& aMatchedFamily)
|
||||
REQUIRES(mLock) override;
|
||||
|
||||
bool UsesSystemFallback() override { return true; }
|
||||
|
||||
|
@ -212,9 +216,10 @@ class gfxMacPlatformFontList final : public gfxPlatformFontList {
|
|||
// file is included in .cpp files, so we can't use objective C classes here.
|
||||
// But CFStringRef and NSString* are the same thing anyway (they're
|
||||
// toll-free bridged).
|
||||
void AddFamily(CFStringRef aFamily);
|
||||
void AddFamily(CFStringRef aFamily) REQUIRES(mLock);
|
||||
|
||||
void AddFamily(const nsACString& aFamilyName, FontVisibility aVisibility);
|
||||
void AddFamily(const nsACString& aFamilyName, FontVisibility aVisibility)
|
||||
REQUIRES(mLock);
|
||||
|
||||
gfxFontEntry* CreateFontEntry(
|
||||
mozilla::fontlist::Face* aFace,
|
||||
|
@ -226,7 +231,8 @@ class gfxMacPlatformFontList final : public gfxPlatformFontList {
|
|||
bool aLoadCmaps) const override;
|
||||
|
||||
void ReadFaceNamesForFamily(mozilla::fontlist::Family* aFamily,
|
||||
bool aNeedFullnamePostscriptNames) override;
|
||||
bool aNeedFullnamePostscriptNames)
|
||||
REQUIRES(mLock) override;
|
||||
|
||||
enum { kATSGenerationInitial = -1 };
|
||||
|
||||
|
|
|
@ -583,14 +583,14 @@ void MacOSFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
|||
|
||||
class gfxMacFontFamily final : public gfxFontFamily {
|
||||
public:
|
||||
gfxMacFontFamily(const nsACString& aName, FontVisibility aVisibility, double aSizeHint)
|
||||
gfxMacFontFamily(const nsACString& aName, FontVisibility aVisibility, double aSizeHint = 0.0)
|
||||
: gfxFontFamily(aName, aVisibility), mSizeHint(aSizeHint) {}
|
||||
|
||||
virtual ~gfxMacFontFamily() = default;
|
||||
|
||||
virtual void LocalizedName(nsACString& aLocalizedName);
|
||||
void LocalizedName(nsACString& aLocalizedName) override;
|
||||
|
||||
virtual void FindStyleVariations(FontInfoData* aFontInfoData = nullptr);
|
||||
void FindStyleVariationsLocked(FontInfoData* aFontInfoData = nullptr) REQUIRES(mLock) override;
|
||||
|
||||
protected:
|
||||
double mSizeHint;
|
||||
|
@ -634,7 +634,7 @@ static inline int GetWeightOverride(const nsAString& aPSName) {
|
|||
return Preferences::GetInt(prefName.get(), 0);
|
||||
}
|
||||
|
||||
void gfxMacFontFamily::FindStyleVariations(FontInfoData* aFontInfoData) {
|
||||
void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
|
||||
if (mHasStyles) {
|
||||
return;
|
||||
}
|
||||
|
@ -735,7 +735,7 @@ void gfxMacFontFamily::FindStyleVariations(FontInfoData* aFontInfoData) {
|
|||
}
|
||||
|
||||
// insert into font entry array of family
|
||||
AddFontEntry(fontEntry);
|
||||
AddFontEntryLocked(fontEntry);
|
||||
}
|
||||
|
||||
SortAvailableFonts();
|
||||
|
@ -760,16 +760,20 @@ class gfxSingleFaceMacFontFamily final : public gfxFontFamily {
|
|||
|
||||
virtual ~gfxSingleFaceMacFontFamily() = default;
|
||||
|
||||
virtual void LocalizedName(nsACString& aLocalizedName);
|
||||
void FindStyleVariationsLocked(FontInfoData* aFontInfoData = nullptr) REQUIRES(mLock) override{};
|
||||
|
||||
virtual void ReadOtherFamilyNames(gfxPlatformFontList* aPlatformFontList);
|
||||
void LocalizedName(nsACString& aLocalizedName) override;
|
||||
|
||||
virtual bool IsSingleFaceFamily() const { return true; }
|
||||
void ReadOtherFamilyNames(gfxPlatformFontList* aPlatformFontList) override;
|
||||
|
||||
bool IsSingleFaceFamily() const override { return true; }
|
||||
};
|
||||
|
||||
void gfxSingleFaceMacFontFamily::LocalizedName(nsACString& aLocalizedName) {
|
||||
nsAutoreleasePool localPool;
|
||||
|
||||
AutoReadLock lock(mLock);
|
||||
|
||||
if (!HasOtherFamilyNames()) {
|
||||
aLocalizedName = mName;
|
||||
return;
|
||||
|
@ -797,6 +801,7 @@ void gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList* aPlat
|
|||
return;
|
||||
}
|
||||
|
||||
AutoWriteLock lock(mLock);
|
||||
gfxFontEntry* fe = mAvailableFonts[0];
|
||||
if (!fe) {
|
||||
return;
|
||||
|
@ -888,7 +893,8 @@ void gfxMacPlatformFontList::AddFamily(CFStringRef aFamily) {
|
|||
AddFamily(nameUtf8, GetVisibilityForFamily(nameUtf8));
|
||||
}
|
||||
|
||||
void gfxMacPlatformFontList::ReadSystemFontList(dom::SystemFontList* aList) {
|
||||
void gfxMacPlatformFontList::ReadSystemFontList(dom::SystemFontList* aList)
|
||||
NO_THREAD_SAFETY_ANALYSIS {
|
||||
// Note: We rely on the records for mSystemTextFontFamilyName and
|
||||
// mSystemDisplayFontFamilyName (if present) being *before* the main
|
||||
// font list, so that those names are known in the content process
|
||||
|
@ -1203,7 +1209,7 @@ static NSString* GetRealFamilyName(NSFont* aFont) {
|
|||
// so we expect the system font to be a variable-weight face rather than requiring
|
||||
// a number of discrete faces of different weights.
|
||||
static gfxFontFamily* CreateFamilyForSystemFont(NSFont* aFont, const nsACString& aFamilyName) {
|
||||
gfxFontFamily* familyEntry = new gfxFontFamily(aFamilyName, FontVisibility::Unknown);
|
||||
gfxFontFamily* familyEntry = new gfxMacFontFamily(aFamilyName, FontVisibility::Unknown);
|
||||
|
||||
NSString* psNameNS = [[aFont fontDescriptor] postscriptName];
|
||||
nsAutoString nameUTF16;
|
||||
|
@ -1366,7 +1372,7 @@ gfxFontEntry* gfxMacPlatformFontList::PlatformGlobalFontFallback(nsPresContext*
|
|||
if (family) {
|
||||
fontlist::Face* face = family->FindFaceForStyle(SharedFontList(), *aMatchStyle);
|
||||
if (face) {
|
||||
fontEntry = GetOrCreateFontEntry(face, family);
|
||||
fontEntry = GetOrCreateFontEntryLocked(face, family);
|
||||
}
|
||||
if (fontEntry) {
|
||||
if (fontEntry->HasCharacter(aCh)) {
|
||||
|
@ -1437,6 +1443,8 @@ gfxFontEntry* gfxMacPlatformFontList::LookupLocalFont(nsPresContext* aPresContex
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
AutoLock lock(mLock);
|
||||
|
||||
nsAutoreleasePool localPool;
|
||||
|
||||
NSString* faceName = GetNSStringForString(NS_ConvertUTF8toUTF16(aFontName));
|
||||
|
@ -1521,12 +1529,10 @@ gfxFontEntry* gfxMacPlatformFontList::MakePlatformFont(const nsACString& aFontNa
|
|||
// WebCore/platform/graphics/mac/FontCacheMac.mm
|
||||
static const char kSystemFont_system[] = "-apple-system";
|
||||
|
||||
bool gfxMacPlatformFontList::FindAndAddFamilies(nsPresContext* aPresContext,
|
||||
StyleGenericFontFamily aGeneric,
|
||||
const nsACString& aFamily,
|
||||
nsTArray<FamilyAndGeneric>* aOutput,
|
||||
FindFamiliesFlags aFlags, gfxFontStyle* aStyle,
|
||||
nsAtom* aLanguage, gfxFloat aDevToCssSize) {
|
||||
bool gfxMacPlatformFontList::FindAndAddFamiliesLocked(
|
||||
nsPresContext* aPresContext, StyleGenericFontFamily aGeneric, const nsACString& aFamily,
|
||||
nsTArray<FamilyAndGeneric>* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle,
|
||||
nsAtom* aLanguage, gfxFloat aDevToCssSize) {
|
||||
if (aFamily.EqualsLiteral(kSystemFont_system)) {
|
||||
// Search for special system font name, -apple-system. This is not done via
|
||||
// the shared fontlist on Catalina or later, because the hidden system font
|
||||
|
@ -1539,9 +1545,9 @@ bool gfxMacPlatformFontList::FindAndAddFamilies(nsPresContext* aPresContext,
|
|||
: mSystemTextFontFamilyName;
|
||||
if (SharedFontList() && !nsCocoaFeatures::OnCatalinaOrLater()) {
|
||||
FindFamiliesFlags flags = aFlags | FindFamiliesFlags::eSearchHiddenFamilies;
|
||||
return gfxPlatformFontList::FindAndAddFamilies(aPresContext, aGeneric, systemFontFamilyName,
|
||||
aOutput, flags, aStyle, aLanguage,
|
||||
aDevToCssSize);
|
||||
return gfxPlatformFontList::FindAndAddFamiliesLocked(aPresContext, aGeneric,
|
||||
systemFontFamilyName, aOutput, flags,
|
||||
aStyle, aLanguage, aDevToCssSize);
|
||||
} else {
|
||||
if (auto* fam = FindSystemFontFamily(systemFontFamilyName)) {
|
||||
aOutput->AppendElement(fam);
|
||||
|
@ -1551,8 +1557,8 @@ bool gfxMacPlatformFontList::FindAndAddFamilies(nsPresContext* aPresContext,
|
|||
return false;
|
||||
}
|
||||
|
||||
return gfxPlatformFontList::FindAndAddFamilies(aPresContext, aGeneric, aFamily, aOutput, aFlags,
|
||||
aStyle, aLanguage, aDevToCssSize);
|
||||
return gfxPlatformFontList::FindAndAddFamiliesLocked(aPresContext, aGeneric, aFamily, aOutput,
|
||||
aFlags, aStyle, aLanguage, aDevToCssSize);
|
||||
}
|
||||
|
||||
void gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID,
|
||||
|
@ -1730,6 +1736,7 @@ already_AddRefed<FontInfoData> gfxMacPlatformFontList::CreateFontInfoData() {
|
|||
bool loadCmaps =
|
||||
!UsesSystemFallback() || gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
|
||||
|
||||
mLock.AssertCurrentThreadIn();
|
||||
RefPtr<MacFontInfo> fi = new MacFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps);
|
||||
return fi.forget();
|
||||
}
|
||||
|
|
|
@ -264,7 +264,7 @@ bool gfxPlatformFontList::Initialize(gfxPlatformFontList* aList) {
|
|||
}
|
||||
|
||||
gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
|
||||
: mFontFamiliesMutex("gfxPlatformFontList::mFontFamiliesMutex"),
|
||||
: mLock("gfxPlatformFontList lock"),
|
||||
mFontFamilies(64),
|
||||
mOtherFamilyNames(16),
|
||||
mSharedCmaps(8) {
|
||||
|
@ -305,7 +305,7 @@ gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
|
|||
|
||||
gfxPlatformFontList::~gfxPlatformFontList() {
|
||||
mSharedCmaps.Clear();
|
||||
ClearLangGroupPrefFonts();
|
||||
ClearLangGroupPrefFontsLocked();
|
||||
|
||||
NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
|
||||
|
||||
|
@ -375,6 +375,7 @@ void gfxPlatformFontList::ApplyWhitelist() {
|
|||
|
||||
void gfxPlatformFontList::ApplyWhitelist(
|
||||
nsTArray<fontlist::Family::InitData>& aFamilies) {
|
||||
mLock.AssertCurrentThreadIn();
|
||||
mFontFamilyWhitelistActive = !mEnabledFontsList.IsEmpty();
|
||||
if (!mFontFamilyWhitelistActive) {
|
||||
return;
|
||||
|
@ -435,6 +436,7 @@ void gfxPlatformFontList::CheckFamilyList(const char* aList[], size_t aCount) {
|
|||
bool gfxPlatformFontList::AddWithLegacyFamilyName(const nsACString& aLegacyName,
|
||||
gfxFontEntry* aFontEntry,
|
||||
FontVisibility aVisibility) {
|
||||
mLock.AssertCurrentThreadIn();
|
||||
bool added = false;
|
||||
nsAutoCString key;
|
||||
ToLowerCase(aLegacyName, key);
|
||||
|
@ -455,7 +457,14 @@ bool gfxPlatformFontList::AddWithLegacyFamilyName(const nsACString& aLegacyName,
|
|||
}
|
||||
|
||||
bool gfxPlatformFontList::InitFontList() {
|
||||
MutexAutoLock lock(mFontFamiliesMutex);
|
||||
// If the startup font-list-init thread is still running, we need to wait
|
||||
// for it to finish before trying to reinitialize here.
|
||||
if (sInitFontListThread && !IsInitFontListThread()) {
|
||||
PR_JoinThread(sInitFontListThread);
|
||||
sInitFontListThread = nullptr;
|
||||
}
|
||||
|
||||
AutoLock lock(mLock);
|
||||
|
||||
if (LOG_FONTINIT_ENABLED()) {
|
||||
LOG_FONTINIT(("(fontinit) system fontlist initialization\n"));
|
||||
|
@ -507,7 +516,7 @@ bool gfxPlatformFontList::InitFontList() {
|
|||
mExtraNames->mPostscriptNames.Clear();
|
||||
}
|
||||
mFaceNameListsInitialized = false;
|
||||
ClearLangGroupPrefFonts();
|
||||
ClearLangGroupPrefFontsLocked();
|
||||
CancelLoader();
|
||||
|
||||
// Clear cached family records that will no longer be valid.
|
||||
|
@ -576,14 +585,15 @@ bool gfxPlatformFontList::InitFontList() {
|
|||
// Set up mDefaultFontEntry as a "last resort" default that we can use
|
||||
// to avoid crashing if the font list is otherwise unusable.
|
||||
gfxFontStyle defStyle;
|
||||
FontFamily fam = GetDefaultFont(nullptr, &defStyle);
|
||||
FontFamily fam = GetDefaultFontLocked(nullptr, &defStyle);
|
||||
gfxFontEntry* fe;
|
||||
if (fam.mIsShared) {
|
||||
auto face = fam.mShared->FindFaceForStyle(SharedFontList(), defStyle);
|
||||
mDefaultFontEntry =
|
||||
face ? GetOrCreateFontEntry(face, fam.mShared) : nullptr;
|
||||
fe = face ? GetOrCreateFontEntryLocked(face, fam.mShared) : nullptr;
|
||||
} else {
|
||||
mDefaultFontEntry = fam.mUnshared->FindFontForStyle(defStyle);
|
||||
fe = fam.mUnshared->FindFontForStyle(defStyle);
|
||||
}
|
||||
mDefaultFontEntry = fe;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -610,6 +620,7 @@ void gfxPlatformFontList::InitializeCodepointsWithNoFonts() {
|
|||
|
||||
void gfxPlatformFontList::FontListChanged() {
|
||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||
AutoLock lock(mLock);
|
||||
InitializeCodepointsWithNoFonts();
|
||||
if (SharedFontList()) {
|
||||
// If we're using a shared local face-name list, this may have changed
|
||||
|
@ -641,8 +652,10 @@ class InitOtherFamilyNamesForStylo : public mozilla::Runnable {
|
|||
if (!list) {
|
||||
return NS_OK;
|
||||
}
|
||||
bool initialized = false;
|
||||
dom::ContentChild::GetSingleton()->SendInitOtherFamilyNames(
|
||||
list->GetGeneration(), mDefer, &pfl->mOtherFamilyNamesInitialized);
|
||||
list->GetGeneration(), mDefer, &initialized);
|
||||
pfl->mOtherFamilyNamesInitialized.compareExchange(false, initialized);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -660,9 +673,11 @@ bool gfxPlatformFontList::InitOtherFamilyNames(
|
|||
|
||||
if (SharedFontList() && !XRE_IsParentProcess()) {
|
||||
if (NS_IsMainThread()) {
|
||||
bool initialized;
|
||||
dom::ContentChild::GetSingleton()->SendInitOtherFamilyNames(
|
||||
SharedFontList()->GetGeneration(), aDeferOtherFamilyNamesLoading,
|
||||
&mOtherFamilyNamesInitialized);
|
||||
&initialized);
|
||||
mOtherFamilyNamesInitialized.compareExchange(false, initialized);
|
||||
} else {
|
||||
NS_DispatchToMainThread(
|
||||
new InitOtherFamilyNamesForStylo(aDeferOtherFamilyNamesLoading));
|
||||
|
@ -836,6 +851,7 @@ void gfxPlatformFontList::UpdateFontList(bool aFullRebuild) {
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (aFullRebuild) {
|
||||
InitFontList();
|
||||
AutoLock lock(mLock);
|
||||
RebuildLocalFonts();
|
||||
} else {
|
||||
// The font list isn't being fully rebuilt, we're just being notified that
|
||||
|
@ -843,6 +859,7 @@ void gfxPlatformFontList::UpdateFontList(bool aFullRebuild) {
|
|||
// done. We only care about this if we have previously encountered a
|
||||
// fallback that required cmaps that were not yet available, and so we
|
||||
// asked for the async cmap loader to run.
|
||||
AutoLock lock(mLock);
|
||||
if (mStartedLoadingCmapsFrom != 0xffffffffu) {
|
||||
InitializeCodepointsWithNoFonts();
|
||||
mStartedLoadingCmapsFrom = 0xffffffffu;
|
||||
|
@ -864,6 +881,8 @@ bool gfxPlatformFontList::IsVisibleToCSS(const fontlist::Family& aFamily,
|
|||
void gfxPlatformFontList::GetFontList(nsAtom* aLangGroup,
|
||||
const nsACString& aGenericFamily,
|
||||
nsTArray<nsString>& aListOfFonts) {
|
||||
AutoLock lock(mLock);
|
||||
|
||||
if (SharedFontList()) {
|
||||
fontlist::FontList* list = SharedFontList();
|
||||
const fontlist::Family* families = list->Families();
|
||||
|
@ -882,7 +901,6 @@ void gfxPlatformFontList::GetFontList(nsAtom* aLangGroup,
|
|||
return;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mFontFamiliesMutex);
|
||||
for (const RefPtr<gfxFontFamily>& family : mFontFamilies.Values()) {
|
||||
if (!IsVisibleToCSS(*family, FontVisibility::User)) {
|
||||
continue;
|
||||
|
@ -900,6 +918,7 @@ void gfxPlatformFontList::GetFontList(nsAtom* aLangGroup,
|
|||
|
||||
void gfxPlatformFontList::GetFontFamilyList(
|
||||
nsTArray<RefPtr<gfxFontFamily>>& aFamilyArray) {
|
||||
AutoLock lock(mLock);
|
||||
MOZ_ASSERT(aFamilyArray.IsEmpty());
|
||||
// This doesn't use ToArray, because the caller passes an AutoTArray.
|
||||
aFamilyArray.SetCapacity(mFontFamilies.Count());
|
||||
|
@ -912,6 +931,7 @@ gfxFont* gfxPlatformFontList::SystemFindFontForChar(
|
|||
nsPresContext* aPresContext, uint32_t aCh, uint32_t aNextCh,
|
||||
Script aRunScript, eFontPresentation aPresentation,
|
||||
const gfxFontStyle* aStyle, FontVisibility* aVisibility) {
|
||||
AutoLock lock(mLock);
|
||||
FontVisibility level =
|
||||
aPresContext ? aPresContext->GetFontVisibility() : FontVisibility::User;
|
||||
MOZ_ASSERT(!mCodepointsWithNoFonts[level].test(aCh),
|
||||
|
@ -928,7 +948,7 @@ gfxFont* gfxPlatformFontList::SystemFindFontForChar(
|
|||
fontlist::Face* face =
|
||||
fallbackFamily.mShared->FindFaceForStyle(SharedFontList(), *aStyle);
|
||||
if (face) {
|
||||
fontEntry = GetOrCreateFontEntry(face, fallbackFamily.mShared);
|
||||
fontEntry = GetOrCreateFontEntryLocked(face, fallbackFamily.mShared);
|
||||
*aVisibility = fallbackFamily.mShared->Visibility();
|
||||
}
|
||||
} else if (!fallbackFamily.mIsShared && fallbackFamily.mUnshared) {
|
||||
|
@ -1357,9 +1377,11 @@ class LoadCmapsRunnable : public CancelableRunnable {
|
|||
RefPtr<CancelableRunnable> task = this;
|
||||
NS_DispatchToMainThreadQueue(task.forget(), EventQueuePriority::Idle);
|
||||
} else {
|
||||
pfl->Lock();
|
||||
pfl->CancelLoadCmapsTask();
|
||||
pfl->InitializeCodepointsWithNoFonts();
|
||||
dom::ContentParent::NotifyUpdatedFonts(false);
|
||||
pfl->Unlock();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1416,7 +1438,7 @@ gfxFontFamily* gfxPlatformFontList::CheckFamily(gfxFontFamily* aFamily) {
|
|||
}
|
||||
|
||||
if (aFamily && aFamily->GetFontList().Length() == 0) {
|
||||
// failed to load any faces for this family, so discard it
|
||||
// Failed to load any faces for this family, so discard it.
|
||||
nsAutoCString key;
|
||||
GenerateFontListKey(aFamily->Name(), key);
|
||||
mFontFamilies.Remove(key);
|
||||
|
@ -1426,7 +1448,7 @@ gfxFontFamily* gfxPlatformFontList::CheckFamily(gfxFontFamily* aFamily) {
|
|||
return aFamily;
|
||||
}
|
||||
|
||||
bool gfxPlatformFontList::FindAndAddFamilies(
|
||||
bool gfxPlatformFontList::FindAndAddFamiliesLocked(
|
||||
nsPresContext* aPresContext, StyleGenericFontFamily aGeneric,
|
||||
const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
|
||||
FindFamiliesFlags aFlags, gfxFontStyle* aStyle, nsAtom* aLanguage,
|
||||
|
@ -1437,6 +1459,7 @@ bool gfxPlatformFontList::FindAndAddFamilies(
|
|||
bool allowHidden = bool(aFlags & FindFamiliesFlags::eSearchHiddenFamilies);
|
||||
FontVisibility visibilityLevel =
|
||||
aPresContext ? aPresContext->GetFontVisibility() : FontVisibility::User;
|
||||
|
||||
if (SharedFontList()) {
|
||||
fontlist::Family* family = SharedFontList()->FindFamily(key);
|
||||
// If not found, and other family names have not yet been initialized,
|
||||
|
@ -1471,12 +1494,7 @@ bool gfxPlatformFontList::FindAndAddFamilies(
|
|||
}
|
||||
if (!family && !mOtherFamilyNamesInitialized &&
|
||||
!(aFlags & FindFamiliesFlags::eNoAddToNamesMissedWhenSearching)) {
|
||||
// localized family names load timed out, add name to list of
|
||||
// names to check after localized names are loaded
|
||||
if (!mOtherNamesMissed) {
|
||||
mOtherNamesMissed = MakeUnique<nsTHashSet<nsCString>>(2);
|
||||
}
|
||||
mOtherNamesMissed->Insert(key);
|
||||
AddToMissedNames(key);
|
||||
}
|
||||
}
|
||||
// Check whether the family we found is actually allowed to be looked up,
|
||||
|
@ -1539,10 +1557,7 @@ bool gfxPlatformFontList::FindAndAddFamilies(
|
|||
!(aFlags & FindFamiliesFlags::eNoAddToNamesMissedWhenSearching)) {
|
||||
// localized family names load timed out, add name to list of
|
||||
// names to check after localized names are loaded
|
||||
if (!mOtherNamesMissed) {
|
||||
mOtherNamesMissed = MakeUnique<nsTHashSet<nsCString>>(2);
|
||||
}
|
||||
mOtherNamesMissed->Insert(key);
|
||||
AddToMissedNames(key);
|
||||
}
|
||||
if (familyEntry) {
|
||||
if (isBlockedByVisibilityLevel(familyEntry)) {
|
||||
|
@ -1594,6 +1609,13 @@ bool gfxPlatformFontList::FindAndAddFamilies(
|
|||
return false;
|
||||
}
|
||||
|
||||
void gfxPlatformFontList::AddToMissedNames(const nsCString& aKey) {
|
||||
if (!mOtherNamesMissed) {
|
||||
mOtherNamesMissed = MakeUnique<nsTHashSet<nsCString>>(2);
|
||||
}
|
||||
mOtherNamesMissed->Insert(aKey);
|
||||
}
|
||||
|
||||
fontlist::Family* gfxPlatformFontList::FindSharedFamily(
|
||||
nsPresContext* aPresContext, const nsACString& aFamily,
|
||||
FindFamiliesFlags aFlags, gfxFontStyle* aStyle, nsAtom* aLanguage,
|
||||
|
@ -1602,8 +1624,9 @@ fontlist::Family* gfxPlatformFontList::FindSharedFamily(
|
|||
return nullptr;
|
||||
}
|
||||
AutoTArray<FamilyAndGeneric, 1> families;
|
||||
if (!FindAndAddFamilies(aPresContext, StyleGenericFontFamily::None, aFamily,
|
||||
&families, aFlags, aStyle, aLanguage, aDevToCss) ||
|
||||
if (!FindAndAddFamiliesLocked(aPresContext, StyleGenericFontFamily::None,
|
||||
aFamily, &families, aFlags, aStyle, aLanguage,
|
||||
aDevToCss) ||
|
||||
!families[0].mFamily.mIsShared) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1707,6 +1730,7 @@ gfxFontEntry* gfxPlatformFontList::FindFontForFamily(
|
|||
const gfxFontStyle* aStyle) {
|
||||
nsAutoCString key;
|
||||
GenerateFontListKey(aFamily, key);
|
||||
|
||||
FontFamily family = FindFamily(aPresContext, key);
|
||||
if (family.IsNull()) {
|
||||
return nullptr;
|
||||
|
@ -1716,12 +1740,12 @@ gfxFontEntry* gfxPlatformFontList::FindFontForFamily(
|
|||
if (!face) {
|
||||
return nullptr;
|
||||
}
|
||||
return GetOrCreateFontEntry(face, family.mShared);
|
||||
return GetOrCreateFontEntryLocked(face, family.mShared);
|
||||
}
|
||||
return family.mUnshared->FindFontForStyle(*aStyle);
|
||||
}
|
||||
|
||||
gfxFontEntry* gfxPlatformFontList::GetOrCreateFontEntry(
|
||||
gfxFontEntry* gfxPlatformFontList::GetOrCreateFontEntryLocked(
|
||||
fontlist::Face* aFace, const fontlist::Family* aFamily) {
|
||||
return mFontEntries
|
||||
.LookupOrInsertWith(aFace,
|
||||
|
@ -1729,25 +1753,28 @@ gfxFontEntry* gfxPlatformFontList::GetOrCreateFontEntry(
|
|||
.get();
|
||||
}
|
||||
|
||||
void gfxPlatformFontList::AddOtherFamilyName(
|
||||
gfxFontFamily* aFamilyEntry, const nsCString& aOtherFamilyName) {
|
||||
nsAutoCString key;
|
||||
GenerateFontListKey(aOtherFamilyName, key);
|
||||
void gfxPlatformFontList::AddOtherFamilyNames(
|
||||
gfxFontFamily* aFamilyEntry, const nsTArray<nsCString>& aOtherFamilyNames) {
|
||||
AutoLock lock(mLock);
|
||||
|
||||
mOtherFamilyNames.LookupOrInsertWith(key, [&] {
|
||||
LOG_FONTLIST(
|
||||
("(fontlist-otherfamily) canonical family: %s, "
|
||||
"other family: %s\n",
|
||||
aFamilyEntry->Name().get(), aOtherFamilyName.get()));
|
||||
if (mBadUnderlineFamilyNames.ContainsSorted(key)) {
|
||||
aFamilyEntry->SetBadUnderlineFamily();
|
||||
}
|
||||
return RefPtr{aFamilyEntry};
|
||||
});
|
||||
for (const auto& name : aOtherFamilyNames) {
|
||||
nsAutoCString key;
|
||||
GenerateFontListKey(name, key);
|
||||
|
||||
mOtherFamilyNames.LookupOrInsertWith(key, [&] {
|
||||
LOG_FONTLIST(
|
||||
("(fontlist-otherfamily) canonical family: %s, other family: %s\n",
|
||||
aFamilyEntry->Name().get(), name.get()));
|
||||
if (mBadUnderlineFamilyNames.ContainsSorted(key)) {
|
||||
aFamilyEntry->SetBadUnderlineFamily();
|
||||
}
|
||||
return RefPtr{aFamilyEntry};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void gfxPlatformFontList::AddFullname(gfxFontEntry* aFontEntry,
|
||||
const nsCString& aFullname) {
|
||||
void gfxPlatformFontList::AddFullnameLocked(gfxFontEntry* aFontEntry,
|
||||
const nsCString& aFullname) {
|
||||
mExtraNames->mFullnames.LookupOrInsertWith(aFullname, [&] {
|
||||
LOG_FONTLIST(("(fontlist-fullname) name: %s, fullname: %s\n",
|
||||
aFontEntry->Name().get(), aFullname.get()));
|
||||
|
@ -1755,8 +1782,8 @@ void gfxPlatformFontList::AddFullname(gfxFontEntry* aFontEntry,
|
|||
});
|
||||
}
|
||||
|
||||
void gfxPlatformFontList::AddPostscriptName(gfxFontEntry* aFontEntry,
|
||||
const nsCString& aPostscriptName) {
|
||||
void gfxPlatformFontList::AddPostscriptNameLocked(
|
||||
gfxFontEntry* aFontEntry, const nsCString& aPostscriptName) {
|
||||
mExtraNames->mPostscriptNames.LookupOrInsertWith(aPostscriptName, [&] {
|
||||
LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
|
||||
aFontEntry->Name().get(), aPostscriptName.get()));
|
||||
|
@ -1766,6 +1793,7 @@ void gfxPlatformFontList::AddPostscriptName(gfxFontEntry* aFontEntry,
|
|||
|
||||
bool gfxPlatformFontList::GetStandardFamilyName(const nsCString& aFontName,
|
||||
nsACString& aFamilyName) {
|
||||
AutoLock lock(mLock);
|
||||
FontFamily family = FindFamily(nullptr, aFontName);
|
||||
if (family.IsNull()) {
|
||||
return false;
|
||||
|
@ -1794,6 +1822,8 @@ FamilyAndGeneric gfxPlatformFontList::GetDefaultFontFamily(
|
|||
return FamilyAndGeneric();
|
||||
}
|
||||
|
||||
AutoLock lock(mLock);
|
||||
|
||||
nsAutoCString value;
|
||||
AutoTArray<nsCString, 4> names;
|
||||
if (mFontPrefs->LookupNameList(PrefName(aGenericFamily, aLangGroup), value)) {
|
||||
|
@ -1819,7 +1849,7 @@ ShmemCharMapHashEntry::ShmemCharMapHashEntry(const gfxSparseBitSet* aCharMap)
|
|||
SharedBitSet::Create(mCharMap.ToPtr(mList), len, *aCharMap);
|
||||
}
|
||||
|
||||
fontlist::Pointer gfxPlatformFontList::GetShmemCharMap(
|
||||
fontlist::Pointer gfxPlatformFontList::GetShmemCharMapLocked(
|
||||
const gfxSparseBitSet* aCmap) {
|
||||
auto* entry = mShmemCharMaps.GetEntry(aCmap);
|
||||
if (!entry) {
|
||||
|
@ -1828,22 +1858,18 @@ fontlist::Pointer gfxPlatformFontList::GetShmemCharMap(
|
|||
return entry->GetCharMap();
|
||||
}
|
||||
|
||||
// lookup cmap in the shared cmap set, adding if not already present
|
||||
gfxCharacterMap* gfxPlatformFontList::FindCharMap(gfxCharacterMap* aCmap) {
|
||||
AutoLock lock(mLock);
|
||||
aCmap->CalcHash();
|
||||
gfxCharacterMap* cmap = AddCmap(aCmap);
|
||||
gfxCharacterMap* cmap = mSharedCmaps.PutEntry(aCmap)->GetKey();
|
||||
cmap->mShared = true;
|
||||
return cmap;
|
||||
}
|
||||
|
||||
// add a cmap to the shared cmap set
|
||||
gfxCharacterMap* gfxPlatformFontList::AddCmap(const gfxCharacterMap* aCharMap) {
|
||||
CharMapHashKey* found =
|
||||
mSharedCmaps.PutEntry(const_cast<gfxCharacterMap*>(aCharMap));
|
||||
return found->GetKey();
|
||||
}
|
||||
|
||||
// remove the cmap from the shared cmap set
|
||||
void gfxPlatformFontList::RemoveCmap(const gfxCharacterMap* aCharMap) {
|
||||
AutoLock lock(mLock);
|
||||
// skip lookups during teardown
|
||||
if (mSharedCmaps.Count() == 0) {
|
||||
return;
|
||||
|
@ -1939,8 +1965,9 @@ void gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(
|
|||
// lookup and add platform fonts uniquely
|
||||
for (const nsCString& genericFamily : aGenericNameFamilies) {
|
||||
AutoTArray<FamilyAndGeneric, 10> families;
|
||||
FindAndAddFamilies(aPresContext, aGenericType, genericFamily, &families,
|
||||
FindFamiliesFlags(0), nullptr, aLangGroup);
|
||||
FindAndAddFamiliesLocked(aPresContext, aGenericType, genericFamily,
|
||||
&families, FindFamiliesFlags(0), nullptr,
|
||||
aLangGroup);
|
||||
for (const FamilyAndGeneric& f : families) {
|
||||
if (!aGenericFamilies->Contains(f.mFamily)) {
|
||||
aGenericFamilies->AppendElement(f.mFamily);
|
||||
|
@ -1949,7 +1976,8 @@ void gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(
|
|||
}
|
||||
}
|
||||
|
||||
gfxPlatformFontList::PrefFontList* gfxPlatformFontList::GetPrefFontsLangGroup(
|
||||
gfxPlatformFontList::PrefFontList*
|
||||
gfxPlatformFontList::GetPrefFontsLangGroupLocked(
|
||||
nsPresContext* aPresContext, StyleGenericFontFamily aGenericType,
|
||||
eFontPrefLang aPrefLang) {
|
||||
if (aGenericType == StyleGenericFontFamily::MozEmoji ||
|
||||
|
@ -1977,6 +2005,8 @@ gfxPlatformFontList::PrefFontList* gfxPlatformFontList::GetPrefFontsLangGroup(
|
|||
void gfxPlatformFontList::AddGenericFonts(
|
||||
nsPresContext* aPresContext, StyleGenericFontFamily aGenericType,
|
||||
nsAtom* aLanguage, nsTArray<FamilyAndGeneric>& aFamilyList) {
|
||||
AutoLock lock(mLock);
|
||||
|
||||
// map lang ==> langGroup
|
||||
nsAtom* langGroup = GetLangGroup(aLanguage);
|
||||
|
||||
|
@ -1985,7 +2015,7 @@ void gfxPlatformFontList::AddGenericFonts(
|
|||
|
||||
// lookup pref fonts
|
||||
PrefFontList* prefFonts =
|
||||
GetPrefFontsLangGroup(aPresContext, aGenericType, prefLang);
|
||||
GetPrefFontsLangGroupLocked(aPresContext, aGenericType, prefLang);
|
||||
|
||||
if (!prefFonts->IsEmpty()) {
|
||||
aFamilyList.SetCapacity(aFamilyList.Length() + prefFonts->Length());
|
||||
|
@ -2181,6 +2211,7 @@ bool gfxPlatformFontList::IsLangCJK(eFontPrefLang aLang) {
|
|||
void gfxPlatformFontList::GetLangPrefs(eFontPrefLang aPrefLangs[],
|
||||
uint32_t& aLen, eFontPrefLang aCharLang,
|
||||
eFontPrefLang aPageLang) {
|
||||
AutoLock lock(mLock);
|
||||
if (IsLangCJK(aCharLang)) {
|
||||
AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang);
|
||||
} else {
|
||||
|
@ -2351,6 +2382,8 @@ StyleGenericFontFamily gfxPlatformFontList::GetDefaultGeneric(
|
|||
return StyleGenericFontFamily::MozEmoji;
|
||||
}
|
||||
|
||||
AutoLock lock(mLock);
|
||||
|
||||
// initialize lang group pref font defaults (i.e. serif/sans-serif)
|
||||
if (MOZ_UNLIKELY(mDefaultGenericsLangGroup.IsEmpty())) {
|
||||
mDefaultGenericsLangGroup.AppendElements(ArrayLength(gPrefLangNames));
|
||||
|
@ -2375,6 +2408,12 @@ StyleGenericFontFamily gfxPlatformFontList::GetDefaultGeneric(
|
|||
|
||||
FontFamily gfxPlatformFontList::GetDefaultFont(nsPresContext* aPresContext,
|
||||
const gfxFontStyle* aStyle) {
|
||||
AutoLock lock(mLock);
|
||||
return GetDefaultFontLocked(aPresContext, aStyle);
|
||||
}
|
||||
|
||||
FontFamily gfxPlatformFontList::GetDefaultFontLocked(
|
||||
nsPresContext* aPresContext, const gfxFontStyle* aStyle) {
|
||||
FontFamily family = GetDefaultFontForPlatform(aPresContext, aStyle);
|
||||
if (!family.IsNull()) {
|
||||
return family;
|
||||
|
@ -2461,6 +2500,7 @@ void gfxPlatformFontList::InitLoader() {
|
|||
20 // max time for one pass through RunLoader = 20ms
|
||||
|
||||
bool gfxPlatformFontList::LoadFontInfo() {
|
||||
AutoLock lock(mLock);
|
||||
TimeStamp start = TimeStamp::Now();
|
||||
uint32_t i, endIndex = mNumFamilies;
|
||||
fontlist::FontList* list = SharedFontList();
|
||||
|
@ -2528,6 +2568,8 @@ bool gfxPlatformFontList::LoadFontInfo() {
|
|||
}
|
||||
|
||||
void gfxPlatformFontList::CleanupLoader() {
|
||||
AutoLock lock(mLock);
|
||||
|
||||
mFontFamiliesToLoad.Clear();
|
||||
mNumFamilies = 0;
|
||||
bool rebuilt = false, forceReflow = false;
|
||||
|
@ -2535,7 +2577,10 @@ void gfxPlatformFontList::CleanupLoader() {
|
|||
// if had missed face names that are now available, force reflow all
|
||||
if (mFaceNamesMissed) {
|
||||
rebuilt = std::any_of(mFaceNamesMissed->cbegin(), mFaceNamesMissed->cend(),
|
||||
[&](const auto& key) { return FindFaceName(key); });
|
||||
[&](const auto& key) {
|
||||
mLock.AssertCurrentThreadIn();
|
||||
return FindFaceName(key);
|
||||
});
|
||||
if (rebuilt) {
|
||||
RebuildLocalFonts();
|
||||
}
|
||||
|
@ -2547,6 +2592,7 @@ void gfxPlatformFontList::CleanupLoader() {
|
|||
forceReflow = std::any_of(
|
||||
mOtherNamesMissed->cbegin(), mOtherNamesMissed->cend(),
|
||||
[&](const auto& key) {
|
||||
mLock.AssertCurrentThreadIn();
|
||||
return FindUnsharedFamily(
|
||||
nullptr, key,
|
||||
(FindFamiliesFlags::eForceOtherFamilyNamesLoading |
|
||||
|
@ -2580,8 +2626,11 @@ void gfxPlatformFontList::GetPrefsAndStartLoader() {
|
|||
StartLoader(delay);
|
||||
} else {
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"StartLoader callback",
|
||||
[delay, fontList = this] { fontList->StartLoader(delay); }));
|
||||
"StartLoader callback", [delay, fontList = this] {
|
||||
fontList->Lock();
|
||||
fontList->StartLoader(delay);
|
||||
fontList->Unlock();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2594,7 +2643,7 @@ void gfxPlatformFontList::RebuildLocalFonts(bool aForgetLocalFaces) {
|
|||
}
|
||||
}
|
||||
|
||||
void gfxPlatformFontList::ClearLangGroupPrefFonts() {
|
||||
void gfxPlatformFontList::ClearLangGroupPrefFontsLocked() {
|
||||
for (uint32_t i = eFontPrefLang_First;
|
||||
i < eFontPrefLang_First + eFontPrefLang_Count; i++) {
|
||||
auto& prefFontsLangGroup = mLangGroupPrefFonts[i];
|
||||
|
@ -2642,6 +2691,8 @@ size_t gfxPlatformFontList::SizeOfFontEntryTableExcludingThis(
|
|||
|
||||
void gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
||||
FontListSizes* aSizes) const {
|
||||
AutoLock lock(mLock);
|
||||
|
||||
aSizes->mFontListSize +=
|
||||
mFontFamilies.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
for (const auto& entry : mFontFamilies) {
|
||||
|
@ -2717,6 +2768,8 @@ void gfxPlatformFontList::InitOtherFamilyNamesInternal(
|
|||
return;
|
||||
}
|
||||
|
||||
AutoLock lock(mLock);
|
||||
|
||||
if (aDeferOtherFamilyNamesLoading) {
|
||||
TimeStamp start = TimeStamp::Now();
|
||||
bool timedOut = false;
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "mozilla/FontPropertyTypes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/RangedArray.h"
|
||||
#include "mozilla/RecursiveMutex.h"
|
||||
#include "nsLanguageAtomService.h"
|
||||
|
||||
#include "base/shared_memory.h"
|
||||
|
@ -164,6 +164,8 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
typedef mozilla::WeightRange WeightRange;
|
||||
typedef mozilla::intl::Script Script;
|
||||
|
||||
using AutoLock = mozilla::RecursiveMutexAutoLock;
|
||||
|
||||
// Class used to hold cached copies of the font-name prefs, so that they can
|
||||
// be accessed from non-main-thread callers who are not allowed to touch the
|
||||
// Preferences service.
|
||||
|
@ -265,7 +267,11 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
// but not completely invalidated.
|
||||
void UpdateFontList(bool aFullRebuild = true);
|
||||
|
||||
virtual void ClearLangGroupPrefFonts();
|
||||
void ClearLangGroupPrefFonts() {
|
||||
AutoLock lock(mLock);
|
||||
ClearLangGroupPrefFontsLocked();
|
||||
}
|
||||
virtual void ClearLangGroupPrefFontsLocked() REQUIRES(mLock);
|
||||
|
||||
void GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily>>& aFamilyArray);
|
||||
|
||||
|
@ -307,15 +313,25 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
// Find family(ies) matching aFamily and append to the aOutput array
|
||||
// (there may be multiple results in the case of fontconfig aliases, etc).
|
||||
// Return true if any match was found and appended, false if none.
|
||||
virtual bool FindAndAddFamilies(
|
||||
bool FindAndAddFamilies(
|
||||
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGeneric,
|
||||
const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
|
||||
FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr,
|
||||
nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0);
|
||||
nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0) {
|
||||
AutoLock lock(mLock);
|
||||
return FindAndAddFamiliesLocked(aPresContext, aGeneric, aFamily, aOutput,
|
||||
aFlags, aStyle, aLanguage, aDevToCssSize);
|
||||
}
|
||||
virtual bool FindAndAddFamiliesLocked(
|
||||
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGeneric,
|
||||
const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
|
||||
FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr,
|
||||
nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0)
|
||||
REQUIRES(mLock);
|
||||
|
||||
gfxFontEntry* FindFontForFamily(nsPresContext* aPresContext,
|
||||
const nsACString& aFamily,
|
||||
const gfxFontStyle* aStyle);
|
||||
const gfxFontStyle* aStyle) REQUIRES(mLock);
|
||||
|
||||
mozilla::fontlist::FontList* SharedFontList() const {
|
||||
return mSharedFontList.get();
|
||||
|
@ -371,13 +387,24 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
|
||||
// name lookup table methods
|
||||
|
||||
void AddOtherFamilyName(gfxFontFamily* aFamilyEntry,
|
||||
const nsCString& aOtherFamilyName);
|
||||
void AddOtherFamilyNames(gfxFontFamily* aFamilyEntry,
|
||||
const nsTArray<nsCString>& aOtherFamilyNames);
|
||||
|
||||
void AddFullname(gfxFontEntry* aFontEntry, const nsCString& aFullname);
|
||||
void AddFullname(gfxFontEntry* aFontEntry, const nsCString& aFullname) {
|
||||
AutoLock lock(mLock);
|
||||
AddFullnameLocked(aFontEntry, aFullname);
|
||||
}
|
||||
void AddFullnameLocked(gfxFontEntry* aFontEntry, const nsCString& aFullname)
|
||||
REQUIRES(mLock);
|
||||
|
||||
void AddPostscriptName(gfxFontEntry* aFontEntry,
|
||||
const nsCString& aPostscriptName);
|
||||
const nsCString& aPostscriptName) {
|
||||
AutoLock lock(mLock);
|
||||
AddPostscriptNameLocked(aFontEntry, aPostscriptName);
|
||||
}
|
||||
void AddPostscriptNameLocked(gfxFontEntry* aFontEntry,
|
||||
const nsCString& aPostscriptName)
|
||||
REQUIRES(mLock);
|
||||
|
||||
bool NeedFullnamePostscriptNames() { return mExtraNames != nullptr; }
|
||||
|
||||
|
@ -400,10 +427,15 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
// get the system default font family
|
||||
FontFamily GetDefaultFont(nsPresContext* aPresContext,
|
||||
const gfxFontStyle* aStyle);
|
||||
FontFamily GetDefaultFontLocked(nsPresContext* aPresContext,
|
||||
const gfxFontStyle* aStyle) REQUIRES(mLock);
|
||||
|
||||
// get the "ultimate" default font, for use if the font list is otherwise
|
||||
// unusable (e.g. in the middle of being updated)
|
||||
gfxFontEntry* GetDefaultFontEntry() { return mDefaultFontEntry.get(); }
|
||||
gfxFontEntry* GetDefaultFontEntry() {
|
||||
AutoLock lock(mLock);
|
||||
return mDefaultFontEntry.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up a font by name on the host platform.
|
||||
|
@ -456,24 +488,28 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
FontListSizes* aSizes) const;
|
||||
|
||||
mozilla::fontlist::Pointer GetShmemCharMap(const gfxSparseBitSet* aCmap);
|
||||
mozilla::fontlist::Pointer GetShmemCharMap(const gfxSparseBitSet* aCmap) {
|
||||
AutoLock lock(mLock);
|
||||
return GetShmemCharMapLocked(aCmap);
|
||||
}
|
||||
mozilla::fontlist::Pointer GetShmemCharMapLocked(const gfxSparseBitSet* aCmap)
|
||||
REQUIRES(mLock);
|
||||
|
||||
// search for existing cmap that matches the input
|
||||
// return the input if no match is found
|
||||
// Search for existing cmap that matches the input; return the input if no
|
||||
// match is found.
|
||||
gfxCharacterMap* FindCharMap(gfxCharacterMap* aCmap);
|
||||
|
||||
// add a cmap to the shared cmap set
|
||||
gfxCharacterMap* AddCmap(const gfxCharacterMap* aCharMap);
|
||||
|
||||
// remove the cmap from the shared cmap set
|
||||
// Remove the cmap from the shared cmap set.
|
||||
void RemoveCmap(const gfxCharacterMap* aCharMap);
|
||||
|
||||
// keep track of userfont sets to notify when global fontlist changes occur
|
||||
// Keep track of userfont sets to notify when global fontlist changes occur.
|
||||
void AddUserFontSet(gfxUserFontSet* aUserFontSet) {
|
||||
AutoLock lock(mLock);
|
||||
mUserFontSetList.Insert(aUserFontSet);
|
||||
}
|
||||
|
||||
void RemoveUserFontSet(gfxUserFontSet* aUserFontSet) {
|
||||
AutoLock lock(mLock);
|
||||
mUserFontSetList.Remove(aUserFontSet);
|
||||
}
|
||||
|
||||
|
@ -496,15 +532,32 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
* make one, and adds it to the cache.
|
||||
*/
|
||||
gfxFontEntry* GetOrCreateFontEntry(mozilla::fontlist::Face* aFace,
|
||||
const mozilla::fontlist::Family* aFamily);
|
||||
const mozilla::fontlist::Family* aFamily) {
|
||||
AutoLock lock(mLock);
|
||||
return GetOrCreateFontEntryLocked(aFace, aFamily);
|
||||
}
|
||||
gfxFontEntry* GetOrCreateFontEntryLocked(
|
||||
mozilla::fontlist::Face* aFace, const mozilla::fontlist::Family* aFamily)
|
||||
REQUIRES(mLock);
|
||||
|
||||
const FontPrefs* GetFontPrefs() const { return mFontPrefs.get(); }
|
||||
const FontPrefs* GetFontPrefs() const REQUIRES(mLock) {
|
||||
return mFontPrefs.get();
|
||||
}
|
||||
|
||||
bool EmojiPrefHasUserValue() const { return mFontPrefs->EmojiHasUserValue(); }
|
||||
bool EmojiPrefHasUserValue() const {
|
||||
AutoLock lock(mLock);
|
||||
return mFontPrefs->EmojiHasUserValue();
|
||||
}
|
||||
|
||||
PrefFontList* GetPrefFontsLangGroup(
|
||||
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGenericType,
|
||||
eFontPrefLang aPrefLang);
|
||||
eFontPrefLang aPrefLang) {
|
||||
AutoLock lock(mLock);
|
||||
return GetPrefFontsLangGroupLocked(aPresContext, aGenericType, aPrefLang);
|
||||
}
|
||||
PrefFontList* GetPrefFontsLangGroupLocked(
|
||||
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGenericType,
|
||||
eFontPrefLang aPrefLang) REQUIRES(mLock);
|
||||
|
||||
// in some situations, need to make decisions about ambiguous characters, may
|
||||
// need to look at multiple pref langs
|
||||
|
@ -555,6 +608,7 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
mozilla::StyleGenericFontFamily aGenericType);
|
||||
|
||||
bool SkipFontFallbackForChar(FontVisibility aVisibility, uint32_t aCh) const {
|
||||
AutoLock lock(mLock);
|
||||
return mCodepointsWithNoFonts[aVisibility].test(aCh);
|
||||
}
|
||||
|
||||
|
@ -566,7 +620,7 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
FontVisibility aVisibility) const;
|
||||
|
||||
// (Re-)initialize the set of codepoints that we know cannot be rendered.
|
||||
void InitializeCodepointsWithNoFonts();
|
||||
void InitializeCodepointsWithNoFonts() REQUIRES(mLock);
|
||||
|
||||
// If using the shared font list, returns a generation count that is
|
||||
// incremented if/when the platform list is reinitialized (e.g. because
|
||||
|
@ -581,6 +635,13 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
return PR_GetCurrentThread() == sInitFontListThread;
|
||||
}
|
||||
|
||||
void Lock() CAPABILITY_ACQUIRE(mLock) { mLock.Lock(); }
|
||||
void Unlock() CAPABILITY_RELEASE(mLock) { mLock.Unlock(); }
|
||||
|
||||
// This is only public because some external callers want to be able to
|
||||
// assert about the locked status.
|
||||
mutable mozilla::RecursiveMutex mLock;
|
||||
|
||||
protected:
|
||||
friend class mozilla::fontlist::FontList;
|
||||
friend class InitOtherFamilyNamesForStylo;
|
||||
|
@ -680,20 +741,20 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
nsPresContext* aPresContext, const nsACString& aFamily,
|
||||
FindFamiliesFlags aFlags = FindFamiliesFlags(0),
|
||||
gfxFontStyle* aStyle = nullptr, nsAtom* aLanguage = nullptr,
|
||||
gfxFloat aDevToCssSize = 1.0);
|
||||
gfxFloat aDevToCssSize = 1.0) REQUIRES(mLock);
|
||||
|
||||
gfxFontFamily* FindUnsharedFamily(
|
||||
nsPresContext* aPresContext, const nsACString& aFamily,
|
||||
FindFamiliesFlags aFlags = FindFamiliesFlags(0),
|
||||
gfxFontStyle* aStyle = nullptr, nsAtom* aLanguage = nullptr,
|
||||
gfxFloat aDevToCssSize = 1.0) {
|
||||
gfxFloat aDevToCssSize = 1.0) REQUIRES(mLock) {
|
||||
if (SharedFontList()) {
|
||||
return nullptr;
|
||||
}
|
||||
AutoTArray<FamilyAndGeneric, 1> families;
|
||||
if (FindAndAddFamilies(aPresContext, mozilla::StyleGenericFontFamily::None,
|
||||
aFamily, &families, aFlags, aStyle, aLanguage,
|
||||
aDevToCssSize)) {
|
||||
if (FindAndAddFamiliesLocked(
|
||||
aPresContext, mozilla::StyleGenericFontFamily::None, aFamily,
|
||||
&families, aFlags, aStyle, aLanguage, aDevToCssSize)) {
|
||||
return families[0].mFamily.mUnshared;
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -703,7 +764,7 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
FindFamiliesFlags aFlags = FindFamiliesFlags(0),
|
||||
gfxFontStyle* aStyle = nullptr,
|
||||
nsAtom* aLanguage = nullptr,
|
||||
gfxFloat aDevToCssSize = 1.0) {
|
||||
gfxFloat aDevToCssSize = 1.0) REQUIRES(mLock) {
|
||||
if (SharedFontList()) {
|
||||
return FontFamily(FindSharedFamily(aPresContext, aFamily, aFlags, aStyle,
|
||||
aLanguage, aDevToCssSize));
|
||||
|
@ -714,7 +775,8 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
|
||||
// Lookup family name in global family list without substitutions or
|
||||
// localized family name lookup. Used for common font fallback families.
|
||||
gfxFontFamily* FindFamilyByCanonicalName(const nsACString& aFamily) {
|
||||
gfxFontFamily* FindFamilyByCanonicalName(const nsACString& aFamily)
|
||||
REQUIRES(mLock) {
|
||||
nsAutoCString key;
|
||||
gfxFontFamily* familyEntry;
|
||||
GenerateFontListKey(aFamily, key);
|
||||
|
@ -729,14 +791,15 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
uint32_t aNextCh, Script aRunScript,
|
||||
eFontPresentation aPresentation,
|
||||
const gfxFontStyle* aMatchStyle,
|
||||
FontFamily& aMatchedFamily);
|
||||
FontFamily& aMatchedFamily) REQUIRES(mLock);
|
||||
|
||||
// Search fonts system-wide for a given character, null if not found.
|
||||
gfxFont* GlobalFontFallback(nsPresContext* aPresContext, uint32_t aCh,
|
||||
uint32_t aNextCh, Script aRunScript,
|
||||
eFontPresentation aPresentation,
|
||||
const gfxFontStyle* aMatchStyle,
|
||||
uint32_t& aCmapCount, FontFamily& aMatchedFamily);
|
||||
uint32_t& aCmapCount, FontFamily& aMatchedFamily)
|
||||
REQUIRES(mLock);
|
||||
|
||||
// Platform-specific implementation of global font fallback, if any;
|
||||
// this may return nullptr in which case the default cmap-based fallback
|
||||
|
@ -752,45 +815,52 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
virtual bool UsesSystemFallback() { return false; }
|
||||
|
||||
void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t& aLen,
|
||||
eFontPrefLang aCharLang, eFontPrefLang aPageLang);
|
||||
eFontPrefLang aCharLang, eFontPrefLang aPageLang)
|
||||
REQUIRES(mLock);
|
||||
|
||||
// verifies that a family contains a non-zero font count
|
||||
gfxFontFamily* CheckFamily(gfxFontFamily* aFamily);
|
||||
gfxFontFamily* CheckFamily(gfxFontFamily* aFamily) REQUIRES(mLock);
|
||||
|
||||
// initialize localized family names
|
||||
void InitOtherFamilyNamesInternal(bool aDeferOtherFamilyNamesLoading);
|
||||
void CancelInitOtherFamilyNamesTask();
|
||||
|
||||
void AddToMissedNames(const nsCString& aKey) REQUIRES(mLock);
|
||||
|
||||
// search through font families, looking for a given name, initializing
|
||||
// facename lists along the way. first checks all families with names
|
||||
// close to face name, then searchs all families if not found.
|
||||
gfxFontEntry* SearchFamiliesForFaceName(const nsACString& aFaceName);
|
||||
gfxFontEntry* SearchFamiliesForFaceName(const nsACString& aFaceName)
|
||||
REQUIRES(mLock);
|
||||
|
||||
// helper method for finding fullname/postscript names in facename lists
|
||||
gfxFontEntry* FindFaceName(const nsACString& aFaceName);
|
||||
gfxFontEntry* FindFaceName(const nsACString& aFaceName) REQUIRES(mLock);
|
||||
|
||||
// look up a font by name, for cases where platform font list
|
||||
// maintains explicit mappings of fullname/psname ==> font
|
||||
virtual gfxFontEntry* LookupInFaceNameLists(const nsACString& aFontName);
|
||||
virtual gfxFontEntry* LookupInFaceNameLists(const nsACString& aFaceName)
|
||||
REQUIRES(mLock);
|
||||
|
||||
gfxFontEntry* LookupInSharedFaceNameList(nsPresContext* aPresContext,
|
||||
const nsACString& aFaceName,
|
||||
WeightRange aWeightForEntry,
|
||||
StretchRange aStretchForEntry,
|
||||
SlantStyleRange aStyleForEntry);
|
||||
SlantStyleRange aStyleForEntry)
|
||||
REQUIRES(mLock);
|
||||
|
||||
// load the bad underline blocklist from pref.
|
||||
void LoadBadUnderlineList();
|
||||
|
||||
void GenerateFontListKey(const nsACString& aKeyName, nsACString& aResult);
|
||||
|
||||
virtual void GetFontFamilyNames(nsTArray<nsCString>& aFontFamilyNames);
|
||||
virtual void GetFontFamilyNames(nsTArray<nsCString>& aFontFamilyNames)
|
||||
REQUIRES(mLock);
|
||||
|
||||
// helper function to map lang to lang group
|
||||
nsAtom* GetLangGroup(nsAtom* aLanguage);
|
||||
|
||||
// gfxFontInfoLoader overrides, used to load in font cmaps
|
||||
void InitLoader() override;
|
||||
void InitLoader() REQUIRES(mLock) override;
|
||||
bool LoadFontInfo() override;
|
||||
void CleanupLoader() override;
|
||||
|
||||
|
@ -800,23 +870,23 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
// If aForgetLocalFaces is true, all gfxFontEntries for src:local fonts must
|
||||
// be discarded (not potentially reused to satisfy the rebuilt rules),
|
||||
// because they may no longer be valid.
|
||||
void RebuildLocalFonts(bool aForgetLocalFaces = false);
|
||||
void RebuildLocalFonts(bool aForgetLocalFaces = false) REQUIRES(mLock);
|
||||
|
||||
void ResolveGenericFontNames(nsPresContext* aPresContext,
|
||||
mozilla::StyleGenericFontFamily aGenericType,
|
||||
eFontPrefLang aPrefLang,
|
||||
PrefFontList* aGenericFamilies);
|
||||
PrefFontList* aGenericFamilies) REQUIRES(mLock);
|
||||
|
||||
void ResolveEmojiFontNames(nsPresContext* aPresContext,
|
||||
PrefFontList* aGenericFamilies);
|
||||
PrefFontList* aGenericFamilies) REQUIRES(mLock);
|
||||
|
||||
void GetFontFamiliesFromGenericFamilies(
|
||||
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGenericType,
|
||||
nsTArray<nsCString>& aGenericNameFamilies, nsAtom* aLangGroup,
|
||||
PrefFontList* aFontFamilies);
|
||||
PrefFontList* aFontFamilies) REQUIRES(mLock);
|
||||
|
||||
virtual nsresult InitFontListForPlatform() = 0;
|
||||
virtual void InitSharedFontListForPlatform() {}
|
||||
virtual nsresult InitFontListForPlatform() REQUIRES(mLock) = 0;
|
||||
virtual void InitSharedFontListForPlatform() REQUIRES(mLock) {}
|
||||
|
||||
virtual gfxFontEntry* CreateFontEntry(
|
||||
mozilla::fontlist::Face* aFace,
|
||||
|
@ -831,7 +901,7 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
* There are separate implementations of this for the per-process font list
|
||||
* and for the shared-memory font list.
|
||||
*/
|
||||
void ApplyWhitelist();
|
||||
void ApplyWhitelist() REQUIRES(mLock);
|
||||
void ApplyWhitelist(nsTArray<mozilla::fontlist::Family::InitData>& aFamilies);
|
||||
|
||||
// Create a new gfxFontFamily of the appropriate subclass for the platform,
|
||||
|
@ -850,7 +920,8 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
* case this method is unused.
|
||||
*/
|
||||
virtual void ReadFaceNamesForFamily(mozilla::fontlist::Family* aFamily,
|
||||
bool aNeedFullnamePostscriptNames) {}
|
||||
bool aNeedFullnamePostscriptNames)
|
||||
REQUIRES(mLock) {}
|
||||
|
||||
typedef nsRefPtrHashtable<nsCStringHashKey, gfxFontFamily> FontFamilyTable;
|
||||
typedef nsRefPtrHashtable<nsCStringHashKey, gfxFontEntry> FontEntryTable;
|
||||
|
@ -864,26 +935,24 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
// Platform-specific helper for GetDefaultFont(...).
|
||||
virtual FontFamily GetDefaultFontForPlatform(nsPresContext* aPresContext,
|
||||
const gfxFontStyle* aStyle,
|
||||
nsAtom* aLanguage = nullptr) = 0;
|
||||
|
||||
// Protects mFontFamilies.
|
||||
mozilla::Mutex mFontFamiliesMutex MOZ_UNANNOTATED;
|
||||
nsAtom* aLanguage = nullptr)
|
||||
REQUIRES(mLock) = 0;
|
||||
|
||||
// canonical family name ==> family entry (unique, one name per family entry)
|
||||
FontFamilyTable mFontFamilies;
|
||||
FontFamilyTable mFontFamilies GUARDED_BY(mLock);
|
||||
|
||||
// other family name ==> family entry (not unique, can have multiple names per
|
||||
// family entry, only names *other* than the canonical names are stored here)
|
||||
FontFamilyTable mOtherFamilyNames;
|
||||
FontFamilyTable mOtherFamilyNames GUARDED_BY(mLock);
|
||||
|
||||
// flag set after InitOtherFamilyNames is called upon first name lookup miss
|
||||
bool mOtherFamilyNamesInitialized = false;
|
||||
mozilla::Atomic<bool> mOtherFamilyNamesInitialized;
|
||||
|
||||
// The pending InitOtherFamilyNames() task.
|
||||
RefPtr<mozilla::CancelableRunnable> mPendingOtherFamilyNameTask;
|
||||
|
||||
// flag set after fullname and Postcript name lists are populated
|
||||
bool mFaceNameListsInitialized = false;
|
||||
mozilla::Atomic<bool> mFaceNameListsInitialized;
|
||||
|
||||
struct ExtraNames {
|
||||
ExtraNames() = default;
|
||||
|
@ -893,13 +962,16 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
// Postscript name ==> font entry (unique, one name per font entry)
|
||||
FontEntryTable mPostscriptNames{64};
|
||||
};
|
||||
mozilla::UniquePtr<ExtraNames> mExtraNames;
|
||||
// The lock is needed to guard access to the actual name tables, but does not
|
||||
// need to be held to just test whether mExtraNames is non-null as it is set
|
||||
// during initialization before other threads have a chance to see it.
|
||||
mozilla::UniquePtr<ExtraNames> mExtraNames PT_GUARDED_BY(mLock);
|
||||
|
||||
// face names missed when face name loading takes a long time
|
||||
mozilla::UniquePtr<nsTHashSet<nsCString>> mFaceNamesMissed;
|
||||
mozilla::UniquePtr<nsTHashSet<nsCString>> mFaceNamesMissed GUARDED_BY(mLock);
|
||||
|
||||
// localized family names missed when face name loading takes a long time
|
||||
mozilla::UniquePtr<nsTHashSet<nsCString>> mOtherNamesMissed;
|
||||
mozilla::UniquePtr<nsTHashSet<nsCString>> mOtherNamesMissed GUARDED_BY(mLock);
|
||||
|
||||
typedef mozilla::RangedArray<mozilla::UniquePtr<PrefFontList>,
|
||||
size_t(mozilla::StyleGenericFontFamily::None),
|
||||
|
@ -908,28 +980,28 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
PrefFontsForLangGroup;
|
||||
mozilla::RangedArray<PrefFontsForLangGroup, eFontPrefLang_First,
|
||||
eFontPrefLang_Count>
|
||||
mLangGroupPrefFonts;
|
||||
mozilla::UniquePtr<PrefFontList> mEmojiPrefFont;
|
||||
mLangGroupPrefFonts GUARDED_BY(mLock);
|
||||
mozilla::UniquePtr<PrefFontList> mEmojiPrefFont GUARDED_BY(mLock);
|
||||
|
||||
// When system-wide font lookup fails for a character, cache it to skip future
|
||||
// searches. This is an array of bitsets, one for each FontVisibility level.
|
||||
mozilla::EnumeratedArray<FontVisibility, FontVisibility::Count,
|
||||
gfxSparseBitSet>
|
||||
mCodepointsWithNoFonts;
|
||||
mCodepointsWithNoFonts GUARDED_BY(mLock);
|
||||
|
||||
// the family to use for U+FFFD fallback, to avoid expensive search every time
|
||||
// on pages with lots of problems
|
||||
mozilla::EnumeratedArray<FontVisibility, FontVisibility::Count, FontFamily>
|
||||
mReplacementCharFallbackFamily;
|
||||
mReplacementCharFallbackFamily GUARDED_BY(mLock);
|
||||
|
||||
// Sorted array of lowercased family names; use ContainsSorted to test
|
||||
nsTArray<nsCString> mBadUnderlineFamilyNames;
|
||||
|
||||
// character map data shared across families
|
||||
// contains weak ptrs to cmaps shared by font entry objects
|
||||
nsTHashtable<CharMapHashKey> mSharedCmaps;
|
||||
nsTHashtable<CharMapHashKey> mSharedCmaps GUARDED_BY(mLock);
|
||||
|
||||
nsTHashtable<ShmemCharMapHashEntry> mShmemCharMaps;
|
||||
nsTHashtable<ShmemCharMapHashEntry> mShmemCharMaps GUARDED_BY(mLock);
|
||||
|
||||
// data used as part of the font cmap loading process
|
||||
nsTArray<RefPtr<gfxFontFamily>> mFontFamiliesToLoad;
|
||||
|
@ -940,12 +1012,13 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
// see bugs 636957, 1070983, 1189129
|
||||
uint32_t mFontlistInitCount = 0; // num times InitFontList called
|
||||
|
||||
nsTHashSet<gfxUserFontSet*> mUserFontSetList;
|
||||
nsTHashSet<gfxUserFontSet*> mUserFontSetList GUARDED_BY(mLock);
|
||||
|
||||
nsLanguageAtomService* mLangService = nullptr;
|
||||
|
||||
nsTArray<uint32_t> mCJKPrefLangs;
|
||||
nsTArray<mozilla::StyleGenericFontFamily> mDefaultGenericsLangGroup;
|
||||
nsTArray<uint32_t> mCJKPrefLangs GUARDED_BY(mLock);
|
||||
nsTArray<mozilla::StyleGenericFontFamily> mDefaultGenericsLangGroup
|
||||
GUARDED_BY(mLock);
|
||||
|
||||
nsTArray<nsCString> mEnabledFontsList;
|
||||
|
||||
|
@ -956,11 +1029,11 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||
mLocalNameTable;
|
||||
|
||||
nsRefPtrHashtable<nsPtrHashKey<mozilla::fontlist::Face>, gfxFontEntry>
|
||||
mFontEntries;
|
||||
mFontEntries GUARDED_BY(mLock);
|
||||
|
||||
mozilla::UniquePtr<FontPrefs> mFontPrefs;
|
||||
|
||||
RefPtr<gfxFontEntry> mDefaultFontEntry;
|
||||
RefPtr<gfxFontEntry> mDefaultFontEntry GUARDED_BY(mLock);
|
||||
|
||||
RefPtr<mozilla::CancelableRunnable> mLoadCmapsRunnable;
|
||||
uint32_t mStartedLoadingCmapsFrom = 0xffffffffu;
|
||||
|
|
|
@ -172,6 +172,7 @@ class gfxUserFontFamily : public gfxFontFamily {
|
|||
|
||||
// add the given font entry to the end of the family's list
|
||||
void AddFontEntry(gfxFontEntry* aFontEntry) {
|
||||
mozilla::AutoWriteLock lock(mLock);
|
||||
MOZ_ASSERT(!mIsSimpleFamily, "not valid for user-font families");
|
||||
// keep ref while removing existing entry
|
||||
RefPtr<gfxFontEntry> fe = aFontEntry;
|
||||
|
@ -196,12 +197,16 @@ class gfxUserFontFamily : public gfxFontFamily {
|
|||
}
|
||||
|
||||
void RemoveFontEntry(gfxFontEntry* aFontEntry) {
|
||||
mozilla::AutoWriteLock lock(mLock);
|
||||
MOZ_ASSERT(!mIsSimpleFamily, "not valid for user-font families");
|
||||
mAvailableFonts.RemoveElement(aFontEntry);
|
||||
}
|
||||
|
||||
// Remove all font entries from the family
|
||||
void DetachFontEntries() { mAvailableFonts.Clear(); }
|
||||
void DetachFontEntries() {
|
||||
mozilla::AutoWriteLock lock(mLock);
|
||||
mAvailableFonts.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
class gfxUserFontEntry;
|
||||
|
|
|
@ -193,12 +193,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.2.25"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00"
|
||||
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||
dependencies = [
|
||||
"num",
|
||||
"libc",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -809,9 +812,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.68"
|
||||
version = "0.2.122"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
|
||||
checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
|
@ -948,17 +951,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.42"
|
||||
|
@ -1531,12 +1523,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.42"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"wasi",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
@ -1596,6 +1588,12 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.21.13"
|
||||
|
|
|
@ -17,7 +17,7 @@ log = "0.4"
|
|||
yaml-rust = "0.4"
|
||||
serde_json = "1.0"
|
||||
time = "0.1"
|
||||
chrono = "0.2"
|
||||
chrono = "0.4"
|
||||
crossbeam = "0.2"
|
||||
osmesa-sys = { version = "0.1.2", optional = true }
|
||||
osmesa-src = { version = "0.2", git = "https://github.com/servo/osmesa-src", optional = true }
|
||||
|
|
|
@ -16,28 +16,54 @@ implementing the trivial example visible in `EmptyUtil
|
|||
|
||||
- Define a new IPC actor, e.g., ``PEmptyUtil`` that allows to get some string
|
||||
via ``GetSomeString()`` from the child to the parent
|
||||
|
||||
- In the ``PUtilityProcess`` definition, expose a new child-level method,
|
||||
e.g., ``StartEmptyUtilService(Endpoint<PEmptyUtilChild>)``
|
||||
|
||||
- Implement ``EmptyUtilChild`` and ``EmptyUtilParent`` classes both deriving
|
||||
from their ``PEmptyUtilXX``. If you want or need to run things from a
|
||||
different thread, you can have a look at ``UtilityProcessGenericActor``
|
||||
|
||||
- Make sure both are refcounted
|
||||
|
||||
- Expose your new service on ``UtilityProcessManager`` with a method
|
||||
performing the heavy lifting of starting your process, you can take
|
||||
inspiration from ``StartEmptyUtil()`` there.
|
||||
inspiration from ``StartEmptyUtil()`` in the sample.
|
||||
|
||||
- Ideally, this starting method should rely on `StartUtility() <https://searchfox.org/mozilla-central/rev/fb511723f821ceabeea23b123f1c50c9e93bde9d/ipc/glue/UtilityProcessManager.cpp#210-258,266>`_
|
||||
|
||||
- To use ``StartUtility()`` mentioned above, please ensure that you provide
|
||||
a ``nsresult BindToUtilityProcess(RefPtr<UtilityProcessParent>
|
||||
aUtilityParent)``. Usually, it should be in charge of creating a set of
|
||||
endpoints and performing ``Bind()`` to setup the IPC. You can see some example for `Utility AudioDecoder <https://searchfox.org/mozilla-central/rev/4b3039b48c3cb67774270ebcc2a7d8624d888092/ipc/glue/UtilityAudioDecoderChild.h#31-51>`_
|
||||
|
||||
- For proper user-facing exposition in ``about:processes`` you will have to also provide an actor
|
||||
name via a method ``UtilityActorName GetActorName() { return UtilityActorName::EmptyUtil; }``
|
||||
|
||||
+ Add member within `enum WebIDLUtilityActorName in <https://searchfox.org/mozilla-central/rev/fb511723f821ceabeea23b123f1c50c9e93bde9d/dom/chrome-webidl/ChromeUtils.webidl#686-689>`_
|
||||
|
||||
+ Add member within `enum class UtilityActorName of <https://searchfox.org/mozilla-central/rev/fb511723f821ceabeea23b123f1c50c9e93bde9d/toolkit/components/processtools/ProcInfo.h#71-74>`_
|
||||
|
||||
+ Update mapping in `switch case <https://searchfox.org/mozilla-central/rev/fb511723f821ceabeea23b123f1c50c9e93bde9d/dom/base/ChromeUtils.cpp#916-919>`_ and update the `static assert <https://searchfox.org/mozilla-central/rev/fb511723f821ceabeea23b123f1c50c9e93bde9d/dom/base/ChromeUtils.cpp#910-911>`_
|
||||
|
||||
- Handle reception of ``StartEmptyUtilService`` on the child side of
|
||||
``UtilityProcess`` within ``RecvStartEmptyUtilService()``
|
||||
|
||||
- The specific sandboxing requirements can be implemented by tracking
|
||||
``SandboxingKind``, and it starts within `UtilityProcessSandboxing header
|
||||
<https://searchfox.org/mozilla-central/source/ipc/glue/UtilityProcessSandboxing.h>`_
|
||||
|
||||
- Try and make sure you at least add some ``gtest`` coverage of your new
|
||||
actor, for example like in `existing gtest
|
||||
<https://searchfox.org/mozilla-central/source/ipc/glue/test/gtest/TestUtilityProcess.cpp>`_
|
||||
|
||||
- Also ensure actual sandbox testing within
|
||||
|
||||
+ ``SandboxTest`` to start your new process,
|
||||
`<https://searchfox.org/mozilla-central/source/security/sandbox/common/test/SandboxTest.cpp>`_
|
||||
|
||||
+ ``SandboxTestingChildTests`` to define the test
|
||||
`<https://searchfox.org/mozilla-central/source/security/sandbox/common/test/SandboxTestingChildTests.h>`_
|
||||
|
||||
+ ``SandboxTestingChild`` to run your test
|
||||
`<https://searchfox.org/mozilla-central/source/security/sandbox/common/test/SandboxTestingChild.cpp>`_
|
||||
|
|
|
@ -1710,23 +1710,26 @@ static MOZ_ALWAYS_INLINE bool ValueToAtomOrSymbolPure(JSContext* cx,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
*id = AtomToId(atom);
|
||||
} else if (idVal.isSymbol()) {
|
||||
*id = PropertyKey::Symbol(idVal.toSymbol());
|
||||
} else {
|
||||
if (!ValueToIdPure(idVal, id)) {
|
||||
|
||||
// Watch out for integer ids because they may be stored in dense elements.
|
||||
static_assert(PropertyKey::IntMin == 0);
|
||||
static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT < PropertyKey::IntMax,
|
||||
"All dense elements must have integer jsids");
|
||||
uint32_t index;
|
||||
if (MOZ_UNLIKELY(atom->isIndex(&index) && index <= PropertyKey::IntMax)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*id = PropertyKey::NonIntAtom(atom);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Watch out for ids that may be stored in dense elements.
|
||||
static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT < PropertyKey::IntMax,
|
||||
"All dense elements must have integer jsids");
|
||||
if (MOZ_UNLIKELY(id->isInt())) {
|
||||
return false;
|
||||
if (idVal.isSymbol()) {
|
||||
*id = PropertyKey::Symbol(idVal.toSymbol());
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetNativeDataPropertyByValuePure(JSContext* cx, JSObject* obj, Value* vp) {
|
||||
|
|
|
@ -609,9 +609,6 @@ skip script test262/built-ins/RegExp/named-groups/non-unicode-property-names-val
|
|||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1761989
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors/no-species.js
|
||||
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1763605
|
||||
skip script test262/built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-no-throw.js
|
||||
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1763606
|
||||
skip script test262/built-ins/TypedArray/prototype/sort/sort-tonumber.js
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ if (typeof detachArrayBuffer === "function") {
|
|||
}
|
||||
}
|
||||
|
||||
// Test a TypeError is thrown when the typed array is detached and
|
||||
// Test no TypeError is thrown when the typed array is detached and
|
||||
// srcLength > 0.
|
||||
for (let {typedArray, buffer} of createTypedArrays()) {
|
||||
let source = {
|
||||
|
@ -130,8 +130,11 @@ if (typeof detachArrayBuffer === "function") {
|
|||
}
|
||||
}
|
||||
};
|
||||
let err = typedArray.length === 0 ? RangeError : TypeError;
|
||||
assertThrowsInstanceOf(() => typedArray.set(source), err);
|
||||
if (typedArray.length === 0) {
|
||||
assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
|
||||
} else {
|
||||
typedArray.set(source);
|
||||
}
|
||||
}
|
||||
|
||||
// Same as above, but with side-effect when executing Get(src, "0").
|
||||
|
@ -182,13 +185,17 @@ if (typeof detachArrayBuffer === "function") {
|
|||
}
|
||||
}
|
||||
});
|
||||
let err = typedArray.length === 0 ? RangeError : TypeError;
|
||||
assertThrowsInstanceOf(() => typedArray.set(source), err);
|
||||
if (typedArray.length === 0) {
|
||||
assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
|
||||
} else {
|
||||
typedArray.set(source);
|
||||
}
|
||||
}
|
||||
|
||||
// Side-effects when getting the source elements detach the buffer. Also
|
||||
// ensure other elements aren't accessed.
|
||||
// ensure other elements are accessed.
|
||||
for (let {typedArray, buffer} of createTypedArrays()) {
|
||||
let accessed = false;
|
||||
let source = Object.defineProperties([], {
|
||||
0: {
|
||||
get() {
|
||||
|
@ -198,12 +205,19 @@ if (typeof detachArrayBuffer === "function") {
|
|||
},
|
||||
1: {
|
||||
get() {
|
||||
throw new Error("Unexpected access");
|
||||
assertEq(accessed, false);
|
||||
accessed = true;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
});
|
||||
let err = typedArray.length <= 1 ? RangeError : TypeError;
|
||||
assertThrowsInstanceOf(() => typedArray.set(source), err);
|
||||
if (typedArray.length <= 1) {
|
||||
assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
|
||||
} else {
|
||||
assertEq(accessed, false);
|
||||
typedArray.set(source);
|
||||
assertEq(accessed, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Side-effects when converting the source elements detach the buffer.
|
||||
|
@ -214,13 +228,17 @@ if (typeof detachArrayBuffer === "function") {
|
|||
return 1;
|
||||
}
|
||||
}];
|
||||
let err = typedArray.length === 0 ? RangeError : TypeError;
|
||||
assertThrowsInstanceOf(() => typedArray.set(source), err);
|
||||
if (typedArray.length === 0) {
|
||||
assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
|
||||
} else {
|
||||
typedArray.set(source);
|
||||
}
|
||||
}
|
||||
|
||||
// Side-effects when converting the source elements detach the buffer. Also
|
||||
// ensure other elements aren't accessed.
|
||||
// ensure other elements are accessed.
|
||||
for (let {typedArray, buffer} of createTypedArrays()) {
|
||||
let accessed = false;
|
||||
let source = [{
|
||||
valueOf() {
|
||||
detachArrayBuffer(buffer);
|
||||
|
@ -228,11 +246,18 @@ if (typeof detachArrayBuffer === "function") {
|
|||
}
|
||||
}, {
|
||||
valueOf() {
|
||||
throw new Error("Unexpected access");
|
||||
assertEq(accessed, false);
|
||||
accessed = true;
|
||||
return 2;
|
||||
}
|
||||
}];
|
||||
let err = typedArray.length <= 1 ? RangeError : TypeError;
|
||||
assertThrowsInstanceOf(() => typedArray.set(source), err);
|
||||
if (typedArray.length <= 1) {
|
||||
assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
|
||||
} else {
|
||||
assertEq(accessed, false);
|
||||
typedArray.set(source);
|
||||
assertEq(accessed, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,17 +44,7 @@ ctors.forEach(function(TypedArray) {
|
|||
}
|
||||
};
|
||||
|
||||
var passed = false;
|
||||
try
|
||||
{
|
||||
ta.set(arraylike, 0x1234);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
passed = true;
|
||||
}
|
||||
|
||||
assertEq(passed, true);
|
||||
ta.set(arraylike, 0x1234);
|
||||
});
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -35,7 +35,7 @@ Object.defineProperty(src, 4, {
|
|||
}
|
||||
});
|
||||
|
||||
assertThrowsInstanceOf(() => a.set(src), TypeError);
|
||||
a.set(src);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "jsnum.h"
|
||||
|
||||
#include "gc/MaybeRooted.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/Runtime.h"
|
||||
#include "vm/StringType.h"
|
||||
|
||||
|
@ -34,42 +35,10 @@ MOZ_ALWAYS_INLINE jsid AtomToId(JSAtom* atom) {
|
|||
// Use the NameToId method instead!
|
||||
inline jsid AtomToId(PropertyName* name) = delete;
|
||||
|
||||
MOZ_ALWAYS_INLINE bool ValueToIntId(const Value& v, jsid* id) {
|
||||
int32_t i;
|
||||
if (v.isInt32()) {
|
||||
i = v.toInt32();
|
||||
} else if (!v.isDouble() || !mozilla::NumberEqualsInt32(v.toDouble(), &i)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!PropertyKey::fitsInInt(i)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*id = PropertyKey::Int(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ValueToIdPure(const Value& v, jsid* id) {
|
||||
if (v.isString()) {
|
||||
if (v.toString()->isAtom()) {
|
||||
*id = AtomToId(&v.toString()->asAtom());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ValueToIntId(v, id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (v.isSymbol()) {
|
||||
*id = PropertyKey::Symbol(v.toSymbol());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
template <AllowGC allowGC>
|
||||
extern bool PrimitiveValueToIdSlow(
|
||||
JSContext* cx, typename MaybeRooted<JS::Value, allowGC>::HandleType v,
|
||||
typename MaybeRooted<jsid, allowGC>::MutableHandleType idp);
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline bool PrimitiveValueToId(
|
||||
|
@ -79,28 +48,33 @@ inline bool PrimitiveValueToId(
|
|||
MOZ_ASSERT(v.isPrimitive());
|
||||
|
||||
if (v.isString()) {
|
||||
JSAtom* atom;
|
||||
if (v.toString()->isAtom()) {
|
||||
idp.set(AtomToId(&v.toString()->asAtom()));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (ValueToIntId(v, idp.address())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (v.isSymbol()) {
|
||||
idp.set(PropertyKey::Symbol(v.toSymbol()));
|
||||
return true;
|
||||
atom = &v.toString()->asAtom();
|
||||
} else {
|
||||
atom = AtomizeString(cx, v.toString());
|
||||
if (!atom) {
|
||||
if constexpr (!allowGC) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
idp.set(AtomToId(atom));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSAtom* atom = ToAtom<allowGC>(cx, v);
|
||||
if (!atom) {
|
||||
return false;
|
||||
if (v.isInt32()) {
|
||||
if (PropertyKey::fitsInInt(v.toInt32())) {
|
||||
idp.set(PropertyKey::Int(v.toInt32()));
|
||||
return true;
|
||||
}
|
||||
} else if (v.isSymbol()) {
|
||||
idp.set(PropertyKey::Symbol(v.toSymbol()));
|
||||
return true;
|
||||
}
|
||||
|
||||
idp.set(AtomToId(atom));
|
||||
return true;
|
||||
return PrimitiveValueToIdSlow<allowGC>(cx, v, idp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -955,6 +955,60 @@ bool js::IndexToIdSlow(JSContext* cx, uint32_t index, MutableHandleId idp) {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
static MOZ_ALWAYS_INLINE JSAtom* PrimitiveToAtom(JSContext* cx,
|
||||
const Value& v) {
|
||||
MOZ_ASSERT(v.isPrimitive());
|
||||
switch (v.type()) {
|
||||
case ValueType::String: {
|
||||
JSAtom* atom = AtomizeString(cx, v.toString());
|
||||
if (!allowGC && !atom) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
}
|
||||
return atom;
|
||||
}
|
||||
case ValueType::Int32: {
|
||||
JSAtom* atom = Int32ToAtom(cx, v.toInt32());
|
||||
if (!allowGC && !atom) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
}
|
||||
return atom;
|
||||
}
|
||||
case ValueType::Double: {
|
||||
JSAtom* atom = NumberToAtom(cx, v.toDouble());
|
||||
if (!allowGC && !atom) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
}
|
||||
return atom;
|
||||
}
|
||||
case ValueType::Boolean:
|
||||
return v.toBoolean() ? cx->names().true_ : cx->names().false_;
|
||||
case ValueType::Null:
|
||||
return cx->names().null;
|
||||
case ValueType::Undefined:
|
||||
return cx->names().undefined;
|
||||
case ValueType::Symbol:
|
||||
MOZ_ASSERT(!cx->isHelperThreadContext());
|
||||
if constexpr (allowGC) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SYMBOL_TO_STRING);
|
||||
}
|
||||
return nullptr;
|
||||
case ValueType::BigInt: {
|
||||
RootedBigInt i(cx, v.toBigInt());
|
||||
return BigIntToAtom<allowGC>(cx, i);
|
||||
}
|
||||
#ifdef ENABLE_RECORD_TUPLE
|
||||
case ValueType::ExtendedPrimitive:
|
||||
#endif
|
||||
case ValueType::Object:
|
||||
case ValueType::Magic:
|
||||
case ValueType::PrivateGCThing:
|
||||
break;
|
||||
}
|
||||
MOZ_CRASH("Unexpected type");
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
static JSAtom* ToAtomSlow(
|
||||
JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg) {
|
||||
|
@ -973,47 +1027,7 @@ static JSAtom* ToAtomSlow(
|
|||
v = v2;
|
||||
}
|
||||
|
||||
if (v.isString()) {
|
||||
JSAtom* atom = AtomizeString(cx, v.toString());
|
||||
if (!allowGC && !atom) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
}
|
||||
return atom;
|
||||
}
|
||||
if (v.isInt32()) {
|
||||
JSAtom* atom = Int32ToAtom(cx, v.toInt32());
|
||||
if (!allowGC && !atom) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
}
|
||||
return atom;
|
||||
}
|
||||
if (v.isDouble()) {
|
||||
JSAtom* atom = NumberToAtom(cx, v.toDouble());
|
||||
if (!allowGC && !atom) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
}
|
||||
return atom;
|
||||
}
|
||||
if (v.isBoolean()) {
|
||||
return v.toBoolean() ? cx->names().true_ : cx->names().false_;
|
||||
}
|
||||
if (v.isNull()) {
|
||||
return cx->names().null;
|
||||
}
|
||||
if (v.isSymbol()) {
|
||||
MOZ_ASSERT(!cx->isHelperThreadContext());
|
||||
if (allowGC) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SYMBOL_TO_STRING);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
if (v.isBigInt()) {
|
||||
RootedBigInt i(cx, v.toBigInt());
|
||||
return BigIntToAtom<allowGC>(cx, i);
|
||||
}
|
||||
MOZ_ASSERT(v.isUndefined());
|
||||
return cx->names().undefined;
|
||||
return PrimitiveToAtom<allowGC>(cx, v);
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
|
@ -1037,9 +1051,38 @@ JSAtom* js::ToAtom(JSContext* cx,
|
|||
}
|
||||
|
||||
template JSAtom* js::ToAtom<CanGC>(JSContext* cx, HandleValue v);
|
||||
|
||||
template JSAtom* js::ToAtom<NoGC>(JSContext* cx, const Value& v);
|
||||
|
||||
template <AllowGC allowGC>
|
||||
bool js::PrimitiveValueToIdSlow(
|
||||
JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType v,
|
||||
typename MaybeRooted<jsid, allowGC>::MutableHandleType idp) {
|
||||
MOZ_ASSERT(v.isPrimitive());
|
||||
MOZ_ASSERT(!v.isString());
|
||||
MOZ_ASSERT(!v.isSymbol());
|
||||
MOZ_ASSERT_IF(v.isInt32(), !PropertyKey::fitsInInt(v.toInt32()));
|
||||
|
||||
int32_t i;
|
||||
if (v.isDouble() && mozilla::NumberEqualsInt32(v.toDouble(), &i) &&
|
||||
PropertyKey::fitsInInt(i)) {
|
||||
idp.set(PropertyKey::Int(i));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSAtom* atom = PrimitiveToAtom<allowGC>(cx, v);
|
||||
if (!atom) {
|
||||
return false;
|
||||
}
|
||||
|
||||
idp.set(AtomToId(atom));
|
||||
return true;
|
||||
}
|
||||
|
||||
template bool js::PrimitiveValueToIdSlow<CanGC>(JSContext* cx, HandleValue v,
|
||||
MutableHandleId idp);
|
||||
template bool js::PrimitiveValueToIdSlow<NoGC>(JSContext* cx, const Value& v,
|
||||
FakeMutableHandle<jsid> idp);
|
||||
|
||||
#ifdef ENABLE_RECORD_TUPLE
|
||||
bool js::EnsureAtomized(JSContext* cx, MutableHandleValue v, bool* updated) {
|
||||
if (v.isString()) {
|
||||
|
|
|
@ -412,12 +412,15 @@ class ElementSpecific {
|
|||
size_t offset = 0) {
|
||||
MOZ_ASSERT(target->type() == TypeIDOfType<T>::id,
|
||||
"target type and NativeType must match");
|
||||
MOZ_ASSERT(!target->hasDetachedBuffer(), "target isn't detached");
|
||||
MOZ_ASSERT(!source->is<TypedArrayObject>(),
|
||||
"use setFromTypedArray instead of this method");
|
||||
MOZ_ASSERT_IF(target->hasDetachedBuffer(), target->length() == 0);
|
||||
MOZ_ASSERT_IF(!target->hasDetachedBuffer(), offset <= target->length());
|
||||
MOZ_ASSERT_IF(!target->hasDetachedBuffer(),
|
||||
len <= target->length() - offset);
|
||||
|
||||
size_t i = 0;
|
||||
if (source->is<NativeObject>()) {
|
||||
if (source->is<NativeObject>() && !target->hasDetachedBuffer()) {
|
||||
// Attempt fast-path infallible conversion of dense elements up to
|
||||
// the first potentially side-effectful lookup or conversion.
|
||||
size_t bound = std::min<size_t>(
|
||||
|
@ -459,11 +462,14 @@ class ElementSpecific {
|
|||
return false;
|
||||
}
|
||||
|
||||
len = std::min<size_t>(len, target->length());
|
||||
if (i >= len) {
|
||||
break;
|
||||
// Ignore out-of-bounds writes, but still execute getElement/valueToNative
|
||||
// because of observable side-effects.
|
||||
if (offset + i >= target->length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!target->hasDetachedBuffer());
|
||||
|
||||
// Compute every iteration in case getElement/valueToNative
|
||||
// detaches the underlying array buffer or GC moves the data.
|
||||
SharedMem<T*> dest =
|
||||
|
|
|
@ -1626,41 +1626,162 @@ static inline bool SetFromNonTypedArray(JSContext* cx,
|
|||
cx, target, source, len, offset);
|
||||
}
|
||||
|
||||
// ES2017 draft rev c57ef95c45a371f9c9485bb1c3881dbdc04524a2
|
||||
// 22.2.3.23 %TypedArray%.prototype.set ( overloaded [ , offset ] )
|
||||
// 22.2.3.23.1 %TypedArray%.prototype.set ( array [ , offset ] )
|
||||
// 22.2.3.23.2 %TypedArray%.prototype.set( typedArray [ , offset ] )
|
||||
// ES2023 draft rev 22cc56ab08fcab92a865978c0aa5c6f1d8ce250f
|
||||
// 23.2.3.24.1 SetTypedArrayFromTypedArray ( target, targetOffset, source )
|
||||
static bool SetTypedArrayFromTypedArray(JSContext* cx,
|
||||
Handle<TypedArrayObject*> target,
|
||||
double targetOffset,
|
||||
Handle<TypedArrayObject*> source) {
|
||||
// WARNING: |source| may be an unwrapped typed array from a different
|
||||
// compartment. Proceed with caution!
|
||||
|
||||
MOZ_ASSERT(targetOffset >= 0);
|
||||
|
||||
// Steps 1-2. (Performed in caller.)
|
||||
MOZ_ASSERT(!target->hasDetachedBuffer());
|
||||
|
||||
// Steps 4-5.
|
||||
if (source->hasDetachedBuffer()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_TYPED_ARRAY_DETACHED);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 3 (Reordered).
|
||||
size_t targetLength = target->length();
|
||||
|
||||
// Steps 13-14 (Split into two checks to provide better error messages).
|
||||
if (targetOffset > targetLength) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 14 (Cont'd).
|
||||
size_t offset = size_t(targetOffset);
|
||||
if (source->length() > targetLength - offset) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SOURCE_ARRAY_TOO_LONG);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 15.
|
||||
if (Scalar::isBigIntType(target->type()) !=
|
||||
Scalar::isBigIntType(source->type())) {
|
||||
JS_ReportErrorNumberASCII(
|
||||
cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_NOT_COMPATIBLE,
|
||||
source->getClass()->name, target->getClass()->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Steps 6-12, 16-24.
|
||||
switch (target->type()) {
|
||||
#define SET_FROM_TYPED_ARRAY(_, T, N) \
|
||||
case Scalar::N: \
|
||||
if (!SetFromTypedArray<T>(target, source, offset)) return false; \
|
||||
break;
|
||||
JS_FOR_EACH_TYPED_ARRAY(SET_FROM_TYPED_ARRAY)
|
||||
#undef SET_FROM_TYPED_ARRAY
|
||||
default:
|
||||
MOZ_CRASH("Unsupported TypedArray type");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ES2023 draft rev 22cc56ab08fcab92a865978c0aa5c6f1d8ce250f
|
||||
// 23.2.3.24.1 SetTypedArrayFromArrayLike ( target, targetOffset, source )
|
||||
static bool SetTypedArrayFromArrayLike(JSContext* cx,
|
||||
Handle<TypedArrayObject*> target,
|
||||
double targetOffset, HandleObject src) {
|
||||
MOZ_ASSERT(targetOffset >= 0);
|
||||
|
||||
// Steps 1-2. (Performed in caller.)
|
||||
MOZ_ASSERT(!target->hasDetachedBuffer());
|
||||
|
||||
// Step 3.
|
||||
// We can't reorder this step because side-effects in step 5 can detach the
|
||||
// underlying array buffer from the typed array.
|
||||
size_t targetLength = target->length();
|
||||
|
||||
// Step 4. (Performed in caller.)
|
||||
|
||||
// Step 5.
|
||||
uint64_t srcLength;
|
||||
if (!GetLengthProperty(cx, src, &srcLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Steps 6-7 (Split into two checks to provide better error messages).
|
||||
if (targetOffset > targetLength) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 7 (Cont'd).
|
||||
size_t offset = size_t(targetOffset);
|
||||
if (srcLength > targetLength - offset) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SOURCE_ARRAY_TOO_LONG);
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(srcLength <= targetLength);
|
||||
|
||||
// Steps 8-9.
|
||||
if (srcLength > 0) {
|
||||
switch (target->type()) {
|
||||
#define SET_FROM_NON_TYPED_ARRAY(_, T, N) \
|
||||
case Scalar::N: \
|
||||
if (!SetFromNonTypedArray<T>(cx, target, src, srcLength, offset)) \
|
||||
return false; \
|
||||
break;
|
||||
JS_FOR_EACH_TYPED_ARRAY(SET_FROM_NON_TYPED_ARRAY)
|
||||
#undef SET_FROM_NON_TYPED_ARRAY
|
||||
default:
|
||||
MOZ_CRASH("Unsupported TypedArray type");
|
||||
}
|
||||
}
|
||||
|
||||
// Step 10.
|
||||
return true;
|
||||
}
|
||||
|
||||
// ES2023 draft rev 22cc56ab08fcab92a865978c0aa5c6f1d8ce250f
|
||||
// 23.2.3.24 %TypedArray%.prototype.set ( source [ , offset ] )
|
||||
// 23.2.3.24.1 SetTypedArrayFromTypedArray ( target, targetOffset, source )
|
||||
// 23.2.3.24.2 SetTypedArrayFromArrayLike ( target, targetOffset, source )
|
||||
/* static */
|
||||
bool TypedArrayObject::set_impl(JSContext* cx, const CallArgs& args) {
|
||||
MOZ_ASSERT(TypedArrayObject::is(args.thisv()));
|
||||
|
||||
// Steps 1-5 (Validation performed as part of CallNonGenericMethod).
|
||||
// Steps 1-3 (Validation performed as part of CallNonGenericMethod).
|
||||
Rooted<TypedArrayObject*> target(
|
||||
cx, &args.thisv().toObject().as<TypedArrayObject>());
|
||||
|
||||
// Steps 6-7.
|
||||
// Steps 4-5.
|
||||
double targetOffset = 0;
|
||||
if (args.length() > 1) {
|
||||
// Step 6.
|
||||
// Step 4.
|
||||
if (!ToInteger(cx, args[1], &targetOffset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 7.
|
||||
// Step 5.
|
||||
if (targetOffset < 0) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Steps 8-9.
|
||||
// 23.2.3.24.1, steps 1-2.
|
||||
// 23.2.3.24.2, steps 1-2.
|
||||
if (target->hasDetachedBuffer()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_TYPED_ARRAY_DETACHED);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 22.2.3.23.1, step 15. (22.2.3.23.2 only applies if args[0] is a typed
|
||||
// 23.2.3.24.2, step 4. (23.2.3.24.1 only applies if args[0] is a typed
|
||||
// array, so it doesn't make a difference there to apply ToObject here.)
|
||||
RootedObject src(cx, ToObject(cx, args.get(0)));
|
||||
if (!src) {
|
||||
|
@ -1680,133 +1801,18 @@ bool TypedArrayObject::set_impl(JSContext* cx, const CallArgs& args) {
|
|||
}
|
||||
}
|
||||
|
||||
// Steps 6-7.
|
||||
if (srcTypedArray) {
|
||||
// Remaining steps of 22.2.3.23.2.
|
||||
|
||||
// WARNING: |srcTypedArray| may be an unwrapped typed array from a
|
||||
// different compartment. Proceed with caution!
|
||||
|
||||
// Steps 11-12.
|
||||
if (srcTypedArray->hasDetachedBuffer()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_TYPED_ARRAY_DETACHED);
|
||||
if (!SetTypedArrayFromTypedArray(cx, target, targetOffset, srcTypedArray)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 10 (Reordered).
|
||||
size_t targetLength = target->length();
|
||||
|
||||
// Step 22 (Split into two checks to provide better error messages).
|
||||
if (targetOffset > targetLength) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 22 (Cont'd).
|
||||
size_t offset = size_t(targetOffset);
|
||||
if (srcTypedArray->length() > targetLength - offset) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SOURCE_ARRAY_TOO_LONG);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Scalar::isBigIntType(target->type()) !=
|
||||
Scalar::isBigIntType(srcTypedArray->type())) {
|
||||
JS_ReportErrorNumberASCII(
|
||||
cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_NOT_COMPATIBLE,
|
||||
srcTypedArray->getClass()->name, target->getClass()->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Steps 13-21, 23-28.
|
||||
switch (target->type()) {
|
||||
#define SET_FROM_TYPED_ARRAY(_, T, N) \
|
||||
case Scalar::N: \
|
||||
if (!SetFromTypedArray<T>(target, srcTypedArray, offset)) return false; \
|
||||
break;
|
||||
JS_FOR_EACH_TYPED_ARRAY(SET_FROM_TYPED_ARRAY)
|
||||
#undef SET_FROM_TYPED_ARRAY
|
||||
default:
|
||||
MOZ_CRASH("Unsupported TypedArray type");
|
||||
}
|
||||
} else {
|
||||
// Remaining steps of 22.2.3.23.1.
|
||||
|
||||
// Step 10.
|
||||
// We can't reorder this step because side-effects in step 16 can
|
||||
// detach the underlying array buffer from the typed array.
|
||||
size_t targetLength = target->length();
|
||||
|
||||
// Step 16.
|
||||
uint64_t srcLength;
|
||||
if (!GetLengthProperty(cx, src, &srcLength)) {
|
||||
if (!SetTypedArrayFromArrayLike(cx, target, targetOffset, src)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 17 (Split into two checks to provide better error messages).
|
||||
if (targetOffset > targetLength) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 17 (Cont'd).
|
||||
size_t offset = size_t(targetOffset);
|
||||
if (srcLength > targetLength - offset) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SOURCE_ARRAY_TOO_LONG);
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(srcLength <= targetLength);
|
||||
|
||||
// Steps 11-14, 18-21.
|
||||
if (srcLength > 0) {
|
||||
// GetLengthProperty in step 16 can lead to the execution of user
|
||||
// code which may detach the buffer. Handle this case here to
|
||||
// ensure SetFromNonTypedArray is never called with a detached
|
||||
// buffer. We still need to execute steps 21.a-b for their
|
||||
// possible side-effects.
|
||||
if (target->hasDetachedBuffer()) {
|
||||
// Steps 21.a-b.
|
||||
RootedValue v(cx);
|
||||
if (!GetElement(cx, src, src, 0, &v)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!target->convertForSideEffect(cx, v)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 21.c.
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_TYPED_ARRAY_DETACHED);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (target->type()) {
|
||||
#define SET_FROM_NON_TYPED_ARRAY(_, T, N) \
|
||||
case Scalar::N: \
|
||||
if (!SetFromNonTypedArray<T>(cx, target, src, srcLength, offset)) \
|
||||
return false; \
|
||||
break;
|
||||
JS_FOR_EACH_TYPED_ARRAY(SET_FROM_NON_TYPED_ARRAY)
|
||||
#undef SET_FROM_NON_TYPED_ARRAY
|
||||
default:
|
||||
MOZ_CRASH("Unsupported TypedArray type");
|
||||
}
|
||||
|
||||
// Step 21.c.
|
||||
// SetFromNonTypedArray doesn't throw when the array buffer gets
|
||||
// detached.
|
||||
if (target->hasDetachedBuffer()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_TYPED_ARRAY_DETACHED);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 29/22.
|
||||
// Step 8.
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1493,12 +1493,14 @@ nsresult nsMathMLChar::StretchInternal(
|
|||
AutoTArray<nsCString, 16> mathFallbacks;
|
||||
nsAutoCString value;
|
||||
gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
|
||||
pfl->Lock();
|
||||
if (pfl->GetFontPrefs()->LookupName("serif.x-math"_ns, value)) {
|
||||
gfxFontUtils::ParseFontList(value, mathFallbacks);
|
||||
}
|
||||
if (pfl->GetFontPrefs()->LookupNameList("serif.x-math"_ns, value)) {
|
||||
gfxFontUtils::ParseFontList(value, mathFallbacks);
|
||||
}
|
||||
pfl->Unlock();
|
||||
InsertMathFallbacks(font.family.families, mathFallbacks);
|
||||
|
||||
#ifdef NOISY_SEARCH
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<!doctype html>
|
||||
<style>
|
||||
input { height: 4em; color: GrayText }
|
||||
</style>
|
||||
<input value="Autofill">
|
||||
<script>
|
||||
let input = SpecialPowers.wrap(document.querySelector("input"));
|
||||
SpecialPowers.wrap(window).windowUtils.addManuallyManagedState(input, "autofill");
|
||||
</script>
|
|
@ -0,0 +1,12 @@
|
|||
<!doctype html>
|
||||
<style>
|
||||
input { height: 4em }
|
||||
</style>
|
||||
<input value="Autofill">
|
||||
<script>
|
||||
let input = SpecialPowers.wrap(document.querySelector("input"));
|
||||
SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutofillField(input);
|
||||
input.getBoundingClientRect(); // previewValue setter depends on the reframe posted by markAsAutofillField() having being processed...
|
||||
input.previewValue = "Autofill";
|
||||
SpecialPowers.wrap(window).windowUtils.addManuallyManagedState(input, "-moz-autofill-preview");
|
||||
</script>
|
|
@ -17,6 +17,7 @@ fuzzy(0-1,0-500) needs-focus == select.html select-ref.html
|
|||
!= autofill-preview.html autofill-preview-blank.html
|
||||
!= autofill.html autofill-preview.html
|
||||
== autofill-prefilled-value.html autofill-preview.html
|
||||
== autofill-preview-line-height.html autofill-line-height.html
|
||||
|
||||
== pseudo-class-lock.html pseudo-class-lock-ref.html
|
||||
|
||||
|
|
|
@ -102,13 +102,6 @@ input {
|
|||
}
|
||||
}
|
||||
|
||||
input::-moz-text-control-editing-root,
|
||||
input::placeholder {
|
||||
word-wrap: normal;
|
||||
/* Make the line-height equal to the available height */
|
||||
line-height: -moz-block-height !important;
|
||||
}
|
||||
|
||||
textarea {
|
||||
display: inline-block;
|
||||
appearance: auto;
|
||||
|
@ -161,41 +154,6 @@ textarea > scrollbar {
|
|||
visibility: hidden;
|
||||
}
|
||||
|
||||
::-moz-text-control-preview {
|
||||
overflow: hidden;
|
||||
font-family: system-ui;
|
||||
}
|
||||
|
||||
:not(:-moz-autofill-preview)::-moz-text-control-editing-root,
|
||||
:placeholder-shown:not(:autofill)::placeholder,
|
||||
:autofill::-moz-text-control-preview {
|
||||
visibility: inherit;
|
||||
}
|
||||
|
||||
input::-moz-text-control-editing-root,
|
||||
input::placeholder,
|
||||
input::-moz-text-control-preview {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
input[type=password]::-moz-text-control-editing-root,
|
||||
input[type=password]::-moz-text-control-preview {
|
||||
/*
|
||||
* In password fields, any character should be put same direction. Otherwise,
|
||||
* caret position at typing tells everybody whether the character is an RTL
|
||||
* or an LTR character. Unfortunately, this makes odd rendering when bidi
|
||||
* text is unmasked.
|
||||
*/
|
||||
unicode-bidi: bidi-override;
|
||||
}
|
||||
|
||||
textarea::-moz-text-control-editing-root {
|
||||
scroll-behavior: inherit;
|
||||
overscroll-behavior: inherit;
|
||||
/* StyleAdjuster makes sure that the overflow value ends up being scrollable */
|
||||
overflow: inherit;
|
||||
}
|
||||
|
||||
::placeholder,
|
||||
::-moz-text-control-preview {
|
||||
/*
|
||||
|
@ -219,10 +177,47 @@ textarea::-moz-text-control-editing-root {
|
|||
user-select: none;
|
||||
}
|
||||
|
||||
::-moz-text-control-preview {
|
||||
font-family: system-ui;
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
opacity: 0.54;
|
||||
}
|
||||
|
||||
:not(:-moz-autofill-preview)::-moz-text-control-editing-root,
|
||||
:placeholder-shown:not(:autofill)::placeholder,
|
||||
:autofill::-moz-text-control-preview {
|
||||
visibility: inherit;
|
||||
}
|
||||
|
||||
input::placeholder,
|
||||
input::-moz-text-control-editing-root,
|
||||
input::-moz-text-control-preview {
|
||||
word-wrap: normal;
|
||||
white-space: pre;
|
||||
/* Make the line-height equal to the available height */
|
||||
line-height: -moz-block-height !important;
|
||||
}
|
||||
|
||||
input[type=password]::-moz-text-control-editing-root,
|
||||
input[type=password]::-moz-text-control-preview {
|
||||
/*
|
||||
* In password fields, any character should be put same direction. Otherwise,
|
||||
* caret position at typing tells everybody whether the character is an RTL
|
||||
* or an LTR character. Unfortunately, this makes odd rendering when bidi
|
||||
* text is unmasked.
|
||||
*/
|
||||
unicode-bidi: bidi-override;
|
||||
}
|
||||
|
||||
textarea::-moz-text-control-editing-root {
|
||||
scroll-behavior: inherit;
|
||||
overscroll-behavior: inherit;
|
||||
/* StyleAdjuster makes sure that the overflow value ends up being scrollable */
|
||||
overflow: inherit;
|
||||
}
|
||||
|
||||
input:read-write,
|
||||
textarea:read-write {
|
||||
-moz-user-modify: read-write !important;
|
||||
|
|
|
@ -145,14 +145,14 @@ class BrowsingContextModule extends Module {
|
|||
|
||||
/**
|
||||
* Returns a tree of all browsing contexts that are descendents of the
|
||||
* given context, or all top-level contexts when no parent is provided.
|
||||
* given context, or all top-level contexts when no root is provided.
|
||||
*
|
||||
* @param {Object=} options
|
||||
* @param {number=} maxDepth
|
||||
* Depth of the browsing context tree to traverse. If not specified
|
||||
* the whole tree is returned.
|
||||
* @param {string=} parent
|
||||
* Id of the parent browsing context.
|
||||
* @param {string=} root
|
||||
* Id of the root browsing context.
|
||||
*
|
||||
* @returns {BrowsingContextGetTreeResult}
|
||||
* Tree of browsing context information.
|
||||
|
@ -160,7 +160,7 @@ class BrowsingContextModule extends Module {
|
|||
* If the browsing context cannot be found.
|
||||
*/
|
||||
getTree(options = {}) {
|
||||
const { maxDepth = null, parent: parentId = null } = options;
|
||||
const { maxDepth = null, root: rootId = null } = options;
|
||||
|
||||
if (maxDepth !== null) {
|
||||
assert.positiveInteger(
|
||||
|
@ -170,16 +170,11 @@ class BrowsingContextModule extends Module {
|
|||
}
|
||||
|
||||
let contexts;
|
||||
if (parentId !== null) {
|
||||
// With a parent id specified return the context info for itself
|
||||
if (rootId !== null) {
|
||||
// With a root id specified return the context info for itself
|
||||
// and the full tree.
|
||||
|
||||
assert.string(
|
||||
parentId,
|
||||
`Expected "parent" to be a string, got ${parentId}`
|
||||
);
|
||||
|
||||
contexts = [this.#getBrowsingContext(parentId)];
|
||||
assert.string(rootId, `Expected "root" to be a string, got ${rootId}`);
|
||||
contexts = [this.#getBrowsingContext(rootId)];
|
||||
} else {
|
||||
// Return all top-level browsing contexts.
|
||||
contexts = TabManager.browsers.map(browser => browser.browsingContext);
|
||||
|
|
|
@ -372,17 +372,11 @@ class SendTab {
|
|||
}
|
||||
|
||||
async _decrypt(ciphertext) {
|
||||
let sendTabKeys = await this._getPersistedSendTabKeys();
|
||||
if (!sendTabKeys) {
|
||||
// If we lost the user's send tab keys for any reason,
|
||||
// `generateAndPersistEncryptedSendTabKeys` will regenerate the send tab keys,
|
||||
// persist them, then persist an encrypted bundle of the keys.
|
||||
// It should be impossible for us to hit this for new devices
|
||||
// this was added to recover users who hit Bug 1752609
|
||||
await this._generateAndPersistEncryptedSendTabKey();
|
||||
sendTabKeys = await this._getPersistedSendTabKeys();
|
||||
}
|
||||
let { privateKey, publicKey, authSecret } = sendTabKeys;
|
||||
let {
|
||||
privateKey,
|
||||
publicKey,
|
||||
authSecret,
|
||||
} = await this._getPersistedSendTabKeys();
|
||||
publicKey = urlsafeBase64Decode(publicKey);
|
||||
authSecret = urlsafeBase64Decode(authSecret);
|
||||
ciphertext = new Uint8Array(urlsafeBase64Decode(ciphertext));
|
||||
|
@ -468,7 +462,8 @@ class SendTab {
|
|||
|
||||
async getEncryptedSendTabKeys() {
|
||||
let encryptedSendTabKeys = await this._getPersistedEncryptedSendTabKey();
|
||||
if (!encryptedSendTabKeys) {
|
||||
const sendTabKeys = await this._getPersistedSendTabKeys();
|
||||
if (!encryptedSendTabKeys || !sendTabKeys) {
|
||||
log.info("Generating and persisting encrypted sendtab keys");
|
||||
// `_generateAndPersistEncryptedKeys` requires the sync key
|
||||
// which cannot be accessed if the login manager is locked
|
||||
|
|
|
@ -243,24 +243,8 @@ class FxAccountsDevice {
|
|||
log.info(
|
||||
`Got new device list: ${devices.map(d => d.id).join(", ")}`
|
||||
);
|
||||
// Check if our push registration previously succeeded and is still
|
||||
// good (although background device registration means it's possible
|
||||
// we'll be fetching the device list before we've actually
|
||||
// registered ourself!)
|
||||
// (For a missing subscription we check for an explicit 'null' -
|
||||
// both to help tests and as a safety valve - missing might mean
|
||||
// "no push available" for self-hosters or similar?)
|
||||
const ourDevice = devices.find(device => device.isCurrentDevice);
|
||||
if (
|
||||
ourDevice &&
|
||||
(ourDevice.pushCallback === null || ourDevice.pushEndpointExpired)
|
||||
) {
|
||||
log.warn(`Our push endpoint needs resubscription`);
|
||||
await this._fxai.fxaPushService.unsubscribe();
|
||||
await this._registerOrUpdateDevice(currentState, accountData);
|
||||
// and there's a reasonable chance there are commands waiting.
|
||||
await this._fxai.commands.pollDeviceCommands();
|
||||
}
|
||||
|
||||
await this._refreshRemoteDevice(currentState, accountData, devices);
|
||||
return devices;
|
||||
}
|
||||
);
|
||||
|
@ -279,6 +263,33 @@ class FxAccountsDevice {
|
|||
return this._fetchAndCacheDeviceListPromise;
|
||||
}
|
||||
|
||||
async _refreshRemoteDevice(currentState, accountData, remoteDevices) {
|
||||
// Check if our push registration previously succeeded and is still
|
||||
// good (although background device registration means it's possible
|
||||
// we'll be fetching the device list before we've actually
|
||||
// registered ourself!)
|
||||
// (For a missing subscription we check for an explicit 'null' -
|
||||
// both to help tests and as a safety valve - missing might mean
|
||||
// "no push available" for self-hosters or similar?)
|
||||
const ourDevice = remoteDevices.find(device => device.isCurrentDevice);
|
||||
if (
|
||||
ourDevice &&
|
||||
(ourDevice.pushCallback === null || ourDevice.pushEndpointExpired)
|
||||
) {
|
||||
log.warn(`Our push endpoint needs resubscription`);
|
||||
await this._fxai.fxaPushService.unsubscribe();
|
||||
await this._registerOrUpdateDevice(currentState, accountData);
|
||||
// and there's a reasonable chance there are commands waiting.
|
||||
await this._fxai.commands.pollDeviceCommands();
|
||||
} else if (
|
||||
ourDevice &&
|
||||
(await this._checkRemoteCommandsUpdateNeeded(ourDevice.availableCommands))
|
||||
) {
|
||||
log.warn(`Our commands need to be updated on the server`);
|
||||
await this._registerOrUpdateDevice(currentState, accountData);
|
||||
}
|
||||
}
|
||||
|
||||
async updateDeviceRegistration() {
|
||||
return this._withCurrentAccountState(async currentState => {
|
||||
const signedInUser = await currentState.getUserAccountData([
|
||||
|
@ -355,6 +366,35 @@ class FxAccountsDevice {
|
|||
);
|
||||
}
|
||||
|
||||
async _checkRemoteCommandsUpdateNeeded(remoteAvailableCommands) {
|
||||
if (!remoteAvailableCommands) {
|
||||
return true;
|
||||
}
|
||||
const remoteAvailableCommandsKeys = Object.keys(
|
||||
remoteAvailableCommands
|
||||
).sort();
|
||||
const localAvailableCommands = await this._fxai.commands.availableCommands();
|
||||
const localAvailableCommandsKeys = Object.keys(
|
||||
localAvailableCommands
|
||||
).sort();
|
||||
|
||||
if (
|
||||
!CommonUtils.arrayEqual(
|
||||
localAvailableCommandsKeys,
|
||||
remoteAvailableCommandsKeys
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const key of localAvailableCommandsKeys) {
|
||||
if (remoteAvailableCommands[key] !== localAvailableCommands[key]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async _updateDeviceRegistrationIfNecessary(currentState) {
|
||||
let data = await currentState.getUserAccountData([
|
||||
"sessionToken",
|
||||
|
|
|
@ -211,6 +211,7 @@ function MockFxAccounts(credentials = null) {
|
|||
observerPreloads: [],
|
||||
device: {
|
||||
_registerOrUpdateDevice() {},
|
||||
_checkRemoteCommandsUpdateNeeded: async () => false,
|
||||
},
|
||||
profile: {
|
||||
getProfile() {
|
||||
|
@ -245,10 +246,12 @@ async function MakeFxAccounts({ internal = {}, credentials } = {}) {
|
|||
if (internal.device) {
|
||||
if (!internal.device._registerOrUpdateDevice) {
|
||||
internal.device._registerOrUpdateDevice = () => Promise.resolve();
|
||||
internal.device._checkRemoteCommandsUpdateNeeded = async () => false;
|
||||
}
|
||||
} else {
|
||||
internal.device = {
|
||||
_registerOrUpdateDevice() {},
|
||||
_checkRemoteCommandsUpdateNeeded: async () => false,
|
||||
};
|
||||
}
|
||||
if (!internal.observerPreloads) {
|
||||
|
|
|
@ -162,6 +162,7 @@ async function MockFxAccounts(credentials, device = {}) {
|
|||
},
|
||||
device: {
|
||||
DEVICE_REGISTRATION_VERSION,
|
||||
_checkRemoteCommandsUpdateNeeded: async () => false,
|
||||
},
|
||||
VERIFICATION_POLL_TIMEOUT_INITIAL: 1,
|
||||
});
|
||||
|
@ -817,6 +818,7 @@ add_task(async function test_refreshDeviceList() {
|
|||
fxaPushService: null,
|
||||
};
|
||||
let device = new FxAccountsDevice(fxai);
|
||||
device._checkRemoteCommandsUpdateNeeded = async () => false;
|
||||
|
||||
Assert.equal(
|
||||
device.recentDeviceList,
|
||||
|
@ -908,6 +910,56 @@ add_task(async function test_refreshDeviceList() {
|
|||
);
|
||||
});
|
||||
|
||||
add_task(async function test_checking_remote_availableCommands_mismatch() {
|
||||
const credentials = getTestUser("baz");
|
||||
credentials.verified = true;
|
||||
const fxa = await MockFxAccounts(credentials);
|
||||
fxa.device._checkRemoteCommandsUpdateNeeded =
|
||||
FxAccountsDevice.prototype._checkRemoteCommandsUpdateNeeded;
|
||||
fxa.commands.availableCommands = async () => {
|
||||
return {
|
||||
"https://identity.mozilla.com/cmd/open-uri": "local-keys",
|
||||
};
|
||||
};
|
||||
|
||||
const ourDevice = {
|
||||
isCurrentDevice: true,
|
||||
availableCommands: {
|
||||
"https://identity.mozilla.com/cmd/open-uri": "remote-keys",
|
||||
},
|
||||
};
|
||||
Assert.ok(
|
||||
await fxa.device._checkRemoteCommandsUpdateNeeded(
|
||||
ourDevice.availableCommands
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_checking_remote_availableCommands_match() {
|
||||
const credentials = getTestUser("baz");
|
||||
credentials.verified = true;
|
||||
const fxa = await MockFxAccounts(credentials);
|
||||
fxa.device._checkRemoteCommandsUpdateNeeded =
|
||||
FxAccountsDevice.prototype._checkRemoteCommandsUpdateNeeded;
|
||||
fxa.commands.availableCommands = async () => {
|
||||
return {
|
||||
"https://identity.mozilla.com/cmd/open-uri": "local-keys",
|
||||
};
|
||||
};
|
||||
|
||||
const ourDevice = {
|
||||
isCurrentDevice: true,
|
||||
availableCommands: {
|
||||
"https://identity.mozilla.com/cmd/open-uri": "local-keys",
|
||||
},
|
||||
};
|
||||
Assert.ok(
|
||||
!(await fxa.device._checkRemoteCommandsUpdateNeeded(
|
||||
ourDevice.availableCommands
|
||||
))
|
||||
);
|
||||
});
|
||||
|
||||
function expandHex(two_hex) {
|
||||
// Return a 64-character hex string, encoding 32 identical bytes.
|
||||
let eight_hex = two_hex + two_hex + two_hex + two_hex;
|
||||
|
|
|
@ -639,9 +639,9 @@ add_task(async function test_send_tab_keys_regenerated_if_lost() {
|
|||
const accountState = {
|
||||
data: {
|
||||
// Since the device object has no
|
||||
// sendTabKeys, when we _decrypt,
|
||||
// we will attempt to regenerate the
|
||||
// keys.
|
||||
// sendTabKeys, it will recover
|
||||
// when we attempt to get the
|
||||
// encryptedSendTabKeys
|
||||
device: {
|
||||
lastCommandIndex: 10,
|
||||
},
|
||||
|
@ -664,39 +664,12 @@ add_task(async function test_send_tab_keys_regenerated_if_lost() {
|
|||
},
|
||||
telemetry: new TelemetryMock(),
|
||||
};
|
||||
|
||||
const sendTab = new SendTab(commands, fxAccounts);
|
||||
sendTab._encrypt = (bytes, device) => {
|
||||
return bytes;
|
||||
};
|
||||
let generateEncryptedKeysCalled = false;
|
||||
sendTab._generateAndPersistEncryptedSendTabKey = async () => {
|
||||
generateEncryptedKeysCalled = true;
|
||||
};
|
||||
sendTab._fxai = fxAccounts;
|
||||
const tab = { title: "tab title", url: "http://example.com" };
|
||||
const to = [{ id: "devid", name: "The Device" }];
|
||||
const reason = "push";
|
||||
|
||||
await sendTab.send(to, tab);
|
||||
Assert.equal(commands._invokes.length, 1);
|
||||
|
||||
for (let { cmd, device, payload } of commands._invokes) {
|
||||
Assert.equal(cmd, COMMAND_SENDTAB);
|
||||
sendTab._fxai = fxAccounts;
|
||||
try {
|
||||
await sendTab.handle(device.id, payload, reason);
|
||||
} catch {
|
||||
// The `handle` function will throw an error
|
||||
// since we are not mocking the `_decrypt`
|
||||
// function. This is intentional, since
|
||||
// we want to capture that `_decrypt` will
|
||||
// call `_generateEncryptedSendTabKeys` if
|
||||
// it fails to retrieve the keys.
|
||||
// Receiving a send tab is covered
|
||||
// in the above test_sendtab_receive test.
|
||||
}
|
||||
}
|
||||
await sendTab.getEncryptedSendTabKeys();
|
||||
Assert.ok(generateEncryptedKeysCalled);
|
||||
});
|
||||
|
||||
|
@ -712,8 +685,10 @@ add_task(async function test_send_tab_keys_are_not_regenerated_if_not_lost() {
|
|||
const accountState = {
|
||||
data: {
|
||||
// Since the device object has
|
||||
// sendTabKeys, when we _decrypt,
|
||||
// we will not try to regenerate them
|
||||
// sendTabKeys, it will not try
|
||||
// to regenerate them
|
||||
// when we attempt to get the
|
||||
// encryptedSendTabKeys
|
||||
device: {
|
||||
lastCommandIndex: 10,
|
||||
sendTabKeys: "keys",
|
||||
|
@ -737,38 +712,11 @@ add_task(async function test_send_tab_keys_are_not_regenerated_if_not_lost() {
|
|||
},
|
||||
telemetry: new TelemetryMock(),
|
||||
};
|
||||
|
||||
const sendTab = new SendTab(commands, fxAccounts);
|
||||
sendTab._encrypt = (bytes, device) => {
|
||||
return bytes;
|
||||
};
|
||||
let generateEncryptedKeysCalled = false;
|
||||
sendTab._generateAndPersistEncryptedSendTabKey = async () => {
|
||||
generateEncryptedKeysCalled = true;
|
||||
};
|
||||
sendTab._fxai = fxAccounts;
|
||||
const tab = { title: "tab title", url: "http://example.com" };
|
||||
const to = [{ id: "devid", name: "The Device" }];
|
||||
const reason = "push";
|
||||
|
||||
await sendTab.send(to, tab);
|
||||
Assert.equal(commands._invokes.length, 1);
|
||||
|
||||
for (let { cmd, device, payload } of commands._invokes) {
|
||||
Assert.equal(cmd, COMMAND_SENDTAB);
|
||||
sendTab._fxai = fxAccounts;
|
||||
try {
|
||||
await sendTab.handle(device.id, payload, reason);
|
||||
} catch {
|
||||
// The `handle` function will throw an error
|
||||
// since we are not mocking the `_decrypt`
|
||||
// function. This is intentional, since
|
||||
// we want to capture that `_decrypt` will
|
||||
// not call `_generateEncryptedSendTabKeys` if
|
||||
// it succeeds to retrieve the keys.
|
||||
// Receiving a send tab is covered
|
||||
// in the above test_sendtab_receive test.
|
||||
}
|
||||
}
|
||||
await sendTab.getEncryptedSendTabKeys();
|
||||
Assert.ok(!generateEncryptedKeysCalled);
|
||||
});
|
||||
|
|
|
@ -13,6 +13,8 @@ const { PREF_ACCOUNT_ROOT } = ChromeUtils.import(
|
|||
|
||||
_("Misc tests for FxAccounts.device");
|
||||
|
||||
fxAccounts.device._checkRemoteCommandsUpdateNeeded = async () => false;
|
||||
|
||||
add_test(function test_default_device_name() {
|
||||
// Note that head_helpers overrides getDefaultLocalName - this test is
|
||||
// really just to ensure the actual implementation is sane - we can't
|
||||
|
|
|
@ -92,9 +92,10 @@ XPCOMUtils.defineLazyGetter(this, "SyncPingSchema", function() {
|
|||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "SyncPingValidator", function() {
|
||||
let { Ajv } = ChromeUtils.import("resource://testing-common/ajv-6.12.6.js");
|
||||
let ajv = new Ajv({ async: "co*" });
|
||||
return ajv.compile(SyncPingSchema);
|
||||
const { JsonSchema } = ChromeUtils.import(
|
||||
"resource://gre/modules/JsonSchema.jsm"
|
||||
);
|
||||
return new JsonSchema.Validator(SyncPingSchema);
|
||||
});
|
||||
|
||||
// This is needed for loadAddonTestFunctions().
|
||||
|
@ -283,13 +284,18 @@ function get_sync_test_telemetry() {
|
|||
}
|
||||
|
||||
function assert_valid_ping(record) {
|
||||
// Our JSON validator does not like `undefined` values, even though they will
|
||||
// be skipped when we serialize to JSON.
|
||||
record = JSON.parse(JSON.stringify(record));
|
||||
|
||||
// This is called as the test harness tears down due to shutdown. This
|
||||
// will typically have no recorded syncs, and the validator complains about
|
||||
// it. So ignore such records (but only ignore when *both* shutdown and
|
||||
// no Syncs - either of them not being true might be an actual problem)
|
||||
if (record && (record.why != "shutdown" || record.syncs.length != 0)) {
|
||||
if (!SyncPingValidator(record)) {
|
||||
if (SyncPingValidator.errors.length) {
|
||||
const result = SyncPingValidator.validate(record);
|
||||
if (!result.valid) {
|
||||
if (result.errors.length) {
|
||||
// validation failed - using a simple |deepEqual([], errors)| tends to
|
||||
// truncate the validation errors in the output and doesn't show that
|
||||
// the ping actually was - so be helpful.
|
||||
|
@ -297,7 +303,7 @@ function assert_valid_ping(record) {
|
|||
info("the ping data is: " + JSON.stringify(record, undefined, 2));
|
||||
info(
|
||||
"the validation failures: " +
|
||||
JSON.stringify(SyncPingValidator.errors, undefined, 2)
|
||||
JSON.stringify(result.errors, undefined, 2)
|
||||
);
|
||||
ok(
|
||||
false,
|
||||
|
|
|
@ -193,6 +193,78 @@ jobs:
|
|||
- name: public/condprof
|
||||
path: archive
|
||||
type: directory
|
||||
android-hw-a51-11-0-arm7-geckoview:
|
||||
worker-type: t-bitbar-gw-perf-a51
|
||||
description: Creates or update conditioned profiles on GeckoView+A51
|
||||
run-on-projects: [] # bug 1765348
|
||||
treeherder:
|
||||
symbol: condprof(geckoview)
|
||||
platform: android-hw-a51-11-0-arm7/opt
|
||||
index:
|
||||
product: firefox
|
||||
job-name: condprof-a51-geckoview_example
|
||||
dependencies:
|
||||
build: build-android-arm-shippable/opt
|
||||
fetches:
|
||||
build:
|
||||
- artifact: en-US/target.condprof.tests.tar.gz
|
||||
- artifact: geckoview_example.apk
|
||||
extract: false
|
||||
toolchain:
|
||||
- linux64-geckodriver
|
||||
run:
|
||||
run-as-root: true
|
||||
command: >-
|
||||
adb install -r $MOZ_FETCHES_DIR/geckoview_example.apk &&
|
||||
python3 virtualenv/virtualenv.py . &&
|
||||
bin/python3 condprof/main.py
|
||||
--force-new
|
||||
--geckodriver ${MOZ_FETCHES_DIR}/geckodriver
|
||||
--device-name a51
|
||||
--firefox org.mozilla.geckoview_example
|
||||
--scenario settled
|
||||
../../archive
|
||||
worker:
|
||||
artifacts:
|
||||
- name: public/condprof
|
||||
path: archive
|
||||
type: directory
|
||||
android-hw-a51-11-0-arm7-fenix:
|
||||
worker-type: t-bitbar-gw-perf-a51
|
||||
description: Creates or update conditioned profiles on Fenix+A51
|
||||
run-on-projects: [] # bug 1765348
|
||||
treeherder:
|
||||
symbol: condprof(fenix)
|
||||
platform: android-hw-a51-11-0-arm7/opt
|
||||
index:
|
||||
product: firefox
|
||||
job-name: condprof-a51-fenix
|
||||
dependencies:
|
||||
build: build-linux64-shippable/opt
|
||||
fetches:
|
||||
build:
|
||||
- artifact: target.condprof.tests.tar.gz
|
||||
toolchain:
|
||||
- linux64-geckodriver
|
||||
run:
|
||||
run-as-root: true
|
||||
command: >-
|
||||
curl -L -o target.apk https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/mobile.v2.fenix.nightly.latest.armeabi-v7a/artifacts/public/build/armeabi-v7a/target.apk &&
|
||||
adb install -r target.apk &&
|
||||
rm -rf target.apk &&
|
||||
python3 virtualenv/virtualenv.py . &&
|
||||
bin/python3 condprof/main.py
|
||||
--force-new
|
||||
--geckodriver ${MOZ_FETCHES_DIR}/geckodriver
|
||||
--device-name a51
|
||||
--firefox org.mozilla.fenix
|
||||
--scenario settled
|
||||
../../archive
|
||||
worker:
|
||||
artifacts:
|
||||
- name: public/condprof
|
||||
path: archive
|
||||
type: directory
|
||||
android-hw-p2-8-0-aarch64-fenix:
|
||||
worker-type: t-bitbar-gw-perf-p2
|
||||
description: Creates or update conditioned profiles on Fenix+P2
|
||||
|
|
|
@ -25,6 +25,13 @@ hw-g5:
|
|||
symbol: perftest-g5
|
||||
platform: android-hw-g5-7-0-arm7-shippable/opt
|
||||
|
||||
hw-a51:
|
||||
worker-type: t-bitbar-gw-perf-a51
|
||||
description: Run ./mach perftest on a Samsung Galaxy a51
|
||||
treeherder:
|
||||
symbol: perftest-a51
|
||||
platform: android-hw-a51-11-0-arm7-shippable/opt
|
||||
|
||||
hw-p2:
|
||||
worker-type: t-bitbar-gw-perf-p2
|
||||
description: Run ./mach perftest on a Pixel 2
|
||||
|
@ -32,13 +39,6 @@ hw-p2:
|
|||
symbol: perftest-p2
|
||||
platform: android-hw-p2-8-0-android-aarch64-shippable/opt
|
||||
|
||||
hw-s7:
|
||||
worker-type: t-bitbar-gw-perf-s7
|
||||
description: Run ./mach perftest on a Samsung Galaxy S7
|
||||
treeherder:
|
||||
symbol: perftest-s7
|
||||
platform: android-hw-s7-8-0-android-aarch64-shippable/opt
|
||||
|
||||
hw-g5-view-fenix:
|
||||
worker-type: t-bitbar-gw-perf-g5
|
||||
description: Run VIEW perftest on Fenix on a G5
|
||||
|
@ -69,6 +69,36 @@ hw-g5-view-fenix:
|
|||
--output $MOZ_FETCHES_DIR/../artifacts
|
||||
testing/performance/perftest_android_view.js
|
||||
|
||||
hw-a51-view-fenix:
|
||||
worker-type: t-bitbar-gw-perf-a51
|
||||
description: Run VIEW perftest on Fenix on a Samsung A51
|
||||
treeherder:
|
||||
symbol: perftest(view-fenix)
|
||||
platform: android-hw-a51-11-0-arm7-shippable/opt
|
||||
attributes:
|
||||
cron: true
|
||||
batch: true
|
||||
run:
|
||||
command: >-
|
||||
mkdir -p $MOZ_FETCHES_DIR/../artifacts &&
|
||||
cd $GECKO_PATH &&
|
||||
python3 python/mozperftest/mozperftest/runner.py
|
||||
--flavor mobile-browser
|
||||
--android
|
||||
--android-app-name org.mozilla.fenix
|
||||
--android-activity org.mozilla.fenix.IntentReceiverActivity
|
||||
--android-clear-logcat
|
||||
--android-capture-logcat logcat
|
||||
--perfherder-metrics name:processLaunchToNavStart,shouldAlert:True
|
||||
--android-install-apk fenix_nightly_armeabi_v7a
|
||||
--hooks testing/performance/hooks_android_view.py
|
||||
--perfherder
|
||||
--perfherder-app fenix
|
||||
--browsertime-geckodriver ${MOZ_FETCHES_DIR}/geckodriver
|
||||
--browsertime-iterations 25
|
||||
--output $MOZ_FETCHES_DIR/../artifacts
|
||||
testing/performance/perftest_android_view.js
|
||||
|
||||
hw-p2-view-fenix:
|
||||
worker-type: t-bitbar-gw-perf-p2
|
||||
description: Run VIEW perftest on Fenix on a Pixel2
|
||||
|
@ -106,6 +136,35 @@ hw-g5-view-gv:
|
|||
treeherder:
|
||||
symbol: perftest(view-gv)
|
||||
platform: android-hw-g5-7-0-arm7-shippable/opt
|
||||
attributes:
|
||||
cron: false
|
||||
run:
|
||||
command: >-
|
||||
mkdir -p $MOZ_FETCHES_DIR/../artifacts &&
|
||||
cd $GECKO_PATH &&
|
||||
python3 python/mozperftest/mozperftest/runner.py
|
||||
--flavor mobile-browser
|
||||
--android
|
||||
--android-app-name org.mozilla.geckoview_example
|
||||
--android-activity org.mozilla.geckoview_example.GeckoViewActivity
|
||||
--android-clear-logcat
|
||||
--android-capture-logcat logcat
|
||||
--perfherder-metrics processLaunchToNavStart
|
||||
--android-install-apk gve_nightly_api16
|
||||
--hooks testing/performance/hooks_android_view.py
|
||||
--perfherder
|
||||
--perfherder-app geckoview
|
||||
--browsertime-geckodriver ${MOZ_FETCHES_DIR}/geckodriver
|
||||
--browsertime-iterations 14
|
||||
--output $MOZ_FETCHES_DIR/../artifacts
|
||||
testing/performance/perftest_android_view.js
|
||||
|
||||
hw-a51-view-gv:
|
||||
worker-type: t-bitbar-gw-perf-a51
|
||||
description: Run VIEW perftest on GV on a Samsung A51
|
||||
treeherder:
|
||||
symbol: perftest(view-gv)
|
||||
platform: android-hw-a51-11-0-arm7-shippable/opt
|
||||
attributes:
|
||||
cron: true
|
||||
run:
|
||||
|
@ -191,6 +250,38 @@ hw-g5-main-fenix:
|
|||
--browsertime-iterations 14
|
||||
testing/performance/perftest_android_main.js
|
||||
|
||||
hw-a51-main-fenix:
|
||||
worker-type: t-bitbar-gw-perf-a51
|
||||
description: Run main (home activity) perftest on Fenix on a Samsung A51
|
||||
treeherder:
|
||||
symbol: perftest(main-fenix)
|
||||
platform: android-hw-a51-11-0-arm7-shippable/opt
|
||||
attributes:
|
||||
cron: false
|
||||
run:
|
||||
command: >-
|
||||
mkdir -p $MOZ_FETCHES_DIR/../artifacts &&
|
||||
cd $GECKO_PATH &&
|
||||
python3 python/mozperftest/mozperftest/runner.py
|
||||
--flavor mobile-browser
|
||||
--android
|
||||
--android-app-name org.mozilla.fenix
|
||||
--android-activity .App
|
||||
--android-clear-logcat
|
||||
--android-capture-logcat logcat
|
||||
--androidlog
|
||||
--androidlog-first-timestamp ".*Start proc.*org\.mozilla\..*\..*App.*"
|
||||
--androidlog-second-timestamp ".*Fully drawn.*org\.mozilla\..*"
|
||||
--androidlog-subtest-name "MAIN"
|
||||
--android-install-apk fenix_nightly_armeabi_v7a
|
||||
--hooks testing/performance/hooks_android_main.py
|
||||
--perfherder
|
||||
--perfherder-app fenix
|
||||
--browsertime-geckodriver ${MOZ_FETCHES_DIR}/geckodriver
|
||||
--output $MOZ_FETCHES_DIR/../artifacts
|
||||
--browsertime-iterations 14
|
||||
testing/performance/perftest_android_main.js
|
||||
|
||||
hw-p2-main-fenix:
|
||||
worker-type: t-bitbar-gw-perf-p2
|
||||
description: Run main (home activity) perftest on Fenix on a Pixel 2
|
||||
|
@ -253,6 +344,35 @@ hw-g5-perfstats-gv:
|
|||
--hooks testing/performance/hooks_perfstats.py
|
||||
testing/performance/perftest_perfstats.js
|
||||
|
||||
hw-a51-perfstats-gv:
|
||||
worker-type: t-bitbar-gw-perf-a51
|
||||
description: Run PerfStats perftest on GeckoView on a Samsung A51
|
||||
treeherder:
|
||||
symbol: perftest(perfstats-gv)
|
||||
platform: android-hw-a51-11-0-arm7-shippable/opt
|
||||
attributes:
|
||||
cron: false
|
||||
run:
|
||||
command: >-
|
||||
mkdir -p $MOZ_FETCHES_DIR/../artifacts &&
|
||||
cd $GECKO_PATH &&
|
||||
python3 python/mozperftest/mozperftest/runner.py
|
||||
--flavor mobile-browser
|
||||
--android
|
||||
--android-app-name org.mozilla.geckoview_example
|
||||
--android-activity org.mozilla.geckoview_example.GeckoViewActivity
|
||||
--android-clear-logcat
|
||||
--android-capture-logcat logcat
|
||||
--android-install-apk gve_nightly_api16
|
||||
--browsertime-geckodriver ${MOZ_FETCHES_DIR}/geckodriver
|
||||
--output $MOZ_FETCHES_DIR/../artifacts
|
||||
--perfherder
|
||||
--perfherder-app geckoview
|
||||
--perfherder-metrics name:HttpChannelCompletion,unit:ms name:HttpChannelCompletion_Cache,unit:ms name:HttpChannelCompletion_Network,unit:ms name:DisplayListBuilding,unit:ms name:Reflowing,unit:ms name:Styling,unit:ms
|
||||
--browsertime-iterations 10
|
||||
--hooks testing/performance/hooks_perfstats.py
|
||||
testing/performance/perftest_perfstats.js
|
||||
|
||||
hw-p2-perfstats-gv:
|
||||
worker-type: t-bitbar-gw-perf-p2
|
||||
description: Run PerfStats pageload test on GeckoView on a Pixel 2
|
||||
|
@ -311,6 +431,35 @@ hw-g5-perfstats-fenix:
|
|||
--hooks testing/performance/hooks_perfstats.py
|
||||
testing/performance/perftest_perfstats.js
|
||||
|
||||
hw-a51-perfstats-fenix:
|
||||
worker-type: t-bitbar-gw-perf-a51
|
||||
description: Run PerfStats perftest on Fenix on a Samsung A51
|
||||
treeherder:
|
||||
symbol: perftest(perfstats-fenix)
|
||||
platform: android-hw-a51-11-0-arm7-shippable/opt
|
||||
attributes:
|
||||
cron: false
|
||||
run:
|
||||
command: >-
|
||||
mkdir -p $MOZ_FETCHES_DIR/../artifacts &&
|
||||
cd $GECKO_PATH &&
|
||||
python3 python/mozperftest/mozperftest/runner.py
|
||||
--flavor mobile-browser
|
||||
--android
|
||||
--android-app-name org.mozilla.fenix
|
||||
--android-activity org.mozilla.fenix.IntentReceiverActivity
|
||||
--android-clear-logcat
|
||||
--android-capture-logcat logcat
|
||||
--android-install-apk fenix_nightly_armeabi_v7a
|
||||
--browsertime-geckodriver ${MOZ_FETCHES_DIR}/geckodriver
|
||||
--output $MOZ_FETCHES_DIR/../artifacts
|
||||
--perfherder
|
||||
--perfherder-app fenix
|
||||
--perfherder-metrics name:HttpChannelCompletion,unit:ms name:HttpChannelCompletion_Cache,unit:ms name:HttpChannelCompletion_Network,unit:ms name:DisplayListBuilding,unit:ms name:Reflowing,unit:ms name:Styling,unit:ms
|
||||
--browsertime-iterations 10
|
||||
--hooks testing/performance/hooks_perfstats.py
|
||||
testing/performance/perftest_perfstats.js
|
||||
|
||||
hw-p2-perfstats-fenix:
|
||||
worker-type: t-bitbar-gw-perf-p2
|
||||
description: Run PerfStats perftest on Fenix on a Pixel2
|
||||
|
|
|
@ -105,7 +105,7 @@ browsertime-tp6m:
|
|||
by-app:
|
||||
geckoview:
|
||||
by-test-platform:
|
||||
android-hw-g5.*shippable-qr.*: [trunk, mozilla-beta, mozilla-release]
|
||||
android-hw-(g5|a51).*shippable-qr.*: [trunk, mozilla-beta, mozilla-release]
|
||||
android-hw-p2.*aarch64-shippable-qr.*: [trunk, mozilla-beta, mozilla-release]
|
||||
default: []
|
||||
default: []
|
||||
|
@ -128,19 +128,15 @@ browsertime-tp6m-essential:
|
|||
by-app:
|
||||
geckoview:
|
||||
by-test-platform:
|
||||
android-hw-g5.*shippable.*: [trunk, mozilla-beta, mozilla-release]
|
||||
android-hw-(g5|a51).*shippable.*: [trunk, mozilla-beta, mozilla-release]
|
||||
android-hw-p2.*aarch64-shippable.*: [trunk, mozilla-beta, mozilla-release]
|
||||
android-hw-s7-.*: []
|
||||
default: []
|
||||
default: []
|
||||
tier:
|
||||
by-test-platform:
|
||||
android-hw-s7-.*: 3
|
||||
default:
|
||||
by-app:
|
||||
geckoview: 1
|
||||
refbrow: 2
|
||||
default: 3
|
||||
by-app:
|
||||
geckoview: 1
|
||||
refbrow: 2
|
||||
default: 3
|
||||
|
||||
browsertime-youtube-playback-mobile:
|
||||
description: Browsertime YouTube Playback on Android
|
||||
|
@ -149,7 +145,7 @@ browsertime-youtube-playback-mobile:
|
|||
apps: [fenix, geckoview, refbrow]
|
||||
subtests:
|
||||
by-test-platform:
|
||||
android-hw-g5.*:
|
||||
android-hw-(g5|a51).*:
|
||||
- [youtube-playback-h264-sfr, ytp-h264-sfr]
|
||||
- [youtube-playback-hfr, ytp-hfr]
|
||||
# Bug 1699469 - Disabled until a crash is fixed.
|
||||
|
@ -163,7 +159,6 @@ browsertime-youtube-playback-mobile:
|
|||
# - [youtube-playback-widevine-h264-sfr, ytp-widevine-h264-sfr]
|
||||
# - [youtube-playback-widevine-hfr, ytp-widevine-hfr]
|
||||
# - [youtube-playback-widevine-vp9-sfr, ytp-widevine-vp9-sfr]
|
||||
android-hw-s7.*: []
|
||||
test-url-param:
|
||||
by-subtest:
|
||||
youtube-playback-h264-sfr: # remove high resolution tests
|
||||
|
@ -171,7 +166,7 @@ browsertime-youtube-playback-mobile:
|
|||
23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38
|
||||
youtube-playback-hfr:
|
||||
by-test-platform:
|
||||
android-hw-g5.*: # remove VP9(1-34) and AV1(51-74) tests
|
||||
android-hw-(g5|a51).*: # remove VP9(1-34) and AV1(51-74) tests
|
||||
exclude=1,2,
|
||||
3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,
|
||||
51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74
|
||||
|
@ -181,7 +176,7 @@ browsertime-youtube-playback-mobile:
|
|||
default: ""
|
||||
youtube-playback-widevine-hfr:
|
||||
by-test-platform:
|
||||
android-hw-g5.*: # remove VP9(1-34) tests
|
||||
android-hw-(g5|a51).*: # remove VP9(1-34) tests
|
||||
exclude=1,2,
|
||||
3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34
|
||||
default: ""
|
||||
|
@ -190,7 +185,7 @@ browsertime-youtube-playback-mobile:
|
|||
by-app:
|
||||
geckoview:
|
||||
by-test-platform:
|
||||
android-hw-g5.*shippable.*: [mozilla-central, mozilla-release]
|
||||
android-hw-(g5|a51).*shippable.*: [mozilla-central, mozilla-release]
|
||||
android-hw-p2.*aarch64-shippable.*: [mozilla-central, mozilla-release]
|
||||
default: []
|
||||
default: []
|
||||
|
@ -253,7 +248,7 @@ browsertime-tp6m-live:
|
|||
by-app:
|
||||
geckoview:
|
||||
by-test-platform:
|
||||
android-hw-g5.*shippable-qr.*: [autoland]
|
||||
android-hw-(g5|a51).*shippable-qr.*: [autoland]
|
||||
android-hw-p2.*aarch64-shippable-qr.*: [autoland]
|
||||
default: []
|
||||
default: []
|
||||
|
@ -293,7 +288,7 @@ browsertime-speedometer-mobile:
|
|||
refbrow: []
|
||||
geckoview:
|
||||
by-test-platform:
|
||||
android-hw-g5.*shippable-qr.*: [trunk, mozilla-beta, mozilla-release]
|
||||
android-hw-(g5|a51).*shippable-qr.*: [trunk, mozilla-beta, mozilla-release]
|
||||
android-hw-p2.*aarch64-shippable-qr.*: [trunk, mozilla-beta, mozilla-release]
|
||||
default: []
|
||||
default:
|
||||
|
@ -316,7 +311,7 @@ browsertime-unity-webgl-mobile:
|
|||
refbrow: []
|
||||
geckoview:
|
||||
by-test-platform:
|
||||
android-hw-g5.*shippable-qr.*: [trunk, mozilla-beta, mozilla-release]
|
||||
android-hw-(g5|a51).*shippable-qr.*: [trunk, mozilla-beta, mozilla-release]
|
||||
android-hw-p2.*aarch64-shippable-qr.*: [trunk, mozilla-beta, mozilla-release]
|
||||
default: []
|
||||
default:
|
||||
|
|
|
@ -366,6 +366,26 @@ android-hw-g5-7-0-arm7-shippable-qr/opt:
|
|||
- android-hw-arm7-raptor-cpu-memory
|
||||
- android-hw-arm7-raptor-cpu-memory-power
|
||||
|
||||
# android-hw-a51-11-0 Samsung Galaxy A51 Android 11.0
|
||||
|
||||
android-hw-a51-11-0-arm7-qr/opt:
|
||||
build-platform: android-arm/opt
|
||||
test-sets:
|
||||
- android-hw-browsertime-a51
|
||||
# - android-hw-browsertime
|
||||
# - android-hw-browsertime-power
|
||||
# - android-hw-arm7-raptor-cpu-memory
|
||||
# - android-hw-arm7-raptor-cpu-memory-power
|
||||
|
||||
android-hw-a51-11-0-arm7-shippable-qr/opt:
|
||||
build-platform: android-arm-shippable/opt
|
||||
test-sets:
|
||||
- android-hw-browsertime-a51
|
||||
# - android-hw-browsertime
|
||||
# - android-hw-browsertime-power
|
||||
# - android-hw-arm7-raptor-cpu-memory
|
||||
# - android-hw-arm7-raptor-cpu-memory-power
|
||||
|
||||
# android-hw-p2-8-0 Google Pixel 2 Android 8.0
|
||||
|
||||
android-hw-p2-8-0-arm7-qr/opt:
|
||||
|
@ -417,25 +437,3 @@ android-hw-p2-8-0-android-aarch64-qr/debug:
|
|||
test-sets:
|
||||
- android-hw-aarch64
|
||||
- android-hw-aarch64-debug-unittests
|
||||
|
||||
# android-hw-s7-8-0 Samsung Galaxy S7 Android 8.0
|
||||
|
||||
android-hw-s7-8-0-arm7-api-16-qr/opt:
|
||||
build-platform: android-api-16/opt
|
||||
test-sets:
|
||||
- android-hw-browsertime
|
||||
|
||||
android-hw-s7-8-0-arm7-api-16-shippable-qr/opt:
|
||||
build-platform: android-api-16-shippable/opt
|
||||
test-sets:
|
||||
- android-hw-browsertime
|
||||
|
||||
android-hw-s7-8-0-android-aarch64-qr/opt:
|
||||
build-platform: android-aarch64/opt
|
||||
test-sets:
|
||||
- android-hw-browsertime
|
||||
|
||||
android-hw-s7-8-0-android-aarch64-shippable-qr/opt:
|
||||
build-platform: android-aarch64-shippable/opt
|
||||
test-sets:
|
||||
- android-hw-browsertime
|
||||
|
|
|
@ -445,6 +445,13 @@ android-hw-aarch64-raptor-cpu-memory-power:
|
|||
android-hw-browsertime-power:
|
||||
- browsertime-power
|
||||
|
||||
android-hw-browsertime-a51:
|
||||
- browsertime-tp6m-essential
|
||||
- browsertime-speedometer-mobile
|
||||
- browsertime-youtube-playback-mobile
|
||||
- browsertime-unity-webgl-mobile
|
||||
# not live, or tp6 proper
|
||||
|
||||
android-hw-browsertime:
|
||||
- browsertime-tp6m
|
||||
- browsertime-tp6m-essential
|
||||
|
|
|
@ -1165,42 +1165,6 @@ def target_tasks_raptor_tp6m(full_task_graph, parameters, graph_config):
|
|||
return [l for l, t in full_task_graph.tasks.items() if filter(t)]
|
||||
|
||||
|
||||
@_target_task("perftest_s7")
|
||||
def target_tasks_perftest_s7(full_task_graph, parameters, graph_config):
|
||||
"""
|
||||
Select tasks required for running raptor page-load tests on geckoview against S7
|
||||
"""
|
||||
|
||||
def filter(task):
|
||||
build_platform = task.attributes.get("build_platform", "")
|
||||
test_platform = task.attributes.get("test_platform", "")
|
||||
attributes = task.attributes
|
||||
vismet = attributes.get("kind") == "visual-metrics-dep"
|
||||
try_name = attributes.get("raptor_try_name")
|
||||
|
||||
if vismet:
|
||||
# Visual metric tasks are configured a bit differently
|
||||
test_platform = task.task.get("extra").get("treeherder-platform")
|
||||
try_name = task.label
|
||||
|
||||
if build_platform and "android" not in build_platform:
|
||||
return False
|
||||
if attributes.get("unittest_suite") != "raptor" and not vismet:
|
||||
return False
|
||||
if "s7" in test_platform and "-qr" in test_platform:
|
||||
if "geckoview" in try_name and (
|
||||
"unity-webgl" in try_name
|
||||
or "speedometer" in try_name
|
||||
or "tp6m-essential" in try_name
|
||||
):
|
||||
if "power" in try_name:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
return [l for l, t in full_task_graph.tasks.items() if filter(t)]
|
||||
|
||||
|
||||
@_target_task("condprof")
|
||||
def target_tasks_condprof(full_task_graph, parameters, graph_config):
|
||||
"""
|
||||
|
|
|
@ -185,15 +185,15 @@ def test_split_variants(monkeypatch, run_transform, make_test_task):
|
|||
pytest.param(
|
||||
{
|
||||
"attributes": {},
|
||||
"test-platform": "android-hw-s7-8-0-android-aarch64-shippable-qr/opt",
|
||||
"test-platform": "android-hw-a51-11-0-arm7-shippable-qr/opt",
|
||||
},
|
||||
{
|
||||
"platform": {
|
||||
"arch": "aarch64",
|
||||
"device": "s7",
|
||||
"arch": "arm7",
|
||||
"device": "a51",
|
||||
"os": {
|
||||
"name": "android",
|
||||
"version": "8.0",
|
||||
"version": "11.0",
|
||||
},
|
||||
},
|
||||
"build": {
|
||||
|
|
|
@ -262,6 +262,8 @@ def add_extra_options(config, tests):
|
|||
test_platform = test["test-platform"]
|
||||
if test_platform.startswith("android-hw-g5"):
|
||||
extra_options.append("--device-name=g5")
|
||||
elif test_platform.startswith("android-hw-a51"):
|
||||
extra_options.append("--device-name=a51")
|
||||
elif test_platform.startswith("android-hw-p2"):
|
||||
extra_options.append("--device-name=p2_aarch64")
|
||||
|
||||
|
|
|
@ -209,11 +209,6 @@ def set_worker_type(config, tasks):
|
|||
task["worker-type"] = "t-bitbar-gw-unit-p2"
|
||||
else:
|
||||
task["worker-type"] = "t-bitbar-gw-perf-p2"
|
||||
elif test_platform.startswith("android-hw-s7"):
|
||||
if task["suite"] != "raptor":
|
||||
task["worker-type"] = "t-bitbar-gw-unit-s7"
|
||||
else:
|
||||
task["worker-type"] = "t-bitbar-gw-perf-s7"
|
||||
elif test_platform.startswith("android-hw-a51"):
|
||||
if task["suite"] != "raptor":
|
||||
task["worker-type"] = "t-bitbar-gw-unit-a51"
|
||||
|
|
|
@ -123,6 +123,7 @@ UNITTEST_PLATFORM_PRETTY_NAMES = {
|
|||
],
|
||||
"x64": ["linux64", "linux64-asan", "linux1804-64", "linux1804-64-asan"],
|
||||
"Android 7.0 Moto G5 32bit": ["android-hw-g5-7.0-arm7"],
|
||||
"Android 7.0 Samsung A51 32bit": ["android-hw-a51-11.0-arm7"],
|
||||
"Android 8.0 Google Pixel 2 32bit": ["android-hw-p2-8.0-arm7"],
|
||||
"Android 8.0 Google Pixel 2 64bit": ["android-hw-p2-8.0-android-aarch64"],
|
||||
"10.14": ["macosx1014-64"],
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,4 +1,4 @@
|
|||
[parent.py]
|
||||
[root.py]
|
||||
disabled:
|
||||
if release_or_beta: https://bugzilla.mozilla.org/show_bug.cgi?id=1712902
|
||||
|
|
@ -16,13 +16,13 @@ class BrowsingContext(BidiModule):
|
|||
@command
|
||||
def get_tree(self,
|
||||
max_depth: Optional[int] = None,
|
||||
parent: Optional[str] = None) -> Mapping[str, Any]:
|
||||
root: Optional[str] = None) -> Mapping[str, Any]:
|
||||
params: MutableMapping[str, Any] = {}
|
||||
|
||||
if max_depth is not None:
|
||||
params["maxDepth"] = max_depth
|
||||
if parent is not None:
|
||||
params["parent"] = parent
|
||||
if root is not None:
|
||||
params["root"] = root
|
||||
|
||||
return params
|
||||
|
||||
|
|
|
@ -129,11 +129,11 @@ async def test_navigate_creates_iframes(
|
|||
assert len(events) == 2
|
||||
|
||||
# Get all browsing contexts from the current tab
|
||||
contexts = await bidi_session.browsing_context.get_tree(parent=current_session.window_handle)
|
||||
contexts = await bidi_session.browsing_context.get_tree(root=current_session.window_handle)
|
||||
|
||||
assert len(contexts) == 1
|
||||
parent_info = contexts[0]
|
||||
children_info = parent_info["children"]
|
||||
root_info = contexts[0]
|
||||
children_info = root_info["children"]
|
||||
assert len(children_info) == 2
|
||||
|
||||
assert_browsing_context(
|
||||
|
@ -141,7 +141,7 @@ async def test_navigate_creates_iframes(
|
|||
children_info[0]["context"],
|
||||
children=None,
|
||||
url=children_info[0]["url"],
|
||||
parent=parent_info["context"],
|
||||
parent=root_info["context"],
|
||||
)
|
||||
|
||||
assert_browsing_context(
|
||||
|
@ -149,7 +149,7 @@ async def test_navigate_creates_iframes(
|
|||
children_info[1]["context"],
|
||||
children=None,
|
||||
url=children_info[1]["url"],
|
||||
parent=parent_info["context"],
|
||||
parent=root_info["context"],
|
||||
)
|
||||
|
||||
remove_listener()
|
||||
|
@ -181,12 +181,12 @@ async def test_navigate_creates_nested_iframes(
|
|||
assert len(events) == 2
|
||||
|
||||
# Get all browsing contexts from the current tab
|
||||
contexts = await bidi_session.browsing_context.get_tree(parent=current_session.window_handle)
|
||||
contexts = await bidi_session.browsing_context.get_tree(root=current_session.window_handle)
|
||||
|
||||
assert len(contexts) == 1
|
||||
parent_info = contexts[0]
|
||||
assert len(parent_info["children"]) == 1
|
||||
child1_info = parent_info["children"][0]
|
||||
root_info = contexts[0]
|
||||
assert len(root_info["children"]) == 1
|
||||
child1_info = root_info["children"][0]
|
||||
assert len(child1_info["children"]) == 1
|
||||
child2_info = child1_info["children"][0]
|
||||
|
||||
|
@ -195,7 +195,7 @@ async def test_navigate_creates_nested_iframes(
|
|||
child1_info["context"],
|
||||
children=None,
|
||||
url=child1_info["url"],
|
||||
parent=parent_info["context"],
|
||||
parent=root_info["context"],
|
||||
)
|
||||
|
||||
assert_browsing_context(
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче