Merge mozilla-central to inbound. a=merge CLOSED TREE

This commit is contained in:
Gurzau Raul 2019-03-01 09:28:28 +02:00
commit 6b94d177d1
203 changed files with 2045 additions and 3108 deletions

View File

@ -26,7 +26,7 @@
</div>
<div id="errorLongContent">
<div id="errorLongDesc">
<p data-l10n-id="restart-required-intro"></p>
<p data-l10n-id="restart-required-intro-brand"></p>
<p data-l10n-id="restart-required-description"></p>
</div>
</div>

View File

@ -261,7 +261,7 @@ var CaptivePortalWatcher = {
gBrowser.selectedTab = tab;
let canonicalURI = makeURI(this.canonicalURL);
let canonicalURI = Services.io.newURI(this.canonicalURL);
// When we are no longer captive, close the tab if it's at the canonical URL.
let tabCloser = () => {

View File

@ -44,8 +44,6 @@ async function submitForm(event) {
event.preventDefault();
let input = document.getElementById("sync-input");
input.disabled = true;
document.getElementById("sync-button").disabled = true;
let { flowId, flowBeginTime } = await metrics;
@ -59,6 +57,7 @@ async function submitForm(event) {
});
window.open(requestURL, "_blank", "noopener");
document.getElementById("sync").hidden = true;
}
const endpoint = RPMGetFxAccountsEndpoint(ENTRYPOINT);

View File

@ -2429,7 +2429,8 @@
if (event.originalTarget.classList.contains("tab-icon-sound") ||
(event.originalTarget.classList.contains("tab-icon-overlay") &&
(event.originalTarget.hasAttribute("soundplaying") ||
event.originalTarget.hasAttribute("muted")))) {
event.originalTarget.hasAttribute("muted") ||
event.originalTarget.hasAttribute("activemedia-blocked")))) {
if (this.multiselected) {
gBrowser.toggleMuteAudioOnMultiSelectedTabs(this);
} else {

View File

@ -27,10 +27,9 @@ add_task(async function findbar_test() {
ok(!gFindBar.hidden, "the Find bar isn't hidden after the location of a " +
"subdocument changes");
let findBarClosePromise = promiseWaitForEvent(gBrowser, "findbarclose");
let findBarClosePromise = BrowserTestUtils.waitForEvent(gBrowser, "findbarclose");
gFindBar.close();
await findBarClosePromise;
gBrowser.removeTab(newTab);
});

View File

@ -8,6 +8,7 @@ prefs =
# Skip migration work in BG__migrateUI for browser_startup.js since it isn't
# representative of common startup.
browser.migration.version=9999999
browser.urlbar.quantumbar=true
browser.startup.record=true
gfx.canvas.willReadFrequently.enable=true
# The form autofill framescript is only used in certain locales if this

View File

@ -1,8 +1,6 @@
"use strict";
// There are a _lot_ of reflows in this test, and processing them takes
// time. On slower builds, we need to boost our allowed test time.
requestLongerTimeout(5);
// This tests searching in the urlbar (a.k.a. the quantumbar).
/**
* WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
@ -14,186 +12,42 @@ requestLongerTimeout(5);
* for tips on how to do that.
*/
/* These reflows happen only the first time the awesomebar panel opens. */
const EXPECTED_REFLOWS_FIRST_OPEN = [];
if (AppConstants.platform != "macosx" &&
(AppConstants.DEBUG ||
AppConstants.platform == "win")) {
EXPECTED_REFLOWS_FIRST_OPEN.push({
/* These reflows happen only the first time the panel opens. */
const EXPECTED_REFLOWS_FIRST_OPEN = [
// This is the this.panel.openPopup() call in UrlbarView._openPanel. See bug
// 1359989, which was filed against the legacy awesomebar but applies here too
// because it seems to be caused by platform code.
{
stack: [
"_openPanel@resource:///modules/UrlbarView.jsm",
"onQueryResults@resource:///modules/UrlbarView.jsm",
"_notify@resource:///modules/UrlbarController.jsm",
"receiveResults@resource:///modules/UrlbarController.jsm",
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
"add@resource:///modules/UrlbarProvidersManager.jsm",
"onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
],
},
{
stack: [
"__rebuild@chrome://browser/content/search/search-one-offs.js",
/* This is limited to a one-line stack, because the next item is an async
function and as such not supported on all trees, according to bug 1501761.
"async*set popup@chrome://browser/content/search/search-one-offs.js",
"_syncOneOffSearchesEnabled@chrome://browser/content/urlbarBindings.xml",
"toggleOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"@chrome://browser/content/urlbarBindings.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",*/
"async*_rebuild@chrome://browser/content/search/search-one-offs.js",
"async*_on_popupshowing@chrome://browser/content/search/search-one-offs.js",
"handleEvent@chrome://browser/content/search/search-one-offs.js",
"_openPanel@resource:///modules/UrlbarView.jsm",
"onQueryResults@resource:///modules/UrlbarView.jsm",
"_notify@resource:///modules/UrlbarController.jsm",
"receiveResults@resource:///modules/UrlbarController.jsm",
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
"add@resource:///modules/UrlbarProvidersManager.jsm",
"onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
*/
],
});
}
EXPECTED_REFLOWS_FIRST_OPEN.push(
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_reuseAcItem@chrome://global/content/elements/autocomplete-richlistitem.js",
"_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
"_invalidate@chrome://global/content/bindings/autocomplete.xml",
"invalidate@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 60, // This number should only ever go down - never up.
},
];
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 6, // This number should only ever go down - never up.
},
// Bug 1359989
{
stack: [
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
}
);
// These extra reflows happen on beta/release as one of the default bookmarks in
// bookmarks.html.in has a long URL.
if (AppConstants.RELEASE_OR_BETA) {
EXPECTED_REFLOWS_FIRST_OPEN.push({
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_onUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"MozAutocompleteRichlistitem/<@chrome://global/content/elements/autocomplete-richlistitem.js",
],
maxCount: 6,
},
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_onOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"MozAutocompleteRichlistitem/<@chrome://global/content/elements/autocomplete-richlistitem.js",
],
maxCount: 6,
},
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_adjustAcItem@chrome://global/content/elements/autocomplete-richlistitem.js",
"_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
"_invalidate@chrome://global/content/bindings/autocomplete.xml",
"invalidate@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 12,
});
}
/**
* Returns a Promise that resolves once the AwesomeBar popup for a particular
* window has appeared after having done a search for its input text.
*
* @param win (browser window)
* The window to do the search in.
* @returns Promise
*/
async function promiseSearchComplete(win) {
let URLBar = win.gURLBar;
if (URLBar.popup.state != "open") {
await BrowserTestUtils.waitForEvent(URLBar.popup, "popupshown");
}
await BrowserTestUtils.waitForCondition(() => {
return URLBar.controller.searchStatus >=
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
});
// There are several setTimeout(fn, 0); calls inside autocomplete.xml
// that we need to wait for. Since those have higher priority than
// idle callbacks, we can be sure they will have run once this
// idle callback is called. The timeout seems to be required in
// automation - presumably because the machines can be pretty busy
// especially if it's GC'ing from previous tests.
await new Promise(resolve => win.requestIdleCallback(resolve, { timeout: 1000 }));
}
add_task(async function setup() {
await addDummyHistoryEntries();
});
/**
* This test ensures that there are no unexpected uninterruptible reflows when
* typing into the URL bar with the default values in Places.
*/
add_task(async function() {
let win = await prepareSettledWindow();
let URLBar = win.gURLBar;
let popup = URLBar.popup;
URLBar.focus();
URLBar.value = "";
let dropmarkerRect = document.getAnonymousElementByAttribute(gURLBar,
"anonid", "historydropmarker").getBoundingClientRect();
let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
"anonid", "moz-input-box").getBoundingClientRect();
await withPerfObserver(async function() {
let oldInvalidate = popup.invalidate.bind(popup);
let oldResultsAdded = popup.onResultsAdded.bind(popup);
// We need to invalidate the frame tree outside of the normal
// mechanism since invalidations and result additions to the
// URL bar occur without firing JS events (which is how we
// normally know to dirty the frame tree).
popup.invalidate = (reason) => {
dirtyFrame(win);
oldInvalidate(reason);
};
popup.onResultsAdded = () => {
dirtyFrame(win);
oldResultsAdded();
};
// Only keying in 6 characters because the number of reflows triggered
// is so high that we risk timing out the test if we key in any more.
const SEARCH_TERM = "ows-10";
for (let i = 0; i < SEARCH_TERM.length; ++i) {
let char = SEARCH_TERM[i];
EventUtils.synthesizeKey(char, {}, win);
await promiseSearchComplete(win);
}
let hiddenPromise = BrowserTestUtils.waitForEvent(URLBar.popup, "popuphidden");
EventUtils.synthesizeKey("VK_ESCAPE", {}, win);
await hiddenPromise;
}, {expectedReflows: EXPECTED_REFLOWS_FIRST_OPEN,
frames: {filter: rects => rects.filter(r => !(
// We put text into the urlbar so expect its textbox to change.
(r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom) ||
// The dropmarker is replaced with the go arrow during the test.
// dropmarkerRect.left isn't always an integer, hence the - 1 and + 1
(r.x1 >= dropmarkerRect.left - 1 && r.x2 <= dropmarkerRect.right + 1 &&
r.y1 >= dropmarkerRect.top && r.y2 <= dropmarkerRect.bottom)
// XXX For some reason the awesomebar panel isn't in our screenshots,
// but that's where we actually expect many changes.
))}}, win);
await BrowserTestUtils.closeWindow(win);
add_task(async function quantumbar() {
await runUrlbarTest(false, true, EXPECTED_REFLOWS_FIRST_OPEN);
});

View File

@ -0,0 +1,111 @@
"use strict";
// This tests searching in the legacy urlbar implementation (a.k.a. the
// awesomebar).
// There are a _lot_ of reflows in this test, and processing them takes
// time. On slower builds, we need to boost our allowed test time.
requestLongerTimeout(5);
/**
* WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
* is a whitelist that should slowly go away as we improve the performance of
* the front-end. Instead of adding more reflows to the whitelist, you should
* be modifying your code to avoid the reflow.
*
* See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
* for tips on how to do that.
*/
/* These reflows happen only the first time the awesomebar panel opens. */
const EXPECTED_REFLOWS_FIRST_OPEN = [];
if (AppConstants.platform != "macosx" &&
(AppConstants.DEBUG ||
AppConstants.platform == "win")) {
EXPECTED_REFLOWS_FIRST_OPEN.push({
stack: [
"__rebuild@chrome://browser/content/search/search-one-offs.js",
/* This is limited to a one-line stack, because the next item is an async
function and as such not supported on all trees, according to bug 1501761.
"async*set popup@chrome://browser/content/search/search-one-offs.js",
"_syncOneOffSearchesEnabled@chrome://browser/content/urlbarBindings.xml",
"toggleOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"@chrome://browser/content/urlbarBindings.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",*/
],
});
}
EXPECTED_REFLOWS_FIRST_OPEN.push(
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_reuseAcItem@chrome://global/content/elements/autocomplete-richlistitem.js",
"_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
"_invalidate@chrome://global/content/bindings/autocomplete.xml",
"invalidate@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 60, // This number should only ever go down - never up.
},
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 6, // This number should only ever go down - never up.
},
// Bug 1359989
{
stack: [
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
}
);
// These extra reflows happen on beta/release as one of the default bookmarks in
// bookmarks.html.in has a long URL.
if (AppConstants.RELEASE_OR_BETA) {
EXPECTED_REFLOWS_FIRST_OPEN.push({
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_onUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"MozAutocompleteRichlistitem/<@chrome://global/content/elements/autocomplete-richlistitem.js",
],
maxCount: 6,
},
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_onOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"MozAutocompleteRichlistitem/<@chrome://global/content/elements/autocomplete-richlistitem.js",
],
maxCount: 6,
},
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_adjustAcItem@chrome://global/content/elements/autocomplete-richlistitem.js",
"_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
"_invalidate@chrome://global/content/bindings/autocomplete.xml",
"invalidate@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 12,
});
}
add_task(async function awesomebar() {
await runUrlbarTest(true, true, EXPECTED_REFLOWS_FIRST_OPEN);
});

View File

@ -1,8 +1,6 @@
"use strict";
// There are a _lot_ of reflows in this test, and processing them takes
// time. On slower builds, we need to boost our allowed test time.
requestLongerTimeout(5);
// This tests searching in the urlbar (a.k.a. the quantumbar).
/**
* WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
@ -14,185 +12,58 @@ requestLongerTimeout(5);
* for tips on how to do that.
*/
/* These reflows happen only the first time the awesomebar panel opens. */
const EXPECTED_REFLOWS_FIRST_OPEN = [];
if (AppConstants.platform != "macosx" &&
(AppConstants.DEBUG ||
AppConstants.platform == "linux" ||
AppConstants.isPlatformAndVersionAtLeast("win", "10"))) {
EXPECTED_REFLOWS_FIRST_OPEN.push({
/* These reflows happen only the first time the panel opens. */
const EXPECTED_REFLOWS_FIRST_OPEN = [
{
stack: [
"_openPanel@resource:///modules/UrlbarView.jsm",
"onQueryResults@resource:///modules/UrlbarView.jsm",
"_notify@resource:///modules/UrlbarController.jsm",
"receiveResults@resource:///modules/UrlbarController.jsm",
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
"add@resource:///modules/UrlbarProvidersManager.jsm",
"onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
],
},
{
stack: [
"__rebuild@chrome://browser/content/search/search-one-offs.js",
/* This is limited to a one-line stack, because the next item is an async
function and as such not supported on all trees, according to bug 1501761.
"async*set popup@chrome://browser/content/search/search-one-offs.js",
"_syncOneOffSearchesEnabled@chrome://browser/content/urlbarBindings.xml",
"toggleOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"@chrome://browser/content/urlbarBindings.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",*/
],
});
}
EXPECTED_REFLOWS_FIRST_OPEN.push(
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_reuseAcItem@chrome://global/content/elements/autocomplete-richlistitem.js",
"_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
"_invalidate@chrome://global/content/bindings/autocomplete.xml",
"invalidate@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 36, // This number should only ever go down - never up.
},
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 6, // This number should only ever go down - never up.
},
// Bug 1359989
{
stack: [
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
}
);
/* These reflows happen everytime the awesomebar panel opens. */
const EXPECTED_REFLOWS_SECOND_OPEN = [
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_reuseAcItem@chrome://global/content/elements/autocomplete-richlistitem.js",
"_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
"_invalidate@chrome://global/content/bindings/autocomplete.xml",
"invalidate@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 24, // This number should only ever go down - never up.
},
// Bug 1359989
{
stack: [
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
"async*_rebuild@chrome://browser/content/search/search-one-offs.js",
"async*_on_popupshowing@chrome://browser/content/search/search-one-offs.js",
"handleEvent@chrome://browser/content/search/search-one-offs.js",
"_openPanel@resource:///modules/UrlbarView.jsm",
"onQueryResults@resource:///modules/UrlbarView.jsm",
"_notify@resource:///modules/UrlbarController.jsm",
"receiveResults@resource:///modules/UrlbarController.jsm",
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
"add@resource:///modules/UrlbarProvidersManager.jsm",
"onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
*/
],
},
];
const SEARCH_TERM = "urlbar-reflows-" + Date.now();
/* These reflows happen every time the panel opens. */
const EXPECTED_REFLOWS_SECOND_OPEN = [
// This is the this.panel.openPopup() call in UrlbarView._openPanel. See bug
// 1359989, which was filed against the legacy awesomebar but applies here too
// because it seems to be caused by platform code.
{
stack: [
"_openPanel@resource:///modules/UrlbarView.jsm",
"onQueryResults@resource:///modules/UrlbarView.jsm",
"_notify@resource:///modules/UrlbarController.jsm",
"receiveResults@resource:///modules/UrlbarController.jsm",
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
"add@resource:///modules/UrlbarProvidersManager.jsm",
"onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
],
},
];
add_task(async function setup() {
await addDummyHistoryEntries(SEARCH_TERM);
});
/**
* This test ensures that there are no unexpected
* uninterruptible reflows when typing into the URL bar
* with the default values in Places.
*/
add_task(async function() {
let win = await prepareSettledWindow();
let URLBar = win.gURLBar;
let popup = URLBar.popup;
URLBar.focus();
URLBar.value = SEARCH_TERM;
let testFn = async function() {
let oldInvalidate = popup.invalidate.bind(popup);
let oldResultsAdded = popup.onResultsAdded.bind(popup);
let oldSetTimeout = win.setTimeout;
// We need to invalidate the frame tree outside of the normal
// mechanism since invalidations and result additions to the
// URL bar occur without firing JS events (which is how we
// normally know to dirty the frame tree).
popup.invalidate = (reason) => {
dirtyFrame(win);
oldInvalidate(reason);
};
popup.onResultsAdded = () => {
dirtyFrame(win);
oldResultsAdded();
};
win.setTimeout = (fn, ms) => {
return oldSetTimeout(() => {
dirtyFrame(win);
fn();
}, ms);
};
URLBar.controller.startSearch(URLBar.value);
await BrowserTestUtils.waitForEvent(URLBar.popup, "popupshown");
await BrowserTestUtils.waitForCondition(() => {
return URLBar.controller.searchStatus >=
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
});
let matchCount = URLBar.popup.matchCount;
await BrowserTestUtils.waitForCondition(() => {
return URLBar.popup.richlistbox.children.length == matchCount;
});
URLBar.controller.stopSearch();
// There are several setTimeout(fn, 0); calls inside autocomplete.xml
// that we need to wait for. Since those have higher priority than
// idle callbacks, we can be sure they will have run once this
// idle callback is called. The timeout seems to be required in
// automation - presumably because the machines can be pretty busy
// especially if it's GC'ing from previous tests.
await new Promise(resolve => win.requestIdleCallback(resolve, { timeout: 1000 }));
let hiddenPromise = BrowserTestUtils.waitForEvent(URLBar.popup, "popuphidden");
EventUtils.synthesizeKey("VK_ESCAPE", {}, win);
await hiddenPromise;
};
let dropmarkerRect = document.getAnonymousElementByAttribute(gURLBar,
"anonid", "historydropmarker").getBoundingClientRect();
let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
"anonid", "moz-input-box").getBoundingClientRect();
let expectedRects = {
filter: rects => rects.filter(r => !(
// We put text into the urlbar so expect its textbox to change.
(r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom) ||
// The dropmarker is displayed as active during some of the test.
// dropmarkerRect.left isn't always an integer, hence the - 1 and + 1
(r.x1 >= dropmarkerRect.left - 1 && r.x2 <= dropmarkerRect.right + 1 &&
r.y1 >= dropmarkerRect.top && r.y2 <= dropmarkerRect.bottom)
// XXX For some reason the awesomebar panel isn't in our screenshots,
// but that's where we actually expect many changes.
)),
};
info("First opening");
await withPerfObserver(testFn, {expectedReflows: EXPECTED_REFLOWS_FIRST_OPEN,
frames: expectedRects}, win);
info("Second opening");
await withPerfObserver(testFn, {expectedReflows: EXPECTED_REFLOWS_SECOND_OPEN,
frames: expectedRects}, win);
await BrowserTestUtils.closeWindow(win);
add_task(async function quantumbar() {
await runUrlbarTest(false, false, EXPECTED_REFLOWS_FIRST_OPEN,
EXPECTED_REFLOWS_SECOND_OPEN);
});

View File

@ -0,0 +1,107 @@
"use strict";
// This tests searching in the legacy urlbar implementation (a.k.a. the
// awesomebar).
// There are a _lot_ of reflows in this test, and processing them takes
// time. On slower builds, we need to boost our allowed test time.
requestLongerTimeout(5);
/**
* WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
* is a whitelist that should slowly go away as we improve the performance of
* the front-end. Instead of adding more reflows to the whitelist, you should
* be modifying your code to avoid the reflow.
*
* See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
* for tips on how to do that.
*/
/* These reflows happen only the first time the awesomebar panel opens. */
const EXPECTED_REFLOWS_FIRST_OPEN = [];
if (AppConstants.platform != "macosx" &&
(AppConstants.DEBUG ||
AppConstants.platform == "linux" ||
AppConstants.isPlatformAndVersionAtLeast("win", "10"))) {
EXPECTED_REFLOWS_FIRST_OPEN.push({
stack: [
"__rebuild@chrome://browser/content/search/search-one-offs.js",
/* This is limited to a one-line stack, because the next item is an async
function and as such not supported on all trees, according to bug 1501761.
"async*set popup@chrome://browser/content/search/search-one-offs.js",
"_syncOneOffSearchesEnabled@chrome://browser/content/urlbarBindings.xml",
"toggleOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"@chrome://browser/content/urlbarBindings.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",*/
],
});
}
EXPECTED_REFLOWS_FIRST_OPEN.push(
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_reuseAcItem@chrome://global/content/elements/autocomplete-richlistitem.js",
"_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
"_invalidate@chrome://global/content/bindings/autocomplete.xml",
"invalidate@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 36, // This number should only ever go down - never up.
},
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 6, // This number should only ever go down - never up.
},
// Bug 1359989
{
stack: [
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
}
);
/* These reflows happen everytime the awesomebar panel opens. */
const EXPECTED_REFLOWS_SECOND_OPEN = [
{
stack: [
"_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
"_reuseAcItem@chrome://global/content/elements/autocomplete-richlistitem.js",
"_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
"_invalidate@chrome://global/content/bindings/autocomplete.xml",
"invalidate@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 24, // This number should only ever go down - never up.
},
// Bug 1359989
{
stack: [
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
},
];
add_task(async function awesomebar() {
await runUrlbarTest(true, false, EXPECTED_REFLOWS_FIRST_OPEN,
EXPECTED_REFLOWS_SECOND_OPEN);
});

View File

@ -1,10 +1,10 @@
"use strict";
ChromeUtils.defineModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
ChromeUtils.defineModuleGetter(this, "PlacesTestUtils",
"resource://testing-common/PlacesTestUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
PlacesTestUtils: "resource://testing-common/PlacesTestUtils.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.jsm",
});
/**
* This function can be called if the test needs to trigger frame dirtying
@ -639,3 +639,121 @@ async function withPerfObserver(testFn, exceptions = {}, win = window) {
let frames = await promiseFrames;
reportUnexpectedFlicker(frames, exceptions.frames);
}
/**
* This test ensures that there are no unexpected
* uninterruptible reflows when typing into the URL bar
* with the default values in Places.
*
* @param {bool} useAwesomebar
* Pass true if the legacy awesomebar is enabled. Pass false if the
* quantumbar is enabled.
* @param {bool} keyed
* Pass true to synthesize typing the search string one key at a time.
* @param {array} expectedReflowsFirstOpen
* The array of expected reflow stacks when the panel is first opened.
* @param {array} [expectedReflowsSecondOpen]
* The array of expected reflow stacks when the panel is subsequently
* opened, if you're testing opening the panel twice.
*/
async function runUrlbarTest(useAwesomebar,
keyed,
expectedReflowsFirstOpen,
expectedReflowsSecondOpen = null) {
const SEARCH_TERM = keyed ? "" : "urlbar-reflows-" + Date.now();
await addDummyHistoryEntries(SEARCH_TERM);
let win = await prepareSettledWindow();
let URLBar = win.gURLBar;
URLBar.focus();
URLBar.value = SEARCH_TERM;
let testFn = async function() {
if (useAwesomebar) {
let popup = URLBar.popup;
let oldInvalidate = popup.invalidate.bind(popup);
let oldResultsAdded = popup.onResultsAdded.bind(popup);
let oldSetTimeout = win.setTimeout;
// We need to invalidate the frame tree outside of the normal
// mechanism since invalidations and result additions to the
// URL bar occur without firing JS events (which is how we
// normally know to dirty the frame tree).
popup.invalidate = (reason) => {
dirtyFrame(win);
oldInvalidate(reason);
};
popup.onResultsAdded = () => {
dirtyFrame(win);
oldResultsAdded();
};
win.setTimeout = (fn, ms) => {
return oldSetTimeout(() => {
dirtyFrame(win);
fn();
}, ms);
};
}
let waitExtra = async () => {
// There are several setTimeout(fn, 0); calls inside autocomplete.xml
// that we need to wait for. Since those have higher priority than
// idle callbacks, we can be sure they will have run once this
// idle callback is called. The timeout seems to be required in
// automation - presumably because the machines can be pretty busy
// especially if it's GC'ing from previous tests.
await new Promise(resolve => win.requestIdleCallback(resolve, { timeout: 1000 }));
};
if (keyed) {
// Only keying in 6 characters because the number of reflows triggered
// is so high that we risk timing out the test if we key in any more.
let searchTerm = "ows-10";
for (let i = 0; i < searchTerm.length; ++i) {
let char = searchTerm[i];
EventUtils.synthesizeKey(char, {}, win);
await UrlbarTestUtils.promiseSearchComplete(win);
await waitExtra();
}
} else {
await UrlbarTestUtils.promiseAutocompleteResultPopup(win, URLBar.value,
SimpleTest.waitForFocus);
await waitExtra();
}
await UrlbarTestUtils.promisePopupClose(win);
};
let dropmarkerRect = win.document.getAnonymousElementByAttribute(URLBar.textbox,
"anonid", "historydropmarker").getBoundingClientRect();
let textBoxRect = win.document.getAnonymousElementByAttribute(URLBar.textbox,
"anonid", "moz-input-box").getBoundingClientRect();
let expectedRects = {
filter: rects => rects.filter(r => !(
// We put text into the urlbar so expect its textbox to change.
(r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom) ||
// The dropmarker is displayed as active during some of the test.
// dropmarkerRect.left isn't always an integer, hence the - 1 and + 1
(r.x1 >= dropmarkerRect.left - 1 && r.x2 <= dropmarkerRect.right + 1 &&
r.y1 >= dropmarkerRect.top && r.y2 <= dropmarkerRect.bottom)
// XXX For some reason the awesomebar panel isn't in our screenshots,
// but that's where we actually expect many changes.
)),
};
info(`First opening, useAwesomebar=${useAwesomebar}`);
await withPerfObserver(testFn, {expectedReflows: expectedReflowsFirstOpen,
frames: expectedRects}, win);
if (expectedReflowsSecondOpen) {
info(`Second opening, useAwesomebar=${useAwesomebar}`);
await withPerfObserver(testFn, {expectedReflows: expectedReflowsSecondOpen,
frames: expectedRects}, win);
}
await BrowserTestUtils.closeWindow(win);
}

View File

@ -0,0 +1,8 @@
[DEFAULT]
prefs =
browser.urlbar.quantumbar=false
[../browser_urlbar_keyed_search_legacy.js]
skip-if = (os == 'linux') || (os == 'win' && debug) || (os == 'win' && bits == 32) # Disabled on Linux and Windows debug due to perma failures. Bug 1392320. Disabled on Win32 because of intermittent OOM failures (bug 1448241).
[../browser_urlbar_search_legacy.js]
skip-if = (debug || ccov) && (os == 'linux' || os == 'win') || (os == 'win' && bits == 32) # Disabled on Linux and Windows debug and ccov due to intermittent timeouts. Bug 1414126, bug 1426611. Disabled on Win32 because of intermittent OOM failures (bug 1448241)

View File

@ -4,6 +4,9 @@
const AUTOPLAY_PAGE = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com") + "browser_autoplay_blocked.html";
const AUTOPLAY_PREF = "media.autoplay.default";
const AUTOPLAY_PERM = "autoplay-media";
function openIdentityPopup() {
let promise = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
gIdentityHandler._identityBox.click();
@ -21,8 +24,28 @@ function autoplayBlockedIcon() {
".blocked-permission-icon.autoplay-media-icon");
}
function sleep(ms) {
/* eslint-disable mozilla/no-arbitrary-setTimeout */
return new Promise(resolve => setTimeout(resolve, ms));
}
async function blockedIconShown(browser) {
// May need to wait for `GloballyAutoplayBlocked` event before showing icon.
if (BrowserTestUtils.is_hidden(autoplayBlockedIcon())) {
await BrowserTestUtils.waitForEvent(browser, "GloballyAutoplayBlocked");
}
ok(!BrowserTestUtils.is_hidden(autoplayBlockedIcon()), "Blocked icon is shown");
}
add_task(async function setup() {
registerCleanupFunction(() => {
Services.perms.removeAll();
Services.prefs.clearUserPref(AUTOPLAY_PREF);
});
});
add_task(async function testMainViewVisible() {
Services.prefs.setIntPref("media.autoplay.default", Ci.nsIAutoplay.ALLOWED);
Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.ALLOWED);
await BrowserTestUtils.withNewTab(AUTOPLAY_PAGE, async function() {
let permissionsList = document.getElementById("identity-popup-permission-list");
@ -35,21 +58,17 @@ add_task(async function testMainViewVisible() {
await closeIdentityPopup();
});
Services.prefs.setIntPref("media.autoplay.default", Ci.nsIAutoplay.BLOCKED);
Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.BLOCKED);
await BrowserTestUtils.withNewTab(AUTOPLAY_PAGE, async function(browser) {
let permissionsList = document.getElementById("identity-popup-permission-list");
let emptyLabel = permissionsList.nextElementSibling.nextElementSibling;
if (BrowserTestUtils.is_hidden(autoplayBlockedIcon())) {
// The block icon would be showed after tab receives `GloballyAutoplayBlocked` event.
await BrowserTestUtils.waitForEvent(browser, "GloballyAutoplayBlocked");
}
ok(!BrowserTestUtils.is_hidden(autoplayBlockedIcon()), "Blocked icon is shown");
await blockedIconShown(browser);
await openIdentityPopup();
ok(BrowserTestUtils.is_hidden(emptyLabel), "List of permissions is not empty");
let labelText = SitePermissions.getPermissionLabel("autoplay-media");
let labelText = SitePermissions.getPermissionLabel(AUTOPLAY_PERM);
let labels = permissionsList.querySelectorAll(".identity-popup-permission-label");
is(labels.length, 1, "One permission visible in main view");
is(labels[0].textContent, labelText, "Correct value");
@ -70,10 +89,62 @@ add_task(async function testMainViewVisible() {
await closeIdentityPopup();
let uri = Services.io.newURI(AUTOPLAY_PAGE);
let state = SitePermissions.get(uri, "autoplay-media").state;
let state = SitePermissions.get(uri, AUTOPLAY_PERM).state;
Assert.equal(state, SitePermissions.ALLOW);
});
Services.perms.removeAll();
Services.prefs.clearUserPref("media.autoplay.default");
});
add_task(async function testGloballyBlockedOnNewWindow() {
Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.BLOCKED);
let uri = Services.io.newURI(AUTOPLAY_PAGE);
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri.spec);
await blockedIconShown(tab.linkedBrowser);
Assert.deepEqual(SitePermissions.get(uri, AUTOPLAY_PERM, tab.linkedBrowser), {
state: SitePermissions.BLOCK,
scope: SitePermissions.SCOPE_PERSISTENT,
});
let promiseWin = BrowserTestUtils.waitForNewWindow();
gBrowser.replaceTabWithWindow(tab);
let win = await promiseWin;
tab = win.gBrowser.selectedTab;
Assert.deepEqual(SitePermissions.get(uri, AUTOPLAY_PERM, tab.linkedBrowser), {
state: SitePermissions.BLOCK,
scope: SitePermissions.SCOPE_PERSISTENT,
});
SitePermissions.remove(uri, AUTOPLAY_PERM, tab.linkedBrowser);
await BrowserTestUtils.closeWindow(win);
});
add_task(async function testBFCache() {
Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.BLOCKED);
await BrowserTestUtils.withNewTab("about:home", async function(browser) {
await BrowserTestUtils.loadURI(browser, AUTOPLAY_PAGE);
await blockedIconShown(browser);
Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.ALLOWED);
gBrowser.goBack();
await TestUtils.waitForCondition(() => {
return BrowserTestUtils.is_hidden(autoplayBlockedIcon());
});
gBrowser.goForward();
// Sleep here to prevent false positives, the icon gets shown with an
// async `GloballyAutoplayBlocked` event. The sleep gives it a little
// time for it to show otherwise there is a chance it passes before it
// would have shown.
await sleep(100);
ok(BrowserTestUtils.is_hidden(autoplayBlockedIcon()), "Blocked icon is hidden");
});
Services.perms.removeAll();
});

View File

@ -8,12 +8,11 @@ var {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
ExtensionSettingsStore: "resource://gre/modules/ExtensionSettingsStore.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
ShellService: "resource:///modules/ShellService.jsm",
});
@ -31,9 +30,10 @@ Object.defineProperty(this, "BROWSER_NEW_TAB_URL", {
}
// If the extension does not have private browsing permission,
// use about:privatebrowsing.
if (aboutNewTabService.newTabURL.startsWith("moz-extension")) {
let url = new URL(aboutNewTabService.newTabURL);
if (!WebExtensionPolicy.getByHostname(url.hostname).privateBrowsingAllowed) {
let extensionInfo = ExtensionSettingsStore.getSetting("url_overrides", "newTabURL");
if (extensionInfo) {
let policy = WebExtensionPolicy.getByID(extensionInfo.id);
if (!policy || !policy.privateBrowsingAllowed) {
return "about:privatebrowsing";
}
}

View File

@ -36,6 +36,7 @@ BROWSER_CHROME_MANIFESTS += [
'content/test/pageinfo/browser.ini',
'content/test/performance/browser.ini',
'content/test/performance/hidpi/browser.ini',
'content/test/performance/legacyurlbar/browser.ini',
'content/test/performance/lowdpi/browser.ini',
'content/test/permissions/browser.ini',
'content/test/plugins/browser.ini',

View File

@ -209,7 +209,7 @@ function openBrowserWindow(cmdLine, triggeringPrincipal, urlOrUrlList, postData
let args;
if (!urlOrUrlList) {
// Just pass in the defaultArgs directly. We'll use system principal on the other end.
args = [gBrowserContentHandler.getDefaultArgs(forcePrivate)];
args = [gBrowserContentHandler.defaultArgs];
} else {
let pService = Cc["@mozilla.org/toolkit/profile-service;1"].
getService(Ci.nsIToolkitProfileService);
@ -520,7 +520,7 @@ nsBrowserContentHandler.prototype = {
/* nsIBrowserHandler */
getDefaultArgs(forcePrivate = false) {
get defaultArgs() {
var prefb = Services.prefs;
if (!gFirstWindow) {
@ -605,7 +605,7 @@ nsBrowserContentHandler.prototype = {
try {
var choice = prefb.getIntPref("browser.startup.page");
if (choice == 1 || choice == 3)
startPage = forcePrivate ? HomePage.getPrivate() : HomePage.get();
startPage = HomePage.get();
} catch (e) {
Cu.reportError(e);
}
@ -623,10 +623,6 @@ nsBrowserContentHandler.prototype = {
return overridePage || startPage || "about:blank";
},
get defaultArgs() {
return this.getDefaultArgs(PrivateBrowsingUtils.permanentPrivateBrowsing);
},
mFeatures: null,
getFeatures: function bch_features(cmdLine) {

View File

@ -11,18 +11,18 @@ add_task(async function() {
ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
let oldChildCount = CustomizableUI.getCustomizationTarget(navbar).childElementCount;
window.resizeTo(kForceOverflowWidthPx, window.outerHeight);
await waitForCondition(() => navbar.hasAttribute("overflowing"));
await TestUtils.waitForCondition(() => navbar.hasAttribute("overflowing"));
ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
ok(CustomizableUI.getCustomizationTarget(navbar).childElementCount < oldChildCount, "Should have fewer children.");
let newWindow = await openAndLoadWindow();
let otherNavBar = newWindow.document.getElementById(CustomizableUI.AREA_NAVBAR);
await waitForCondition(() => otherNavBar.hasAttribute("overflowing"));
await TestUtils.waitForCondition(() => otherNavBar.hasAttribute("overflowing"));
ok(otherNavBar.hasAttribute("overflowing"), "Other window should have an overflowing toolbar.");
await promiseWindowClosed(newWindow);
window.resizeTo(originalWindowWidth, window.outerHeight);
await waitForCondition(() => !navbar.hasAttribute("overflowing"));
await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing"));
ok(!navbar.hasAttribute("overflowing"), "Should no longer have an overflowing toolbar.");
});

View File

@ -191,13 +191,8 @@ this.windows = class extends ExtensionAPI {
args.appendElement(mkstr(createData.url));
}
} else {
let url;
if (createData.incognito) {
url = PrivateBrowsingUtils.permanentPrivateBrowsing ?
HomePage.getPrivate().split("|", 1)[0] : "about:privatebrowsing";
} else {
url = HomePage.get().split("|", 1)[0];
}
let url = createData.incognito && !PrivateBrowsingUtils.permanentPrivateBrowsing ?
"about:privatebrowsing" : HomePage.get().split("|", 1)[0];
args.appendElement(mkstr(url));
if (url.startsWith("about:") &&

View File

@ -471,42 +471,6 @@ add_task(async function test_overriding_home_page_incognito_not_allowed() {
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_overriding_home_page_incognito_not_allowed_bypass() {
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
let extension = ExtensionTestUtils.loadExtension({
manifest: {
name: "extension",
},
background() {
browser.test.sendMessage("url", browser.runtime.getURL("home.html"));
},
files: {"home.html": "<h1>1</h1>"},
useAddonManager: "temporary",
});
await extension.startup();
let url = await extension.awaitMessage("url");
// Verify manually setting the pref to the extension page does not work.
let changed = promisePrefChangeObserved(HOMEPAGE_URL_PREF);
Services.prefs.setStringPref(HOMEPAGE_URL_PREF, url);
await changed;
let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
let win = OpenBrowserWindow({private: true});
await windowOpenedPromise;
win.BrowserHome();
await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
is(win.gURLBar.value, "", "home page not used in private window");
changed = promisePrefChangeObserved(HOMEPAGE_URL_PREF);
Services.prefs.clearUserPref(HOMEPAGE_URL_PREF);
await changed;
await extension.unload();
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_overriding_home_page_incognito_spanning() {
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
@ -546,3 +510,30 @@ add_task(async function test_overriding_home_page_incognito_spanning() {
await extension.unload();
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_overriding_home_page_incognito_external() {
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
let extension = ExtensionTestUtils.loadExtension({
manifest: {
chrome_settings_overrides: {"homepage": "https://example.com/home.html"},
name: "extension",
},
useAddonManager: "temporary",
});
await extension.startup();
// Verify a private window does not open the extension page.
let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
let win = OpenBrowserWindow({private: true});
await windowOpenedPromise;
win.BrowserHome();
await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
is(win.gURLBar.value, "", "home page not used in private window");
is(gBrowser.selectedBrowser.currentURI.spec, "about:home", "home page not used in private window");
await extension.unload();
await BrowserTestUtils.closeWindow(win);
});

View File

@ -604,58 +604,6 @@ add_task(async function test_overriding_newtab_incognito_not_allowed() {
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_overriding_newtab_incognito_not_allowed_bypass() {
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
let extension = ExtensionTestUtils.loadExtension({
manifest: {
name: "extension",
applications: {
gecko: {id: "@not-allowed-newtab"},
},
},
background() {
browser.test.sendMessage("url", browser.runtime.getURL("newtab.html"));
},
files: {
"newtab.html": `
<!DOCTYPE html>
<head>
<meta charset="utf-8"/></head>
<html>
<body>
</body>
</html>
`,
},
useAddonManager: "permanent",
});
await extension.startup();
let url = await extension.awaitMessage("url");
// Verify setting the pref directly doesn't bypass permissions.
let origUrl = aboutNewTabService.newTabURL;
aboutNewTabService.newTabURL = url;
// Verify a private window does not open the extension page. We would
// get an extra notification that we don't listen for if it gets loaded.
let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
let win = OpenBrowserWindow({private: true});
await windowOpenedPromise;
let newTabOpened = waitForNewTab();
win.BrowserOpenTab();
await newTabOpened;
is(win.gURLBar.value, "", "directly set newtab not used in private window");
aboutNewTabService.newTabURL = origUrl;
await extension.unload();
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_overriding_newtab_incognito_spanning() {
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});

View File

@ -4,7 +4,7 @@
restart-required-title = Restart Required
restart-required-header = Sorry. We just need to do one small thing to keep going.
restart-required-intro = We have just installed an update in the background. Click Restart { -brand-short-name } to finish
restart-required-intro-brand = { -brand-short-name } has just been updated in the background. Click Restart { -brand-short-name } to finish
applying it.
restart-required-description = We will restore all your pages, windows and tabs afterwards, so you can be on your way quickly.

View File

@ -12,6 +12,8 @@ var EXPORTED_SYMBOLS = ["HomePage"];
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
"resource://gre/modules/ExtensionSettingsStore.jsm");
const kPrefName = "browser.startup.homepage";
@ -48,8 +50,17 @@ let HomePage = {
get(aWindow) {
if (PrivateBrowsingUtils.permanentPrivateBrowsing ||
(aWindow && PrivateBrowsingUtils.isWindowPrivate(aWindow))) {
return this.getPrivate();
// If an extension controls the setting and does not have private
// browsing permission, use the default setting.
let extensionInfo = ExtensionSettingsStore.getSetting("prefs", "homepage_override");
if (extensionInfo) {
let policy = WebExtensionPolicy.getByID(extensionInfo.id);
if (!policy || !policy.privateBrowsingAllowed) {
return this.getDefault();
}
}
}
return getHomepagePref();
},
@ -57,24 +68,6 @@ let HomePage = {
return getHomepagePref(true);
},
getPrivate() {
let homePages = getHomepagePref();
if (!homePages.includes("moz-extension")) {
return homePages;
}
// Verify private access and build a new list.
let privateHomePages = homePages.split("|").filter(page => {
let url = new URL(page);
if (url.protocol !== "moz-extension:") {
return true;
}
let policy = WebExtensionPolicy.getByHostname(url.hostname);
return policy && policy.privateBrowsingAllowed;
});
// Extensions may not be ready on startup, fallback to defaults.
return privateHomePages.join("|") || this.getDefault();
},
get overridden() {
return Services.prefs.prefHasUserValue(kPrefName);
},

View File

@ -157,7 +157,7 @@ const GloballyBlockedPermissions = {
Ci.nsISupportsWeakReference]),
onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
if (aWebProgress.isTopLevel) {
GloballyBlockedPermissions.remove(browser, id);
GloballyBlockedPermissions.remove(browser, id, prePath);
browser.removeProgressListener(this);
}
},
@ -165,9 +165,11 @@ const GloballyBlockedPermissions = {
},
// Removes a permission with the specified id for the specified browser.
remove(browser, id) {
remove(browser, id, prePath = null) {
let entry = this._stateByBrowser.get(browser);
let prePath = browser.currentURI.prePath;
if (!prePath) {
prePath = browser.currentURI.prePath;
}
if (entry && entry[prePath]) {
delete entry[prePath][id];
}
@ -192,6 +194,15 @@ const GloballyBlockedPermissions = {
}
return permissions;
},
// Copies the globally blocked permission state of one browser
// into a new entry for the other browser.
copy(browser, newBrowser) {
let entry = this._stateByBrowser.get(browser);
if (entry) {
this._stateByBrowser.set(newBrowser, entry);
}
},
};
/**
@ -594,6 +605,7 @@ var SitePermissions = {
*/
copyTemporaryPermissions(browser, newBrowser) {
TemporaryPermissions.copy(browser, newBrowser);
GloballyBlockedPermissions.copy(browser, newBrowser);
},
/**

View File

@ -84,11 +84,9 @@ add_task(async function test_context_menu() {
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.contextmenu", 1);
// Also check events.
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
TelemetryTestUtils.assertEvents(events, [
["navigation", "search", "contextmenu", null, {engine: "other-MozSearch"}],
]);
TelemetryTestUtils.assertEvents(
[{object: "contextmenu", value: null, extra: {engine: "other-MozSearch"}}],
{category: "navigation", method: "search"});
contextMenu.hidePopup();
BrowserTestUtils.removeTab(gBrowser.selectedTab);
@ -122,11 +120,9 @@ add_task(async function test_about_newtab() {
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.newtab", 1);
// Also check events.
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
TelemetryTestUtils.assertEvents(events, [
["navigation", "search", "about_newtab", "enter", {engine: "other-MozSearch"}],
]);
TelemetryTestUtils.assertEvents(
[{object: "about_newtab", value: "enter", extra: {engine: "other-MozSearch"}}],
{category: "navigation", method: "search"});
BrowserTestUtils.removeTab(tab);
});

View File

@ -78,11 +78,9 @@ add_task(async function test_abouthome_activitystream_simpleQuery() {
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.abouthome", 1);
// Also check events.
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
TelemetryTestUtils.assertEvents(events, [
["navigation", "search", "about_home", "enter", {engine: "other-MozSearch"}],
]);
TelemetryTestUtils.assertEvents(
[{object: "about_home", value: "enter", extra: {engine: "other-MozSearch"}}],
{category: "navigation", method: "search"});
BrowserTestUtils.removeTab(tab);
});

View File

@ -120,11 +120,9 @@ add_task(async function test_plainQuery() {
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.searchbar", 1);
// Also check events.
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
TelemetryTestUtils.assertEvents(events, [
["navigation", "search", "searchbar", "enter", {engine: "other-MozSearch"}],
]);
TelemetryTestUtils.assertEvents(
[{object: "searchbar", value: "enter", extra: {engine: "other-MozSearch"}}],
{category: "navigation", method: "search"});
// Check the histograms as well.
let resultMethods = resultMethodHist.snapshot();
@ -167,11 +165,9 @@ add_task(async function test_oneOff_enter() {
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch2.searchbar", 1);
// Also check events.
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
TelemetryTestUtils.assertEvents(events, [
["navigation", "search", "searchbar", "oneoff", {engine: "other-MozSearch2"}],
]);
TelemetryTestUtils.assertEvents(
[{object: "searchbar", value: "oneoff", extra: {engine: "other-MozSearch2"}}],
{category: "navigation", method: "search"});
// Check the histograms as well.
let resultMethods = resultMethodHist.snapshot();
@ -283,11 +279,9 @@ add_task(async function test_suggestion_click() {
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, searchEngineId + ".searchbar", 1);
// Also check events.
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
TelemetryTestUtils.assertEvents(events, [
["navigation", "search", "searchbar", "suggestion", {engine: searchEngineId}],
]);
TelemetryTestUtils.assertEvents(
[{object: "searchbar", value: "suggestion", extra: {engine: searchEngineId}}],
{category: "navigation", method: "search"});
// Check the histograms as well.
let resultMethods = resultMethodHist.snapshot();

View File

@ -154,9 +154,9 @@ add_task(async function test_simpleQuery() {
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
// Also check events.
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
TelemetryTestUtils.assertEvents(events, [["navigation", "search", "urlbar", "enter", {engine: "other-MozSearch"}]]);
TelemetryTestUtils.assertEvents(
[["navigation", "search", "urlbar", "enter", {engine: "other-MozSearch"}]],
{category: "navigation", method: "search"});
// Check the histograms as well.
TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
@ -202,9 +202,9 @@ add_task(async function test_searchAlias() {
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
// Also check events.
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
TelemetryTestUtils.assertEvents(events, [["navigation", "search", "urlbar", "alias", {engine: "other-MozSearch"}]]);
TelemetryTestUtils.assertEvents(
[["navigation", "search", "urlbar", "alias", {engine: "other-MozSearch"}]],
{category: "navigation", method: "search"});
// Check the histograms as well.
TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
@ -281,9 +281,9 @@ add_task(async function test_oneOff_enter() {
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
// Also check events.
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
TelemetryTestUtils.assertEvents(events, [["navigation", "search", "urlbar", "oneoff", {engine: "other-MozSearch"}]]);
TelemetryTestUtils.assertEvents(
[["navigation", "search", "urlbar", "oneoff", {engine: "other-MozSearch"}]],
{category: "navigation", method: "search"});
// Check the histograms as well.
TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
@ -382,9 +382,9 @@ add_task(async function test_suggestion_click() {
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, searchEngineId + ".urlbar", 1);
// Also check events.
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
TelemetryTestUtils.assertEvents(events, [["navigation", "search", "urlbar", "suggestion", {engine: searchEngineId}]]);
TelemetryTestUtils.assertEvents(
[["navigation", "search", "urlbar", "suggestion", {engine: searchEngineId}]],
{category: "navigation", method: "search"});
// Check the histograms as well.
TelemetryTestUtils.assertHistogram(resultIndexHist, 3, 1);

View File

@ -247,8 +247,9 @@ static bool ReadPrincipalInfo(JSStructuredCloneReader* aReader, uint32_t aTag,
MOZ_DIAGNOSTIC_ASSERT(!originNoSuffix.IsEmpty());
aInfo =
ContentPrincipalInfo(attrs, originNoSuffix, spec, std::move(policies));
// XXX: Do we care about mDomain for structured clone?
aInfo = ContentPrincipalInfo(attrs, originNoSuffix, spec, Nothing(),
std::move(policies));
} else {
#ifdef FUZZING
return false;

View File

@ -4,31 +4,29 @@
"use strict";
const { Toolbox } = require("devtools/client/framework/toolbox");
const { TelemetryTestUtils } = ChromeUtils.import("resource://testing-common/TelemetryTestUtils.jsm");
const URL = "data:text/html;charset=utf8,browser_toolbox_telemetry_close.js";
const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
const { RIGHT, BOTTOM } = Toolbox.HostType;
const DATA = [
{
timestamp: null,
category: "devtools.main",
method: "close",
object: "tools",
value: null,
extra: {
host: "right",
width: "1440",
width: w => w > 0,
},
},
{
timestamp: null,
category: "devtools.main",
method: "close",
object: "tools",
value: null,
extra: {
host: "bottom",
width: "1440",
width: w => w > 0,
},
},
];
@ -38,8 +36,7 @@ add_task(async function() {
Services.telemetry.clearEvents();
// Ensure no events have been logged
const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
ok(!snapshot.parent, "No events have been logged for the main process");
TelemetryTestUtils.assertNumberOfEvents(0);
await openAndCloseToolbox("webconsole", RIGHT);
await openAndCloseToolbox("webconsole", BOTTOM);
@ -57,25 +54,5 @@ async function openAndCloseToolbox(toolId, host) {
}
function checkResults() {
const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
event[2] === "close" &&
event[3] === "tools" &&
event[4] === null
);
for (const i in DATA) {
const [ timestamp, category, method, object, value, extra ] = events[i];
const expected = DATA[i];
// ignore timestamp
ok(timestamp > 0, "timestamp is greater than 0");
is(category, expected.category, "category is correct");
is(method, expected.method, "method is correct");
is(object, expected.object, "object is correct");
is(value, expected.value, "value is correct");
is(extra.host, expected.extra.host, "host is correct");
ok(extra.width > 0, "width is greater than 0");
}
TelemetryTestUtils.assertEvents(DATA, {category: "devtools.main", method: "close", object: "tools"});
}

View File

@ -16,6 +16,7 @@ const TEST_URI =
<div id="box"></div>`;
add_task(async function() {
await pushPref("devtools.layout.boxmodel.highlightProperty", true);
await addTab("data:text/html," + encodeURIComponent(TEST_URI));
const { inspector, boxmodel } = await openLayoutView();
await selectNode("#box", inspector);

View File

@ -16,6 +16,7 @@ const TEST_URI =
<div id="box"></div>`;
add_task(async function() {
await pushPref("devtools.layout.boxmodel.highlightProperty", true);
await addTab("data:text/html," + encodeURIComponent(TEST_URI));
const { inspector, boxmodel } = await openLayoutView();
const { rulePreviewTooltip } = boxmodel;

View File

@ -28,6 +28,7 @@ class ChangesContextMenu {
// Window object to which the Changes panel belongs to.
this.window = this.document.defaultView;
this._onCopyDeclaration = this.view.copyDeclaration.bind(this.view);
this._onCopyRule = this.view.copyRule.bind(this.view);
this._onCopySelection = this.view.copySelection.bind(this.view);
this._onSelectAll = this._onSelectAll.bind(this);
@ -55,16 +56,24 @@ class ChangesContextMenu {
});
menu.append(menuitemCopy);
const declEl = target.closest(".changes__declaration");
const ruleEl = target.closest("[data-rule-id]");
const ruleId = ruleEl ? ruleEl.dataset.ruleId : null;
if (ruleId) {
if (ruleId || declEl) {
// Copy Rule option
menu.append(new MenuItem({
label: getStr("changes.contextmenu.copyRule"),
click: () => this._onCopyRule(ruleId),
}));
// Copy Declaration option. Visible only if there is a declaration element target.
menu.append(new MenuItem({
label: getStr("changes.contextmenu.copyDeclaration"),
click: () => this._onCopyDeclaration(declEl),
visible: !!declEl,
}));
menu.append(new MenuItem({
type: "separator",
}));

View File

@ -146,6 +146,22 @@ class ChangesView {
clipboardHelper.copyString(text);
}
/**
* Handler for the "Copy Declaration" option from the context menu.
* Builds a CSS declaration string with the property name and value, and copies it
* to the clipboard. The declaration is commented out if it is marked as removed.
*
* @param {DOMElement} element
* Host element of a CSS declaration rendered the Changes panel.
*/
copyDeclaration(element) {
const name = element.querySelector(".changes__declaration-name").textContent;
const value = element.querySelector(".changes__declaration-value").textContent;
const isRemoved = element.classList.contains("diff-remove");
const text = isRemoved ? `/* ${name}: ${value}; */` : `${name}: ${value};`;
clipboardHelper.copyString(text);
}
/**
* Handler for the "Copy Rule" option from the context menu.
* Gets the full content of the target CSS rule (including any changes applied)

View File

@ -28,11 +28,11 @@ class CSSDeclaration extends PureComponent {
render() {
const { className, marker, property, value } = this.props;
return dom.div({ className: `declaration ${className}` },
return dom.div({ className: `changes__declaration ${className}` },
marker,
dom.span({ className: "declaration-name theme-fg-color3"}, property),
dom.span({ className: "changes__declaration-name theme-fg-color3"}, property),
": ",
dom.span({ className: "declaration-value theme-fg-color1"}, value),
dom.span({ className: "changes__declaration-value theme-fg-color1"}, value),
";"
);
}

View File

@ -44,7 +44,7 @@ registerCleanupFunction(() => {
* @return {Array}
*/
function getDeclarations(panelDoc, selector = "", containerNode = null) {
const els = panelDoc.querySelectorAll(`#sidebar-panel-changes .declaration${selector}`);
const els = panelDoc.querySelectorAll(`.changes__declaration${selector}`);
return [...els]
.filter(el => {
@ -52,8 +52,8 @@ function getDeclarations(panelDoc, selector = "", containerNode = null) {
})
.map(el => {
return {
property: el.querySelector(".declaration-name").textContent,
value: el.querySelector(".declaration-value").textContent,
property: el.querySelector(".changes__declaration-name").textContent,
value: el.querySelector(".changes__declaration-value").textContent,
};
});
}

View File

@ -28,7 +28,7 @@ add_task(async function() {
expectedPattern: "color",
visible: {
copyLocation: false,
copyPropertyDeclaration: true,
copyDeclaration: true,
copyPropertyName: true,
copyPropertyValue: false,
copySelector: false,
@ -42,7 +42,7 @@ add_task(async function() {
expectedPattern: "12px",
visible: {
copyLocation: false,
copyPropertyDeclaration: true,
copyDeclaration: true,
copyPropertyName: false,
copyPropertyValue: true,
copySelector: false,
@ -56,7 +56,7 @@ add_task(async function() {
expectedPattern: "#00F !important",
visible: {
copyLocation: false,
copyPropertyDeclaration: true,
copyDeclaration: true,
copyPropertyName: false,
copyPropertyValue: true,
copySelector: false,
@ -66,11 +66,11 @@ add_task(async function() {
{
desc: "Test Copy Property Declaration",
node: ruleEditor.rule.textProps[2].editor.nameSpan,
menuItemLabel: "styleinspector.contextmenu.copyPropertyDeclaration",
menuItemLabel: "styleinspector.contextmenu.copyDeclaration",
expectedPattern: "font-size: 12px;",
visible: {
copyLocation: false,
copyPropertyDeclaration: true,
copyDeclaration: true,
copyPropertyName: true,
copyPropertyValue: false,
copySelector: false,
@ -80,11 +80,11 @@ add_task(async function() {
{
desc: "Test Copy Property Declaration with Priority",
node: ruleEditor.rule.textProps[3].editor.nameSpan,
menuItemLabel: "styleinspector.contextmenu.copyPropertyDeclaration",
menuItemLabel: "styleinspector.contextmenu.copyDeclaration",
expectedPattern: "border-color: #00F !important;",
visible: {
copyLocation: false,
copyPropertyDeclaration: true,
copyDeclaration: true,
copyPropertyName: true,
copyPropertyValue: false,
copySelector: false,
@ -104,7 +104,7 @@ add_task(async function() {
"}",
visible: {
copyLocation: false,
copyPropertyDeclaration: true,
copyDeclaration: true,
copyPropertyName: true,
copyPropertyValue: false,
copySelector: false,
@ -118,7 +118,7 @@ add_task(async function() {
expectedPattern: "html, body, #testid",
visible: {
copyLocation: false,
copyPropertyDeclaration: false,
copyDeclaration: false,
copyPropertyName: false,
copyPropertyValue: false,
copySelector: true,
@ -133,7 +133,7 @@ add_task(async function() {
"inspector/rules/test/doc_copystyles.css",
visible: {
copyLocation: true,
copyPropertyDeclaration: false,
copyDeclaration: false,
copyPropertyName: false,
copyPropertyValue: false,
copySelector: false,
@ -156,7 +156,7 @@ add_task(async function() {
"}",
visible: {
copyLocation: false,
copyPropertyDeclaration: true,
copyDeclaration: true,
copyPropertyName: true,
copyPropertyValue: false,
copySelector: false,
@ -179,7 +179,7 @@ add_task(async function() {
"}",
visible: {
copyLocation: false,
copyPropertyDeclaration: true,
copyDeclaration: true,
copyPropertyName: true,
copyPropertyValue: false,
copySelector: false,
@ -189,11 +189,11 @@ add_task(async function() {
{
desc: "Test Copy Property Declaration with Disabled Property",
node: ruleEditor.rule.textProps[0].editor.nameSpan,
menuItemLabel: "styleinspector.contextmenu.copyPropertyDeclaration",
menuItemLabel: "styleinspector.contextmenu.copyDeclaration",
expectedPattern: "\/\\* color: #F00; \\*\/",
visible: {
copyLocation: false,
copyPropertyDeclaration: true,
copyDeclaration: true,
copyPropertyName: true,
copyPropertyValue: false,
copySelector: false,
@ -220,8 +220,8 @@ async function checkCopyStyle(view, node, menuItemLabel, expectedPattern, visibl
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copy"));
const menuitemCopyLocation = allMenuItems.find(item => item.label ===
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyLocation"));
const menuitemCopyPropertyDeclaration = allMenuItems.find(item => item.label ===
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyDeclaration"));
const menuitemCopyDeclaration = allMenuItems.find(item => item.label ===
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyDeclaration"));
const menuitemCopyPropertyName = allMenuItems.find(item => item.label ===
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyName"));
const menuitemCopyPropertyValue = allMenuItems.find(item => item.label ===
@ -241,10 +241,10 @@ async function checkCopyStyle(view, node, menuItemLabel, expectedPattern, visibl
"Copy Location visible attribute is as expected: " +
visible.copyLocation);
is(menuitemCopyPropertyDeclaration.visible,
visible.copyPropertyDeclaration,
is(menuitemCopyDeclaration.visible,
visible.copyDeclaration,
"Copy Property Declaration visible attribute is as expected: " +
visible.copyPropertyDeclaration);
visible.copyDeclaration);
is(menuitemCopyPropertyName.visible,
visible.copyPropertyName,

View File

@ -58,6 +58,10 @@ const TEST_DATA = [
];
add_task(async function() {
// Bug 1517210: GC heuristics are broken for this test, so that the test ends up
// running out of memory if we don't force to reduce the GC side before/after the test.
Cu.forceShrinkingGC();
requestLongerTimeout(4);
info("Starting the test with the pref set to true before toolbox is opened");
@ -79,6 +83,10 @@ add_task(async function() {
info("Resetting " + PREF_UA_STYLES);
Services.prefs.clearUserPref(PREF_UA_STYLES);
// Bug 1517210: GC heuristics are broken for this test, so that the test ends up
// running out of memory if we don't force to reduce the GC side before/after the test.
Cu.forceShrinkingGC();
});
async function setUserAgentStylesPref(val) {

View File

@ -46,7 +46,7 @@ function StyleInspectorMenu(view, options) {
this._onCopyColor = this._onCopyColor.bind(this);
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
this._onCopyLocation = this._onCopyLocation.bind(this);
this._onCopyPropertyDeclaration = this._onCopyPropertyDeclaration.bind(this);
this._onCopyDeclaration = this._onCopyDeclaration.bind(this);
this._onCopyPropertyName = this._onCopyPropertyName.bind(this);
this._onCopyPropertyValue = this._onCopyPropertyValue.bind(this);
this._onCopyRule = this._onCopyRule.bind(this);
@ -131,11 +131,11 @@ StyleInspectorMenu.prototype = {
},
visible: this._isImageUrl(),
});
const copyPropDeclarationLabel = "styleinspector.contextmenu.copyPropertyDeclaration";
const menuitemCopyPropertyDeclaration = new MenuItem({
label: STYLE_INSPECTOR_L10N.getStr(copyPropDeclarationLabel),
const copyDeclarationLabel = "styleinspector.contextmenu.copyDeclaration";
const menuitemCopyDeclaration = new MenuItem({
label: STYLE_INSPECTOR_L10N.getStr(copyDeclarationLabel),
click: () => {
this._onCopyPropertyDeclaration();
this._onCopyDeclaration();
},
visible: false,
});
@ -165,11 +165,11 @@ StyleInspectorMenu.prototype = {
if (this.isRuleView && this._clickedNodeInfo) {
switch (this._clickedNodeInfo.type) {
case VIEW_NODE_PROPERTY_TYPE :
menuitemCopyPropertyDeclaration.visible = true;
menuitemCopyDeclaration.visible = true;
menuitemCopyPropertyName.visible = true;
break;
case VIEW_NODE_VALUE_TYPE :
menuitemCopyPropertyDeclaration.visible = true;
menuitemCopyDeclaration.visible = true;
menuitemCopyPropertyValue.visible = true;
break;
case VIEW_NODE_SELECTOR_TYPE :
@ -187,7 +187,7 @@ StyleInspectorMenu.prototype = {
menu.append(menuitemCopyColor);
menu.append(menuitemCopyUrl);
menu.append(menuitemCopyImageDataUrl);
menu.append(menuitemCopyPropertyDeclaration);
menu.append(menuitemCopyDeclaration);
menu.append(menuitemCopyPropertyName);
menu.append(menuitemCopyPropertyValue);
menu.append(menuitemCopySelector);
@ -409,9 +409,9 @@ StyleInspectorMenu.prototype = {
},
/**
* Copy the rule property declaration of the current clicked node.
* Copy the CSS declaration of the current clicked node.
*/
_onCopyPropertyDeclaration: function() {
_onCopyDeclaration: function() {
if (!this._clickedNodeInfo) {
return;
}

View File

@ -43,6 +43,10 @@ changes.contextmenu.copyAllChanges=Copy All Changes
# Changes" button
changes.contextmenu.copyAllChangesDescription=Copy a list of all CSS changes to clipboard.
# LOCALIZATION NOTE (changes.contextmenu.copyDeclaration): Label for "Copy Declaration"
# option in Changes panel context menu which copies the target CSS declaration.
changes.contextmenu.copyDeclaration=Copy Declaration
# LOCALIZATION NOTE (changes.contextmenu.copyRule): Label for "Copy Rule" option in
# Changes panel context menu which copies the complete contents of a CSS rule.
changes.contextmenu.copyRule=Copy Rule

View File

@ -157,7 +157,7 @@
display: block;
}
#sidebar-panel-changes .declaration-name {
.changes__declaration-name {
margin-left: 10px;
}

View File

@ -338,31 +338,29 @@ This is best shown via an example:
"use strict";
const { Toolbox } = require("devtools/client/framework/toolbox");
const { TelemetryTestUtils } = ChromeUtils.import("resource://testing-common/TelemetryTestUtils.jsm");
const URL = "data:text/html;charset=utf8,browser_toolbox_telemetry_close.js";
const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
const { SIDE, BOTTOM } = Toolbox.HostType;
const TELEMETRY_DATA = [
const { RIGHT, BOTTOM } = Toolbox.HostType;
const DATA = [
{
timestamp: null,
category: "devtools.main",
method: "close",
object: "tools",
value: null,
extra: {
host: "right",
width: "1440"
width: w => w > 0,
}
},
{
timestamp: null,
category: "devtools.main",
method: "close",
object: "tools",
value: null,
extra: {
host: "bottom",
width: "1440"
width: w => w > 0,
}
}
];
@ -372,8 +370,7 @@ add_task(async function() {
Services.telemetry.clearEvents();
// Ensure no events have been logged
const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
ok(!snapshot.parent, "No events have been logged for the main process");
TelemetryTestUtils.assertNumberOfEvents(0);
await openAndCloseToolbox("webconsole", SIDE);
await openAndCloseToolbox("webconsole", BOTTOM);
@ -391,27 +388,7 @@ async function openAndCloseToolbox(toolId, host) {
}
function checkResults() {
const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
event[2] === "close" &&
event[3] === "tools" &&
event[4] === null
);
for (const i in TELEMETRY_DATA) {
const [ timestamp, category, method, object, value, extra ] = events[i];
const expected = TELEMETRY_DATA[i];
// ignore timestamp
ok(timestamp > 0, "timestamp is greater than 0");
is(category, expected.category, "category is correct");
is(method, expected.method, "method is correct");
is(object, expected.object, "object is correct");
is(value, expected.value, "value is correct");
is(extra.host, expected.extra.host, "host is correct");
ok(extra.width > 0, "width is greater than 0");
}
TelemetryTestUtils.assertEvents(DATA, {category: "devtools.main", method: "close", object: "tools"});
}
```

View File

@ -102,9 +102,6 @@ function Sandbox(options) {
sandboxPrototype: "prototype" in options ? options.prototype : {},
invisibleToDebugger: "invisibleToDebugger" in options ?
options.invisibleToDebugger : false,
// For now create the sandbox in a new compartment. This is temporary until
// bug 1515290 fixes some devtools tests to not rely on this.
freshCompartment: true,
};
const sandbox = Cu.Sandbox(systemPrincipal, options);

View File

@ -206,9 +206,9 @@ styleinspector.contextmenu.copy.accessKey=C
# rule view context menu for copying the source location.
styleinspector.contextmenu.copyLocation=Copy Location
# LOCALIZATION NOTE (styleinspector.contextmenu.copyPropertyDeclaration): Text
# displayed in the rule view context menu for copying the property declaration.
styleinspector.contextmenu.copyPropertyDeclaration=Copy Property Declaration
# LOCALIZATION NOTE (styleinspector.contextmenu.copyDeclaration): Text
# displayed in the rule view context menu for copying the CSS declaration.
styleinspector.contextmenu.copyDeclaration=Copy Declaration
# LOCALIZATION NOTE (styleinspector.contextmenu.copyPropertyName): Text displayed in
# the rule view context menu for copying the property name.

View File

@ -28,6 +28,7 @@
#include "nsContentUtils.h"
#include "nsScriptError.h"
#include "nsThreadUtils.h"
#include "xpcprivate.h"
namespace mozilla {
namespace dom {
@ -547,9 +548,43 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(BrowsingContext)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(BrowsingContext, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(BrowsingContext, Release)
class RemoteLocationProxy
: public RemoteObjectProxy<BrowsingContext::LocationProxy,
Location_Binding::sCrossOriginAttributes,
Location_Binding::sCrossOriginMethods> {
public:
typedef RemoteObjectProxy Base;
constexpr RemoteLocationProxy()
: RemoteObjectProxy(prototypes::id::Location) {}
void NoteChildren(JSObject* aProxy,
nsCycleCollectionTraversalCallback& aCb) const override {
auto location =
static_cast<BrowsingContext::LocationProxy*>(GetNative(aProxy));
CycleCollectionNoteChild(aCb, location->GetBrowsingContext(),
"js::GetObjectPrivate(obj)->GetBrowsingContext()");
}
};
static const RemoteLocationProxy sSingleton;
// Give RemoteLocationProxy 2 reserved slots, like the other wrappers,
// so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
// malloc.
template <>
const js::Class RemoteLocationProxy::Base::sClass =
PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
void BrowsingContext::Location(JSContext* aCx,
JS::MutableHandle<JSObject*> aLocation,
OOMReporter& aError) {}
ErrorResult& aError) {
aError.MightThrowJSException();
sSingleton.GetProxyObject(aCx, &mLocation, aLocation);
if (!aLocation) {
aError.StealExceptionFromJSContext(aCx);
}
}
void BrowsingContext::Close(CallerType aCallerType, ErrorResult& aError) {
// FIXME We need to set mClosed, but only once we're sending the
@ -673,6 +708,28 @@ void BrowsingContext::Transaction::Commit(BrowsingContext* aBrowsingContext) {
Apply(aBrowsingContext);
}
void BrowsingContext::LocationProxy::SetHref(const nsAString& aHref,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) {
nsPIDOMWindowOuter* win = GetBrowsingContext()->GetDOMWindow();
if (!win || !win->GetLocation()) {
aError.Throw(NS_ERROR_FAILURE);
return;
}
win->GetLocation()->SetHref(aHref, aSubjectPrincipal, aError);
}
void BrowsingContext::LocationProxy::Replace(const nsAString& aUrl,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) {
nsPIDOMWindowOuter* win = GetBrowsingContext()->GetDOMWindow();
if (!win || !win->GetLocation()) {
aError.Throw(NS_ERROR_FAILURE);
return;
}
win->GetLocation()->Replace(aUrl, aSubjectPrincipal, aError);
}
} // namespace dom
namespace ipc {

View File

@ -20,6 +20,7 @@
#include "nsWrapperCache.h"
class nsGlobalWindowOuter;
class nsIPrincipal;
class nsOuterWindowProxy;
class PickleIterator;
@ -31,7 +32,6 @@ namespace mozilla {
class ErrorResult;
class LogModule;
class OOMReporter;
namespace ipc {
class IProtocol;
@ -267,7 +267,7 @@ class BrowsingContext : public nsWrapperCache,
BrowsingContext* Window() { return Self(); }
BrowsingContext* Self() { return this; }
void Location(JSContext* aCx, JS::MutableHandle<JSObject*> aLocation,
OOMReporter& aError);
ErrorResult& aError);
void Close(CallerType aCallerType, ErrorResult& aError);
bool GetClosed(ErrorResult&) { return mClosed; }
void Focus(ErrorResult& aError);
@ -329,6 +329,34 @@ class BrowsingContext : public nsWrapperCache,
BrowsingContext* TopLevelBrowsingContext();
friend class Location;
friend class RemoteLocationProxy;
/**
* LocationProxy is the class for the native object stored as a private in a
* RemoteLocationProxy proxy representing a Location object in a different
* process. It forwards all operations to its BrowsingContext and aggregates
* its refcount to that BrowsingContext.
*/
class LocationProxy {
public:
MozExternalRefCountType AddRef() { return GetBrowsingContext()->AddRef(); }
MozExternalRefCountType Release() {
return GetBrowsingContext()->Release();
}
void SetHref(const nsAString& aHref, nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError);
void Replace(const nsAString& aUrl, nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError);
private:
friend class RemoteLocationProxy;
BrowsingContext* GetBrowsingContext() {
return reinterpret_cast<BrowsingContext*>(
uintptr_t(this) - offsetof(BrowsingContext, mLocation));
}
};
// Type of BrowsingContent
const Type mType;
@ -345,6 +373,7 @@ class BrowsingContext : public nsWrapperCache,
// nsOuterWindowProxy handler, which will update the pointer from its
// objectMoved hook and clear it from its finalize hook.
JS::Heap<JSObject*> mWindowProxy;
LocationProxy mLocation;
// This flag is only valid in the top level browsing context, it indicates
// whether the corresponding document has been activated by user gesture.

View File

@ -108,6 +108,7 @@ LOCAL_INCLUDES += [
'/docshell/shistory',
'/dom/base',
'/dom/bindings',
'/js/xpconnect/src',
'/layout/base',
'/layout/generic',
'/layout/style',

View File

@ -29,7 +29,7 @@ namespace dom {
class Location final : public nsISupports, public nsWrapperCache {
public:
typedef Location RemoteProxy;
typedef BrowsingContext::LocationProxy RemoteProxy;
Location(nsPIDOMWindowInner* aWindow, nsIDocShell* aDocShell);

View File

@ -32,6 +32,8 @@ class RemoteOuterWindowProxy
Window_Binding::sCrossOriginAttributes,
Window_Binding::sCrossOriginMethods> {
public:
typedef RemoteObjectProxy Base;
constexpr RemoteOuterWindowProxy()
: RemoteObjectProxy(prototypes::id::Window) {}
@ -45,17 +47,22 @@ class RemoteOuterWindowProxy
// SpiderMonkey extensions
bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::AutoIdVector& props) const final;
void finalize(JSFreeOp* aFop, JSObject* aProxy) const final;
const char* className(JSContext* aCx,
JS::Handle<JSObject*> aProxy) const final;
void NoteChildren(JSObject* aProxy,
nsCycleCollectionTraversalCallback& aCb) const override {
CycleCollectionNoteChild(aCb,
static_cast<BrowsingContext*>(GetNative(aProxy)),
"js::GetObjectPrivate(obj)");
}
};
static const RemoteOuterWindowProxy sSingleton;
// Give RemoteOuterWindowProxyClass 2 reserved slots, like the other wrappers,
// Give RemoteOuterWindowProxy 2 reserved slots, like the other wrappers,
// so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
// malloc.
const js::Class RemoteOuterWindowProxyClass =
template <>
const js::Class RemoteOuterWindowProxy::Base::sClass =
PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
@ -63,30 +70,8 @@ bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
MOZ_ASSERT(!aContext->GetDocShell(),
"Why are we creating a RemoteOuterWindowProxy?");
xpc::CompartmentPrivate* priv =
xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx));
xpc::CompartmentPrivate::RemoteProxyMap& map = priv->GetRemoteProxyMap();
auto result = map.lookupForAdd(aContext);
if (result) {
aRetVal.set(result->value());
return true;
}
JS::Rooted<JSObject*> obj(
aCx, sSingleton.CreateProxyObject(aCx, aContext,
&RemoteOuterWindowProxyClass));
if (!obj) {
return false;
}
NS_ADDREF(aContext);
if (!map.add(result, aContext, obj)) {
JS_ReportOutOfMemory(aCx);
return false;
}
aRetVal.set(obj);
return true;
sSingleton.GetProxyObject(aCx, aContext, aRetVal);
return !!aRetVal;
}
static BrowsingContext* GetBrowsingContext(JSObject* aProxy) {
@ -177,17 +162,5 @@ bool RemoteOuterWindowProxy::getOwnEnumerablePropertyKeys(
return AppendIndexedPropertyNames(aCx, GetBrowsingContext(aProxy), aProps);
}
void RemoteOuterWindowProxy::finalize(JSFreeOp* aFop, JSObject* aProxy) const {
BrowsingContext* bc = GetBrowsingContext(aProxy);
RefPtr<BrowsingContext> self(dont_AddRef(bc));
}
const char* RemoteOuterWindowProxy::className(
JSContext* aCx, JS::Handle<JSObject*> aProxy) const {
MOZ_ASSERT(js::IsProxy(aProxy));
return "Object";
}
} // namespace dom
} // namespace mozilla

View File

@ -9132,7 +9132,6 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
# We'll use a JSObject. It might make more sense to use remoteType's
# RemoteProxy, but it's not easy to construct a type for that from here.
remoteType = BuiltinTypes[IDLBuiltinType.Types.object]
extendedAttributes.append('canOOM')
extendedAttributes.remove('infallible')
prototypeID, _ = PrototypeIDAndDepth(self.descriptor)
prefix = fill("""

View File

@ -11,12 +11,6 @@
namespace mozilla {
namespace dom {
// Give RemoteObjectProxy 2 reserved slots, like the other wrappers, so
// JSObject::swap can swap it with CrossCompartmentWrappers without requiring
// malloc.
const js::Class RemoteObjectProxyClass =
PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
bool RemoteObjectProxyBase::getOwnPropertyDescriptor(
JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc) const {
@ -169,12 +163,41 @@ bool RemoteObjectProxyBase::getOwnEnumerablePropertyKeys(
return true;
}
JSObject* RemoteObjectProxyBase::CreateProxyObject(
JSContext* aCx, void* aNative, const js::Class* aClasp) const {
const char* RemoteObjectProxyBase::className(
JSContext* aCx, JS::Handle<JSObject*> aProxy) const {
MOZ_ASSERT(js::IsProxy(aProxy));
return "Object";
}
void RemoteObjectProxyBase::GetOrCreateProxyObject(
JSContext* aCx, void* aNative, const js::Class* aClasp,
JS::MutableHandle<JSObject*> aProxy, bool& aNewObjectCreated) const {
xpc::CompartmentPrivate* priv =
xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx));
xpc::CompartmentPrivate::RemoteProxyMap& map = priv->GetRemoteProxyMap();
auto result = map.lookupForAdd(aNative);
if (result) {
aProxy.set(result->value());
return;
}
js::ProxyOptions options;
options.setClass(aClasp);
JS::Rooted<JS::Value> native(aCx, JS::PrivateValue(aNative));
return js::NewProxyObject(aCx, this, native, nullptr, options);
JS::Rooted<JSObject*> obj(
aCx, js::NewProxyObject(aCx, this, native, nullptr, options));
if (!obj) {
return;
}
aNewObjectCreated = true;
if (!map.add(result, aNative, obj)) {
return;
}
aProxy.set(obj);
}
const char RemoteObjectProxyBase::sCrossOriginProxyFamily = 0;

View File

@ -70,10 +70,15 @@ class RemoteObjectProxyBase : public js::BaseProxyHandler,
bool getOwnEnumerablePropertyKeys(JSContext* aCx,
JS::Handle<JSObject*> aProxy,
JS::AutoIdVector& aProps) const override;
const char* className(JSContext* aCx,
JS::Handle<JSObject*> aProxy) const final;
bool isCallable(JSObject* aObj) const final { return false; }
bool isConstructor(JSObject* aObj) const final { return false; }
virtual void NoteChildren(JSObject* aProxy,
nsCycleCollectionTraversalCallback& aCb) const = 0;
static void* GetNative(JSObject* aProxy) {
return js::GetProxyPrivate(aProxy).toPrivate();
}
@ -101,8 +106,17 @@ class RemoteObjectProxyBase : public js::BaseProxyHandler,
}
protected:
JSObject* CreateProxyObject(JSContext* aCx, void* aNative,
const js::Class* aClasp) const;
/**
* Gets an existing cached proxy object, or creates a new one and caches it.
* aProxy will be null on failure. aNewObjectCreated is set to true if a new
* object was created, callers probably need to addref the native in that
* case. aNewObjectCreated can be true even if aProxy is null, if something
* failed after creating the object.
*/
void GetOrCreateProxyObject(JSContext* aCx, void* aNative,
const js::Class* aClasp,
JS::MutableHandle<JSObject*> aProxy,
bool& aNewObjectCreated) const;
const prototypes::ID mPrototypeID;
@ -126,9 +140,18 @@ class RemoteObjectProxyBase : public js::BaseProxyHandler,
template <class Native, JSPropertySpec* P, JSFunctionSpec* F>
class RemoteObjectProxy : public RemoteObjectProxyBase {
public:
JSObject* CreateProxyObject(JSContext* aCx, Native* aNative,
const js::Class* aClasp) const {
return RemoteObjectProxyBase::CreateProxyObject(aCx, aNative, aClasp);
void finalize(JSFreeOp* aFop, JSObject* aProxy) const final {
auto native = static_cast<Native*>(GetNative(aProxy));
RefPtr<Native> self(dont_AddRef(native));
}
void GetProxyObject(JSContext* aCx, Native* aNative,
JS::MutableHandle<JSObject*> aProxy) const {
bool objectCreated = false;
GetOrCreateProxyObject(aCx, aNative, &sClass, aProxy, objectCreated);
if (objectCreated) {
NS_ADDREF(aNative);
}
}
protected:
@ -140,6 +163,8 @@ class RemoteObjectProxy : public RemoteObjectProxyBase {
return MaybeCrossOriginObjectMixins::EnsureHolder(
aCx, aProxy, /* slot = */ 0, P, F, aHolder);
}
static const js::Class sClass;
};
/**

View File

@ -2496,7 +2496,7 @@ nsresult ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
aSavedResponseOut->mValue.principalInfo() =
mozilla::ipc::ContentPrincipalInfo(attrs, origin, specNoSuffix,
std::move(policies));
Nothing(), std::move(policies));
}
bool nullPadding = false;

View File

@ -27,12 +27,10 @@ using namespace gfx;
* due to CORS security.
*/
struct ImageCacheKey {
ImageCacheKey(imgIContainer* aImage, HTMLCanvasElement* aCanvas,
bool aIsAccelerated)
: mImage(aImage), mCanvas(aCanvas), mIsAccelerated(aIsAccelerated) {}
ImageCacheKey(imgIContainer* aImage, HTMLCanvasElement* aCanvas)
: mImage(aImage), mCanvas(aCanvas) {}
nsCOMPtr<imgIContainer> mImage;
HTMLCanvasElement* mCanvas;
bool mIsAccelerated;
};
/**
@ -43,13 +41,11 @@ struct ImageCacheEntryData {
ImageCacheEntryData(const ImageCacheEntryData& aOther)
: mImage(aOther.mImage),
mCanvas(aOther.mCanvas),
mIsAccelerated(aOther.mIsAccelerated),
mSourceSurface(aOther.mSourceSurface),
mSize(aOther.mSize) {}
explicit ImageCacheEntryData(const ImageCacheKey& aKey)
: mImage(aKey.mImage),
mCanvas(aKey.mCanvas),
mIsAccelerated(aKey.mIsAccelerated) {}
mCanvas(aKey.mCanvas) {}
nsExpirationState* GetExpirationState() { return &mState; }
size_t SizeInBytes() { return mSize.width * mSize.height * 4; }
@ -57,7 +53,6 @@ struct ImageCacheEntryData {
// Key
nsCOMPtr<imgIContainer> mImage;
HTMLCanvasElement* mCanvas;
bool mIsAccelerated;
// Value
RefPtr<SourceSurface> mSourceSurface;
IntSize mSize;
@ -76,13 +71,12 @@ class ImageCacheEntry : public PLDHashEntryHdr {
~ImageCacheEntry() {}
bool KeyEquals(KeyTypePointer key) const {
return mData->mImage == key->mImage && mData->mCanvas == key->mCanvas &&
mData->mIsAccelerated == key->mIsAccelerated;
return mData->mImage == key->mImage && mData->mCanvas == key->mCanvas;
}
static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
static PLDHashNumber HashKey(KeyTypePointer key) {
return HashGeneric(key->mImage.get(), key->mCanvas, key->mIsAccelerated);
return HashGeneric(key->mImage.get(), key->mCanvas);
}
enum { ALLOW_MEMMOVE = true };
@ -93,11 +87,10 @@ class ImageCacheEntry : public PLDHashEntryHdr {
* Used for all images across all canvases.
*/
struct AllCanvasImageCacheKey {
AllCanvasImageCacheKey(imgIContainer* aImage, bool aIsAccelerated)
: mImage(aImage), mIsAccelerated(aIsAccelerated) {}
explicit AllCanvasImageCacheKey(imgIContainer* aImage)
: mImage(aImage) {}
nsCOMPtr<imgIContainer> mImage;
bool mIsAccelerated;
};
class AllCanvasImageCacheEntry : public PLDHashEntryHdr {
@ -106,27 +99,25 @@ class AllCanvasImageCacheEntry : public PLDHashEntryHdr {
typedef const AllCanvasImageCacheKey* KeyTypePointer;
explicit AllCanvasImageCacheEntry(const KeyType* aKey)
: mImage(aKey->mImage), mIsAccelerated(aKey->mIsAccelerated) {}
: mImage(aKey->mImage) {}
AllCanvasImageCacheEntry(const AllCanvasImageCacheEntry& toCopy)
: mImage(toCopy.mImage),
mIsAccelerated(toCopy.mIsAccelerated),
mSourceSurface(toCopy.mSourceSurface) {}
~AllCanvasImageCacheEntry() {}
bool KeyEquals(KeyTypePointer key) const {
return mImage == key->mImage && mIsAccelerated == key->mIsAccelerated;
return mImage == key->mImage;
}
static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
static PLDHashNumber HashKey(KeyTypePointer key) {
return HashGeneric(key->mImage.get(), key->mIsAccelerated);
return HashGeneric(key->mImage.get());
}
enum { ALLOW_MEMMOVE = true };
nsCOMPtr<imgIContainer> mImage;
bool mIsAccelerated;
RefPtr<SourceSurface> mSourceSurface;
};
@ -149,11 +140,10 @@ class ImageCache final : public nsExpirationTracker<ImageCacheEntryData, 4> {
// Remove from the all canvas cache entry first since nsExpirationTracker
// will delete aObject.
mAllCanvasCache.RemoveEntry(
AllCanvasImageCacheKey(aObject->mImage, aObject->mIsAccelerated));
AllCanvasImageCacheKey(aObject->mImage));
// Deleting the entry will delete aObject since the entry owns aObject.
mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas,
aObject->mIsAccelerated));
mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas));
}
nsTHashtable<ImageCacheEntry> mCache;
@ -273,8 +263,7 @@ static already_AddRefed<imgIContainer> GetImageContainer(dom::Element* aImage) {
void CanvasImageCache::NotifyDrawImage(Element* aImage,
HTMLCanvasElement* aCanvas,
SourceSurface* aSource,
const IntSize& aSize,
bool aIsAccelerated) {
const IntSize& aSize) {
if (!gImageCache) {
gImageCache = new ImageCache();
nsContentUtils::RegisterShutdownObserver(
@ -286,8 +275,8 @@ void CanvasImageCache::NotifyDrawImage(Element* aImage,
return;
}
AllCanvasImageCacheKey allCanvasCacheKey(imgContainer, aIsAccelerated);
ImageCacheKey canvasCacheKey(imgContainer, aCanvas, aIsAccelerated);
AllCanvasImageCacheKey allCanvasCacheKey(imgContainer);
ImageCacheKey canvasCacheKey(imgContainer, aCanvas);
ImageCacheEntry* entry = gImageCache->mCache.PutEntry(canvasCacheKey);
if (entry) {
@ -317,8 +306,7 @@ void CanvasImageCache::NotifyDrawImage(Element* aImage,
gImageCache->AgeOneGeneration();
}
SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage,
bool aIsAccelerated) {
SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage) {
if (!gImageCache) {
return nullptr;
}
@ -329,7 +317,7 @@ SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage,
}
AllCanvasImageCacheEntry* entry = gImageCache->mAllCanvasCache.GetEntry(
AllCanvasImageCacheKey(imgContainer, aIsAccelerated));
AllCanvasImageCacheKey(imgContainer));
if (!entry) {
return nullptr;
}
@ -339,8 +327,7 @@ SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage,
SourceSurface* CanvasImageCache::LookupCanvas(Element* aImage,
HTMLCanvasElement* aCanvas,
IntSize* aSizeOut,
bool aIsAccelerated) {
IntSize* aSizeOut) {
if (!gImageCache) {
return nullptr;
}
@ -351,7 +338,7 @@ SourceSurface* CanvasImageCache::LookupCanvas(Element* aImage,
}
ImageCacheEntry* entry = gImageCache->mCache.GetEntry(
ImageCacheKey(imgContainer, aCanvas, aIsAccelerated));
ImageCacheKey(imgContainer, aCanvas));
if (!entry) {
return nullptr;
}

View File

@ -33,15 +33,13 @@ class CanvasImageCache {
*/
static void NotifyDrawImage(dom::Element* aImage,
dom::HTMLCanvasElement* aCanvas,
SourceSurface* aSource, const gfx::IntSize& aSize,
bool aIsAccelerated);
SourceSurface* aSource, const gfx::IntSize& aSize);
/**
* Check whether aImage has recently been drawn any canvas. If we return
* a non-null surface, then the same image was recently drawn into a canvas.
*/
static SourceSurface* LookupAllCanvas(dom::Element* aImage,
bool aIsAccelerated);
static SourceSurface* LookupAllCanvas(dom::Element* aImage);
/**
* Like the top above, but restricts the lookup to only aCanvas. This is
@ -49,8 +47,7 @@ class CanvasImageCache {
*/
static SourceSurface* LookupCanvas(dom::Element* aImage,
dom::HTMLCanvasElement* aCanvas,
gfx::IntSize* aSizeOut,
bool aIsAccelerated);
gfx::IntSize* aSizeOut);
};
} // namespace mozilla

View File

@ -106,8 +106,6 @@
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/FloatingPoint.h"
#include "nsGlobalWindow.h"
#include "GLContext.h"
#include "GLContextProvider.h"
#include "nsIScreenManager.h"
#include "nsFilterInstance.h"
#include "nsSVGLength2.h"
@ -125,16 +123,6 @@
#undef free // apparently defined by some windows header, clashing with a
// free() method in SkTypes.h
#include "SkiaGLGlue.h"
#ifdef USE_SKIA
# include "SurfaceTypes.h"
# include "GLBlitHelper.h"
# include "ScopedGLHelpers.h"
#endif
using mozilla::gl::GLContext;
using mozilla::gl::GLContextProvider;
using mozilla::gl::SkiaGLGlue;
#ifdef XP_WIN
# include "gfxWindowsPlatform.h"
@ -760,105 +748,6 @@ CanvasShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
return NS_OK;
}
class CanvasDrawObserver {
public:
explicit CanvasDrawObserver(CanvasRenderingContext2D* aCanvasContext);
// Only enumerate draw calls that could affect the heuristic
enum DrawCallType { PutImageData, GetImageData, DrawImage };
// This is the one that we call on relevant draw calls and count
// GPU vs. CPU preferrable calls...
void DidDrawCall(DrawCallType aType);
// When this returns true, the observer is done making the decisions.
// Right now, we expect to get rid of the observer after the FrameEnd
// returns true, though the decision could eventually change if the
// function calls shift. If we change to monitor the functions called
// and make decisions to change more than once, we would probably want
// FrameEnd to reset the timer and counters as it returns true.
bool FrameEnd();
private:
// These values will be picked up from preferences:
int32_t mMinFramesBeforeDecision;
float mMinSecondsBeforeDecision;
int32_t mMinCallsBeforeDecision;
CanvasRenderingContext2D* mCanvasContext;
int32_t mSoftwarePreferredCalls;
int32_t mGPUPreferredCalls;
int32_t mFramesRendered;
TimeStamp mCreationTime;
};
// We are not checking for the validity of the preference values. For example,
// negative values will have an effect of a quick exit, so no harm done.
CanvasDrawObserver::CanvasDrawObserver(CanvasRenderingContext2D* aCanvasContext)
: mMinFramesBeforeDecision(gfxPrefs::CanvasAutoAccelerateMinFrames()),
mMinSecondsBeforeDecision(gfxPrefs::CanvasAutoAccelerateMinSeconds()),
mMinCallsBeforeDecision(gfxPrefs::CanvasAutoAccelerateMinCalls()),
mCanvasContext(aCanvasContext),
mSoftwarePreferredCalls(0),
mGPUPreferredCalls(0),
mFramesRendered(0),
mCreationTime(TimeStamp::NowLoRes()) {}
void CanvasDrawObserver::DidDrawCall(DrawCallType aType) {
switch (aType) {
case PutImageData:
case GetImageData:
if (mGPUPreferredCalls == 0 && mSoftwarePreferredCalls == 0) {
mCreationTime = TimeStamp::NowLoRes();
}
mSoftwarePreferredCalls++;
break;
case DrawImage:
if (mGPUPreferredCalls == 0 && mSoftwarePreferredCalls == 0) {
mCreationTime = TimeStamp::NowLoRes();
}
mGPUPreferredCalls++;
break;
}
}
// If we return true, the observer is done making the decisions...
bool CanvasDrawObserver::FrameEnd() {
mFramesRendered++;
// We log the first mMinFramesBeforeDecision frames of any
// canvas object then make a call to determine whether it should
// be GPU or CPU backed
if ((mFramesRendered >= mMinFramesBeforeDecision) ||
((TimeStamp::NowLoRes() - mCreationTime).ToSeconds()) >
mMinSecondsBeforeDecision) {
// If we don't have enough data, don't bother changing...
if (mGPUPreferredCalls > mMinCallsBeforeDecision ||
mSoftwarePreferredCalls > mMinCallsBeforeDecision) {
CanvasRenderingContext2D::RenderingMode switchToMode;
if (mGPUPreferredCalls >= mSoftwarePreferredCalls) {
switchToMode =
CanvasRenderingContext2D::RenderingMode::OpenGLBackendMode;
} else {
switchToMode =
CanvasRenderingContext2D::RenderingMode::SoftwareBackendMode;
}
if (switchToMode != mCanvasContext->mRenderingMode) {
if (!mCanvasContext->SwitchRenderingMode(switchToMode)) {
gfxDebug() << "Canvas acceleration failed mode switch to "
<< switchToMode;
}
}
}
// If we ever redesign this class to constantly monitor the functions
// and keep making decisions, we would probably want to reset the counters
// and the timers here...
return true;
}
return false;
}
class CanvasRenderingContext2DUserData : public LayerUserData {
public:
explicit CanvasRenderingContext2DUserData(CanvasRenderingContext2D* aContext)
@ -884,12 +773,6 @@ class CanvasRenderingContext2DUserData : public LayerUserData {
static_cast<CanvasRenderingContext2D*>(aData);
if (context) {
context->MarkContextClean();
if (context->mDrawObserver) {
if (context->mDrawObserver->FrameEnd()) {
// Note that this call deletes and nulls out mDrawObserver:
context->RemoveDrawObserver();
}
}
}
}
bool IsForContext(CanvasRenderingContext2D* aContext) {
@ -909,7 +792,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(CanvasRenderingContext2D)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CanvasRenderingContext2D)
// Make sure we remove ourselves from the list of demotable contexts (raw
// pointers), since we're logically destructed at this point.
CanvasRenderingContext2D::RemoveDemotableContext(tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCanvasElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
for (uint32_t i = 0; i < tmp->mStyleStack.Length(); i++) {
@ -1000,15 +882,10 @@ NS_INTERFACE_MAP_END
// Initialize our static variables.
uintptr_t CanvasRenderingContext2D::sNumLivingContexts = 0;
DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
static bool sMaxContextsInitialized = false;
static int32_t sMaxContexts = 0;
CanvasRenderingContext2D::CanvasRenderingContext2D(
layers::LayersBackend aCompositorBackend)
: mRenderingMode(RenderingMode::OpenGLBackendMode),
mCompositorBackend(aCompositorBackend)
// these are the default values from the Canvas spec
,
: // these are the default values from the Canvas spec
mWidth(0),
mHeight(0),
mZero(false),
@ -1017,35 +894,21 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(
mOpaque(false),
mResetLayer(true),
mIPC(false),
mIsSkiaGL(false),
mHasPendingStableStateCallback(false),
mDrawObserver(nullptr),
mIsEntireFrameInvalid(false),
mPredictManyRedrawCalls(false),
mIsCapturedFrameInvalid(false),
mPathTransformWillUpdate(false),
mInvalidateCount(0),
mWriteOnly(false) {
if (!sMaxContextsInitialized) {
sMaxContexts = gfxPrefs::CanvasAzureAcceleratedLimit();
sMaxContextsInitialized = true;
}
sNumLivingContexts++;
mShutdownObserver = new CanvasShutdownObserver(this);
nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
// The default is to use OpenGL mode
if (AllowOpenGLCanvas()) {
mDrawObserver = new CanvasDrawObserver(this);
} else {
mRenderingMode = RenderingMode::SoftwareBackendMode;
}
}
CanvasRenderingContext2D::~CanvasRenderingContext2D() {
RemoveDrawObserver();
RemovePostRefreshObserver();
RemoveShutdownObserver();
Reset();
@ -1057,7 +920,6 @@ CanvasRenderingContext2D::~CanvasRenderingContext2D() {
if (!sNumLivingContexts) {
NS_IF_RELEASE(sErrorTarget);
}
RemoveDemotableContext(this);
}
JSObject* CanvasRenderingContext2D::WrapObject(
@ -1228,13 +1090,6 @@ void CanvasRenderingContext2D::Redraw(const gfx::Rect& aR) {
}
void CanvasRenderingContext2D::DidRefresh() {
if (IsTargetValid() && mIsSkiaGL) {
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
MOZ_ASSERT(glue);
auto gl = glue->GetGLContext();
gl->FlushIfHeavyGLCallsSinceLastFlush();
}
}
void CanvasRenderingContext2D::RedrawUser(const gfxRect& aR) {
@ -1249,70 +1104,6 @@ void CanvasRenderingContext2D::RedrawUser(const gfxRect& aR) {
Redraw(newr);
}
bool CanvasRenderingContext2D::AllowOpenGLCanvas() const {
// If we somehow didn't have the correct compositor in the constructor,
// we could do something like this to get it:
//
// HTMLCanvasElement* el = GetCanvas();
// if (el) {
// mCompositorBackend = el->GetCompositorBackendType();
// }
//
// We could have LAYERS_NONE if there was no widget at the time of
// canvas creation, but in that case the
// HTMLCanvasElement::GetCompositorBackendType would return LAYERS_NONE
// as well, so it wouldn't help much.
//
// XXX Disable SkiaGL on WebRender, since there is a case that R8G8B8X8
// is used, but WebRender does not support R8G8B8X8.
return (mCompositorBackend == LayersBackend::LAYERS_OPENGL) &&
gfxPlatform::GetPlatform()->AllowOpenGLCanvas();
}
bool CanvasRenderingContext2D::SwitchRenderingMode(
RenderingMode aRenderingMode) {
if (!(IsTargetValid() || mBufferProvider) ||
mRenderingMode == aRenderingMode) {
return false;
}
MOZ_ASSERT(mBufferProvider);
#ifdef USE_SKIA_GPU
// Do not attempt to switch into GL mode if the platform doesn't allow it.
if ((aRenderingMode == RenderingMode::OpenGLBackendMode) &&
!AllowOpenGLCanvas()) {
return false;
}
#endif
RefPtr<PersistentBufferProvider> oldBufferProvider = mBufferProvider;
// Return the old target to the buffer provider.
// We need to do this before calling EnsureTarget.
ReturnTarget();
mTarget = nullptr;
mBufferProvider = nullptr;
mResetLayer = true;
// Recreate mTarget using the new rendering mode
RenderingMode attemptedMode = EnsureTarget(nullptr, aRenderingMode);
if (!IsTargetValid()) {
return false;
}
if (oldBufferProvider && mTarget) {
CopyBufferProvider(*oldBufferProvider, *mTarget,
IntRect(0, 0, mWidth, mHeight));
}
// We succeeded, so update mRenderingMode to reflect reality
mRenderingMode = attemptedMode;
return true;
}
bool CanvasRenderingContext2D::CopyBufferProvider(
PersistentBufferProvider& aOld, DrawTarget& aTarget, IntRect aCopyRect) {
// Borrowing the snapshot must be done after ReturnTarget.
@ -1328,119 +1119,6 @@ bool CanvasRenderingContext2D::CopyBufferProvider(
}
void CanvasRenderingContext2D::Demote() {
if (SwitchRenderingMode(RenderingMode::SoftwareBackendMode)) {
RemoveDemotableContext(this);
}
}
std::vector<CanvasRenderingContext2D*>&
CanvasRenderingContext2D::DemotableContexts() {
// This is a list of raw pointers to cycle-collected objects. We need to
// ensure that we remove elements from it during UNLINK (which can happen
// considerably before the actual destructor) since the object is logically
// destroyed at that point and will be in an inconsistant state.
static std::vector<CanvasRenderingContext2D*> contexts;
return contexts;
}
void CanvasRenderingContext2D::DemoteOldestContextIfNecessary() {
MOZ_ASSERT(sMaxContextsInitialized);
if (sMaxContexts <= 0) {
return;
}
std::vector<CanvasRenderingContext2D*>& contexts = DemotableContexts();
if (contexts.size() < (size_t)sMaxContexts) return;
CanvasRenderingContext2D* oldest = contexts.front();
if (oldest->SwitchRenderingMode(RenderingMode::SoftwareBackendMode)) {
RemoveDemotableContext(oldest);
}
}
void CanvasRenderingContext2D::AddDemotableContext(
CanvasRenderingContext2D* aContext) {
MOZ_ASSERT(sMaxContextsInitialized);
if (sMaxContexts <= 0) return;
std::vector<CanvasRenderingContext2D*>::iterator iter = std::find(
DemotableContexts().begin(), DemotableContexts().end(), aContext);
if (iter != DemotableContexts().end()) return;
DemotableContexts().push_back(aContext);
}
void CanvasRenderingContext2D::RemoveDemotableContext(
CanvasRenderingContext2D* aContext) {
MOZ_ASSERT(sMaxContextsInitialized);
if (sMaxContexts <= 0) return;
std::vector<CanvasRenderingContext2D*>::iterator iter = std::find(
DemotableContexts().begin(), DemotableContexts().end(), aContext);
if (iter != DemotableContexts().end()) DemotableContexts().erase(iter);
}
#define MIN_SKIA_GL_DIMENSION 16
bool CanvasRenderingContext2D::CheckSizeForSkiaGL(IntSize aSize) {
MOZ_ASSERT(NS_IsMainThread());
int minsize = Preferences::GetInt("gfx.canvas.min-size-for-skia-gl", 128);
if (aSize.width < MIN_SKIA_GL_DIMENSION ||
aSize.height < MIN_SKIA_GL_DIMENSION ||
(aSize.width * aSize.height < minsize * minsize)) {
return false;
}
// Maximum pref allows 3 different options:
// 0 means unlimited size
// > 0 means use value as an absolute threshold
// < 0 means use the number of screen pixels as a threshold
int maxsize = Preferences::GetInt("gfx.canvas.max-size-for-skia-gl", 0);
// unlimited max size
if (!maxsize) {
return true;
}
// absolute max size threshold
if (maxsize > 0) {
return aSize.width <= maxsize && aSize.height <= maxsize;
}
// Cache the number of pixels on the primary screen
static int32_t gScreenPixels = -1;
if (gScreenPixels < 0) {
// Default to historical mobile screen size of 980x480, like FishIEtank.
// In addition, allow skia use up to this size even if the screen is
// smaller. A lot content expects this size to work well. See Bug 999841
if (gfxPlatform::GetPlatform()->HasEnoughTotalSystemMemoryForSkiaGL()) {
gScreenPixels = 980 * 480;
}
nsCOMPtr<nsIScreenManager> screenManager =
do_GetService("@mozilla.org/gfx/screenmanager;1");
if (screenManager) {
nsCOMPtr<nsIScreen> primaryScreen;
screenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen));
if (primaryScreen) {
int32_t x, y, width, height;
primaryScreen->GetRect(&x, &y, &width, &height);
gScreenPixels = std::max(gScreenPixels, width * height);
}
}
}
// Just always use a scale of 1.0. It can be changed if a lot of contents need
// it.
static double gDefaultScale = 1.0;
double scale = gDefaultScale > 0 ? gDefaultScale : 1.0;
int32_t threshold = ceil(scale * scale * gScreenPixels);
// screen size acts as max threshold
return threshold < 0 || (aSize.width * aSize.height) <= threshold;
}
void CanvasRenderingContext2D::ScheduleStableStateCallback() {
@ -1489,30 +1167,22 @@ void CanvasRenderingContext2D::RestoreClipsAndTransformToTarget() {
}
}
CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
const gfx::Rect* aCoveredRect, RenderingMode aRenderingMode) {
bool CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect) {
if (AlreadyShutDown()) {
gfxCriticalError() << "Attempt to render into a Canvas2d after shutdown.";
SetErrorState();
return aRenderingMode;
return false;
}
// This would make no sense, so make sure we don't get ourselves in a mess
MOZ_ASSERT(mRenderingMode != RenderingMode::DefaultBackendMode);
RenderingMode mode = (aRenderingMode == RenderingMode::DefaultBackendMode)
? mRenderingMode
: aRenderingMode;
if (mTarget && mode == mRenderingMode) {
return mRenderingMode;
if (mTarget) {
return true;
}
// Check that the dimensions are sane
if (mWidth > gfxPrefs::MaxCanvasSize() ||
mHeight > gfxPrefs::MaxCanvasSize() || mWidth < 0 || mHeight < 0) {
SetErrorState();
return aRenderingMode;
return false;
}
// If the next drawing command covers the entire canvas, we can skip copying
@ -1542,7 +1212,7 @@ CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
IntRect persistedRect =
canDiscardContent ? IntRect() : IntRect(0, 0, mWidth, mHeight);
if (mBufferProvider && mode == mRenderingMode) {
if (mBufferProvider) {
mTarget = mBufferProvider->BorrowDrawTarget(persistedRect);
if (mTarget && !mBufferProvider->PreservesDrawingState()) {
@ -1550,28 +1220,21 @@ CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
}
if (mTarget) {
return mode;
return true;
}
}
RefPtr<DrawTarget> newTarget;
RefPtr<PersistentBufferProvider> newProvider;
if (mode == RenderingMode::OpenGLBackendMode &&
!TrySkiaGLTarget(newTarget, newProvider)) {
// Fall back to software.
mode = RenderingMode::SoftwareBackendMode;
}
if (mode == RenderingMode::SoftwareBackendMode &&
!TrySharedTarget(newTarget, newProvider) &&
if (!TrySharedTarget(newTarget, newProvider) &&
!TryBasicTarget(newTarget, newProvider)) {
gfxCriticalError(
CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(GetSize())))
<< "Failed borrow shared and basic targets.";
SetErrorState();
return mode;
return false;
}
MOZ_ASSERT(newTarget);
@ -1612,7 +1275,7 @@ CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
// canvas is already invalid, which can speed up future drawing.
Redraw();
return mode;
return true;
}
void CanvasRenderingContext2D::SetInitialState() {
@ -1672,57 +1335,6 @@ static already_AddRefed<LayerManager> LayerManagerFromCanvasElement(
aCanvasElement->OwnerDoc());
}
bool CanvasRenderingContext2D::TrySkiaGLTarget(
RefPtr<gfx::DrawTarget>& aOutDT,
RefPtr<layers::PersistentBufferProvider>& aOutProvider) {
aOutDT = nullptr;
aOutProvider = nullptr;
mIsSkiaGL = false;
IntSize size(mWidth, mHeight);
if (!AllowOpenGLCanvas() || !CheckSizeForSkiaGL(size)) {
return false;
}
RefPtr<LayerManager> layerManager =
LayerManagerFromCanvasElement(mCanvasElement);
if (!layerManager) {
return false;
}
DemoteOldestContextIfNecessary();
mBufferProvider = nullptr;
#ifdef USE_SKIA_GPU
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
if (!glue || !glue->GetGrContext() || !glue->GetGLContext()) {
return false;
}
SurfaceFormat format = GetSurfaceFormat();
aOutDT = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(),
size, format);
if (!aOutDT) {
gfxCriticalNote
<< "Failed to create a SkiaGL DrawTarget, falling back to software\n";
return false;
}
MOZ_ASSERT(aOutDT->GetType() == DrawTargetType::HARDWARE_RASTER);
AddDemotableContext(this);
aOutProvider = new PersistentBufferProviderBasic(aOutDT);
mIsSkiaGL = true;
// Drop a note in the debug builds if we ever use accelerated Skia canvas.
gfxWarningOnce() << "Using SkiaGL canvas.";
#endif
// could still be null if USE_SKIA_GPU is not #defined.
return !!aOutDT;
}
bool CanvasRenderingContext2D::TrySharedTarget(
RefPtr<gfx::DrawTarget>& aOutDT,
RefPtr<layers::PersistentBufferProvider>& aOutProvider) {
@ -1912,16 +1524,6 @@ CanvasRenderingContext2D::SetContextOptions(JSContext* aCx,
return NS_ERROR_UNEXPECTED;
}
if (Preferences::GetBool("gfx.canvas.willReadFrequently.enable", false)) {
// Use software when there is going to be a lot of readback
if (attributes.mWillReadFrequently) {
// We want to lock into software, so remove the observer that
// may potentially change that...
RemoveDrawObserver();
mRenderingMode = RenderingMode::SoftwareBackendMode;
}
}
mContextAttributesHasAlpha = attributes.mAlpha;
UpdateIsOpaque();
@ -4537,7 +4139,7 @@ CanvasRenderingContext2D::CachedSurfaceFromElement(Element* aElement) {
return res;
}
res.mSourceSurface = CanvasImageCache::LookupAllCanvas(aElement, mIsSkiaGL);
res.mSourceSurface = CanvasImageCache::LookupAllCanvas(aElement);
if (!res.mSourceSurface) {
return res;
}
@ -4576,10 +4178,6 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
double aDw, double aDh,
uint8_t aOptional_argc,
ErrorResult& aError) {
if (mDrawObserver) {
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::DrawImage);
}
MOZ_ASSERT(aOptional_argc == 0 || aOptional_argc == 2 || aOptional_argc == 6);
if (!ValidateRect(aDx, aDy, aDw, aDh, true)) {
@ -4640,8 +4238,7 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
element = video;
}
srcSurf = CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize,
mIsSkiaGL);
srcSurf = CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize);
}
nsLayoutUtils::DirectDrawInfo drawInfo;
@ -4692,7 +4289,7 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
if (res.mSourceSurface) {
if (res.mImageRequest) {
CanvasImageCache::NotifyDrawImage(
element, mCanvasElement, res.mSourceSurface, imgSize, mIsSkiaGL);
element, mCanvasElement, res.mSourceSurface, imgSize);
}
srcSurf = res.mSourceSurface;
} else {
@ -5118,10 +4715,6 @@ void CanvasRenderingContext2D::DrawWindow(nsGlobalWindowInner& aWindow,
already_AddRefed<ImageData> CanvasRenderingContext2D::GetImageData(
JSContext* aCx, double aSx, double aSy, double aSw, double aSh,
nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) {
if (mDrawObserver) {
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::GetImageData);
}
if (!mCanvasElement && !mDocShell) {
NS_ERROR("No canvas element and no docshell in GetImageData!!!");
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
@ -5190,10 +4783,6 @@ already_AddRefed<ImageData> CanvasRenderingContext2D::GetImageData(
nsresult CanvasRenderingContext2D::GetImageDataArray(
JSContext* aCx, int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight,
nsIPrincipal& aSubjectPrincipal, JSObject** aRetval) {
if (mDrawObserver) {
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::GetImageData);
}
MOZ_ASSERT(aWidth && aHeight);
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
@ -5349,10 +4938,6 @@ nsresult CanvasRenderingContext2D::PutImageData_explicit(
int32_t aX, int32_t aY, uint32_t aW, uint32_t aH,
dom::Uint8ClampedArray* aArray, bool aHasDirtyRect, int32_t aDirtyX,
int32_t aDirtyY, int32_t aDirtyWidth, int32_t aDirtyHeight) {
if (mDrawObserver) {
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::PutImageData);
}
if (aW == 0 || aH == 0) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
@ -5520,29 +5105,11 @@ already_AddRefed<ImageData> CanvasRenderingContext2D::CreateImageData(
static uint8_t g2DContextLayerUserData;
uint32_t CanvasRenderingContext2D::SkiaGLTex() const {
if (!mTarget) {
return 0;
}
MOZ_ASSERT(IsTargetValid());
return (uint32_t)(uintptr_t)mTarget->GetNativeSurface(
NativeSurfaceType::OPENGL_TEXTURE);
}
void CanvasRenderingContext2D::RemoveDrawObserver() {
if (mDrawObserver) {
delete mDrawObserver;
mDrawObserver = nullptr;
}
}
already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
nsDisplayListBuilder* aBuilder, Layer* aOldLayer, LayerManager* aManager) {
if (mOpaque || mIsSkiaGL) {
if (mOpaque) {
// If we're opaque then make sure we have a surface so we paint black
// instead of transparent.
// If we're using SkiaGL, then SkiaGLTex() below needs the target to
// be accessible.
EnsureTarget();
}
@ -5563,16 +5130,6 @@ already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
CanvasInitializeData data;
if (mIsSkiaGL) {
GLuint skiaGLTex = SkiaGLTex();
if (skiaGLTex) {
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
MOZ_ASSERT(glue);
data.mGLContext = glue->GetGLContext();
data.mFrontbufferGLTex = skiaGLTex;
}
}
data.mBufferProvider = mBufferProvider;
if (userData && userData->IsForContext(this) &&
@ -5619,11 +5176,9 @@ already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
bool CanvasRenderingContext2D::UpdateWebRenderCanvasData(
nsDisplayListBuilder* aBuilder, WebRenderCanvasData* aCanvasData) {
if (mOpaque || mIsSkiaGL) {
if (mOpaque) {
// If we're opaque then make sure we have a surface so we paint black
// instead of transparent.
// If we're using SkiaGL, then SkiaGLTex() below needs the target to
// be accessible.
EnsureTarget();
}
@ -5645,15 +5200,6 @@ bool CanvasRenderingContext2D::UpdateWebRenderCanvasData(
if (!mResetLayer && renderer) {
CanvasInitializeData data;
if (mIsSkiaGL) {
GLuint skiaGLTex = SkiaGLTex();
if (skiaGLTex) {
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
MOZ_ASSERT(glue);
data.mGLContext = glue->GetGLContext();
data.mFrontbufferGLTex = skiaGLTex;
}
}
data.mBufferProvider = mBufferProvider;
if (renderer->IsDataValid(data)) {
@ -5695,16 +5241,6 @@ bool CanvasRenderingContext2D::InitializeCanvasRenderer(
}
}
if (mIsSkiaGL) {
GLuint skiaGLTex = SkiaGLTex();
if (skiaGLTex) {
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
MOZ_ASSERT(glue);
data.mGLContext = glue->GetGLContext();
data.mFrontbufferGLTex = skiaGLTex;
}
}
data.mBufferProvider = mBufferProvider;
aRenderer->Initialize(data);

View File

@ -376,14 +376,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
double aH, const nsAString& aBgColor, uint32_t aFlags,
mozilla::ErrorResult& aError);
enum RenderingMode {
SoftwareBackendMode,
OpenGLBackendMode,
DefaultBackendMode
};
bool SwitchRenderingMode(RenderingMode aRenderingMode);
// Eventually this should be deprecated. Keeping for now to keep the binding
// functional.
void Demote();
@ -509,9 +501,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
void OnShutdown();
// Check the global setup, as well as the compositor type:
bool AllowOpenGLCanvas() const;
/**
* Update CurrentState().filter with the filter description for
* CurrentState().filterChain.
@ -616,17 +605,12 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
* is in turn an error in creating the sErrorTarget then they would both
* be null so IsTargetValid() would still return null.
*
* Returns the actual rendering mode being used by the created target.
* Returns true on success.
*/
RenderingMode EnsureTarget(
const gfx::Rect* aCoveredRect = nullptr,
RenderingMode aRenderMode = RenderingMode::DefaultBackendMode);
bool EnsureTarget(const gfx::Rect* aCoveredRect = nullptr);
void RestoreClipsAndTransformToTarget();
bool TrySkiaGLTarget(RefPtr<gfx::DrawTarget>& aOutDT,
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
bool TrySharedTarget(RefPtr<gfx::DrawTarget>& aOutDT,
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
@ -704,19 +688,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
return CurrentState().font;
}
// This function maintains a list of raw pointers to cycle-collected
// objects. We need to ensure that no entries persist beyond unlink,
// since the objects are logically destructed at that point.
static std::vector<CanvasRenderingContext2D*>& DemotableContexts();
static void DemoteOldestContextIfNecessary();
static void AddDemotableContext(CanvasRenderingContext2D* aContext);
static void RemoveDemotableContext(CanvasRenderingContext2D* aContext);
RenderingMode mRenderingMode;
layers::LayersBackend mCompositorBackend;
// Member vars
int32_t mWidth, mHeight;
@ -742,9 +713,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
bool mResetLayer;
// This is needed for drawing in drawAsyncXULElement
bool mIPC;
// True if the current DrawTarget is using skia-gl, used so we can avoid
// requesting the DT from mBufferProvider to check.
bool mIsSkiaGL;
bool mHasPendingStableStateCallback;
@ -760,14 +728,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
RefPtr<mozilla::layers::PersistentBufferProvider> mBufferProvider;
uint32_t SkiaGLTex() const;
// This observes our draw calls at the beginning of the canvas
// lifetime and switches to software or GPU mode depending on
// what it thinks is best
CanvasDrawObserver* mDrawObserver;
void RemoveDrawObserver();
RefPtr<CanvasShutdownObserver> mShutdownObserver;
void RemoveShutdownObserver();
bool AlreadyShutDown() const { return !mShutdownObserver; }
@ -919,8 +879,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
const Optional<double>& aMaxWidth,
TextDrawOperation aOp, float* aWidth);
bool CheckSizeForSkiaGL(mozilla::gfx::IntSize aSize);
// A clip or a transform, recorded and restored in order.
struct ClipState {
explicit ClipState(mozilla::gfx::Path* aClip) : clip(aClip) {}

View File

@ -16,6 +16,7 @@
#include "mozilla/Telemetry.h"
#include "CanvasRenderingContext2D.h"
#include "CanvasUtils.h"
#include "GLContext.h"
#include "GLScreenBuffer.h"
#include "WebGL1Context.h"
#include "WebGL2Context.h"

View File

@ -43,17 +43,6 @@ function IsAzureSkia() {
return enabled;
}
function IsAcceleratedSkia() {
var enabled = false;
try {
var props = Cc["@mozilla.org/gfx/info;1"].getService(SpecialPowers.Ci.nsIGfxInfo).getInfo();
enabled = props.AzureCanvasBackend == "skia" && props.AzureCanvasAccelerated;
} catch(e) { }
return enabled;
}
function IsAzureCairo() {
var enabled = false;
@ -6585,9 +6574,6 @@ isPixel(ctx, 98,48, 0,255,0,255, 0);
function test_2d_gradient_radial_inside1() {
if (IsAcceleratedSkia())
return;
var canvas = document.getElementById('c240');
var ctx = canvas.getContext('2d');

View File

@ -20,12 +20,31 @@
#include "mozilla/dom/TimeRanges.h"
#include "AudioStream.h"
NS_IMPL_NS_NEW_HTML_ELEMENT(Audio)
nsGenericHTMLElement* NS_NewHTMLAudioElement(
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser) {
mozilla::dom::HTMLAudioElement* element =
new mozilla::dom::HTMLAudioElement(std::move(aNodeInfo));
element->Init();
return element;
}
namespace mozilla {
namespace dom {
NS_IMPL_ELEMENT_CLONE(HTMLAudioElement)
nsresult HTMLAudioElement::Clone(mozilla::dom::NodeInfo* aNodeInfo,
nsINode** aResult) const {
*aResult = nullptr;
RefPtr<mozilla::dom::NodeInfo> ni(aNodeInfo);
HTMLAudioElement* it = new HTMLAudioElement(ni.forget());
it->Init();
nsCOMPtr<nsINode> kungFuDeathGrip = it;
nsresult rv = const_cast<HTMLAudioElement*>(this)->CopyInnerTo(it);
if (NS_SUCCEEDED(rv)) {
kungFuDeathGrip.swap(*aResult);
}
return rv;
}
HTMLAudioElement::HTMLAudioElement(already_AddRefed<NodeInfo>&& aNodeInfo)
: HTMLMediaElement(std::move(aNodeInfo)) {
@ -54,7 +73,8 @@ already_AddRefed<HTMLAudioElement> HTMLAudioElement::Audio(
RefPtr<mozilla::dom::NodeInfo> nodeInfo = doc->NodeInfoManager()->GetNodeInfo(
nsGkAtoms::audio, nullptr, kNameSpaceID_XHTML, ELEMENT_NODE);
RefPtr<HTMLAudioElement> audio = new HTMLAudioElement(nodeInfo.forget());
RefPtr<HTMLAudioElement> audio =
static_cast<HTMLAudioElement*>(NS_NewHTMLAudioElement(nodeInfo.forget()));
audio->SetHTMLAttr(nsGkAtoms::preload, NS_LITERAL_STRING("auto"), aRv);
if (aRv.Failed()) {
return nullptr;

View File

@ -3499,13 +3499,27 @@ HTMLMediaElement::HTMLMediaElement(
mShutdownObserver(new ShutdownObserver),
mPlayed(new TimeRanges(ToSupports(OwnerDoc()))),
mPaused(true, "HTMLMediaElement::mPaused"),
mAudioTrackList(new AudioTrackList(OwnerDoc()->GetParentObject(), this)),
mVideoTrackList(new VideoTrackList(OwnerDoc()->GetParentObject(), this)),
mErrorSink(new ErrorSink(this)),
mAudioChannelWrapper(new AudioChannelAgentCallback(this)),
mSink(MakePair(nsString(), RefPtr<AudioDeviceInfo>())) {
MOZ_ASSERT(mMainThreadEventTarget);
MOZ_ASSERT(mAbstractMainThread);
// Please don't add anything to this constructor or the initialization
// list that can cause AddRef to be called. This prevents subclasses
// from overriding AddRef in a way that works with our refcount
// logging mechanisms. Put these things inside of the ::Init method
// instead.
}
void HTMLMediaElement::Init() {
MOZ_ASSERT(mRefCnt == 0 && !mRefCnt.IsPurple(),
"HTMLMediaElement::Init called when AddRef has been called "
"at least once already, probably in the constructor. Please "
"see the documentation in the HTMLMediaElement constructor.");
MOZ_ASSERT(!mRefCnt.IsPurple());
mAudioTrackList = new AudioTrackList(OwnerDoc()->GetParentObject(), this);
mVideoTrackList = new VideoTrackList(OwnerDoc()->GetParentObject(), this);
DecoderDoctorLogger::LogConstruction(this);
@ -3526,9 +3540,12 @@ HTMLMediaElement::HTMLMediaElement(
MediaShutdownManager::InitStatics();
mShutdownObserver->Subscribe(this);
mInitialized = true;
}
HTMLMediaElement::~HTMLMediaElement() {
MOZ_ASSERT(mInitialized,
"HTMLMediaElement must be initialized before it is destroyed.");
NS_ASSERTION(
!mHasSelfReference,
"How can we be destroyed if we're still holding a self reference?");

View File

@ -117,6 +117,7 @@ class HTMLMediaElement : public nsGenericHTMLElement,
explicit HTMLMediaElement(
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
void Init();
void ReportCanPlayTelemetry();
@ -1750,6 +1751,9 @@ class HTMLMediaElement : public nsGenericHTMLElement,
// threshold.
void ReportPlayedTimeAfterBlockedTelemetry();
// True if Init() has been called after construction
bool mInitialized = false;
// True if user has called load(), seek() or element has started playing
// before. It's *only* use for checking autoplay policy
bool mIsBlessed = false;

View File

@ -35,14 +35,33 @@
#include <algorithm>
#include <limits>
NS_IMPL_NS_NEW_HTML_ELEMENT(Video)
nsGenericHTMLElement* NS_NewHTMLVideoElement(
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser) {
mozilla::dom::HTMLVideoElement* element =
new mozilla::dom::HTMLVideoElement(std::move(aNodeInfo));
element->Init();
return element;
}
namespace mozilla {
namespace dom {
static bool sVideoStatsEnabled;
NS_IMPL_ELEMENT_CLONE(HTMLVideoElement)
nsresult HTMLVideoElement::Clone(mozilla::dom::NodeInfo* aNodeInfo,
nsINode** aResult) const {
*aResult = nullptr;
RefPtr<mozilla::dom::NodeInfo> ni(aNodeInfo);
HTMLVideoElement* it = new HTMLVideoElement(ni.forget());
it->Init();
nsCOMPtr<nsINode> kungFuDeathGrip = it;
nsresult rv = const_cast<HTMLVideoElement*>(this)->CopyInnerTo(it);
if (NS_SUCCEEDED(rv)) {
kungFuDeathGrip.swap(*aResult);
}
return rv;
}
HTMLVideoElement::HTMLVideoElement(already_AddRefed<NodeInfo>&& aNodeInfo)
: HTMLMediaElement(std::move(aNodeInfo)), mIsOrientationLocked(false) {
@ -308,7 +327,8 @@ void HTMLVideoElement::ReleaseVideoWakeLockIfExists() {
}
}
void HTMLVideoElement::Init() {
/* static */
void HTMLVideoElement::InitStatics() {
Preferences::AddBoolVarCache(&sVideoStatsEnabled,
"media.video_stats.enabled");
}

View File

@ -38,7 +38,7 @@ class HTMLVideoElement final : public HTMLMediaElement {
nsAttrValue& aResult) override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
static void Init();
static void InitStatics();
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction()
const override;

View File

@ -1636,6 +1636,7 @@ void nsTextEditorState::SetSelectionRange(
props.SetEnd(aEnd);
props.SetDirection(aDirection);
} else {
MOZ_ASSERT(mBoundFrame, "Our frame should still be valid");
WeakPtr<nsTextEditorState> self(this);
aRv = mBoundFrame->SetSelectionRange(aStart, aEnd, aDirection);
if (aRv.Failed() || !self.get()) {
@ -2461,9 +2462,8 @@ bool nsTextEditorState::SetValue(const nsAString& aValue,
// TODO(emilio): It seems wrong to pass ValueChangeKind::Script if
// BySetUserInput is in aFlags.
auto changeKind = (aFlags & eSetValue_Internal)
? ValueChangeKind::Internal
: ValueChangeKind::Script;
auto changeKind = (aFlags & eSetValue_Internal) ? ValueChangeKind::Internal
: ValueChangeKind::Script;
// XXX Should we stop notifying "value changed" if mTextCtrlElement has
// been cleared?

View File

@ -1273,7 +1273,8 @@ void ContentChild::InitXPCOM(
mozilla::ipc::IPCResult ContentChild::RecvRequestMemoryReport(
const uint32_t& aGeneration, const bool& aAnonymize,
const bool& aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile) {
const bool& aMinimizeMemoryUsage,
const Maybe<mozilla::ipc::FileDescriptor>& aDMDFile) {
nsCString process;
GetProcessName(process);
AppendProcessId(process);
@ -1611,7 +1612,7 @@ static bool StartMacOSContentSandbox() {
#endif
mozilla::ipc::IPCResult ContentChild::RecvSetProcessSandbox(
const MaybeFileDesc& aBroker) {
const Maybe<mozilla::ipc::FileDescriptor>& aBroker) {
// We may want to move the sandbox initialization somewhere else
// at some point; see bug 880808.
#if defined(MOZ_CONTENT_SANDBOX)
@ -3918,4 +3919,4 @@ nsresult GetObjDir(nsIFile** aObjDir) {
}
#endif /* XP_MACOSX */
} // namespace mozilla
} // namespace mozilla

View File

@ -188,12 +188,12 @@ class ContentChild final : public PContentChild,
Endpoint<PVideoDecoderManagerChild>&& aVideoManager,
nsTArray<uint32_t>&& namespaces);
virtual mozilla::ipc::IPCResult RecvAudioDefaultDeviceChange();
mozilla::ipc::IPCResult RecvAudioDefaultDeviceChange();
mozilla::ipc::IPCResult RecvReinitRenderingForDeviceReset();
virtual mozilla::ipc::IPCResult RecvSetProcessSandbox(
const MaybeFileDesc& aBroker);
mozilla::ipc::IPCResult RecvSetProcessSandbox(
const Maybe<FileDescriptor>& aBroker);
PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
const TabId& aSameTabGroupAs,
@ -361,7 +361,7 @@ class ContentChild final : public PContentChild,
mozilla::ipc::IPCResult RecvNotifyAlertsObserver(const nsCString& aType,
const nsString& aData);
virtual mozilla::ipc::IPCResult RecvLoadProcessScript(const nsString& aURL);
mozilla::ipc::IPCResult RecvLoadProcessScript(const nsString& aURL);
mozilla::ipc::IPCResult RecvAsyncMessage(const nsString& aMsg,
InfallibleTArray<CpowEntry>&& aCpows,
@ -576,7 +576,7 @@ class ContentChild final : public PContentChild,
mozilla::ipc::IPCResult RecvRequestMemoryReport(
const uint32_t& generation, const bool& anonymize,
const bool& minimizeMemoryUsage, const MaybeFileDesc& DMDFile);
const bool& minimizeMemoryUsage, const Maybe<FileDescriptor>& DMDFile);
mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes(
const XPCOMInitData& aXPCOMInit, const StructuredCloneData& aInitialData,
@ -822,4 +822,4 @@ uint64_t NextWindowID();
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_ContentChild_h
#endif // mozilla_dom_ContentChild_h

View File

@ -2568,7 +2568,7 @@ void ContentParent::InitInternal(ProcessPriority aInitialPriority) {
#ifdef MOZ_CONTENT_SANDBOX
bool shouldSandbox = true;
MaybeFileDesc brokerFd = void_t();
Maybe<FileDescriptor> brokerFd;
// XXX: Checking the pref here makes it possible to enable/disable sandboxing
// during an active session. Currently the pref is only used for testing
// purpose. If the decision is made to permanently rely on the pref, this
@ -2583,14 +2583,14 @@ void ContentParent::InitInternal(ProcessPriority aInitialPriority) {
UniquePtr<SandboxBroker::Policy> policy =
sSandboxBrokerPolicyFactory->GetContentPolicy(Pid(), isFileProcess);
if (policy) {
brokerFd = FileDescriptor();
brokerFd = Some(FileDescriptor());
mSandboxBroker =
SandboxBroker::Create(std::move(policy), Pid(), brokerFd);
SandboxBroker::Create(std::move(policy), Pid(), brokerFd.ref());
if (!mSandboxBroker) {
KillHard("SandboxBroker::Create failed");
return;
}
MOZ_ASSERT(static_cast<const FileDescriptor&>(brokerFd).IsValid());
MOZ_ASSERT(brokerFd.ref().IsValid());
}
}
# endif
@ -3455,10 +3455,9 @@ bool ContentParent::DeallocPHeapSnapshotTempFileHelperParent(
return true;
}
bool ContentParent::SendRequestMemoryReport(const uint32_t& aGeneration,
const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile) {
bool ContentParent::SendRequestMemoryReport(
const uint32_t& aGeneration, const bool& aAnonymize,
const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
// This automatically cancels the previous request.
mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
Unused << PContentParent::SendRequestMemoryReport(
@ -5923,4 +5922,4 @@ ParentIdleListener::Observe(nsISupports*, const char* aTopic,
mozilla::Unused << mParent->SendNotifyIdleObserver(
mObserver, nsDependentCString(aTopic), nsDependentString(aData));
return NS_OK;
}
}

View File

@ -1170,7 +1170,7 @@ class ContentParent final : public PContentParent,
bool SendRequestMemoryReport(const uint32_t& aGeneration,
const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile) override;
const Maybe<FileDescriptor>& aDMDFile) override;
nsresult SaveRecording(nsIFile* aFile, bool* aRetval);

View File

@ -50,13 +50,11 @@ MemoryReportRequestHost::~MemoryReportRequestHost() {
NS_IMPL_ISUPPORTS(MemoryReportRequestClient, nsIRunnable)
/* static */
void MemoryReportRequestClient::Start(uint32_t aGeneration, bool aAnonymize,
bool aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile,
const nsACString& aProcessString,
const ReportCallback& aReportCallback,
const FinishCallback& aFinishCallback) {
/* static */ void MemoryReportRequestClient::Start(
uint32_t aGeneration, bool aAnonymize, bool aMinimizeMemoryUsage,
const Maybe<FileDescriptor>& aDMDFile, const nsACString& aProcessString,
const ReportCallback& aReportCallback,
const FinishCallback& aFinishCallback) {
RefPtr<MemoryReportRequestClient> request = new MemoryReportRequestClient(
aGeneration, aAnonymize, aDMDFile, aProcessString, aReportCallback,
aFinishCallback);
@ -75,16 +73,17 @@ void MemoryReportRequestClient::Start(uint32_t aGeneration, bool aAnonymize,
}
MemoryReportRequestClient::MemoryReportRequestClient(
uint32_t aGeneration, bool aAnonymize, const MaybeFileDesc& aDMDFile,
const nsACString& aProcessString, const ReportCallback& aReportCallback,
uint32_t aGeneration, bool aAnonymize,
const Maybe<FileDescriptor>& aDMDFile, const nsACString& aProcessString,
const ReportCallback& aReportCallback,
const FinishCallback& aFinishCallback)
: mGeneration(aGeneration),
mAnonymize(aAnonymize),
mProcessString(aProcessString),
mReportCallback(aReportCallback),
mFinishCallback(aFinishCallback) {
if (aDMDFile.type() == MaybeFileDesc::TFileDescriptor) {
mDMDFile = aDMDFile.get_FileDescriptor();
if (aDMDFile.isSome()) {
mDMDFile = aDMDFile.value();
}
}

View File

@ -18,7 +18,6 @@ class nsMemoryReporterManager;
namespace mozilla {
namespace dom {
class MaybeFileDesc;
class MemoryReport;
class MemoryReportRequestHost final {
@ -44,7 +43,8 @@ class MemoryReportRequestClient final : public nsIRunnable {
NS_DECL_ISUPPORTS
static void Start(uint32_t aGeneration, bool aAnonymize,
bool aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile,
bool aMinimizeMemoryUsage,
const Maybe<mozilla::ipc::FileDescriptor>& aDMDFile,
const nsACString& aProcessString,
const ReportCallback& aReportCallback,
const FinishCallback& aFinishCallback);
@ -53,7 +53,7 @@ class MemoryReportRequestClient final : public nsIRunnable {
private:
MemoryReportRequestClient(uint32_t aGeneration, bool aAnonymize,
const MaybeFileDesc& aDMDFile,
const Maybe<mozilla::ipc::FileDescriptor>& aDMDFile,
const nsACString& aProcessString,
const ReportCallback& aReportCallback,
const FinishCallback& aFinishCallback);

View File

@ -18,10 +18,5 @@ struct MemoryReport {
nsCString desc;
};
union MaybeFileDesc {
FileDescriptor;
void_t;
};
}
}

View File

@ -435,12 +435,12 @@ child:
* usually only be performed zero or one times. The child may
* abnormally exit if this fails; the details are OS-specific.
*/
async SetProcessSandbox(MaybeFileDesc aBroker);
async SetProcessSandbox(FileDescriptor? aBroker);
async RequestMemoryReport(uint32_t generation,
bool anonymize,
bool minimizeMemoryUsage,
MaybeFileDesc DMDFile);
FileDescriptor? DMDFile);
async RequestPerformanceMetrics(nsID aID);
/**
@ -1294,4 +1294,4 @@ both:
};
}
}
}

View File

@ -5,55 +5,38 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/PermissionMessageUtils.h"
#include "nsISerializable.h"
#include "nsSerializationHelper.h"
#include "mozilla/ipc/BackgroundUtils.h"
namespace IPC {
namespace mozilla {
namespace ipc {
void ParamTraits<nsIPrincipal>::Write(Message* aMsg, nsIPrincipal* aParam) {
bool isNull = !aParam;
WriteParam(aMsg, isNull);
if (isNull) {
return;
void IPDLParamTraits<nsIPrincipal>::Write(IPC::Message* aMsg, IProtocol* aActor,
nsIPrincipal* aParam) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
Maybe<PrincipalInfo> info;
if (aParam) {
info.emplace();
nsresult rv = PrincipalToPrincipalInfo(aParam, info.ptr());
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
}
nsCString principalString;
nsresult rv = NS_SerializeToString(aParam, principalString);
if (NS_FAILED(rv)) {
MOZ_CRASH("Unable to serialize principal.");
return;
}
WriteParam(aMsg, principalString);
WriteIPDLParam(aMsg, aActor, info);
}
bool ParamTraits<nsIPrincipal>::Read(const Message* aMsg, PickleIterator* aIter,
RefPtr<nsIPrincipal>* aResult) {
bool isNull;
if (!ReadParam(aMsg, aIter, &isNull)) {
bool IPDLParamTraits<nsIPrincipal>::Read(const IPC::Message* aMsg,
PickleIterator* aIter,
IProtocol* aActor,
RefPtr<nsIPrincipal>* aResult) {
Maybe<PrincipalInfo> info;
if (!ReadIPDLParam(aMsg, aIter, aActor, &info)) {
return false;
}
if (isNull) {
*aResult = nullptr;
return true;
}
nsCString principalString;
if (!ReadParam(aMsg, aIter, &principalString)) {
return false;
}
nsCOMPtr<nsISupports> iSupports;
nsresult rv =
NS_DeserializeObject(principalString, getter_AddRefs(iSupports));
NS_ENSURE_SUCCESS(rv, false);
nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(iSupports);
NS_ENSURE_TRUE(principal, false);
*aResult = principal.forget();
return true;
nsresult rv = NS_OK;
*aResult = info ? PrincipalInfoToPrincipal(info.ref(), &rv) : nullptr;
return NS_SUCCEEDED(rv);
}
} // namespace IPC
} // namespace ipc
} // namespace mozilla

View File

@ -7,24 +7,18 @@
#ifndef mozilla_dom_permission_message_utils_h__
#define mozilla_dom_permission_message_utils_h__
#include "mozilla/ipc/IPDLParamTraits.h"
#include "ipc/IPCMessageUtils.h"
#include "nsCOMPtr.h"
#include "nsIPrincipal.h"
namespace IPC {
template <>
struct ParamTraits<nsIPrincipal> {
static void Write(Message* aMsg, nsIPrincipal* aParam);
static bool Read(const Message* aMsg, PickleIterator* aIter,
RefPtr<nsIPrincipal>* aResult);
};
/**
* Legacy IPC::Principal type. Use nsIPrincipal directly in new IPDL code.
*/
class Principal {
friend struct ParamTraits<Principal>;
friend struct mozilla::ipc::IPDLParamTraits<Principal>;
public:
Principal() : mPrincipal(nullptr) {}
@ -42,18 +36,44 @@ class Principal {
RefPtr<nsIPrincipal> mPrincipal;
};
} // namespace IPC
namespace mozilla {
namespace ipc {
template <>
struct ParamTraits<Principal> {
typedef Principal paramType;
static void Write(Message* aMsg, const paramType& aParam) {
WriteParam(aMsg, aParam.mPrincipal);
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aResult) {
return ReadParam(aMsg, aIter, &aResult->mPrincipal);
struct IPDLParamTraits<nsIPrincipal> {
static void Write(IPC::Message* aMsg, IProtocol* aActor,
nsIPrincipal* aParam);
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
IProtocol* aActor, RefPtr<nsIPrincipal>* aResult);
// Overload to support deserializing nsCOMPtr<nsIPrincipal> directly.
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
IProtocol* aActor, nsCOMPtr<nsIPrincipal>* aResult) {
RefPtr<nsIPrincipal> result;
if (!Read(aMsg, aIter, aActor, &result)) {
return false;
}
*aResult = result.forget();
return true;
}
};
} // namespace IPC
template <>
struct IPDLParamTraits<IPC::Principal> {
typedef IPC::Principal paramType;
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const paramType& aParam) {
WriteIPDLParam(aMsg, aActor, aParam.mPrincipal);
}
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
IProtocol* aActor, paramType* aResult) {
return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mPrincipal);
}
};
} // namespace ipc
} // namespace mozilla
#endif // mozilla_dom_permission_message_utils_h__

View File

@ -7,6 +7,7 @@
#include "MediaFormatReader.h"
#include "AllocationPolicy.h"
#include "GeckoProfiler.h"
#include "MediaData.h"
#include "MediaInfo.h"
#include "VideoFrameContainer.h"
@ -2631,6 +2632,7 @@ void MediaFormatReader::SkipVideoDemuxToNextKeyFrame(TimeUnit aTimeThreshold) {
}
void MediaFormatReader::VideoSkipReset(uint32_t aSkipped) {
PROFILER_ADD_MARKER("SkippedVideoDecode", GRAPHICS);
MOZ_ASSERT(OnTaskQueue());
// Some frames may have been output by the decoder since we initiated the

View File

@ -21,7 +21,7 @@ protocol PRDD
parent:
// args TBD, sent by UI process to initiate core settings
async Init(MaybeFileDesc sandboxBroker);
async Init(FileDescriptor? sandboxBroker);
async InitProfiler(Endpoint<PProfilerChild> endpoint);
@ -31,7 +31,7 @@ parent:
async RequestMemoryReport(uint32_t generation,
bool anonymize,
bool minimizeMemoryUsage,
MaybeFileDesc DMDFile);
FileDescriptor? DMDFile);
child:
// args TBD, sent when init complete. Occurs once, after Init().

View File

@ -29,20 +29,20 @@ RDDChild::RDDChild(RDDProcessHost* aHost) : mHost(aHost), mRDDReady(false) {
RDDChild::~RDDChild() { MOZ_COUNT_DTOR(RDDChild); }
bool RDDChild::Init() {
MaybeFileDesc brokerFd = void_t();
Maybe<FileDescriptor> brokerFd;
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
auto policy = SandboxBrokerPolicyFactory::GetUtilityPolicy(OtherPid());
if (policy != nullptr) {
brokerFd = FileDescriptor();
brokerFd = Some(FileDescriptor());
mSandboxBroker =
SandboxBroker::Create(std::move(policy), OtherPid(), brokerFd);
SandboxBroker::Create(std::move(policy), OtherPid(), brokerFd.ref());
// This is unlikely to fail and probably indicates OS resource
// exhaustion, but we can at least try to recover.
if (NS_WARN_IF(mSandboxBroker == nullptr)) {
return false;
}
MOZ_ASSERT(static_cast<const FileDescriptor&>(brokerFd).IsValid());
MOZ_ASSERT(brokerFd.ref().IsValid());
}
#endif // XP_LINUX && MOZ_SANDBOX
@ -85,7 +85,7 @@ mozilla::ipc::IPCResult RDDChild::RecvInitCrashReporter(
bool RDDChild::SendRequestMemoryReport(const uint32_t& aGeneration,
const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile) {
const Maybe<FileDescriptor>& aDMDFile) {
mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
Unused << PRDDChild::SendRequestMemoryReport(aGeneration, aAnonymize,
aMinimizeMemoryUsage, aDMDFile);

View File

@ -49,7 +49,7 @@ class RDDChild final : public PRDDChild {
bool SendRequestMemoryReport(const uint32_t& aGeneration,
const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile);
const Maybe<ipc::FileDescriptor>& aDMDFile);
static void Destroy(UniquePtr<RDDChild>&& aChild);

View File

@ -128,15 +128,16 @@ static void StartRDDMacSandbox() {
}
#endif
mozilla::ipc::IPCResult RDDParent::RecvInit(const MaybeFileDesc& aBrokerFd) {
mozilla::ipc::IPCResult RDDParent::RecvInit(
const Maybe<FileDescriptor>& aBrokerFd) {
Unused << SendInitComplete();
#if defined(MOZ_SANDBOX)
# if defined(XP_MACOSX)
StartRDDMacSandbox();
# elif defined(XP_LINUX)
int fd = -1;
if (aBrokerFd.type() == MaybeFileDesc::TFileDescriptor) {
fd = aBrokerFd.get_FileDescriptor().ClonePlatformHandle().release();
if (aBrokerFd.isSome()) {
fd = aBrokerFd.value().ClonePlatformHandle().release();
}
SetRemoteDataDecoderSandbox(fd);
# endif // XP_MACOSX/XP_LINUX
@ -163,7 +164,7 @@ mozilla::ipc::IPCResult RDDParent::RecvNewContentRemoteDecoderManager(
mozilla::ipc::IPCResult RDDParent::RecvRequestMemoryReport(
const uint32_t& aGeneration, const bool& aAnonymize,
const bool& aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile) {
const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
nsPrintfCString processName("RDD (pid %u)", (unsigned)getpid());
mozilla::dom::MemoryReportRequestClient::Start(

View File

@ -24,7 +24,7 @@ class RDDParent final : public PRDDParent {
bool Init(base::ProcessId aParentPid, const char* aParentBuildID,
MessageLoop* aIOLoop, IPC::Channel* aChannel);
mozilla::ipc::IPCResult RecvInit(const MaybeFileDesc& aBrokerFd);
mozilla::ipc::IPCResult RecvInit(const Maybe<ipc::FileDescriptor>& aBrokerFd);
mozilla::ipc::IPCResult RecvInitProfiler(
Endpoint<PProfilerChild>&& aEndpoint);
@ -32,7 +32,8 @@ class RDDParent final : public PRDDParent {
Endpoint<PRemoteDecoderManagerParent>&& aEndpoint);
mozilla::ipc::IPCResult RecvRequestMemoryReport(
const uint32_t& generation, const bool& anonymize,
const bool& minimizeMemoryUsage, const MaybeFileDesc& DMDFile);
const bool& minimizeMemoryUsage,
const Maybe<ipc::FileDescriptor>& DMDFile);
void ActorDestroy(ActorDestroyReason aWhy) override;

View File

@ -221,10 +221,10 @@ class RDDMemoryReporter : public MemoryReportingProcess {
bool IsAlive() const override { return !!GetChild(); }
bool SendRequestMemoryReport(const uint32_t& aGeneration,
const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const dom::MaybeFileDesc& aDMDFile) override {
bool SendRequestMemoryReport(
const uint32_t& aGeneration, const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const Maybe<ipc::FileDescriptor>& aDMDFile) override {
RDDChild* child = GetChild();
if (!child) {
return false;

View File

@ -10,8 +10,10 @@
# include "mmsystem.h"
#endif
#include "MediaQueue.h"
#include "VideoSink.h"
#include "GeckoProfiler.h"
#include "MediaQueue.h"
#include "VideoUtils.h"
#include "mozilla/IntegerPrintfMacros.h"
@ -451,6 +453,10 @@ void VideoSink::UpdateRenderedVideoFrames() {
}
}
if (droppedCount > 0) {
PROFILER_ADD_MARKER("DroppedUncompositedVideoFrames", GRAPHICS);
}
if (droppedCount || sentToCompositorCount) {
uint32_t totalCompositorDroppedCount = mContainer->GetDroppedImageCount();
uint32_t compositorDroppedCount =

View File

@ -26,7 +26,6 @@
("%s: " arg, __func__, ##__VA_ARGS__))
using namespace mozilla;
using namespace mozilla::gl;
using namespace mozilla::java::sdk;
using media::TimeUnit;

View File

@ -114,7 +114,7 @@ nsresult CreatePrincipalInfo(nsILineInputStream* aStream,
// CSP will be applied during the script load.
nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
aEntry->principal() = mozilla::ipc::ContentPrincipalInfo(
attrs, origin, aEntry->scope(), std::move(policies));
attrs, origin, aEntry->scope(), Nothing(), std::move(policies));
return NS_OK;
}

View File

@ -45,8 +45,7 @@ class CompareCallback {
nsresult Compare(ServiceWorkerRegistrationInfo* aRegistration,
nsIPrincipal* aPrincipal, const nsAString& aCacheName,
const nsAString& aURL, CompareCallback* aCallback,
nsILoadGroup* aLoadGroup);
const nsAString& aURL, CompareCallback* aCallback);
} // namespace serviceWorkerScriptCache

View File

@ -274,7 +274,8 @@ TEST(ServiceWorkerRegistrar, TestWriteData) {
nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
reg.principal() = mozilla::ipc::ContentPrincipalInfo(
mozilla::OriginAttributes(i, i % 2), spec, spec, std::move(policies));
mozilla::OriginAttributes(i, i % 2), spec, spec, mozilla::Nothing(),
std::move(policies));
swr->TestRegisterServiceWorker(reg);
}
@ -863,7 +864,8 @@ TEST(ServiceWorkerRegistrar, TestDedupeWrite) {
nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
reg.principal() = mozilla::ipc::ContentPrincipalInfo(
mozilla::OriginAttributes(0, false), spec, spec, std::move(policies));
mozilla::OriginAttributes(0, false), spec, spec, mozilla::Nothing(),
std::move(policies));
swr->TestRegisterServiceWorker(reg);
}

View File

@ -66,7 +66,6 @@ struct IDWriteRenderingParams;
struct IDWriteFontFace;
struct IDWriteFontCollection;
class GrContext;
class SkCanvas;
struct gfxFontStyle;
@ -1508,13 +1507,6 @@ class DrawTarget : public external::AtomicRefCounted<DrawTarget> {
*/
virtual void DetachAllSnapshots() = 0;
#ifdef USE_SKIA_GPU
virtual bool InitWithGrContext(GrContext *aGrContext, const IntSize &aSize,
SurfaceFormat aFormat) {
MOZ_CRASH("GFX: InitWithGrContext");
}
#endif
protected:
UserData mUserData;
Matrix mTransform;
@ -1749,11 +1741,6 @@ class GFX2D_API Factory {
static Config *sConfig;
public:
#ifdef USE_SKIA_GPU
static already_AddRefed<DrawTarget> CreateDrawTargetSkiaWithGrContext(
GrContext *aGrContext, const IntSize &aSize, SurfaceFormat aFormat);
#endif
static void PurgeAllCaches();
static already_AddRefed<DrawTarget> CreateDualDrawTarget(DrawTarget *targetA,

View File

@ -29,13 +29,6 @@
#include "Swizzle.h"
#include <algorithm>
#ifdef USE_SKIA_GPU
# include "GLDefs.h"
# include "skia/include/gpu/GrContext.h"
# include "skia/include/gpu/GrTexture.h"
# include "skia/include/gpu/gl/GrGLInterface.h"
#endif
#ifdef MOZ_WIDGET_COCOA
# include "BorrowedContext.h"
# include <ApplicationServices/ApplicationServices.h>
@ -649,11 +642,6 @@ void DrawTargetSkia::DrawSurface(SourceSurface* aSurface, const Rect& aDest,
}
DrawTargetType DrawTargetSkia::GetType() const {
#ifdef USE_SKIA_GPU
if (mGrContext) {
return DrawTargetType::HARDWARE_RASTER;
}
#endif
return DrawTargetType::SOFTWARE_RASTER;
}
@ -700,10 +688,9 @@ void DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface* aSurface,
auto shadowDest = IntPoint::Round(aDest + aOffset);
SkBitmap blurMask;
if (!UsingSkiaGPU() && ExtractAlphaBitmap(image, &blurMask)) {
// Prefer using our own box blur instead of Skia's when we're
// not using the GPU. It currently performs much better than
// SkBlurImageFilter or SkBlurMaskFilter on the CPU.
if (ExtractAlphaBitmap(image, &blurMask)) {
// Prefer using our own box blur instead of Skia's. It currently performs
// much better than SkBlurImageFilter or SkBlurMaskFilter on the CPU.
AlphaBoxBlur blur(Rect(0, 0, blurMask.width(), blurMask.height()),
int32_t(blurMask.rowBytes()), aSigma, aSigma);
blur.Blur(reinterpret_cast<uint8_t*>(blurMask.getPixels()));
@ -1587,18 +1574,6 @@ already_AddRefed<SourceSurface> DrawTargetSkia::CreateSourceSurfaceFromData(
already_AddRefed<DrawTarget> DrawTargetSkia::CreateSimilarDrawTarget(
const IntSize& aSize, SurfaceFormat aFormat) const {
RefPtr<DrawTargetSkia> target = new DrawTargetSkia();
#ifdef USE_SKIA_GPU
if (UsingSkiaGPU()) {
// Try to create a GPU draw target first if we're currently using the GPU.
// Mark the DT as cached so that shadow DTs, extracted subrects, and similar
// can be reused.
if (target->InitWithGrContext(mGrContext.get(), aSize, aFormat, true)) {
return target.forget();
}
// Otherwise, just fall back to a software draw target.
}
#endif
#ifdef DEBUG
if (!IsBackedByPixels(mCanvas)) {
// If our canvas is backed by vector storage such as PDF then we want to
@ -1620,57 +1595,9 @@ bool DrawTargetSkia::CanCreateSimilarDrawTarget(const IntSize& aSize,
return size_t(std::max(aSize.width, aSize.height)) < GetMaxSurfaceSize();
}
bool DrawTargetSkia::UsingSkiaGPU() const {
#ifdef USE_SKIA_GPU
return !!mGrContext;
#else
return false;
#endif
}
#ifdef USE_SKIA_GPU
already_AddRefed<SourceSurface> DrawTargetSkia::OptimizeGPUSourceSurface(
SourceSurface* aSurface) const {
// Check if the underlying SkImage already has an associated GrTexture.
sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
if (!image || image->isTextureBacked()) {
RefPtr<SourceSurface> surface(aSurface);
return surface.forget();
}
// Upload the SkImage to a GrTexture otherwise.
sk_sp<SkImage> texture = image->makeTextureImage(mGrContext.get(), nullptr);
if (texture) {
// Create a new SourceSurfaceSkia whose SkImage contains the GrTexture.
RefPtr<SourceSurfaceSkia> surface = new SourceSurfaceSkia();
if (surface->InitFromImage(texture, aSurface->GetFormat())) {
return surface.forget();
}
}
// The data was too big to fit in a GrTexture.
if (aSurface->GetType() == SurfaceType::SKIA) {
// It is already a Skia source surface, so just reuse it as-is.
RefPtr<SourceSurface> surface(aSurface);
return surface.forget();
}
// Wrap it in a Skia source surface so that can do tiled uploads on-demand.
RefPtr<SourceSurfaceSkia> surface = new SourceSurfaceSkia();
surface->InitFromImage(image);
return surface.forget();
}
#endif
already_AddRefed<SourceSurface>
DrawTargetSkia::OptimizeSourceSurfaceForUnknownAlpha(
SourceSurface* aSurface) const {
#ifdef USE_SKIA_GPU
if (UsingSkiaGPU()) {
return OptimizeGPUSourceSurface(aSurface);
}
#endif
if (aSurface->GetType() == SurfaceType::SKIA) {
RefPtr<SourceSurface> surface(aSurface);
return surface.forget();
@ -1690,12 +1617,6 @@ DrawTargetSkia::OptimizeSourceSurfaceForUnknownAlpha(
already_AddRefed<SourceSurface> DrawTargetSkia::OptimizeSourceSurface(
SourceSurface* aSurface) const {
#ifdef USE_SKIA_GPU
if (UsingSkiaGPU()) {
return OptimizeGPUSourceSurface(aSurface);
}
#endif
if (aSurface->GetType() == SurfaceType::SKIA) {
RefPtr<SourceSurface> surface(aSurface);
return surface.forget();
@ -1714,48 +1635,9 @@ already_AddRefed<SourceSurface> DrawTargetSkia::OptimizeSourceSurface(
return dataSurface.forget();
}
#ifdef USE_SKIA_GPU
static inline GrGLenum GfxFormatToGrGLFormat(SurfaceFormat format) {
switch (format) {
case SurfaceFormat::B8G8R8A8:
return LOCAL_GL_BGRA8_EXT;
case SurfaceFormat::B8G8R8X8:
// We probably need to do something here.
return LOCAL_GL_BGRA8_EXT;
case SurfaceFormat::R5G6B5_UINT16:
return LOCAL_GL_RGB565;
case SurfaceFormat::A8:
return LOCAL_GL_ALPHA8;
default:
return LOCAL_GL_RGBA8;
}
}
#endif
already_AddRefed<SourceSurface>
DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(
const NativeSurface& aSurface) const {
#ifdef USE_SKIA_GPU
if (aSurface.mType == NativeSurfaceType::OPENGL_TEXTURE && UsingSkiaGPU()) {
// Wrap the OpenGL texture id in a Skia texture handle.
GrGLTextureInfo texInfo;
texInfo.fTarget = LOCAL_GL_TEXTURE_2D;
texInfo.fID = (GrGLuint)(uintptr_t)aSurface.mSurface;
texInfo.fFormat = GfxFormatToGrGLFormat(aSurface.mFormat);
GrBackendTexture texDesc(aSurface.mSize.width, aSurface.mSize.height,
GrMipMapped::kNo, texInfo);
sk_sp<SkImage> texture = SkImage::MakeFromAdoptedTexture(
mGrContext.get(), texDesc, kTopLeft_GrSurfaceOrigin,
GfxFormatToSkiaColorType(aSurface.mFormat),
GfxFormatToSkiaAlphaType(aSurface.mFormat));
RefPtr<SourceSurfaceSkia> newSurf = new SourceSurfaceSkia();
if (texture && newSurf->InitFromImage(texture, aSurface.mFormat)) {
return newSurf.forget();
}
return nullptr;
}
#endif
return nullptr;
}
@ -1838,55 +1720,6 @@ bool DrawTargetSkia::Init(SkCanvas* aCanvas) {
return true;
}
#ifdef USE_SKIA_GPU
/** Indicating a DT should be cached means that space will be reserved in Skia's
* cache for the render target at creation time, with any unused resources
* exceeding the cache limits being purged. When the DT is freed, it will then
* be guaranteed to be kept around for subsequent allocations until it gets
* incidentally purged.
*
* If it is not marked as cached, no space will be purged to make room for the
* render target in the cache. When the DT is freed, If there is space within
* the resource limits it may be added to the cache, otherwise it will be freed
* immediately if the cache is already full.
*
* If you want to ensure that the resources will be kept around for reuse, it is
* better to mark them as cached. Such resources should be short-lived to ensure
* they don't permanently tie up cache resource limits. Long-lived resources
* should generally be left as uncached.
*
* In neither case will cache resource limits affect whether the resource
* allocation succeeds. The amount of in-use GPU resources is allowed to exceed
* the size of the cache. Thus, only hard GPU out-of-memory conditions will
* cause resource allocation to fail.
*/
bool DrawTargetSkia::InitWithGrContext(GrContext* aGrContext,
const IntSize& aSize,
SurfaceFormat aFormat, bool aCached) {
MOZ_ASSERT(aGrContext, "null GrContext");
if (size_t(std::max(aSize.width, aSize.height)) > GetMaxSurfaceSize()) {
return false;
}
// Create a GPU rendertarget/texture using the supplied GrContext.
// MakeRenderTarget also implicitly clears the underlying texture on creation.
mSurface = SkSurface::MakeRenderTarget(aGrContext, SkBudgeted(aCached),
MakeSkiaImageInfo(aSize, aFormat));
if (!mSurface) {
return false;
}
mGrContext = sk_ref_sp(aGrContext);
mSize = aSize;
mFormat = aFormat;
mCanvas = mSurface->getCanvas();
SetPermitSubpixelAA(IsOpaque(mFormat));
return true;
}
#endif
bool DrawTargetSkia::Init(unsigned char* aData, const IntSize& aSize,
int32_t aStride, SurfaceFormat aFormat,
bool aUninitialized) {
@ -1914,16 +1747,6 @@ void DrawTargetSkia::SetTransform(const Matrix& aTransform) {
}
void* DrawTargetSkia::GetNativeSurface(NativeSurfaceType aType) {
#ifdef USE_SKIA_GPU
if (aType == NativeSurfaceType::OPENGL_TEXTURE && mSurface) {
GrBackendTexture tex =
mSurface->getBackendTexture(SkSurface::kFlushRead_BackendHandleAccess);
GrGLTextureInfo info;
if (tex.getGLTextureInfo(&info)) {
return (void*)(uintptr_t)info.fID;
}
}
#endif
return nullptr;
}

View File

@ -130,18 +130,6 @@ class DrawTargetSkia : public DrawTarget {
SurfaceFormat aFormat, bool aUninitialized = false);
bool Init(SkCanvas *aCanvas);
#ifdef USE_SKIA_GPU
bool InitWithGrContext(GrContext *aGrContext, const IntSize &aSize,
SurfaceFormat aFormat, bool aCached);
virtual bool InitWithGrContext(GrContext *aGrContext, const IntSize &aSize,
SurfaceFormat aFormat) override {
return InitWithGrContext(aGrContext, aSize, aFormat, false);
}
already_AddRefed<SourceSurface> OptimizeGPUSourceSurface(
SourceSurface *aSurface) const;
#endif
// Skia assumes that texture sizes fit in 16-bit signed integers.
static size_t GetMaxSurfaceSize() { return 32767; }
@ -163,8 +151,6 @@ class DrawTargetSkia : public DrawTarget {
const StrokeOptions *aStrokeOptions = nullptr,
const DrawOptions &aOptions = DrawOptions());
bool UsingSkiaGPU() const;
struct PushedLayer {
PushedLayer(bool aOldPermitSubpixelAA, SourceSurface *aMask)
: mOldPermitSubpixelAA(aOldPermitSubpixelAA), mMask(aMask) {}
@ -173,10 +159,6 @@ class DrawTargetSkia : public DrawTarget {
};
std::vector<PushedLayer> mPushedLayers;
#ifdef USE_SKIA_GPU
sk_sp<GrContext> mGrContext;
#endif
IntSize mSize;
sk_sp<SkSurface> mSurface;
SkCanvas *mCanvas;

View File

@ -920,18 +920,6 @@ already_AddRefed<ScaledFont> Factory::CreateScaledFontForDWriteFont(
#endif // WIN32
#ifdef USE_SKIA_GPU
already_AddRefed<DrawTarget> Factory::CreateDrawTargetSkiaWithGrContext(
GrContext* aGrContext, const IntSize& aSize, SurfaceFormat aFormat) {
RefPtr<DrawTarget> newTarget = new DrawTargetSkia();
if (!newTarget->InitWithGrContext(aGrContext, aSize, aFormat)) {
return nullptr;
}
return newTarget.forget();
}
#endif // USE_SKIA_GPU
#ifdef USE_SKIA
already_AddRefed<DrawTarget> Factory::CreateDrawTargetWithSkCanvas(
SkCanvas* aCanvas) {

View File

@ -125,16 +125,6 @@ uint8_t* SourceSurfaceSkia::GetData() {
if (!mImage) {
return nullptr;
}
#ifdef USE_SKIA_GPU
if (mImage->isTextureBacked()) {
if (sk_sp<SkImage> raster =
ReadSkImage(mImage, MakeSkiaImageInfo(mSize, mFormat), mStride)) {
mImage = raster;
} else {
gfxCriticalError() << "Failed making Skia raster image for GPU surface";
}
}
#endif
SkPixmap pixmap;
if (!mImage->peekPixels(&pixmap)) {
gfxCriticalError() << "Failed accessing pixels for Skia raster image";

View File

@ -1447,7 +1447,7 @@ void GLContext::LoadMoreSymbols(const SymbolLoader& loader) {
CORE_SYMBOL(GetTexLevelParameteriv),
END_SYMBOLS};
const bool warnOnFailures = ShouldSpew();
loader.LoadSymbols(devSymbols, warnOnFailures);
(void)loader.LoadSymbols(devSymbols, warnOnFailures);
}
#undef CORE_SYMBOL

View File

@ -1,375 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "skia/include/gpu/GrContext.h"
#include "skia/include/gpu/gl/GrGLInterface.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/ThreadLocal.h"
#include "mozilla/DebugOnly.h"
/* SkPostConfig.h includes windows.h, which includes windef.h
* which redefines min/max. We don't want that. */
#ifdef _WIN32
# undef min
# undef max
#endif
#include "GLContext.h"
#include "SkiaGLGlue.h"
using mozilla::gl::GLContext;
using mozilla::gl::GLFeature;
using mozilla::gl::SkiaGLGlue;
template <typename R, typename... A>
static inline GrGLFunction<R (*)(A...)> WrapGL(RefPtr<GLContext> aContext,
R (GLContext::*aFunc)(A...)) {
return [aContext, aFunc](A... args) -> R {
aContext->MakeCurrent();
return (aContext->*aFunc)(args...);
};
}
template <typename R, typename... A>
static inline GrGLFunction<R (*)(A...)> WrapGL(RefPtr<GLContext> aContext,
R (*aFunc)(GLContext*, A...)) {
return [aContext, aFunc](A... args) -> R {
aContext->MakeCurrent();
return (*aFunc)(aContext, args...);
};
}
// Core GL functions required by Ganesh
static const GLubyte* glGetString_mozilla(GLContext* aContext, GrGLenum aName) {
// GLContext only exposes a OpenGL 2.0 style API, so we have to intercept a
// bunch of checks that Ganesh makes to determine which capabilities are
// present on the GL implementation and change them to match what GLContext
// actually exposes.
if (aName == LOCAL_GL_VERSION) {
if (aContext->IsGLES()) {
return reinterpret_cast<const GLubyte*>("OpenGL ES 2.0");
}
return reinterpret_cast<const GLubyte*>("2.0");
} else if (aName == LOCAL_GL_EXTENSIONS) {
// Only expose the bare minimum extensions we want to support to ensure a
// functional Ganesh as GLContext only exposes certain extensions
static bool extensionsStringBuilt = false;
static char extensionsString[1024];
if (!extensionsStringBuilt) {
extensionsString[0] = '\0';
if (aContext->IsGLES()) {
// OES is only applicable to GLES2
if (aContext->IsExtensionSupported(
GLContext::OES_packed_depth_stencil)) {
strcat(extensionsString, "GL_OES_packed_depth_stencil ");
}
if (aContext->IsExtensionSupported(GLContext::OES_rgb8_rgba8)) {
strcat(extensionsString, "GL_OES_rgb8_rgba8 ");
}
if (aContext->IsExtensionSupported(GLContext::OES_texture_npot)) {
strcat(extensionsString, "GL_OES_texture_npot ");
}
if (aContext->IsExtensionSupported(
GLContext::OES_vertex_array_object)) {
strcat(extensionsString, "GL_OES_vertex_array_object ");
}
if (aContext->IsSupported(GLFeature::standard_derivatives)) {
strcat(extensionsString, "GL_OES_standard_derivatives ");
}
} else {
if (aContext->IsSupported(GLFeature::framebuffer_object)) {
strcat(extensionsString, "GL_ARB_framebuffer_object ");
} else if (aContext->IsExtensionSupported(
GLContext::EXT_framebuffer_object)) {
strcat(extensionsString, "GL_EXT_framebuffer_object ");
}
if (aContext->IsSupported(GLFeature::texture_rg)) {
strcat(extensionsString, "GL_ARB_texture_rg ");
}
}
if (aContext->IsExtensionSupported(
GLContext::EXT_texture_format_BGRA8888)) {
strcat(extensionsString, "GL_EXT_texture_format_BGRA8888 ");
}
if (aContext->IsExtensionSupported(GLContext::EXT_packed_depth_stencil)) {
strcat(extensionsString, "GL_EXT_packed_depth_stencil ");
}
if (aContext->IsExtensionSupported(GLContext::EXT_bgra)) {
strcat(extensionsString, "GL_EXT_bgra ");
}
if (aContext->IsExtensionSupported(GLContext::EXT_read_format_bgra)) {
strcat(extensionsString, "GL_EXT_read_format_bgra ");
}
extensionsStringBuilt = true;
#ifdef DEBUG
printf_stderr("Exported SkiaGL extensions: %s\n", extensionsString);
#endif
}
return reinterpret_cast<const GLubyte*>(extensionsString);
} else if (aName == LOCAL_GL_SHADING_LANGUAGE_VERSION) {
if (aContext->IsGLES()) {
return reinterpret_cast<const GLubyte*>("OpenGL ES GLSL ES 1.0");
}
return reinterpret_cast<const GLubyte*>("1.10");
}
return aContext->fGetString(aName);
}
static GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context) {
auto* i = new GrGLInterface();
context->MakeCurrent();
// We support both desktop GL and GLES2
if (context->IsGLES()) {
i->fStandard = kGLES_GrGLStandard;
} else {
i->fStandard = kGL_GrGLStandard;
}
GrGLFunction<GrGLGetStringFn> getString =
WrapGL(context, &glGetString_mozilla);
GrGLFunction<GrGLGetIntegervFn> getIntegerv =
WrapGL(context, &GLContext::fGetIntegerv);
GrGLExtensions extensions;
if (!extensions.init(i->fStandard, getString, nullptr, getIntegerv)) {
delete i;
return nullptr;
}
i->fExtensions.swap(&extensions);
// Core GL functions required by Ganesh
i->fFunctions.fActiveTexture = WrapGL(context, &GLContext::fActiveTexture);
i->fFunctions.fAttachShader = WrapGL(context, &GLContext::fAttachShader);
i->fFunctions.fBindAttribLocation =
WrapGL(context, &GLContext::fBindAttribLocation);
i->fFunctions.fBindBuffer = WrapGL(context, &GLContext::fBindBuffer);
i->fFunctions.fBindFramebuffer =
WrapGL(context, &GLContext::fBindFramebuffer);
i->fFunctions.fBindRenderbuffer =
WrapGL(context, &GLContext::fBindRenderbuffer);
i->fFunctions.fBindTexture = WrapGL(context, &GLContext::fBindTexture);
i->fFunctions.fBlendFunc = WrapGL(context, &GLContext::fBlendFunc);
i->fFunctions.fBlendColor = WrapGL(context, &GLContext::fBlendColor);
i->fFunctions.fBlendEquation = WrapGL(context, &GLContext::fBlendEquation);
i->fFunctions.fBufferData = WrapGL(context, &GLContext::fBufferData);
i->fFunctions.fBufferSubData = WrapGL(context, &GLContext::fBufferSubData);
i->fFunctions.fCheckFramebufferStatus =
WrapGL(context, &GLContext::fCheckFramebufferStatus);
i->fFunctions.fClear = WrapGL(context, &GLContext::fClear);
i->fFunctions.fClearColor = WrapGL(context, &GLContext::fClearColor);
i->fFunctions.fClearStencil = WrapGL(context, &GLContext::fClearStencil);
i->fFunctions.fColorMask = WrapGL(context, &GLContext::fColorMask);
i->fFunctions.fCompileShader = WrapGL(context, &GLContext::fCompileShader);
i->fFunctions.fCompressedTexImage2D =
WrapGL(context, &GLContext::fCompressedTexImage2D);
i->fFunctions.fCompressedTexSubImage2D =
WrapGL(context, &GLContext::fCompressedTexSubImage2D);
i->fFunctions.fCopyTexSubImage2D =
WrapGL(context, &GLContext::fCopyTexSubImage2D);
i->fFunctions.fCreateProgram = WrapGL(context, &GLContext::fCreateProgram);
i->fFunctions.fCreateShader = WrapGL(context, &GLContext::fCreateShader);
i->fFunctions.fCullFace = WrapGL(context, &GLContext::fCullFace);
i->fFunctions.fDeleteBuffers = WrapGL(context, &GLContext::fDeleteBuffers);
i->fFunctions.fDeleteFramebuffers =
WrapGL(context, &GLContext::fDeleteFramebuffers);
i->fFunctions.fDeleteProgram = WrapGL(context, &GLContext::fDeleteProgram);
i->fFunctions.fDeleteRenderbuffers =
WrapGL(context, &GLContext::fDeleteRenderbuffers);
i->fFunctions.fDeleteShader = WrapGL(context, &GLContext::fDeleteShader);
i->fFunctions.fDeleteTextures = WrapGL(context, &GLContext::fDeleteTextures);
i->fFunctions.fDepthMask = WrapGL(context, &GLContext::fDepthMask);
i->fFunctions.fDisable = WrapGL(context, &GLContext::fDisable);
i->fFunctions.fDisableVertexAttribArray =
WrapGL(context, &GLContext::fDisableVertexAttribArray);
i->fFunctions.fDrawArrays = WrapGL(context, &GLContext::fDrawArrays);
i->fFunctions.fDrawElements = WrapGL(context, &GLContext::fDrawElements);
i->fFunctions.fDrawRangeElements =
WrapGL(context, &GLContext::fDrawRangeElements);
i->fFunctions.fEnable = WrapGL(context, &GLContext::fEnable);
i->fFunctions.fEnableVertexAttribArray =
WrapGL(context, &GLContext::fEnableVertexAttribArray);
i->fFunctions.fFinish = WrapGL(context, &GLContext::fFinish);
i->fFunctions.fFlush = WrapGL(context, &GLContext::fFlush);
i->fFunctions.fFramebufferRenderbuffer =
WrapGL(context, &GLContext::fFramebufferRenderbuffer);
i->fFunctions.fFramebufferTexture2D =
WrapGL(context, &GLContext::fFramebufferTexture2D);
i->fFunctions.fFrontFace = WrapGL(context, &GLContext::fFrontFace);
i->fFunctions.fGenBuffers = WrapGL(context, &GLContext::fGenBuffers);
i->fFunctions.fGenFramebuffers =
WrapGL(context, &GLContext::fGenFramebuffers);
i->fFunctions.fGenRenderbuffers =
WrapGL(context, &GLContext::fGenRenderbuffers);
i->fFunctions.fGetFramebufferAttachmentParameteriv =
WrapGL(context, &GLContext::fGetFramebufferAttachmentParameteriv);
i->fFunctions.fGenTextures = WrapGL(context, &GLContext::fGenTextures);
i->fFunctions.fGenerateMipmap = WrapGL(context, &GLContext::fGenerateMipmap);
i->fFunctions.fGetBufferParameteriv =
WrapGL(context, &GLContext::fGetBufferParameteriv);
i->fFunctions.fGetError = WrapGL(context, &GLContext::fGetError);
i->fFunctions.fGetIntegerv = getIntegerv;
i->fFunctions.fGetProgramInfoLog =
WrapGL(context, &GLContext::fGetProgramInfoLog);
i->fFunctions.fGetProgramiv = WrapGL(context, &GLContext::fGetProgramiv);
i->fFunctions.fGetRenderbufferParameteriv =
WrapGL(context, &GLContext::fGetRenderbufferParameteriv);
i->fFunctions.fGetShaderInfoLog =
WrapGL(context, &GLContext::fGetShaderInfoLog);
i->fFunctions.fGetShaderiv = WrapGL(context, &GLContext::fGetShaderiv);
i->fFunctions.fGetShaderPrecisionFormat =
WrapGL(context, &GLContext::fGetShaderPrecisionFormat);
i->fFunctions.fGetString = getString;
i->fFunctions.fGetUniformLocation =
WrapGL(context, &GLContext::fGetUniformLocation);
i->fFunctions.fIsTexture = WrapGL(context, &GLContext::fIsTexture);
i->fFunctions.fLineWidth = WrapGL(context, &GLContext::fLineWidth);
i->fFunctions.fLinkProgram = WrapGL(context, &GLContext::fLinkProgram);
i->fFunctions.fPixelStorei = WrapGL(context, &GLContext::fPixelStorei);
i->fFunctions.fPolygonMode = WrapGL(context, &GLContext::fPolygonMode);
i->fFunctions.fReadPixels = WrapGL(context, &GLContext::fReadPixels);
i->fFunctions.fRenderbufferStorage =
WrapGL(context, &GLContext::fRenderbufferStorage);
i->fFunctions.fScissor = WrapGL(context, &GLContext::fScissor);
i->fFunctions.fShaderSource = WrapGL(context, &GLContext::fShaderSource);
i->fFunctions.fStencilFunc = WrapGL(context, &GLContext::fStencilFunc);
i->fFunctions.fStencilFuncSeparate =
WrapGL(context, &GLContext::fStencilFuncSeparate);
i->fFunctions.fStencilMask = WrapGL(context, &GLContext::fStencilMask);
i->fFunctions.fStencilMaskSeparate =
WrapGL(context, &GLContext::fStencilMaskSeparate);
i->fFunctions.fStencilOp = WrapGL(context, &GLContext::fStencilOp);
i->fFunctions.fStencilOpSeparate =
WrapGL(context, &GLContext::fStencilOpSeparate);
i->fFunctions.fTexImage2D = WrapGL(context, &GLContext::fTexImage2D);
i->fFunctions.fTexParameteri = WrapGL(context, &GLContext::fTexParameteri);
i->fFunctions.fTexParameteriv = WrapGL(context, &GLContext::fTexParameteriv);
i->fFunctions.fTexSubImage2D = WrapGL(context, &GLContext::fTexSubImage2D);
i->fFunctions.fUniform1f = WrapGL(context, &GLContext::fUniform1f);
i->fFunctions.fUniform1i = WrapGL(context, &GLContext::fUniform1i);
i->fFunctions.fUniform1fv = WrapGL(context, &GLContext::fUniform1fv);
i->fFunctions.fUniform1iv = WrapGL(context, &GLContext::fUniform1iv);
i->fFunctions.fUniform2f = WrapGL(context, &GLContext::fUniform2f);
i->fFunctions.fUniform2i = WrapGL(context, &GLContext::fUniform2i);
i->fFunctions.fUniform2fv = WrapGL(context, &GLContext::fUniform2fv);
i->fFunctions.fUniform2iv = WrapGL(context, &GLContext::fUniform2iv);
i->fFunctions.fUniform3f = WrapGL(context, &GLContext::fUniform3f);
i->fFunctions.fUniform3i = WrapGL(context, &GLContext::fUniform3i);
i->fFunctions.fUniform3fv = WrapGL(context, &GLContext::fUniform3fv);
i->fFunctions.fUniform3iv = WrapGL(context, &GLContext::fUniform3iv);
i->fFunctions.fUniform4f = WrapGL(context, &GLContext::fUniform4f);
i->fFunctions.fUniform4i = WrapGL(context, &GLContext::fUniform4i);
i->fFunctions.fUniform4fv = WrapGL(context, &GLContext::fUniform4fv);
i->fFunctions.fUniform4iv = WrapGL(context, &GLContext::fUniform4iv);
i->fFunctions.fUniformMatrix2fv =
WrapGL(context, &GLContext::fUniformMatrix2fv);
i->fFunctions.fUniformMatrix3fv =
WrapGL(context, &GLContext::fUniformMatrix3fv);
i->fFunctions.fUniformMatrix4fv =
WrapGL(context, &GLContext::fUniformMatrix4fv);
i->fFunctions.fUseProgram = WrapGL(context, &GLContext::fUseProgram);
i->fFunctions.fVertexAttrib1f = WrapGL(context, &GLContext::fVertexAttrib1f);
i->fFunctions.fVertexAttrib2fv =
WrapGL(context, &GLContext::fVertexAttrib2fv);
i->fFunctions.fVertexAttrib3fv =
WrapGL(context, &GLContext::fVertexAttrib3fv);
i->fFunctions.fVertexAttrib4fv =
WrapGL(context, &GLContext::fVertexAttrib4fv);
i->fFunctions.fVertexAttribPointer =
WrapGL(context, &GLContext::fVertexAttribPointer);
i->fFunctions.fViewport = WrapGL(context, &GLContext::fViewport);
// Required for either desktop OpenGL 2.0 or OpenGL ES 2.0
i->fFunctions.fStencilFuncSeparate =
WrapGL(context, &GLContext::fStencilFuncSeparate);
i->fFunctions.fStencilMaskSeparate =
WrapGL(context, &GLContext::fStencilMaskSeparate);
i->fFunctions.fStencilOpSeparate =
WrapGL(context, &GLContext::fStencilOpSeparate);
// GLContext supports glMapBuffer
i->fFunctions.fMapBuffer = WrapGL(context, &GLContext::fMapBuffer);
i->fFunctions.fUnmapBuffer = WrapGL(context, &GLContext::fUnmapBuffer);
// GLContext supports glRenderbufferStorageMultisample/glBlitFramebuffer
i->fFunctions.fRenderbufferStorageMultisample =
WrapGL(context, &GLContext::fRenderbufferStorageMultisample);
i->fFunctions.fBlitFramebuffer =
WrapGL(context, &GLContext::fBlitFramebuffer);
// GLContext supports glCompressedTexImage2D
i->fFunctions.fCompressedTexImage2D =
WrapGL(context, &GLContext::fCompressedTexImage2D);
// GL_OES_vertex_array_object
i->fFunctions.fBindVertexArray =
WrapGL(context, &GLContext::fBindVertexArray);
i->fFunctions.fDeleteVertexArrays =
WrapGL(context, &GLContext::fDeleteVertexArrays);
i->fFunctions.fGenVertexArrays =
WrapGL(context, &GLContext::fGenVertexArrays);
// Desktop GL
i->fFunctions.fGetTexLevelParameteriv =
WrapGL(context, &GLContext::fGetTexLevelParameteriv);
i->fFunctions.fDrawBuffer = WrapGL(context, &GLContext::fDrawBuffer);
i->fFunctions.fReadBuffer = WrapGL(context, &GLContext::fReadBuffer);
// Desktop OpenGL > 1.5
i->fFunctions.fGenQueries = WrapGL(context, &GLContext::fGenQueries);
i->fFunctions.fDeleteQueries = WrapGL(context, &GLContext::fDeleteQueries);
i->fFunctions.fBeginQuery = WrapGL(context, &GLContext::fBeginQuery);
i->fFunctions.fEndQuery = WrapGL(context, &GLContext::fEndQuery);
i->fFunctions.fGetQueryiv = WrapGL(context, &GLContext::fGetQueryiv);
i->fFunctions.fGetQueryObjectiv =
WrapGL(context, &GLContext::fGetQueryObjectiv);
i->fFunctions.fGetQueryObjectuiv =
WrapGL(context, &GLContext::fGetQueryObjectuiv);
// Desktop OpenGL > 2.0
i->fFunctions.fDrawBuffers = WrapGL(context, &GLContext::fDrawBuffers);
return i;
}
SkiaGLGlue::SkiaGLGlue(GLContext* context) : mGLContext(context) {
mGrGLInterface.reset(CreateGrGLInterfaceFromGLContext(mGLContext));
mGrContext = GrContext::MakeGL(mGrGLInterface);
}
SkiaGLGlue::~SkiaGLGlue() {
/*
* These members have inter-dependencies, but do not keep each other alive, so
* destruction order is very important here: mGrContext uses mGrGLInterface,
* and through it, uses mGLContext
*/
mGrContext = nullptr;
if (mGrGLInterface) {
// Ensure that no references to the GLContext remain, even if the GrContext
// still lives.
mGrGLInterface->fFunctions = GrGLInterface::Functions();
mGrGLInterface = nullptr;
}
mGLContext = nullptr;
}

View File

@ -1,63 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef SKIA_GL_GLUE_H_
#define SKIA_GL_GLUE_H_
#ifdef USE_SKIA_GPU
# include "skia/include/core/SkRefCnt.h"
# include "mozilla/RefPtr.h"
struct GrGLInterface;
class GrContext;
namespace mozilla {
namespace gl {
class GLContext;
class SkiaGLGlue : public GenericAtomicRefCounted {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SkiaGLGlue, override)
explicit SkiaGLGlue(GLContext* context);
GLContext* GetGLContext() const { return mGLContext.get(); }
GrContext* GetGrContext() const { return mGrContext.get(); }
protected:
virtual ~SkiaGLGlue();
private:
RefPtr<GLContext> mGLContext;
sk_sp<GrGLInterface> mGrGLInterface;
sk_sp<GrContext> mGrContext;
};
} // namespace gl
} // namespace mozilla
#else // USE_SKIA_GPU
class GrContext;
namespace mozilla {
namespace gl {
class GLContext;
class SkiaGLGlue : public GenericAtomicRefCounted {
public:
SkiaGLGlue(GLContext* context);
GLContext* GetGLContext() const { return nullptr; }
GrContext* GetGrContext() const { return nullptr; }
};
} // namespace gl
} // namespace mozilla
#endif // USE_SKIA_GPU
#endif // SKIA_GL_GLUE_H_

View File

@ -74,14 +74,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
'SharedSurfaceANGLE.cpp',
'SharedSurfaceD3D11Interop.cpp',
]
if CONFIG['MOZ_ENABLE_SKIA_GPU']:
EXPORTS += ['SkiaGLGlue.h']
SOURCES += [
'SkiaGLGlue.cpp',
]
if CONFIG['CC_TYPE'] == 'clang':
# Suppress warnings from Skia header files.
SOURCES['SkiaGLGlue.cpp'].flags += ['-Wno-implicit-fallthrough']
if gl_provider == 'CGL':
# These files include Mac headers that are unfriendly to unified builds

View File

@ -240,7 +240,7 @@ mozilla::ipc::IPCResult GPUChild::RecvNotifyDeviceReset(
bool GPUChild::SendRequestMemoryReport(const uint32_t& aGeneration,
const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile) {
const Maybe<FileDescriptor>& aDMDFile) {
mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
Unused << PGPUChild::SendRequestMemoryReport(aGeneration, aAnonymize,
aMinimizeMemoryUsage, aDMDFile);

View File

@ -78,7 +78,7 @@ class GPUChild final : public PGPUChild, public gfxVarReceiver {
bool SendRequestMemoryReport(const uint32_t& aGeneration,
const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile);
const Maybe<ipc::FileDescriptor>& aDMDFile);
static void Destroy(UniquePtr<GPUChild>&& aChild);

View File

@ -444,7 +444,7 @@ void GPUParent::GetGPUProcessName(nsACString& aStr) {
mozilla::ipc::IPCResult GPUParent::RecvRequestMemoryReport(
const uint32_t& aGeneration, const bool& aAnonymize,
const bool& aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile) {
const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
nsAutoCString processName;
GetGPUProcessName(processName);

View File

@ -74,7 +74,8 @@ class GPUParent final : public PGPUParent {
mozilla::ipc::IPCResult RecvNotifyGpuObservers(const nsCString& aTopic);
mozilla::ipc::IPCResult RecvRequestMemoryReport(
const uint32_t& generation, const bool& anonymize,
const bool& minimizeMemoryUsage, const MaybeFileDesc& DMDFile);
const bool& minimizeMemoryUsage,
const Maybe<ipc::FileDescriptor>& DMDFile);
mozilla::ipc::IPCResult RecvShutdownVR();
void ActorDestroy(ActorDestroyReason aWhy) override;

View File

@ -1037,7 +1037,7 @@ class GPUMemoryReporter : public MemoryReportingProcess {
bool SendRequestMemoryReport(const uint32_t& aGeneration,
const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const dom::MaybeFileDesc& aDMDFile) override {
const Maybe<FileDescriptor>& aDMDFile) override {
GPUChild* child = GetChild();
if (!child) {
return false;

Some files were not shown because too many files have changed in this diff Show More