mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-03 12:35:58 +00:00
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
commit
6b94d177d1
@ -26,7 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="errorLongContent">
|
<div id="errorLongContent">
|
||||||
<div id="errorLongDesc">
|
<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>
|
<p data-l10n-id="restart-required-description"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -261,7 +261,7 @@ var CaptivePortalWatcher = {
|
|||||||
|
|
||||||
gBrowser.selectedTab = tab;
|
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.
|
// When we are no longer captive, close the tab if it's at the canonical URL.
|
||||||
let tabCloser = () => {
|
let tabCloser = () => {
|
||||||
|
@ -44,8 +44,6 @@ async function submitForm(event) {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
let input = document.getElementById("sync-input");
|
let input = document.getElementById("sync-input");
|
||||||
input.disabled = true;
|
|
||||||
document.getElementById("sync-button").disabled = true;
|
|
||||||
|
|
||||||
let { flowId, flowBeginTime } = await metrics;
|
let { flowId, flowBeginTime } = await metrics;
|
||||||
|
|
||||||
@ -59,6 +57,7 @@ async function submitForm(event) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
window.open(requestURL, "_blank", "noopener");
|
window.open(requestURL, "_blank", "noopener");
|
||||||
|
document.getElementById("sync").hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const endpoint = RPMGetFxAccountsEndpoint(ENTRYPOINT);
|
const endpoint = RPMGetFxAccountsEndpoint(ENTRYPOINT);
|
||||||
|
@ -2429,7 +2429,8 @@
|
|||||||
if (event.originalTarget.classList.contains("tab-icon-sound") ||
|
if (event.originalTarget.classList.contains("tab-icon-sound") ||
|
||||||
(event.originalTarget.classList.contains("tab-icon-overlay") &&
|
(event.originalTarget.classList.contains("tab-icon-overlay") &&
|
||||||
(event.originalTarget.hasAttribute("soundplaying") ||
|
(event.originalTarget.hasAttribute("soundplaying") ||
|
||||||
event.originalTarget.hasAttribute("muted")))) {
|
event.originalTarget.hasAttribute("muted") ||
|
||||||
|
event.originalTarget.hasAttribute("activemedia-blocked")))) {
|
||||||
if (this.multiselected) {
|
if (this.multiselected) {
|
||||||
gBrowser.toggleMuteAudioOnMultiSelectedTabs(this);
|
gBrowser.toggleMuteAudioOnMultiSelectedTabs(this);
|
||||||
} else {
|
} else {
|
||||||
|
@ -27,10 +27,9 @@ add_task(async function findbar_test() {
|
|||||||
ok(!gFindBar.hidden, "the Find bar isn't hidden after the location of a " +
|
ok(!gFindBar.hidden, "the Find bar isn't hidden after the location of a " +
|
||||||
"subdocument changes");
|
"subdocument changes");
|
||||||
|
|
||||||
let findBarClosePromise = promiseWaitForEvent(gBrowser, "findbarclose");
|
let findBarClosePromise = BrowserTestUtils.waitForEvent(gBrowser, "findbarclose");
|
||||||
gFindBar.close();
|
gFindBar.close();
|
||||||
await findBarClosePromise;
|
await findBarClosePromise;
|
||||||
|
|
||||||
gBrowser.removeTab(newTab);
|
gBrowser.removeTab(newTab);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ prefs =
|
|||||||
# Skip migration work in BG__migrateUI for browser_startup.js since it isn't
|
# Skip migration work in BG__migrateUI for browser_startup.js since it isn't
|
||||||
# representative of common startup.
|
# representative of common startup.
|
||||||
browser.migration.version=9999999
|
browser.migration.version=9999999
|
||||||
|
browser.urlbar.quantumbar=true
|
||||||
browser.startup.record=true
|
browser.startup.record=true
|
||||||
gfx.canvas.willReadFrequently.enable=true
|
gfx.canvas.willReadFrequently.enable=true
|
||||||
# The form autofill framescript is only used in certain locales if this
|
# The form autofill framescript is only used in certain locales if this
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// There are a _lot_ of reflows in this test, and processing them takes
|
// This tests searching in the urlbar (a.k.a. the quantumbar).
|
||||||
// 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
|
* 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.
|
* for tips on how to do that.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* These reflows happen only the first time the awesomebar panel opens. */
|
/* These reflows happen only the first time the panel opens. */
|
||||||
const EXPECTED_REFLOWS_FIRST_OPEN = [];
|
const EXPECTED_REFLOWS_FIRST_OPEN = [
|
||||||
if (AppConstants.platform != "macosx" &&
|
// This is the this.panel.openPopup() call in UrlbarView._openPanel. See bug
|
||||||
(AppConstants.DEBUG ||
|
// 1359989, which was filed against the legacy awesomebar but applies here too
|
||||||
AppConstants.platform == "win")) {
|
// because it seems to be caused by platform code.
|
||||||
EXPECTED_REFLOWS_FIRST_OPEN.push({
|
{
|
||||||
|
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: [
|
stack: [
|
||||||
"__rebuild@chrome://browser/content/search/search-one-offs.js",
|
"__rebuild@chrome://browser/content/search/search-one-offs.js",
|
||||||
/* This is limited to a one-line stack, because the next item is an async
|
/* 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.
|
function and as such not supported on all trees, according to bug 1501761.
|
||||||
"async*set popup@chrome://browser/content/search/search-one-offs.js",
|
"async*_rebuild@chrome://browser/content/search/search-one-offs.js",
|
||||||
"_syncOneOffSearchesEnabled@chrome://browser/content/urlbarBindings.xml",
|
"async*_on_popupshowing@chrome://browser/content/search/search-one-offs.js",
|
||||||
"toggleOneOffSearches@chrome://browser/content/urlbarBindings.xml",
|
"handleEvent@chrome://browser/content/search/search-one-offs.js",
|
||||||
"_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
|
"_openPanel@resource:///modules/UrlbarView.jsm",
|
||||||
"@chrome://browser/content/urlbarBindings.xml",
|
"onQueryResults@resource:///modules/UrlbarView.jsm",
|
||||||
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
"_notify@resource:///modules/UrlbarController.jsm",
|
||||||
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
"receiveResults@resource:///modules/UrlbarController.jsm",
|
||||||
"openPopup@chrome://global/content/bindings/autocomplete.xml",
|
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
|
||||||
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",*/
|
"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.
|
|
||||||
},
|
},
|
||||||
|
];
|
||||||
|
|
||||||
{
|
add_task(async function quantumbar() {
|
||||||
stack: [
|
await runUrlbarTest(false, true, EXPECTED_REFLOWS_FIRST_OPEN);
|
||||||
"_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);
|
|
||||||
});
|
});
|
||||||
|
@ -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);
|
||||||
|
});
|
@ -1,8 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// There are a _lot_ of reflows in this test, and processing them takes
|
// This tests searching in the urlbar (a.k.a. the quantumbar).
|
||||||
// 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
|
* 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.
|
* for tips on how to do that.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* These reflows happen only the first time the awesomebar panel opens. */
|
/* These reflows happen only the first time the panel opens. */
|
||||||
const EXPECTED_REFLOWS_FIRST_OPEN = [];
|
const EXPECTED_REFLOWS_FIRST_OPEN = [
|
||||||
if (AppConstants.platform != "macosx" &&
|
{
|
||||||
(AppConstants.DEBUG ||
|
stack: [
|
||||||
AppConstants.platform == "linux" ||
|
"_openPanel@resource:///modules/UrlbarView.jsm",
|
||||||
AppConstants.isPlatformAndVersionAtLeast("win", "10"))) {
|
"onQueryResults@resource:///modules/UrlbarView.jsm",
|
||||||
EXPECTED_REFLOWS_FIRST_OPEN.push({
|
"_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: [
|
stack: [
|
||||||
"__rebuild@chrome://browser/content/search/search-one-offs.js",
|
"__rebuild@chrome://browser/content/search/search-one-offs.js",
|
||||||
/* This is limited to a one-line stack, because the next item is an async
|
/* 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.
|
function and as such not supported on all trees, according to bug 1501761.
|
||||||
"async*set popup@chrome://browser/content/search/search-one-offs.js",
|
"async*_rebuild@chrome://browser/content/search/search-one-offs.js",
|
||||||
"_syncOneOffSearchesEnabled@chrome://browser/content/urlbarBindings.xml",
|
"async*_on_popupshowing@chrome://browser/content/search/search-one-offs.js",
|
||||||
"toggleOneOffSearches@chrome://browser/content/urlbarBindings.xml",
|
"handleEvent@chrome://browser/content/search/search-one-offs.js",
|
||||||
"_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
|
"_openPanel@resource:///modules/UrlbarView.jsm",
|
||||||
"@chrome://browser/content/urlbarBindings.xml",
|
"onQueryResults@resource:///modules/UrlbarView.jsm",
|
||||||
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
"_notify@resource:///modules/UrlbarController.jsm",
|
||||||
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
"receiveResults@resource:///modules/UrlbarController.jsm",
|
||||||
"openPopup@chrome://global/content/bindings/autocomplete.xml",
|
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
|
||||||
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",*/
|
"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: 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",
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
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() {
|
add_task(async function quantumbar() {
|
||||||
await addDummyHistoryEntries(SEARCH_TERM);
|
await runUrlbarTest(false, false, EXPECTED_REFLOWS_FIRST_OPEN,
|
||||||
});
|
EXPECTED_REFLOWS_SECOND_OPEN);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
});
|
});
|
||||||
|
@ -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);
|
||||||
|
});
|
@ -1,10 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
ChromeUtils.defineModuleGetter(this, "PlacesUtils",
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
"resource://gre/modules/PlacesUtils.jsm");
|
PlacesTestUtils: "resource://testing-common/PlacesTestUtils.jsm",
|
||||||
ChromeUtils.defineModuleGetter(this, "PlacesTestUtils",
|
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
|
||||||
"resource://testing-common/PlacesTestUtils.jsm");
|
UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.jsm",
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function can be called if the test needs to trigger frame dirtying
|
* 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;
|
let frames = await promiseFrames;
|
||||||
reportUnexpectedFlicker(frames, exceptions.frames);
|
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);
|
||||||
|
}
|
||||||
|
@ -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)
|
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
const AUTOPLAY_PAGE = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com") + "browser_autoplay_blocked.html";
|
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() {
|
function openIdentityPopup() {
|
||||||
let promise = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
|
let promise = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
|
||||||
gIdentityHandler._identityBox.click();
|
gIdentityHandler._identityBox.click();
|
||||||
@ -21,8 +24,28 @@ function autoplayBlockedIcon() {
|
|||||||
".blocked-permission-icon.autoplay-media-icon");
|
".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() {
|
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() {
|
await BrowserTestUtils.withNewTab(AUTOPLAY_PAGE, async function() {
|
||||||
let permissionsList = document.getElementById("identity-popup-permission-list");
|
let permissionsList = document.getElementById("identity-popup-permission-list");
|
||||||
@ -35,21 +58,17 @@ add_task(async function testMainViewVisible() {
|
|||||||
await closeIdentityPopup();
|
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) {
|
await BrowserTestUtils.withNewTab(AUTOPLAY_PAGE, async function(browser) {
|
||||||
let permissionsList = document.getElementById("identity-popup-permission-list");
|
let permissionsList = document.getElementById("identity-popup-permission-list");
|
||||||
let emptyLabel = permissionsList.nextElementSibling.nextElementSibling;
|
let emptyLabel = permissionsList.nextElementSibling.nextElementSibling;
|
||||||
|
|
||||||
if (BrowserTestUtils.is_hidden(autoplayBlockedIcon())) {
|
await blockedIconShown(browser);
|
||||||
// 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 openIdentityPopup();
|
await openIdentityPopup();
|
||||||
ok(BrowserTestUtils.is_hidden(emptyLabel), "List of permissions is not empty");
|
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");
|
let labels = permissionsList.querySelectorAll(".identity-popup-permission-label");
|
||||||
is(labels.length, 1, "One permission visible in main view");
|
is(labels.length, 1, "One permission visible in main view");
|
||||||
is(labels[0].textContent, labelText, "Correct value");
|
is(labels[0].textContent, labelText, "Correct value");
|
||||||
@ -70,10 +89,62 @@ add_task(async function testMainViewVisible() {
|
|||||||
await closeIdentityPopup();
|
await closeIdentityPopup();
|
||||||
|
|
||||||
let uri = Services.io.newURI(AUTOPLAY_PAGE);
|
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);
|
Assert.equal(state, SitePermissions.ALLOW);
|
||||||
});
|
});
|
||||||
|
|
||||||
Services.perms.removeAll();
|
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();
|
||||||
});
|
});
|
||||||
|
@ -8,12 +8,11 @@ var {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm
|
|||||||
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
|
|
||||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
||||||
ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
|
ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
|
||||||
|
ExtensionSettingsStore: "resource://gre/modules/ExtensionSettingsStore.jsm",
|
||||||
|
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||||
ShellService: "resource:///modules/ShellService.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,
|
// If the extension does not have private browsing permission,
|
||||||
// use about:privatebrowsing.
|
// use about:privatebrowsing.
|
||||||
if (aboutNewTabService.newTabURL.startsWith("moz-extension")) {
|
let extensionInfo = ExtensionSettingsStore.getSetting("url_overrides", "newTabURL");
|
||||||
let url = new URL(aboutNewTabService.newTabURL);
|
if (extensionInfo) {
|
||||||
if (!WebExtensionPolicy.getByHostname(url.hostname).privateBrowsingAllowed) {
|
let policy = WebExtensionPolicy.getByID(extensionInfo.id);
|
||||||
|
if (!policy || !policy.privateBrowsingAllowed) {
|
||||||
return "about:privatebrowsing";
|
return "about:privatebrowsing";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ BROWSER_CHROME_MANIFESTS += [
|
|||||||
'content/test/pageinfo/browser.ini',
|
'content/test/pageinfo/browser.ini',
|
||||||
'content/test/performance/browser.ini',
|
'content/test/performance/browser.ini',
|
||||||
'content/test/performance/hidpi/browser.ini',
|
'content/test/performance/hidpi/browser.ini',
|
||||||
|
'content/test/performance/legacyurlbar/browser.ini',
|
||||||
'content/test/performance/lowdpi/browser.ini',
|
'content/test/performance/lowdpi/browser.ini',
|
||||||
'content/test/permissions/browser.ini',
|
'content/test/permissions/browser.ini',
|
||||||
'content/test/plugins/browser.ini',
|
'content/test/plugins/browser.ini',
|
||||||
|
@ -209,7 +209,7 @@ function openBrowserWindow(cmdLine, triggeringPrincipal, urlOrUrlList, postData
|
|||||||
let args;
|
let args;
|
||||||
if (!urlOrUrlList) {
|
if (!urlOrUrlList) {
|
||||||
// Just pass in the defaultArgs directly. We'll use system principal on the other end.
|
// Just pass in the defaultArgs directly. We'll use system principal on the other end.
|
||||||
args = [gBrowserContentHandler.getDefaultArgs(forcePrivate)];
|
args = [gBrowserContentHandler.defaultArgs];
|
||||||
} else {
|
} else {
|
||||||
let pService = Cc["@mozilla.org/toolkit/profile-service;1"].
|
let pService = Cc["@mozilla.org/toolkit/profile-service;1"].
|
||||||
getService(Ci.nsIToolkitProfileService);
|
getService(Ci.nsIToolkitProfileService);
|
||||||
@ -520,7 +520,7 @@ nsBrowserContentHandler.prototype = {
|
|||||||
|
|
||||||
/* nsIBrowserHandler */
|
/* nsIBrowserHandler */
|
||||||
|
|
||||||
getDefaultArgs(forcePrivate = false) {
|
get defaultArgs() {
|
||||||
var prefb = Services.prefs;
|
var prefb = Services.prefs;
|
||||||
|
|
||||||
if (!gFirstWindow) {
|
if (!gFirstWindow) {
|
||||||
@ -605,7 +605,7 @@ nsBrowserContentHandler.prototype = {
|
|||||||
try {
|
try {
|
||||||
var choice = prefb.getIntPref("browser.startup.page");
|
var choice = prefb.getIntPref("browser.startup.page");
|
||||||
if (choice == 1 || choice == 3)
|
if (choice == 1 || choice == 3)
|
||||||
startPage = forcePrivate ? HomePage.getPrivate() : HomePage.get();
|
startPage = HomePage.get();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Cu.reportError(e);
|
Cu.reportError(e);
|
||||||
}
|
}
|
||||||
@ -623,10 +623,6 @@ nsBrowserContentHandler.prototype = {
|
|||||||
return overridePage || startPage || "about:blank";
|
return overridePage || startPage || "about:blank";
|
||||||
},
|
},
|
||||||
|
|
||||||
get defaultArgs() {
|
|
||||||
return this.getDefaultArgs(PrivateBrowsingUtils.permanentPrivateBrowsing);
|
|
||||||
},
|
|
||||||
|
|
||||||
mFeatures: null,
|
mFeatures: null,
|
||||||
|
|
||||||
getFeatures: function bch_features(cmdLine) {
|
getFeatures: function bch_features(cmdLine) {
|
||||||
|
@ -11,18 +11,18 @@ add_task(async function() {
|
|||||||
ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
|
ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
|
||||||
let oldChildCount = CustomizableUI.getCustomizationTarget(navbar).childElementCount;
|
let oldChildCount = CustomizableUI.getCustomizationTarget(navbar).childElementCount;
|
||||||
window.resizeTo(kForceOverflowWidthPx, window.outerHeight);
|
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(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
|
||||||
|
|
||||||
ok(CustomizableUI.getCustomizationTarget(navbar).childElementCount < oldChildCount, "Should have fewer children.");
|
ok(CustomizableUI.getCustomizationTarget(navbar).childElementCount < oldChildCount, "Should have fewer children.");
|
||||||
let newWindow = await openAndLoadWindow();
|
let newWindow = await openAndLoadWindow();
|
||||||
let otherNavBar = newWindow.document.getElementById(CustomizableUI.AREA_NAVBAR);
|
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.");
|
ok(otherNavBar.hasAttribute("overflowing"), "Other window should have an overflowing toolbar.");
|
||||||
await promiseWindowClosed(newWindow);
|
await promiseWindowClosed(newWindow);
|
||||||
|
|
||||||
window.resizeTo(originalWindowWidth, window.outerHeight);
|
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.");
|
ok(!navbar.hasAttribute("overflowing"), "Should no longer have an overflowing toolbar.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -191,13 +191,8 @@ this.windows = class extends ExtensionAPI {
|
|||||||
args.appendElement(mkstr(createData.url));
|
args.appendElement(mkstr(createData.url));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let url;
|
let url = createData.incognito && !PrivateBrowsingUtils.permanentPrivateBrowsing ?
|
||||||
if (createData.incognito) {
|
"about:privatebrowsing" : HomePage.get().split("|", 1)[0];
|
||||||
url = PrivateBrowsingUtils.permanentPrivateBrowsing ?
|
|
||||||
HomePage.getPrivate().split("|", 1)[0] : "about:privatebrowsing";
|
|
||||||
} else {
|
|
||||||
url = HomePage.get().split("|", 1)[0];
|
|
||||||
}
|
|
||||||
args.appendElement(mkstr(url));
|
args.appendElement(mkstr(url));
|
||||||
|
|
||||||
if (url.startsWith("about:") &&
|
if (url.startsWith("about:") &&
|
||||||
|
@ -471,42 +471,6 @@ add_task(async function test_overriding_home_page_incognito_not_allowed() {
|
|||||||
await BrowserTestUtils.closeWindow(win);
|
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() {
|
add_task(async function test_overriding_home_page_incognito_spanning() {
|
||||||
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
|
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 extension.unload();
|
||||||
await BrowserTestUtils.closeWindow(win);
|
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);
|
||||||
|
});
|
||||||
|
@ -604,58 +604,6 @@ add_task(async function test_overriding_newtab_incognito_not_allowed() {
|
|||||||
await BrowserTestUtils.closeWindow(win);
|
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() {
|
add_task(async function test_overriding_newtab_incognito_spanning() {
|
||||||
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
|
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
restart-required-title = Restart Required
|
restart-required-title = Restart Required
|
||||||
restart-required-header = Sorry. We just need to do one small thing to keep going.
|
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.
|
applying it.
|
||||||
restart-required-description = We will restore all your pages, windows and tabs afterwards, so you can be on your way quickly.
|
restart-required-description = We will restore all your pages, windows and tabs afterwards, so you can be on your way quickly.
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ var EXPORTED_SYMBOLS = ["HomePage"];
|
|||||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
|
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
|
||||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||||
|
ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
|
||||||
|
"resource://gre/modules/ExtensionSettingsStore.jsm");
|
||||||
|
|
||||||
const kPrefName = "browser.startup.homepage";
|
const kPrefName = "browser.startup.homepage";
|
||||||
|
|
||||||
@ -48,8 +50,17 @@ let HomePage = {
|
|||||||
get(aWindow) {
|
get(aWindow) {
|
||||||
if (PrivateBrowsingUtils.permanentPrivateBrowsing ||
|
if (PrivateBrowsingUtils.permanentPrivateBrowsing ||
|
||||||
(aWindow && PrivateBrowsingUtils.isWindowPrivate(aWindow))) {
|
(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();
|
return getHomepagePref();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -57,24 +68,6 @@ let HomePage = {
|
|||||||
return getHomepagePref(true);
|
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() {
|
get overridden() {
|
||||||
return Services.prefs.prefHasUserValue(kPrefName);
|
return Services.prefs.prefHasUserValue(kPrefName);
|
||||||
},
|
},
|
||||||
|
@ -157,7 +157,7 @@ const GloballyBlockedPermissions = {
|
|||||||
Ci.nsISupportsWeakReference]),
|
Ci.nsISupportsWeakReference]),
|
||||||
onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
|
onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
|
||||||
if (aWebProgress.isTopLevel) {
|
if (aWebProgress.isTopLevel) {
|
||||||
GloballyBlockedPermissions.remove(browser, id);
|
GloballyBlockedPermissions.remove(browser, id, prePath);
|
||||||
browser.removeProgressListener(this);
|
browser.removeProgressListener(this);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -165,9 +165,11 @@ const GloballyBlockedPermissions = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Removes a permission with the specified id for the specified browser.
|
// 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 entry = this._stateByBrowser.get(browser);
|
||||||
let prePath = browser.currentURI.prePath;
|
if (!prePath) {
|
||||||
|
prePath = browser.currentURI.prePath;
|
||||||
|
}
|
||||||
if (entry && entry[prePath]) {
|
if (entry && entry[prePath]) {
|
||||||
delete entry[prePath][id];
|
delete entry[prePath][id];
|
||||||
}
|
}
|
||||||
@ -192,6 +194,15 @@ const GloballyBlockedPermissions = {
|
|||||||
}
|
}
|
||||||
return permissions;
|
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) {
|
copyTemporaryPermissions(browser, newBrowser) {
|
||||||
TemporaryPermissions.copy(browser, newBrowser);
|
TemporaryPermissions.copy(browser, newBrowser);
|
||||||
|
GloballyBlockedPermissions.copy(browser, newBrowser);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,11 +84,9 @@ add_task(async function test_context_menu() {
|
|||||||
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.contextmenu", 1);
|
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.contextmenu", 1);
|
||||||
|
|
||||||
// Also check events.
|
// Also check events.
|
||||||
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
|
TelemetryTestUtils.assertEvents(
|
||||||
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
|
[{object: "contextmenu", value: null, extra: {engine: "other-MozSearch"}}],
|
||||||
TelemetryTestUtils.assertEvents(events, [
|
{category: "navigation", method: "search"});
|
||||||
["navigation", "search", "contextmenu", null, {engine: "other-MozSearch"}],
|
|
||||||
]);
|
|
||||||
|
|
||||||
contextMenu.hidePopup();
|
contextMenu.hidePopup();
|
||||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||||
@ -122,11 +120,9 @@ add_task(async function test_about_newtab() {
|
|||||||
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.newtab", 1);
|
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.newtab", 1);
|
||||||
|
|
||||||
// Also check events.
|
// Also check events.
|
||||||
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
|
TelemetryTestUtils.assertEvents(
|
||||||
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
|
[{object: "about_newtab", value: "enter", extra: {engine: "other-MozSearch"}}],
|
||||||
TelemetryTestUtils.assertEvents(events, [
|
{category: "navigation", method: "search"});
|
||||||
["navigation", "search", "about_newtab", "enter", {engine: "other-MozSearch"}],
|
|
||||||
]);
|
|
||||||
|
|
||||||
BrowserTestUtils.removeTab(tab);
|
BrowserTestUtils.removeTab(tab);
|
||||||
});
|
});
|
||||||
|
@ -78,11 +78,9 @@ add_task(async function test_abouthome_activitystream_simpleQuery() {
|
|||||||
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.abouthome", 1);
|
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.abouthome", 1);
|
||||||
|
|
||||||
// Also check events.
|
// Also check events.
|
||||||
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
|
TelemetryTestUtils.assertEvents(
|
||||||
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
|
[{object: "about_home", value: "enter", extra: {engine: "other-MozSearch"}}],
|
||||||
TelemetryTestUtils.assertEvents(events, [
|
{category: "navigation", method: "search"});
|
||||||
["navigation", "search", "about_home", "enter", {engine: "other-MozSearch"}],
|
|
||||||
]);
|
|
||||||
|
|
||||||
BrowserTestUtils.removeTab(tab);
|
BrowserTestUtils.removeTab(tab);
|
||||||
});
|
});
|
||||||
|
@ -120,11 +120,9 @@ add_task(async function test_plainQuery() {
|
|||||||
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.searchbar", 1);
|
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.searchbar", 1);
|
||||||
|
|
||||||
// Also check events.
|
// Also check events.
|
||||||
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
|
TelemetryTestUtils.assertEvents(
|
||||||
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
|
[{object: "searchbar", value: "enter", extra: {engine: "other-MozSearch"}}],
|
||||||
TelemetryTestUtils.assertEvents(events, [
|
{category: "navigation", method: "search"});
|
||||||
["navigation", "search", "searchbar", "enter", {engine: "other-MozSearch"}],
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Check the histograms as well.
|
// Check the histograms as well.
|
||||||
let resultMethods = resultMethodHist.snapshot();
|
let resultMethods = resultMethodHist.snapshot();
|
||||||
@ -167,11 +165,9 @@ add_task(async function test_oneOff_enter() {
|
|||||||
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch2.searchbar", 1);
|
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch2.searchbar", 1);
|
||||||
|
|
||||||
// Also check events.
|
// Also check events.
|
||||||
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
|
TelemetryTestUtils.assertEvents(
|
||||||
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
|
[{object: "searchbar", value: "oneoff", extra: {engine: "other-MozSearch2"}}],
|
||||||
TelemetryTestUtils.assertEvents(events, [
|
{category: "navigation", method: "search"});
|
||||||
["navigation", "search", "searchbar", "oneoff", {engine: "other-MozSearch2"}],
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Check the histograms as well.
|
// Check the histograms as well.
|
||||||
let resultMethods = resultMethodHist.snapshot();
|
let resultMethods = resultMethodHist.snapshot();
|
||||||
@ -283,11 +279,9 @@ add_task(async function test_suggestion_click() {
|
|||||||
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, searchEngineId + ".searchbar", 1);
|
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, searchEngineId + ".searchbar", 1);
|
||||||
|
|
||||||
// Also check events.
|
// Also check events.
|
||||||
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
|
TelemetryTestUtils.assertEvents(
|
||||||
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
|
[{object: "searchbar", value: "suggestion", extra: {engine: searchEngineId}}],
|
||||||
TelemetryTestUtils.assertEvents(events, [
|
{category: "navigation", method: "search"});
|
||||||
["navigation", "search", "searchbar", "suggestion", {engine: searchEngineId}],
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Check the histograms as well.
|
// Check the histograms as well.
|
||||||
let resultMethods = resultMethodHist.snapshot();
|
let resultMethods = resultMethodHist.snapshot();
|
||||||
|
@ -154,9 +154,9 @@ add_task(async function test_simpleQuery() {
|
|||||||
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
|
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
|
||||||
|
|
||||||
// Also check events.
|
// Also check events.
|
||||||
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
|
TelemetryTestUtils.assertEvents(
|
||||||
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
|
[["navigation", "search", "urlbar", "enter", {engine: "other-MozSearch"}]],
|
||||||
TelemetryTestUtils.assertEvents(events, [["navigation", "search", "urlbar", "enter", {engine: "other-MozSearch"}]]);
|
{category: "navigation", method: "search"});
|
||||||
|
|
||||||
// Check the histograms as well.
|
// Check the histograms as well.
|
||||||
TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
|
TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
|
||||||
@ -202,9 +202,9 @@ add_task(async function test_searchAlias() {
|
|||||||
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
|
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
|
||||||
|
|
||||||
// Also check events.
|
// Also check events.
|
||||||
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
|
TelemetryTestUtils.assertEvents(
|
||||||
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
|
[["navigation", "search", "urlbar", "alias", {engine: "other-MozSearch"}]],
|
||||||
TelemetryTestUtils.assertEvents(events, [["navigation", "search", "urlbar", "alias", {engine: "other-MozSearch"}]]);
|
{category: "navigation", method: "search"});
|
||||||
|
|
||||||
// Check the histograms as well.
|
// Check the histograms as well.
|
||||||
TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
|
TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
|
||||||
@ -281,9 +281,9 @@ add_task(async function test_oneOff_enter() {
|
|||||||
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
|
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
|
||||||
|
|
||||||
// Also check events.
|
// Also check events.
|
||||||
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
|
TelemetryTestUtils.assertEvents(
|
||||||
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
|
[["navigation", "search", "urlbar", "oneoff", {engine: "other-MozSearch"}]],
|
||||||
TelemetryTestUtils.assertEvents(events, [["navigation", "search", "urlbar", "oneoff", {engine: "other-MozSearch"}]]);
|
{category: "navigation", method: "search"});
|
||||||
|
|
||||||
// Check the histograms as well.
|
// Check the histograms as well.
|
||||||
TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
|
TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
|
||||||
@ -382,9 +382,9 @@ add_task(async function test_suggestion_click() {
|
|||||||
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, searchEngineId + ".urlbar", 1);
|
TelemetryTestUtils.assertKeyedHistogramSum(search_hist, searchEngineId + ".urlbar", 1);
|
||||||
|
|
||||||
// Also check events.
|
// Also check events.
|
||||||
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
|
TelemetryTestUtils.assertEvents(
|
||||||
events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
|
[["navigation", "search", "urlbar", "suggestion", {engine: searchEngineId}]],
|
||||||
TelemetryTestUtils.assertEvents(events, [["navigation", "search", "urlbar", "suggestion", {engine: searchEngineId}]]);
|
{category: "navigation", method: "search"});
|
||||||
|
|
||||||
// Check the histograms as well.
|
// Check the histograms as well.
|
||||||
TelemetryTestUtils.assertHistogram(resultIndexHist, 3, 1);
|
TelemetryTestUtils.assertHistogram(resultIndexHist, 3, 1);
|
||||||
|
@ -247,8 +247,9 @@ static bool ReadPrincipalInfo(JSStructuredCloneReader* aReader, uint32_t aTag,
|
|||||||
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!originNoSuffix.IsEmpty());
|
MOZ_DIAGNOSTIC_ASSERT(!originNoSuffix.IsEmpty());
|
||||||
|
|
||||||
aInfo =
|
// XXX: Do we care about mDomain for structured clone?
|
||||||
ContentPrincipalInfo(attrs, originNoSuffix, spec, std::move(policies));
|
aInfo = ContentPrincipalInfo(attrs, originNoSuffix, spec, Nothing(),
|
||||||
|
std::move(policies));
|
||||||
} else {
|
} else {
|
||||||
#ifdef FUZZING
|
#ifdef FUZZING
|
||||||
return false;
|
return false;
|
||||||
|
@ -4,31 +4,29 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { Toolbox } = require("devtools/client/framework/toolbox");
|
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 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 { RIGHT, BOTTOM } = Toolbox.HostType;
|
||||||
const DATA = [
|
const DATA = [
|
||||||
{
|
{
|
||||||
timestamp: null,
|
|
||||||
category: "devtools.main",
|
category: "devtools.main",
|
||||||
method: "close",
|
method: "close",
|
||||||
object: "tools",
|
object: "tools",
|
||||||
value: null,
|
value: null,
|
||||||
extra: {
|
extra: {
|
||||||
host: "right",
|
host: "right",
|
||||||
width: "1440",
|
width: w => w > 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
timestamp: null,
|
|
||||||
category: "devtools.main",
|
category: "devtools.main",
|
||||||
method: "close",
|
method: "close",
|
||||||
object: "tools",
|
object: "tools",
|
||||||
value: null,
|
value: null,
|
||||||
extra: {
|
extra: {
|
||||||
host: "bottom",
|
host: "bottom",
|
||||||
width: "1440",
|
width: w => w > 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -38,8 +36,7 @@ add_task(async function() {
|
|||||||
Services.telemetry.clearEvents();
|
Services.telemetry.clearEvents();
|
||||||
|
|
||||||
// Ensure no events have been logged
|
// Ensure no events have been logged
|
||||||
const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
|
TelemetryTestUtils.assertNumberOfEvents(0);
|
||||||
ok(!snapshot.parent, "No events have been logged for the main process");
|
|
||||||
|
|
||||||
await openAndCloseToolbox("webconsole", RIGHT);
|
await openAndCloseToolbox("webconsole", RIGHT);
|
||||||
await openAndCloseToolbox("webconsole", BOTTOM);
|
await openAndCloseToolbox("webconsole", BOTTOM);
|
||||||
@ -57,25 +54,5 @@ async function openAndCloseToolbox(toolId, host) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkResults() {
|
function checkResults() {
|
||||||
const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
|
TelemetryTestUtils.assertEvents(DATA, {category: "devtools.main", method: "close", object: "tools"});
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ const TEST_URI =
|
|||||||
<div id="box"></div>`;
|
<div id="box"></div>`;
|
||||||
|
|
||||||
add_task(async function() {
|
add_task(async function() {
|
||||||
|
await pushPref("devtools.layout.boxmodel.highlightProperty", true);
|
||||||
await addTab("data:text/html," + encodeURIComponent(TEST_URI));
|
await addTab("data:text/html," + encodeURIComponent(TEST_URI));
|
||||||
const { inspector, boxmodel } = await openLayoutView();
|
const { inspector, boxmodel } = await openLayoutView();
|
||||||
await selectNode("#box", inspector);
|
await selectNode("#box", inspector);
|
||||||
|
@ -16,6 +16,7 @@ const TEST_URI =
|
|||||||
<div id="box"></div>`;
|
<div id="box"></div>`;
|
||||||
|
|
||||||
add_task(async function() {
|
add_task(async function() {
|
||||||
|
await pushPref("devtools.layout.boxmodel.highlightProperty", true);
|
||||||
await addTab("data:text/html," + encodeURIComponent(TEST_URI));
|
await addTab("data:text/html," + encodeURIComponent(TEST_URI));
|
||||||
const { inspector, boxmodel } = await openLayoutView();
|
const { inspector, boxmodel } = await openLayoutView();
|
||||||
const { rulePreviewTooltip } = boxmodel;
|
const { rulePreviewTooltip } = boxmodel;
|
||||||
|
@ -28,6 +28,7 @@ class ChangesContextMenu {
|
|||||||
// Window object to which the Changes panel belongs to.
|
// Window object to which the Changes panel belongs to.
|
||||||
this.window = this.document.defaultView;
|
this.window = this.document.defaultView;
|
||||||
|
|
||||||
|
this._onCopyDeclaration = this.view.copyDeclaration.bind(this.view);
|
||||||
this._onCopyRule = this.view.copyRule.bind(this.view);
|
this._onCopyRule = this.view.copyRule.bind(this.view);
|
||||||
this._onCopySelection = this.view.copySelection.bind(this.view);
|
this._onCopySelection = this.view.copySelection.bind(this.view);
|
||||||
this._onSelectAll = this._onSelectAll.bind(this);
|
this._onSelectAll = this._onSelectAll.bind(this);
|
||||||
@ -55,16 +56,24 @@ class ChangesContextMenu {
|
|||||||
});
|
});
|
||||||
menu.append(menuitemCopy);
|
menu.append(menuitemCopy);
|
||||||
|
|
||||||
|
const declEl = target.closest(".changes__declaration");
|
||||||
const ruleEl = target.closest("[data-rule-id]");
|
const ruleEl = target.closest("[data-rule-id]");
|
||||||
const ruleId = ruleEl ? ruleEl.dataset.ruleId : null;
|
const ruleId = ruleEl ? ruleEl.dataset.ruleId : null;
|
||||||
|
|
||||||
if (ruleId) {
|
if (ruleId || declEl) {
|
||||||
// Copy Rule option
|
// Copy Rule option
|
||||||
menu.append(new MenuItem({
|
menu.append(new MenuItem({
|
||||||
label: getStr("changes.contextmenu.copyRule"),
|
label: getStr("changes.contextmenu.copyRule"),
|
||||||
click: () => this._onCopyRule(ruleId),
|
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({
|
menu.append(new MenuItem({
|
||||||
type: "separator",
|
type: "separator",
|
||||||
}));
|
}));
|
||||||
|
@ -146,6 +146,22 @@ class ChangesView {
|
|||||||
clipboardHelper.copyString(text);
|
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.
|
* Handler for the "Copy Rule" option from the context menu.
|
||||||
* Gets the full content of the target CSS rule (including any changes applied)
|
* Gets the full content of the target CSS rule (including any changes applied)
|
||||||
|
@ -28,11 +28,11 @@ class CSSDeclaration extends PureComponent {
|
|||||||
render() {
|
render() {
|
||||||
const { className, marker, property, value } = this.props;
|
const { className, marker, property, value } = this.props;
|
||||||
|
|
||||||
return dom.div({ className: `declaration ${className}` },
|
return dom.div({ className: `changes__declaration ${className}` },
|
||||||
marker,
|
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),
|
||||||
";"
|
";"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ registerCleanupFunction(() => {
|
|||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
function getDeclarations(panelDoc, selector = "", containerNode = null) {
|
function getDeclarations(panelDoc, selector = "", containerNode = null) {
|
||||||
const els = panelDoc.querySelectorAll(`#sidebar-panel-changes .declaration${selector}`);
|
const els = panelDoc.querySelectorAll(`.changes__declaration${selector}`);
|
||||||
|
|
||||||
return [...els]
|
return [...els]
|
||||||
.filter(el => {
|
.filter(el => {
|
||||||
@ -52,8 +52,8 @@ function getDeclarations(panelDoc, selector = "", containerNode = null) {
|
|||||||
})
|
})
|
||||||
.map(el => {
|
.map(el => {
|
||||||
return {
|
return {
|
||||||
property: el.querySelector(".declaration-name").textContent,
|
property: el.querySelector(".changes__declaration-name").textContent,
|
||||||
value: el.querySelector(".declaration-value").textContent,
|
value: el.querySelector(".changes__declaration-value").textContent,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ add_task(async function() {
|
|||||||
expectedPattern: "color",
|
expectedPattern: "color",
|
||||||
visible: {
|
visible: {
|
||||||
copyLocation: false,
|
copyLocation: false,
|
||||||
copyPropertyDeclaration: true,
|
copyDeclaration: true,
|
||||||
copyPropertyName: true,
|
copyPropertyName: true,
|
||||||
copyPropertyValue: false,
|
copyPropertyValue: false,
|
||||||
copySelector: false,
|
copySelector: false,
|
||||||
@ -42,7 +42,7 @@ add_task(async function() {
|
|||||||
expectedPattern: "12px",
|
expectedPattern: "12px",
|
||||||
visible: {
|
visible: {
|
||||||
copyLocation: false,
|
copyLocation: false,
|
||||||
copyPropertyDeclaration: true,
|
copyDeclaration: true,
|
||||||
copyPropertyName: false,
|
copyPropertyName: false,
|
||||||
copyPropertyValue: true,
|
copyPropertyValue: true,
|
||||||
copySelector: false,
|
copySelector: false,
|
||||||
@ -56,7 +56,7 @@ add_task(async function() {
|
|||||||
expectedPattern: "#00F !important",
|
expectedPattern: "#00F !important",
|
||||||
visible: {
|
visible: {
|
||||||
copyLocation: false,
|
copyLocation: false,
|
||||||
copyPropertyDeclaration: true,
|
copyDeclaration: true,
|
||||||
copyPropertyName: false,
|
copyPropertyName: false,
|
||||||
copyPropertyValue: true,
|
copyPropertyValue: true,
|
||||||
copySelector: false,
|
copySelector: false,
|
||||||
@ -66,11 +66,11 @@ add_task(async function() {
|
|||||||
{
|
{
|
||||||
desc: "Test Copy Property Declaration",
|
desc: "Test Copy Property Declaration",
|
||||||
node: ruleEditor.rule.textProps[2].editor.nameSpan,
|
node: ruleEditor.rule.textProps[2].editor.nameSpan,
|
||||||
menuItemLabel: "styleinspector.contextmenu.copyPropertyDeclaration",
|
menuItemLabel: "styleinspector.contextmenu.copyDeclaration",
|
||||||
expectedPattern: "font-size: 12px;",
|
expectedPattern: "font-size: 12px;",
|
||||||
visible: {
|
visible: {
|
||||||
copyLocation: false,
|
copyLocation: false,
|
||||||
copyPropertyDeclaration: true,
|
copyDeclaration: true,
|
||||||
copyPropertyName: true,
|
copyPropertyName: true,
|
||||||
copyPropertyValue: false,
|
copyPropertyValue: false,
|
||||||
copySelector: false,
|
copySelector: false,
|
||||||
@ -80,11 +80,11 @@ add_task(async function() {
|
|||||||
{
|
{
|
||||||
desc: "Test Copy Property Declaration with Priority",
|
desc: "Test Copy Property Declaration with Priority",
|
||||||
node: ruleEditor.rule.textProps[3].editor.nameSpan,
|
node: ruleEditor.rule.textProps[3].editor.nameSpan,
|
||||||
menuItemLabel: "styleinspector.contextmenu.copyPropertyDeclaration",
|
menuItemLabel: "styleinspector.contextmenu.copyDeclaration",
|
||||||
expectedPattern: "border-color: #00F !important;",
|
expectedPattern: "border-color: #00F !important;",
|
||||||
visible: {
|
visible: {
|
||||||
copyLocation: false,
|
copyLocation: false,
|
||||||
copyPropertyDeclaration: true,
|
copyDeclaration: true,
|
||||||
copyPropertyName: true,
|
copyPropertyName: true,
|
||||||
copyPropertyValue: false,
|
copyPropertyValue: false,
|
||||||
copySelector: false,
|
copySelector: false,
|
||||||
@ -104,7 +104,7 @@ add_task(async function() {
|
|||||||
"}",
|
"}",
|
||||||
visible: {
|
visible: {
|
||||||
copyLocation: false,
|
copyLocation: false,
|
||||||
copyPropertyDeclaration: true,
|
copyDeclaration: true,
|
||||||
copyPropertyName: true,
|
copyPropertyName: true,
|
||||||
copyPropertyValue: false,
|
copyPropertyValue: false,
|
||||||
copySelector: false,
|
copySelector: false,
|
||||||
@ -118,7 +118,7 @@ add_task(async function() {
|
|||||||
expectedPattern: "html, body, #testid",
|
expectedPattern: "html, body, #testid",
|
||||||
visible: {
|
visible: {
|
||||||
copyLocation: false,
|
copyLocation: false,
|
||||||
copyPropertyDeclaration: false,
|
copyDeclaration: false,
|
||||||
copyPropertyName: false,
|
copyPropertyName: false,
|
||||||
copyPropertyValue: false,
|
copyPropertyValue: false,
|
||||||
copySelector: true,
|
copySelector: true,
|
||||||
@ -133,7 +133,7 @@ add_task(async function() {
|
|||||||
"inspector/rules/test/doc_copystyles.css",
|
"inspector/rules/test/doc_copystyles.css",
|
||||||
visible: {
|
visible: {
|
||||||
copyLocation: true,
|
copyLocation: true,
|
||||||
copyPropertyDeclaration: false,
|
copyDeclaration: false,
|
||||||
copyPropertyName: false,
|
copyPropertyName: false,
|
||||||
copyPropertyValue: false,
|
copyPropertyValue: false,
|
||||||
copySelector: false,
|
copySelector: false,
|
||||||
@ -156,7 +156,7 @@ add_task(async function() {
|
|||||||
"}",
|
"}",
|
||||||
visible: {
|
visible: {
|
||||||
copyLocation: false,
|
copyLocation: false,
|
||||||
copyPropertyDeclaration: true,
|
copyDeclaration: true,
|
||||||
copyPropertyName: true,
|
copyPropertyName: true,
|
||||||
copyPropertyValue: false,
|
copyPropertyValue: false,
|
||||||
copySelector: false,
|
copySelector: false,
|
||||||
@ -179,7 +179,7 @@ add_task(async function() {
|
|||||||
"}",
|
"}",
|
||||||
visible: {
|
visible: {
|
||||||
copyLocation: false,
|
copyLocation: false,
|
||||||
copyPropertyDeclaration: true,
|
copyDeclaration: true,
|
||||||
copyPropertyName: true,
|
copyPropertyName: true,
|
||||||
copyPropertyValue: false,
|
copyPropertyValue: false,
|
||||||
copySelector: false,
|
copySelector: false,
|
||||||
@ -189,11 +189,11 @@ add_task(async function() {
|
|||||||
{
|
{
|
||||||
desc: "Test Copy Property Declaration with Disabled Property",
|
desc: "Test Copy Property Declaration with Disabled Property",
|
||||||
node: ruleEditor.rule.textProps[0].editor.nameSpan,
|
node: ruleEditor.rule.textProps[0].editor.nameSpan,
|
||||||
menuItemLabel: "styleinspector.contextmenu.copyPropertyDeclaration",
|
menuItemLabel: "styleinspector.contextmenu.copyDeclaration",
|
||||||
expectedPattern: "\/\\* color: #F00; \\*\/",
|
expectedPattern: "\/\\* color: #F00; \\*\/",
|
||||||
visible: {
|
visible: {
|
||||||
copyLocation: false,
|
copyLocation: false,
|
||||||
copyPropertyDeclaration: true,
|
copyDeclaration: true,
|
||||||
copyPropertyName: true,
|
copyPropertyName: true,
|
||||||
copyPropertyValue: false,
|
copyPropertyValue: false,
|
||||||
copySelector: false,
|
copySelector: false,
|
||||||
@ -220,8 +220,8 @@ async function checkCopyStyle(view, node, menuItemLabel, expectedPattern, visibl
|
|||||||
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copy"));
|
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copy"));
|
||||||
const menuitemCopyLocation = allMenuItems.find(item => item.label ===
|
const menuitemCopyLocation = allMenuItems.find(item => item.label ===
|
||||||
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyLocation"));
|
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyLocation"));
|
||||||
const menuitemCopyPropertyDeclaration = allMenuItems.find(item => item.label ===
|
const menuitemCopyDeclaration = allMenuItems.find(item => item.label ===
|
||||||
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyDeclaration"));
|
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyDeclaration"));
|
||||||
const menuitemCopyPropertyName = allMenuItems.find(item => item.label ===
|
const menuitemCopyPropertyName = allMenuItems.find(item => item.label ===
|
||||||
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyName"));
|
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyName"));
|
||||||
const menuitemCopyPropertyValue = allMenuItems.find(item => item.label ===
|
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: " +
|
"Copy Location visible attribute is as expected: " +
|
||||||
visible.copyLocation);
|
visible.copyLocation);
|
||||||
|
|
||||||
is(menuitemCopyPropertyDeclaration.visible,
|
is(menuitemCopyDeclaration.visible,
|
||||||
visible.copyPropertyDeclaration,
|
visible.copyDeclaration,
|
||||||
"Copy Property Declaration visible attribute is as expected: " +
|
"Copy Property Declaration visible attribute is as expected: " +
|
||||||
visible.copyPropertyDeclaration);
|
visible.copyDeclaration);
|
||||||
|
|
||||||
is(menuitemCopyPropertyName.visible,
|
is(menuitemCopyPropertyName.visible,
|
||||||
visible.copyPropertyName,
|
visible.copyPropertyName,
|
||||||
|
@ -58,6 +58,10 @@ const TEST_DATA = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
add_task(async function() {
|
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);
|
requestLongerTimeout(4);
|
||||||
|
|
||||||
info("Starting the test with the pref set to true before toolbox is opened");
|
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);
|
info("Resetting " + PREF_UA_STYLES);
|
||||||
Services.prefs.clearUserPref(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) {
|
async function setUserAgentStylesPref(val) {
|
||||||
|
@ -46,7 +46,7 @@ function StyleInspectorMenu(view, options) {
|
|||||||
this._onCopyColor = this._onCopyColor.bind(this);
|
this._onCopyColor = this._onCopyColor.bind(this);
|
||||||
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
|
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
|
||||||
this._onCopyLocation = this._onCopyLocation.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._onCopyPropertyName = this._onCopyPropertyName.bind(this);
|
||||||
this._onCopyPropertyValue = this._onCopyPropertyValue.bind(this);
|
this._onCopyPropertyValue = this._onCopyPropertyValue.bind(this);
|
||||||
this._onCopyRule = this._onCopyRule.bind(this);
|
this._onCopyRule = this._onCopyRule.bind(this);
|
||||||
@ -131,11 +131,11 @@ StyleInspectorMenu.prototype = {
|
|||||||
},
|
},
|
||||||
visible: this._isImageUrl(),
|
visible: this._isImageUrl(),
|
||||||
});
|
});
|
||||||
const copyPropDeclarationLabel = "styleinspector.contextmenu.copyPropertyDeclaration";
|
const copyDeclarationLabel = "styleinspector.contextmenu.copyDeclaration";
|
||||||
const menuitemCopyPropertyDeclaration = new MenuItem({
|
const menuitemCopyDeclaration = new MenuItem({
|
||||||
label: STYLE_INSPECTOR_L10N.getStr(copyPropDeclarationLabel),
|
label: STYLE_INSPECTOR_L10N.getStr(copyDeclarationLabel),
|
||||||
click: () => {
|
click: () => {
|
||||||
this._onCopyPropertyDeclaration();
|
this._onCopyDeclaration();
|
||||||
},
|
},
|
||||||
visible: false,
|
visible: false,
|
||||||
});
|
});
|
||||||
@ -165,11 +165,11 @@ StyleInspectorMenu.prototype = {
|
|||||||
if (this.isRuleView && this._clickedNodeInfo) {
|
if (this.isRuleView && this._clickedNodeInfo) {
|
||||||
switch (this._clickedNodeInfo.type) {
|
switch (this._clickedNodeInfo.type) {
|
||||||
case VIEW_NODE_PROPERTY_TYPE :
|
case VIEW_NODE_PROPERTY_TYPE :
|
||||||
menuitemCopyPropertyDeclaration.visible = true;
|
menuitemCopyDeclaration.visible = true;
|
||||||
menuitemCopyPropertyName.visible = true;
|
menuitemCopyPropertyName.visible = true;
|
||||||
break;
|
break;
|
||||||
case VIEW_NODE_VALUE_TYPE :
|
case VIEW_NODE_VALUE_TYPE :
|
||||||
menuitemCopyPropertyDeclaration.visible = true;
|
menuitemCopyDeclaration.visible = true;
|
||||||
menuitemCopyPropertyValue.visible = true;
|
menuitemCopyPropertyValue.visible = true;
|
||||||
break;
|
break;
|
||||||
case VIEW_NODE_SELECTOR_TYPE :
|
case VIEW_NODE_SELECTOR_TYPE :
|
||||||
@ -187,7 +187,7 @@ StyleInspectorMenu.prototype = {
|
|||||||
menu.append(menuitemCopyColor);
|
menu.append(menuitemCopyColor);
|
||||||
menu.append(menuitemCopyUrl);
|
menu.append(menuitemCopyUrl);
|
||||||
menu.append(menuitemCopyImageDataUrl);
|
menu.append(menuitemCopyImageDataUrl);
|
||||||
menu.append(menuitemCopyPropertyDeclaration);
|
menu.append(menuitemCopyDeclaration);
|
||||||
menu.append(menuitemCopyPropertyName);
|
menu.append(menuitemCopyPropertyName);
|
||||||
menu.append(menuitemCopyPropertyValue);
|
menu.append(menuitemCopyPropertyValue);
|
||||||
menu.append(menuitemCopySelector);
|
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) {
|
if (!this._clickedNodeInfo) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,10 @@ changes.contextmenu.copyAllChanges=Copy All Changes
|
|||||||
# Changes" button
|
# Changes" button
|
||||||
changes.contextmenu.copyAllChangesDescription=Copy a list of all CSS changes to clipboard.
|
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
|
# 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 panel context menu which copies the complete contents of a CSS rule.
|
||||||
changes.contextmenu.copyRule=Copy Rule
|
changes.contextmenu.copyRule=Copy Rule
|
||||||
|
@ -157,7 +157,7 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sidebar-panel-changes .declaration-name {
|
.changes__declaration-name {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,31 +338,29 @@ This is best shown via an example:
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { Toolbox } = require("devtools/client/framework/toolbox");
|
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 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 { SIDE, BOTTOM } = Toolbox.HostType;
|
const DATA = [
|
||||||
const TELEMETRY_DATA = [
|
|
||||||
{
|
{
|
||||||
timestamp: null,
|
|
||||||
category: "devtools.main",
|
category: "devtools.main",
|
||||||
method: "close",
|
method: "close",
|
||||||
object: "tools",
|
object: "tools",
|
||||||
value: null,
|
value: null,
|
||||||
extra: {
|
extra: {
|
||||||
host: "right",
|
host: "right",
|
||||||
width: "1440"
|
width: w => w > 0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
timestamp: null,
|
|
||||||
category: "devtools.main",
|
category: "devtools.main",
|
||||||
method: "close",
|
method: "close",
|
||||||
object: "tools",
|
object: "tools",
|
||||||
value: null,
|
value: null,
|
||||||
extra: {
|
extra: {
|
||||||
host: "bottom",
|
host: "bottom",
|
||||||
width: "1440"
|
width: w => w > 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -372,8 +370,7 @@ add_task(async function() {
|
|||||||
Services.telemetry.clearEvents();
|
Services.telemetry.clearEvents();
|
||||||
|
|
||||||
// Ensure no events have been logged
|
// Ensure no events have been logged
|
||||||
const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
|
TelemetryTestUtils.assertNumberOfEvents(0);
|
||||||
ok(!snapshot.parent, "No events have been logged for the main process");
|
|
||||||
|
|
||||||
await openAndCloseToolbox("webconsole", SIDE);
|
await openAndCloseToolbox("webconsole", SIDE);
|
||||||
await openAndCloseToolbox("webconsole", BOTTOM);
|
await openAndCloseToolbox("webconsole", BOTTOM);
|
||||||
@ -391,27 +388,7 @@ async function openAndCloseToolbox(toolId, host) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkResults() {
|
function checkResults() {
|
||||||
const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
|
TelemetryTestUtils.assertEvents(DATA, {category: "devtools.main", method: "close", object: "tools"});
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -102,9 +102,6 @@ function Sandbox(options) {
|
|||||||
sandboxPrototype: "prototype" in options ? options.prototype : {},
|
sandboxPrototype: "prototype" in options ? options.prototype : {},
|
||||||
invisibleToDebugger: "invisibleToDebugger" in options ?
|
invisibleToDebugger: "invisibleToDebugger" in options ?
|
||||||
options.invisibleToDebugger : false,
|
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);
|
const sandbox = Cu.Sandbox(systemPrincipal, options);
|
||||||
|
@ -206,9 +206,9 @@ styleinspector.contextmenu.copy.accessKey=C
|
|||||||
# rule view context menu for copying the source location.
|
# rule view context menu for copying the source location.
|
||||||
styleinspector.contextmenu.copyLocation=Copy Location
|
styleinspector.contextmenu.copyLocation=Copy Location
|
||||||
|
|
||||||
# LOCALIZATION NOTE (styleinspector.contextmenu.copyPropertyDeclaration): Text
|
# LOCALIZATION NOTE (styleinspector.contextmenu.copyDeclaration): Text
|
||||||
# displayed in the rule view context menu for copying the property declaration.
|
# displayed in the rule view context menu for copying the CSS declaration.
|
||||||
styleinspector.contextmenu.copyPropertyDeclaration=Copy Property Declaration
|
styleinspector.contextmenu.copyDeclaration=Copy Declaration
|
||||||
|
|
||||||
# LOCALIZATION NOTE (styleinspector.contextmenu.copyPropertyName): Text displayed in
|
# LOCALIZATION NOTE (styleinspector.contextmenu.copyPropertyName): Text displayed in
|
||||||
# the rule view context menu for copying the property name.
|
# the rule view context menu for copying the property name.
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsScriptError.h"
|
#include "nsScriptError.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
#include "xpcprivate.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
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_ROOT_NATIVE(BrowsingContext, AddRef)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(BrowsingContext, Release)
|
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,
|
void BrowsingContext::Location(JSContext* aCx,
|
||||||
JS::MutableHandle<JSObject*> aLocation,
|
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) {
|
void BrowsingContext::Close(CallerType aCallerType, ErrorResult& aError) {
|
||||||
// FIXME We need to set mClosed, but only once we're sending the
|
// 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);
|
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 dom
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
|
|
||||||
class nsGlobalWindowOuter;
|
class nsGlobalWindowOuter;
|
||||||
|
class nsIPrincipal;
|
||||||
class nsOuterWindowProxy;
|
class nsOuterWindowProxy;
|
||||||
class PickleIterator;
|
class PickleIterator;
|
||||||
|
|
||||||
@ -31,7 +32,6 @@ namespace mozilla {
|
|||||||
|
|
||||||
class ErrorResult;
|
class ErrorResult;
|
||||||
class LogModule;
|
class LogModule;
|
||||||
class OOMReporter;
|
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
class IProtocol;
|
class IProtocol;
|
||||||
@ -267,7 +267,7 @@ class BrowsingContext : public nsWrapperCache,
|
|||||||
BrowsingContext* Window() { return Self(); }
|
BrowsingContext* Window() { return Self(); }
|
||||||
BrowsingContext* Self() { return this; }
|
BrowsingContext* Self() { return this; }
|
||||||
void Location(JSContext* aCx, JS::MutableHandle<JSObject*> aLocation,
|
void Location(JSContext* aCx, JS::MutableHandle<JSObject*> aLocation,
|
||||||
OOMReporter& aError);
|
ErrorResult& aError);
|
||||||
void Close(CallerType aCallerType, ErrorResult& aError);
|
void Close(CallerType aCallerType, ErrorResult& aError);
|
||||||
bool GetClosed(ErrorResult&) { return mClosed; }
|
bool GetClosed(ErrorResult&) { return mClosed; }
|
||||||
void Focus(ErrorResult& aError);
|
void Focus(ErrorResult& aError);
|
||||||
@ -329,6 +329,34 @@ class BrowsingContext : public nsWrapperCache,
|
|||||||
|
|
||||||
BrowsingContext* TopLevelBrowsingContext();
|
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
|
// Type of BrowsingContent
|
||||||
const Type mType;
|
const Type mType;
|
||||||
|
|
||||||
@ -345,6 +373,7 @@ class BrowsingContext : public nsWrapperCache,
|
|||||||
// nsOuterWindowProxy handler, which will update the pointer from its
|
// nsOuterWindowProxy handler, which will update the pointer from its
|
||||||
// objectMoved hook and clear it from its finalize hook.
|
// objectMoved hook and clear it from its finalize hook.
|
||||||
JS::Heap<JSObject*> mWindowProxy;
|
JS::Heap<JSObject*> mWindowProxy;
|
||||||
|
LocationProxy mLocation;
|
||||||
|
|
||||||
// This flag is only valid in the top level browsing context, it indicates
|
// This flag is only valid in the top level browsing context, it indicates
|
||||||
// whether the corresponding document has been activated by user gesture.
|
// whether the corresponding document has been activated by user gesture.
|
||||||
|
@ -108,6 +108,7 @@ LOCAL_INCLUDES += [
|
|||||||
'/docshell/shistory',
|
'/docshell/shistory',
|
||||||
'/dom/base',
|
'/dom/base',
|
||||||
'/dom/bindings',
|
'/dom/bindings',
|
||||||
|
'/js/xpconnect/src',
|
||||||
'/layout/base',
|
'/layout/base',
|
||||||
'/layout/generic',
|
'/layout/generic',
|
||||||
'/layout/style',
|
'/layout/style',
|
||||||
|
@ -29,7 +29,7 @@ namespace dom {
|
|||||||
|
|
||||||
class Location final : public nsISupports, public nsWrapperCache {
|
class Location final : public nsISupports, public nsWrapperCache {
|
||||||
public:
|
public:
|
||||||
typedef Location RemoteProxy;
|
typedef BrowsingContext::LocationProxy RemoteProxy;
|
||||||
|
|
||||||
Location(nsPIDOMWindowInner* aWindow, nsIDocShell* aDocShell);
|
Location(nsPIDOMWindowInner* aWindow, nsIDocShell* aDocShell);
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@ class RemoteOuterWindowProxy
|
|||||||
Window_Binding::sCrossOriginAttributes,
|
Window_Binding::sCrossOriginAttributes,
|
||||||
Window_Binding::sCrossOriginMethods> {
|
Window_Binding::sCrossOriginMethods> {
|
||||||
public:
|
public:
|
||||||
|
typedef RemoteObjectProxy Base;
|
||||||
|
|
||||||
constexpr RemoteOuterWindowProxy()
|
constexpr RemoteOuterWindowProxy()
|
||||||
: RemoteObjectProxy(prototypes::id::Window) {}
|
: RemoteObjectProxy(prototypes::id::Window) {}
|
||||||
|
|
||||||
@ -45,17 +47,22 @@ class RemoteOuterWindowProxy
|
|||||||
// SpiderMonkey extensions
|
// SpiderMonkey extensions
|
||||||
bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
|
bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||||
JS::AutoIdVector& props) const final;
|
JS::AutoIdVector& props) const final;
|
||||||
void finalize(JSFreeOp* aFop, JSObject* aProxy) const final;
|
|
||||||
const char* className(JSContext* aCx,
|
void NoteChildren(JSObject* aProxy,
|
||||||
JS::Handle<JSObject*> aProxy) const final;
|
nsCycleCollectionTraversalCallback& aCb) const override {
|
||||||
|
CycleCollectionNoteChild(aCb,
|
||||||
|
static_cast<BrowsingContext*>(GetNative(aProxy)),
|
||||||
|
"js::GetObjectPrivate(obj)");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const RemoteOuterWindowProxy sSingleton;
|
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
|
// so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
|
||||||
// malloc.
|
// malloc.
|
||||||
const js::Class RemoteOuterWindowProxyClass =
|
template <>
|
||||||
|
const js::Class RemoteOuterWindowProxy::Base::sClass =
|
||||||
PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
|
PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
|
||||||
|
|
||||||
bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
|
bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
|
||||||
@ -63,30 +70,8 @@ bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
|
|||||||
MOZ_ASSERT(!aContext->GetDocShell(),
|
MOZ_ASSERT(!aContext->GetDocShell(),
|
||||||
"Why are we creating a RemoteOuterWindowProxy?");
|
"Why are we creating a RemoteOuterWindowProxy?");
|
||||||
|
|
||||||
xpc::CompartmentPrivate* priv =
|
sSingleton.GetProxyObject(aCx, aContext, aRetVal);
|
||||||
xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx));
|
return !!aRetVal;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static BrowsingContext* GetBrowsingContext(JSObject* aProxy) {
|
static BrowsingContext* GetBrowsingContext(JSObject* aProxy) {
|
||||||
@ -177,17 +162,5 @@ bool RemoteOuterWindowProxy::getOwnEnumerablePropertyKeys(
|
|||||||
return AppendIndexedPropertyNames(aCx, GetBrowsingContext(aProxy), aProps);
|
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 dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -9132,7 +9132,6 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
|||||||
# We'll use a JSObject. It might make more sense to use remoteType's
|
# 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.
|
# RemoteProxy, but it's not easy to construct a type for that from here.
|
||||||
remoteType = BuiltinTypes[IDLBuiltinType.Types.object]
|
remoteType = BuiltinTypes[IDLBuiltinType.Types.object]
|
||||||
extendedAttributes.append('canOOM')
|
|
||||||
extendedAttributes.remove('infallible')
|
extendedAttributes.remove('infallible')
|
||||||
prototypeID, _ = PrototypeIDAndDepth(self.descriptor)
|
prototypeID, _ = PrototypeIDAndDepth(self.descriptor)
|
||||||
prefix = fill("""
|
prefix = fill("""
|
||||||
|
@ -11,12 +11,6 @@
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
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(
|
bool RemoteObjectProxyBase::getOwnPropertyDescriptor(
|
||||||
JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
|
JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
|
||||||
JS::MutableHandle<JS::PropertyDescriptor> aDesc) const {
|
JS::MutableHandle<JS::PropertyDescriptor> aDesc) const {
|
||||||
@ -169,12 +163,41 @@ bool RemoteObjectProxyBase::getOwnEnumerablePropertyKeys(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* RemoteObjectProxyBase::CreateProxyObject(
|
const char* RemoteObjectProxyBase::className(
|
||||||
JSContext* aCx, void* aNative, const js::Class* aClasp) const {
|
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;
|
js::ProxyOptions options;
|
||||||
options.setClass(aClasp);
|
options.setClass(aClasp);
|
||||||
JS::Rooted<JS::Value> native(aCx, JS::PrivateValue(aNative));
|
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;
|
const char RemoteObjectProxyBase::sCrossOriginProxyFamily = 0;
|
||||||
|
@ -70,10 +70,15 @@ class RemoteObjectProxyBase : public js::BaseProxyHandler,
|
|||||||
bool getOwnEnumerablePropertyKeys(JSContext* aCx,
|
bool getOwnEnumerablePropertyKeys(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aProxy,
|
JS::Handle<JSObject*> aProxy,
|
||||||
JS::AutoIdVector& aProps) const override;
|
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 isCallable(JSObject* aObj) const final { return false; }
|
||||||
bool isConstructor(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) {
|
static void* GetNative(JSObject* aProxy) {
|
||||||
return js::GetProxyPrivate(aProxy).toPrivate();
|
return js::GetProxyPrivate(aProxy).toPrivate();
|
||||||
}
|
}
|
||||||
@ -101,8 +106,17 @@ class RemoteObjectProxyBase : public js::BaseProxyHandler,
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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;
|
const prototypes::ID mPrototypeID;
|
||||||
|
|
||||||
@ -126,9 +140,18 @@ class RemoteObjectProxyBase : public js::BaseProxyHandler,
|
|||||||
template <class Native, JSPropertySpec* P, JSFunctionSpec* F>
|
template <class Native, JSPropertySpec* P, JSFunctionSpec* F>
|
||||||
class RemoteObjectProxy : public RemoteObjectProxyBase {
|
class RemoteObjectProxy : public RemoteObjectProxyBase {
|
||||||
public:
|
public:
|
||||||
JSObject* CreateProxyObject(JSContext* aCx, Native* aNative,
|
void finalize(JSFreeOp* aFop, JSObject* aProxy) const final {
|
||||||
const js::Class* aClasp) const {
|
auto native = static_cast<Native*>(GetNative(aProxy));
|
||||||
return RemoteObjectProxyBase::CreateProxyObject(aCx, aNative, aClasp);
|
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:
|
protected:
|
||||||
@ -140,6 +163,8 @@ class RemoteObjectProxy : public RemoteObjectProxyBase {
|
|||||||
return MaybeCrossOriginObjectMixins::EnsureHolder(
|
return MaybeCrossOriginObjectMixins::EnsureHolder(
|
||||||
aCx, aProxy, /* slot = */ 0, P, F, aHolder);
|
aCx, aProxy, /* slot = */ 0, P, F, aHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const js::Class sClass;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
2
dom/cache/DBSchema.cpp
vendored
2
dom/cache/DBSchema.cpp
vendored
@ -2496,7 +2496,7 @@ nsresult ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
|
|||||||
nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
|
nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
|
||||||
aSavedResponseOut->mValue.principalInfo() =
|
aSavedResponseOut->mValue.principalInfo() =
|
||||||
mozilla::ipc::ContentPrincipalInfo(attrs, origin, specNoSuffix,
|
mozilla::ipc::ContentPrincipalInfo(attrs, origin, specNoSuffix,
|
||||||
std::move(policies));
|
Nothing(), std::move(policies));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nullPadding = false;
|
bool nullPadding = false;
|
||||||
|
@ -27,12 +27,10 @@ using namespace gfx;
|
|||||||
* due to CORS security.
|
* due to CORS security.
|
||||||
*/
|
*/
|
||||||
struct ImageCacheKey {
|
struct ImageCacheKey {
|
||||||
ImageCacheKey(imgIContainer* aImage, HTMLCanvasElement* aCanvas,
|
ImageCacheKey(imgIContainer* aImage, HTMLCanvasElement* aCanvas)
|
||||||
bool aIsAccelerated)
|
: mImage(aImage), mCanvas(aCanvas) {}
|
||||||
: mImage(aImage), mCanvas(aCanvas), mIsAccelerated(aIsAccelerated) {}
|
|
||||||
nsCOMPtr<imgIContainer> mImage;
|
nsCOMPtr<imgIContainer> mImage;
|
||||||
HTMLCanvasElement* mCanvas;
|
HTMLCanvasElement* mCanvas;
|
||||||
bool mIsAccelerated;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,13 +41,11 @@ struct ImageCacheEntryData {
|
|||||||
ImageCacheEntryData(const ImageCacheEntryData& aOther)
|
ImageCacheEntryData(const ImageCacheEntryData& aOther)
|
||||||
: mImage(aOther.mImage),
|
: mImage(aOther.mImage),
|
||||||
mCanvas(aOther.mCanvas),
|
mCanvas(aOther.mCanvas),
|
||||||
mIsAccelerated(aOther.mIsAccelerated),
|
|
||||||
mSourceSurface(aOther.mSourceSurface),
|
mSourceSurface(aOther.mSourceSurface),
|
||||||
mSize(aOther.mSize) {}
|
mSize(aOther.mSize) {}
|
||||||
explicit ImageCacheEntryData(const ImageCacheKey& aKey)
|
explicit ImageCacheEntryData(const ImageCacheKey& aKey)
|
||||||
: mImage(aKey.mImage),
|
: mImage(aKey.mImage),
|
||||||
mCanvas(aKey.mCanvas),
|
mCanvas(aKey.mCanvas) {}
|
||||||
mIsAccelerated(aKey.mIsAccelerated) {}
|
|
||||||
|
|
||||||
nsExpirationState* GetExpirationState() { return &mState; }
|
nsExpirationState* GetExpirationState() { return &mState; }
|
||||||
size_t SizeInBytes() { return mSize.width * mSize.height * 4; }
|
size_t SizeInBytes() { return mSize.width * mSize.height * 4; }
|
||||||
@ -57,7 +53,6 @@ struct ImageCacheEntryData {
|
|||||||
// Key
|
// Key
|
||||||
nsCOMPtr<imgIContainer> mImage;
|
nsCOMPtr<imgIContainer> mImage;
|
||||||
HTMLCanvasElement* mCanvas;
|
HTMLCanvasElement* mCanvas;
|
||||||
bool mIsAccelerated;
|
|
||||||
// Value
|
// Value
|
||||||
RefPtr<SourceSurface> mSourceSurface;
|
RefPtr<SourceSurface> mSourceSurface;
|
||||||
IntSize mSize;
|
IntSize mSize;
|
||||||
@ -76,13 +71,12 @@ class ImageCacheEntry : public PLDHashEntryHdr {
|
|||||||
~ImageCacheEntry() {}
|
~ImageCacheEntry() {}
|
||||||
|
|
||||||
bool KeyEquals(KeyTypePointer key) const {
|
bool KeyEquals(KeyTypePointer key) const {
|
||||||
return mData->mImage == key->mImage && mData->mCanvas == key->mCanvas &&
|
return mData->mImage == key->mImage && mData->mCanvas == key->mCanvas;
|
||||||
mData->mIsAccelerated == key->mIsAccelerated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
|
static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
|
||||||
static PLDHashNumber HashKey(KeyTypePointer 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 };
|
enum { ALLOW_MEMMOVE = true };
|
||||||
|
|
||||||
@ -93,11 +87,10 @@ class ImageCacheEntry : public PLDHashEntryHdr {
|
|||||||
* Used for all images across all canvases.
|
* Used for all images across all canvases.
|
||||||
*/
|
*/
|
||||||
struct AllCanvasImageCacheKey {
|
struct AllCanvasImageCacheKey {
|
||||||
AllCanvasImageCacheKey(imgIContainer* aImage, bool aIsAccelerated)
|
explicit AllCanvasImageCacheKey(imgIContainer* aImage)
|
||||||
: mImage(aImage), mIsAccelerated(aIsAccelerated) {}
|
: mImage(aImage) {}
|
||||||
|
|
||||||
nsCOMPtr<imgIContainer> mImage;
|
nsCOMPtr<imgIContainer> mImage;
|
||||||
bool mIsAccelerated;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AllCanvasImageCacheEntry : public PLDHashEntryHdr {
|
class AllCanvasImageCacheEntry : public PLDHashEntryHdr {
|
||||||
@ -106,27 +99,25 @@ class AllCanvasImageCacheEntry : public PLDHashEntryHdr {
|
|||||||
typedef const AllCanvasImageCacheKey* KeyTypePointer;
|
typedef const AllCanvasImageCacheKey* KeyTypePointer;
|
||||||
|
|
||||||
explicit AllCanvasImageCacheEntry(const KeyType* aKey)
|
explicit AllCanvasImageCacheEntry(const KeyType* aKey)
|
||||||
: mImage(aKey->mImage), mIsAccelerated(aKey->mIsAccelerated) {}
|
: mImage(aKey->mImage) {}
|
||||||
|
|
||||||
AllCanvasImageCacheEntry(const AllCanvasImageCacheEntry& toCopy)
|
AllCanvasImageCacheEntry(const AllCanvasImageCacheEntry& toCopy)
|
||||||
: mImage(toCopy.mImage),
|
: mImage(toCopy.mImage),
|
||||||
mIsAccelerated(toCopy.mIsAccelerated),
|
|
||||||
mSourceSurface(toCopy.mSourceSurface) {}
|
mSourceSurface(toCopy.mSourceSurface) {}
|
||||||
|
|
||||||
~AllCanvasImageCacheEntry() {}
|
~AllCanvasImageCacheEntry() {}
|
||||||
|
|
||||||
bool KeyEquals(KeyTypePointer key) const {
|
bool KeyEquals(KeyTypePointer key) const {
|
||||||
return mImage == key->mImage && mIsAccelerated == key->mIsAccelerated;
|
return mImage == key->mImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
|
static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
|
||||||
static PLDHashNumber HashKey(KeyTypePointer key) {
|
static PLDHashNumber HashKey(KeyTypePointer key) {
|
||||||
return HashGeneric(key->mImage.get(), key->mIsAccelerated);
|
return HashGeneric(key->mImage.get());
|
||||||
}
|
}
|
||||||
enum { ALLOW_MEMMOVE = true };
|
enum { ALLOW_MEMMOVE = true };
|
||||||
|
|
||||||
nsCOMPtr<imgIContainer> mImage;
|
nsCOMPtr<imgIContainer> mImage;
|
||||||
bool mIsAccelerated;
|
|
||||||
RefPtr<SourceSurface> mSourceSurface;
|
RefPtr<SourceSurface> mSourceSurface;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -149,11 +140,10 @@ class ImageCache final : public nsExpirationTracker<ImageCacheEntryData, 4> {
|
|||||||
// Remove from the all canvas cache entry first since nsExpirationTracker
|
// Remove from the all canvas cache entry first since nsExpirationTracker
|
||||||
// will delete aObject.
|
// will delete aObject.
|
||||||
mAllCanvasCache.RemoveEntry(
|
mAllCanvasCache.RemoveEntry(
|
||||||
AllCanvasImageCacheKey(aObject->mImage, aObject->mIsAccelerated));
|
AllCanvasImageCacheKey(aObject->mImage));
|
||||||
|
|
||||||
// Deleting the entry will delete aObject since the entry owns aObject.
|
// Deleting the entry will delete aObject since the entry owns aObject.
|
||||||
mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas,
|
mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas));
|
||||||
aObject->mIsAccelerated));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsTHashtable<ImageCacheEntry> mCache;
|
nsTHashtable<ImageCacheEntry> mCache;
|
||||||
@ -273,8 +263,7 @@ static already_AddRefed<imgIContainer> GetImageContainer(dom::Element* aImage) {
|
|||||||
void CanvasImageCache::NotifyDrawImage(Element* aImage,
|
void CanvasImageCache::NotifyDrawImage(Element* aImage,
|
||||||
HTMLCanvasElement* aCanvas,
|
HTMLCanvasElement* aCanvas,
|
||||||
SourceSurface* aSource,
|
SourceSurface* aSource,
|
||||||
const IntSize& aSize,
|
const IntSize& aSize) {
|
||||||
bool aIsAccelerated) {
|
|
||||||
if (!gImageCache) {
|
if (!gImageCache) {
|
||||||
gImageCache = new ImageCache();
|
gImageCache = new ImageCache();
|
||||||
nsContentUtils::RegisterShutdownObserver(
|
nsContentUtils::RegisterShutdownObserver(
|
||||||
@ -286,8 +275,8 @@ void CanvasImageCache::NotifyDrawImage(Element* aImage,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AllCanvasImageCacheKey allCanvasCacheKey(imgContainer, aIsAccelerated);
|
AllCanvasImageCacheKey allCanvasCacheKey(imgContainer);
|
||||||
ImageCacheKey canvasCacheKey(imgContainer, aCanvas, aIsAccelerated);
|
ImageCacheKey canvasCacheKey(imgContainer, aCanvas);
|
||||||
ImageCacheEntry* entry = gImageCache->mCache.PutEntry(canvasCacheKey);
|
ImageCacheEntry* entry = gImageCache->mCache.PutEntry(canvasCacheKey);
|
||||||
|
|
||||||
if (entry) {
|
if (entry) {
|
||||||
@ -317,8 +306,7 @@ void CanvasImageCache::NotifyDrawImage(Element* aImage,
|
|||||||
gImageCache->AgeOneGeneration();
|
gImageCache->AgeOneGeneration();
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage,
|
SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage) {
|
||||||
bool aIsAccelerated) {
|
|
||||||
if (!gImageCache) {
|
if (!gImageCache) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -329,7 +317,7 @@ SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage,
|
|||||||
}
|
}
|
||||||
|
|
||||||
AllCanvasImageCacheEntry* entry = gImageCache->mAllCanvasCache.GetEntry(
|
AllCanvasImageCacheEntry* entry = gImageCache->mAllCanvasCache.GetEntry(
|
||||||
AllCanvasImageCacheKey(imgContainer, aIsAccelerated));
|
AllCanvasImageCacheKey(imgContainer));
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -339,8 +327,7 @@ SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage,
|
|||||||
|
|
||||||
SourceSurface* CanvasImageCache::LookupCanvas(Element* aImage,
|
SourceSurface* CanvasImageCache::LookupCanvas(Element* aImage,
|
||||||
HTMLCanvasElement* aCanvas,
|
HTMLCanvasElement* aCanvas,
|
||||||
IntSize* aSizeOut,
|
IntSize* aSizeOut) {
|
||||||
bool aIsAccelerated) {
|
|
||||||
if (!gImageCache) {
|
if (!gImageCache) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -351,7 +338,7 @@ SourceSurface* CanvasImageCache::LookupCanvas(Element* aImage,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImageCacheEntry* entry = gImageCache->mCache.GetEntry(
|
ImageCacheEntry* entry = gImageCache->mCache.GetEntry(
|
||||||
ImageCacheKey(imgContainer, aCanvas, aIsAccelerated));
|
ImageCacheKey(imgContainer, aCanvas));
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -33,15 +33,13 @@ class CanvasImageCache {
|
|||||||
*/
|
*/
|
||||||
static void NotifyDrawImage(dom::Element* aImage,
|
static void NotifyDrawImage(dom::Element* aImage,
|
||||||
dom::HTMLCanvasElement* aCanvas,
|
dom::HTMLCanvasElement* aCanvas,
|
||||||
SourceSurface* aSource, const gfx::IntSize& aSize,
|
SourceSurface* aSource, const gfx::IntSize& aSize);
|
||||||
bool aIsAccelerated);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether aImage has recently been drawn any canvas. If we return
|
* 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.
|
* a non-null surface, then the same image was recently drawn into a canvas.
|
||||||
*/
|
*/
|
||||||
static SourceSurface* LookupAllCanvas(dom::Element* aImage,
|
static SourceSurface* LookupAllCanvas(dom::Element* aImage);
|
||||||
bool aIsAccelerated);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like the top above, but restricts the lookup to only aCanvas. This is
|
* 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,
|
static SourceSurface* LookupCanvas(dom::Element* aImage,
|
||||||
dom::HTMLCanvasElement* aCanvas,
|
dom::HTMLCanvasElement* aCanvas,
|
||||||
gfx::IntSize* aSizeOut,
|
gfx::IntSize* aSizeOut);
|
||||||
bool aIsAccelerated);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -106,8 +106,6 @@
|
|||||||
#include "mozilla/dom/SVGMatrix.h"
|
#include "mozilla/dom/SVGMatrix.h"
|
||||||
#include "mozilla/FloatingPoint.h"
|
#include "mozilla/FloatingPoint.h"
|
||||||
#include "nsGlobalWindow.h"
|
#include "nsGlobalWindow.h"
|
||||||
#include "GLContext.h"
|
|
||||||
#include "GLContextProvider.h"
|
|
||||||
#include "nsIScreenManager.h"
|
#include "nsIScreenManager.h"
|
||||||
#include "nsFilterInstance.h"
|
#include "nsFilterInstance.h"
|
||||||
#include "nsSVGLength2.h"
|
#include "nsSVGLength2.h"
|
||||||
@ -125,16 +123,6 @@
|
|||||||
|
|
||||||
#undef free // apparently defined by some windows header, clashing with a
|
#undef free // apparently defined by some windows header, clashing with a
|
||||||
// free() method in SkTypes.h
|
// 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
|
#ifdef XP_WIN
|
||||||
# include "gfxWindowsPlatform.h"
|
# include "gfxWindowsPlatform.h"
|
||||||
@ -760,105 +748,6 @@ CanvasShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
|
|||||||
return NS_OK;
|
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 {
|
class CanvasRenderingContext2DUserData : public LayerUserData {
|
||||||
public:
|
public:
|
||||||
explicit CanvasRenderingContext2DUserData(CanvasRenderingContext2D* aContext)
|
explicit CanvasRenderingContext2DUserData(CanvasRenderingContext2D* aContext)
|
||||||
@ -884,12 +773,6 @@ class CanvasRenderingContext2DUserData : public LayerUserData {
|
|||||||
static_cast<CanvasRenderingContext2D*>(aData);
|
static_cast<CanvasRenderingContext2D*>(aData);
|
||||||
if (context) {
|
if (context) {
|
||||||
context->MarkContextClean();
|
context->MarkContextClean();
|
||||||
if (context->mDrawObserver) {
|
|
||||||
if (context->mDrawObserver->FrameEnd()) {
|
|
||||||
// Note that this call deletes and nulls out mDrawObserver:
|
|
||||||
context->RemoveDrawObserver();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool IsForContext(CanvasRenderingContext2D* aContext) {
|
bool IsForContext(CanvasRenderingContext2D* aContext) {
|
||||||
@ -909,7 +792,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(CanvasRenderingContext2D)
|
|||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CanvasRenderingContext2D)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CanvasRenderingContext2D)
|
||||||
// Make sure we remove ourselves from the list of demotable contexts (raw
|
// Make sure we remove ourselves from the list of demotable contexts (raw
|
||||||
// pointers), since we're logically destructed at this point.
|
// pointers), since we're logically destructed at this point.
|
||||||
CanvasRenderingContext2D::RemoveDemotableContext(tmp);
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCanvasElement)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCanvasElement)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
|
||||||
for (uint32_t i = 0; i < tmp->mStyleStack.Length(); i++) {
|
for (uint32_t i = 0; i < tmp->mStyleStack.Length(); i++) {
|
||||||
@ -1000,15 +882,10 @@ NS_INTERFACE_MAP_END
|
|||||||
// Initialize our static variables.
|
// Initialize our static variables.
|
||||||
uintptr_t CanvasRenderingContext2D::sNumLivingContexts = 0;
|
uintptr_t CanvasRenderingContext2D::sNumLivingContexts = 0;
|
||||||
DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
|
DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
|
||||||
static bool sMaxContextsInitialized = false;
|
|
||||||
static int32_t sMaxContexts = 0;
|
|
||||||
|
|
||||||
CanvasRenderingContext2D::CanvasRenderingContext2D(
|
CanvasRenderingContext2D::CanvasRenderingContext2D(
|
||||||
layers::LayersBackend aCompositorBackend)
|
layers::LayersBackend aCompositorBackend)
|
||||||
: mRenderingMode(RenderingMode::OpenGLBackendMode),
|
: // these are the default values from the Canvas spec
|
||||||
mCompositorBackend(aCompositorBackend)
|
|
||||||
// these are the default values from the Canvas spec
|
|
||||||
,
|
|
||||||
mWidth(0),
|
mWidth(0),
|
||||||
mHeight(0),
|
mHeight(0),
|
||||||
mZero(false),
|
mZero(false),
|
||||||
@ -1017,35 +894,21 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(
|
|||||||
mOpaque(false),
|
mOpaque(false),
|
||||||
mResetLayer(true),
|
mResetLayer(true),
|
||||||
mIPC(false),
|
mIPC(false),
|
||||||
mIsSkiaGL(false),
|
|
||||||
mHasPendingStableStateCallback(false),
|
mHasPendingStableStateCallback(false),
|
||||||
mDrawObserver(nullptr),
|
|
||||||
mIsEntireFrameInvalid(false),
|
mIsEntireFrameInvalid(false),
|
||||||
mPredictManyRedrawCalls(false),
|
mPredictManyRedrawCalls(false),
|
||||||
mIsCapturedFrameInvalid(false),
|
mIsCapturedFrameInvalid(false),
|
||||||
mPathTransformWillUpdate(false),
|
mPathTransformWillUpdate(false),
|
||||||
mInvalidateCount(0),
|
mInvalidateCount(0),
|
||||||
mWriteOnly(false) {
|
mWriteOnly(false) {
|
||||||
if (!sMaxContextsInitialized) {
|
|
||||||
sMaxContexts = gfxPrefs::CanvasAzureAcceleratedLimit();
|
|
||||||
sMaxContextsInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
sNumLivingContexts++;
|
sNumLivingContexts++;
|
||||||
|
|
||||||
mShutdownObserver = new CanvasShutdownObserver(this);
|
mShutdownObserver = new CanvasShutdownObserver(this);
|
||||||
nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
|
nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
|
||||||
|
|
||||||
// The default is to use OpenGL mode
|
|
||||||
if (AllowOpenGLCanvas()) {
|
|
||||||
mDrawObserver = new CanvasDrawObserver(this);
|
|
||||||
} else {
|
|
||||||
mRenderingMode = RenderingMode::SoftwareBackendMode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CanvasRenderingContext2D::~CanvasRenderingContext2D() {
|
CanvasRenderingContext2D::~CanvasRenderingContext2D() {
|
||||||
RemoveDrawObserver();
|
|
||||||
RemovePostRefreshObserver();
|
RemovePostRefreshObserver();
|
||||||
RemoveShutdownObserver();
|
RemoveShutdownObserver();
|
||||||
Reset();
|
Reset();
|
||||||
@ -1057,7 +920,6 @@ CanvasRenderingContext2D::~CanvasRenderingContext2D() {
|
|||||||
if (!sNumLivingContexts) {
|
if (!sNumLivingContexts) {
|
||||||
NS_IF_RELEASE(sErrorTarget);
|
NS_IF_RELEASE(sErrorTarget);
|
||||||
}
|
}
|
||||||
RemoveDemotableContext(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* CanvasRenderingContext2D::WrapObject(
|
JSObject* CanvasRenderingContext2D::WrapObject(
|
||||||
@ -1228,13 +1090,6 @@ void CanvasRenderingContext2D::Redraw(const gfx::Rect& aR) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CanvasRenderingContext2D::DidRefresh() {
|
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) {
|
void CanvasRenderingContext2D::RedrawUser(const gfxRect& aR) {
|
||||||
@ -1249,70 +1104,6 @@ void CanvasRenderingContext2D::RedrawUser(const gfxRect& aR) {
|
|||||||
Redraw(newr);
|
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(
|
bool CanvasRenderingContext2D::CopyBufferProvider(
|
||||||
PersistentBufferProvider& aOld, DrawTarget& aTarget, IntRect aCopyRect) {
|
PersistentBufferProvider& aOld, DrawTarget& aTarget, IntRect aCopyRect) {
|
||||||
// Borrowing the snapshot must be done after ReturnTarget.
|
// Borrowing the snapshot must be done after ReturnTarget.
|
||||||
@ -1328,119 +1119,6 @@ bool CanvasRenderingContext2D::CopyBufferProvider(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CanvasRenderingContext2D::Demote() {
|
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() {
|
void CanvasRenderingContext2D::ScheduleStableStateCallback() {
|
||||||
@ -1489,30 +1167,22 @@ void CanvasRenderingContext2D::RestoreClipsAndTransformToTarget() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
|
bool CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect) {
|
||||||
const gfx::Rect* aCoveredRect, RenderingMode aRenderingMode) {
|
|
||||||
if (AlreadyShutDown()) {
|
if (AlreadyShutDown()) {
|
||||||
gfxCriticalError() << "Attempt to render into a Canvas2d after shutdown.";
|
gfxCriticalError() << "Attempt to render into a Canvas2d after shutdown.";
|
||||||
SetErrorState();
|
SetErrorState();
|
||||||
return aRenderingMode;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This would make no sense, so make sure we don't get ourselves in a mess
|
if (mTarget) {
|
||||||
MOZ_ASSERT(mRenderingMode != RenderingMode::DefaultBackendMode);
|
return true;
|
||||||
|
|
||||||
RenderingMode mode = (aRenderingMode == RenderingMode::DefaultBackendMode)
|
|
||||||
? mRenderingMode
|
|
||||||
: aRenderingMode;
|
|
||||||
|
|
||||||
if (mTarget && mode == mRenderingMode) {
|
|
||||||
return mRenderingMode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the dimensions are sane
|
// Check that the dimensions are sane
|
||||||
if (mWidth > gfxPrefs::MaxCanvasSize() ||
|
if (mWidth > gfxPrefs::MaxCanvasSize() ||
|
||||||
mHeight > gfxPrefs::MaxCanvasSize() || mWidth < 0 || mHeight < 0) {
|
mHeight > gfxPrefs::MaxCanvasSize() || mWidth < 0 || mHeight < 0) {
|
||||||
SetErrorState();
|
SetErrorState();
|
||||||
return aRenderingMode;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the next drawing command covers the entire canvas, we can skip copying
|
// If the next drawing command covers the entire canvas, we can skip copying
|
||||||
@ -1542,7 +1212,7 @@ CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
|
|||||||
IntRect persistedRect =
|
IntRect persistedRect =
|
||||||
canDiscardContent ? IntRect() : IntRect(0, 0, mWidth, mHeight);
|
canDiscardContent ? IntRect() : IntRect(0, 0, mWidth, mHeight);
|
||||||
|
|
||||||
if (mBufferProvider && mode == mRenderingMode) {
|
if (mBufferProvider) {
|
||||||
mTarget = mBufferProvider->BorrowDrawTarget(persistedRect);
|
mTarget = mBufferProvider->BorrowDrawTarget(persistedRect);
|
||||||
|
|
||||||
if (mTarget && !mBufferProvider->PreservesDrawingState()) {
|
if (mTarget && !mBufferProvider->PreservesDrawingState()) {
|
||||||
@ -1550,28 +1220,21 @@ CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mTarget) {
|
if (mTarget) {
|
||||||
return mode;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<DrawTarget> newTarget;
|
RefPtr<DrawTarget> newTarget;
|
||||||
RefPtr<PersistentBufferProvider> newProvider;
|
RefPtr<PersistentBufferProvider> newProvider;
|
||||||
|
|
||||||
if (mode == RenderingMode::OpenGLBackendMode &&
|
if (!TrySharedTarget(newTarget, newProvider) &&
|
||||||
!TrySkiaGLTarget(newTarget, newProvider)) {
|
|
||||||
// Fall back to software.
|
|
||||||
mode = RenderingMode::SoftwareBackendMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == RenderingMode::SoftwareBackendMode &&
|
|
||||||
!TrySharedTarget(newTarget, newProvider) &&
|
|
||||||
!TryBasicTarget(newTarget, newProvider)) {
|
!TryBasicTarget(newTarget, newProvider)) {
|
||||||
gfxCriticalError(
|
gfxCriticalError(
|
||||||
CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(GetSize())))
|
CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(GetSize())))
|
||||||
<< "Failed borrow shared and basic targets.";
|
<< "Failed borrow shared and basic targets.";
|
||||||
|
|
||||||
SetErrorState();
|
SetErrorState();
|
||||||
return mode;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(newTarget);
|
MOZ_ASSERT(newTarget);
|
||||||
@ -1612,7 +1275,7 @@ CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
|
|||||||
// canvas is already invalid, which can speed up future drawing.
|
// canvas is already invalid, which can speed up future drawing.
|
||||||
Redraw();
|
Redraw();
|
||||||
|
|
||||||
return mode;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasRenderingContext2D::SetInitialState() {
|
void CanvasRenderingContext2D::SetInitialState() {
|
||||||
@ -1672,57 +1335,6 @@ static already_AddRefed<LayerManager> LayerManagerFromCanvasElement(
|
|||||||
aCanvasElement->OwnerDoc());
|
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(
|
bool CanvasRenderingContext2D::TrySharedTarget(
|
||||||
RefPtr<gfx::DrawTarget>& aOutDT,
|
RefPtr<gfx::DrawTarget>& aOutDT,
|
||||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider) {
|
RefPtr<layers::PersistentBufferProvider>& aOutProvider) {
|
||||||
@ -1912,16 +1524,6 @@ CanvasRenderingContext2D::SetContextOptions(JSContext* aCx,
|
|||||||
return NS_ERROR_UNEXPECTED;
|
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;
|
mContextAttributesHasAlpha = attributes.mAlpha;
|
||||||
UpdateIsOpaque();
|
UpdateIsOpaque();
|
||||||
|
|
||||||
@ -4537,7 +4139,7 @@ CanvasRenderingContext2D::CachedSurfaceFromElement(Element* aElement) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.mSourceSurface = CanvasImageCache::LookupAllCanvas(aElement, mIsSkiaGL);
|
res.mSourceSurface = CanvasImageCache::LookupAllCanvas(aElement);
|
||||||
if (!res.mSourceSurface) {
|
if (!res.mSourceSurface) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -4576,10 +4178,6 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
|
|||||||
double aDw, double aDh,
|
double aDw, double aDh,
|
||||||
uint8_t aOptional_argc,
|
uint8_t aOptional_argc,
|
||||||
ErrorResult& aError) {
|
ErrorResult& aError) {
|
||||||
if (mDrawObserver) {
|
|
||||||
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::DrawImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(aOptional_argc == 0 || aOptional_argc == 2 || aOptional_argc == 6);
|
MOZ_ASSERT(aOptional_argc == 0 || aOptional_argc == 2 || aOptional_argc == 6);
|
||||||
|
|
||||||
if (!ValidateRect(aDx, aDy, aDw, aDh, true)) {
|
if (!ValidateRect(aDx, aDy, aDw, aDh, true)) {
|
||||||
@ -4640,8 +4238,7 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
|
|||||||
element = video;
|
element = video;
|
||||||
}
|
}
|
||||||
|
|
||||||
srcSurf = CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize,
|
srcSurf = CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize);
|
||||||
mIsSkiaGL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsLayoutUtils::DirectDrawInfo drawInfo;
|
nsLayoutUtils::DirectDrawInfo drawInfo;
|
||||||
@ -4692,7 +4289,7 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
|
|||||||
if (res.mSourceSurface) {
|
if (res.mSourceSurface) {
|
||||||
if (res.mImageRequest) {
|
if (res.mImageRequest) {
|
||||||
CanvasImageCache::NotifyDrawImage(
|
CanvasImageCache::NotifyDrawImage(
|
||||||
element, mCanvasElement, res.mSourceSurface, imgSize, mIsSkiaGL);
|
element, mCanvasElement, res.mSourceSurface, imgSize);
|
||||||
}
|
}
|
||||||
srcSurf = res.mSourceSurface;
|
srcSurf = res.mSourceSurface;
|
||||||
} else {
|
} else {
|
||||||
@ -5118,10 +4715,6 @@ void CanvasRenderingContext2D::DrawWindow(nsGlobalWindowInner& aWindow,
|
|||||||
already_AddRefed<ImageData> CanvasRenderingContext2D::GetImageData(
|
already_AddRefed<ImageData> CanvasRenderingContext2D::GetImageData(
|
||||||
JSContext* aCx, double aSx, double aSy, double aSw, double aSh,
|
JSContext* aCx, double aSx, double aSy, double aSw, double aSh,
|
||||||
nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) {
|
nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) {
|
||||||
if (mDrawObserver) {
|
|
||||||
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::GetImageData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mCanvasElement && !mDocShell) {
|
if (!mCanvasElement && !mDocShell) {
|
||||||
NS_ERROR("No canvas element and no docshell in GetImageData!!!");
|
NS_ERROR("No canvas element and no docshell in GetImageData!!!");
|
||||||
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||||
@ -5190,10 +4783,6 @@ already_AddRefed<ImageData> CanvasRenderingContext2D::GetImageData(
|
|||||||
nsresult CanvasRenderingContext2D::GetImageDataArray(
|
nsresult CanvasRenderingContext2D::GetImageDataArray(
|
||||||
JSContext* aCx, int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight,
|
JSContext* aCx, int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight,
|
||||||
nsIPrincipal& aSubjectPrincipal, JSObject** aRetval) {
|
nsIPrincipal& aSubjectPrincipal, JSObject** aRetval) {
|
||||||
if (mDrawObserver) {
|
|
||||||
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::GetImageData);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(aWidth && aHeight);
|
MOZ_ASSERT(aWidth && aHeight);
|
||||||
|
|
||||||
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
|
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,
|
int32_t aX, int32_t aY, uint32_t aW, uint32_t aH,
|
||||||
dom::Uint8ClampedArray* aArray, bool aHasDirtyRect, int32_t aDirtyX,
|
dom::Uint8ClampedArray* aArray, bool aHasDirtyRect, int32_t aDirtyX,
|
||||||
int32_t aDirtyY, int32_t aDirtyWidth, int32_t aDirtyHeight) {
|
int32_t aDirtyY, int32_t aDirtyWidth, int32_t aDirtyHeight) {
|
||||||
if (mDrawObserver) {
|
|
||||||
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::PutImageData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aW == 0 || aH == 0) {
|
if (aW == 0 || aH == 0) {
|
||||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||||
}
|
}
|
||||||
@ -5520,29 +5105,11 @@ already_AddRefed<ImageData> CanvasRenderingContext2D::CreateImageData(
|
|||||||
|
|
||||||
static uint8_t g2DContextLayerUserData;
|
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(
|
already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
|
||||||
nsDisplayListBuilder* aBuilder, Layer* aOldLayer, LayerManager* aManager) {
|
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
|
// If we're opaque then make sure we have a surface so we paint black
|
||||||
// instead of transparent.
|
// instead of transparent.
|
||||||
// If we're using SkiaGL, then SkiaGLTex() below needs the target to
|
|
||||||
// be accessible.
|
|
||||||
EnsureTarget();
|
EnsureTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5563,16 +5130,6 @@ already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
|
|||||||
|
|
||||||
CanvasInitializeData data;
|
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;
|
data.mBufferProvider = mBufferProvider;
|
||||||
|
|
||||||
if (userData && userData->IsForContext(this) &&
|
if (userData && userData->IsForContext(this) &&
|
||||||
@ -5619,11 +5176,9 @@ already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
|
|||||||
|
|
||||||
bool CanvasRenderingContext2D::UpdateWebRenderCanvasData(
|
bool CanvasRenderingContext2D::UpdateWebRenderCanvasData(
|
||||||
nsDisplayListBuilder* aBuilder, WebRenderCanvasData* aCanvasData) {
|
nsDisplayListBuilder* aBuilder, WebRenderCanvasData* aCanvasData) {
|
||||||
if (mOpaque || mIsSkiaGL) {
|
if (mOpaque) {
|
||||||
// If we're opaque then make sure we have a surface so we paint black
|
// If we're opaque then make sure we have a surface so we paint black
|
||||||
// instead of transparent.
|
// instead of transparent.
|
||||||
// If we're using SkiaGL, then SkiaGLTex() below needs the target to
|
|
||||||
// be accessible.
|
|
||||||
EnsureTarget();
|
EnsureTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5645,15 +5200,6 @@ bool CanvasRenderingContext2D::UpdateWebRenderCanvasData(
|
|||||||
if (!mResetLayer && renderer) {
|
if (!mResetLayer && renderer) {
|
||||||
CanvasInitializeData data;
|
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;
|
data.mBufferProvider = mBufferProvider;
|
||||||
|
|
||||||
if (renderer->IsDataValid(data)) {
|
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;
|
data.mBufferProvider = mBufferProvider;
|
||||||
|
|
||||||
aRenderer->Initialize(data);
|
aRenderer->Initialize(data);
|
||||||
|
@ -376,14 +376,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
|
|||||||
double aH, const nsAString& aBgColor, uint32_t aFlags,
|
double aH, const nsAString& aBgColor, uint32_t aFlags,
|
||||||
mozilla::ErrorResult& aError);
|
mozilla::ErrorResult& aError);
|
||||||
|
|
||||||
enum RenderingMode {
|
|
||||||
SoftwareBackendMode,
|
|
||||||
OpenGLBackendMode,
|
|
||||||
DefaultBackendMode
|
|
||||||
};
|
|
||||||
|
|
||||||
bool SwitchRenderingMode(RenderingMode aRenderingMode);
|
|
||||||
|
|
||||||
// Eventually this should be deprecated. Keeping for now to keep the binding
|
// Eventually this should be deprecated. Keeping for now to keep the binding
|
||||||
// functional.
|
// functional.
|
||||||
void Demote();
|
void Demote();
|
||||||
@ -509,9 +501,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
|
|||||||
|
|
||||||
void OnShutdown();
|
void OnShutdown();
|
||||||
|
|
||||||
// Check the global setup, as well as the compositor type:
|
|
||||||
bool AllowOpenGLCanvas() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update CurrentState().filter with the filter description for
|
* Update CurrentState().filter with the filter description for
|
||||||
* CurrentState().filterChain.
|
* CurrentState().filterChain.
|
||||||
@ -616,17 +605,12 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
|
|||||||
* is in turn an error in creating the sErrorTarget then they would both
|
* is in turn an error in creating the sErrorTarget then they would both
|
||||||
* be null so IsTargetValid() would still return null.
|
* 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(
|
bool EnsureTarget(const gfx::Rect* aCoveredRect = nullptr);
|
||||||
const gfx::Rect* aCoveredRect = nullptr,
|
|
||||||
RenderingMode aRenderMode = RenderingMode::DefaultBackendMode);
|
|
||||||
|
|
||||||
void RestoreClipsAndTransformToTarget();
|
void RestoreClipsAndTransformToTarget();
|
||||||
|
|
||||||
bool TrySkiaGLTarget(RefPtr<gfx::DrawTarget>& aOutDT,
|
|
||||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
|
|
||||||
|
|
||||||
bool TrySharedTarget(RefPtr<gfx::DrawTarget>& aOutDT,
|
bool TrySharedTarget(RefPtr<gfx::DrawTarget>& aOutDT,
|
||||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
|
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
|
||||||
|
|
||||||
@ -704,19 +688,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
|
|||||||
return CurrentState().font;
|
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
|
// Member vars
|
||||||
int32_t mWidth, mHeight;
|
int32_t mWidth, mHeight;
|
||||||
|
|
||||||
@ -742,9 +713,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
|
|||||||
bool mResetLayer;
|
bool mResetLayer;
|
||||||
// This is needed for drawing in drawAsyncXULElement
|
// This is needed for drawing in drawAsyncXULElement
|
||||||
bool mIPC;
|
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;
|
bool mHasPendingStableStateCallback;
|
||||||
|
|
||||||
@ -760,14 +728,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
|
|||||||
|
|
||||||
RefPtr<mozilla::layers::PersistentBufferProvider> mBufferProvider;
|
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;
|
RefPtr<CanvasShutdownObserver> mShutdownObserver;
|
||||||
void RemoveShutdownObserver();
|
void RemoveShutdownObserver();
|
||||||
bool AlreadyShutDown() const { return !mShutdownObserver; }
|
bool AlreadyShutDown() const { return !mShutdownObserver; }
|
||||||
@ -919,8 +879,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
|
|||||||
const Optional<double>& aMaxWidth,
|
const Optional<double>& aMaxWidth,
|
||||||
TextDrawOperation aOp, float* aWidth);
|
TextDrawOperation aOp, float* aWidth);
|
||||||
|
|
||||||
bool CheckSizeForSkiaGL(mozilla::gfx::IntSize aSize);
|
|
||||||
|
|
||||||
// A clip or a transform, recorded and restored in order.
|
// A clip or a transform, recorded and restored in order.
|
||||||
struct ClipState {
|
struct ClipState {
|
||||||
explicit ClipState(mozilla::gfx::Path* aClip) : clip(aClip) {}
|
explicit ClipState(mozilla::gfx::Path* aClip) : clip(aClip) {}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
#include "CanvasRenderingContext2D.h"
|
#include "CanvasRenderingContext2D.h"
|
||||||
#include "CanvasUtils.h"
|
#include "CanvasUtils.h"
|
||||||
|
#include "GLContext.h"
|
||||||
#include "GLScreenBuffer.h"
|
#include "GLScreenBuffer.h"
|
||||||
#include "WebGL1Context.h"
|
#include "WebGL1Context.h"
|
||||||
#include "WebGL2Context.h"
|
#include "WebGL2Context.h"
|
||||||
|
@ -43,17 +43,6 @@ function IsAzureSkia() {
|
|||||||
return enabled;
|
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() {
|
function IsAzureCairo() {
|
||||||
var enabled = false;
|
var enabled = false;
|
||||||
|
|
||||||
@ -6585,9 +6574,6 @@ isPixel(ctx, 98,48, 0,255,0,255, 0);
|
|||||||
|
|
||||||
function test_2d_gradient_radial_inside1() {
|
function test_2d_gradient_radial_inside1() {
|
||||||
|
|
||||||
if (IsAcceleratedSkia())
|
|
||||||
return;
|
|
||||||
|
|
||||||
var canvas = document.getElementById('c240');
|
var canvas = document.getElementById('c240');
|
||||||
var ctx = canvas.getContext('2d');
|
var ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
@ -20,12 +20,31 @@
|
|||||||
#include "mozilla/dom/TimeRanges.h"
|
#include "mozilla/dom/TimeRanges.h"
|
||||||
#include "AudioStream.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 mozilla {
|
||||||
namespace dom {
|
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)
|
HTMLAudioElement::HTMLAudioElement(already_AddRefed<NodeInfo>&& aNodeInfo)
|
||||||
: HTMLMediaElement(std::move(aNodeInfo)) {
|
: HTMLMediaElement(std::move(aNodeInfo)) {
|
||||||
@ -54,7 +73,8 @@ already_AddRefed<HTMLAudioElement> HTMLAudioElement::Audio(
|
|||||||
RefPtr<mozilla::dom::NodeInfo> nodeInfo = doc->NodeInfoManager()->GetNodeInfo(
|
RefPtr<mozilla::dom::NodeInfo> nodeInfo = doc->NodeInfoManager()->GetNodeInfo(
|
||||||
nsGkAtoms::audio, nullptr, kNameSpaceID_XHTML, ELEMENT_NODE);
|
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);
|
audio->SetHTMLAttr(nsGkAtoms::preload, NS_LITERAL_STRING("auto"), aRv);
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -3499,13 +3499,27 @@ HTMLMediaElement::HTMLMediaElement(
|
|||||||
mShutdownObserver(new ShutdownObserver),
|
mShutdownObserver(new ShutdownObserver),
|
||||||
mPlayed(new TimeRanges(ToSupports(OwnerDoc()))),
|
mPlayed(new TimeRanges(ToSupports(OwnerDoc()))),
|
||||||
mPaused(true, "HTMLMediaElement::mPaused"),
|
mPaused(true, "HTMLMediaElement::mPaused"),
|
||||||
mAudioTrackList(new AudioTrackList(OwnerDoc()->GetParentObject(), this)),
|
|
||||||
mVideoTrackList(new VideoTrackList(OwnerDoc()->GetParentObject(), this)),
|
|
||||||
mErrorSink(new ErrorSink(this)),
|
mErrorSink(new ErrorSink(this)),
|
||||||
mAudioChannelWrapper(new AudioChannelAgentCallback(this)),
|
mAudioChannelWrapper(new AudioChannelAgentCallback(this)),
|
||||||
mSink(MakePair(nsString(), RefPtr<AudioDeviceInfo>())) {
|
mSink(MakePair(nsString(), RefPtr<AudioDeviceInfo>())) {
|
||||||
MOZ_ASSERT(mMainThreadEventTarget);
|
MOZ_ASSERT(mMainThreadEventTarget);
|
||||||
MOZ_ASSERT(mAbstractMainThread);
|
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);
|
DecoderDoctorLogger::LogConstruction(this);
|
||||||
|
|
||||||
@ -3526,9 +3540,12 @@ HTMLMediaElement::HTMLMediaElement(
|
|||||||
MediaShutdownManager::InitStatics();
|
MediaShutdownManager::InitStatics();
|
||||||
|
|
||||||
mShutdownObserver->Subscribe(this);
|
mShutdownObserver->Subscribe(this);
|
||||||
|
mInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
HTMLMediaElement::~HTMLMediaElement() {
|
HTMLMediaElement::~HTMLMediaElement() {
|
||||||
|
MOZ_ASSERT(mInitialized,
|
||||||
|
"HTMLMediaElement must be initialized before it is destroyed.");
|
||||||
NS_ASSERTION(
|
NS_ASSERTION(
|
||||||
!mHasSelfReference,
|
!mHasSelfReference,
|
||||||
"How can we be destroyed if we're still holding a self reference?");
|
"How can we be destroyed if we're still holding a self reference?");
|
||||||
|
@ -117,6 +117,7 @@ class HTMLMediaElement : public nsGenericHTMLElement,
|
|||||||
|
|
||||||
explicit HTMLMediaElement(
|
explicit HTMLMediaElement(
|
||||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
|
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
|
||||||
|
void Init();
|
||||||
|
|
||||||
void ReportCanPlayTelemetry();
|
void ReportCanPlayTelemetry();
|
||||||
|
|
||||||
@ -1750,6 +1751,9 @@ class HTMLMediaElement : public nsGenericHTMLElement,
|
|||||||
// threshold.
|
// threshold.
|
||||||
void ReportPlayedTimeAfterBlockedTelemetry();
|
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
|
// True if user has called load(), seek() or element has started playing
|
||||||
// before. It's *only* use for checking autoplay policy
|
// before. It's *only* use for checking autoplay policy
|
||||||
bool mIsBlessed = false;
|
bool mIsBlessed = false;
|
||||||
|
@ -35,14 +35,33 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
#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 mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
static bool sVideoStatsEnabled;
|
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)
|
HTMLVideoElement::HTMLVideoElement(already_AddRefed<NodeInfo>&& aNodeInfo)
|
||||||
: HTMLMediaElement(std::move(aNodeInfo)), mIsOrientationLocked(false) {
|
: HTMLMediaElement(std::move(aNodeInfo)), mIsOrientationLocked(false) {
|
||||||
@ -308,7 +327,8 @@ void HTMLVideoElement::ReleaseVideoWakeLockIfExists() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLVideoElement::Init() {
|
/* static */
|
||||||
|
void HTMLVideoElement::InitStatics() {
|
||||||
Preferences::AddBoolVarCache(&sVideoStatsEnabled,
|
Preferences::AddBoolVarCache(&sVideoStatsEnabled,
|
||||||
"media.video_stats.enabled");
|
"media.video_stats.enabled");
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ class HTMLVideoElement final : public HTMLMediaElement {
|
|||||||
nsAttrValue& aResult) override;
|
nsAttrValue& aResult) override;
|
||||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
|
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
|
||||||
|
|
||||||
static void Init();
|
static void InitStatics();
|
||||||
|
|
||||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction()
|
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction()
|
||||||
const override;
|
const override;
|
||||||
|
@ -1636,6 +1636,7 @@ void nsTextEditorState::SetSelectionRange(
|
|||||||
props.SetEnd(aEnd);
|
props.SetEnd(aEnd);
|
||||||
props.SetDirection(aDirection);
|
props.SetDirection(aDirection);
|
||||||
} else {
|
} else {
|
||||||
|
MOZ_ASSERT(mBoundFrame, "Our frame should still be valid");
|
||||||
WeakPtr<nsTextEditorState> self(this);
|
WeakPtr<nsTextEditorState> self(this);
|
||||||
aRv = mBoundFrame->SetSelectionRange(aStart, aEnd, aDirection);
|
aRv = mBoundFrame->SetSelectionRange(aStart, aEnd, aDirection);
|
||||||
if (aRv.Failed() || !self.get()) {
|
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
|
// TODO(emilio): It seems wrong to pass ValueChangeKind::Script if
|
||||||
// BySetUserInput is in aFlags.
|
// BySetUserInput is in aFlags.
|
||||||
auto changeKind = (aFlags & eSetValue_Internal)
|
auto changeKind = (aFlags & eSetValue_Internal) ? ValueChangeKind::Internal
|
||||||
? ValueChangeKind::Internal
|
: ValueChangeKind::Script;
|
||||||
: ValueChangeKind::Script;
|
|
||||||
|
|
||||||
// XXX Should we stop notifying "value changed" if mTextCtrlElement has
|
// XXX Should we stop notifying "value changed" if mTextCtrlElement has
|
||||||
// been cleared?
|
// been cleared?
|
||||||
|
@ -1273,7 +1273,8 @@ void ContentChild::InitXPCOM(
|
|||||||
|
|
||||||
mozilla::ipc::IPCResult ContentChild::RecvRequestMemoryReport(
|
mozilla::ipc::IPCResult ContentChild::RecvRequestMemoryReport(
|
||||||
const uint32_t& aGeneration, const bool& aAnonymize,
|
const uint32_t& aGeneration, const bool& aAnonymize,
|
||||||
const bool& aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile) {
|
const bool& aMinimizeMemoryUsage,
|
||||||
|
const Maybe<mozilla::ipc::FileDescriptor>& aDMDFile) {
|
||||||
nsCString process;
|
nsCString process;
|
||||||
GetProcessName(process);
|
GetProcessName(process);
|
||||||
AppendProcessId(process);
|
AppendProcessId(process);
|
||||||
@ -1611,7 +1612,7 @@ static bool StartMacOSContentSandbox() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
mozilla::ipc::IPCResult ContentChild::RecvSetProcessSandbox(
|
mozilla::ipc::IPCResult ContentChild::RecvSetProcessSandbox(
|
||||||
const MaybeFileDesc& aBroker) {
|
const Maybe<mozilla::ipc::FileDescriptor>& aBroker) {
|
||||||
// We may want to move the sandbox initialization somewhere else
|
// We may want to move the sandbox initialization somewhere else
|
||||||
// at some point; see bug 880808.
|
// at some point; see bug 880808.
|
||||||
#if defined(MOZ_CONTENT_SANDBOX)
|
#if defined(MOZ_CONTENT_SANDBOX)
|
||||||
@ -3918,4 +3919,4 @@ nsresult GetObjDir(nsIFile** aObjDir) {
|
|||||||
}
|
}
|
||||||
#endif /* XP_MACOSX */
|
#endif /* XP_MACOSX */
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -188,12 +188,12 @@ class ContentChild final : public PContentChild,
|
|||||||
Endpoint<PVideoDecoderManagerChild>&& aVideoManager,
|
Endpoint<PVideoDecoderManagerChild>&& aVideoManager,
|
||||||
nsTArray<uint32_t>&& namespaces);
|
nsTArray<uint32_t>&& namespaces);
|
||||||
|
|
||||||
virtual mozilla::ipc::IPCResult RecvAudioDefaultDeviceChange();
|
mozilla::ipc::IPCResult RecvAudioDefaultDeviceChange();
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvReinitRenderingForDeviceReset();
|
mozilla::ipc::IPCResult RecvReinitRenderingForDeviceReset();
|
||||||
|
|
||||||
virtual mozilla::ipc::IPCResult RecvSetProcessSandbox(
|
mozilla::ipc::IPCResult RecvSetProcessSandbox(
|
||||||
const MaybeFileDesc& aBroker);
|
const Maybe<FileDescriptor>& aBroker);
|
||||||
|
|
||||||
PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
|
PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
|
||||||
const TabId& aSameTabGroupAs,
|
const TabId& aSameTabGroupAs,
|
||||||
@ -361,7 +361,7 @@ class ContentChild final : public PContentChild,
|
|||||||
mozilla::ipc::IPCResult RecvNotifyAlertsObserver(const nsCString& aType,
|
mozilla::ipc::IPCResult RecvNotifyAlertsObserver(const nsCString& aType,
|
||||||
const nsString& aData);
|
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,
|
mozilla::ipc::IPCResult RecvAsyncMessage(const nsString& aMsg,
|
||||||
InfallibleTArray<CpowEntry>&& aCpows,
|
InfallibleTArray<CpowEntry>&& aCpows,
|
||||||
@ -576,7 +576,7 @@ class ContentChild final : public PContentChild,
|
|||||||
|
|
||||||
mozilla::ipc::IPCResult RecvRequestMemoryReport(
|
mozilla::ipc::IPCResult RecvRequestMemoryReport(
|
||||||
const uint32_t& generation, const bool& anonymize,
|
const uint32_t& generation, const bool& anonymize,
|
||||||
const bool& minimizeMemoryUsage, const MaybeFileDesc& DMDFile);
|
const bool& minimizeMemoryUsage, const Maybe<FileDescriptor>& DMDFile);
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes(
|
mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes(
|
||||||
const XPCOMInitData& aXPCOMInit, const StructuredCloneData& aInitialData,
|
const XPCOMInitData& aXPCOMInit, const StructuredCloneData& aInitialData,
|
||||||
@ -822,4 +822,4 @@ uint64_t NextWindowID();
|
|||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif // mozilla_dom_ContentChild_h
|
#endif // mozilla_dom_ContentChild_h
|
||||||
|
@ -2568,7 +2568,7 @@ void ContentParent::InitInternal(ProcessPriority aInitialPriority) {
|
|||||||
|
|
||||||
#ifdef MOZ_CONTENT_SANDBOX
|
#ifdef MOZ_CONTENT_SANDBOX
|
||||||
bool shouldSandbox = true;
|
bool shouldSandbox = true;
|
||||||
MaybeFileDesc brokerFd = void_t();
|
Maybe<FileDescriptor> brokerFd;
|
||||||
// XXX: Checking the pref here makes it possible to enable/disable sandboxing
|
// XXX: Checking the pref here makes it possible to enable/disable sandboxing
|
||||||
// during an active session. Currently the pref is only used for testing
|
// 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
|
// 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 =
|
UniquePtr<SandboxBroker::Policy> policy =
|
||||||
sSandboxBrokerPolicyFactory->GetContentPolicy(Pid(), isFileProcess);
|
sSandboxBrokerPolicyFactory->GetContentPolicy(Pid(), isFileProcess);
|
||||||
if (policy) {
|
if (policy) {
|
||||||
brokerFd = FileDescriptor();
|
brokerFd = Some(FileDescriptor());
|
||||||
mSandboxBroker =
|
mSandboxBroker =
|
||||||
SandboxBroker::Create(std::move(policy), Pid(), brokerFd);
|
SandboxBroker::Create(std::move(policy), Pid(), brokerFd.ref());
|
||||||
if (!mSandboxBroker) {
|
if (!mSandboxBroker) {
|
||||||
KillHard("SandboxBroker::Create failed");
|
KillHard("SandboxBroker::Create failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(static_cast<const FileDescriptor&>(brokerFd).IsValid());
|
MOZ_ASSERT(brokerFd.ref().IsValid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
@ -3455,10 +3455,9 @@ bool ContentParent::DeallocPHeapSnapshotTempFileHelperParent(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContentParent::SendRequestMemoryReport(const uint32_t& aGeneration,
|
bool ContentParent::SendRequestMemoryReport(
|
||||||
const bool& aAnonymize,
|
const uint32_t& aGeneration, const bool& aAnonymize,
|
||||||
const bool& aMinimizeMemoryUsage,
|
const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
|
||||||
const MaybeFileDesc& aDMDFile) {
|
|
||||||
// This automatically cancels the previous request.
|
// This automatically cancels the previous request.
|
||||||
mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
|
mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
|
||||||
Unused << PContentParent::SendRequestMemoryReport(
|
Unused << PContentParent::SendRequestMemoryReport(
|
||||||
@ -5923,4 +5922,4 @@ ParentIdleListener::Observe(nsISupports*, const char* aTopic,
|
|||||||
mozilla::Unused << mParent->SendNotifyIdleObserver(
|
mozilla::Unused << mParent->SendNotifyIdleObserver(
|
||||||
mObserver, nsDependentCString(aTopic), nsDependentString(aData));
|
mObserver, nsDependentCString(aTopic), nsDependentString(aData));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -1170,7 +1170,7 @@ class ContentParent final : public PContentParent,
|
|||||||
bool SendRequestMemoryReport(const uint32_t& aGeneration,
|
bool SendRequestMemoryReport(const uint32_t& aGeneration,
|
||||||
const bool& aAnonymize,
|
const bool& aAnonymize,
|
||||||
const bool& aMinimizeMemoryUsage,
|
const bool& aMinimizeMemoryUsage,
|
||||||
const MaybeFileDesc& aDMDFile) override;
|
const Maybe<FileDescriptor>& aDMDFile) override;
|
||||||
|
|
||||||
nsresult SaveRecording(nsIFile* aFile, bool* aRetval);
|
nsresult SaveRecording(nsIFile* aFile, bool* aRetval);
|
||||||
|
|
||||||
|
@ -50,13 +50,11 @@ MemoryReportRequestHost::~MemoryReportRequestHost() {
|
|||||||
|
|
||||||
NS_IMPL_ISUPPORTS(MemoryReportRequestClient, nsIRunnable)
|
NS_IMPL_ISUPPORTS(MemoryReportRequestClient, nsIRunnable)
|
||||||
|
|
||||||
/* static */
|
/* static */ void MemoryReportRequestClient::Start(
|
||||||
void MemoryReportRequestClient::Start(uint32_t aGeneration, bool aAnonymize,
|
uint32_t aGeneration, bool aAnonymize, bool aMinimizeMemoryUsage,
|
||||||
bool aMinimizeMemoryUsage,
|
const Maybe<FileDescriptor>& aDMDFile, const nsACString& aProcessString,
|
||||||
const MaybeFileDesc& aDMDFile,
|
const ReportCallback& aReportCallback,
|
||||||
const nsACString& aProcessString,
|
const FinishCallback& aFinishCallback) {
|
||||||
const ReportCallback& aReportCallback,
|
|
||||||
const FinishCallback& aFinishCallback) {
|
|
||||||
RefPtr<MemoryReportRequestClient> request = new MemoryReportRequestClient(
|
RefPtr<MemoryReportRequestClient> request = new MemoryReportRequestClient(
|
||||||
aGeneration, aAnonymize, aDMDFile, aProcessString, aReportCallback,
|
aGeneration, aAnonymize, aDMDFile, aProcessString, aReportCallback,
|
||||||
aFinishCallback);
|
aFinishCallback);
|
||||||
@ -75,16 +73,17 @@ void MemoryReportRequestClient::Start(uint32_t aGeneration, bool aAnonymize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
MemoryReportRequestClient::MemoryReportRequestClient(
|
MemoryReportRequestClient::MemoryReportRequestClient(
|
||||||
uint32_t aGeneration, bool aAnonymize, const MaybeFileDesc& aDMDFile,
|
uint32_t aGeneration, bool aAnonymize,
|
||||||
const nsACString& aProcessString, const ReportCallback& aReportCallback,
|
const Maybe<FileDescriptor>& aDMDFile, const nsACString& aProcessString,
|
||||||
|
const ReportCallback& aReportCallback,
|
||||||
const FinishCallback& aFinishCallback)
|
const FinishCallback& aFinishCallback)
|
||||||
: mGeneration(aGeneration),
|
: mGeneration(aGeneration),
|
||||||
mAnonymize(aAnonymize),
|
mAnonymize(aAnonymize),
|
||||||
mProcessString(aProcessString),
|
mProcessString(aProcessString),
|
||||||
mReportCallback(aReportCallback),
|
mReportCallback(aReportCallback),
|
||||||
mFinishCallback(aFinishCallback) {
|
mFinishCallback(aFinishCallback) {
|
||||||
if (aDMDFile.type() == MaybeFileDesc::TFileDescriptor) {
|
if (aDMDFile.isSome()) {
|
||||||
mDMDFile = aDMDFile.get_FileDescriptor();
|
mDMDFile = aDMDFile.value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ class nsMemoryReporterManager;
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
class MaybeFileDesc;
|
|
||||||
class MemoryReport;
|
class MemoryReport;
|
||||||
|
|
||||||
class MemoryReportRequestHost final {
|
class MemoryReportRequestHost final {
|
||||||
@ -44,7 +43,8 @@ class MemoryReportRequestClient final : public nsIRunnable {
|
|||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
static void Start(uint32_t aGeneration, bool aAnonymize,
|
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 nsACString& aProcessString,
|
||||||
const ReportCallback& aReportCallback,
|
const ReportCallback& aReportCallback,
|
||||||
const FinishCallback& aFinishCallback);
|
const FinishCallback& aFinishCallback);
|
||||||
@ -53,7 +53,7 @@ class MemoryReportRequestClient final : public nsIRunnable {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
MemoryReportRequestClient(uint32_t aGeneration, bool aAnonymize,
|
MemoryReportRequestClient(uint32_t aGeneration, bool aAnonymize,
|
||||||
const MaybeFileDesc& aDMDFile,
|
const Maybe<mozilla::ipc::FileDescriptor>& aDMDFile,
|
||||||
const nsACString& aProcessString,
|
const nsACString& aProcessString,
|
||||||
const ReportCallback& aReportCallback,
|
const ReportCallback& aReportCallback,
|
||||||
const FinishCallback& aFinishCallback);
|
const FinishCallback& aFinishCallback);
|
||||||
|
@ -18,10 +18,5 @@ struct MemoryReport {
|
|||||||
nsCString desc;
|
nsCString desc;
|
||||||
};
|
};
|
||||||
|
|
||||||
union MaybeFileDesc {
|
|
||||||
FileDescriptor;
|
|
||||||
void_t;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,12 +435,12 @@ child:
|
|||||||
* usually only be performed zero or one times. The child may
|
* usually only be performed zero or one times. The child may
|
||||||
* abnormally exit if this fails; the details are OS-specific.
|
* abnormally exit if this fails; the details are OS-specific.
|
||||||
*/
|
*/
|
||||||
async SetProcessSandbox(MaybeFileDesc aBroker);
|
async SetProcessSandbox(FileDescriptor? aBroker);
|
||||||
|
|
||||||
async RequestMemoryReport(uint32_t generation,
|
async RequestMemoryReport(uint32_t generation,
|
||||||
bool anonymize,
|
bool anonymize,
|
||||||
bool minimizeMemoryUsage,
|
bool minimizeMemoryUsage,
|
||||||
MaybeFileDesc DMDFile);
|
FileDescriptor? DMDFile);
|
||||||
async RequestPerformanceMetrics(nsID aID);
|
async RequestPerformanceMetrics(nsID aID);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1294,4 +1294,4 @@ both:
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,55 +5,38 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||||
#include "nsISerializable.h"
|
#include "mozilla/ipc/BackgroundUtils.h"
|
||||||
#include "nsSerializationHelper.h"
|
|
||||||
|
|
||||||
namespace IPC {
|
namespace mozilla {
|
||||||
|
namespace ipc {
|
||||||
|
|
||||||
void ParamTraits<nsIPrincipal>::Write(Message* aMsg, nsIPrincipal* aParam) {
|
void IPDLParamTraits<nsIPrincipal>::Write(IPC::Message* aMsg, IProtocol* aActor,
|
||||||
bool isNull = !aParam;
|
nsIPrincipal* aParam) {
|
||||||
WriteParam(aMsg, isNull);
|
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
|
||||||
if (isNull) {
|
|
||||||
return;
|
Maybe<PrincipalInfo> info;
|
||||||
|
if (aParam) {
|
||||||
|
info.emplace();
|
||||||
|
nsresult rv = PrincipalToPrincipalInfo(aParam, info.ptr());
|
||||||
|
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCString principalString;
|
WriteIPDLParam(aMsg, aActor, info);
|
||||||
nsresult rv = NS_SerializeToString(aParam, principalString);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
MOZ_CRASH("Unable to serialize principal.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteParam(aMsg, principalString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParamTraits<nsIPrincipal>::Read(const Message* aMsg, PickleIterator* aIter,
|
bool IPDLParamTraits<nsIPrincipal>::Read(const IPC::Message* aMsg,
|
||||||
RefPtr<nsIPrincipal>* aResult) {
|
PickleIterator* aIter,
|
||||||
bool isNull;
|
IProtocol* aActor,
|
||||||
if (!ReadParam(aMsg, aIter, &isNull)) {
|
RefPtr<nsIPrincipal>* aResult) {
|
||||||
|
Maybe<PrincipalInfo> info;
|
||||||
|
if (!ReadIPDLParam(aMsg, aIter, aActor, &info)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNull) {
|
nsresult rv = NS_OK;
|
||||||
*aResult = nullptr;
|
*aResult = info ? PrincipalInfoToPrincipal(info.ref(), &rv) : nullptr;
|
||||||
return true;
|
return NS_SUCCEEDED(rv);
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace IPC
|
} // namespace ipc
|
||||||
|
} // namespace mozilla
|
||||||
|
@ -7,24 +7,18 @@
|
|||||||
#ifndef mozilla_dom_permission_message_utils_h__
|
#ifndef mozilla_dom_permission_message_utils_h__
|
||||||
#define mozilla_dom_permission_message_utils_h__
|
#define mozilla_dom_permission_message_utils_h__
|
||||||
|
|
||||||
|
#include "mozilla/ipc/IPDLParamTraits.h"
|
||||||
#include "ipc/IPCMessageUtils.h"
|
#include "ipc/IPCMessageUtils.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsIPrincipal.h"
|
#include "nsIPrincipal.h"
|
||||||
|
|
||||||
namespace IPC {
|
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.
|
* Legacy IPC::Principal type. Use nsIPrincipal directly in new IPDL code.
|
||||||
*/
|
*/
|
||||||
class Principal {
|
class Principal {
|
||||||
friend struct ParamTraits<Principal>;
|
friend struct mozilla::ipc::IPDLParamTraits<Principal>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Principal() : mPrincipal(nullptr) {}
|
Principal() : mPrincipal(nullptr) {}
|
||||||
@ -42,18 +36,44 @@ class Principal {
|
|||||||
RefPtr<nsIPrincipal> mPrincipal;
|
RefPtr<nsIPrincipal> mPrincipal;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace IPC
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace ipc {
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct ParamTraits<Principal> {
|
struct IPDLParamTraits<nsIPrincipal> {
|
||||||
typedef Principal paramType;
|
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
||||||
static void Write(Message* aMsg, const paramType& aParam) {
|
nsIPrincipal* aParam);
|
||||||
WriteParam(aMsg, aParam.mPrincipal);
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
||||||
}
|
IProtocol* aActor, RefPtr<nsIPrincipal>* aResult);
|
||||||
static bool Read(const Message* aMsg, PickleIterator* aIter,
|
|
||||||
paramType* aResult) {
|
// Overload to support deserializing nsCOMPtr<nsIPrincipal> directly.
|
||||||
return ReadParam(aMsg, aIter, &aResult->mPrincipal);
|
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__
|
#endif // mozilla_dom_permission_message_utils_h__
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "MediaFormatReader.h"
|
#include "MediaFormatReader.h"
|
||||||
|
|
||||||
#include "AllocationPolicy.h"
|
#include "AllocationPolicy.h"
|
||||||
|
#include "GeckoProfiler.h"
|
||||||
#include "MediaData.h"
|
#include "MediaData.h"
|
||||||
#include "MediaInfo.h"
|
#include "MediaInfo.h"
|
||||||
#include "VideoFrameContainer.h"
|
#include "VideoFrameContainer.h"
|
||||||
@ -2631,6 +2632,7 @@ void MediaFormatReader::SkipVideoDemuxToNextKeyFrame(TimeUnit aTimeThreshold) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MediaFormatReader::VideoSkipReset(uint32_t aSkipped) {
|
void MediaFormatReader::VideoSkipReset(uint32_t aSkipped) {
|
||||||
|
PROFILER_ADD_MARKER("SkippedVideoDecode", GRAPHICS);
|
||||||
MOZ_ASSERT(OnTaskQueue());
|
MOZ_ASSERT(OnTaskQueue());
|
||||||
|
|
||||||
// Some frames may have been output by the decoder since we initiated the
|
// Some frames may have been output by the decoder since we initiated the
|
||||||
|
@ -21,7 +21,7 @@ protocol PRDD
|
|||||||
parent:
|
parent:
|
||||||
|
|
||||||
// args TBD, sent by UI process to initiate core settings
|
// args TBD, sent by UI process to initiate core settings
|
||||||
async Init(MaybeFileDesc sandboxBroker);
|
async Init(FileDescriptor? sandboxBroker);
|
||||||
|
|
||||||
async InitProfiler(Endpoint<PProfilerChild> endpoint);
|
async InitProfiler(Endpoint<PProfilerChild> endpoint);
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ parent:
|
|||||||
async RequestMemoryReport(uint32_t generation,
|
async RequestMemoryReport(uint32_t generation,
|
||||||
bool anonymize,
|
bool anonymize,
|
||||||
bool minimizeMemoryUsage,
|
bool minimizeMemoryUsage,
|
||||||
MaybeFileDesc DMDFile);
|
FileDescriptor? DMDFile);
|
||||||
|
|
||||||
child:
|
child:
|
||||||
// args TBD, sent when init complete. Occurs once, after Init().
|
// args TBD, sent when init complete. Occurs once, after Init().
|
||||||
|
@ -29,20 +29,20 @@ RDDChild::RDDChild(RDDProcessHost* aHost) : mHost(aHost), mRDDReady(false) {
|
|||||||
RDDChild::~RDDChild() { MOZ_COUNT_DTOR(RDDChild); }
|
RDDChild::~RDDChild() { MOZ_COUNT_DTOR(RDDChild); }
|
||||||
|
|
||||||
bool RDDChild::Init() {
|
bool RDDChild::Init() {
|
||||||
MaybeFileDesc brokerFd = void_t();
|
Maybe<FileDescriptor> brokerFd;
|
||||||
|
|
||||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||||
auto policy = SandboxBrokerPolicyFactory::GetUtilityPolicy(OtherPid());
|
auto policy = SandboxBrokerPolicyFactory::GetUtilityPolicy(OtherPid());
|
||||||
if (policy != nullptr) {
|
if (policy != nullptr) {
|
||||||
brokerFd = FileDescriptor();
|
brokerFd = Some(FileDescriptor());
|
||||||
mSandboxBroker =
|
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
|
// This is unlikely to fail and probably indicates OS resource
|
||||||
// exhaustion, but we can at least try to recover.
|
// exhaustion, but we can at least try to recover.
|
||||||
if (NS_WARN_IF(mSandboxBroker == nullptr)) {
|
if (NS_WARN_IF(mSandboxBroker == nullptr)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(static_cast<const FileDescriptor&>(brokerFd).IsValid());
|
MOZ_ASSERT(brokerFd.ref().IsValid());
|
||||||
}
|
}
|
||||||
#endif // XP_LINUX && MOZ_SANDBOX
|
#endif // XP_LINUX && MOZ_SANDBOX
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ mozilla::ipc::IPCResult RDDChild::RecvInitCrashReporter(
|
|||||||
bool RDDChild::SendRequestMemoryReport(const uint32_t& aGeneration,
|
bool RDDChild::SendRequestMemoryReport(const uint32_t& aGeneration,
|
||||||
const bool& aAnonymize,
|
const bool& aAnonymize,
|
||||||
const bool& aMinimizeMemoryUsage,
|
const bool& aMinimizeMemoryUsage,
|
||||||
const MaybeFileDesc& aDMDFile) {
|
const Maybe<FileDescriptor>& aDMDFile) {
|
||||||
mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
|
mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
|
||||||
Unused << PRDDChild::SendRequestMemoryReport(aGeneration, aAnonymize,
|
Unused << PRDDChild::SendRequestMemoryReport(aGeneration, aAnonymize,
|
||||||
aMinimizeMemoryUsage, aDMDFile);
|
aMinimizeMemoryUsage, aDMDFile);
|
||||||
|
@ -49,7 +49,7 @@ class RDDChild final : public PRDDChild {
|
|||||||
bool SendRequestMemoryReport(const uint32_t& aGeneration,
|
bool SendRequestMemoryReport(const uint32_t& aGeneration,
|
||||||
const bool& aAnonymize,
|
const bool& aAnonymize,
|
||||||
const bool& aMinimizeMemoryUsage,
|
const bool& aMinimizeMemoryUsage,
|
||||||
const MaybeFileDesc& aDMDFile);
|
const Maybe<ipc::FileDescriptor>& aDMDFile);
|
||||||
|
|
||||||
static void Destroy(UniquePtr<RDDChild>&& aChild);
|
static void Destroy(UniquePtr<RDDChild>&& aChild);
|
||||||
|
|
||||||
|
@ -128,15 +128,16 @@ static void StartRDDMacSandbox() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RDDParent::RecvInit(const MaybeFileDesc& aBrokerFd) {
|
mozilla::ipc::IPCResult RDDParent::RecvInit(
|
||||||
|
const Maybe<FileDescriptor>& aBrokerFd) {
|
||||||
Unused << SendInitComplete();
|
Unused << SendInitComplete();
|
||||||
#if defined(MOZ_SANDBOX)
|
#if defined(MOZ_SANDBOX)
|
||||||
# if defined(XP_MACOSX)
|
# if defined(XP_MACOSX)
|
||||||
StartRDDMacSandbox();
|
StartRDDMacSandbox();
|
||||||
# elif defined(XP_LINUX)
|
# elif defined(XP_LINUX)
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
if (aBrokerFd.type() == MaybeFileDesc::TFileDescriptor) {
|
if (aBrokerFd.isSome()) {
|
||||||
fd = aBrokerFd.get_FileDescriptor().ClonePlatformHandle().release();
|
fd = aBrokerFd.value().ClonePlatformHandle().release();
|
||||||
}
|
}
|
||||||
SetRemoteDataDecoderSandbox(fd);
|
SetRemoteDataDecoderSandbox(fd);
|
||||||
# endif // XP_MACOSX/XP_LINUX
|
# endif // XP_MACOSX/XP_LINUX
|
||||||
@ -163,7 +164,7 @@ mozilla::ipc::IPCResult RDDParent::RecvNewContentRemoteDecoderManager(
|
|||||||
|
|
||||||
mozilla::ipc::IPCResult RDDParent::RecvRequestMemoryReport(
|
mozilla::ipc::IPCResult RDDParent::RecvRequestMemoryReport(
|
||||||
const uint32_t& aGeneration, const bool& aAnonymize,
|
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());
|
nsPrintfCString processName("RDD (pid %u)", (unsigned)getpid());
|
||||||
|
|
||||||
mozilla::dom::MemoryReportRequestClient::Start(
|
mozilla::dom::MemoryReportRequestClient::Start(
|
||||||
|
@ -24,7 +24,7 @@ class RDDParent final : public PRDDParent {
|
|||||||
bool Init(base::ProcessId aParentPid, const char* aParentBuildID,
|
bool Init(base::ProcessId aParentPid, const char* aParentBuildID,
|
||||||
MessageLoop* aIOLoop, IPC::Channel* aChannel);
|
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(
|
mozilla::ipc::IPCResult RecvInitProfiler(
|
||||||
Endpoint<PProfilerChild>&& aEndpoint);
|
Endpoint<PProfilerChild>&& aEndpoint);
|
||||||
|
|
||||||
@ -32,7 +32,8 @@ class RDDParent final : public PRDDParent {
|
|||||||
Endpoint<PRemoteDecoderManagerParent>&& aEndpoint);
|
Endpoint<PRemoteDecoderManagerParent>&& aEndpoint);
|
||||||
mozilla::ipc::IPCResult RecvRequestMemoryReport(
|
mozilla::ipc::IPCResult RecvRequestMemoryReport(
|
||||||
const uint32_t& generation, const bool& anonymize,
|
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;
|
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||||
|
|
||||||
|
@ -221,10 +221,10 @@ class RDDMemoryReporter : public MemoryReportingProcess {
|
|||||||
|
|
||||||
bool IsAlive() const override { return !!GetChild(); }
|
bool IsAlive() const override { return !!GetChild(); }
|
||||||
|
|
||||||
bool SendRequestMemoryReport(const uint32_t& aGeneration,
|
bool SendRequestMemoryReport(
|
||||||
const bool& aAnonymize,
|
const uint32_t& aGeneration, const bool& aAnonymize,
|
||||||
const bool& aMinimizeMemoryUsage,
|
const bool& aMinimizeMemoryUsage,
|
||||||
const dom::MaybeFileDesc& aDMDFile) override {
|
const Maybe<ipc::FileDescriptor>& aDMDFile) override {
|
||||||
RDDChild* child = GetChild();
|
RDDChild* child = GetChild();
|
||||||
if (!child) {
|
if (!child) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -10,8 +10,10 @@
|
|||||||
# include "mmsystem.h"
|
# include "mmsystem.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "MediaQueue.h"
|
|
||||||
#include "VideoSink.h"
|
#include "VideoSink.h"
|
||||||
|
|
||||||
|
#include "GeckoProfiler.h"
|
||||||
|
#include "MediaQueue.h"
|
||||||
#include "VideoUtils.h"
|
#include "VideoUtils.h"
|
||||||
|
|
||||||
#include "mozilla/IntegerPrintfMacros.h"
|
#include "mozilla/IntegerPrintfMacros.h"
|
||||||
@ -451,6 +453,10 @@ void VideoSink::UpdateRenderedVideoFrames() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (droppedCount > 0) {
|
||||||
|
PROFILER_ADD_MARKER("DroppedUncompositedVideoFrames", GRAPHICS);
|
||||||
|
}
|
||||||
|
|
||||||
if (droppedCount || sentToCompositorCount) {
|
if (droppedCount || sentToCompositorCount) {
|
||||||
uint32_t totalCompositorDroppedCount = mContainer->GetDroppedImageCount();
|
uint32_t totalCompositorDroppedCount = mContainer->GetDroppedImageCount();
|
||||||
uint32_t compositorDroppedCount =
|
uint32_t compositorDroppedCount =
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
("%s: " arg, __func__, ##__VA_ARGS__))
|
("%s: " arg, __func__, ##__VA_ARGS__))
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::gl;
|
|
||||||
using namespace mozilla::java::sdk;
|
using namespace mozilla::java::sdk;
|
||||||
using media::TimeUnit;
|
using media::TimeUnit;
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ nsresult CreatePrincipalInfo(nsILineInputStream* aStream,
|
|||||||
// CSP will be applied during the script load.
|
// CSP will be applied during the script load.
|
||||||
nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
|
nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
|
||||||
aEntry->principal() = mozilla::ipc::ContentPrincipalInfo(
|
aEntry->principal() = mozilla::ipc::ContentPrincipalInfo(
|
||||||
attrs, origin, aEntry->scope(), std::move(policies));
|
attrs, origin, aEntry->scope(), Nothing(), std::move(policies));
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,7 @@ class CompareCallback {
|
|||||||
|
|
||||||
nsresult Compare(ServiceWorkerRegistrationInfo* aRegistration,
|
nsresult Compare(ServiceWorkerRegistrationInfo* aRegistration,
|
||||||
nsIPrincipal* aPrincipal, const nsAString& aCacheName,
|
nsIPrincipal* aPrincipal, const nsAString& aCacheName,
|
||||||
const nsAString& aURL, CompareCallback* aCallback,
|
const nsAString& aURL, CompareCallback* aCallback);
|
||||||
nsILoadGroup* aLoadGroup);
|
|
||||||
|
|
||||||
} // namespace serviceWorkerScriptCache
|
} // namespace serviceWorkerScriptCache
|
||||||
|
|
||||||
|
@ -274,7 +274,8 @@ TEST(ServiceWorkerRegistrar, TestWriteData) {
|
|||||||
|
|
||||||
nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
|
nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
|
||||||
reg.principal() = mozilla::ipc::ContentPrincipalInfo(
|
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);
|
swr->TestRegisterServiceWorker(reg);
|
||||||
}
|
}
|
||||||
@ -863,7 +864,8 @@ TEST(ServiceWorkerRegistrar, TestDedupeWrite) {
|
|||||||
|
|
||||||
nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
|
nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
|
||||||
reg.principal() = mozilla::ipc::ContentPrincipalInfo(
|
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);
|
swr->TestRegisterServiceWorker(reg);
|
||||||
}
|
}
|
||||||
|
13
gfx/2d/2D.h
13
gfx/2d/2D.h
@ -66,7 +66,6 @@ struct IDWriteRenderingParams;
|
|||||||
struct IDWriteFontFace;
|
struct IDWriteFontFace;
|
||||||
struct IDWriteFontCollection;
|
struct IDWriteFontCollection;
|
||||||
|
|
||||||
class GrContext;
|
|
||||||
class SkCanvas;
|
class SkCanvas;
|
||||||
struct gfxFontStyle;
|
struct gfxFontStyle;
|
||||||
|
|
||||||
@ -1508,13 +1507,6 @@ class DrawTarget : public external::AtomicRefCounted<DrawTarget> {
|
|||||||
*/
|
*/
|
||||||
virtual void DetachAllSnapshots() = 0;
|
virtual void DetachAllSnapshots() = 0;
|
||||||
|
|
||||||
#ifdef USE_SKIA_GPU
|
|
||||||
virtual bool InitWithGrContext(GrContext *aGrContext, const IntSize &aSize,
|
|
||||||
SurfaceFormat aFormat) {
|
|
||||||
MOZ_CRASH("GFX: InitWithGrContext");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
UserData mUserData;
|
UserData mUserData;
|
||||||
Matrix mTransform;
|
Matrix mTransform;
|
||||||
@ -1749,11 +1741,6 @@ class GFX2D_API Factory {
|
|||||||
static Config *sConfig;
|
static Config *sConfig;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#ifdef USE_SKIA_GPU
|
|
||||||
static already_AddRefed<DrawTarget> CreateDrawTargetSkiaWithGrContext(
|
|
||||||
GrContext *aGrContext, const IntSize &aSize, SurfaceFormat aFormat);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void PurgeAllCaches();
|
static void PurgeAllCaches();
|
||||||
|
|
||||||
static already_AddRefed<DrawTarget> CreateDualDrawTarget(DrawTarget *targetA,
|
static already_AddRefed<DrawTarget> CreateDualDrawTarget(DrawTarget *targetA,
|
||||||
|
@ -29,13 +29,6 @@
|
|||||||
#include "Swizzle.h"
|
#include "Swizzle.h"
|
||||||
#include <algorithm>
|
#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
|
#ifdef MOZ_WIDGET_COCOA
|
||||||
# include "BorrowedContext.h"
|
# include "BorrowedContext.h"
|
||||||
# include <ApplicationServices/ApplicationServices.h>
|
# include <ApplicationServices/ApplicationServices.h>
|
||||||
@ -649,11 +642,6 @@ void DrawTargetSkia::DrawSurface(SourceSurface* aSurface, const Rect& aDest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
DrawTargetType DrawTargetSkia::GetType() const {
|
DrawTargetType DrawTargetSkia::GetType() const {
|
||||||
#ifdef USE_SKIA_GPU
|
|
||||||
if (mGrContext) {
|
|
||||||
return DrawTargetType::HARDWARE_RASTER;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return DrawTargetType::SOFTWARE_RASTER;
|
return DrawTargetType::SOFTWARE_RASTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,10 +688,9 @@ void DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface* aSurface,
|
|||||||
auto shadowDest = IntPoint::Round(aDest + aOffset);
|
auto shadowDest = IntPoint::Round(aDest + aOffset);
|
||||||
|
|
||||||
SkBitmap blurMask;
|
SkBitmap blurMask;
|
||||||
if (!UsingSkiaGPU() && ExtractAlphaBitmap(image, &blurMask)) {
|
if (ExtractAlphaBitmap(image, &blurMask)) {
|
||||||
// Prefer using our own box blur instead of Skia's when we're
|
// Prefer using our own box blur instead of Skia's. It currently performs
|
||||||
// not using the GPU. It currently performs much better than
|
// much better than SkBlurImageFilter or SkBlurMaskFilter on the CPU.
|
||||||
// SkBlurImageFilter or SkBlurMaskFilter on the CPU.
|
|
||||||
AlphaBoxBlur blur(Rect(0, 0, blurMask.width(), blurMask.height()),
|
AlphaBoxBlur blur(Rect(0, 0, blurMask.width(), blurMask.height()),
|
||||||
int32_t(blurMask.rowBytes()), aSigma, aSigma);
|
int32_t(blurMask.rowBytes()), aSigma, aSigma);
|
||||||
blur.Blur(reinterpret_cast<uint8_t*>(blurMask.getPixels()));
|
blur.Blur(reinterpret_cast<uint8_t*>(blurMask.getPixels()));
|
||||||
@ -1587,18 +1574,6 @@ already_AddRefed<SourceSurface> DrawTargetSkia::CreateSourceSurfaceFromData(
|
|||||||
already_AddRefed<DrawTarget> DrawTargetSkia::CreateSimilarDrawTarget(
|
already_AddRefed<DrawTarget> DrawTargetSkia::CreateSimilarDrawTarget(
|
||||||
const IntSize& aSize, SurfaceFormat aFormat) const {
|
const IntSize& aSize, SurfaceFormat aFormat) const {
|
||||||
RefPtr<DrawTargetSkia> target = new DrawTargetSkia();
|
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
|
#ifdef DEBUG
|
||||||
if (!IsBackedByPixels(mCanvas)) {
|
if (!IsBackedByPixels(mCanvas)) {
|
||||||
// If our canvas is backed by vector storage such as PDF then we want to
|
// 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();
|
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>
|
already_AddRefed<SourceSurface>
|
||||||
DrawTargetSkia::OptimizeSourceSurfaceForUnknownAlpha(
|
DrawTargetSkia::OptimizeSourceSurfaceForUnknownAlpha(
|
||||||
SourceSurface* aSurface) const {
|
SourceSurface* aSurface) const {
|
||||||
#ifdef USE_SKIA_GPU
|
|
||||||
if (UsingSkiaGPU()) {
|
|
||||||
return OptimizeGPUSourceSurface(aSurface);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (aSurface->GetType() == SurfaceType::SKIA) {
|
if (aSurface->GetType() == SurfaceType::SKIA) {
|
||||||
RefPtr<SourceSurface> surface(aSurface);
|
RefPtr<SourceSurface> surface(aSurface);
|
||||||
return surface.forget();
|
return surface.forget();
|
||||||
@ -1690,12 +1617,6 @@ DrawTargetSkia::OptimizeSourceSurfaceForUnknownAlpha(
|
|||||||
|
|
||||||
already_AddRefed<SourceSurface> DrawTargetSkia::OptimizeSourceSurface(
|
already_AddRefed<SourceSurface> DrawTargetSkia::OptimizeSourceSurface(
|
||||||
SourceSurface* aSurface) const {
|
SourceSurface* aSurface) const {
|
||||||
#ifdef USE_SKIA_GPU
|
|
||||||
if (UsingSkiaGPU()) {
|
|
||||||
return OptimizeGPUSourceSurface(aSurface);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (aSurface->GetType() == SurfaceType::SKIA) {
|
if (aSurface->GetType() == SurfaceType::SKIA) {
|
||||||
RefPtr<SourceSurface> surface(aSurface);
|
RefPtr<SourceSurface> surface(aSurface);
|
||||||
return surface.forget();
|
return surface.forget();
|
||||||
@ -1714,48 +1635,9 @@ already_AddRefed<SourceSurface> DrawTargetSkia::OptimizeSourceSurface(
|
|||||||
return dataSurface.forget();
|
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>
|
already_AddRefed<SourceSurface>
|
||||||
DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(
|
DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(
|
||||||
const NativeSurface& aSurface) const {
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1838,55 +1720,6 @@ bool DrawTargetSkia::Init(SkCanvas* aCanvas) {
|
|||||||
return true;
|
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,
|
bool DrawTargetSkia::Init(unsigned char* aData, const IntSize& aSize,
|
||||||
int32_t aStride, SurfaceFormat aFormat,
|
int32_t aStride, SurfaceFormat aFormat,
|
||||||
bool aUninitialized) {
|
bool aUninitialized) {
|
||||||
@ -1914,16 +1747,6 @@ void DrawTargetSkia::SetTransform(const Matrix& aTransform) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void* DrawTargetSkia::GetNativeSurface(NativeSurfaceType aType) {
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,18 +130,6 @@ class DrawTargetSkia : public DrawTarget {
|
|||||||
SurfaceFormat aFormat, bool aUninitialized = false);
|
SurfaceFormat aFormat, bool aUninitialized = false);
|
||||||
bool Init(SkCanvas *aCanvas);
|
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.
|
// Skia assumes that texture sizes fit in 16-bit signed integers.
|
||||||
static size_t GetMaxSurfaceSize() { return 32767; }
|
static size_t GetMaxSurfaceSize() { return 32767; }
|
||||||
|
|
||||||
@ -163,8 +151,6 @@ class DrawTargetSkia : public DrawTarget {
|
|||||||
const StrokeOptions *aStrokeOptions = nullptr,
|
const StrokeOptions *aStrokeOptions = nullptr,
|
||||||
const DrawOptions &aOptions = DrawOptions());
|
const DrawOptions &aOptions = DrawOptions());
|
||||||
|
|
||||||
bool UsingSkiaGPU() const;
|
|
||||||
|
|
||||||
struct PushedLayer {
|
struct PushedLayer {
|
||||||
PushedLayer(bool aOldPermitSubpixelAA, SourceSurface *aMask)
|
PushedLayer(bool aOldPermitSubpixelAA, SourceSurface *aMask)
|
||||||
: mOldPermitSubpixelAA(aOldPermitSubpixelAA), mMask(aMask) {}
|
: mOldPermitSubpixelAA(aOldPermitSubpixelAA), mMask(aMask) {}
|
||||||
@ -173,10 +159,6 @@ class DrawTargetSkia : public DrawTarget {
|
|||||||
};
|
};
|
||||||
std::vector<PushedLayer> mPushedLayers;
|
std::vector<PushedLayer> mPushedLayers;
|
||||||
|
|
||||||
#ifdef USE_SKIA_GPU
|
|
||||||
sk_sp<GrContext> mGrContext;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
IntSize mSize;
|
IntSize mSize;
|
||||||
sk_sp<SkSurface> mSurface;
|
sk_sp<SkSurface> mSurface;
|
||||||
SkCanvas *mCanvas;
|
SkCanvas *mCanvas;
|
||||||
|
@ -920,18 +920,6 @@ already_AddRefed<ScaledFont> Factory::CreateScaledFontForDWriteFont(
|
|||||||
|
|
||||||
#endif // WIN32
|
#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
|
#ifdef USE_SKIA
|
||||||
already_AddRefed<DrawTarget> Factory::CreateDrawTargetWithSkCanvas(
|
already_AddRefed<DrawTarget> Factory::CreateDrawTargetWithSkCanvas(
|
||||||
SkCanvas* aCanvas) {
|
SkCanvas* aCanvas) {
|
||||||
|
@ -125,16 +125,6 @@ uint8_t* SourceSurfaceSkia::GetData() {
|
|||||||
if (!mImage) {
|
if (!mImage) {
|
||||||
return nullptr;
|
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;
|
SkPixmap pixmap;
|
||||||
if (!mImage->peekPixels(&pixmap)) {
|
if (!mImage->peekPixels(&pixmap)) {
|
||||||
gfxCriticalError() << "Failed accessing pixels for Skia raster image";
|
gfxCriticalError() << "Failed accessing pixels for Skia raster image";
|
||||||
|
@ -1447,7 +1447,7 @@ void GLContext::LoadMoreSymbols(const SymbolLoader& loader) {
|
|||||||
CORE_SYMBOL(GetTexLevelParameteriv),
|
CORE_SYMBOL(GetTexLevelParameteriv),
|
||||||
END_SYMBOLS};
|
END_SYMBOLS};
|
||||||
const bool warnOnFailures = ShouldSpew();
|
const bool warnOnFailures = ShouldSpew();
|
||||||
loader.LoadSymbols(devSymbols, warnOnFailures);
|
(void)loader.LoadSymbols(devSymbols, warnOnFailures);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef CORE_SYMBOL
|
#undef CORE_SYMBOL
|
||||||
|
@ -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;
|
|
||||||
}
|
|
@ -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_
|
|
@ -74,14 +74,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
|||||||
'SharedSurfaceANGLE.cpp',
|
'SharedSurfaceANGLE.cpp',
|
||||||
'SharedSurfaceD3D11Interop.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':
|
if gl_provider == 'CGL':
|
||||||
# These files include Mac headers that are unfriendly to unified builds
|
# These files include Mac headers that are unfriendly to unified builds
|
||||||
|
@ -240,7 +240,7 @@ mozilla::ipc::IPCResult GPUChild::RecvNotifyDeviceReset(
|
|||||||
bool GPUChild::SendRequestMemoryReport(const uint32_t& aGeneration,
|
bool GPUChild::SendRequestMemoryReport(const uint32_t& aGeneration,
|
||||||
const bool& aAnonymize,
|
const bool& aAnonymize,
|
||||||
const bool& aMinimizeMemoryUsage,
|
const bool& aMinimizeMemoryUsage,
|
||||||
const MaybeFileDesc& aDMDFile) {
|
const Maybe<FileDescriptor>& aDMDFile) {
|
||||||
mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
|
mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
|
||||||
Unused << PGPUChild::SendRequestMemoryReport(aGeneration, aAnonymize,
|
Unused << PGPUChild::SendRequestMemoryReport(aGeneration, aAnonymize,
|
||||||
aMinimizeMemoryUsage, aDMDFile);
|
aMinimizeMemoryUsage, aDMDFile);
|
||||||
|
@ -78,7 +78,7 @@ class GPUChild final : public PGPUChild, public gfxVarReceiver {
|
|||||||
bool SendRequestMemoryReport(const uint32_t& aGeneration,
|
bool SendRequestMemoryReport(const uint32_t& aGeneration,
|
||||||
const bool& aAnonymize,
|
const bool& aAnonymize,
|
||||||
const bool& aMinimizeMemoryUsage,
|
const bool& aMinimizeMemoryUsage,
|
||||||
const MaybeFileDesc& aDMDFile);
|
const Maybe<ipc::FileDescriptor>& aDMDFile);
|
||||||
|
|
||||||
static void Destroy(UniquePtr<GPUChild>&& aChild);
|
static void Destroy(UniquePtr<GPUChild>&& aChild);
|
||||||
|
|
||||||
|
@ -444,7 +444,7 @@ void GPUParent::GetGPUProcessName(nsACString& aStr) {
|
|||||||
|
|
||||||
mozilla::ipc::IPCResult GPUParent::RecvRequestMemoryReport(
|
mozilla::ipc::IPCResult GPUParent::RecvRequestMemoryReport(
|
||||||
const uint32_t& aGeneration, const bool& aAnonymize,
|
const uint32_t& aGeneration, const bool& aAnonymize,
|
||||||
const bool& aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile) {
|
const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
|
||||||
nsAutoCString processName;
|
nsAutoCString processName;
|
||||||
GetGPUProcessName(processName);
|
GetGPUProcessName(processName);
|
||||||
|
|
||||||
|
@ -74,7 +74,8 @@ class GPUParent final : public PGPUParent {
|
|||||||
mozilla::ipc::IPCResult RecvNotifyGpuObservers(const nsCString& aTopic);
|
mozilla::ipc::IPCResult RecvNotifyGpuObservers(const nsCString& aTopic);
|
||||||
mozilla::ipc::IPCResult RecvRequestMemoryReport(
|
mozilla::ipc::IPCResult RecvRequestMemoryReport(
|
||||||
const uint32_t& generation, const bool& anonymize,
|
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();
|
mozilla::ipc::IPCResult RecvShutdownVR();
|
||||||
|
|
||||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||||
|
@ -1037,7 +1037,7 @@ class GPUMemoryReporter : public MemoryReportingProcess {
|
|||||||
bool SendRequestMemoryReport(const uint32_t& aGeneration,
|
bool SendRequestMemoryReport(const uint32_t& aGeneration,
|
||||||
const bool& aAnonymize,
|
const bool& aAnonymize,
|
||||||
const bool& aMinimizeMemoryUsage,
|
const bool& aMinimizeMemoryUsage,
|
||||||
const dom::MaybeFileDesc& aDMDFile) override {
|
const Maybe<FileDescriptor>& aDMDFile) override {
|
||||||
GPUChild* child = GetChild();
|
GPUChild* child = GetChild();
|
||||||
if (!child) {
|
if (!child) {
|
||||||
return false;
|
return false;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user