зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central
This commit is contained in:
Коммит
794f08e4fd
|
@ -74,6 +74,7 @@ devtools/client/preferences/
|
|||
devtools/shared/css/generated/properties-db.js
|
||||
devtools/client/webconsole/test/node/fixtures/stubs/*.js
|
||||
!devtools/client/webconsole/test/node/fixtures/stubs/index.js
|
||||
devtools/client/shared/components/test/node/stubs/reps/*.js
|
||||
|
||||
# Ignore devtools files testing sourcemaps / code style
|
||||
devtools/client/framework/test/code_*
|
||||
|
|
|
@ -462,8 +462,8 @@
|
|||
#endif
|
||||
<menuitem id="feedbackPage"
|
||||
oncommand="openFeedbackPage()"
|
||||
data-l10n-id="menu-help-feedback-page"
|
||||
appmenu-data-l10n-id="appmenu-help-feedback-page"/>
|
||||
data-l10n-id="menu-help-share-ideas"
|
||||
appmenu-data-l10n-id="appmenu-help-share-ideas"/>
|
||||
<menuitem id="helpSafeMode"
|
||||
oncommand="safeModeRestart();"
|
||||
data-l10n-id="menu-help-enter-troubleshoot-mode2"
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
* 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/. */
|
||||
|
||||
const {
|
||||
document: gDoc,
|
||||
ChromeUtils,
|
||||
} = window.docShell.chromeEventHandler.ownerGlobal;
|
||||
const { RemoteL10n } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/RemoteL10n.jsm"
|
||||
);
|
||||
const browser = window.docShell.chromeEventHandler;
|
||||
const { document: gDoc, XPCOMUtils } = browser.ownerGlobal;
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AboutWelcomeParent: "resource:///actors/AboutWelcomeParent.jsm",
|
||||
RemoteL10n: "resource://activity-stream/lib/RemoteL10n.jsm",
|
||||
});
|
||||
|
||||
const [CONFIG, PARAMS] = window.arguments[0];
|
||||
|
||||
|
@ -106,15 +106,22 @@ async function renderSpotlight(ready) {
|
|||
* Render content based on about:welcome multistage template.
|
||||
*/
|
||||
function renderMultistage(ready) {
|
||||
const AWParent = new AboutWelcomeParent();
|
||||
const receive = name => data =>
|
||||
AWParent.onContentMessage(`AWPage:${name}`, data, browser);
|
||||
|
||||
// Expose top level functions expected by the bundle.
|
||||
window.AWGetDefaultSites = () => {};
|
||||
window.AWGetFeatureConfig = () => CONFIG;
|
||||
window.AWGetFxAMetricsFlowURI = () => {};
|
||||
window.AWGetImportableSites = () => "[]";
|
||||
window.AWGetRegion = () => {};
|
||||
window.AWGetSelectedTheme = () => {};
|
||||
window.AWSendEventTelemetry = () => {};
|
||||
window.AWSendToParent = () => {};
|
||||
window.AWGetRegion = receive("GET_REGION");
|
||||
window.AWGetSelectedTheme = receive("GET_SELECTED_THEME");
|
||||
window.AWSendEventTelemetry = receive("TELEMETRY_EVENT");
|
||||
window.AWSendToParent = (name, data) => receive(name)(data);
|
||||
window.AWFinish = () => {
|
||||
window.close();
|
||||
};
|
||||
|
||||
// Update styling to be compatible with about:welcome.
|
||||
const link = document.head.appendChild(document.createElement("link"));
|
||||
|
|
|
@ -234,10 +234,9 @@ class AboutWelcomeParent extends JSWindowActorParent {
|
|||
*
|
||||
* @param {string} type
|
||||
* @param {any=} data
|
||||
* @param {Browser} browser
|
||||
* @param {Window} window
|
||||
* @param {Browser} the xul:browser rendering the page
|
||||
*/
|
||||
async onContentMessage(type, data, browser, window) {
|
||||
async onContentMessage(type, data, browser) {
|
||||
log.debug(`Received content event: ${type}`);
|
||||
switch (type) {
|
||||
case "AWPage:SET_WELCOME_MESSAGE_SEEN":
|
||||
|
@ -327,12 +326,10 @@ class AboutWelcomeParent extends JSWindowActorParent {
|
|||
receiveMessage(message) {
|
||||
const { name, data } = message;
|
||||
let browser;
|
||||
let window;
|
||||
|
||||
if (this.manager.rootFrameLoader) {
|
||||
browser = this.manager.rootFrameLoader.ownerElement;
|
||||
window = browser.ownerGlobal;
|
||||
return this.onContentMessage(name, data, browser, window);
|
||||
return this.onContentMessage(name, data, browser);
|
||||
}
|
||||
|
||||
log.warn(`Not handling ${name} because the browser doesn't exist.`);
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<!-- 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/. -->
|
||||
<svg width="115" height="89" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M86.676 83.103c15.377 0 27.842-12.465 27.842-27.842 0-15.376-12.465-27.842-27.842-27.842-15.377 0-27.842 12.466-27.842 27.842 0 15.377 12.465 27.842 27.842 27.842z" fill="#FFEA80"/>
|
||||
<path d="M84.457 41.839l-25.25 43.159a2.59 2.59 0 002.232 3.898h50.484a2.589 2.589 0 002.591-2.6 2.594 2.594 0 00-.354-1.298L88.914 41.84a2.586 2.586 0 00-4.457 0z" fill="#7542E5"/>
|
||||
<path d="M114.16 85.031L95.432 52.967l-4.084 4.084-4.653-4.657-4.656 4.657-4.085-4.085L59.21 85.03a2.591 2.591 0 002.233 3.904h50.48a2.59 2.59 0 002.236-3.904z" fill="#7542E5"/>
|
||||
<path d="M86.68 52.394l3.923 3.922a1.037 1.037 0 001.465 0l3.34-3.34-6.493-11.142a2.587 2.587 0 00-4.467 0l-6.509 11.132 3.34 3.34a1.037 1.037 0 001.466 0l3.936-3.912z" fill="#B48EFF"/>
|
||||
<path d="M41.036 17.67L.368 85.014a2.586 2.586 0 002.3 3.893h81.346a2.586 2.586 0 002.295-3.893L45.636 17.67a2.706 2.706 0 00-4.6 0z" fill="#AB71FF"/>
|
||||
<path d="M56.329 35.373L45.635 17.671a2.706 2.706 0 00-4.594 0L30.347 35.373l-.954 1.58 5.56 7.635a1.032 1.032 0 001.67 0l6.68-9.214 6.704 9.214a1.03 1.03 0 001.67 0l5.583-7.663-.931-1.551z" fill="#D9BFFF"/>
|
||||
<path d="M41.086 1.131v14.41a1.13 1.13 0 001.13 1.131h26.507a1.12 1.12 0 001.044-.697 1.14 1.14 0 00-.242-1.236l-6.409-6.403 6.39-6.404c.322-.325.417-.811.243-1.235A1.135 1.135 0 0068.723 0H42.216c-.624 0-1.13.507-1.13 1.131z" fill="#FFA266"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 1.6 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 4.2 KiB |
|
@ -26,9 +26,6 @@ browser.jar:
|
|||
* res/activity-stream/data/content/abouthomecache/page.html.template (./data/content/abouthomecache/page.html.template)
|
||||
* res/activity-stream/data/content/abouthomecache/script.js.template (./data/content/abouthomecache/script.js.template)
|
||||
content/activity-stream/data/content/assets/ (./data/content/assets/*)
|
||||
#ifdef XP_WIN
|
||||
content/activity-stream/data/content/assets/remote (./data/content/windows-assets/*)
|
||||
#endif
|
||||
content/activity-stream/data/content/tippytop/ (./data/content/tippytop/*)
|
||||
res/activity-stream/data/content/activity-stream.bundle.js (./data/content/activity-stream.bundle.js)
|
||||
res/activity-stream/data/content/newtab-render.js (./data/content/newtab-render.js)
|
||||
|
|
|
@ -313,6 +313,108 @@ const MESSAGES = () => [
|
|||
frequency: { lifetime: 3 },
|
||||
trigger: { id: "defaultBrowserCheck" },
|
||||
},
|
||||
{
|
||||
id: "BETTER_INTERNET_GLOBAL_ROLLOUT",
|
||||
groups: ["eco"],
|
||||
content: {
|
||||
template: "logo-and-content",
|
||||
logo: {
|
||||
imageURL:
|
||||
"chrome://activity-stream/content/data/content/assets/remote/mountain.svg",
|
||||
size: "115px",
|
||||
},
|
||||
body: {
|
||||
title: {
|
||||
label: {
|
||||
string_id: "spotlight-better-internet-header",
|
||||
},
|
||||
size: "24px",
|
||||
},
|
||||
text: {
|
||||
label: {
|
||||
string_id: "spotlight-better-internet-body",
|
||||
},
|
||||
size: "16px",
|
||||
},
|
||||
primary: {
|
||||
label: {
|
||||
string_id: "spotlight-pin-primary-button",
|
||||
},
|
||||
action: {
|
||||
type: "PIN_FIREFOX_TO_TASKBAR",
|
||||
},
|
||||
},
|
||||
secondary: {
|
||||
label: {
|
||||
string_id: "spotlight-pin-secondary-button",
|
||||
},
|
||||
action: {
|
||||
type: "CANCEL",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
trigger: {
|
||||
id: "defaultBrowserCheck",
|
||||
},
|
||||
template: "spotlight",
|
||||
frequency: {
|
||||
lifetime: 1,
|
||||
},
|
||||
targeting:
|
||||
"userMonthlyActivity|length >= 1 && userMonthlyActivity|length <= 6 && doesAppNeedPin",
|
||||
},
|
||||
{
|
||||
id: "PEACE_OF_MIND_GLOBAL_ROLLOUT",
|
||||
groups: ["eco"],
|
||||
content: {
|
||||
template: "logo-and-content",
|
||||
logo: {
|
||||
imageURL:
|
||||
"chrome://activity-stream/content/data/content/assets/remote/umbrella.png",
|
||||
size: "115px",
|
||||
},
|
||||
body: {
|
||||
title: {
|
||||
label: {
|
||||
string_id: "spotlight-peace-mind-header",
|
||||
},
|
||||
size: "24px",
|
||||
},
|
||||
text: {
|
||||
label: {
|
||||
string_id: "spotlight-peace-mind-body",
|
||||
},
|
||||
size: "16px",
|
||||
},
|
||||
primary: {
|
||||
label: {
|
||||
string_id: "spotlight-pin-primary-button",
|
||||
},
|
||||
action: {
|
||||
type: "PIN_FIREFOX_TO_TASKBAR",
|
||||
},
|
||||
},
|
||||
secondary: {
|
||||
label: {
|
||||
string_id: "spotlight-pin-secondary-button",
|
||||
},
|
||||
action: {
|
||||
type: "CANCEL",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
trigger: {
|
||||
id: "defaultBrowserCheck",
|
||||
},
|
||||
template: "spotlight",
|
||||
frequency: {
|
||||
lifetime: 1,
|
||||
},
|
||||
targeting:
|
||||
"userMonthlyActivity|length >= 7 && userMonthlyActivity|length <= 13 && doesAppNeedPin",
|
||||
},
|
||||
{
|
||||
id: "MULTISTAGE_SPOTLIGHT_MESSAGE",
|
||||
groups: ["panel-test-provider"],
|
||||
|
|
|
@ -46,6 +46,7 @@ support-files=
|
|||
[browser_highlights_section.js]
|
||||
[browser_discovery_card.js]
|
||||
[browser_getScreenshots.js]
|
||||
[browser_multistage_spotlight.js]
|
||||
[browser_newtab_overrides.js]
|
||||
[browser_newtab_header.js]
|
||||
[browser_newtab_last_LinkMenu.js]
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Spotlight } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/Spotlight.jsm"
|
||||
);
|
||||
const { PanelTestProvider } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/PanelTestProvider.jsm"
|
||||
);
|
||||
const { BrowserWindowTracker } = ChromeUtils.import(
|
||||
"resource:///modules/BrowserWindowTracker.jsm"
|
||||
);
|
||||
const { SpecialMessageActions } = ChromeUtils.import(
|
||||
"resource://messaging-system/lib/SpecialMessageActions.jsm"
|
||||
);
|
||||
|
||||
async function waitForClick(selector, win) {
|
||||
await TestUtils.waitForCondition(() => win.document.querySelector(selector));
|
||||
win.document.querySelector(selector).click();
|
||||
}
|
||||
|
||||
async function showDialog(dialogOptions) {
|
||||
Spotlight.showSpotlightDialog(
|
||||
dialogOptions.browser,
|
||||
dialogOptions.message,
|
||||
dialogOptions.dispatchStub
|
||||
);
|
||||
const [win] = await TestUtils.topicObserved("subdialog-loaded");
|
||||
return win;
|
||||
}
|
||||
|
||||
add_task(async function test_specialAction() {
|
||||
let message = (await PanelTestProvider.getMessages()).find(
|
||||
m => m.id === "MULTISTAGE_SPOTLIGHT_MESSAGE"
|
||||
);
|
||||
let dispatchStub = sinon.stub();
|
||||
let browser = BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser;
|
||||
let specialActionStub = sinon.stub(SpecialMessageActions, "handleAction");
|
||||
|
||||
let win = await showDialog({ message, browser, dispatchStub });
|
||||
await waitForClick("button.primary", win);
|
||||
win.close();
|
||||
|
||||
Assert.equal(
|
||||
specialActionStub.callCount,
|
||||
1,
|
||||
"Should be called by primary action"
|
||||
);
|
||||
Assert.deepEqual(
|
||||
specialActionStub.firstCall.args[0],
|
||||
message.content.screens[0].content.primary_button.action,
|
||||
"Should be called with button action"
|
||||
);
|
||||
|
||||
specialActionStub.restore();
|
||||
});
|
|
@ -12,7 +12,7 @@ describe("PanelTestProvider", () => {
|
|||
it("should have correct number of messages", () => {
|
||||
// Careful: when changing this number make sure that new messages also go
|
||||
// through schema verifications.
|
||||
assert.lengthOf(messages, 13);
|
||||
assert.lengthOf(messages, 15);
|
||||
});
|
||||
it("should be a valid message", () => {
|
||||
const updateMessages = messages.filter(
|
||||
|
|
|
@ -344,29 +344,16 @@ const SnapshotGroups = new (class SnapshotGroups {
|
|||
throw new Error("Unknown sortBy value");
|
||||
}
|
||||
let start = Math.max(0, startIndex);
|
||||
let db = await PlacesUtils.promiseDBConnection();
|
||||
let urlRows = await db.executeCached(
|
||||
`
|
||||
SELECT h.url
|
||||
FROM moz_places_metadata_groups_to_snapshots s
|
||||
JOIN moz_places_metadata_snapshots sn USING(place_id)
|
||||
JOIN moz_places h ON h.id = s.place_id
|
||||
WHERE s.group_id = :group_id
|
||||
ORDER BY ${sortBy} ${sortDescending ? "DESC" : "ASC"}
|
||||
LIMIT ${start + count}
|
||||
`,
|
||||
{ group_id: id }
|
||||
);
|
||||
|
||||
let snapshots = [];
|
||||
let urls = urlRows.map(row => row.getResultByName("url"));
|
||||
let end = Math.min(urls.length, count + start);
|
||||
for (let i = start; i < end; i++) {
|
||||
let snapShot = await Snapshots.get(urls[i]);
|
||||
snapshots.push(snapShot);
|
||||
}
|
||||
let snapshots = await Snapshots.query({
|
||||
limit: start + count,
|
||||
group: id,
|
||||
sortBy,
|
||||
sortDescending,
|
||||
});
|
||||
|
||||
return snapshots;
|
||||
let end = Math.min(snapshots.length, count + start);
|
||||
return snapshots.slice(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -463,6 +463,13 @@ const Snapshots = new (class Snapshots {
|
|||
* Whether to include tombstones in the snapshots to obtain.
|
||||
* @param {number} [options.type]
|
||||
* Restrict the snapshots to those with a particular type of page data available.
|
||||
* @param {number} [options.group]
|
||||
* Restrict the snapshots to those within a particular group.
|
||||
* @param {boolean} [sortDescending]
|
||||
* Whether or not to sortDescending. Defaults to true.
|
||||
* @param {string} [sortBy]
|
||||
* A string to choose what to sort the snapshots by, e.g. "last_interaction_at"
|
||||
* By default results are sorted by last_interaction_at.
|
||||
* @returns {Snapshot[]}
|
||||
* Returns snapshots in order of descending last interaction time.
|
||||
*/
|
||||
|
@ -470,12 +477,16 @@ const Snapshots = new (class Snapshots {
|
|||
limit = 100,
|
||||
includeTombstones = false,
|
||||
type = undefined,
|
||||
group = undefined,
|
||||
sortDescending = true,
|
||||
sortBy = "last_interaction_at",
|
||||
} = {}) {
|
||||
await this.#ensureVersionUpdates();
|
||||
let db = await PlacesUtils.promiseDBConnection();
|
||||
|
||||
let clauses = [];
|
||||
let bindings = {};
|
||||
let joins = [];
|
||||
let limitStatement = "";
|
||||
|
||||
if (!includeTombstones) {
|
||||
|
@ -487,6 +498,14 @@ const Snapshots = new (class Snapshots {
|
|||
bindings.type = type;
|
||||
}
|
||||
|
||||
if (group) {
|
||||
clauses.push("group_id = :group");
|
||||
bindings.group = group;
|
||||
joins.push(
|
||||
"LEFT JOIN moz_places_metadata_groups_to_snapshots USING(place_id)"
|
||||
);
|
||||
}
|
||||
|
||||
if (limit != -1) {
|
||||
limitStatement = "LIMIT :limit";
|
||||
bindings.limit = limit;
|
||||
|
@ -496,7 +515,7 @@ const Snapshots = new (class Snapshots {
|
|||
|
||||
let rows = await db.executeCached(
|
||||
`
|
||||
SELECT h.url AS url, IFNULL(s.title, h.title) AS title, created_at,
|
||||
SELECT h.url, IFNULL(s.title, h.title) AS title, created_at,
|
||||
removed_at, document_type, first_interaction_at, last_interaction_at,
|
||||
user_persisted, description, site_name, preview_image_url,
|
||||
group_concat('[' || e.type || ', ' || e.data || ']') AS page_data,
|
||||
|
@ -504,9 +523,10 @@ const Snapshots = new (class Snapshots {
|
|||
FROM moz_places_metadata_snapshots s
|
||||
JOIN moz_places h ON h.id = s.place_id
|
||||
LEFT JOIN moz_places_metadata_snapshots_extra e ON e.place_id = s.place_id
|
||||
${joins.join(" ")}
|
||||
${whereStatement}
|
||||
GROUP BY s.place_id
|
||||
ORDER BY last_interaction_at DESC
|
||||
ORDER BY ${sortBy} ${sortDescending ? "DESC" : "ASC"}
|
||||
${limitStatement}
|
||||
`,
|
||||
bindings
|
||||
|
|
|
@ -8,7 +8,6 @@ support-files =
|
|||
skip-if =
|
||||
os == "linux" && bits = 64 # high frequency intermittent Bug 1744379
|
||||
[browser_browserGlue_upgradeDialog_trigger.js]
|
||||
skip-if = true # temporary disable for bug 1754127
|
||||
[browser_bug538331.js]
|
||||
skip-if = !updater
|
||||
reason = test depends on update channel
|
||||
|
|
|
@ -327,6 +327,13 @@ const PREF_OTHER_DEFAULTS = new Map([
|
|||
["ui.popup.disable_autohide", false],
|
||||
]);
|
||||
|
||||
// Default values for Nimbus urlbar variables that do not have fallback prefs.
|
||||
// Variables with fallback prefs do not need to be defined here because their
|
||||
// defaults are the values of their fallbacks.
|
||||
const NIMBUS_DEFAULTS = {
|
||||
isBestMatchExperiment: false,
|
||||
};
|
||||
|
||||
// Maps preferences under browser.urlbar.suggest to behavior names, as defined
|
||||
// in mozIPlacesAutoComplete.
|
||||
const SUGGEST_PREF_TO_BEHAVIOR = {
|
||||
|
@ -1177,7 +1184,9 @@ class Preferences {
|
|||
|
||||
get _nimbus() {
|
||||
if (!this.__nimbus) {
|
||||
this.__nimbus = NimbusFeatures.urlbar.getAllVariables();
|
||||
this.__nimbus = NimbusFeatures.urlbar.getAllVariables({
|
||||
defaultValues: NIMBUS_DEFAULTS,
|
||||
});
|
||||
}
|
||||
return this.__nimbus;
|
||||
}
|
||||
|
|
|
@ -268,10 +268,37 @@ class ProviderQuickSuggest extends UrlbarProvider {
|
|||
|
||||
this._addedResultInLastQuery = true;
|
||||
|
||||
// Record the Nimbus "exposure" event. Note that `recordExposureEvent` will
|
||||
// make sure only one event gets recorded even it is called multiple times
|
||||
// in the same browser session. However, it's an expensive call regardless,
|
||||
// so do it only once per browser session and do it on idle.
|
||||
// The user triggered a suggestion. Per spec, the Nimbus exposure event
|
||||
// should be recorded now, subject to the following logic:
|
||||
//
|
||||
// If the user is in a best match experiment:
|
||||
// Record if the suggestion is itself a best match and either of the
|
||||
// following are true:
|
||||
// * The best match feature is enabled (i.e., the user is in a treatment
|
||||
// branch), and the user has not disabled best match
|
||||
// * The best match feature is disabled (i.e., the user is in the control
|
||||
// branch)
|
||||
// Else:
|
||||
// Record the event
|
||||
if (
|
||||
!UrlbarPrefs.get("isBestMatchExperiment") ||
|
||||
(suggestion.is_best_match &&
|
||||
(!UrlbarPrefs.get("bestMatchEnabled") ||
|
||||
UrlbarPrefs.get("suggest.bestmatch")))
|
||||
) {
|
||||
this._ensureExposureEventRecorded();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the Nimbus exposure event if it hasn't already been recorded during
|
||||
* the app session. This method actually queues the recording on idle because
|
||||
* it's potentially an expensive operation.
|
||||
*/
|
||||
_ensureExposureEventRecorded() {
|
||||
// `recordExposureEvent()` makes sure only one event is recorded per app
|
||||
// session even if it's called many times, but since it may be expensive, we
|
||||
// also keep `_recordedExposureEvent`.
|
||||
if (!this._recordedExposureEvent) {
|
||||
this._recordedExposureEvent = true;
|
||||
Services.tm.idleDispatchToMainThread(() =>
|
||||
|
|
|
@ -623,18 +623,38 @@ Changelog
|
|||
Nimbus Exposure Event
|
||||
---------------------
|
||||
|
||||
A `Nimbus exposure event`_ is recorded the first time a user query matches a
|
||||
Firefox Suggest suggestion while the user is enrolled in a Nimbus experiment or
|
||||
rollout. At most one event per app session is recorded.
|
||||
A `Nimbus exposure event`_ is recorded once per app session when the user first
|
||||
encounters the UI of an experiment in which they're enrolled. The timing of the
|
||||
event depends on the experiment.
|
||||
|
||||
.. _Nimbus exposure event: https://experimenter.info/jetstream/jetstream/#enrollment-vs-exposure
|
||||
Listed below are the slugs of supported experiments along with details on when
|
||||
their exposure events are recorded.
|
||||
|
||||
:firefox-suggest-best-match_:
|
||||
If the user is in a treatment branch and they did not disable best match, the
|
||||
event is recorded the first time they trigger a best match; if the user is in
|
||||
a treatment branch and they did disable best match, the event is not recorded
|
||||
at all. If the user is in the control branch, the event is recorded the first
|
||||
time they would have triggered a best match. (Users in the control branch
|
||||
cannot "disable" best match since the feature is totally hidden from them.)
|
||||
:All other experiments:
|
||||
For all other experiments not listed above, the event is recorded the first
|
||||
time the user triggers a Firefox Suggest suggestion.
|
||||
|
||||
Changelog
|
||||
Firefox 92.0
|
||||
Introduced. [Bug 1724076_, 1727392_]
|
||||
|
||||
Firefox 99.0
|
||||
Support for the firefox-suggest-best-match_ experiment is added. [Bug
|
||||
1752953_]
|
||||
|
||||
.. _Nimbus exposure event: https://experimenter.info/jetstream/jetstream/#enrollment-vs-exposure
|
||||
.. _firefox-suggest-best-match: https://experimenter.services.mozilla.com/nimbus/firefox-suggest-best-match/
|
||||
|
||||
.. _1724076: https://bugzilla.mozilla.org/show_bug.cgi?id=1724076
|
||||
.. _1727392: https://bugzilla.mozilla.org/show_bug.cgi?id=1727392
|
||||
.. _1752953: https://bugzilla.mozilla.org/show_bug.cgi?id=1752953
|
||||
|
||||
Merino Search Queries
|
||||
---------------------
|
||||
|
|
|
@ -724,6 +724,63 @@ class QSTestUtils {
|
|||
await unenrollUpdatePromise;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the Nimbus exposure event.
|
||||
*/
|
||||
async clearExposureEvent() {
|
||||
// Exposure event recording is queued to the idle thread, so wait for idle
|
||||
// before we start so any events from previous tasks will have been recorded
|
||||
// and won't interfere with this task.
|
||||
await new Promise(resolve => Services.tm.idleDispatchToMainThread(resolve));
|
||||
|
||||
Services.telemetry.clearEvents();
|
||||
NimbusFeatures.urlbar._didSendExposureEvent = false;
|
||||
UrlbarProviderQuickSuggest._recordedExposureEvent = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the Nimbus exposure event is recorded or not as expected.
|
||||
*
|
||||
* @param {boolean} expectedRecorded
|
||||
* Whether the event is expected to be recorded.
|
||||
* @param {string} [branchSlug]
|
||||
* If the event is expected to be recorded, then this should be the name of
|
||||
* the experiment branch for which it was recorded.
|
||||
*/
|
||||
async assertExposureEvent(expectedRecorded) {
|
||||
this.Assert.equal(
|
||||
UrlbarProviderQuickSuggest._recordedExposureEvent,
|
||||
expectedRecorded,
|
||||
"_recordedExposureEvent is correct"
|
||||
);
|
||||
|
||||
let filter = {
|
||||
category: "normandy",
|
||||
method: "expose",
|
||||
object: "nimbus_experiment",
|
||||
};
|
||||
|
||||
let expectedEvents = [];
|
||||
if (expectedRecorded) {
|
||||
expectedEvents.push({
|
||||
...filter,
|
||||
extra: {
|
||||
branchSlug: "control",
|
||||
featureId: "urlbar",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// The event recording is queued to the idle thread when the search starts,
|
||||
// so likewise queue the assert to idle instead of doing it immediately.
|
||||
await new Promise(resolve => {
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
TelemetryTestUtils.assertEvents(expectedEvents, filter);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var QuickSuggestTestUtils = new QSTestUtils();
|
||||
|
|
|
@ -27,6 +27,16 @@ const SUGGESTIONS = [1, 2, 3].map(i => ({
|
|||
_test_is_best_match: true,
|
||||
}));
|
||||
|
||||
const NON_BEST_MATCH_SUGGESTION = {
|
||||
id: 99,
|
||||
title: "Non-best match",
|
||||
url: "http://example.com/nonbestmatch",
|
||||
keywords: ["non"],
|
||||
click_url: "http://example.com/click",
|
||||
impression_url: "http://example.com/impression",
|
||||
advertiser: "TestAdvertiser",
|
||||
};
|
||||
|
||||
add_task(async function init() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
|
@ -42,7 +52,9 @@ add_task(async function init() {
|
|||
await UrlbarProviderQuickSuggest._blockTaskQueue.emptyPromise;
|
||||
await UrlbarProviderQuickSuggest.clearBlockedSuggestions();
|
||||
|
||||
await QuickSuggestTestUtils.ensureQuickSuggestInit(SUGGESTIONS);
|
||||
await QuickSuggestTestUtils.ensureQuickSuggestInit(
|
||||
SUGGESTIONS.concat(NON_BEST_MATCH_SUGGESTION)
|
||||
);
|
||||
});
|
||||
|
||||
// Picks the block button with the keyboard.
|
||||
|
@ -214,3 +226,109 @@ add_task(async function blockingDisabled() {
|
|||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
||||
|
||||
// When the user is enrolled in a best match experiment with the feature enabled
|
||||
// (i.e., the treatment branch), the Nimbus exposure event should be recorded
|
||||
// after triggering a best match.
|
||||
add_task(async function nimbusExposure_featureEnabled() {
|
||||
await doNimbusExposureTest({
|
||||
bestMatchEnabled: true,
|
||||
bestMatchExpected: true,
|
||||
exposureEventExpected: true,
|
||||
});
|
||||
});
|
||||
|
||||
// When the user is enrolled in a best match experiment with the feature enabled
|
||||
// (i.e., the treatment branch) but the user disabled best match, the Nimbus
|
||||
// exposure event should not be recorded at all.
|
||||
add_task(async function nimbusExposure_featureEnabled_userDisabled() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.urlbar.suggest.bestmatch", false]],
|
||||
});
|
||||
await doNimbusExposureTest({
|
||||
bestMatchEnabled: true,
|
||||
bestMatchExpected: false,
|
||||
exposureEventExpected: false,
|
||||
});
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
||||
|
||||
// When the user is enrolled in a best match experiment with the feature
|
||||
// disabled (i.e., the control branch), the Nimbus exposure event should be
|
||||
// recorded when the user would have triggered a best match.
|
||||
add_task(async function nimbusExposure_featureDisabled() {
|
||||
await doNimbusExposureTest({
|
||||
bestMatchEnabled: false,
|
||||
bestMatchExpected: false,
|
||||
exposureEventExpected: true,
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Installs a mock experiment, triggers best match, and asserts that the Nimbus
|
||||
* exposure event was or was not recorded appropriately.
|
||||
*
|
||||
* @param {boolean} bestMatchEnabled
|
||||
* The value to set for the experiment's `bestMatchEnabled` Nimbus variable.
|
||||
* @param {boolean} bestMatchExpected
|
||||
* Whether a best match result is expected to be shown.
|
||||
* @param {boolean} exposureEventExpected
|
||||
* Whether an exposure event is expected to be recorded.
|
||||
*/
|
||||
async function doNimbusExposureTest({
|
||||
bestMatchEnabled,
|
||||
bestMatchExpected,
|
||||
exposureEventExpected,
|
||||
}) {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.urlbar.bestMatch.enabled", false]],
|
||||
});
|
||||
await QuickSuggestTestUtils.clearExposureEvent();
|
||||
await QuickSuggestTestUtils.withExperiment({
|
||||
valueOverrides: {
|
||||
bestMatchEnabled,
|
||||
isBestMatchExperiment: true,
|
||||
},
|
||||
callback: async () => {
|
||||
// No exposure event should be recorded after only enrolling.
|
||||
await QuickSuggestTestUtils.assertExposureEvent(false);
|
||||
|
||||
// Do a search that doesn't trigger a best match. No exposure event should
|
||||
// be recorded.
|
||||
info("Doing first search");
|
||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||
window,
|
||||
value: NON_BEST_MATCH_SUGGESTION.keywords[0],
|
||||
fireInputEvent: true,
|
||||
});
|
||||
await QuickSuggestTestUtils.assertIsQuickSuggest({
|
||||
window,
|
||||
url: NON_BEST_MATCH_SUGGESTION.url,
|
||||
});
|
||||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
await QuickSuggestTestUtils.assertExposureEvent(false);
|
||||
|
||||
// Do a search that would have triggered a best match. The exposure event
|
||||
// should be recorded.
|
||||
info("Doing second search");
|
||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||
window,
|
||||
value: SUGGESTIONS[0].keywords[0],
|
||||
fireInputEvent: true,
|
||||
});
|
||||
await QuickSuggestTestUtils.assertIsQuickSuggest({
|
||||
window,
|
||||
originalUrl: SUGGESTIONS[0].url,
|
||||
isBestMatch: bestMatchExpected,
|
||||
});
|
||||
await QuickSuggestTestUtils.assertExposureEvent(
|
||||
exposureEventExpected,
|
||||
"control"
|
||||
);
|
||||
|
||||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
},
|
||||
});
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
}
|
||||
|
|
|
@ -771,92 +771,45 @@ add_task(async function bestmatchLearnMore() {
|
|||
// Tests the Nimbus exposure event gets recorded after a quick suggest result
|
||||
// impression.
|
||||
add_task(async function nimbusExposure() {
|
||||
// Exposure event recording is queued to the idle thread, so wait for idle
|
||||
// before we start so any events from previous tasks will have been recorded
|
||||
// and won't interfere with this task.
|
||||
await new Promise(resolve => Services.tm.idleDispatchToMainThread(resolve));
|
||||
await QuickSuggestTestUtils.clearExposureEvent();
|
||||
|
||||
Services.telemetry.clearEvents();
|
||||
NimbusFeatures.urlbar._didSendExposureEvent = false;
|
||||
UrlbarProviderQuickSuggest._recordedExposureEvent = false;
|
||||
let doExperimentCleanup = await QuickSuggestTestUtils.enrollExperiment({
|
||||
await QuickSuggestTestUtils.withExperiment({
|
||||
valueOverrides: {
|
||||
quickSuggestEnabled: true,
|
||||
quickSuggestShouldShowOnboardingDialog: false,
|
||||
},
|
||||
callback: async () => {
|
||||
// No exposure event should be recorded after only enrolling.
|
||||
await QuickSuggestTestUtils.assertExposureEvent(false);
|
||||
|
||||
// Do a search that doesn't trigger a quick suggest result. No exposure
|
||||
// event should be recorded.
|
||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||
window,
|
||||
value: "nimbusExposure no result",
|
||||
fireInputEvent: true,
|
||||
});
|
||||
await QuickSuggestTestUtils.assertNoQuickSuggestResults(window);
|
||||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
QuickSuggestTestUtils.assertExposureEvent(false);
|
||||
|
||||
// Do a search that does trigger a quick suggest result. The exposure
|
||||
// event should be recorded.
|
||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||
window,
|
||||
value: TEST_SEARCH_STRING,
|
||||
fireInputEvent: true,
|
||||
});
|
||||
await QuickSuggestTestUtils.assertIsQuickSuggest({
|
||||
window,
|
||||
index: 1,
|
||||
url: TEST_URL,
|
||||
});
|
||||
await QuickSuggestTestUtils.assertExposureEvent(true, "control");
|
||||
|
||||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
},
|
||||
});
|
||||
|
||||
// This filter is needed to exclude the enrollment event.
|
||||
let filter = {
|
||||
category: "normandy",
|
||||
method: "expose",
|
||||
object: "nimbus_experiment",
|
||||
};
|
||||
|
||||
// No exposure event should be recorded after only enrolling.
|
||||
Assert.ok(
|
||||
!UrlbarProviderQuickSuggest._recordedExposureEvent,
|
||||
"_recordedExposureEvent remains false after enrolling"
|
||||
);
|
||||
TelemetryTestUtils.assertEvents([], filter);
|
||||
|
||||
// Do a search that doesn't trigger a quick suggest result. No exposure event
|
||||
// should be recorded.
|
||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||
window,
|
||||
value: "nimbusExposure no result",
|
||||
fireInputEvent: true,
|
||||
});
|
||||
await QuickSuggestTestUtils.assertNoQuickSuggestResults(window);
|
||||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
Assert.ok(
|
||||
!UrlbarProviderQuickSuggest._recordedExposureEvent,
|
||||
"_recordedExposureEvent remains false after no quick suggest result"
|
||||
);
|
||||
TelemetryTestUtils.assertEvents([], filter);
|
||||
|
||||
// Do a search that does trigger a quick suggest result. The exposure event
|
||||
// should be recorded.
|
||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||
window,
|
||||
value: TEST_SEARCH_STRING,
|
||||
fireInputEvent: true,
|
||||
});
|
||||
await QuickSuggestTestUtils.assertIsQuickSuggest({
|
||||
window,
|
||||
index: 1,
|
||||
url: TEST_URL,
|
||||
});
|
||||
Assert.ok(
|
||||
UrlbarProviderQuickSuggest._recordedExposureEvent,
|
||||
"_recordedExposureEvent is true after showing quick suggest result"
|
||||
);
|
||||
|
||||
// The event recording is queued to the idle thread when the search starts, so
|
||||
// likewise queue the assert to idle instead of doing it immediately.
|
||||
await new Promise(resolve => {
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
TelemetryTestUtils.assertEvents(
|
||||
[
|
||||
{
|
||||
category: "normandy",
|
||||
method: "expose",
|
||||
object: "nimbus_experiment",
|
||||
extra: {
|
||||
branchSlug: "control",
|
||||
featureId: "urlbar",
|
||||
},
|
||||
},
|
||||
],
|
||||
filter
|
||||
);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
|
||||
await doExperimentCleanup();
|
||||
});
|
||||
|
||||
// The "firefox-suggest-update" notification should cause TelemetryEnvironment
|
||||
|
|
|
@ -249,8 +249,8 @@ appmenu-help-more-troubleshooting-info =
|
|||
.accesskey = t
|
||||
appmenu-help-report-site-issue =
|
||||
.label = Report site issue…
|
||||
appmenu-help-feedback-page =
|
||||
.label = Submit feedback…
|
||||
appmenu-help-share-ideas =
|
||||
.label = Share ideas and feedback…
|
||||
.accesskey = S
|
||||
|
||||
## appmenu-help-enter-troubleshoot-mode and appmenu-help-exit-troubleshoot-mode
|
||||
|
|
|
@ -305,8 +305,8 @@ menu-help-more-troubleshooting-info =
|
|||
.accesskey = T
|
||||
menu-help-report-site-issue =
|
||||
.label = Report Site Issue…
|
||||
menu-help-feedback-page =
|
||||
.label = Submit Feedback…
|
||||
menu-help-share-ideas =
|
||||
.label = Share Ideas and Feedback…
|
||||
.accesskey = S
|
||||
menu-help-enter-troubleshoot-mode2 =
|
||||
.label = Troubleshoot Mode…
|
||||
|
|
|
@ -164,3 +164,15 @@ spotlight-total-cookie-protection-body = Total Cookie Protection stops trackers
|
|||
spotlight-total-cookie-protection-expanded = { -brand-short-name } builds a fence around cookies, limiting them to the site you’re on so trackers can’t use them to follow you. With early access, you’ll help optimize this feature so we can keep building a better web for everyone.
|
||||
spotlight-total-cookie-protection-primary-button = Turn on Total Cookie Protection
|
||||
spotlight-total-cookie-protection-secondary-button = Not now
|
||||
|
||||
## Emotive Continuous Onboarding
|
||||
|
||||
spotlight-better-internet-header = A better internet starts with you
|
||||
spotlight-better-internet-body = When you use { -brand-short-name}, you’re voting for an open and accessible internet that’s better for everyone.
|
||||
spotlight-peace-mind-header = We’ve got you covered
|
||||
spotlight-peace-mind-body = Every month, { -brand-short-name } blocks an average of over 3,000 trackers per user. Because nothing, especially privacy nuisances like trackers, should stand between you and the good internet.
|
||||
spotlight-pin-primary-button = { PLATFORM() ->
|
||||
[macos] Keep in Dock
|
||||
*[other] Pin to taskbar
|
||||
}
|
||||
spotlight-pin-secondary-button = Not now
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%include ../../shared/customizableui/panelUI.inc.css
|
||||
@import "chrome://browser/skin/customizableui/panelUI.inc.css";
|
||||
|
||||
#customizationui-widget-panel[viewId="PanelUI-profiler"][type="arrow"][side="top"],
|
||||
#customizationui-widget-panel[viewId="PanelUI-profiler"][type="arrow"][side="bottom"] {
|
||||
|
|
|
@ -15,7 +15,7 @@ browser.jar:
|
|||
skin/classic/browser/pageInfo.png
|
||||
* skin/classic/browser/webRTC-indicator.css
|
||||
skin/classic/browser/webRTC-legacy-indicator.css (../shared/webRTC-legacy-indicator.css)
|
||||
* skin/classic/browser/customizableui/panelUI.css (customizableui/panelUI.css)
|
||||
skin/classic/browser/customizableui/panelUI.css (customizableui/panelUI.css)
|
||||
skin/classic/browser/downloads/allDownloadsView.css (downloads/allDownloadsView.css)
|
||||
skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
|
||||
skin/classic/browser/places/editBookmark.css (places/editBookmark.css)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%include ../../shared/customizableui/panelUI.inc.css
|
||||
@import "chrome://browser/skin/customizableui/panelUI.inc.css";
|
||||
|
||||
#customizationui-widget-panel[viewId="PanelUI-profiler"][type="arrow"][side="top"],
|
||||
#customizationui-widget-panel[viewId="PanelUI-profiler"][type="arrow"][side="bottom"] {
|
||||
|
|
|
@ -11,7 +11,7 @@ browser.jar:
|
|||
* skin/classic/browser/compacttheme.css
|
||||
skin/classic/browser/pageInfo.css
|
||||
* skin/classic/browser/webRTC-indicator.css
|
||||
* skin/classic/browser/customizableui/panelUI.css (customizableui/panelUI.css)
|
||||
skin/classic/browser/customizableui/panelUI.css (customizableui/panelUI.css)
|
||||
skin/classic/browser/downloads/allDownloadsView.css (downloads/allDownloadsView.css)
|
||||
skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
|
||||
skin/classic/browser/monitor-base.png
|
||||
|
|
|
@ -673,14 +673,17 @@ toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton
|
|||
|
||||
.PanelUI-fxa-service-description-label,
|
||||
.PanelUI-remotetabs-instruction-label {
|
||||
/* Use 'lighter' font for this to de-emphasize it compared to the title.
|
||||
* We use 300 on Linux because 100 is too light (lacks contrast with
|
||||
* the background) for some fonts in combination with anti-aliasing. */
|
||||
%if defined(XP_MACOSX) || defined(XP_WIN)
|
||||
/* Use 'lighter' font for this to de-emphasize it compared to the title. */
|
||||
font-weight: lighter;
|
||||
%else
|
||||
font-weight: 300;
|
||||
%endif
|
||||
}
|
||||
|
||||
@media (-moz-platform: linux) {
|
||||
.PanelUI-fxa-service-description-label,
|
||||
.PanelUI-remotetabs-instruction-label {
|
||||
/* Use 300 on Linux because 100 is too light (lacks contrast with
|
||||
* the background) for some fonts in combination with anti-aliasing. */
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
|
||||
#fxa-menu-header-title {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
skin/classic/browser/controlcenter/panel.css (../shared/controlcenter/panel.css)
|
||||
skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
|
||||
skin/classic/browser/controlcenter/hero-message-background.svg (../shared/controlcenter/hero-message-background.svg)
|
||||
skin/classic/browser/customizableui/panelUI.inc.css (../shared/customizableui/panelUI.inc.css)
|
||||
skin/classic/browser/customizableui/empty-overflow-panel.png (../shared/customizableui/empty-overflow-panel.png)
|
||||
skin/classic/browser/customizableui/empty-overflow-panel@2x.png (../shared/customizableui/empty-overflow-panel@2x.png)
|
||||
skin/classic/browser/customizableui/density-compact.svg (../shared/customizableui/density-compact.svg)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%include ../../shared/customizableui/panelUI.inc.css
|
||||
@import "chrome://browser/skin/customizableui/panelUI.inc.css";
|
||||
|
||||
#customizationui-widget-panel[viewId="PanelUI-profiler"][type="arrow"][side="top"],
|
||||
#customizationui-widget-panel[viewId="PanelUI-profiler"][type="arrow"][side="bottom"] {
|
||||
|
|
|
@ -15,7 +15,7 @@ browser.jar:
|
|||
skin/classic/browser/pageInfo.png
|
||||
* skin/classic/browser/webRTC-indicator.css
|
||||
skin/classic/browser/webRTC-legacy-indicator.css (../shared/webRTC-legacy-indicator.css)
|
||||
* skin/classic/browser/customizableui/panelUI.css (customizableui/panelUI.css)
|
||||
skin/classic/browser/customizableui/panelUI.css (customizableui/panelUI.css)
|
||||
skin/classic/browser/downloads/allDownloadsView.css (downloads/allDownloadsView.css)
|
||||
skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
|
||||
skin/classic/browser/notification-icons/camera.png (notification-icons/camera.png)
|
||||
|
|
|
@ -61,7 +61,7 @@ to work from wherever they are. If they don't, please file a bug.
|
|||
Invoking mach through Visual Studio
|
||||
===================================
|
||||
|
||||
It's possible to build the tree via Visual Studio. There is some light magic
|
||||
It's possible to run mach commands via Visual Studio. There is some light magic
|
||||
involved here.
|
||||
|
||||
Alongside the Visual Studio project files is a batch script named ``mach.bat``.
|
||||
|
@ -71,7 +71,12 @@ and invokes *mach* inside an msys shell with the arguments specified to the
|
|||
batch script. This script essentially allows you to invoke mach commands
|
||||
inside the MozillaBuild environment without having to load MozillaBuild.
|
||||
|
||||
While projects currently only utilize the ``mach build`` command, the batch
|
||||
script does not limit it's use: any mach command can be invoked. Developers
|
||||
may abuse this fact to add custom projects and commands that invoke other
|
||||
mach commands.
|
||||
Projects currently utilize the ``mach build`` and ``mach clobber`` commands
|
||||
for building and cleaning the tree respectively. Note that running ``clobber``
|
||||
deletes the Visual Studio project files, and running ``build`` recreates them.
|
||||
This might cause issues while Visual Studio is running. Thus a full rebuild is
|
||||
currently neither recommended, nor supported, but incremental builds should work.
|
||||
|
||||
The batch script does not limit its use: any mach command can be invoked.
|
||||
Developers may use this fact to add custom projects and commands that invoke
|
||||
other mach commands.
|
||||
|
|
|
@ -34,4 +34,7 @@ DevToolsModules(
|
|||
)
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ["test/chrome/chrome.ini"]
|
||||
BROWSER_CHROME_MANIFESTS += ["test/browser/browser.ini"]
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
"test/browser/browser.ini",
|
||||
"test/node/stubs/reps/stubs.ini",
|
||||
]
|
||||
|
|
|
@ -6,3 +6,4 @@ support-files =
|
|||
!/devtools/client/shared/test/telemetry-test-helpers.js
|
||||
|
||||
[browser_notification_box_basic.js]
|
||||
[browser_reps_stubs.js]
|
||||
|
|
|
@ -0,0 +1,218 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from ../../../../shared/test/shared-head.js */
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/devtools/client/shared/test/shared-head.js",
|
||||
this
|
||||
);
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,stub generation";
|
||||
/**
|
||||
* A Map keyed by filename, and for which the value is also a Map, with the key being the
|
||||
* label for the stub, and the value the expression to evaluate to get the stub.
|
||||
*/
|
||||
const EXPRESSIONS_BY_FILE = {
|
||||
"infinity.js": new Map([
|
||||
["Infinity", `Infinity`],
|
||||
["NegativeInfinity", `-Infinity`],
|
||||
]),
|
||||
"nan.js": new Map([["NaN", `2 * document`]]),
|
||||
"null.js": new Map([["Null", `null`]]),
|
||||
"number.js": new Map([
|
||||
["Int", `2 + 3`],
|
||||
["True", `true`],
|
||||
["False", `false`],
|
||||
["NegZeroGrip", `1 / -Infinity`],
|
||||
]),
|
||||
"undefined.js": new Map([["Undefined", `undefined`]]),
|
||||
// XXX: File a bug blocking Bug 1671400 for enabling automatic generation for one of
|
||||
// the following file.
|
||||
// "accessible.js",
|
||||
// "accessor.js",
|
||||
// "attribute.js",
|
||||
// "big-int.js",
|
||||
// "comment-node.js",
|
||||
// "date-time.js",
|
||||
// "document-type.js",
|
||||
// "document.js",
|
||||
// "element-node.js",
|
||||
// "error.js",
|
||||
// "event.js",
|
||||
// "failure.js",
|
||||
// "function.js",
|
||||
// "grip-array.js",
|
||||
// "grip-map-entry.js",
|
||||
// "grip-map.js",
|
||||
// "grip.js",
|
||||
// "long-string.js",
|
||||
// "object-with-text.js",
|
||||
// "object-with-url.js",
|
||||
// "promise.js",
|
||||
// "regexp.js",
|
||||
// "stylesheet.js",
|
||||
// "symbol.js",
|
||||
// "text-node.js",
|
||||
// "window.js",
|
||||
};
|
||||
|
||||
add_task(async function() {
|
||||
const isStubsUpdate = env.get(STUBS_UPDATE_ENV) == "true";
|
||||
|
||||
const tab = await addTab(TEST_URI);
|
||||
const {
|
||||
CommandsFactory,
|
||||
} = require("devtools/shared/commands/commands-factory");
|
||||
const commands = await CommandsFactory.forTab(tab);
|
||||
await commands.targetCommand.startListening();
|
||||
|
||||
let failed = false;
|
||||
for (const stubFile of Object.keys(EXPRESSIONS_BY_FILE)) {
|
||||
info(`${isStubsUpdate ? "Update" : "Check"} ${stubFile}`);
|
||||
|
||||
const generatedStubs = await generateStubs(commands, stubFile);
|
||||
if (isStubsUpdate) {
|
||||
await writeStubsToFile(env, stubFile, generatedStubs);
|
||||
ok(true, `${stubFile} was updated`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const existingStubs = getStubFile(stubFile);
|
||||
if (generatedStubs.size !== existingStubs.size) {
|
||||
failed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const [key, packet] of generatedStubs) {
|
||||
const packetStr = getSerializedPacket(packet, { sortKeys: true });
|
||||
const grip = getSerializedPacket(existingStubs.get(key), {
|
||||
sortKeys: true,
|
||||
});
|
||||
is(packetStr, grip, `"${key}" packet has expected value`);
|
||||
failed = failed || packetStr !== grip;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
ok(
|
||||
false,
|
||||
"The reps stubs need to be updated by running `" +
|
||||
`mach test ${getCurrentTestFilePath()} --headless --setenv STUBS_UPDATE=true` +
|
||||
"`"
|
||||
);
|
||||
} else {
|
||||
ok(true, "Stubs are up to date");
|
||||
}
|
||||
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
||||
async function generateStubs(commands, stubFile) {
|
||||
const stubs = new Map();
|
||||
|
||||
for (const [key, expression] of EXPRESSIONS_BY_FILE[stubFile]) {
|
||||
const { result } = await commands.scriptCommand.execute(expression);
|
||||
stubs.set(key, getCleanedPacket(key, result));
|
||||
}
|
||||
|
||||
return stubs;
|
||||
}
|
||||
|
||||
function getCleanedPacket(key, packet) {
|
||||
// TODO: Remove / normalize any data that is not stable
|
||||
return packet;
|
||||
}
|
||||
|
||||
// HELPER
|
||||
|
||||
const CHROME_PREFIX = "chrome://mochitests/content/browser/";
|
||||
const STUBS_FOLDER = "devtools/client/shared/components/test/node/stubs/reps/";
|
||||
const STUBS_UPDATE_ENV = "STUBS_UPDATE";
|
||||
|
||||
/**
|
||||
* Write stubs to a given file
|
||||
*
|
||||
* @param {Object} env
|
||||
* @param {String} fileName: The file to write the stubs in.
|
||||
* @param {Map} packets: A Map of the packets.
|
||||
*/
|
||||
async function writeStubsToFile(env, fileName, packets) {
|
||||
const mozRepo = env.get("MOZ_DEVELOPER_REPO_DIR");
|
||||
const filePath = `${mozRepo}/${STUBS_FOLDER + fileName}`;
|
||||
|
||||
const stubs = Array.from(packets.entries()).map(([key, packet]) => {
|
||||
const stringifiedPacket = getSerializedPacket(packet);
|
||||
return `stubs.set(\`${key}\`, ${stringifiedPacket});`;
|
||||
});
|
||||
|
||||
const fileContent = `/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
"use strict";
|
||||
/*
|
||||
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN browser_reps_stubs.js with STUBS_UPDATE=true env TO UPDATE.
|
||||
*/
|
||||
|
||||
const stubs = new Map();
|
||||
${stubs.join("\n\n")}
|
||||
|
||||
module.exports = stubs;
|
||||
`;
|
||||
|
||||
const textEncoder = new TextEncoder();
|
||||
await IOUtils.write(filePath, textEncoder.encode(fileContent));
|
||||
}
|
||||
|
||||
function getStubFile(fileName) {
|
||||
return require(CHROME_PREFIX + STUBS_FOLDER + fileName);
|
||||
}
|
||||
|
||||
function sortObjectKeys(obj) {
|
||||
const isArray = Array.isArray(obj);
|
||||
const isObject = Object.prototype.toString.call(obj) === "[object Object]";
|
||||
const isFront = obj?._grip;
|
||||
|
||||
if (isObject && !isFront) {
|
||||
// Reorder keys for objects, but skip fronts to avoid infinite recursion.
|
||||
const sortedKeys = Object.keys(obj).sort((k1, k2) => k1.localeCompare(k2));
|
||||
const withSortedKeys = {};
|
||||
sortedKeys.forEach(k => {
|
||||
withSortedKeys[k] = k !== "stacktrace" ? sortObjectKeys(obj[k]) : obj[k];
|
||||
});
|
||||
return withSortedKeys;
|
||||
} else if (isArray) {
|
||||
return obj.map(item => sortObjectKeys(item));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} packet
|
||||
* The packet to serialize.
|
||||
* @param {Object}
|
||||
* - {Boolean} sortKeys: pass true to sort all keys alphabetically in the
|
||||
* packet before serialization. For instance stub comparison should not
|
||||
* fail if the order of properties changed.
|
||||
*/
|
||||
function getSerializedPacket(packet, { sortKeys = false } = {}) {
|
||||
if (sortKeys) {
|
||||
packet = sortObjectKeys(packet);
|
||||
}
|
||||
|
||||
return JSON.stringify(
|
||||
packet,
|
||||
function(_, value) {
|
||||
// The message can have fronts that we need to serialize
|
||||
if (value && value._grip) {
|
||||
return { _grip: value._grip, actorID: value.actorID };
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
2
|
||||
);
|
||||
}
|
|
@ -67,7 +67,7 @@ describe("Boolean", () => {
|
|||
|
||||
describe("Negative Zero", () => {
|
||||
const stubNegativeZeroGrip = stubs.get("NegZeroGrip");
|
||||
const stubNegativeZeroValue = stubs.get("NegZeroValue");
|
||||
const stubNegativeZeroValue = -0;
|
||||
|
||||
it("correctly selects Number Rep for negative zero grip", () => {
|
||||
expect(getRep(stubNegativeZeroGrip)).toBe(Number.rep);
|
||||
|
@ -121,12 +121,11 @@ describe("Zero", () => {
|
|||
});
|
||||
|
||||
describe("Unsafe Int", () => {
|
||||
const stub = stubs.get("UnsafeInt");
|
||||
|
||||
it("renders with expected test content for a long number", () => {
|
||||
const renderedComponent = shallow(
|
||||
Rep({
|
||||
object: stub,
|
||||
// eslint-disable-next-line no-loss-of-precision
|
||||
object: 900719925474099122,
|
||||
shouldRenderTooltip: true,
|
||||
})
|
||||
);
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// This file is a fake test so we can have support files in the stubs.ini, which are then
|
||||
// referenced as support files in the webconsole mochitest ini file.
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function() {
|
||||
ok(true, "this is not a test");
|
||||
});
|
|
@ -3,12 +3,16 @@
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
"use strict";
|
||||
/*
|
||||
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN browser_reps_stubs.js with STUBS_UPDATE=true env TO UPDATE.
|
||||
*/
|
||||
|
||||
const stubs = new Map();
|
||||
stubs.set("Infinity", {
|
||||
stubs.set(`Infinity`, {
|
||||
type: "Infinity",
|
||||
});
|
||||
stubs.set("NegativeInfinity", {
|
||||
|
||||
stubs.set(`NegativeInfinity`, {
|
||||
type: "-Infinity",
|
||||
});
|
||||
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
"use strict";
|
||||
/*
|
||||
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN browser_reps_stubs.js with STUBS_UPDATE=true env TO UPDATE.
|
||||
*/
|
||||
|
||||
const stubs = new Map();
|
||||
stubs.set("NaN", {
|
||||
stubs.set(`NaN`, {
|
||||
type: "NaN",
|
||||
});
|
||||
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
"use strict";
|
||||
/*
|
||||
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN browser_reps_stubs.js with STUBS_UPDATE=true env TO UPDATE.
|
||||
*/
|
||||
|
||||
const stubs = new Map();
|
||||
stubs.set("Null", {
|
||||
stubs.set(`Null`, {
|
||||
type: "null",
|
||||
});
|
||||
|
||||
|
|
|
@ -3,16 +3,19 @@
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
"use strict";
|
||||
/*
|
||||
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN browser_reps_stubs.js with STUBS_UPDATE=true env TO UPDATE.
|
||||
*/
|
||||
|
||||
const stubs = new Map();
|
||||
stubs.set("Int", 5);
|
||||
stubs.set("True", true);
|
||||
stubs.set("False", false);
|
||||
stubs.set("NegZeroValue", -0);
|
||||
stubs.set("NegZeroGrip", {
|
||||
stubs.set(`Int`, 5);
|
||||
|
||||
stubs.set(`True`, true);
|
||||
|
||||
stubs.set(`False`, false);
|
||||
|
||||
stubs.set(`NegZeroGrip`, {
|
||||
type: "-0",
|
||||
});
|
||||
// eslint-disable-next-line no-loss-of-precision
|
||||
stubs.set("UnsafeInt", 900719925474099122);
|
||||
|
||||
module.exports = stubs;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
[DEFAULT]
|
||||
tags = devtools
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
infinity.js
|
||||
nan.js
|
||||
null.js
|
||||
number.js
|
||||
undefined.js
|
||||
|
||||
[browser_dummy.js]
|
||||
skip-if=true #This is only here so we can expose the support files in other ini files.
|
|
@ -3,9 +3,12 @@
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
"use strict";
|
||||
/*
|
||||
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN browser_reps_stubs.js with STUBS_UPDATE=true env TO UPDATE.
|
||||
*/
|
||||
|
||||
const stubs = new Map();
|
||||
stubs.set("Undefined", {
|
||||
stubs.set(`Undefined`, {
|
||||
type: "undefined",
|
||||
});
|
||||
|
||||
|
|
|
@ -31,8 +31,6 @@ support-files =
|
|||
inspector-search-data.html
|
||||
inspector-traversal-data.html
|
||||
inspector-shadow.html
|
||||
navigate-first.html
|
||||
navigate-second.html
|
||||
storage-cookies-same-name.html
|
||||
storage-dynamic-windows.html
|
||||
storage-listings.html
|
||||
|
@ -138,8 +136,6 @@ skip-if =
|
|||
[browser_markers-styles.js]
|
||||
[browser_markers-timestamp.js]
|
||||
[browser_memory_allocations_01.js]
|
||||
[browser_navigateEvents.js]
|
||||
https_first_disabled = true
|
||||
[browser_perf-01.js]
|
||||
[browser_perf-02.js]
|
||||
[browser_perf-04.js]
|
||||
|
|
|
@ -1,189 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const URL1 = MAIN_DOMAIN + "navigate-first.html";
|
||||
const URL2 = MAIN_DOMAIN + "navigate-second.html";
|
||||
|
||||
const { PromptTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/PromptTestUtils.jsm"
|
||||
);
|
||||
|
||||
var isE10s = Services.appinfo.browserTabsRemoteAutostart;
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.require_user_interaction_for_beforeunload", false]],
|
||||
});
|
||||
|
||||
var signalAllEventsReceived;
|
||||
var onAllEventsReceived = new Promise(resolve => {
|
||||
signalAllEventsReceived = resolve;
|
||||
});
|
||||
|
||||
// State machine to check events order
|
||||
var i = 0;
|
||||
function assertEvent(event, data) {
|
||||
switch (i++) {
|
||||
case 0:
|
||||
is(event, "request", "Get first page load");
|
||||
is(data, URL1);
|
||||
break;
|
||||
case 1:
|
||||
is(event, "load-new-document", "Ask to load the second page");
|
||||
break;
|
||||
case 2:
|
||||
is(event, "unload-dialog", "We get the dialog on first page unload");
|
||||
break;
|
||||
case 3:
|
||||
is(
|
||||
event,
|
||||
"will-navigate",
|
||||
"The very first event is will-navigate on server side"
|
||||
);
|
||||
is(data.newURI, URL2, "newURI property is correct");
|
||||
break;
|
||||
case isE10s ? 4 : 5: // When e10s is disabled tabNavigated/request order is swapped
|
||||
is(
|
||||
event,
|
||||
"tabNavigated",
|
||||
"After the request, the client receive tabNavigated"
|
||||
);
|
||||
is(data.state, "start", "state is start");
|
||||
is(data.url, URL2, "url property is correct");
|
||||
break;
|
||||
case isE10s ? 5 : 4:
|
||||
is(
|
||||
event,
|
||||
"request",
|
||||
"RDP is async with messageManager, the request happens after will-navigate"
|
||||
);
|
||||
is(data, URL2);
|
||||
break;
|
||||
case 6:
|
||||
is(event, "DOMContentLoaded");
|
||||
is(data.readyState, "interactive");
|
||||
break;
|
||||
case 7:
|
||||
is(event, "load");
|
||||
is(data.readyState, "complete");
|
||||
break;
|
||||
case 8:
|
||||
is(
|
||||
event,
|
||||
"navigate",
|
||||
"Then once the second doc is loaded, we get the navigate event"
|
||||
);
|
||||
break;
|
||||
case 9:
|
||||
is(event, "tabNavigated", "Finally, the receive the client event");
|
||||
is(data.state, "stop", "state is stop");
|
||||
is(data.url, URL2, "url property is correct");
|
||||
|
||||
signalAllEventsReceived();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var httpObserver = function(subject, topic, state) {
|
||||
const channel = subject.QueryInterface(Ci.nsIHttpChannel);
|
||||
const url = channel.URI.spec;
|
||||
// Only listen for our document request, as many other requests can happen
|
||||
if (url == URL1 || url == URL2) {
|
||||
assertEvent("request", url);
|
||||
}
|
||||
};
|
||||
Services.obs.addObserver(httpObserver, "http-on-modify-request");
|
||||
registerCleanupFunction(() => {
|
||||
Services.obs.removeObserver(httpObserver, "http-on-modify-request");
|
||||
});
|
||||
|
||||
function onMessage({ data }) {
|
||||
assertEvent(data.event, data.data);
|
||||
}
|
||||
|
||||
async function connectAndAttachTab(tab) {
|
||||
const target = await createAndAttachTargetForTab(tab);
|
||||
const actorID = target.actorID;
|
||||
target.on("tabNavigated", function(packet) {
|
||||
assertEvent("tabNavigated", packet);
|
||||
});
|
||||
// In order to listen to internal will-navigate/navigate events
|
||||
target.on("will-navigate", function(data) {
|
||||
assertEvent("will-navigate", {
|
||||
newURI: data.url,
|
||||
});
|
||||
});
|
||||
target.on("navigate", () => assertEvent("navigate"));
|
||||
return { target, actorID };
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
// Navigation events (navigate/will-navigate) on the target no longer fire with server targets.
|
||||
// We should probably drop this test once we stop supporting client side targets (bug 1721852).
|
||||
await pushPref("devtools.target-switching.server.enabled", false);
|
||||
|
||||
// Open a test tab
|
||||
const browser = await addTab(URL1);
|
||||
|
||||
// Listen for alert() call being made in navigate-first during unload
|
||||
const beforeUnloadPromise = PromptTestUtils.handleNextPrompt(
|
||||
browser,
|
||||
{ modalType: Services.prompt.MODAL_TYPE_CONTENT, promptType: "confirmEx" },
|
||||
{ buttonNumClick: 0 }
|
||||
).then(() => {
|
||||
assertEvent("unload-dialog");
|
||||
});
|
||||
|
||||
// Listen for messages sent by the content task
|
||||
browser.messageManager.addMessageListener("devtools-test:event", onMessage);
|
||||
|
||||
const tab = gBrowser.getTabForBrowser(browser);
|
||||
const { target, actorID } = await connectAndAttachTab(tab);
|
||||
await ContentTask.spawn(browser, [actorID], async function(actorId) {
|
||||
// Forward DOMContentLoaded and load events
|
||||
addEventListener(
|
||||
"DOMContentLoaded",
|
||||
function() {
|
||||
sendSyncMessage("devtools-test:event", {
|
||||
event: "DOMContentLoaded",
|
||||
data: { readyState: content.document.readyState },
|
||||
});
|
||||
},
|
||||
{ capture: true }
|
||||
);
|
||||
addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
sendSyncMessage("devtools-test:event", {
|
||||
event: "load",
|
||||
data: { readyState: content.document.readyState },
|
||||
});
|
||||
},
|
||||
{ capture: true }
|
||||
);
|
||||
});
|
||||
|
||||
// Load another document in this doc to dispatch these events
|
||||
assertEvent("load-new-document");
|
||||
|
||||
// Use BrowserTestUtils instead of navigateTo as there is no toolbox opened
|
||||
const onBrowserLoaded = BrowserTestUtils.browserLoaded(
|
||||
gBrowser.selectedBrowser
|
||||
);
|
||||
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, URL2);
|
||||
await beforeUnloadPromise;
|
||||
await onBrowserLoaded;
|
||||
|
||||
// Wait for all events to be received
|
||||
await onAllEventsReceived;
|
||||
|
||||
// Cleanup
|
||||
browser.messageManager.removeMessageListener(
|
||||
"devtools-test:event",
|
||||
onMessage
|
||||
);
|
||||
await target.destroy();
|
||||
Services.obs.addObserver(httpObserver, "http-on-modify-request");
|
||||
DevToolsServer.destroy();
|
||||
});
|
|
@ -1,15 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
First
|
||||
<script>
|
||||
"use strict";
|
||||
window.onbeforeunload = function(e) {
|
||||
e.returnValue = "?";
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,9 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
Second
|
||||
</body>
|
||||
</html>
|
|
@ -1324,37 +1324,34 @@ void nsSHistory::LoadURIOrBFCache(LoadEntryResult& aLoadEntry) {
|
|||
"saving presentation=%i",
|
||||
canSave));
|
||||
|
||||
if (!canSave) {
|
||||
nsCOMPtr<nsFrameLoaderOwner> frameLoaderOwner =
|
||||
do_QueryInterface(canonicalBC->GetEmbedderElement());
|
||||
if (frameLoaderOwner) {
|
||||
RefPtr<nsFrameLoader> currentFrameLoader =
|
||||
frameLoaderOwner->GetFrameLoader();
|
||||
if (currentFrameLoader &&
|
||||
currentFrameLoader->GetMaybePendingBrowsingContext()) {
|
||||
WindowGlobalParent* wgp =
|
||||
currentFrameLoader->GetMaybePendingBrowsingContext()
|
||||
->Canonical()
|
||||
->GetCurrentWindowGlobal();
|
||||
if (wgp) {
|
||||
wgp->PermitUnload([canonicalBC, loadState, she, frameLoader,
|
||||
currentFrameLoader](bool aAllow) {
|
||||
if (aAllow) {
|
||||
FinishRestore(canonicalBC, loadState, she, frameLoader,
|
||||
false);
|
||||
} else if (currentFrameLoader
|
||||
->GetMaybePendingBrowsingContext()) {
|
||||
nsISHistory* shistory =
|
||||
currentFrameLoader->GetMaybePendingBrowsingContext()
|
||||
->Canonical()
|
||||
->GetSessionHistory();
|
||||
if (shistory) {
|
||||
shistory->InternalSetRequestedIndex(-1);
|
||||
}
|
||||
nsCOMPtr<nsFrameLoaderOwner> frameLoaderOwner =
|
||||
do_QueryInterface(canonicalBC->GetEmbedderElement());
|
||||
if (frameLoaderOwner) {
|
||||
RefPtr<nsFrameLoader> currentFrameLoader =
|
||||
frameLoaderOwner->GetFrameLoader();
|
||||
if (currentFrameLoader &&
|
||||
currentFrameLoader->GetMaybePendingBrowsingContext()) {
|
||||
if (WindowGlobalParent* wgp =
|
||||
currentFrameLoader->GetMaybePendingBrowsingContext()
|
||||
->Canonical()
|
||||
->GetCurrentWindowGlobal()) {
|
||||
wgp->PermitUnload([canonicalBC, loadState, she, frameLoader,
|
||||
currentFrameLoader, canSave](bool aAllow) {
|
||||
if (aAllow) {
|
||||
FinishRestore(canonicalBC, loadState, she, frameLoader,
|
||||
canSave && canonicalBC->AllowedInBFCache(
|
||||
Nothing(), nullptr));
|
||||
} else if (currentFrameLoader->GetMaybePendingBrowsingContext()) {
|
||||
nsISHistory* shistory =
|
||||
currentFrameLoader->GetMaybePendingBrowsingContext()
|
||||
->Canonical()
|
||||
->GetSessionHistory();
|
||||
if (shistory) {
|
||||
shistory->InternalSetRequestedIndex(-1);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<html>
|
||||
<script>
|
||||
onpageshow = function(pageShowEvent) {
|
||||
var bc = new BroadcastChannel("ship_beforeunload");
|
||||
bc.onmessage = function(event) {
|
||||
if (event.data.action == "register_beforeunload") {
|
||||
onbeforeunload = function() {
|
||||
bc.postMessage("beforeunload_fired");
|
||||
bc.close();
|
||||
}
|
||||
if (event.data.loadNextPageFromSessionHistory) {
|
||||
history.back();
|
||||
} else {
|
||||
location.href += "?differentpage";
|
||||
}
|
||||
} else if (event.data.action == "navigate_to_page_b") {
|
||||
bc.close();
|
||||
if (event.data.blockBFCache) {
|
||||
window.blockBFCache = new RTCPeerConnection();
|
||||
}
|
||||
location.href += "?pageb";
|
||||
} else if (event.data.action == "back_to_page_b") {
|
||||
if (event.data.forwardNavigateToPageB) {
|
||||
history.forward();
|
||||
} else {
|
||||
history.back();
|
||||
}
|
||||
bc.close();
|
||||
} else if (event.data.action == "close") {
|
||||
bc.close();
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
bc.postMessage({type: pageShowEvent.type, persisted: pageShowEvent.persisted});
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -200,3 +200,15 @@ support-files =
|
|||
[test_recursive_frames.html]
|
||||
[test_bug1699721.html]
|
||||
skip-if = !fission # tests fission-only process switching behaviour
|
||||
[test_ship_beforeunload_fired.html]
|
||||
support-files =
|
||||
file_ship_beforeunload_fired.html
|
||||
skip-if = !sessionHistoryInParent
|
||||
[test_ship_beforeunload_fired_2.html]
|
||||
support-files =
|
||||
file_ship_beforeunload_fired.html
|
||||
skip-if = !sessionHistoryInParent
|
||||
[test_ship_beforeunload_fired_3.html]
|
||||
support-files =
|
||||
file_ship_beforeunload_fired.html
|
||||
skip-if = !sessionHistoryInParent
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test that ensures beforeunload is fired when session-history-in-parent is enabled
|
||||
</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/*
|
||||
* This test ensures beforeunload is fired on the current page
|
||||
* when it is entering BFCache and the next page is coming out
|
||||
* from BFCache
|
||||
*
|
||||
* (1) The controller page opens a new window, and page A is loaded there.
|
||||
* (2) Page A then navigates to page B, and a beforeunload event
|
||||
* listener is registered on page B.
|
||||
* (3) Page B then navigates back to page A, and the beforeunload handler
|
||||
* should send a message to the controller page.
|
||||
* (4) Page A then navigates back to page B to check if page B has
|
||||
* been successfully added to BFCache.
|
||||
*/
|
||||
|
||||
var bc = new BroadcastChannel("ship_beforeunload");
|
||||
var pageshowCount = 0;
|
||||
var beforeUnloadFired = false;
|
||||
bc.onmessage = function(event) {
|
||||
if (event.data.type == "pageshow") {
|
||||
++pageshowCount;
|
||||
if (pageshowCount == 1) {
|
||||
bc.postMessage({action: "navigate_to_page_b"});
|
||||
} else if (pageshowCount == 2) {
|
||||
ok(!event.data.persisted, "?pageb shouldn't in BFCache because it's the first navigation");
|
||||
bc.postMessage({action: "register_beforeunload", loadNextPageFromSessionHistory: true});
|
||||
} else if (pageshowCount == 3) {
|
||||
ok(event.data.persisted, "navigated back to page A that was in BFCacache from page B");
|
||||
ok(beforeUnloadFired, "beforeunload has fired on page B");
|
||||
bc.postMessage({action: "back_to_page_b", forwardNavigateToPageB: true});
|
||||
} else if (pageshowCount == 4) {
|
||||
ok(event.data.persisted, "page B has beforeunload fired and also entered BFCache");
|
||||
bc.postMessage({action: "close"});
|
||||
SimpleTest.finish();
|
||||
}
|
||||
} else if (event.data == "beforeunload_fired") {
|
||||
beforeUnloadFired = true;
|
||||
}
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["fission.bfcacheInParent", true],
|
||||
["docshell.shistory.bfcache.ship_allow_beforeunload_listeners", true]
|
||||
]},
|
||||
function() {
|
||||
window.open("file_ship_beforeunload_fired.html", "", "noopener");
|
||||
}
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<body onload="runTest()"></body>
|
||||
</html>
|
|
@ -0,0 +1,65 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test that ensures beforeunload is fired when session-history-in-parent is enabled
|
||||
</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/*
|
||||
* This test ensures beforeunload is fired on the current page
|
||||
* when it is entering BFCache, and the next page is not coming from
|
||||
* session history and also not coming out from BFCache.
|
||||
*
|
||||
* (1) The controller page opens a new window, and page A is loaded there.
|
||||
* (2) Page A then navigates to page B, and a beforeunload event
|
||||
* listener is registered on page B.
|
||||
* (3) Page B then navigates to page C, and the beforeunload handler
|
||||
* should send a message to the controller page.
|
||||
* (4) Page C then navigates back to page B to check if page B has
|
||||
* been successfully added to BFCache.
|
||||
*/
|
||||
|
||||
var bc = new BroadcastChannel("ship_beforeunload");
|
||||
var pageshowCount = 0;
|
||||
|
||||
var beforeUnloadFired = false;
|
||||
bc.onmessage = function(event) {
|
||||
if (event.data.type == "pageshow") {
|
||||
++pageshowCount;
|
||||
if (pageshowCount == 1) {
|
||||
bc.postMessage({action: "navigate_to_page_b"});
|
||||
} else if (pageshowCount == 2) {
|
||||
ok(!event.data.persisted, "?page B shouldn't in BFCache because it's the first navigation");
|
||||
bc.postMessage({action: "register_beforeunload",
|
||||
loadNextPageFromSessionHistory: false});
|
||||
} else if (pageshowCount == 3) {
|
||||
ok(!event.data.persisted, "navigated to page C that was a new page");
|
||||
ok(beforeUnloadFired, "beforeUnload should be fired on page B");
|
||||
bc.postMessage({action: "back_to_page_b", forwardNavigateToPageB: false});
|
||||
} else if (pageshowCount == 4) {
|
||||
ok(event.data.persisted, "page B has been successfully added to BFCache");
|
||||
bc.postMessage({action: "close"});
|
||||
SimpleTest.finish();
|
||||
}
|
||||
} else if (event.data == "beforeunload_fired") {
|
||||
beforeUnloadFired = true;
|
||||
}
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["fission.bfcacheInParent", true],
|
||||
["docshell.shistory.bfcache.ship_allow_beforeunload_listeners", true]
|
||||
]},
|
||||
function() {
|
||||
window.open("file_ship_beforeunload_fired.html", "", "noopener");
|
||||
}
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<body onload="runTest()"></body>
|
||||
</html>
|
|
@ -0,0 +1,65 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test that ensures beforeunload is fired when session-history-in-parent is enabled
|
||||
</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/*
|
||||
* This test ensures beforeunload is fired on the current page
|
||||
* when it is entering BFCache, and the next page is not coming out
|
||||
* from BFCache, but coming from session history.
|
||||
*
|
||||
* (1) The controller page opens a new window, and page A is loaded there.
|
||||
* (2) Page A then navigates to page B, and a beforeunload event
|
||||
* listener is registered on page B.
|
||||
* (3) Page B then navigates back to page A, and the beforeunload handler
|
||||
* should send a message to the controller page.
|
||||
* (4) Page A then navigates back to page B to check if page B has
|
||||
* been successfully added to BFCache.
|
||||
*/
|
||||
|
||||
var bc = new BroadcastChannel("ship_beforeunload");
|
||||
var pageshowCount = 0;
|
||||
|
||||
var beforeUnloadFired = false;
|
||||
bc.onmessage = function(event) {
|
||||
if (event.data.type == "pageshow") {
|
||||
++pageshowCount;
|
||||
if (pageshowCount == 1) {
|
||||
bc.postMessage({action: "navigate_to_page_b", blockBFCache: true});
|
||||
} else if (pageshowCount == 2) {
|
||||
ok(!event.data.persisted, "?page B shouldn't in BFCache because it's the first navigation");
|
||||
bc.postMessage({action: "register_beforeunload",
|
||||
loadNextPageFromSessionHistory: true});
|
||||
} else if (pageshowCount == 3) {
|
||||
ok(!event.data.persisted, "navigated back to page A that was session history but not in BFCache");
|
||||
ok(beforeUnloadFired, "beforeUnload should be fired on page B");
|
||||
bc.postMessage({action: "back_to_page_b", forwardNavigateToPageB: true});
|
||||
} else if (pageshowCount == 4) {
|
||||
ok(event.data.persisted, "page B has been successfully added to BFCache");
|
||||
bc.postMessage({action: "close"});
|
||||
SimpleTest.finish();
|
||||
}
|
||||
} else if (event.data == "beforeunload_fired") {
|
||||
beforeUnloadFired = true;
|
||||
}
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["fission.bfcacheInParent", true],
|
||||
["docshell.shistory.bfcache.ship_allow_beforeunload_listeners", true]
|
||||
]},
|
||||
function() {
|
||||
window.open("file_ship_beforeunload_fired.html", "", "noopener");
|
||||
}
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<body onload="runTest()"></body>
|
||||
</html>
|
|
@ -11173,10 +11173,15 @@ bool Document::CanSavePresentation(nsIRequest* aNewRequest,
|
|||
ret = false;
|
||||
}
|
||||
if (manager->HasBeforeUnloadListeners()) {
|
||||
MOZ_LOG(gPageCacheLog, mozilla::LogLevel::Verbose,
|
||||
("Save of %s blocked due to beforeUnload handlers", uri.get()));
|
||||
aBFCacheCombo |= BFCacheStatus::BEFOREUNLOAD_LISTENER;
|
||||
ret = false;
|
||||
if (!mozilla::SessionHistoryInParent() ||
|
||||
!StaticPrefs::
|
||||
docshell_shistory_bfcache_ship_allow_beforeunload_listeners()) {
|
||||
MOZ_LOG(
|
||||
gPageCacheLog, mozilla::LogLevel::Verbose,
|
||||
("Save of %s blocked due to beforeUnload handlers", uri.get()));
|
||||
aBFCacheCombo |= BFCacheStatus::BEFOREUNLOAD_LISTENER;
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2120,9 +2120,7 @@ already_AddRefed<Promise> Navigator::RequestMediaKeySystemAccess(
|
|||
}
|
||||
|
||||
RefPtr<DetailedPromise> promise = DetailedPromise::Create(
|
||||
mWindow->AsGlobal(), aRv, "navigator.requestMediaKeySystemAccess"_ns,
|
||||
Telemetry::VIDEO_EME_REQUEST_SUCCESS_LATENCY_MS,
|
||||
Telemetry::VIDEO_EME_REQUEST_FAILURE_LATENCY_MS);
|
||||
mWindow->AsGlobal(), aRv, "navigator.requestMediaKeySystemAccess"_ns);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
#include "mozilla/SpinEventLoopUntil.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/StaticPrefs_browser.h"
|
||||
#include "mozilla/StaticPrefs_docshell.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include "mozilla/StaticPrefs_privacy.h"
|
||||
#include "mozilla/StorageAccess.h"
|
||||
|
@ -6590,13 +6591,22 @@ void nsGlobalWindowInner::EventListenerAdded(nsAtom* aType) {
|
|||
mHasVRDisplayActivateEvents = true;
|
||||
}
|
||||
|
||||
if ((aType == nsGkAtoms::onunload || aType == nsGkAtoms::onbeforeunload) &&
|
||||
mWindowGlobalChild) {
|
||||
if (aType == nsGkAtoms::onunload && mWindowGlobalChild) {
|
||||
if (++mUnloadOrBeforeUnloadListenerCount == 1) {
|
||||
mWindowGlobalChild->BlockBFCacheFor(BFCacheStatus::UNLOAD_LISTENER);
|
||||
}
|
||||
if (aType == nsGkAtoms::onbeforeunload &&
|
||||
(!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS))) {
|
||||
}
|
||||
|
||||
if (aType == nsGkAtoms::onbeforeunload && mWindowGlobalChild) {
|
||||
if (!mozilla::SessionHistoryInParent() ||
|
||||
!StaticPrefs::
|
||||
docshell_shistory_bfcache_ship_allow_beforeunload_listeners()) {
|
||||
if (++mUnloadOrBeforeUnloadListenerCount == 1) {
|
||||
mWindowGlobalChild->BlockBFCacheFor(
|
||||
BFCacheStatus::BEFOREUNLOAD_LISTENER);
|
||||
}
|
||||
}
|
||||
if (!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS)) {
|
||||
mWindowGlobalChild->BeforeUnloadAdded();
|
||||
MOZ_ASSERT(mWindowGlobalChild->BeforeUnloadListeners() > 0);
|
||||
}
|
||||
|
@ -6618,14 +6628,23 @@ void nsGlobalWindowInner::EventListenerAdded(nsAtom* aType) {
|
|||
}
|
||||
|
||||
void nsGlobalWindowInner::EventListenerRemoved(nsAtom* aType) {
|
||||
if ((aType == nsGkAtoms::onunload || aType == nsGkAtoms::onbeforeunload) &&
|
||||
mWindowGlobalChild) {
|
||||
if (aType == nsGkAtoms::onunload && mWindowGlobalChild) {
|
||||
MOZ_ASSERT(mUnloadOrBeforeUnloadListenerCount > 0);
|
||||
if (--mUnloadOrBeforeUnloadListenerCount == 0) {
|
||||
mWindowGlobalChild->UnblockBFCacheFor(BFCacheStatus::UNLOAD_LISTENER);
|
||||
}
|
||||
if (aType == nsGkAtoms::onbeforeunload &&
|
||||
(!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS))) {
|
||||
}
|
||||
|
||||
if (aType == nsGkAtoms::onbeforeunload && mWindowGlobalChild) {
|
||||
if (!mozilla::SessionHistoryInParent() ||
|
||||
!StaticPrefs::
|
||||
docshell_shistory_bfcache_ship_allow_beforeunload_listeners()) {
|
||||
if (--mUnloadOrBeforeUnloadListenerCount == 0) {
|
||||
mWindowGlobalChild->UnblockBFCacheFor(
|
||||
BFCacheStatus::BEFOREUNLOAD_LISTENER);
|
||||
}
|
||||
}
|
||||
if (!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS)) {
|
||||
mWindowGlobalChild->BeforeUnloadRemoved();
|
||||
MOZ_ASSERT(mWindowGlobalChild->BeforeUnloadListeners() >= 0);
|
||||
}
|
||||
|
|
|
@ -1520,7 +1520,7 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
|
|||
|
||||
RefPtr<mozilla::dom::VREventObserver> mVREventObserver;
|
||||
|
||||
// The number of unload and beforeunload even listeners registered on this
|
||||
// The number of unload and beforeunload event listeners registered on this
|
||||
// window.
|
||||
uint64_t mUnloadOrBeforeUnloadListenerCount = 0;
|
||||
|
||||
|
|
|
@ -4766,10 +4766,9 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
|
|||
|
||||
AdjustedTarget tempTarget(this, bounds.IsEmpty() ? nullptr : &bounds);
|
||||
if (!tempTarget) {
|
||||
gfxDevCrash(LogReason::InvalidDrawTarget)
|
||||
<< "Invalid adjusted target in Canvas2D "
|
||||
<< gfx::hexa((DrawTarget*)mTarget) << ", " << NeedToDrawShadow()
|
||||
<< NeedToApplyFilter();
|
||||
gfxWarning() << "Invalid adjusted target in Canvas2D "
|
||||
<< gfx::hexa((DrawTarget*)mTarget) << ", "
|
||||
<< NeedToDrawShadow() << NeedToApplyFilter();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -5452,7 +5452,10 @@ uint32_t ClientWebGLContext::GetPrincipalHashValue() const {
|
|||
return mCanvasElement->NodePrincipal()->GetHashValue();
|
||||
}
|
||||
if (mOffscreenCanvas) {
|
||||
return mOffscreenCanvas->GetOwnerGlobal()->GetPrincipalHashValue();
|
||||
nsIGlobalObject* global = mOffscreenCanvas->GetOwnerGlobal();
|
||||
if (global) {
|
||||
return global->GetPrincipalHashValue();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -163,7 +163,6 @@ already_AddRefed<TextTrack> TextTrackManager::AddTextTrack(
|
|||
NS_ConvertUTF16toUTF8(aLabel).get(),
|
||||
NS_ConvertUTF16toUTF8(aLanguage).get());
|
||||
AddCues(track);
|
||||
ReportTelemetryForTrack(track);
|
||||
|
||||
if (aTextTrackSource == TextTrackSource::Track) {
|
||||
RefPtr<nsIRunnable> task = NewRunnableMethod(
|
||||
|
@ -182,7 +181,6 @@ void TextTrackManager::AddTextTrack(TextTrack* aTextTrack) {
|
|||
WEBVTT_LOG("AddTextTrack TextTrack %p", aTextTrack);
|
||||
mTextTracks->AddTextTrack(aTextTrack, CompareTextTracks(mMediaElement));
|
||||
AddCues(aTextTrack);
|
||||
ReportTelemetryForTrack(aTextTrack);
|
||||
|
||||
if (aTextTrack->GetTextTrackSource() == TextTrackSource::Track) {
|
||||
RefPtr<nsIRunnable> task = NewRunnableMethod(
|
||||
|
@ -848,15 +846,6 @@ void TextTrackManager::NotifyReset() {
|
|||
UpdateCueDisplay();
|
||||
}
|
||||
|
||||
void TextTrackManager::ReportTelemetryForTrack(TextTrack* aTextTrack) const {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aTextTrack);
|
||||
MOZ_ASSERT(mTextTracks->Length() > 0);
|
||||
|
||||
TextTrackKind kind = aTextTrack->Kind();
|
||||
Telemetry::Accumulate(Telemetry::WEBVTT_TRACK_KINDS, uint32_t(kind));
|
||||
}
|
||||
|
||||
bool TextTrackManager::IsLoaded() {
|
||||
return mTextTracks ? mTextTracks->AreTextTracksLoaded() : true;
|
||||
}
|
||||
|
|
|
@ -149,8 +149,6 @@ class TextTrackManager final : public nsIDOMEventListener {
|
|||
nsTArray<TextTrack*>& aTextTracks);
|
||||
bool TrackIsDefault(TextTrack* aTextTrack);
|
||||
|
||||
void ReportTelemetryForTrack(TextTrack* aTextTrack) const;
|
||||
|
||||
bool IsShutdown() const;
|
||||
|
||||
// This function will check media element's show poster flag to decide whether
|
||||
|
|
|
@ -1388,6 +1388,7 @@ nsCString BFCacheStatusToString(uint32_t aFlags) {
|
|||
ADD_BFCACHESTATUS_TO_STRING(HAS_USED_VR);
|
||||
ADD_BFCACHESTATUS_TO_STRING(CONTAINS_REMOTE_SUBFRAMES);
|
||||
ADD_BFCACHESTATUS_TO_STRING(NOT_ONLY_TOPLEVEL_IN_BCG);
|
||||
ADD_BFCACHESTATUS_TO_STRING(BEFOREUNLOAD_LISTENER);
|
||||
ADD_BFCACHESTATUS_TO_STRING(ACTIVE_LOCK);
|
||||
|
||||
#undef ADD_BFCACHESTATUS_TO_STRING
|
||||
|
|
|
@ -113,8 +113,6 @@ bool VP9Benchmark::IsVP9DecodeFast(bool aDefault) {
|
|||
Preferences::SetUint(sBenchmarkFpsVersionCheck,
|
||||
sBenchmarkVersionID);
|
||||
}
|
||||
Telemetry::Accumulate(Telemetry::HistogramID::VIDEO_VP9_BENCHMARK_FPS,
|
||||
aDecodeFps);
|
||||
},
|
||||
[]() {});
|
||||
}
|
||||
|
|
|
@ -67,17 +67,6 @@ already_AddRefed<DetailedPromise> DetailedPromise::Create(
|
|||
return aRv.Failed() ? nullptr : promise.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<DetailedPromise> DetailedPromise::Create(
|
||||
nsIGlobalObject* aGlobal, ErrorResult& aRv, const nsACString& aName,
|
||||
Telemetry::HistogramID aSuccessLatencyProbe,
|
||||
Telemetry::HistogramID aFailureLatencyProbe) {
|
||||
RefPtr<DetailedPromise> promise = new DetailedPromise(
|
||||
aGlobal, aName, aSuccessLatencyProbe, aFailureLatencyProbe);
|
||||
promise->CreateWrapper(aRv);
|
||||
return aRv.Failed() ? nullptr : promise.forget();
|
||||
}
|
||||
|
||||
void DetailedPromise::MaybeReportTelemetry(eStatus aStatus) {
|
||||
if (mResponded) {
|
||||
return;
|
||||
|
|
|
@ -25,11 +25,6 @@ class DetailedPromise : public Promise {
|
|||
ErrorResult& aRv,
|
||||
const nsACString& aName);
|
||||
|
||||
static already_AddRefed<DetailedPromise> Create(
|
||||
nsIGlobalObject* aGlobal, ErrorResult& aRv, const nsACString& aName,
|
||||
Telemetry::HistogramID aSuccessLatencyProbe,
|
||||
Telemetry::HistogramID aFailureLatencyProbe);
|
||||
|
||||
template <typename T>
|
||||
void MaybeResolve(T&& aArg) {
|
||||
EME_LOG("%s promise resolved", mName.get());
|
||||
|
|
|
@ -408,6 +408,12 @@ function assertHasBeforeUnload(browser, expected) {
|
|||
* inner window is removed from the DOM.
|
||||
*/
|
||||
add_task(async function test_inner_window_scenarios() {
|
||||
// Turn this off because the test expects the page to be not bfcached.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["docshell.shistory.bfcache.ship_allow_beforeunload_listeners", false],
|
||||
],
|
||||
});
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
|
@ -592,6 +598,12 @@ add_task(async function test_inner_window_scenarios() {
|
|||
* to the iframe DOM nodes instead of the inner windows.
|
||||
*/
|
||||
add_task(async function test_outer_window_scenarios() {
|
||||
// Turn this off because the test expects the page to be not bfcached.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["docshell.shistory.bfcache.ship_allow_beforeunload_listeners", false],
|
||||
],
|
||||
});
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
|
@ -787,6 +799,12 @@ add_task(async function test_outer_window_scenarios() {
|
|||
* are added on both inner and outer windows.
|
||||
*/
|
||||
add_task(async function test_mixed_inner_and_outer_window_scenarios() {
|
||||
// Turn this off because the test expects the page to be not bfcached.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["docshell.shistory.bfcache.ship_allow_beforeunload_listeners", false],
|
||||
],
|
||||
});
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
|
|
|
@ -40,7 +40,8 @@ uint32_t gfxFT2LockedFace::GetGlyph(uint32_t aCharCode) {
|
|||
#else
|
||||
uint32_t gid = FT_Get_Char_Index(mFace, aCharCode);
|
||||
#endif
|
||||
if (!gid && mFace->charmap->encoding == FT_ENCODING_MS_SYMBOL) {
|
||||
if (!gid && mFace->charmap &&
|
||||
mFace->charmap->encoding == FT_ENCODING_MS_SYMBOL) {
|
||||
if (auto pua = gfxFontUtils::MapLegacySymbolFontCharToPUA(aCharCode)) {
|
||||
gid = FT_Get_Char_Index(mFace, pua);
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ use crate::api::{BlobImageKey, ImageDescriptor, DirtyRect, TileSize};
|
|||
use crate::api::{BlobImageHandler, AsyncBlobImageRasterizer, BlobImageData, BlobImageParams};
|
||||
use crate::api::{BlobImageRequest, BlobImageDescriptor, BlobImageResources};
|
||||
use crate::api::{FontKey, FontTemplate, FontInstanceData, FontInstanceKey};
|
||||
use crate::api::SharedFontInstanceMap;
|
||||
use crate::api::units::*;
|
||||
use crate::glyph_rasterizer::SharedFontInstanceMap;
|
||||
use crate::render_api::{ResourceUpdate, TransactionMsg, AddFont};
|
||||
use crate::image_tiling::*;
|
||||
use crate::profiler;
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use api::{FontInstanceFlags, FontSize, BaseFontInstance};
|
||||
use api::{FontKey, FontRenderMode, FontTemplate};
|
||||
use api::{ColorU, GlyphIndex, GlyphDimensions, SyntheticItalics};
|
||||
use api::{FontInstanceData, FontInstanceFlags, FontInstanceKey};
|
||||
use api::{FontInstanceOptions, FontInstancePlatformOptions};
|
||||
use api::{FontKey, FontRenderMode, FontSize, FontTemplate, FontVariation};
|
||||
use api::{ColorU, GlyphIndex, GlyphDimensions, SyntheticItalics, IdNamespace};
|
||||
use api::channel::crossbeam::{unbounded, Receiver, Sender};
|
||||
use api::units::*;
|
||||
use api::{ImageDescriptor, ImageDescriptorFlags, ImageFormat, DirtyRect};
|
||||
|
@ -29,7 +30,7 @@ use std::cell::Cell;
|
|||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Condvar, Mutex, MutexGuard};
|
||||
use std::sync::{Arc, Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
pub static GLYPH_FLASHING: AtomicBool = AtomicBool::new(false);
|
||||
|
@ -472,6 +473,141 @@ impl<'a> From<&'a LayoutToWorldTransform> for FontTransform {
|
|||
// Ensure glyph sizes are reasonably limited to avoid that scenario.
|
||||
pub const FONT_SIZE_LIMIT: f32 = 320.0;
|
||||
|
||||
/// Immutable description of a font instance's shared state.
|
||||
///
|
||||
/// `BaseFontInstance` can be identified by a `FontInstanceKey` to avoid hashing it.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Ord, PartialOrd, MallocSizeOf)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct BaseFontInstance {
|
||||
///
|
||||
pub instance_key: FontInstanceKey,
|
||||
///
|
||||
pub font_key: FontKey,
|
||||
///
|
||||
pub size: FontSize,
|
||||
///
|
||||
pub bg_color: ColorU,
|
||||
///
|
||||
pub render_mode: FontRenderMode,
|
||||
///
|
||||
pub flags: FontInstanceFlags,
|
||||
///
|
||||
pub synthetic_italics: SyntheticItalics,
|
||||
///
|
||||
#[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
|
||||
pub platform_options: Option<FontInstancePlatformOptions>,
|
||||
///
|
||||
pub variations: Vec<FontVariation>,
|
||||
}
|
||||
|
||||
pub type FontInstanceMap = FastHashMap<FontInstanceKey, Arc<BaseFontInstance>>;
|
||||
/// A map of font instance data accessed concurrently from multiple threads.
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
|
||||
pub struct SharedFontInstanceMap {
|
||||
map: Arc<RwLock<FontInstanceMap>>,
|
||||
}
|
||||
|
||||
impl SharedFontInstanceMap {
|
||||
/// Creates an empty shared map.
|
||||
pub fn new() -> Self {
|
||||
SharedFontInstanceMap {
|
||||
map: Arc::new(RwLock::new(FastHashMap::default()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Acquires a write lock on the shared map.
|
||||
pub fn lock(&mut self) -> Option<RwLockReadGuard<FontInstanceMap>> {
|
||||
self.map.read().ok()
|
||||
}
|
||||
|
||||
///
|
||||
pub fn get_font_instance_data(&self, key: FontInstanceKey) -> Option<FontInstanceData> {
|
||||
match self.map.read().unwrap().get(&key) {
|
||||
Some(instance) => Some(FontInstanceData {
|
||||
font_key: instance.font_key,
|
||||
size: instance.size.into(),
|
||||
options: Some(FontInstanceOptions {
|
||||
render_mode: instance.render_mode,
|
||||
flags: instance.flags,
|
||||
bg_color: instance.bg_color,
|
||||
synthetic_italics: instance.synthetic_italics,
|
||||
}),
|
||||
platform_options: instance.platform_options,
|
||||
variations: instance.variations.clone(),
|
||||
}),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace the shared map with the provided map.
|
||||
pub fn set(&mut self, map: FontInstanceMap) {
|
||||
*self.map.write().unwrap() = map;
|
||||
}
|
||||
|
||||
///
|
||||
pub fn get_font_instance(&self, instance_key: FontInstanceKey) -> Option<Arc<BaseFontInstance>> {
|
||||
let instance_map = self.map.read().unwrap();
|
||||
instance_map.get(&instance_key).map(|instance| { Arc::clone(instance) })
|
||||
}
|
||||
|
||||
///
|
||||
pub fn add_font_instance(
|
||||
&mut self,
|
||||
instance_key: FontInstanceKey,
|
||||
font_key: FontKey,
|
||||
size: f32,
|
||||
options: Option<FontInstanceOptions>,
|
||||
platform_options: Option<FontInstancePlatformOptions>,
|
||||
variations: Vec<FontVariation>,
|
||||
) {
|
||||
let FontInstanceOptions {
|
||||
render_mode,
|
||||
flags,
|
||||
bg_color,
|
||||
synthetic_italics,
|
||||
..
|
||||
} = options.unwrap_or_default();
|
||||
|
||||
let instance = Arc::new(BaseFontInstance {
|
||||
instance_key,
|
||||
font_key,
|
||||
size: size.into(),
|
||||
bg_color,
|
||||
render_mode,
|
||||
flags,
|
||||
synthetic_italics,
|
||||
platform_options,
|
||||
variations,
|
||||
});
|
||||
|
||||
self.map
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(instance_key, instance);
|
||||
}
|
||||
|
||||
///
|
||||
pub fn delete_font_instance(&mut self, instance_key: FontInstanceKey) {
|
||||
self.map.write().unwrap().remove(&instance_key);
|
||||
}
|
||||
|
||||
///
|
||||
pub fn clear_namespace(&mut self, namespace: IdNamespace) {
|
||||
self.map
|
||||
.write()
|
||||
.unwrap()
|
||||
.retain(|key, _| key.0 != namespace);
|
||||
}
|
||||
|
||||
///
|
||||
pub fn clone_map(&self) -> FontInstanceMap {
|
||||
self.map.read().unwrap().clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// A mutable font instance description.
|
||||
///
|
||||
/// Performance is sensitive to the size of this structure, so it should only contain
|
||||
|
|
|
@ -14,7 +14,7 @@ use time::precise_time_ns;
|
|||
//use crate::api::peek_poke::PeekPoke;
|
||||
use crate::api::channel::{Sender, single_msg_channel, unbounded_channel};
|
||||
use crate::api::{ColorF, BuiltDisplayList, IdNamespace, ExternalScrollId, Parameter, BoolParameter};
|
||||
use crate::api::{SharedFontInstanceMap, FontKey, FontInstanceKey, NativeFontHandle};
|
||||
use crate::api::{FontKey, FontInstanceKey, NativeFontHandle};
|
||||
use crate::api::{BlobImageData, BlobImageKey, ImageData, ImageDescriptor, ImageKey, Epoch, QualitySettings};
|
||||
use crate::api::{BlobImageParams, BlobImageRequest, BlobImageResult, AsyncBlobImageRasterizer, BlobImageHandler};
|
||||
use crate::api::{DocumentId, PipelineId, PropertyBindingId, PropertyBindingKey, ExternalEvent};
|
||||
|
@ -25,6 +25,7 @@ use crate::api::{FontInstanceOptions, FontInstancePlatformOptions, FontVariation
|
|||
use crate::api::DEFAULT_TILE_SIZE;
|
||||
use crate::api::units::*;
|
||||
use crate::api_resources::ApiResources;
|
||||
use crate::glyph_rasterizer::SharedFontInstanceMap;
|
||||
use crate::scene_builder_thread::{SceneBuilderRequest, SceneBuilderResult};
|
||||
use crate::intern::InterningMemoryReport;
|
||||
use crate::profiler::{self, TransactionProfile};
|
||||
|
|
|
@ -42,7 +42,7 @@ use api::ExternalImageId;
|
|||
use api::{ExternalImageSource, ExternalImageType, FontRenderMode, ImageFormat};
|
||||
use api::{PipelineId, ImageRendering, Checkpoint, NotificationRequest};
|
||||
use api::{VoidPtrToSizeFn, PremultipliedColorF};
|
||||
use api::{RenderNotifier, ImageBufferKind, SharedFontInstanceMap};
|
||||
use api::{RenderNotifier, ImageBufferKind};
|
||||
#[cfg(feature = "replay")]
|
||||
use api::ExternalImage;
|
||||
use api::units::*;
|
||||
|
@ -68,7 +68,7 @@ use crate::device::FBOId;
|
|||
use crate::debug_item::DebugItem;
|
||||
use crate::frame_builder::{Frame, ChasePrimitive, FrameBuilderConfig};
|
||||
use crate::glyph_cache::GlyphCache;
|
||||
use crate::glyph_rasterizer::{GlyphFormat, GlyphRasterizer};
|
||||
use crate::glyph_rasterizer::{GlyphFormat, GlyphRasterizer, SharedFontInstanceMap};
|
||||
use crate::gpu_cache::{GpuCacheUpdate, GpuCacheUpdateList};
|
||||
use crate::gpu_cache::{GpuCacheDebugChunk, GpuCacheDebugCmd};
|
||||
use crate::gpu_types::{PrimitiveInstanceData, ScalingInstance, SvgFilterInstance, CopyInstance};
|
||||
|
|
|
@ -8,7 +8,6 @@ use api::{ExternalImageData, ExternalImageType, ExternalImageId, BlobImageResult
|
|||
use api::{DirtyRect, GlyphDimensions, IdNamespace, DEFAULT_TILE_SIZE};
|
||||
use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering, TileSize};
|
||||
use api::{BlobImageKey, VoidPtrToSizeFn};
|
||||
use api::{SharedFontInstanceMap, BaseFontInstance};
|
||||
use api::units::*;
|
||||
use crate::{render_api::{ClearCache, AddFont, ResourceUpdate, MemoryReport}, util::WeakTable};
|
||||
use crate::image_tiling::{compute_tile_size, compute_tile_range};
|
||||
|
@ -23,6 +22,7 @@ use crate::device::TextureFilter;
|
|||
use crate::glyph_cache::GlyphCache;
|
||||
use crate::glyph_cache::GlyphCacheEntry;
|
||||
use crate::glyph_rasterizer::{GLYPH_FLASHING, FontInstance, GlyphFormat, GlyphKey, GlyphRasterizer};
|
||||
use crate::glyph_rasterizer::{SharedFontInstanceMap, BaseFontInstance};
|
||||
use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
|
||||
use crate::gpu_types::UvRectKind;
|
||||
use crate::internal_types::{
|
||||
|
@ -39,8 +39,6 @@ use smallvec::SmallVec;
|
|||
use std::collections::hash_map::Entry::{self, Occupied, Vacant};
|
||||
use std::collections::hash_map::{Iter, IterMut};
|
||||
use std::collections::VecDeque;
|
||||
#[cfg(any(feature = "capture", feature = "replay"))]
|
||||
use std::collections::HashMap;
|
||||
use std::{cmp, mem};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
@ -1791,7 +1789,7 @@ struct PlainImageTemplate {
|
|||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct PlainResources {
|
||||
font_templates: FastHashMap<FontKey, PlainFontTemplate>,
|
||||
font_instances: HashMap<FontInstanceKey, Arc<BaseFontInstance>>,
|
||||
font_instances: FastHashMap<FontInstanceKey, Arc<BaseFontInstance>>,
|
||||
image_templates: FastHashMap<ImageKey, PlainImageTemplate>,
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
use api::{AsyncBlobImageRasterizer, BlobImageResult, Parameter};
|
||||
use api::{DocumentId, PipelineId, ExternalEvent, BlobImageRequest};
|
||||
use api::{NotificationRequest, Checkpoint, IdNamespace, QualitySettings};
|
||||
use api::{PrimitiveKeyKind, SharedFontInstanceMap};
|
||||
use api::{GlyphDimensionRequest, GlyphIndexRequest};
|
||||
use api::{PrimitiveKeyKind, GlyphDimensionRequest, GlyphIndexRequest};
|
||||
use api::channel::{unbounded_channel, single_msg_channel, Receiver, Sender};
|
||||
use api::units::*;
|
||||
use crate::render_api::{ApiMsg, FrameMsg, SceneMsg, ResourceUpdate, TransactionMsg, MemoryReport};
|
||||
|
@ -16,6 +15,7 @@ use crate::frame_builder::FrameBuilderConfig;
|
|||
use crate::scene_building::SceneBuilder;
|
||||
use crate::clip::{ClipIntern, PolygonIntern};
|
||||
use crate::filterdata::FilterDataIntern;
|
||||
use crate::glyph_rasterizer::SharedFontInstanceMap;
|
||||
use crate::intern::{Internable, Interner, UpdateList};
|
||||
use crate::internal_types::{FastHashMap, FastHashSet};
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter, BuiltDisplayList, PrimitiveFlags};
|
||||
use api::{ClipId, ColorF, CommonItemProperties, ComplexClipRegion, ComponentTransferFuncType, RasterSpace};
|
||||
use api::{DisplayItem, DisplayItemRef, ExtendMode, ExternalScrollId, FilterData, SharedFontInstanceMap};
|
||||
use api::{DisplayItem, DisplayItemRef, ExtendMode, ExternalScrollId, FilterData};
|
||||
use api::{FilterOp, FilterPrimitive, FontInstanceKey, FontSize, GlyphInstance, GlyphOptions, GradientStop};
|
||||
use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, ColorDepth, QualitySettings};
|
||||
use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId, MixBlendMode, StackingContextFlags};
|
||||
|
@ -52,7 +52,7 @@ use crate::clip::{ClipInternData, ClipNodeKind, ClipInstance, SceneClipInstance}
|
|||
use crate::clip::{PolygonDataHandle};
|
||||
use crate::spatial_tree::{SceneSpatialTree, SpatialNodeIndex, get_external_scroll_offset};
|
||||
use crate::frame_builder::{ChasePrimitive, FrameBuilderConfig};
|
||||
use crate::glyph_rasterizer::FontInstance;
|
||||
use crate::glyph_rasterizer::{FontInstance, SharedFontInstanceMap};
|
||||
use crate::hit_test::HitTestingScene;
|
||||
use crate::intern::Interner;
|
||||
use crate::internal_types::{FastHashMap, LayoutPrimitiveInfo, Filter, PlaneSplitter, PlaneSplitterIndex, PipelineInstanceId};
|
||||
|
|
|
@ -7,8 +7,7 @@ use std::cmp::Ordering;
|
|||
use std::hash::{Hash, Hasher};
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, RwLock, RwLockReadGuard};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
// local imports
|
||||
use crate::IdNamespace;
|
||||
use crate::channel::Sender;
|
||||
|
@ -54,142 +53,6 @@ impl FontSize {
|
|||
pub fn to_f64_px(&self) -> f64 { self.0 as f64 }
|
||||
}
|
||||
|
||||
/// Immutable description of a font instance requested by the user of the API.
|
||||
///
|
||||
/// `BaseFontInstance` can be identified by a `FontInstanceKey` so we should
|
||||
/// never need to hash it.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Ord, PartialOrd, MallocSizeOf)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
|
||||
pub struct BaseFontInstance {
|
||||
///
|
||||
pub instance_key: FontInstanceKey,
|
||||
///
|
||||
pub font_key: FontKey,
|
||||
///
|
||||
pub size: FontSize,
|
||||
///
|
||||
pub bg_color: ColorU,
|
||||
///
|
||||
pub render_mode: FontRenderMode,
|
||||
///
|
||||
pub flags: FontInstanceFlags,
|
||||
///
|
||||
pub synthetic_italics: SyntheticItalics,
|
||||
///
|
||||
#[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(skip))]
|
||||
pub platform_options: Option<FontInstancePlatformOptions>,
|
||||
///
|
||||
pub variations: Vec<FontVariation>,
|
||||
}
|
||||
|
||||
pub type FontInstanceMap = HashMap<FontInstanceKey, Arc<BaseFontInstance>>;
|
||||
/// A map of font instance data accessed concurrently from multiple threads.
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
|
||||
pub struct SharedFontInstanceMap {
|
||||
map: Arc<RwLock<FontInstanceMap>>,
|
||||
}
|
||||
|
||||
impl SharedFontInstanceMap {
|
||||
/// Creates an empty shared map.
|
||||
pub fn new() -> Self {
|
||||
SharedFontInstanceMap {
|
||||
map: Arc::new(RwLock::new(HashMap::default()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Acquires a write lock on the shared map.
|
||||
pub fn lock(&mut self) -> Option<RwLockReadGuard<FontInstanceMap>> {
|
||||
self.map.read().ok()
|
||||
}
|
||||
|
||||
///
|
||||
pub fn get_font_instance_data(&self, key: FontInstanceKey) -> Option<FontInstanceData> {
|
||||
match self.map.read().unwrap().get(&key) {
|
||||
Some(instance) => Some(FontInstanceData {
|
||||
font_key: instance.font_key,
|
||||
size: instance.size.into(),
|
||||
options: Some(FontInstanceOptions {
|
||||
render_mode: instance.render_mode,
|
||||
flags: instance.flags,
|
||||
bg_color: instance.bg_color,
|
||||
synthetic_italics: instance.synthetic_italics,
|
||||
}),
|
||||
platform_options: instance.platform_options,
|
||||
variations: instance.variations.clone(),
|
||||
}),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace the shared map with the provided map.
|
||||
pub fn set(&mut self, map: FontInstanceMap) {
|
||||
*self.map.write().unwrap() = map;
|
||||
}
|
||||
|
||||
///
|
||||
pub fn get_font_instance(&self, instance_key: FontInstanceKey) -> Option<Arc<BaseFontInstance>> {
|
||||
let instance_map = self.map.read().unwrap();
|
||||
instance_map.get(&instance_key).map(|instance| { Arc::clone(instance) })
|
||||
}
|
||||
|
||||
///
|
||||
pub fn add_font_instance(
|
||||
&mut self,
|
||||
instance_key: FontInstanceKey,
|
||||
font_key: FontKey,
|
||||
size: f32,
|
||||
options: Option<FontInstanceOptions>,
|
||||
platform_options: Option<FontInstancePlatformOptions>,
|
||||
variations: Vec<FontVariation>,
|
||||
) {
|
||||
let FontInstanceOptions {
|
||||
render_mode,
|
||||
flags,
|
||||
bg_color,
|
||||
synthetic_italics,
|
||||
..
|
||||
} = options.unwrap_or_default();
|
||||
|
||||
let instance = Arc::new(BaseFontInstance {
|
||||
instance_key,
|
||||
font_key,
|
||||
size: size.into(),
|
||||
bg_color,
|
||||
render_mode,
|
||||
flags,
|
||||
synthetic_italics,
|
||||
platform_options,
|
||||
variations,
|
||||
});
|
||||
|
||||
self.map
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(instance_key, instance);
|
||||
}
|
||||
|
||||
///
|
||||
pub fn delete_font_instance(&mut self, instance_key: FontInstanceKey) {
|
||||
self.map.write().unwrap().remove(&instance_key);
|
||||
}
|
||||
|
||||
///
|
||||
pub fn clear_namespace(&mut self, namespace: IdNamespace) {
|
||||
self.map
|
||||
.write()
|
||||
.unwrap()
|
||||
.retain(|key, _| key.0 != namespace);
|
||||
}
|
||||
|
||||
///
|
||||
pub fn clone_map(&self) -> FontInstanceMap {
|
||||
self.map.read().unwrap().clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct NativeFontHandle {
|
||||
|
|
|
@ -3093,8 +3093,8 @@ static bool ShouldPauseMutatorWhileWaiting(const SliceBudget& budget,
|
|||
budgetWasIncreased;
|
||||
}
|
||||
|
||||
void GCRuntime::incrementalSlice(SliceBudget& budget,
|
||||
JS::GCReason reason, bool budgetWasIncreased) {
|
||||
void GCRuntime::incrementalSlice(SliceBudget& budget, JS::GCReason reason,
|
||||
bool budgetWasIncreased) {
|
||||
MOZ_ASSERT_IF(isIncrementalGCInProgress(), isIncremental);
|
||||
|
||||
AutoSetThreadIsPerformingGC performingGC;
|
||||
|
|
|
@ -523,11 +523,13 @@ class VsyncRefreshDriverTimer : public RefreshDriverTimer {
|
|||
// thread.
|
||||
// TODO: On Linux Wayland, the vsync thread is currently the main thread,
|
||||
// and yet we still dispatch the runnable. Do we need to?
|
||||
bool useVsyncPriority = mozilla::BrowserTabsRemoteAutostart();
|
||||
nsCOMPtr<nsIRunnable> vsyncEvent = new PrioritizableRunnable(
|
||||
NS_NewRunnableFunction(
|
||||
"VsyncRefreshDriverTimer::NotifyVsyncOnMainThread",
|
||||
[self = RefPtr{this}]() { self->NotifyVsyncOnMainThread(); }),
|
||||
nsIRunnablePriority::PRIORITY_VSYNC);
|
||||
useVsyncPriority ? nsIRunnablePriority::PRIORITY_VSYNC
|
||||
: nsIRunnablePriority::PRIORITY_NORMAL);
|
||||
NS_DispatchToMainThread(vsyncEvent);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -43,11 +43,11 @@ StreamLoader::OnStartRequest(nsIRequest* aRequest) {
|
|||
int64_t length;
|
||||
nsresult rv = channel->GetContentLength(&length);
|
||||
if (NS_SUCCEEDED(rv) && length > 0) {
|
||||
if (uint64_t(length) >
|
||||
std::numeric_limits<nsACString::size_type>::max()) {
|
||||
CheckedInt<nsACString::size_type> checkedLength(length);
|
||||
if (!checkedLength.isValid()) {
|
||||
return (mStatus = NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
if (!mBytes.SetCapacity(length, fallible)) {
|
||||
if (!mBytes.SetCapacity(checkedLength.value(), fallible)) {
|
||||
return (mStatus = NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1816,6 +1816,13 @@
|
|||
value: @IS_ANDROID@
|
||||
mirror: always
|
||||
|
||||
# If true, page with beforeunload event listeners can be bfcached.
|
||||
# This only works when sessionHistoryInParent is enabled.
|
||||
- name: docshell.shistory.bfcache.ship_allow_beforeunload_listeners
|
||||
type: bool
|
||||
value: @IS_NIGHTLY_BUILD@
|
||||
mirror: always
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Prefs starting with "dom."
|
||||
#---------------------------------------------------------------------------
|
||||
|
|
|
@ -11870,8 +11870,6 @@ app.os.stg.fedoraproject.org
|
|||
|
||||
// FearWorks Media Ltd. : https://fearworksmedia.co.uk
|
||||
// submitted by Keith Fairley <domains@fearworksmedia.co.uk>
|
||||
couk.me
|
||||
ukco.me
|
||||
conn.uk
|
||||
copro.uk
|
||||
hosp.uk
|
||||
|
|
|
@ -115,7 +115,7 @@ nsresult Http3Stream::TryActivating() {
|
|||
head->Method(method);
|
||||
head->Path(path);
|
||||
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
#ifdef DEBUG
|
||||
nsAutoCString contentLength;
|
||||
if (NS_SUCCEEDED(head->GetHeader(nsHttp::Content_Length, contentLength))) {
|
||||
int64_t len;
|
||||
|
@ -204,7 +204,7 @@ nsresult Http3Stream::OnReadSegment(const char* buf, uint32_t count,
|
|||
break;
|
||||
}
|
||||
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
#ifdef DEBUG
|
||||
mRequestBodyLenSent += *countRead;
|
||||
#endif
|
||||
mTotalSent += *countRead;
|
||||
|
@ -214,7 +214,7 @@ nsresult Http3Stream::OnReadSegment(const char* buf, uint32_t count,
|
|||
case EARLY_RESPONSE:
|
||||
// We do not need to send the rest of the request, so just ignore it.
|
||||
*countRead = count;
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
#ifdef DEBUG
|
||||
mRequestBodyLenSent += count;
|
||||
#endif
|
||||
break;
|
||||
|
@ -404,8 +404,8 @@ nsresult Http3Stream::ReadSegments(nsAHttpSegmentReader* reader) {
|
|||
Telemetry::HTTP3_SENDING_BLOCKED_BY_FLOW_CONTROL_PER_TRANS,
|
||||
mSendingBlockedByFlowControlCount);
|
||||
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
MOZ_DIAGNOSTIC_ASSERT(mRequestBodyLenSent == mRequestBodyLenExpected);
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(mRequestBodyLenSent == mRequestBodyLenExpected);
|
||||
#endif
|
||||
rv = NS_OK;
|
||||
again = false;
|
||||
|
|
|
@ -161,7 +161,7 @@ class Http3Stream final : public nsAHttpSegmentReader,
|
|||
nsresult mSocketInCondition = NS_ERROR_NOT_INITIALIZED;
|
||||
nsresult mSocketOutCondition = NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
#ifdef DEBUG
|
||||
uint32_t mRequestBodyLenExpected{0};
|
||||
uint32_t mRequestBodyLenSent{0};
|
||||
#endif
|
||||
|
|
|
@ -158,7 +158,7 @@ class VisualStudioBackend(CommonBackend):
|
|||
basename,
|
||||
target,
|
||||
build_command=command,
|
||||
clean_command="$(SolutionDir)\\mach.bat build clean",
|
||||
clean_command="$(SolutionDir)\\mach.bat clobber",
|
||||
)
|
||||
|
||||
projects[basename] = (project_id, basename, target)
|
||||
|
|
|
@ -1134,4 +1134,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
|
|||
|
||||
static const int32_t kUnknownId = -1;
|
||||
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1654512523002000);
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1654771757823000);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,5 +1,21 @@
|
|||
{
|
||||
"data": [
|
||||
{
|
||||
"stash": {
|
||||
"blocked": [
|
||||
"{44a402f4-c627-4ecb-87c4-5fe5d0599047}:10.0.1",
|
||||
"{83e2015a-e472-4351-a409-eab977a62bb6}:4.0.0",
|
||||
"{bdd06799-956a-4228-9688-6a6bb3969d04}:1.0.0",
|
||||
"{6111770a-21eb-40a1-8022-39d7acedb2f0}:0.5.0"
|
||||
],
|
||||
"unblocked": []
|
||||
},
|
||||
"schema": 1646152603459,
|
||||
"key_format": "{guid}:{version}",
|
||||
"stash_time": 1646159708703,
|
||||
"id": "2efbeab7-0e69-4aeb-b0c1-e51a962487b3",
|
||||
"last_modified": 1646159885129
|
||||
},
|
||||
{
|
||||
"stash": {
|
||||
"blocked": [
|
||||
|
|
|
@ -1,5 +1,113 @@
|
|||
{
|
||||
"data": [
|
||||
{
|
||||
"schema": 1646254109453,
|
||||
"derHash": "YZB58QCmv7ZcsumIkN0KxJK2RmXiVKZqUp2PWRfYKrE=",
|
||||
"subject": "CN=SSL.com EV TLS Transit ECC CA R1,O=SSL Corp,C=US",
|
||||
"subjectDN": "MEsxCzAJBgNVBAYTAlVTMREwDwYDVQQKDAhTU0wgQ29ycDEpMCcGA1UEAwwgU1NMLmNvbSBFViBUTFMgVHJhbnNpdCBFQ0MgQ0EgUjE=",
|
||||
"whitelist": false,
|
||||
"attachment": {
|
||||
"hash": "813568ad3957479c17622a959b8ab63a4cf63c31d2ca33b7e821bf2b24596db3",
|
||||
"size": 1240,
|
||||
"filename": "TJF_18-c6aze9ptYohDyVqW8qpXBnJDFv7VibJ8Mwrk=.pem",
|
||||
"location": "security-state-staging/intermediates/e8dfd781-2c65-4f2e-8034-57aae5790501.pem",
|
||||
"mimetype": "application/x-pem-file"
|
||||
},
|
||||
"pubKeyHash": "TJF/18+c6aze9ptYohDyVqW8qpXBnJDFv7VibJ8Mwrk=",
|
||||
"crlite_enrolled": false,
|
||||
"id": "6c40d6c3-44da-4591-8301-206e579b5343",
|
||||
"last_modified": 1646254643604
|
||||
},
|
||||
{
|
||||
"schema": 1646232512995,
|
||||
"derHash": "EIFi8rNe1xxuqVAvlLk+l1R4nd6HGyrCbOBtRyB6lcw=",
|
||||
"subject": "CN=E-Tugra TLS ECC CA R1,O=E-TUGRA EBG BILISIM TEKNOLOJILERI VE HIZMETLERI ANONIM SIRKETI,C=TR",
|
||||
"subjectDN": "MHYxCzAJBgNVBAYTAlRSMUcwRQYDVQQKDD5FLVRVR1JBIEVCRyBCSUxJU0lNIFRFS05PTE9KSUxFUkkgVkUgSElaTUVUTEVSSSBBTk9OSU0gU0lSS0VUSTEeMBwGA1UEAwwVRS1UdWdyYSBUTFMgRUNDIENBIFIx",
|
||||
"whitelist": false,
|
||||
"attachment": {
|
||||
"hash": "865f7fc1eaa78ee98b3634dd19ba26f991e41b72612fd898dffb0a9b402f2f8d",
|
||||
"size": 1284,
|
||||
"filename": "77Kdi8Xr9UzIu5aCuPnN3svP6mCdcSnpHa2V6e8x1zA=.pem",
|
||||
"location": "security-state-staging/intermediates/2ba21fbd-496c-4064-b6aa-1bb4c08a8c3c.pem",
|
||||
"mimetype": "application/x-pem-file"
|
||||
},
|
||||
"pubKeyHash": "77Kdi8Xr9UzIu5aCuPnN3svP6mCdcSnpHa2V6e8x1zA=",
|
||||
"crlite_enrolled": false,
|
||||
"id": "4a2fa335-2783-4e37-bc80-fd22c3d5dde8",
|
||||
"last_modified": 1646233042429
|
||||
},
|
||||
{
|
||||
"schema": 1646232514397,
|
||||
"derHash": "JOegR1aXeTq/Pg3bBNVC/+fJPMcdGfYGcUSsqJpMpng=",
|
||||
"subject": "CN=E-Tugra EV TLS RSA CA R1,O=E-TUGRA EBG BILISIM TEKNOLOJILERI VE HIZMETLERI ANONIM SIRKETI,C=TR",
|
||||
"subjectDN": "MHkxCzAJBgNVBAYTAlRSMUcwRQYDVQQKDD5FLVRVR1JBIEVCRyBCSUxJU0lNIFRFS05PTE9KSUxFUkkgVkUgSElaTUVUTEVSSSBBTk9OSU0gU0lSS0VUSTEhMB8GA1UEAwwYRS1UdWdyYSBFViBUTFMgUlNBIENBIFIx",
|
||||
"whitelist": false,
|
||||
"attachment": {
|
||||
"hash": "ff832707ff6388c2f86f03c8876a2067b549ee5e964ee24eaf6836a126e93f47",
|
||||
"size": 2454,
|
||||
"filename": "xybzNe-3QsP87NG3ziCnmdMQCSi_ImhJj-f6c7P2LVg=.pem",
|
||||
"location": "security-state-staging/intermediates/421a9b84-482d-4dd3-956d-27a6423db871.pem",
|
||||
"mimetype": "application/x-pem-file"
|
||||
},
|
||||
"pubKeyHash": "xybzNe+3QsP87NG3ziCnmdMQCSi/ImhJj+f6c7P2LVg=",
|
||||
"crlite_enrolled": false,
|
||||
"id": "399e9081-2069-446f-9ee5-44f2b7f4f8ea",
|
||||
"last_modified": 1646233042419
|
||||
},
|
||||
{
|
||||
"schema": 1646232515698,
|
||||
"derHash": "WGpcmDbZ+zvoY7p2Wnlm2UApf+x73UiAFseqHq4fHVE=",
|
||||
"subject": "CN=E-Tugra TLS RSA CA R1,O=E-TUGRA EBG BILISIM TEKNOLOJILERI VE HIZMETLERI ANONIM SIRKETI,C=TR",
|
||||
"subjectDN": "MHYxCzAJBgNVBAYTAlRSMUcwRQYDVQQKDD5FLVRVR1JBIEVCRyBCSUxJU0lNIFRFS05PTE9KSUxFUkkgVkUgSElaTUVUTEVSSSBBTk9OSU0gU0lSS0VUSTEeMBwGA1UEAwwVRS1UdWdyYSBUTFMgUlNBIENBIFIx",
|
||||
"whitelist": false,
|
||||
"attachment": {
|
||||
"hash": "4eca0adeab34bbc93fb526a917efe4b0dfe1c89303f3813218c4c53646a37413",
|
||||
"size": 2434,
|
||||
"filename": "1vdxb07v0C-5fBq6GPagfHvdyZ31E78A2uKjjcHp3Z0=.pem",
|
||||
"location": "security-state-staging/intermediates/f971e33f-fec1-4627-b26d-452f26fd9551.pem",
|
||||
"mimetype": "application/x-pem-file"
|
||||
},
|
||||
"pubKeyHash": "1vdxb07v0C+5fBq6GPagfHvdyZ31E78A2uKjjcHp3Z0=",
|
||||
"crlite_enrolled": false,
|
||||
"id": "44db4b01-6471-46ba-9792-c342a677e89f",
|
||||
"last_modified": 1646233042409
|
||||
},
|
||||
{
|
||||
"schema": 1646232517034,
|
||||
"derHash": "e6jwu0n1Aem7cuOhNwjGqTMUD9xlWSo3rN5mrQfeYH4=",
|
||||
"subject": "CN=E-Tugra EV TLS ECC CA R1,O=E-TUGRA EBG BILISIM TEKNOLOJILERI VE HIZMETLERI ANONIM SIRKETI,C=TR",
|
||||
"subjectDN": "MHkxCzAJBgNVBAYTAlRSMUcwRQYDVQQKDD5FLVRVR1JBIEVCRyBCSUxJU0lNIFRFS05PTE9KSUxFUkkgVkUgSElaTUVUTEVSSSBBTk9OSU0gU0lSS0VUSTEhMB8GA1UEAwwYRS1UdWdyYSBFViBUTFMgRUNDIENBIFIx",
|
||||
"whitelist": false,
|
||||
"attachment": {
|
||||
"hash": "302b1dc9a9b8372cfd5bcf67052ac9ad6cf7fa23a9b994da49fc4ff8d64b8fad",
|
||||
"size": 1301,
|
||||
"filename": "4ZfJiEG0nvuWdrXyXFm7I_5f5kGPrz17N0dYeK9fTB8=.pem",
|
||||
"location": "security-state-staging/intermediates/e1526cc7-7873-45a6-b71a-40bee1c454dd.pem",
|
||||
"mimetype": "application/x-pem-file"
|
||||
},
|
||||
"pubKeyHash": "4ZfJiEG0nvuWdrXyXFm7I/5f5kGPrz17N0dYeK9fTB8=",
|
||||
"crlite_enrolled": false,
|
||||
"id": "24e440a2-1aae-463f-8ad8-b016dd56e58e",
|
||||
"last_modified": 1646233042398
|
||||
},
|
||||
{
|
||||
"schema": 1646103458585,
|
||||
"derHash": "qEdUTMPNVOhVyjl4DCFiQx9cjjJ+xm1aQ88maHe+xQ8=",
|
||||
"subject": "CN=HydrantID SSL CA D1,O=Avalanche Cloud Corporation,C=US",
|
||||
"subjectDN": "MFExCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtBdmFsYW5jaGUgQ2xvdWQgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0h5ZHJhbnRJRCBTU0wgQ0EgRDE=",
|
||||
"whitelist": false,
|
||||
"attachment": {
|
||||
"hash": "06ef680fca20d39a376ae63a23282c3c882a1d9a10e1b090d7a649ca52cb495b",
|
||||
"size": 1691,
|
||||
"filename": "pFJuHwTjYt84g_qC76hABYpNYJN5mgRCOZ3SeolVQWw=.pem",
|
||||
"location": "security-state-staging/intermediates/78620e34-e02c-45a6-829f-9e58d846ec6a.pem",
|
||||
"mimetype": "application/x-pem-file"
|
||||
},
|
||||
"pubKeyHash": "pFJuHwTjYt84g/qC76hABYpNYJN5mgRCOZ3SeolVQWw=",
|
||||
"crlite_enrolled": true,
|
||||
"id": "4881e3af-3f96-44cf-b1e0-4b814adb983c",
|
||||
"last_modified": 1646189839663
|
||||
},
|
||||
{
|
||||
"schema": 1645797876228,
|
||||
"derHash": "TJ55n+pib17TXY+RVI+2o5AFAwmfMrxJ3A+1ZrCg7zc=",
|
||||
|
@ -2466,24 +2574,6 @@
|
|||
"id": "806d2ed6-4b90-44a3-8208-2c60f2a2e5f3",
|
||||
"last_modified": 1645579197432
|
||||
},
|
||||
{
|
||||
"schema": 1645578786208,
|
||||
"derHash": "yhTPmzCboDK7IZEMGu2uTSn+Bla0+L/6I8vpTUMcBnQ=",
|
||||
"subject": "CN=Entrust Certification Authority - DE QWAC1,O=Entrust Datacard Deutschland GmbH,C=DE",
|
||||
"subjectDN": "MIGIMTMwMQYDVQQDDCpFbnRydXN0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gREUgUVdBQzExGDAWBgNVBGEMD1ZBVERFLTExOTI2NDMxNjEqMCgGA1UECgwhRW50cnVzdCBEYXRhY2FyZCBEZXV0c2NobGFuZCBHbWJIMQswCQYDVQQGEwJERQ==",
|
||||
"whitelist": false,
|
||||
"attachment": {
|
||||
"hash": "4e133243cde83dcbe732252fbf43b8518690328d9c29c7647170c786d537e396",
|
||||
"size": 1792,
|
||||
"filename": "ZWhmaUZRaiEz-pmpHFYrrwb8L7sV4g8Lss57AOkaaLg=.pem",
|
||||
"location": "security-state-staging/intermediates/b6535e1d-acae-4e64-a88c-09d9aad68077.pem",
|
||||
"mimetype": "application/x-pem-file"
|
||||
},
|
||||
"pubKeyHash": "ZWhmaUZRaiEz+pmpHFYrrwb8L7sV4g8Lss57AOkaaLg=",
|
||||
"crlite_enrolled": true,
|
||||
"id": "e3c9fc9c-b56e-40f6-94aa-9fcd0d028567",
|
||||
"last_modified": 1645579197419
|
||||
},
|
||||
{
|
||||
"schema": 1645578791076,
|
||||
"derHash": "kzuA97lyVd9c8dlaEj6QFyLdswtIGvOqg1SCARGe0wM=",
|
||||
|
@ -11466,42 +11556,6 @@
|
|||
"id": "308fb64b-a058-4676-aa68-e8e33b332c2f",
|
||||
"last_modified": 1629359842217
|
||||
},
|
||||
{
|
||||
"schema": 1628733014053,
|
||||
"derHash": "HsCvw+2fK63KBo4MLYH5xi75dSIxYxe3iGYrPtrTgHU=",
|
||||
"subject": "CN=CRYPTAS EV Issuing CA,O=CRYPTAS it-Security GmbH,C=AT",
|
||||
"subjectDN": "MFAxCzAJBgNVBAYTAkFUMSEwHwYDVQQKExhDUllQVEFTIGl0LVNlY3VyaXR5IEdtYkgxHjAcBgNVBAMTFUNSWVBUQVMgRVYgSXNzdWluZyBDQQ==",
|
||||
"whitelist": false,
|
||||
"attachment": {
|
||||
"hash": "2457cbcf379f5f195fb7ba4cfda565f717ef9156b63623457e3301d515f0a255",
|
||||
"size": 1735,
|
||||
"filename": "Hfy6dQZGrjdPYWGB1jtGCNqt0xhK43ly0PpF6FLmg3A=.pem",
|
||||
"location": "security-state-staging/intermediates/bc8ea5bd-51a8-4d5a-843d-4e5dc8487e16.pem",
|
||||
"mimetype": "application/x-pem-file"
|
||||
},
|
||||
"pubKeyHash": "Hfy6dQZGrjdPYWGB1jtGCNqt0xhK43ly0PpF6FLmg3A=",
|
||||
"crlite_enrolled": true,
|
||||
"id": "35a5d389-1b24-494b-b20f-25ff30eee6b3",
|
||||
"last_modified": 1629359842197
|
||||
},
|
||||
{
|
||||
"schema": 1628797804852,
|
||||
"derHash": "+uzdBdny5f6EmN5WzfiVwKaXCU4Xc97eX84gAbTHsVI=",
|
||||
"subject": "CN=CRYPTAS OV Issuing CA,O=CRYPTAS it-Security GmbH,C=AT",
|
||||
"subjectDN": "MFAxCzAJBgNVBAYTAkFUMSEwHwYDVQQKExhDUllQVEFTIGl0LVNlY3VyaXR5IEdtYkgxHjAcBgNVBAMTFUNSWVBUQVMgT1YgSXNzdWluZyBDQQ==",
|
||||
"whitelist": false,
|
||||
"attachment": {
|
||||
"hash": "f56a51e5163cf8ad0112976fedb21ae8b4b37916e6ce6589da1af5850254ff9f",
|
||||
"size": 1739,
|
||||
"filename": "U8nQD9wXAUszOzpIA4B47LOCJYIzJLUU65_asRztVds=.pem",
|
||||
"location": "security-state-staging/intermediates/ea32cf1d-0468-4c6e-8a78-d5381be82033.pem",
|
||||
"mimetype": "application/x-pem-file"
|
||||
},
|
||||
"pubKeyHash": "U8nQD9wXAUszOzpIA4B47LOCJYIzJLUU65/asRztVds=",
|
||||
"crlite_enrolled": true,
|
||||
"id": "57899723-0793-43ef-ad24-f5da978584e9",
|
||||
"last_modified": 1629359842177
|
||||
},
|
||||
{
|
||||
"schema": 1627740208946,
|
||||
"derHash": "wt/7PBuwbeTBCSblF/82b5OJLV4C3G95CAJ121f9b8g=",
|
||||
|
@ -12510,24 +12564,6 @@
|
|||
"id": "8cef2110-60e3-4274-b66f-73184cf70e37",
|
||||
"last_modified": 1614909446623
|
||||
},
|
||||
{
|
||||
"schema": 1614908982274,
|
||||
"derHash": "qEdUTMPNVOhVyjl4DCFiQx9cjjJ+xm1aQ88maHe+xQ8=",
|
||||
"subject": "CN=HydrantID SSL CA D1,O=Avalanche Cloud Corporation,C=US",
|
||||
"subjectDN": "MFExCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtBdmFsYW5jaGUgQ2xvdWQgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0h5ZHJhbnRJRCBTU0wgQ0EgRDE=",
|
||||
"whitelist": false,
|
||||
"attachment": {
|
||||
"hash": "06ef680fca20d39a376ae63a23282c3c882a1d9a10e1b090d7a649ca52cb495b",
|
||||
"size": 1691,
|
||||
"filename": "pFJuHwTjYt84g_qC76hABYpNYJN5mgRCOZ3SeolVQWw=.pem",
|
||||
"location": "security-state-staging/intermediates/78620e34-e02c-45a6-829f-9e58d846ec6a.pem",
|
||||
"mimetype": "application/x-pem-file"
|
||||
},
|
||||
"pubKeyHash": "pFJuHwTjYt84g/qC76hABYpNYJN5mgRCOZ3SeolVQWw=",
|
||||
"crlite_enrolled": false,
|
||||
"id": "4881e3af-3f96-44cf-b1e0-4b814adb983c",
|
||||
"last_modified": 1614909446597
|
||||
},
|
||||
{
|
||||
"schema": 1614585512688,
|
||||
"derHash": "TvqqEECsL0TT3uIG2VIqKI2E7Djd9ZKYySbgL0ydmu8=",
|
||||
|
|
|
@ -295,6 +295,11 @@ artifact_map
|
|||
For beetmover jobs, this indicates which yaml file should be used to
|
||||
generate the upstream artifacts and payload instructions to the task.
|
||||
|
||||
release_artifacts
|
||||
=================
|
||||
A set of artifacts that are candidates for downstream release tasks to operate
|
||||
on.
|
||||
|
||||
batch
|
||||
=====
|
||||
Used by `perftest` to indicates that a task can be run as a batch.
|
||||
|
|
|
@ -86,7 +86,6 @@ class Kind:
|
|||
dependencies=task_dict.get("dependencies"),
|
||||
soft_dependencies=task_dict.get("soft-dependencies"),
|
||||
if_dependencies=task_dict.get("if-dependencies"),
|
||||
release_artifacts=task_dict.get("release-artifacts"),
|
||||
)
|
||||
for task_dict in transforms(trans_config, inputs)
|
||||
]
|
||||
|
|
|
@ -41,21 +41,10 @@ class Task:
|
|||
dependencies = attr.ib(factory=dict)
|
||||
soft_dependencies = attr.ib(factory=list)
|
||||
if_dependencies = attr.ib(factory=list)
|
||||
release_artifacts = attr.ib(
|
||||
converter=attr.converters.optional(frozenset),
|
||||
default=None,
|
||||
)
|
||||
|
||||
def __attrs_post_init__(self):
|
||||
self.attributes["kind"] = self.kind
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
if self.label.startswith(self.kind + "-"):
|
||||
return self.label[len(self.kind) + 1 :]
|
||||
else:
|
||||
raise AttributeError(f"Task {self.label} does not have a name.")
|
||||
|
||||
def to_json(self):
|
||||
rv = {
|
||||
"kind": self.kind,
|
||||
|
@ -70,8 +59,6 @@ class Task:
|
|||
}
|
||||
if self.task_id:
|
||||
rv["task_id"] = self.task_id
|
||||
if self.release_artifacts:
|
||||
rv["release_artifacts"] = sorted(self.release_artifacts)
|
||||
return rv
|
||||
|
||||
@classmethod
|
||||
|
@ -91,7 +78,6 @@ class Task:
|
|||
dependencies=task_dict.get("dependencies"),
|
||||
soft_dependencies=task_dict.get("soft_dependencies"),
|
||||
if_dependencies=task_dict.get("if_dependencies"),
|
||||
release_artifacts=task_dict.get("release-artifacts"),
|
||||
)
|
||||
if "task_id" in task_dict:
|
||||
rv.task_id = task_dict["task_id"]
|
||||
|
|
|
@ -56,7 +56,6 @@ def generate_tasks(*tasks):
|
|||
"optimization",
|
||||
"dependencies",
|
||||
"soft_dependencies",
|
||||
"release_artifacts",
|
||||
):
|
||||
task.setdefault(attr, None)
|
||||
|
||||
|
|
|
@ -69,7 +69,6 @@ job_description_schema = Schema(
|
|||
"optimization"
|
||||
],
|
||||
Optional("use-sccache"): task_description_schema["use-sccache"],
|
||||
Optional("release-artifacts"): task_description_schema["release-artifacts"],
|
||||
Optional("priority"): task_description_schema["priority"],
|
||||
# The "when" section contains descriptions of the circumstances under which
|
||||
# this task should be included in the task graph. This will be converted
|
||||
|
|
|
@ -17,7 +17,10 @@ from gecko_taskgraph.util.schema import (
|
|||
resolve_keyed_by,
|
||||
taskref_or_string,
|
||||
)
|
||||
from gecko_taskgraph.util.attributes import copy_attributes_from_dependent_job
|
||||
from gecko_taskgraph.util.attributes import (
|
||||
copy_attributes_from_dependent_job,
|
||||
task_name,
|
||||
)
|
||||
from gecko_taskgraph.util.taskcluster import get_artifact_prefix
|
||||
from gecko_taskgraph.util.treeherder import add_suffix
|
||||
from gecko_taskgraph.transforms.job import job_description_schema
|
||||
|
@ -159,7 +162,7 @@ def setup_name(config, jobs):
|
|||
dep = job["primary-dependency"]
|
||||
# Set the name to the same as the dep task, without kind name.
|
||||
# Label will get set automatically with this kinds name.
|
||||
job["name"] = job.get("name", dep.name)
|
||||
job["name"] = job.get("name", task_name(dep))
|
||||
yield job
|
||||
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ def generate_complete_artifacts(job, kind):
|
|||
upstream_artifacts = []
|
||||
if kind not in SIGNING_FORMATS:
|
||||
kind = "default"
|
||||
for artifact in job.release_artifacts:
|
||||
for artifact in job.attributes["release_artifacts"]:
|
||||
basename = os.path.basename(artifact)
|
||||
if basename in SIGNING_FORMATS[kind]:
|
||||
upstream_artifacts.append(
|
||||
|
|
|
@ -122,7 +122,7 @@ def add_command_arguments(config, tasks):
|
|||
"type": "directory",
|
||||
}
|
||||
]
|
||||
task["release-artifacts"] = release_artifacts
|
||||
task.setdefault("attributes", {})["release_artifacts"] = release_artifacts
|
||||
task["label"] = config.kind
|
||||
|
||||
yield task
|
||||
|
|
|
@ -72,7 +72,9 @@ def split_public_and_private(config, jobs):
|
|||
# in a single task. Only use a single task for each type though.
|
||||
partner_config = get_partner_config_by_kind(config, config.kind)
|
||||
for job in jobs:
|
||||
upstream_artifacts = job["primary-dependency"].release_artifacts
|
||||
upstream_artifacts = job["primary-dependency"].attributes.get(
|
||||
"release_artifacts"
|
||||
)
|
||||
attribution_task_ref = "<{}>".format(job["primary-dependency"].label)
|
||||
prefix = get_artifact_prefix(job["primary-dependency"])
|
||||
artifacts = defaultdict(list)
|
||||
|
|
|
@ -481,6 +481,9 @@ def make_job_description(config, jobs):
|
|||
repackage_config=repackage_config,
|
||||
locale=locale,
|
||||
)
|
||||
attributes["release_artifacts"] = [
|
||||
artifact["name"] for artifact in worker["artifacts"]
|
||||
]
|
||||
|
||||
task = {
|
||||
"label": job["label"],
|
||||
|
@ -507,7 +510,6 @@ def make_job_description(config, jobs):
|
|||
project=config.params["project"],
|
||||
existing_fetch=job.get("fetches"),
|
||||
),
|
||||
"release-artifacts": [artifact["name"] for artifact in worker["artifacts"]],
|
||||
}
|
||||
|
||||
if build_platform.startswith("macosx"):
|
||||
|
|
|
@ -105,7 +105,7 @@ def make_repackage_signing_description(config, jobs):
|
|||
scopes = [signing_cert_scope]
|
||||
|
||||
upstream_artifacts = []
|
||||
for artifact in sorted(dep_job.release_artifacts):
|
||||
for artifact in sorted(dep_job.attributes.get("release_artifacts")):
|
||||
basename = os.path.basename(artifact)
|
||||
if basename in SIGNING_FORMATS:
|
||||
upstream_artifacts.append(
|
||||
|
|
|
@ -173,6 +173,9 @@ def make_task_description(config, jobs):
|
|||
)
|
||||
attributes["signed"] = True
|
||||
|
||||
if "linux" in build_platform:
|
||||
attributes["release_artifacts"] = ["public/build/KEY"]
|
||||
|
||||
if dep_job.attributes.get("chunk_locales"):
|
||||
# Used for l10n attribute passthrough
|
||||
attributes["chunk_locales"] = dep_job.attributes.get("chunk_locales")
|
||||
|
@ -202,9 +205,6 @@ def make_task_description(config, jobs):
|
|||
if dep_job.kind in task["dependencies"]:
|
||||
task["if-dependencies"] = [dep_job.kind]
|
||||
|
||||
if "linux" in build_platform:
|
||||
task["release-artifacts"] = ["public/build/KEY"]
|
||||
|
||||
if "macosx" in build_platform:
|
||||
shippable = "false"
|
||||
if "shippable" in attributes and attributes["shippable"]:
|
||||
|
|
|
@ -192,8 +192,6 @@ task_description_schema = Schema(
|
|||
"worker-type": str,
|
||||
# Whether the job should use sccache compiler caching.
|
||||
Required("use-sccache"): bool,
|
||||
# Set of artifacts relevant to release tasks
|
||||
Optional("release-artifacts"): [str],
|
||||
# information specific to the worker implementation that will run this task
|
||||
Optional("worker"): {
|
||||
Required("implementation"): str,
|
||||
|
@ -851,7 +849,8 @@ def build_scriptworker_signing_payload(config, task, task_def):
|
|||
for attribute in ("entitlements-url", "requirements-plist-url"):
|
||||
if worker.get(attribute):
|
||||
task_def["payload"][attribute] = worker[attribute]
|
||||
artifacts = set(task.get("release-artifacts", []))
|
||||
|
||||
artifacts = set(task.setdefault("attributes", {}).get("release_artifacts", []))
|
||||
for upstream_artifact in worker["upstream-artifacts"]:
|
||||
for path in upstream_artifact["paths"]:
|
||||
artifacts.update(
|
||||
|
@ -861,7 +860,7 @@ def build_scriptworker_signing_payload(config, task, task_def):
|
|||
behavior=worker.get("mac-behavior"),
|
||||
)
|
||||
)
|
||||
task["release-artifacts"] = list(artifacts)
|
||||
task["attributes"]["release_artifacts"] = list(artifacts)
|
||||
|
||||
|
||||
@payload_builder(
|
||||
|
@ -2008,7 +2007,6 @@ def build_task(config, tasks):
|
|||
"soft-dependencies": task.get("soft-dependencies", []),
|
||||
"attributes": attributes,
|
||||
"optimization": task.get("optimization", None),
|
||||
"release-artifacts": task.get("release-artifacts", []),
|
||||
}
|
||||
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче