зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound a=merge
a=release IGNORE BAD COMMIT MESSAGES
This commit is contained in:
Коммит
8b07ba2a07
|
@ -62,7 +62,6 @@ DEFAULT_NO_CONNECTIONS_PREFS = {
|
|||
'browser.safebrowsing.provider.google.gethashURL': 'http://localhost/safebrowsing-dummy/gethash',
|
||||
'browser.safebrowsing.provider.google4.updateURL': 'http://localhost/safebrowsing4-dummy/update',
|
||||
'browser.safebrowsing.provider.google4.gethashURL': 'http://localhost/safebrowsing4-dummy/gethash',
|
||||
'browser.selfsupport.url': 'https://localhost/selfsupport-dummy',
|
||||
'browser.safebrowsing.provider.mozilla.gethashURL': 'http://localhost/safebrowsing-dummy/gethash',
|
||||
'browser.safebrowsing.provider.mozilla.updateURL': 'http://localhost/safebrowsing-dummy/update',
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
const { Cu, Ci } = require("chrome");
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
const { SelfSupportBackend } = Cu.import("resource:///modules/SelfSupportBackend.jsm", {});
|
||||
const Startup = Cu.import("resource://gre/modules/sdk/system/Startup.js", {}).exports;
|
||||
|
||||
// Adapted from the SpecialPowers.exactGC() code. We don't have a
|
||||
|
@ -38,11 +37,6 @@ function gc() {
|
|||
// object then it will be unloaded after the memory measurements.
|
||||
exports.asyncWindowLeakTest = function*(assert, asyncTestFunc) {
|
||||
|
||||
// SelfSupportBackend periodically tries to open windows. This can
|
||||
// mess up our window leak detection below, so turn it off.
|
||||
if (SelfSupportBackend._log)
|
||||
SelfSupportBackend.uninit();
|
||||
|
||||
// Wait for the browser to finish loading.
|
||||
yield Startup.onceInitialized;
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
"browser.safebrowsing.provider.google4.updateURL": "http://localhost/safebrowsing4-dummy/update",
|
||||
"browser.safebrowsing.provider.google4.gethashURL": "http://localhost/safebrowsing4-dummy/gethash",
|
||||
"browser.safebrowsing.provider.google4.reportURL": "http://localhost/safebrowsing4-dummy/malwarereport",
|
||||
"browser.selfsupport.url": "https://localhost/selfsupport-dummy",
|
||||
"browser.safebrowsing.provider.mozilla.gethashURL": "http://localhost/safebrowsing-dummy/gethash",
|
||||
"browser.safebrowsing.provider.mozilla.updateURL": "http://localhost/safebrowsing-dummy/update",
|
||||
"browser.newtabpage.directory.source": "data:application/json,{'jetpack':1}",
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
# UITour
|
||||
origin uitour 1 https://www.mozilla.org
|
||||
origin uitour 1 https://self-repair.mozilla.org
|
||||
origin uitour 1 https://support.mozilla.org
|
||||
origin uitour 1 https://addons.mozilla.org
|
||||
origin uitour 1 https://discovery.addons.mozilla.org
|
||||
|
|
|
@ -822,8 +822,6 @@ pref("browser.rights.3.shown", false);
|
|||
pref("browser.rights.override", true);
|
||||
#endif
|
||||
|
||||
pref("browser.selfsupport.url", "https://self-repair.mozilla.org/%LOCALE%/repair");
|
||||
|
||||
pref("browser.sessionstore.resume_from_crash", true);
|
||||
pref("browser.sessionstore.resume_session_once", false);
|
||||
|
||||
|
|
|
@ -145,7 +145,8 @@
|
|||
noautofocus="true"
|
||||
hidden="true"
|
||||
overflowpadding="4"
|
||||
norolluponanchor="true" />
|
||||
norolluponanchor="true"
|
||||
nomaxresults="true" />
|
||||
|
||||
<!-- for search with one-off buttons -->
|
||||
<panel type="autocomplete" id="PopupSearchAutoComplete" noautofocus="true" hidden="true"/>
|
||||
|
@ -320,7 +321,7 @@
|
|||
<observes element="viewTabsSidebar" attribute="checked"/>
|
||||
</toolbarbutton>
|
||||
<toolbarseparator/>
|
||||
<toolbarbutton label="&sidebarCloseButton.tooltip;"
|
||||
<toolbarbutton label="&sidebarMenuClose.label;"
|
||||
class="subviewbutton"
|
||||
oncommand="SidebarUI.hide()"/>
|
||||
</panel>
|
||||
|
|
|
@ -1000,11 +1000,15 @@
|
|||
var newTitle = "";
|
||||
var docElement = this.ownerDocument.documentElement;
|
||||
var sep = docElement.getAttribute("titlemenuseparator");
|
||||
let tab = this.getTabForBrowser(aBrowser);
|
||||
let docTitle;
|
||||
|
||||
// Strip out any null bytes in the content title, since the
|
||||
// underlying widget implementations of nsWindow::SetTitle pass
|
||||
// null-terminated strings to system APIs.
|
||||
var docTitle = aBrowser.contentTitle.replace(/\0/g, "");
|
||||
if (tab._labelIsContentTitle) {
|
||||
// Strip out any null bytes in the content title, since the
|
||||
// underlying widget implementations of nsWindow::SetTitle pass
|
||||
// null-terminated strings to system APIs.
|
||||
docTitle = tab.getAttribute("label").replace(/\0/g, "");
|
||||
}
|
||||
|
||||
if (!docTitle)
|
||||
docTitle = docElement.getAttribute("titledefault");
|
||||
|
@ -1412,13 +1416,14 @@
|
|||
<method name="setInitialTabTitle">
|
||||
<parameter name="aTab"/>
|
||||
<parameter name="aTitle"/>
|
||||
<parameter name="aOptions"/>
|
||||
<body><![CDATA[
|
||||
if (aTitle) {
|
||||
aTab.setAttribute("label", aTitle);
|
||||
|
||||
// Don't replace the set label with the empty tab label or the URL
|
||||
// while the tab is loading.
|
||||
aTab._suppressTransientPlaceholderLabel = true;
|
||||
|
||||
this._setTabLabel(aTab, aTitle, aOptions);
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
@ -1437,7 +1442,10 @@
|
|||
delete aTab._suppressTransientPlaceholderLabel;
|
||||
}
|
||||
|
||||
if (!title) {
|
||||
let isContentTitle = false;
|
||||
if (title) {
|
||||
isContentTitle = true;
|
||||
} else {
|
||||
if (browser.currentURI.spec) {
|
||||
try {
|
||||
title = this.mURIFixup.createExposableURI(browser.currentURI).spec;
|
||||
|
@ -1465,14 +1473,33 @@
|
|||
title = this.mStringBundle.getString("tabs.emptyTabTitle");
|
||||
}
|
||||
|
||||
if (aTab.label == title)
|
||||
return this._setTabLabel(aTab, title, { isContentTitle });
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_setTabLabel">
|
||||
<parameter name="aTab"/>
|
||||
<parameter name="aLabel"/>
|
||||
<parameter name="aOptions"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (!aLabel || aTab.getAttribute("label") == aLabel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aTab.label = title;
|
||||
this._tabAttrModified(aTab, ["label"]);
|
||||
aTab.setAttribute("label", aLabel);
|
||||
aTab._labelIsContentTitle = aOptions && aOptions.isContentTitle;
|
||||
|
||||
if (aTab.selected)
|
||||
// Dispatch TabAttrModified event unless we're setting the label
|
||||
// before the TabOpen event was dispatched.
|
||||
if (!aOptions || !aOptions.beforeTabOpen) {
|
||||
this._tabAttrModified(aTab, ["label"]);
|
||||
}
|
||||
|
||||
if (aTab.selected) {
|
||||
this.updateTitlebar();
|
||||
}
|
||||
|
||||
return true;
|
||||
]]>
|
||||
|
@ -2313,7 +2340,7 @@
|
|||
t.setAttribute("label", this.mStringBundle.getString("tabs.emptyTabTitle"));
|
||||
} else {
|
||||
// Set URL as label so that the tab isn't empty initially.
|
||||
this.setInitialTabTitle(t, aURI);
|
||||
this.setInitialTabTitle(t, aURI, { beforeTabOpen: true });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ async function wait_for_tab_playing_event(tab, expectPlaying) {
|
|||
ok(true, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
|
||||
return true;
|
||||
}
|
||||
return await BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
|
||||
return BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
|
||||
if (event.detail.changed.includes("soundplaying")) {
|
||||
is(tab.hasAttribute("soundplaying"), expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
|
||||
is(tab.soundPlaying, expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
|
||||
|
@ -53,8 +53,6 @@ async function pause(tab, options) {
|
|||
let browser = tab.linkedBrowser;
|
||||
let awaitDOMAudioPlaybackStopped =
|
||||
BrowserTestUtils.waitForEvent(browser, "DOMAudioPlaybackStopped", "DOMAudioPlaybackStopped event should get fired after pause");
|
||||
let awaitTabPausedAttrModified =
|
||||
wait_for_tab_playing_event(tab, false);
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let audio = content.document.querySelector("audio");
|
||||
audio.pause();
|
||||
|
@ -73,7 +71,7 @@ async function pause(tab, options) {
|
|||
ok(tab.hasAttribute("soundplaying"), "The tab should still have the soundplaying attribute immediately after DOMAudioPlaybackStopped");
|
||||
}
|
||||
|
||||
await awaitTabPausedAttrModified;
|
||||
await wait_for_tab_playing_event(tab, false);
|
||||
ok(!tab.hasAttribute("soundplaying"), "The tab should not have the soundplaying attribute after the timeout has resolved");
|
||||
} finally {
|
||||
// Make sure other tests don't timeout if an exception gets thrown above.
|
||||
|
|
|
@ -34,7 +34,7 @@ XPCOMUtils.defineLazyGetter(this, "WeaveService", () =>
|
|||
PageThumbs:false, PdfJs:false, PermissionUI:false, PlacesBackups:false,
|
||||
PlacesUtils:false, PluralForm:false, PrivateBrowsingUtils:false,
|
||||
ProcessHangMonitor:false, ReaderParent:false, RecentWindow:false,
|
||||
RemotePrompt:false, SelfSupportBackend:false, SessionStore:false,
|
||||
RemotePrompt:false, SessionStore:false,
|
||||
ShellService:false, SimpleServiceDiscovery:false, TabCrashHandler:false,
|
||||
Task:false, UITour:false, WebChannel:false,
|
||||
WindowsRegistry:false, webrtcUI:false, UserAgentOverrides: false */
|
||||
|
@ -83,7 +83,6 @@ let initializedModules = {};
|
|||
["ReaderParent", "resource:///modules/ReaderParent.jsm"],
|
||||
["RecentWindow", "resource:///modules/RecentWindow.jsm"],
|
||||
["RemotePrompt", "resource:///modules/RemotePrompt.jsm"],
|
||||
["SelfSupportBackend", "resource:///modules/SelfSupportBackend.jsm", "init"],
|
||||
["SessionStore", "resource:///modules/sessionstore/SessionStore.jsm"],
|
||||
["ShellService", "resource:///modules/ShellService.jsm"],
|
||||
["SimpleServiceDiscovery", "resource://gre/modules/SimpleServiceDiscovery.jsm"],
|
||||
|
@ -126,10 +125,6 @@ XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
|
|||
const global = this;
|
||||
|
||||
const listeners = {
|
||||
observers: {
|
||||
"sessionstore-windows-restored": ["SelfSupportBackend"],
|
||||
},
|
||||
|
||||
ppmm: {
|
||||
// PLEASE KEEP THIS LIST IN SYNC WITH THE LISTENERS ADDED IN ContentPrefServiceParent.init
|
||||
"ContentPrefs:FunctionCall": ["ContentPrefServiceParent"],
|
||||
|
@ -171,16 +166,6 @@ const listeners = {
|
|||
"webrtc:UpdateBrowserIndicators": ["webrtcUI"],
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
for (let module of this.observers[topic]) {
|
||||
try {
|
||||
this[module].observe(subject, topic, data);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage(modules, data) {
|
||||
let val;
|
||||
for (let module of modules[data.name]) {
|
||||
|
@ -194,10 +179,6 @@ const listeners = {
|
|||
},
|
||||
|
||||
init() {
|
||||
for (let observer of Object.keys(this.observers)) {
|
||||
Services.obs.addObserver(this, observer);
|
||||
}
|
||||
|
||||
let receiveMessageMM = this.receiveMessage.bind(this, this.mm);
|
||||
for (let message of Object.keys(this.mm)) {
|
||||
Services.mm.addMessageListener(message, receiveMessageMM);
|
||||
|
|
|
@ -2646,7 +2646,7 @@ var SessionStoreInternal = {
|
|||
// If the page has a title, set it.
|
||||
if (activePageData) {
|
||||
if (activePageData.title) {
|
||||
win.gBrowser.setInitialTabTitle(tab, activePageData.title);
|
||||
win.gBrowser.setInitialTabTitle(tab, activePageData.title, { isContentTitle: true });
|
||||
} else if (activePageData.url != "about:blank") {
|
||||
win.gBrowser.setInitialTabTitle(tab, activePageData.url);
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ add_task(async function() {
|
|||
isnot(CONTENT_TITLE.length, 0, "content title isn't empty");
|
||||
isnot(CONTENT_TITLE, TEST_URL, "content title is different from the URL");
|
||||
is(firstTab.label, CONTENT_TITLE, "first tab displays content title");
|
||||
ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
|
||||
ok(secondTab.hasAttribute("pending"), "second tab is pending");
|
||||
is(secondTab.label, TEST_URL, "second tab displays URL as its title");
|
||||
|
||||
|
@ -60,7 +61,8 @@ add_task(async function() {
|
|||
gBrowser.selectedTab = secondTab;
|
||||
await browserLoadedPromise;
|
||||
ok(!secondTab.hasAttribute("pending"), "second tab isn't pending anymore");
|
||||
is(gBrowser.selectedTab.label, CONTENT_TITLE, "second tab displays content title");
|
||||
is(secondTab.label, CONTENT_TITLE, "second tab displays content title");
|
||||
ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
|
||||
checkLabelChangeCount(1);
|
||||
|
||||
info("restoring the modified browser state");
|
||||
|
@ -68,6 +70,7 @@ add_task(async function() {
|
|||
await promiseBrowserState(SessionStore.getBrowserState());
|
||||
[firstTab, secondTab] = gBrowser.tabs;
|
||||
is(secondTab, gBrowser.selectedTab, "second tab is selected after restoring");
|
||||
ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
|
||||
ok(firstTab.hasAttribute("pending"), "first tab is pending after restoring");
|
||||
is(firstTab.label, CONTENT_TITLE, "first tab displays content title in pending state");
|
||||
|
||||
|
@ -75,6 +78,7 @@ add_task(async function() {
|
|||
checkLabelChangeCount = observeLabelChanges(firstTab);
|
||||
let tabContentRestored = TestUtils.topicObserved("sessionstore-debug-tab-restored");
|
||||
gBrowser.selectedTab = firstTab;
|
||||
ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
|
||||
await tabContentRestored;
|
||||
ok(!firstTab.hasAttribute("pending"), "first tab isn't pending anymore");
|
||||
checkLabelChangeCount(0);
|
||||
|
|
|
@ -666,7 +666,8 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
|||
<!ENTITY fullZoom.label "Zoom">
|
||||
<!ENTITY fullZoom.accesskey "Z">
|
||||
|
||||
<!ENTITY sidebarCloseButton.tooltip "Close Sidebar">
|
||||
<!ENTITY sidebarCloseButton.tooltip "Close sidebar">
|
||||
<!ENTITY sidebarMenuClose.label "Close Sidebar">
|
||||
|
||||
<!ENTITY quitApplicationCmdWin2.label "Exit">
|
||||
<!ENTITY quitApplicationCmdWin2.accesskey "x">
|
||||
|
|
|
@ -1,353 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["SelfSupportBackend"];
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "HiddenFrame",
|
||||
"resource://gre/modules/HiddenFrame.jsm");
|
||||
|
||||
// Enables or disables the Self Support.
|
||||
const PREF_ENABLED = "browser.selfsupport.enabled";
|
||||
// Url to open in the Self Support browser, in the urlFormatter service format.
|
||||
const PREF_URL = "browser.selfsupport.url";
|
||||
// Unified Telemetry status.
|
||||
const PREF_TELEMETRY_UNIFIED = "toolkit.telemetry.unified";
|
||||
// UITour status.
|
||||
const PREF_UITOUR_ENABLED = "browser.uitour.enabled";
|
||||
|
||||
// Controls the interval at which the self support page tries to reload in case of
|
||||
// errors.
|
||||
const RETRY_INTERVAL_MS = 30000;
|
||||
// Maximum number of SelfSupport page load attempts in case of failure.
|
||||
const MAX_RETRIES = 5;
|
||||
// The delay after which to load the self-support, at startup.
|
||||
const STARTUP_DELAY_MS = 5000;
|
||||
|
||||
const LOGGER_NAME = "Browser.SelfSupportBackend";
|
||||
const PREF_BRANCH_LOG = "browser.selfsupport.log.";
|
||||
const PREF_LOG_LEVEL = PREF_BRANCH_LOG + "level";
|
||||
const PREF_LOG_DUMP = PREF_BRANCH_LOG + "dump";
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
const UITOUR_FRAME_SCRIPT = "chrome://browser/content/content-UITour.js";
|
||||
|
||||
// Whether the FHR/Telemetry unification features are enabled.
|
||||
// Changing this pref requires a restart.
|
||||
const IS_UNIFIED_TELEMETRY = Services.prefs.getBoolPref(PREF_TELEMETRY_UNIFIED, false);
|
||||
|
||||
var gLogAppenderDump = null;
|
||||
|
||||
this.SelfSupportBackend = Object.freeze({
|
||||
init() {
|
||||
SelfSupportBackendInternal.init();
|
||||
},
|
||||
|
||||
uninit() {
|
||||
SelfSupportBackendInternal.uninit();
|
||||
},
|
||||
});
|
||||
|
||||
var SelfSupportBackendInternal = {
|
||||
// The browser element that will load the SelfSupport page.
|
||||
_browser: null,
|
||||
// The Id of the timer triggering delayed SelfSupport page load.
|
||||
_delayedLoadTimerId: null,
|
||||
// The HiddenFrame holding the _browser element.
|
||||
_frame: null,
|
||||
_log: null,
|
||||
_progressListener: null,
|
||||
|
||||
// Whether we're invited to let test code talk to our frame.
|
||||
_testing: false,
|
||||
|
||||
// Whether self-support is enabled, and we want to continue lazy UI
|
||||
// startup after the session has been restored.
|
||||
_lazyStartupEnabled: false,
|
||||
|
||||
/**
|
||||
* Initializes the self support backend.
|
||||
*/
|
||||
init() {
|
||||
this._configureLogging();
|
||||
|
||||
this._log.trace("init");
|
||||
|
||||
Services.prefs.addObserver(PREF_BRANCH_LOG, this);
|
||||
|
||||
// Only allow to use SelfSupport if Unified Telemetry is enabled.
|
||||
let reportingEnabled = IS_UNIFIED_TELEMETRY;
|
||||
if (!reportingEnabled) {
|
||||
this._log.config("init - Disabling SelfSupport because FHR and Unified Telemetry are disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure UITour is enabled.
|
||||
let uiTourEnabled = Services.prefs.getBoolPref(PREF_UITOUR_ENABLED, false);
|
||||
if (!uiTourEnabled) {
|
||||
this._log.config("init - Disabling SelfSupport because UITour is disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the preferences to see if we want this to be active.
|
||||
if (!Services.prefs.getBoolPref(PREF_ENABLED, true)) {
|
||||
this._log.config("init - SelfSupport is disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
this._lazyStartupEnabled = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Shut down the self support backend, if active.
|
||||
*/
|
||||
uninit() {
|
||||
if (!this._log) {
|
||||
// We haven't been initialized yet, so just return.
|
||||
return;
|
||||
}
|
||||
|
||||
this._log.trace("uninit");
|
||||
|
||||
Services.prefs.removeObserver(PREF_BRANCH_LOG, this);
|
||||
|
||||
// Cancel delayed loading, if still active, when shutting down.
|
||||
clearTimeout(this._delayedLoadTimerId);
|
||||
|
||||
// Dispose of the hidden browser.
|
||||
if (this._browser !== null) {
|
||||
if (this._browser.contentWindow) {
|
||||
this._browser.contentWindow.removeEventListener("DOMWindowClose", this, true);
|
||||
}
|
||||
|
||||
if (this._progressListener) {
|
||||
this._browser.removeProgressListener(this._progressListener);
|
||||
this._progressListener.destroy();
|
||||
this._progressListener = null;
|
||||
}
|
||||
|
||||
this._browser.remove();
|
||||
this._browser = null;
|
||||
}
|
||||
|
||||
if (this._frame) {
|
||||
this._frame.destroy();
|
||||
this._frame = null;
|
||||
}
|
||||
if (this._testing) {
|
||||
Services.obs.notifyObservers(this._browser, "self-support-browser-destroyed");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle notifications. Once all windows are created, we wait a little bit more
|
||||
* since tabs might still be loading. Then, we open the self support.
|
||||
*/
|
||||
// Observers are added in nsBrowserGlue.js
|
||||
observe(aSubject, aTopic, aData) {
|
||||
this._log.trace("observe - Topic " + aTopic);
|
||||
|
||||
if (aTopic === "sessionstore-windows-restored") {
|
||||
if (this._lazyStartupEnabled) {
|
||||
this._delayedLoadTimerId = setTimeout(this._loadSelfSupport.bind(this), STARTUP_DELAY_MS);
|
||||
this._lazyStartupEnabled = false;
|
||||
}
|
||||
} else if (aTopic === "nsPref:changed") {
|
||||
this._configureLogging();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Configure the logger based on the preferences.
|
||||
*/
|
||||
_configureLogging() {
|
||||
if (!this._log) {
|
||||
this._log = Log.repository.getLogger(LOGGER_NAME);
|
||||
|
||||
// Log messages need to go to the browser console.
|
||||
let consoleAppender = new Log.ConsoleAppender(new Log.BasicFormatter());
|
||||
this._log.addAppender(consoleAppender);
|
||||
}
|
||||
|
||||
// Make sure the logger keeps up with the logging level preference.
|
||||
this._log.level = Log.Level[Services.prefs.getStringPref(PREF_LOG_LEVEL, "Warn")];
|
||||
|
||||
// If enabled in the preferences, add a dump appender.
|
||||
let logDumping = Services.prefs.getBoolPref(PREF_LOG_DUMP, false);
|
||||
if (logDumping != !!gLogAppenderDump) {
|
||||
if (logDumping) {
|
||||
gLogAppenderDump = new Log.DumpAppender(new Log.BasicFormatter());
|
||||
this._log.addAppender(gLogAppenderDump);
|
||||
} else {
|
||||
this._log.removeAppender(gLogAppenderDump);
|
||||
gLogAppenderDump = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create an hidden frame to host our |browser|, then load the SelfSupport page in it.
|
||||
* @param aURL The URL to load in the browser.
|
||||
*/
|
||||
_makeHiddenBrowser(aURL) {
|
||||
this._frame = new HiddenFrame();
|
||||
return this._frame.get().then(aFrame => {
|
||||
let doc = aFrame.document;
|
||||
|
||||
this._browser = doc.createElementNS(XUL_NS, "browser");
|
||||
this._browser.setAttribute("type", "content");
|
||||
this._browser.setAttribute("disableglobalhistory", "true");
|
||||
this._browser.setAttribute("src", aURL);
|
||||
|
||||
if (this._testing) {
|
||||
Services.obs.notifyObservers(this._browser, "self-support-browser-created");
|
||||
}
|
||||
doc.documentElement.appendChild(this._browser);
|
||||
});
|
||||
},
|
||||
|
||||
handleEvent(aEvent) {
|
||||
this._log.trace("handleEvent - aEvent.type " + aEvent.type + ", Trusted " + aEvent.isTrusted);
|
||||
|
||||
if (aEvent.type === "DOMWindowClose") {
|
||||
let window = this._browser.contentDocument.defaultView;
|
||||
let target = aEvent.target;
|
||||
|
||||
if (target == window) {
|
||||
// preventDefault stops the default window.close(). We need to do that to prevent
|
||||
// Services.appShell.hiddenDOMWindow from being destroyed.
|
||||
aEvent.preventDefault();
|
||||
|
||||
this.uninit();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the self support page correctly loads.
|
||||
*/
|
||||
_pageSuccessCallback() {
|
||||
this._log.debug("_pageSuccessCallback - Page correctly loaded.");
|
||||
this._browser.removeProgressListener(this._progressListener);
|
||||
this._progressListener.destroy();
|
||||
this._progressListener = null;
|
||||
|
||||
// Allow SelfSupportBackend to catch |window.close()| issued by the content.
|
||||
this._browser.contentWindow.addEventListener("DOMWindowClose", this, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the self support page fails to load.
|
||||
*/
|
||||
_pageLoadErrorCallback() {
|
||||
this._log.info("_pageLoadErrorCallback - Too many failed load attempts. Giving up.");
|
||||
this.uninit();
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a browser and attach it to an hidden window. The browser will contain the
|
||||
* self support page and attempt to load the page content. If loading fails, try again
|
||||
* after an interval.
|
||||
*/
|
||||
_loadSelfSupport() {
|
||||
// Fetch the Self Support URL from the preferences.
|
||||
let unformattedURL = Services.prefs.getStringPref(PREF_URL, "");
|
||||
let url = Services.urlFormatter.formatURL(unformattedURL);
|
||||
if (!url.startsWith("https:")) {
|
||||
this._log.error("_loadSelfSupport - Non HTTPS URL provided: " + url);
|
||||
return;
|
||||
}
|
||||
|
||||
this._log.config("_loadSelfSupport - URL " + url);
|
||||
|
||||
// Create the hidden browser.
|
||||
this._makeHiddenBrowser(url).then(() => {
|
||||
// Load UITour frame script.
|
||||
this._browser.messageManager.loadFrameScript(UITOUR_FRAME_SCRIPT, true);
|
||||
|
||||
// We need to watch for load errors as well and, in case, try to reload
|
||||
// the self support page.
|
||||
const webFlags = Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
|
||||
Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
|
||||
Ci.nsIWebProgress.NOTIFY_LOCATION;
|
||||
|
||||
this._progressListener = new ProgressListener(() => this._pageLoadErrorCallback(),
|
||||
() => this._pageSuccessCallback());
|
||||
|
||||
this._browser.addProgressListener(this._progressListener, webFlags);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A progress listener object which notifies of page load error and load success
|
||||
* through callbacks. When the page fails to load, the progress listener tries to
|
||||
* reload it up to MAX_RETRIES times. The page is not loaded again immediately, but
|
||||
* after a timeout.
|
||||
*
|
||||
* @param aLoadErrorCallback Called when a page failed to load MAX_RETRIES times.
|
||||
* @param aLoadSuccessCallback Called when a page correctly loads.
|
||||
*/
|
||||
function ProgressListener(aLoadErrorCallback, aLoadSuccessCallback) {
|
||||
this._loadErrorCallback = aLoadErrorCallback;
|
||||
this._loadSuccessCallback = aLoadSuccessCallback;
|
||||
// The number of page loads attempted.
|
||||
this._loadAttempts = 0;
|
||||
this._log = Log.repository.getLogger(LOGGER_NAME);
|
||||
// The Id of the timer which triggers page load again in case of errors.
|
||||
this._reloadTimerId = null;
|
||||
}
|
||||
|
||||
ProgressListener.prototype = {
|
||||
onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
|
||||
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
|
||||
this._log.warn("onLocationChange - There was a problem fetching the SelfSupport URL (attempt " +
|
||||
this._loadAttempts + ").");
|
||||
|
||||
// Increase the number of attempts and bail out if we failed too many times.
|
||||
this._loadAttempts++;
|
||||
if (this._loadAttempts > MAX_RETRIES) {
|
||||
this._loadErrorCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reload the page after the retry interval expires. The interval is multiplied
|
||||
// by the number of attempted loads, so that it takes a bit more to try to reload
|
||||
// when frequently failing.
|
||||
this._reloadTimerId = setTimeout(() => {
|
||||
this._log.debug("onLocationChange - Reloading SelfSupport URL in the hidden browser.");
|
||||
aWebProgress.DOMWindow.location.reload();
|
||||
}, RETRY_INTERVAL_MS * this._loadAttempts);
|
||||
}
|
||||
},
|
||||
|
||||
onStateChange(aWebProgress, aRequest, aFlags, aStatus) {
|
||||
if (aFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
aFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||
aFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW &&
|
||||
Components.isSuccessCode(aStatus)) {
|
||||
this._loadSuccessCallback();
|
||||
}
|
||||
},
|
||||
|
||||
destroy() {
|
||||
// Make sure we don't try to reload self support when shutting down.
|
||||
clearTimeout(this._reloadTimerId);
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
};
|
|
@ -16,9 +16,6 @@ with Files("test/browser/*ContentSearch*"):
|
|||
with Files("test/browser/*PermissionUI*"):
|
||||
BUG_COMPONENT = ("Firefox", "Site Identity and Permission Panels")
|
||||
|
||||
with Files("test/browser/browser_SelfSupportBackend.js"):
|
||||
BUG_COMPONENT = ("Toolkit", "Telemetry")
|
||||
|
||||
with Files("test/browser/*SitePermissions*"):
|
||||
BUG_COMPONENT = ("Firefox", "Site Identity and Permission Panels")
|
||||
|
||||
|
@ -97,9 +94,6 @@ with Files("ReaderParent.jsm"):
|
|||
with Files("Sanitizer.jsm"):
|
||||
BUG_COMPONENT = ("Firefox", "Preferences")
|
||||
|
||||
with Files("SelfSupportBackend.jsm"):
|
||||
BUG_COMPONENT = ("Toolkit", "Telemetry")
|
||||
|
||||
with Files("SitePermissions.jsm"):
|
||||
BUG_COMPONENT = ("Firefox", "Site Identity and Permission Panels")
|
||||
|
||||
|
@ -160,7 +154,6 @@ EXTRA_JS_MODULES += [
|
|||
'RecentWindow.jsm',
|
||||
'RemotePrompt.jsm',
|
||||
'Sanitizer.jsm',
|
||||
'SelfSupportBackend.jsm',
|
||||
'SitePermissions.jsm',
|
||||
'Social.jsm',
|
||||
'SocialService.jsm',
|
||||
|
|
|
@ -19,10 +19,6 @@ support-files =
|
|||
[browser_PermissionUI_prompts.js]
|
||||
[browser_ProcessHangNotifications.js]
|
||||
skip-if = !e10s
|
||||
[browser_SelfSupportBackend.js]
|
||||
support-files =
|
||||
../../../components/uitour/test/uitour.html
|
||||
../../../components/uitour/UITour-lib.js
|
||||
[browser_SitePermissions.js]
|
||||
[browser_SitePermissions_combinations.js]
|
||||
[browser_SitePermissions_expiry.js]
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Pass an empty scope object to the import to prevent "leaked window property"
|
||||
// errors in tests.
|
||||
var Preferences = Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
|
||||
var PromiseUtils = Cu.import("resource://gre/modules/PromiseUtils.jsm", {}).PromiseUtils;
|
||||
var SelfSupportBackend =
|
||||
Cu.import("resource:///modules/SelfSupportBackend.jsm", {}).SelfSupportBackend;
|
||||
|
||||
const PREF_SELFSUPPORT_ENABLED = "browser.selfsupport.enabled";
|
||||
const PREF_SELFSUPPORT_URL = "browser.selfsupport.url";
|
||||
const PREF_UITOUR_ENABLED = "browser.uitour.enabled";
|
||||
|
||||
const TEST_WAIT_RETRIES = 60;
|
||||
|
||||
const TEST_PAGE_URL = getRootDirectory(gTestPath) + "uitour.html";
|
||||
const TEST_PAGE_URL_HTTPS = TEST_PAGE_URL.replace("chrome://mochitests/content/", "https://example.com/");
|
||||
|
||||
function sendSessionRestoredNotification() {
|
||||
let selfSupportBackendImpl =
|
||||
Cu.import("resource:///modules/SelfSupportBackend.jsm", {}).SelfSupportBackendInternal;
|
||||
selfSupportBackendImpl.observe(null, "sessionstore-windows-restored", null);
|
||||
}
|
||||
|
||||
function toggleSelfSupportTestMode(testing) {
|
||||
let selfSupportBackendImpl =
|
||||
Cu.import("resource:///modules/SelfSupportBackend.jsm", {}).SelfSupportBackendInternal;
|
||||
selfSupportBackendImpl._testing = testing;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wait for self support page to load.
|
||||
*
|
||||
* @param aURL The URL to look for to identify the browser.
|
||||
*
|
||||
* @returns {Promise} Return a promise which is resolved when SelfSupport page is fully
|
||||
* loaded.
|
||||
*/
|
||||
function promiseSelfSupportLoad(aURL) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Find the SelfSupport browser.
|
||||
let browser = null;
|
||||
let browserPromise = TestUtils.topicObserved("self-support-browser-created",
|
||||
(subject, topic) => {
|
||||
let url = subject.getAttribute("src");
|
||||
Cu.reportError("Got browser with src: " + url);
|
||||
if (url == aURL) {
|
||||
browser = subject;
|
||||
}
|
||||
return url == aURL;
|
||||
});
|
||||
|
||||
// Once found, append a "load" listener to catch page loads.
|
||||
browserPromise.then(() => {
|
||||
if (browser.contentDocument.readyState === "complete") {
|
||||
resolve(browser);
|
||||
} else {
|
||||
let handler = () => {
|
||||
browser.removeEventListener("load", handler, true);
|
||||
resolve(browser);
|
||||
};
|
||||
browser.addEventListener("load", handler, true);
|
||||
}
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the test environment.
|
||||
*/
|
||||
add_task(async function setupEnvironment() {
|
||||
// We always run the SelfSupportBackend in tests to check for weird behaviours.
|
||||
// Disable it to test its start-up.
|
||||
SelfSupportBackend.uninit();
|
||||
|
||||
// Testing prefs are set via |user_pref|, so we need to get their value in order
|
||||
// to restore them.
|
||||
let selfSupportEnabled = Preferences.get(PREF_SELFSUPPORT_ENABLED, true);
|
||||
let uitourEnabled = Preferences.get(PREF_UITOUR_ENABLED, false);
|
||||
let selfSupportURL = Preferences.get(PREF_SELFSUPPORT_URL, "");
|
||||
|
||||
// Enable the SelfSupport backend and set the page URL. We also make sure UITour
|
||||
// is enabled.
|
||||
Preferences.set(PREF_SELFSUPPORT_ENABLED, true);
|
||||
Preferences.set(PREF_UITOUR_ENABLED, true);
|
||||
Preferences.set(PREF_SELFSUPPORT_URL, TEST_PAGE_URL_HTTPS);
|
||||
|
||||
// Whitelist the HTTPS page to use UITour.
|
||||
let pageURI = Services.io.newURI(TEST_PAGE_URL_HTTPS);
|
||||
Services.perms.add(pageURI, "uitour", Services.perms.ALLOW_ACTION);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.perms.remove(pageURI, "uitour");
|
||||
Preferences.set(PREF_SELFSUPPORT_ENABLED, selfSupportEnabled);
|
||||
Preferences.set(PREF_UITOUR_ENABLED, uitourEnabled);
|
||||
Preferences.set(PREF_SELFSUPPORT_URL, selfSupportURL);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that the self support page can use the UITour API and close itself.
|
||||
*/
|
||||
add_task(async function test_selfSupport() {
|
||||
toggleSelfSupportTestMode(true);
|
||||
registerCleanupFunction(toggleSelfSupportTestMode.bind(null, false));
|
||||
// Initialise the SelfSupport backend and trigger the load.
|
||||
SelfSupportBackend.init();
|
||||
|
||||
// Wait for the SelfSupport page to load.
|
||||
let selfSupportBrowserPromise = promiseSelfSupportLoad(TEST_PAGE_URL_HTTPS);
|
||||
|
||||
// SelfSupportBackend waits for "sessionstore-windows-restored" to start loading. Send it.
|
||||
info("Sending sessionstore-windows-restored");
|
||||
sendSessionRestoredNotification();
|
||||
|
||||
// Wait for the SelfSupport page to load.
|
||||
info("Waiting for the SelfSupport local page to load.");
|
||||
let selfSupportBrowser = await selfSupportBrowserPromise;
|
||||
Assert.ok(!!selfSupportBrowser, "SelfSupport browser must exist.");
|
||||
|
||||
// Get a reference to the UITour API.
|
||||
info("Testing access to the UITour API.");
|
||||
let contentWindow =
|
||||
Cu.waiveXrays(selfSupportBrowser.contentDocument.defaultView);
|
||||
let uitourAPI = contentWindow.Mozilla.UITour;
|
||||
|
||||
// Test the UITour API with a ping.
|
||||
let pingPromise = new Promise((resolve) => {
|
||||
uitourAPI.ping(resolve);
|
||||
});
|
||||
await pingPromise;
|
||||
info("Ping succeeded");
|
||||
|
||||
let observePromise = ContentTask.spawn(selfSupportBrowser, null, async function checkObserve() {
|
||||
await new Promise(resolve => {
|
||||
let win = Cu.waiveXrays(content);
|
||||
win.Mozilla.UITour.observe((event, data) => {
|
||||
if (event != "Heartbeat:Engaged") {
|
||||
return;
|
||||
}
|
||||
Assert.equal(data.flowId, "myFlowID", "Check flowId");
|
||||
Assert.ok(!!data.timestamp, "Check timestamp");
|
||||
resolve(data);
|
||||
}, () => {});
|
||||
});
|
||||
});
|
||||
|
||||
info("Notifying Heartbeat:Engaged");
|
||||
UITour.notify("Heartbeat:Engaged", {
|
||||
flowId: "myFlowID",
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
await observePromise;
|
||||
info("Observed in the hidden frame");
|
||||
|
||||
let selfSupportClosed = TestUtils.topicObserved("self-support-browser-destroyed");
|
||||
// Close SelfSupport from content.
|
||||
contentWindow.close();
|
||||
|
||||
await selfSupportClosed;
|
||||
Assert.ok(!selfSupportBrowser.parentNode, "SelfSupport browser must have been removed.");
|
||||
|
||||
// We shouldn't need this, but let's keep it to make sure closing SelfSupport twice
|
||||
// doesn't create any problem.
|
||||
SelfSupportBackend.uninit();
|
||||
});
|
||||
|
|
@ -30,6 +30,7 @@ function SourceMapURLService(target, sourceMapService) {
|
|||
* Reset the service. This flushes the internal cache.
|
||||
*/
|
||||
SourceMapURLService.prototype.reset = function () {
|
||||
this._sourceMapService.clearSourceMaps();
|
||||
this._urls.clear();
|
||||
};
|
||||
|
||||
|
|
|
@ -11,10 +11,17 @@ support-files =
|
|||
code_binary_search.coffee
|
||||
code_binary_search.js
|
||||
code_binary_search.map
|
||||
code_bundle_reload_1.js
|
||||
code_bundle_reload_1.js.map
|
||||
code_bundle_reload_2.js
|
||||
code_bundle_reload_2.js.map
|
||||
code_inline_bundle.js
|
||||
code_inline_original.js
|
||||
code_math.js
|
||||
code_reload_1.js
|
||||
code_reload_2.js
|
||||
doc_empty-tab-01.html
|
||||
doc_reload.html
|
||||
head.js
|
||||
shared-head.js
|
||||
shared-redux-head.js
|
||||
|
@ -24,6 +31,8 @@ support-files =
|
|||
browser_toolbox_options_enable_serviceworkers_testing_frame_script.js
|
||||
browser_toolbox_options_enable_serviceworkers_testing.html
|
||||
serviceworker.js
|
||||
sjs_code_reload.sjs
|
||||
sjs_code_bundle_reload_map.sjs
|
||||
test_browser_toolbox_debugger.js
|
||||
|
||||
[browser_browser_toolbox.js]
|
||||
|
@ -39,6 +48,7 @@ support-files =
|
|||
[browser_new_activation_workflow.js]
|
||||
[browser_source_map-01.js]
|
||||
[browser_source_map-inline.js]
|
||||
[browser_source_map-reload.js]
|
||||
[browser_target_from_url.js]
|
||||
[browser_target_events.js]
|
||||
[browser_target_remote.js]
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that reloading re-reads the source maps.
|
||||
|
||||
"use strict";
|
||||
|
||||
const INITIAL_URL = URL_ROOT + "doc_empty-tab-01.html";
|
||||
const PAGE_URL = URL_ROOT + "doc_reload.html";
|
||||
const JS_URL = URL_ROOT + "sjs_code_reload.sjs";
|
||||
|
||||
const ORIGINAL_URL_1 = "webpack:///code_reload_1.js";
|
||||
const ORIGINAL_URL_2 = "webpack:///code_reload_2.js";
|
||||
|
||||
const GENERATED_LINE = 86;
|
||||
const ORIGINAL_LINE = 13;
|
||||
|
||||
add_task(function* () {
|
||||
// Start with the empty page, then navigate, so that we can properly
|
||||
// listen for new sources arriving.
|
||||
const toolbox = yield openNewTabAndToolbox(INITIAL_URL, "webconsole");
|
||||
const service = toolbox.sourceMapURLService;
|
||||
const tab = toolbox.target.tab;
|
||||
|
||||
let sourceSeen = waitForSourceLoad(toolbox, JS_URL);
|
||||
tab.linkedBrowser.loadURI(PAGE_URL);
|
||||
yield sourceSeen;
|
||||
|
||||
info(`checking original location for ${JS_URL}:${GENERATED_LINE}`);
|
||||
let newLoc = yield service.originalPositionFor(JS_URL, GENERATED_LINE);
|
||||
is(newLoc.sourceUrl, ORIGINAL_URL_1, "check mapped URL");
|
||||
is(newLoc.line, ORIGINAL_LINE, "check mapped line number");
|
||||
|
||||
// Reload the page. The sjs ensures that a different source file
|
||||
// will be loaded.
|
||||
sourceSeen = waitForSourceLoad(toolbox, JS_URL);
|
||||
yield refreshTab(tab);
|
||||
yield sourceSeen;
|
||||
|
||||
info(`checking post-reload original location for ${JS_URL}:${GENERATED_LINE}`);
|
||||
newLoc = yield service.originalPositionFor(JS_URL, GENERATED_LINE);
|
||||
is(newLoc.sourceUrl, ORIGINAL_URL_2, "check post-reload mapped URL");
|
||||
is(newLoc.line, ORIGINAL_LINE, "check post-reload mapped line number");
|
||||
|
||||
yield toolbox.destroy();
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
|
@ -0,0 +1,94 @@
|
|||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // identity function for calling harmony imports with the correct context
|
||||
/******/ __webpack_require__.i = function(value) { return value; };
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, {
|
||||
/******/ configurable: false,
|
||||
/******/ enumerable: true,
|
||||
/******/ get: getter
|
||||
/******/ });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 0);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([
|
||||
/* 0 */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Original source code for the inline source map test.
|
||||
// The generated file was made with
|
||||
// webpack --devtool source-map code_reload_1.js code_bundle_reload_1.js
|
||||
// perl -pi -e 's/sjs_code_bundle_reload_map.sjs/sjs_code_bundle_reload_map.sjs/' \
|
||||
// code_bundle_reload_1.js
|
||||
|
||||
|
||||
|
||||
function f() {
|
||||
console.log("The first version of the script");
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
//# sourceMappingURL=sjs_code_bundle_reload_map.sjs
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"sources":["webpack:///webpack/bootstrap 59857d9393d4518a63ff","webpack:///./code_reload_1.js"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;AChEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA","file":"code_bundle_reload_1.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 59857d9393d4518a63ff","/* Any copyright is dedicated to the Public Domain.\n http://creativecommons.org/publicdomain/zero/1.0/ */\n\n// Original source code for the inline source map test.\n// The generated file was made with\n// webpack --devtool source-map code_reload_1.js code_bundle_reload_1.js\n// perl -pi -e 's/code_bundle_reload_1.js.map/sjs_code_bundle_reload_map.sjs/' \\\n// code_bundle_reload_1.js\n\n\"use strict\";\n\nfunction f() {\n console.log(\"The first version of the script\");\n}\n\nf();\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./code_reload_1.js\n// module id = 0\n// module chunks = 0"],"sourceRoot":""}
|
|
@ -0,0 +1,94 @@
|
|||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // identity function for calling harmony imports with the correct context
|
||||
/******/ __webpack_require__.i = function(value) { return value; };
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, {
|
||||
/******/ configurable: false,
|
||||
/******/ enumerable: true,
|
||||
/******/ get: getter
|
||||
/******/ });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 0);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([
|
||||
/* 0 */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Original source code for the inline source map test.
|
||||
// The generated file was made with
|
||||
// webpack --devtool source-map code_reload_2.js code_bundle_reload_2.js
|
||||
// perl -pi -e 's/sjs_code_bundle_reload_map.sjs/sjs_code_bundle_reload_map.sjs/' \
|
||||
// code_bundle_reload_2.js
|
||||
|
||||
|
||||
|
||||
function f() {
|
||||
console.log("The second version of the script");
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
//# sourceMappingURL=sjs_code_bundle_reload_map.sjs
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"sources":["webpack:///webpack/bootstrap 9497621dfe5d6f67322e","webpack:///./code_reload_2.js"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;AChEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA","file":"code_bundle_reload_2.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 9497621dfe5d6f67322e","/* Any copyright is dedicated to the Public Domain.\n http://creativecommons.org/publicdomain/zero/1.0/ */\n\n// Original source code for the inline source map test.\n// The generated file was made with\n// webpack --devtool source-map code_reload_2.js code_bundle_reload_2.js\n// perl -pi -e 's/code_bundle_reload_2.js.map/sjs_code_bundle_reload_map.sjs/' \\\n// code_bundle_reload_2.js\n\n\"use strict\";\n\nfunction f() {\n console.log(\"The second version of the script\");\n}\n\nf();\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./code_reload_2.js\n// module id = 0\n// module chunks = 0"],"sourceRoot":""}
|
|
@ -0,0 +1,16 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Original source code for the inline source map test.
|
||||
// The generated file was made with
|
||||
// webpack --devtool source-map code_reload_1.js code_bundle_reload_1.js
|
||||
// perl -pi -e 's/code_bundle_reload_1.js.map/sjs_code_bundle_reload_map.sjs/' \
|
||||
// code_bundle_reload_1.js
|
||||
|
||||
"use strict";
|
||||
|
||||
function f() {
|
||||
console.log("The first version of the script");
|
||||
}
|
||||
|
||||
f();
|
|
@ -0,0 +1,16 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Original source code for the inline source map test.
|
||||
// The generated file was made with
|
||||
// webpack --devtool source-map code_reload_2.js code_bundle_reload_2.js
|
||||
// perl -pi -e 's/code_bundle_reload_2.js.map/sjs_code_bundle_reload_map.sjs/' \
|
||||
// code_bundle_reload_2.js
|
||||
|
||||
"use strict";
|
||||
|
||||
function f() {
|
||||
console.log("The second version of the script");
|
||||
}
|
||||
|
||||
f();
|
|
@ -0,0 +1,15 @@
|
|||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<script src="sjs_code_reload.sjs"></script>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Empty test page 1</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,26 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* globals getState, setState */
|
||||
/* exported handleRequest */
|
||||
|
||||
"use strict";
|
||||
|
||||
function handleRequest(request, response) {
|
||||
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setHeader("Expires", "0");
|
||||
response.setHeader("Access-Control-Allow-Origin", "*", false);
|
||||
|
||||
// Redirect to a different file each time.
|
||||
let counter = 1 + +getState("counter");
|
||||
|
||||
let index = request.path.lastIndexOf("/");
|
||||
let newPath = request.path.substr(0, index + 1) +
|
||||
"code_bundle_reload_" + counter + ".js.map";
|
||||
let newUrl = request.scheme + "://" + request.host + newPath;
|
||||
|
||||
response.setStatusLine(request.httpVersion, 302, "Found");
|
||||
response.setHeader("Location", newUrl);
|
||||
setState("counter", "" + counter);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* globals getState, setState */
|
||||
/* exported handleRequest */
|
||||
|
||||
"use strict";
|
||||
|
||||
function handleRequest(request, response) {
|
||||
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setHeader("Expires", "0");
|
||||
response.setHeader("Access-Control-Allow-Origin", "*", false);
|
||||
|
||||
// Redirect to a different file each time.
|
||||
let counter = 1 + +getState("counter");
|
||||
|
||||
let index = request.path.lastIndexOf("/");
|
||||
let newPath = request.path.substr(0, index + 1) +
|
||||
"code_bundle_reload_" + counter + ".js";
|
||||
let newUrl = request.scheme + "://" + request.host + newPath;
|
||||
|
||||
response.setStatusLine(request.httpVersion, 302, "Found");
|
||||
response.setHeader("Location", newUrl);
|
||||
setState("counter", "" + counter);
|
||||
}
|
|
@ -164,9 +164,10 @@ using namespace mozilla::dom;
|
|||
// that the error message actually displays the sizes.
|
||||
//
|
||||
|
||||
// We need different numbers on debug and opt to deal with the owning thread
|
||||
// pointer that comes with the non-threadsafe refcount on FragmentOrElement.
|
||||
#if defined(DEBUG) || defined(MOZ_ASAN)
|
||||
// We need different numbers on certain build types to deal with the owning
|
||||
// thread pointer that comes with the non-threadsafe refcount on
|
||||
// FragmentOrElement.
|
||||
#ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
|
||||
#define EXTRA_DOM_ELEMENT_BYTES 8
|
||||
#else
|
||||
#define EXTRA_DOM_ELEMENT_BYTES 0
|
||||
|
|
|
@ -338,6 +338,7 @@ nsDOMWindowUtils::UpdateLayerTree()
|
|||
if (view) {
|
||||
presShell->Paint(view, view->GetBounds(),
|
||||
nsIPresShell::PAINT_LAYERS | nsIPresShell::PAINT_SYNC_DECODE_IMAGES);
|
||||
presShell->GetLayerManager()->WaitOnTransactionProcessed();
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
|
|
|
@ -61,6 +61,7 @@ support-files = ../file_bug357450.js
|
|||
[test_bug1063837.xul]
|
||||
[test_bug1139964.xul]
|
||||
[test_bug1209621.xul]
|
||||
[test_bug1346936.html]
|
||||
[test_cpows.xul]
|
||||
[test_registerElement_content.xul]
|
||||
[test_registerElement_ep.xul]
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
</html>
|
|
@ -0,0 +1,4 @@
|
|||
//# sourceMappingURL=bar.js.map
|
||||
|
||||
// Define a single function to prevent script source from being gc'd
|
||||
function foo() {}
|
|
@ -0,0 +1 @@
|
|||
SourceMap: foo.js.map
|
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1346936
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1346936</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1346936">Mozilla Bug 1346936</a>
|
||||
<style type="text/css">
|
||||
#link1 a { -moz-user-select:none; }
|
||||
</style>
|
||||
<div id="link1"><a href="http://www.mozilla.org/">link1</a></div>
|
||||
<div id="link2"><a href="http://www.mozilla.org/">link2</a></div>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1346936 **/
|
||||
|
||||
Components.utils.import("resource://gre/modules/jsdebugger.jsm");
|
||||
addDebuggerToGlobal(this);
|
||||
|
||||
window.onload = function () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.src = "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug1346936.html";
|
||||
iframe.onload = function () {
|
||||
var script = iframe.contentWindow.document.createElement("script");
|
||||
script.src = "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug1346936.js";
|
||||
script.onload = function () {
|
||||
var dbg = new Debugger(iframe.contentWindow);
|
||||
ok(dbg, "Should be able to create debugger");
|
||||
|
||||
var scripts = dbg.findScripts({
|
||||
url: "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug1346936.js"
|
||||
});
|
||||
ok(scripts.length > 0, "Should be able to find script");
|
||||
|
||||
is(scripts[0].source.sourceMapURL, "foo.js.map");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
iframe.contentWindow.document.body.appendChild(script);
|
||||
};
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
};
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -31,6 +31,9 @@ TEST_DIRS += [
|
|||
TEST_HARNESS_FILES.testing.mochitest.tests.dom.base.test.chrome += [
|
||||
'chrome/bug421622-referer.sjs',
|
||||
'chrome/bug884693.sjs',
|
||||
'chrome/nochrome_bug1346936.html',
|
||||
'chrome/nochrome_bug1346936.js',
|
||||
'chrome/nochrome_bug1346936.js^headers^',
|
||||
'chrome/nochrome_bug765993.html',
|
||||
'chrome/nochrome_bug765993.js',
|
||||
'chrome/nochrome_bug765993.js^headers^',
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "nsTextNode.h"
|
||||
#include "nsIController.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/HTMLInputElement.h"
|
||||
|
@ -992,15 +993,22 @@ nsTextInputListener::HandleEvent(nsIDOMEvent* aEvent)
|
|||
mTxtCtrlElement->IsTextArea() ?
|
||||
nsIWidget::NativeKeyBindingsForMultiLineEditor :
|
||||
nsIWidget::NativeKeyBindingsForSingleLineEditor;
|
||||
|
||||
nsIWidget* widget = keyEvent->mWidget;
|
||||
// If the event is created by chrome script, the widget is nullptr.
|
||||
if (!widget) {
|
||||
widget = mFrame->GetNearestWidget();
|
||||
NS_ENSURE_TRUE(widget, NS_OK);
|
||||
}
|
||||
|
||||
if (widget->ExecuteNativeKeyBinding(nativeKeyBindingsType,
|
||||
*keyEvent, DoCommandCallback, mFrame)) {
|
||||
|
||||
// WidgetKeyboardEvent::ExecuteEditCommands() requires non-nullptr mWidget.
|
||||
// If the event is created by chrome script, it is nullptr but we need to
|
||||
// execute native key bindings. Therefore, we need to set widget to
|
||||
// WidgetEvent::mWidget temporarily.
|
||||
AutoRestore<nsCOMPtr<nsIWidget>> saveWidget(keyEvent->mWidget);
|
||||
keyEvent->mWidget = widget;
|
||||
if (keyEvent->ExecuteEditCommands(nativeKeyBindingsType,
|
||||
DoCommandCallback, mFrame)) {
|
||||
aEvent->PreventDefault();
|
||||
}
|
||||
return NS_OK;
|
||||
|
|
|
@ -87,19 +87,6 @@ using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/IPCTypes.h";
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct NativeKeyBinding
|
||||
{
|
||||
CommandInt[] singleLineCommands;
|
||||
CommandInt[] multiLineCommands;
|
||||
CommandInt[] richTextCommands;
|
||||
};
|
||||
|
||||
union MaybeNativeKeyBinding
|
||||
{
|
||||
NativeKeyBinding;
|
||||
void_t;
|
||||
};
|
||||
|
||||
struct ShowInfo
|
||||
{
|
||||
nsString name;
|
||||
|
@ -511,8 +498,17 @@ parent:
|
|||
|
||||
async ReplyKeyEvent(WidgetKeyboardEvent event);
|
||||
|
||||
sync RequestNativeKeyBindings(WidgetKeyboardEvent event)
|
||||
returns (MaybeNativeKeyBinding bindings);
|
||||
/**
|
||||
* Retrieves edit commands for the key combination represented by aEvent.
|
||||
*
|
||||
* @param aType One of nsIWidget::NativeKeyBindingsType.
|
||||
* @param aEvent KeyboardEvent which represents a key combination.
|
||||
* Note that this must be a trusted event.
|
||||
* @return Array of edit commands which should be executed in
|
||||
* editor of native applications.
|
||||
*/
|
||||
sync RequestNativeKeyBindings(uint32_t aType, WidgetKeyboardEvent aEvent)
|
||||
returns (CommandInt[] commands);
|
||||
|
||||
async SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
|
||||
int32_t aNativeKeyCode,
|
||||
|
@ -691,7 +687,7 @@ child:
|
|||
*/
|
||||
async SynthMouseMoveEvent(WidgetMouseEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
|
||||
async RealMouseButtonEvent(WidgetMouseEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
|
||||
async RealKeyEvent(WidgetKeyboardEvent event, MaybeNativeKeyBinding keyBinding);
|
||||
async RealKeyEvent(WidgetKeyboardEvent event);
|
||||
async MouseWheelEvent(WidgetWheelEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
|
||||
async RealTouchEvent(WidgetTouchEvent aEvent,
|
||||
ScrollableLayerGuid aGuid,
|
||||
|
|
|
@ -1878,22 +1878,27 @@ TabChild::RecvPluginEvent(const WidgetPluginEvent& aEvent)
|
|||
}
|
||||
|
||||
void
|
||||
TabChild::RequestNativeKeyBindings(AutoCacheNativeKeyCommands* aAutoCache,
|
||||
const WidgetKeyboardEvent* aEvent)
|
||||
TabChild::RequestEditCommands(nsIWidget::NativeKeyBindingsType aType,
|
||||
const WidgetKeyboardEvent& aEvent,
|
||||
nsTArray<CommandInt>& aCommands)
|
||||
{
|
||||
MaybeNativeKeyBinding maybeBindings;
|
||||
if (!SendRequestNativeKeyBindings(*aEvent, &maybeBindings)) {
|
||||
MOZ_ASSERT(aCommands.IsEmpty());
|
||||
|
||||
if (NS_WARN_IF(aEvent.IsEditCommandsInitialized(aType))) {
|
||||
aCommands = aEvent.EditCommandsConstRef(aType);
|
||||
return;
|
||||
}
|
||||
|
||||
if (maybeBindings.type() == MaybeNativeKeyBinding::TNativeKeyBinding) {
|
||||
const NativeKeyBinding& bindings = maybeBindings;
|
||||
aAutoCache->Cache(bindings.singleLineCommands(),
|
||||
bindings.multiLineCommands(),
|
||||
bindings.richTextCommands());
|
||||
} else {
|
||||
aAutoCache->CacheNoCommands();
|
||||
switch (aType) {
|
||||
case nsIWidget::NativeKeyBindingsForSingleLineEditor:
|
||||
case nsIWidget::NativeKeyBindingsForMultiLineEditor:
|
||||
case nsIWidget::NativeKeyBindingsForRichTextEditor:
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Invalid native key bindings type");
|
||||
}
|
||||
|
||||
SendRequestNativeKeyBindings(aType, aEvent, &aCommands);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
|
@ -1944,29 +1949,20 @@ TabChild::UpdateRepeatedKeyEventEndTime(const WidgetKeyboardEvent& aEvent)
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& aEvent,
|
||||
const MaybeNativeKeyBinding& aBindings)
|
||||
TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& aEvent)
|
||||
{
|
||||
if (SkipRepeatedKeyEvent(aEvent)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
AutoCacheNativeKeyCommands autoCache(mPuppetWidget);
|
||||
MOZ_ASSERT(aEvent.mMessage != eKeyPress ||
|
||||
aEvent.AreAllEditCommandsInitialized(),
|
||||
"eKeyPress event should have native key binding information");
|
||||
|
||||
if (aEvent.mMessage == eKeyPress) {
|
||||
// If content code called preventDefault() on a keydown event, then we don't
|
||||
// want to process any following keypress events.
|
||||
if (mIgnoreKeyPressEvent) {
|
||||
return IPC_OK();
|
||||
}
|
||||
if (aBindings.type() == MaybeNativeKeyBinding::TNativeKeyBinding) {
|
||||
const NativeKeyBinding& bindings = aBindings;
|
||||
autoCache.Cache(bindings.singleLineCommands(),
|
||||
bindings.multiLineCommands(),
|
||||
bindings.richTextCommands());
|
||||
} else {
|
||||
autoCache.CacheNoCommands();
|
||||
}
|
||||
// If content code called preventDefault() on a keydown event, then we don't
|
||||
// want to process any following keypress events.
|
||||
if (aEvent.mMessage == eKeyPress && mIgnoreKeyPressEvent) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
WidgetKeyboardEvent localEvent(aEvent);
|
||||
|
|
|
@ -389,8 +389,7 @@ public:
|
|||
const uint32_t& aDropEffect) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvRealKeyEvent(const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
const MaybeNativeKeyBinding& aBindings) override;
|
||||
RecvRealKeyEvent(const mozilla::WidgetKeyboardEvent& aEvent) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvMouseWheelEvent(const mozilla::WidgetWheelEvent& aEvent,
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
|
@ -512,8 +511,9 @@ public:
|
|||
|
||||
void NotifyPainted();
|
||||
|
||||
void RequestNativeKeyBindings(mozilla::widget::AutoCacheNativeKeyCommands* aAutoCache,
|
||||
const WidgetKeyboardEvent* aEvent);
|
||||
void RequestEditCommands(nsIWidget::NativeKeyBindingsType aType,
|
||||
const WidgetKeyboardEvent& aEvent,
|
||||
nsTArray<CommandInt>& aCommands);
|
||||
|
||||
/**
|
||||
* Signal to this TabChild that it should be made visible:
|
||||
|
|
|
@ -1214,22 +1214,24 @@ TabParent::RecvDispatchKeyboardEvent(const mozilla::WidgetKeyboardEvent& aEvent)
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
static void
|
||||
DoCommandCallback(mozilla::Command aCommand, void* aData)
|
||||
{
|
||||
static_cast<InfallibleTArray<mozilla::CommandInt>*>(aData)->
|
||||
AppendElement(aCommand);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
TabParent::RecvRequestNativeKeyBindings(const WidgetKeyboardEvent& aEvent,
|
||||
MaybeNativeKeyBinding* aBindings)
|
||||
TabParent::RecvRequestNativeKeyBindings(const uint32_t& aType,
|
||||
const WidgetKeyboardEvent& aEvent,
|
||||
nsTArray<CommandInt>* aCommands)
|
||||
{
|
||||
AutoTArray<mozilla::CommandInt, 4> singleLine;
|
||||
AutoTArray<mozilla::CommandInt, 4> multiLine;
|
||||
AutoTArray<mozilla::CommandInt, 4> richText;
|
||||
MOZ_ASSERT(aCommands);
|
||||
MOZ_ASSERT(aCommands->IsEmpty());
|
||||
|
||||
*aBindings = mozilla::void_t();
|
||||
nsIWidget::NativeKeyBindingsType keyBindingsType =
|
||||
static_cast<nsIWidget::NativeKeyBindingsType>(aType);
|
||||
switch (keyBindingsType) {
|
||||
case nsIWidget::NativeKeyBindingsForSingleLineEditor:
|
||||
case nsIWidget::NativeKeyBindingsForMultiLineEditor:
|
||||
case nsIWidget::NativeKeyBindingsForRichTextEditor:
|
||||
break;
|
||||
default:
|
||||
return IPC_FAIL(this, "Invalid aType value");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
|
@ -1237,24 +1239,14 @@ TabParent::RecvRequestNativeKeyBindings(const WidgetKeyboardEvent& aEvent,
|
|||
}
|
||||
|
||||
WidgetKeyboardEvent localEvent(aEvent);
|
||||
localEvent.mWidget = widget;
|
||||
|
||||
if (NS_FAILED(widget->AttachNativeKeyEvent(localEvent))) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
widget->ExecuteNativeKeyBinding(
|
||||
nsIWidget::NativeKeyBindingsForSingleLineEditor,
|
||||
localEvent, DoCommandCallback, &singleLine);
|
||||
widget->ExecuteNativeKeyBinding(
|
||||
nsIWidget::NativeKeyBindingsForMultiLineEditor,
|
||||
localEvent, DoCommandCallback, &multiLine);
|
||||
widget->ExecuteNativeKeyBinding(
|
||||
nsIWidget::NativeKeyBindingsForRichTextEditor,
|
||||
localEvent, DoCommandCallback, &richText);
|
||||
|
||||
if (!singleLine.IsEmpty() || !multiLine.IsEmpty() || !richText.IsEmpty()) {
|
||||
*aBindings = NativeKeyBinding(singleLine, multiLine, richText);
|
||||
}
|
||||
localEvent.InitEditCommandsFor(keyBindingsType);
|
||||
*aCommands = localEvent.EditCommandsConstRef(keyBindingsType);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
@ -1444,31 +1436,15 @@ TabParent::SendRealKeyEvent(WidgetKeyboardEvent& aEvent)
|
|||
}
|
||||
aEvent.mRefPoint += GetChildProcessOffset();
|
||||
|
||||
MaybeNativeKeyBinding bindings;
|
||||
bindings = void_t();
|
||||
if (aEvent.mMessage == eKeyPress) {
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
|
||||
AutoTArray<mozilla::CommandInt, 4> singleLine;
|
||||
AutoTArray<mozilla::CommandInt, 4> multiLine;
|
||||
AutoTArray<mozilla::CommandInt, 4> richText;
|
||||
|
||||
widget->ExecuteNativeKeyBinding(
|
||||
nsIWidget::NativeKeyBindingsForSingleLineEditor,
|
||||
aEvent, DoCommandCallback, &singleLine);
|
||||
widget->ExecuteNativeKeyBinding(
|
||||
nsIWidget::NativeKeyBindingsForMultiLineEditor,
|
||||
aEvent, DoCommandCallback, &multiLine);
|
||||
widget->ExecuteNativeKeyBinding(
|
||||
nsIWidget::NativeKeyBindingsForRichTextEditor,
|
||||
aEvent, DoCommandCallback, &richText);
|
||||
|
||||
if (!singleLine.IsEmpty() || !multiLine.IsEmpty() || !richText.IsEmpty()) {
|
||||
bindings = NativeKeyBinding(singleLine, multiLine, richText);
|
||||
}
|
||||
// XXX Should we do this only when input context indicates an editor having
|
||||
// focus and the key event won't cause inputting text?
|
||||
aEvent.InitAllEditCommands();
|
||||
} else {
|
||||
aEvent.PreventNativeKeyBindings();
|
||||
}
|
||||
|
||||
return PBrowserParent::SendRealKeyEvent(aEvent, bindings);
|
||||
return PBrowserParent::SendRealKeyEvent(aEvent);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -393,8 +393,10 @@ public:
|
|||
LayoutDeviceToCSSScale GetLayoutDeviceToCSSScale();
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvRequestNativeKeyBindings(const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
MaybeNativeKeyBinding* aBindings) override;
|
||||
RecvRequestNativeKeyBindings(
|
||||
const uint32_t& aType,
|
||||
const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
nsTArray<mozilla::CommandInt>* aCommands) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvSynthesizeNativeKeyEvent(const int32_t& aNativeKeyboardLayout,
|
||||
|
|
|
@ -2736,7 +2736,10 @@ ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
|
|||
}
|
||||
|
||||
nsAutoCString sourceMapURL;
|
||||
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-SourceMap"), sourceMapURL);
|
||||
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("SourceMap"), sourceMapURL);
|
||||
if (NS_FAILED(rv)) {
|
||||
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-SourceMap"), sourceMapURL);
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aRequest->mHasSourceMapURL = true;
|
||||
aRequest->mSourceMapURL = NS_ConvertUTF8toUTF16(sourceMapURL);
|
||||
|
|
|
@ -3,47 +3,29 @@ const URL =
|
|||
"window.focus();" +
|
||||
"var down = 0; var press = 0;" +
|
||||
"onkeydown = function(e) {" +
|
||||
" var startTime = Date.now();" +
|
||||
" document.body.setAttribute('data-down', ++down);" +
|
||||
" if (e.keyCode == 'D') while (Date.now() - startTime < 500) {}" +
|
||||
" if (e.keyCode == KeyboardEvent.DOM_VK_D) while (Date.now() - startTime < 500) {}" +
|
||||
"};" +
|
||||
"onkeypress = function(e) {" +
|
||||
" var startTime = Date.now();" +
|
||||
" document.body.setAttribute('data-press', ++press);" +
|
||||
" if (e.charCode == 'P') while (Date.now() - startTime < 500) {}" +
|
||||
" if (e.charCode == 'p'.charCodeAt(0)) while (Date.now() - startTime < 500) {}" +
|
||||
"};" +
|
||||
"</script>";
|
||||
|
||||
function createKeyEvent(type, id, repeated) {
|
||||
var code = id.charCodeAt(0);
|
||||
return new KeyboardEvent(type, { keyCode: code, charCode: code, bubbles: true, repeat: repeated });
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
// Need to dispatch a DOM Event explicitly via PresShell to get KeyEvent with .repeat = true to
|
||||
// be handled by EventStateManager, which then forwards the event to the child process.
|
||||
var utils = EventUtils._getDOMWindowUtils(window);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keydown", "D", false), true);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keypress", "D", false), true);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keydown", "D", true), true);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keypress", "D", true), true);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keydown", "D", true), true);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keypress", "D", true), true);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keyup", "D", true), true);
|
||||
EventUtils.synthesizeKey("d", { code: "KeyD", repeat: 3 });
|
||||
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
is(content.document.body.getAttribute("data-down"), "2", "Correct number of events");
|
||||
is(content.document.body.getAttribute("data-press"), "2", "Correct number of events");
|
||||
});
|
||||
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keydown", "P", false), true);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keypress", "P", false), true);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keydown", "P", true), true);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keypress", "P", true), true);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keydown", "P", true), true);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keypress", "P", true), true);
|
||||
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keyup", "P", true), true);
|
||||
EventUtils.synthesizeKey("p", { code: "KeyP", repeat: 3 });
|
||||
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
is(content.document.body.getAttribute("data-down"), "4", "Correct number of events");
|
||||
|
|
|
@ -627,10 +627,16 @@ EditorEventListener::KeyPress(WidgetKeyboardEvent* aKeyboardEvent)
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = editorBase->GetDocument();
|
||||
bool handled = widget->ExecuteNativeKeyBinding(
|
||||
nsIWidget::NativeKeyBindingsForRichTextEditor,
|
||||
*aKeyboardEvent, DoCommandCallback, doc);
|
||||
if (handled) {
|
||||
|
||||
// WidgetKeyboardEvent::ExecuteEditCommands() requires non-nullptr mWidget.
|
||||
// If the event is created by chrome script, it is nullptr but we need to
|
||||
// execute native key bindings. Therefore, we need to set widget to
|
||||
// WidgetEvent::mWidget temporarily.
|
||||
AutoRestore<nsCOMPtr<nsIWidget>> saveWidget(aKeyboardEvent->mWidget);
|
||||
aKeyboardEvent->mWidget = widget;
|
||||
if (aKeyboardEvent->ExecuteEditCommands(
|
||||
nsIWidget::NativeKeyBindingsForRichTextEditor,
|
||||
DoCommandCallback, doc)) {
|
||||
aKeyboardEvent->PreventDefault();
|
||||
}
|
||||
return NS_OK;
|
||||
|
|
|
@ -204,6 +204,7 @@ DrawTargetCaptureImpl::ContainsOnlyColoredGlyphs(RefPtr<ScaledFont>& aScaledFont
|
|||
{
|
||||
uint8_t* start = &mDrawCommandStorage.front();
|
||||
uint8_t* current = start;
|
||||
bool result = false;
|
||||
|
||||
while (current < start + mDrawCommandStorage.size()) {
|
||||
DrawingCommand* command =
|
||||
|
@ -251,8 +252,9 @@ DrawTargetCaptureImpl::ContainsOnlyColoredGlyphs(RefPtr<ScaledFont>& aScaledFont
|
|||
aGlyphs.insert(aGlyphs.end(),
|
||||
fillGlyphs->mGlyphs.begin(),
|
||||
fillGlyphs->mGlyphs.end());
|
||||
result = true;
|
||||
}
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "GLConsts.h"
|
||||
#include "GLContextCGL.h"
|
||||
|
||||
using namespace mozilla;
|
||||
// IOSurface signatures
|
||||
|
@ -510,9 +511,13 @@ MacIOSurface::GetReadFormat()
|
|||
}
|
||||
|
||||
CGLError
|
||||
MacIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctx, size_t plane)
|
||||
MacIOSurface::CGLTexImageIOSurface2D(mozilla::gl::GLContext* aGL,
|
||||
CGLContextObj ctx,
|
||||
size_t plane,
|
||||
mozilla::gfx::SurfaceFormat* aOutReadFormat)
|
||||
{
|
||||
MOZ_ASSERT(plane >= 0);
|
||||
bool isCompatibilityProfile = aGL->IsCompatibilityProfile();
|
||||
OSType pixelFormat = GetPixelFormat();
|
||||
|
||||
GLenum internalFormat;
|
||||
|
@ -522,34 +527,65 @@ MacIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctx, size_t plane)
|
|||
MOZ_ASSERT(GetPlaneCount() == 2);
|
||||
MOZ_ASSERT(plane < 2);
|
||||
|
||||
// The LOCAL_GL_LUMINANCE and LOCAL_GL_LUMINANCE_ALPHA are the deprecated
|
||||
// format. So, use LOCAL_GL_RED and LOCAL_GL_RB if we use core profile.
|
||||
// https://www.khronos.org/opengl/wiki/Image_Format#Legacy_Image_Formats
|
||||
if (plane == 0) {
|
||||
internalFormat = format = GL_LUMINANCE;
|
||||
internalFormat = format = (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE)
|
||||
: (LOCAL_GL_RED);
|
||||
} else {
|
||||
internalFormat = format = GL_LUMINANCE_ALPHA;
|
||||
internalFormat = format = (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE_ALPHA)
|
||||
: (LOCAL_GL_RG);
|
||||
}
|
||||
type = LOCAL_GL_UNSIGNED_BYTE;
|
||||
if (aOutReadFormat) {
|
||||
*aOutReadFormat = mozilla::gfx::SurfaceFormat::NV12;
|
||||
}
|
||||
type = GL_UNSIGNED_BYTE;
|
||||
} else if (pixelFormat == '2vuy') {
|
||||
MOZ_ASSERT(plane == 0);
|
||||
|
||||
internalFormat = GL_RGB;
|
||||
format = LOCAL_GL_YCBCR_422_APPLE;
|
||||
type = GL_UNSIGNED_SHORT_8_8_APPLE;
|
||||
// The YCBCR_422_APPLE ext is only available in compatibility profile. So,
|
||||
// we should use RGB_422_APPLE for core profile. The difference between
|
||||
// YCBCR_422_APPLE and RGB_422_APPLE is that the YCBCR_422_APPLE converts
|
||||
// the YCbCr value to RGB with REC 601 conversion. But the RGB_422_APPLE
|
||||
// doesn't contain color conversion. You should do the color conversion by
|
||||
// yourself for RGB_422_APPLE.
|
||||
//
|
||||
// https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_ycbcr_422.txt
|
||||
// https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_rgb_422.txt
|
||||
if (isCompatibilityProfile) {
|
||||
format = LOCAL_GL_YCBCR_422_APPLE;
|
||||
if (aOutReadFormat) {
|
||||
*aOutReadFormat = mozilla::gfx::SurfaceFormat::R8G8B8X8;
|
||||
}
|
||||
} else {
|
||||
format = LOCAL_GL_RGB_422_APPLE;
|
||||
if (aOutReadFormat) {
|
||||
*aOutReadFormat = mozilla::gfx::SurfaceFormat::YUV422;
|
||||
}
|
||||
}
|
||||
internalFormat = LOCAL_GL_RGB;
|
||||
type = LOCAL_GL_UNSIGNED_SHORT_8_8_APPLE;
|
||||
} else {
|
||||
MOZ_ASSERT(plane == 0);
|
||||
|
||||
internalFormat = HasAlpha() ? GL_RGBA : GL_RGB;
|
||||
format = GL_BGRA;
|
||||
type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||
internalFormat = HasAlpha() ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
|
||||
format = LOCAL_GL_BGRA;
|
||||
type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||
if (aOutReadFormat) {
|
||||
*aOutReadFormat = HasAlpha() ? mozilla::gfx::SurfaceFormat::R8G8B8A8
|
||||
: mozilla::gfx::SurfaceFormat::R8G8B8X8;
|
||||
}
|
||||
}
|
||||
CGLError temp = MacIOSurfaceLib::CGLTexImageIOSurface2D(ctx,
|
||||
GL_TEXTURE_RECTANGLE_ARB,
|
||||
internalFormat,
|
||||
GetDevicePixelWidth(plane),
|
||||
GetDevicePixelHeight(plane),
|
||||
format,
|
||||
type,
|
||||
mIOSurfacePtr, plane);
|
||||
return temp;
|
||||
|
||||
return MacIOSurfaceLib::CGLTexImageIOSurface2D(ctx,
|
||||
LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
internalFormat,
|
||||
GetDevicePixelWidth(plane),
|
||||
GetDevicePixelHeight(plane),
|
||||
format,
|
||||
type,
|
||||
mIOSurfacePtr,
|
||||
plane);
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -596,7 +632,6 @@ already_AddRefed<MacIOSurface> MacIOSurface::IOSurfaceContextGetSurface(CGContex
|
|||
return ioSurface.forget();
|
||||
}
|
||||
|
||||
|
||||
CGContextType GetContextType(CGContextRef ref)
|
||||
{
|
||||
if (!MacIOSurfaceLib::isInit() || !MacIOSurfaceLib::sCGContextGetTypePtr)
|
||||
|
@ -611,5 +646,3 @@ CGContextType GetContextType(CGContextRef ref)
|
|||
return CG_CONTEXT_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
#include <CoreVideo/CoreVideo.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
class GLContext;
|
||||
}
|
||||
}
|
||||
|
||||
struct _CGLContextObject;
|
||||
|
||||
typedef _CGLContextObject* CGLContextObj;
|
||||
|
@ -120,7 +126,10 @@ public:
|
|||
|
||||
// We would like to forward declare NSOpenGLContext, but it is an @interface
|
||||
// and this file is also used from c++, so we use a void *.
|
||||
CGLError CGLTexImageIOSurface2D(CGLContextObj ctxt, size_t plane = 0);
|
||||
CGLError CGLTexImageIOSurface2D(mozilla::gl::GLContext* aGL,
|
||||
CGLContextObj ctxt,
|
||||
size_t plane,
|
||||
mozilla::gfx::SurfaceFormat* aOutReadFormat = nullptr);
|
||||
already_AddRefed<SourceSurface> GetAsSurface();
|
||||
CGContextRef CreateIOSurfaceContext();
|
||||
|
||||
|
|
|
@ -212,6 +212,13 @@ ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBu
|
|||
cairoPath->AppendPathToBuilder(builder);
|
||||
return;
|
||||
}
|
||||
if (backendType == BackendType::RECORDING) {
|
||||
SkPath skPath = GetSkiaPathForGlyphs(aBuffer);
|
||||
RefPtr<Path> path = MakeAndAddRef<PathSkia>(skPath, FillRule::FILL_WINDING);
|
||||
path->StreamToSink(aBuilder);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(false, "Path not being copied");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,8 @@ enum class SurfaceFormat : int8_t {
|
|||
// This one is a single-byte, so endianness isn't an issue.
|
||||
A8,
|
||||
|
||||
R8G8,
|
||||
|
||||
// These ones are their own special cases.
|
||||
YUV,
|
||||
NV12,
|
||||
|
|
|
@ -79,4 +79,4 @@ to make sure that mozjs_sys also has its Cargo.lock file updated if needed, henc
|
|||
the need to run the cargo update command in js/src as well. Hopefully this will
|
||||
be resolved soon.
|
||||
|
||||
Latest Commit: 8516d6c04235e684d9bf9c783ba4fc99dab3bf02
|
||||
Latest Commit: 102603520d52f335f152ab74b6bcfdae061b6bc8
|
||||
|
|
|
@ -778,14 +778,18 @@ GLBlitHelper::BlitMacIOSurfaceImage(layers::MacIOSurfaceImage* ioImage)
|
|||
mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textures[0]);
|
||||
mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
surf->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(mGL)->GetCGLContext(), 0);
|
||||
surf->CGLTexImageIOSurface2D(mGL,
|
||||
gl::GLContextCGL::Cast(mGL)->GetCGLContext(),
|
||||
0);
|
||||
mGL->fUniform2f(mYTexScaleLoc, surf->GetWidth(0), surf->GetHeight(0));
|
||||
|
||||
mGL->fActiveTexture(LOCAL_GL_TEXTURE1);
|
||||
mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textures[1]);
|
||||
mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
surf->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(mGL)->GetCGLContext(), 1);
|
||||
surf->CGLTexImageIOSurface2D(mGL,
|
||||
gl::GLContextCGL::Cast(mGL)->GetCGLContext(),
|
||||
1);
|
||||
mGL->fUniform2f(mCbCrTexScaleLoc, surf->GetWidth(1), surf->GetHeight(1));
|
||||
|
||||
mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
|
|
@ -142,7 +142,7 @@ BackTextureWithIOSurf(GLContext* gl, GLuint tex, MacIOSurface* ioSurf)
|
|||
CGLContextObj cgl = GLContextCGL::Cast(gl)->GetCGLContext();
|
||||
MOZ_ASSERT(cgl);
|
||||
|
||||
ioSurf->CGLTexImageIOSurface2D(cgl);
|
||||
ioSurf->CGLTexImageIOSurface2D(gl, cgl, 0);
|
||||
}
|
||||
|
||||
SharedSurface_IOSurface::SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf,
|
||||
|
|
|
@ -596,6 +596,11 @@ public:
|
|||
*/
|
||||
virtual void FlushRendering() { }
|
||||
|
||||
/**
|
||||
* Make sure that the previous transaction has been
|
||||
* received. This will synchronsly wait on a remote compositor. */
|
||||
virtual void WaitOnTransactionProcessed() { }
|
||||
|
||||
virtual void SendInvalidRegion(const nsIntRegion& aRegion) {}
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "mozilla/TouchEvents.h"
|
||||
#include "mozilla/Preferences.h" // for Preferences
|
||||
#include "mozilla/EventStateManager.h" // for WheelPrefs
|
||||
#include "mozilla/webrender/WebRenderAPI.h"
|
||||
#include "nsDebug.h" // for NS_WARNING
|
||||
#include "nsPoint.h" // for nsIntPoint
|
||||
#include "nsThreadUtils.h" // for NS_IsMainThread
|
||||
|
@ -364,6 +365,60 @@ APZCTreeManager::UpdateHitTestingTree(uint64_t aRootLayerTreeId,
|
|||
aOriginatingLayersId, aPaintSequenceNumber);
|
||||
}
|
||||
|
||||
bool
|
||||
APZCTreeManager::PushStateToWR(wr::WebRenderAPI* aWrApi,
|
||||
const TimeStamp& aSampleTime)
|
||||
{
|
||||
APZThreadUtils::AssertOnCompositorThread();
|
||||
MOZ_ASSERT(aWrApi);
|
||||
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
|
||||
bool activeAnimations = false;
|
||||
uint64_t lastLayersId = -1;
|
||||
WrPipelineId lastPipelineId;
|
||||
|
||||
// We iterate backwards here because the HitTestingTreeNode is optimized
|
||||
// for backwards iteration. The equivalent code in AsyncCompositionManager
|
||||
// iterates forwards, but the direction shouldn't really matter in practice
|
||||
// so we do what's faster. In the future, if we need to start doing the
|
||||
// equivalent of AlignFixedAndStickyLayers here, then the order will become
|
||||
// important and we'll need to take that into consideration.
|
||||
ForEachNode<ReverseIterator>(mRootNode.get(),
|
||||
[&](HitTestingTreeNode* aNode)
|
||||
{
|
||||
if (!aNode->IsPrimaryHolder()) {
|
||||
return;
|
||||
}
|
||||
AsyncPanZoomController* apzc = aNode->GetApzc();
|
||||
MOZ_ASSERT(apzc);
|
||||
|
||||
if (aNode->GetLayersId() != lastLayersId) {
|
||||
// If we walked into or out of a subtree, we need to get the new
|
||||
// pipeline id.
|
||||
lastLayersId = aNode->GetLayersId();
|
||||
const LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(lastLayersId);
|
||||
MOZ_ASSERT(state && state->mWrBridge);
|
||||
lastPipelineId = state->mWrBridge->PipelineId();
|
||||
}
|
||||
|
||||
ParentLayerPoint layerTranslation = apzc->GetCurrentAsyncTransform(
|
||||
AsyncPanZoomController::RESPECT_FORCE_DISABLE).mTranslation;
|
||||
// The positive translation means the painted content is supposed to
|
||||
// move down (or to the right), and that corresponds to a reduction in
|
||||
// the scroll offset. Since we are effectively giving WR the async
|
||||
// scroll delta here, we want to negate the translation.
|
||||
ParentLayerPoint asyncScrollDelta = -layerTranslation;
|
||||
aWrApi->UpdateScrollPosition(lastPipelineId, apzc->GetGuid().mScrollId,
|
||||
wr::ToWrPoint(asyncScrollDelta));
|
||||
|
||||
apzc->ReportCheckerboard(aSampleTime);
|
||||
activeAnimations |= apzc->AdvanceAnimations(aSampleTime);
|
||||
});
|
||||
|
||||
return activeAnimations;
|
||||
}
|
||||
|
||||
// Compute the clip region to be used for a layer with an APZC. This function
|
||||
// is only called for layers which actually have scrollable metrics and an APZC.
|
||||
template<class ScrollNode> static ParentLayerIntRegion
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
namespace mozilla {
|
||||
class MultiTouchInput;
|
||||
|
||||
namespace wr {
|
||||
class WebRenderAPI;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
|
||||
class Layer;
|
||||
|
@ -144,6 +148,18 @@ public:
|
|||
uint64_t aOriginatingLayersId,
|
||||
uint32_t aPaintSequenceNumber);
|
||||
|
||||
/**
|
||||
* Called when webrender is enabled, from the compositor thread. This function
|
||||
* walks through the tree of APZC instances and tells webrender about the
|
||||
* async scroll position. It also advances APZ animations to the specified
|
||||
* sample time. In effect it is the webrender equivalent of (part of) the
|
||||
* code in AsyncCompositionManager.
|
||||
* Returns true if any APZ animations are in progress and we need to keep
|
||||
* compositing.
|
||||
*/
|
||||
bool PushStateToWR(wr::WebRenderAPI* aWrApi,
|
||||
const TimeStamp& aSampleTime);
|
||||
|
||||
/**
|
||||
* Walk the tree of APZCs and flushes the repaint requests for all the APZCS
|
||||
* corresponding to the given layers id. Finally, sends a flush complete
|
||||
|
|
|
@ -656,6 +656,14 @@ ClientLayerManager::FlushRendering()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::WaitOnTransactionProcessed()
|
||||
{
|
||||
CompositorBridgeChild* remoteRenderer = GetCompositorBridgeChild();
|
||||
if (remoteRenderer) {
|
||||
remoteRenderer->SendWaitOnTransactionProcessed();
|
||||
}
|
||||
}
|
||||
void
|
||||
ClientLayerManager::UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier,
|
||||
uint64_t aDeviceResetSeqNo)
|
||||
|
|
|
@ -114,6 +114,7 @@ public:
|
|||
}
|
||||
|
||||
virtual void FlushRendering() override;
|
||||
virtual void WaitOnTransactionProcessed() override;
|
||||
virtual void SendInvalidRegion(const nsIntRegion& aRegion) override;
|
||||
|
||||
virtual uint32_t StartFrameTimeRecording(int32_t aBufferSize) override;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/layers/GPUVideoTextureHost.h"
|
||||
#include "mozilla/layers/WebRenderTextureHost.h"
|
||||
#include "mozilla/webrender/WebRenderAPI.h"
|
||||
#include "nsAString.h"
|
||||
#include "mozilla/RefPtr.h" // for nsRefPtr
|
||||
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||
|
@ -555,6 +556,33 @@ BufferTextureHost::Unlock()
|
|||
mLocked = false;
|
||||
}
|
||||
|
||||
void
|
||||
BufferTextureHost::AddWRImage(wr::WebRenderAPI* aAPI,
|
||||
Range<const wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExtID)
|
||||
{
|
||||
MOZ_ASSERT(aImageKeys.length() == 1);
|
||||
// XXX handling YUV
|
||||
gfx::SurfaceFormat wrFormat =
|
||||
(GetFormat() == gfx::SurfaceFormat::YUV) ? gfx::SurfaceFormat::B8G8R8A8
|
||||
: GetFormat();
|
||||
gfx::SurfaceFormat format = GetFormat();
|
||||
uint32_t wrStride = 0;
|
||||
|
||||
if (format == gfx::SurfaceFormat::YUV) {
|
||||
// XXX this stride is used until yuv image rendering by webrender is used.
|
||||
// Software converted RGB buffers strides are aliened to 16
|
||||
wrStride = gfx::GetAlignedStride<16>(GetSize().width, BytesPerPixel(gfx::SurfaceFormat::B8G8R8A8));
|
||||
} else {
|
||||
wrStride = ImageDataSerializer::ComputeRGBStride(format, GetSize().width);
|
||||
}
|
||||
|
||||
wr::ImageDescriptor descriptor(GetSize(), wrStride, wrFormat);
|
||||
aAPI->AddExternalImageBuffer(aImageKeys[0],
|
||||
descriptor,
|
||||
aExtID);
|
||||
}
|
||||
|
||||
void
|
||||
TextureHost::DeserializeReadLock(const ReadLockDescriptor& aDesc,
|
||||
ISurfaceAllocator* aAllocator)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/layers/LayersTypes.h" // for LayerRenderState, etc
|
||||
#include "mozilla/layers/LayersSurfaces.h"
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "mozilla/Range.h"
|
||||
#include "mozilla/UniquePtr.h" // for UniquePtr
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
|
@ -36,6 +37,10 @@ namespace ipc {
|
|||
class Shmem;
|
||||
} // namespace ipc
|
||||
|
||||
namespace wr {
|
||||
class WebRenderAPI;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
|
||||
class BufferDescriptor;
|
||||
|
@ -591,6 +596,15 @@ public:
|
|||
virtual MacIOSurfaceTextureHostOGL* AsMacIOSurfaceTextureHost() { return nullptr; }
|
||||
virtual WebRenderTextureHost* AsWebRenderTextureHost() { return nullptr; }
|
||||
|
||||
// Add all necessary textureHost informations to WebrenderAPI. Then, WR could
|
||||
// use these informations to compose this textureHost.
|
||||
virtual void AddWRImage(wr::WebRenderAPI* aAPI,
|
||||
Range<const wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExtID)
|
||||
{
|
||||
MOZ_ASSERT_UNREACHABLE("No AddWRImage() implementation for this TextureHost type.");
|
||||
}
|
||||
|
||||
protected:
|
||||
void ReadUnlock();
|
||||
|
||||
|
@ -678,6 +692,10 @@ public:
|
|||
|
||||
const BufferDescriptor& GetBufferDescriptor() const { return mDescriptor; }
|
||||
|
||||
virtual void AddWRImage(wr::WebRenderAPI* aAPI,
|
||||
Range<const wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExtID) override;
|
||||
|
||||
protected:
|
||||
bool Upload(nsIntRegion *aRegion = nullptr);
|
||||
bool MaybeUpload(nsIntRegion *aRegion = nullptr);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/gfx/DeviceManagerDx.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/layers/CompositorBridgeChild.h"
|
||||
#include "mozilla/webrender/WebRenderAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -854,6 +855,14 @@ DXGITextureHostD3D11::BindTextureSource(CompositableTextureSourceRef& aTexture)
|
|||
return !!aTexture;
|
||||
}
|
||||
|
||||
void
|
||||
DXGITextureHostD3D11::AddWRImage(wr::WebRenderAPI* aAPI,
|
||||
Range<const wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExtID)
|
||||
{
|
||||
MOZ_ASSERT_UNREACHABLE("No AddWRImage() implementation for this DXGITextureHostD3D11 type.");
|
||||
}
|
||||
|
||||
DXGIYCbCrTextureHostD3D11::DXGIYCbCrTextureHostD3D11(TextureFlags aFlags,
|
||||
const SurfaceDescriptorDXGIYCbCr& aDescriptor)
|
||||
: TextureHost(aFlags)
|
||||
|
@ -987,6 +996,14 @@ DXGIYCbCrTextureHostD3D11::BindTextureSource(CompositableTextureSourceRef& aText
|
|||
return !!aTexture;
|
||||
}
|
||||
|
||||
void
|
||||
DXGIYCbCrTextureHostD3D11::AddWRImage(wr::WebRenderAPI* aAPI,
|
||||
Range<const wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExtID)
|
||||
{
|
||||
MOZ_ASSERT_UNREACHABLE("No AddWRImage() implementation for this DXGIYCbCrTextureHostD3D11 type.");
|
||||
}
|
||||
|
||||
bool
|
||||
DataTextureSourceD3D11::Update(DataSourceSurface* aSurface,
|
||||
nsIntRegion* aDestRegion,
|
||||
|
|
|
@ -325,6 +325,10 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void AddWRImage(wr::WebRenderAPI* aAPI,
|
||||
Range<const wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExtID) override;
|
||||
|
||||
protected:
|
||||
bool LockInternal();
|
||||
void UnlockInternal();
|
||||
|
@ -370,6 +374,10 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void AddWRImage(wr::WebRenderAPI* aAPI,
|
||||
Range<const wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExtID) override;
|
||||
|
||||
protected:
|
||||
RefPtr<ID3D11Device> GetDevice();
|
||||
|
||||
|
|
|
@ -1177,7 +1177,7 @@ CompositorBridgeChild::GetNextExternalImageId()
|
|||
MOZ_RELEASE_ASSERT(sNextID != UINT32_MAX);
|
||||
|
||||
uint64_t imageId = mNamespace;
|
||||
imageId = imageId << 32 | sNextID;
|
||||
imageId = (imageId << 32) | sNextID;
|
||||
return Some(wr::ToExternalImageId(imageId));
|
||||
}
|
||||
|
||||
|
|
|
@ -523,6 +523,12 @@ CompositorBridgeParent::RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
CompositorBridgeParent::RecvWaitOnTransactionProcessed()
|
||||
{
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
CompositorBridgeParent::RecvFlushRendering()
|
||||
{
|
||||
|
@ -1595,7 +1601,8 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel
|
|||
RefPtr<widget::CompositorWidget> widget = mWidget;
|
||||
RefPtr<wr::WebRenderAPI> api = wr::WebRenderAPI::Create(
|
||||
gfxPrefs::WebRenderProfilerEnabled(), this, Move(widget), aSize);
|
||||
RefPtr<WebRenderCompositableHolder> holder = new WebRenderCompositableHolder();
|
||||
RefPtr<WebRenderCompositableHolder> holder =
|
||||
new WebRenderCompositableHolder(WebRenderBridgeParent::AllocIdNameSpace());
|
||||
MOZ_ASSERT(api); // TODO have a fallback
|
||||
api->SetRootPipeline(aPipelineId);
|
||||
mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr, Move(api), Move(holder));
|
||||
|
@ -1631,6 +1638,12 @@ CompositorBridgeParent::DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aA
|
|||
return true;
|
||||
}
|
||||
|
||||
RefPtr<WebRenderBridgeParent>
|
||||
CompositorBridgeParent::GetWebRenderBridgeParent() const
|
||||
{
|
||||
return mWrBridge;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorBridgeParent::SetWebRenderProfilerEnabled(bool aEnabled)
|
||||
{
|
||||
|
@ -1834,12 +1847,14 @@ CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart,
|
|||
void
|
||||
CompositorBridgeParent::NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd)
|
||||
{
|
||||
if (!mWrBridge) {
|
||||
return;
|
||||
}
|
||||
mWrBridge->CompositableHolder()->Update(aPipelineId, aEpoch);
|
||||
|
||||
if (mPaused) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mWrBridge);
|
||||
|
||||
mWrBridge->CompositableHolder()->Update(aPipelineId, aEpoch);
|
||||
|
||||
if (mWrBridge->PipelineId() == aPipelineId) {
|
||||
uint64_t transactionId = mWrBridge->FlushTransactionIdsForEpoch(aEpoch);
|
||||
|
|
|
@ -199,6 +199,7 @@ public:
|
|||
const gfx::IntRect& aRect) override;
|
||||
virtual mozilla::ipc::IPCResult RecvFlushRendering() override;
|
||||
virtual mozilla::ipc::IPCResult RecvFlushRenderingAsync() override;
|
||||
virtual mozilla::ipc::IPCResult RecvWaitOnTransactionProcessed() override;
|
||||
virtual mozilla::ipc::IPCResult RecvForcePresent() override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override;
|
||||
|
@ -447,11 +448,18 @@ public:
|
|||
return mOptions;
|
||||
}
|
||||
|
||||
TimeDuration GetVsyncInterval() const {
|
||||
// the variable is called "rate" but really it's an interval
|
||||
return mVsyncRate;
|
||||
}
|
||||
|
||||
PWebRenderBridgeParent* AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
|
||||
const LayoutDeviceIntSize& aSize,
|
||||
TextureFactoryIdentifier* aTextureFactoryIdentifier,
|
||||
uint32_t* aIdNamespace) override;
|
||||
bool DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) override;
|
||||
RefPtr<WebRenderBridgeParent> GetWebRenderBridgeParent() const;
|
||||
|
||||
static void SetWebRenderProfilerEnabled(bool aEnabled);
|
||||
|
||||
static CompositorBridgeParent* GetCompositorBridgeParentFromLayersId(const uint64_t& aLayersId);
|
||||
|
|
|
@ -60,6 +60,7 @@ public:
|
|||
virtual mozilla::ipc::IPCResult RecvFlushRendering() override { return IPC_OK(); }
|
||||
virtual mozilla::ipc::IPCResult RecvFlushRenderingAsync() override { return IPC_OK(); }
|
||||
virtual mozilla::ipc::IPCResult RecvForcePresent() override { return IPC_OK(); }
|
||||
virtual mozilla::ipc::IPCResult RecvWaitOnTransactionProcessed() override { return IPC_OK(); }
|
||||
virtual mozilla::ipc::IPCResult RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override { return IPC_OK(); }
|
||||
virtual mozilla::ipc::IPCResult RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override { return IPC_OK(); }
|
||||
virtual mozilla::ipc::IPCResult RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) override { return IPC_OK(); }
|
||||
|
|
|
@ -194,6 +194,9 @@ parent:
|
|||
// synchronous repaints on resize.
|
||||
async FlushRenderingAsync();
|
||||
|
||||
// Make sure any pending composites have been received.
|
||||
sync WaitOnTransactionProcessed();
|
||||
|
||||
// Force an additional frame presentation to be executed. This is used to
|
||||
// work around a windows presentation bug (See Bug 1232042)
|
||||
async ForcePresent();
|
||||
|
|
|
@ -21,7 +21,7 @@ using mozilla::wr::ExternalImageId from "mozilla/webrender/WebRenderTypes.h";
|
|||
using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
|
||||
using mozilla::wr::FontKey from "mozilla/webrender/WebRenderTypes.h";
|
||||
using WrBuiltDisplayListDescriptor from "mozilla/webrender/webrender_ffi.h";
|
||||
using WrAuxiliaryListsDescriptor from "mozilla/webrender/webrender_ffi.h";
|
||||
using WrSize from "mozilla/webrender/webrender_ffi.h";
|
||||
using mozilla::layers::WebRenderScrollData from "mozilla/layers/WebRenderScrollData.h";
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -53,10 +53,10 @@ parent:
|
|||
async DeleteFont(FontKey aFontKey);
|
||||
async DPBegin(IntSize aSize);
|
||||
async DPEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
|
||||
ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc,
|
||||
WrSize aContentSize, ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc,
|
||||
WebRenderScrollData aScrollData);
|
||||
sync DPSyncEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
|
||||
ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc,
|
||||
WrSize aContentSize, ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc,
|
||||
WebRenderScrollData aScrollData);
|
||||
sync DPGetSnapshot(PTexture texture);
|
||||
async AddExternalImageId(ExternalImageId aImageId, CompositableHandle aHandle);
|
||||
|
|
|
@ -31,6 +31,11 @@ struct OpAddExternalImage {
|
|||
ImageKey key;
|
||||
};
|
||||
|
||||
struct OpAddExternalVideoImage {
|
||||
ExternalImageId externalImageId;
|
||||
ImageKey[] keys;
|
||||
};
|
||||
|
||||
struct OpAddCompositorAnimations {
|
||||
CompositorAnimations data;
|
||||
OptionalTransform transform;
|
||||
|
@ -39,6 +44,7 @@ struct OpAddCompositorAnimations {
|
|||
|
||||
union WebRenderParentCommand {
|
||||
OpAddExternalImage;
|
||||
OpAddExternalVideoImage;
|
||||
CompositableOperation;
|
||||
OpAddCompositorAnimations;
|
||||
};
|
||||
|
|
|
@ -202,6 +202,7 @@ EXPORTS.mozilla.layers += [
|
|||
'TextureWrapperImage.h',
|
||||
'TransactionIdAllocator.h',
|
||||
'UpdateImageHelper.h',
|
||||
'wr/ScrollingLayersHelper.h',
|
||||
'wr/StackingContextHelper.h',
|
||||
'wr/WebRenderBridgeChild.h',
|
||||
'wr/WebRenderBridgeParent.h',
|
||||
|
@ -397,6 +398,7 @@ UNIFIED_SOURCES += [
|
|||
'SourceSurfaceVolatileData.cpp',
|
||||
'TextureSourceProvider.cpp',
|
||||
'TextureWrapperImage.cpp',
|
||||
'wr/ScrollingLayersHelper.cpp',
|
||||
'wr/StackingContextHelper.cpp',
|
||||
'wr/WebRenderBridgeChild.cpp',
|
||||
'wr/WebRenderBridgeParent.cpp',
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "MacIOSurfaceTextureHostOGL.h"
|
||||
#include "mozilla/gfx/MacIOSurface.h"
|
||||
#include "mozilla/webrender/WebRenderAPI.h"
|
||||
#include "GLContextCGL.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -35,7 +36,13 @@ MacIOSurfaceTextureHostOGL::CreateTextureSourceForPlane(size_t aPlane)
|
|||
gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
|
||||
mSurface->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(gl)->GetCGLContext(), aPlane);
|
||||
gfx::SurfaceFormat readFormat = gfx::SurfaceFormat::UNKNOWN;
|
||||
mSurface->CGLTexImageIOSurface2D(gl,
|
||||
gl::GLContextCGL::Cast(gl)->GetCGLContext(),
|
||||
aPlane,
|
||||
&readFormat);
|
||||
// With compositorOGL, we doesn't support the yuv interleaving format yet.
|
||||
MOZ_ASSERT(readFormat != gfx::SurfaceFormat::YUV422);
|
||||
|
||||
return new GLTextureSource(mProvider, textureHandle, LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
gfx::IntSize(mSurface->GetDevicePixelWidth(aPlane),
|
||||
|
@ -107,70 +114,64 @@ MacIOSurfaceTextureHostOGL::gl() const
|
|||
return mProvider ? mProvider->GetGLContext() : nullptr;
|
||||
}
|
||||
|
||||
MacIOSurfaceTextureSourceOGL::MacIOSurfaceTextureSourceOGL(
|
||||
CompositorOGL* aCompositor,
|
||||
MacIOSurface* aSurface)
|
||||
: mCompositor(aCompositor)
|
||||
, mSurface(aSurface)
|
||||
{
|
||||
MOZ_ASSERT(aCompositor);
|
||||
MOZ_COUNT_CTOR(MacIOSurfaceTextureSourceOGL);
|
||||
}
|
||||
|
||||
MacIOSurfaceTextureSourceOGL::~MacIOSurfaceTextureSourceOGL()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MacIOSurfaceTextureSourceOGL);
|
||||
}
|
||||
|
||||
gfx::IntSize
|
||||
MacIOSurfaceTextureSourceOGL::GetSize() const
|
||||
{
|
||||
return gfx::IntSize(mSurface->GetDevicePixelWidth(),
|
||||
mSurface->GetDevicePixelHeight());
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat
|
||||
MacIOSurfaceTextureSourceOGL::GetFormat() const
|
||||
{
|
||||
return mSurface->HasAlpha() ? gfx::SurfaceFormat::R8G8B8A8
|
||||
: gfx::SurfaceFormat::R8G8B8X8;
|
||||
}
|
||||
|
||||
void
|
||||
MacIOSurfaceTextureSourceOGL::BindTexture(GLenum aTextureUnit,
|
||||
gfx::SamplingFilter aSamplingFilter)
|
||||
MacIOSurfaceTextureHostOGL::AddWRImage(wr::WebRenderAPI* aAPI,
|
||||
Range<const wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExtID)
|
||||
{
|
||||
gl::GLContext* gl = this->gl();
|
||||
if (!gl || !gl->MakeCurrent()) {
|
||||
NS_WARNING("Trying to bind a texture without a working GLContext");
|
||||
return;
|
||||
MOZ_ASSERT(mSurface);
|
||||
|
||||
switch (GetFormat()) {
|
||||
case gfx::SurfaceFormat::R8G8B8X8:
|
||||
case gfx::SurfaceFormat::R8G8B8A8: {
|
||||
MOZ_ASSERT(aImageKeys.length() == 1);
|
||||
MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
|
||||
wr::ImageDescriptor descriptor(GetSize(), GetFormat());
|
||||
aAPI->AddExternalImage(aImageKeys[0],
|
||||
descriptor,
|
||||
aExtID,
|
||||
WrExternalImageBufferType::TextureRectHandle,
|
||||
0);
|
||||
break;
|
||||
}
|
||||
case gfx::SurfaceFormat::YUV422: {
|
||||
// This is the special buffer format. The buffer contents could be a
|
||||
// converted RGB interleaving data or a YCbCr interleaving data depending
|
||||
// on the different platform setting. (e.g. It will be RGB at OpenGL 2.1
|
||||
// and YCbCr at OpenGL 3.1)
|
||||
MOZ_ASSERT(aImageKeys.length() == 1);
|
||||
MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
|
||||
wr::ImageDescriptor descriptor(GetSize(), gfx::SurfaceFormat::R8G8B8X8);
|
||||
aAPI->AddExternalImage(aImageKeys[0],
|
||||
descriptor,
|
||||
aExtID,
|
||||
WrExternalImageBufferType::TextureRectHandle,
|
||||
0);
|
||||
break;
|
||||
}
|
||||
case gfx::SurfaceFormat::NV12: {
|
||||
MOZ_ASSERT(aImageKeys.length() == 2);
|
||||
MOZ_ASSERT(mSurface->GetPlaneCount() == 2);
|
||||
wr::ImageDescriptor descriptor0(gfx::IntSize(mSurface->GetDevicePixelWidth(0), mSurface->GetDevicePixelHeight(0)),
|
||||
gfx::SurfaceFormat::A8);
|
||||
wr::ImageDescriptor descriptor1(gfx::IntSize(mSurface->GetDevicePixelWidth(1), mSurface->GetDevicePixelHeight(1)),
|
||||
gfx::SurfaceFormat::R8G8);
|
||||
aAPI->AddExternalImage(aImageKeys[0],
|
||||
descriptor0,
|
||||
aExtID,
|
||||
WrExternalImageBufferType::TextureRectHandle,
|
||||
0);
|
||||
aAPI->AddExternalImage(aImageKeys[1],
|
||||
descriptor1,
|
||||
aExtID,
|
||||
WrExternalImageBufferType::TextureRectHandle,
|
||||
1);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
||||
}
|
||||
}
|
||||
GLuint tex = mCompositor->GetTemporaryTexture(GetTextureTarget(), aTextureUnit);
|
||||
|
||||
gl->fActiveTexture(aTextureUnit);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, tex);
|
||||
mSurface->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(gl)->GetCGLContext());
|
||||
ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
|
||||
}
|
||||
|
||||
void
|
||||
MacIOSurfaceTextureSourceOGL::SetTextureSourceProvider(TextureSourceProvider* aProvider)
|
||||
{
|
||||
CompositorOGL* ogl = nullptr;
|
||||
if (Compositor* compositor = aProvider->AsCompositor()) {
|
||||
ogl = compositor->AsCompositorOGL();
|
||||
}
|
||||
|
||||
mCompositor = ogl;
|
||||
if (mCompositor && mNextSibling) {
|
||||
mNextSibling->SetTextureSourceProvider(aProvider);
|
||||
}
|
||||
}
|
||||
|
||||
gl::GLContext*
|
||||
MacIOSurfaceTextureSourceOGL::gl() const
|
||||
{
|
||||
return mCompositor ? mCompositor->gl() : nullptr;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -14,49 +14,6 @@ class MacIOSurface;
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
* A texture source meant for use with MacIOSurfaceTextureHostOGL.
|
||||
*
|
||||
* It does not own any GL texture, and attaches its shared handle to one of
|
||||
* the compositor's temporary textures when binding.
|
||||
*/
|
||||
class MacIOSurfaceTextureSourceOGL : public TextureSource
|
||||
, public TextureSourceOGL
|
||||
{
|
||||
public:
|
||||
MacIOSurfaceTextureSourceOGL(CompositorOGL* aCompositor,
|
||||
MacIOSurface* aSurface);
|
||||
virtual ~MacIOSurfaceTextureSourceOGL();
|
||||
|
||||
virtual const char* Name() const override { return "MacIOSurfaceTextureSourceOGL"; }
|
||||
|
||||
virtual TextureSourceOGL* AsSourceOGL() override { return this; }
|
||||
|
||||
virtual void BindTexture(GLenum activetex,
|
||||
gfx::SamplingFilter aSamplingFilter) override;
|
||||
|
||||
virtual bool IsValid() const override { return !!gl(); }
|
||||
|
||||
virtual gfx::IntSize GetSize() const override;
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override;
|
||||
|
||||
virtual GLenum GetTextureTarget() const override { return LOCAL_GL_TEXTURE_RECTANGLE_ARB; }
|
||||
|
||||
virtual GLenum GetWrapMode() const override { return LOCAL_GL_CLAMP_TO_EDGE; }
|
||||
|
||||
// MacIOSurfaceTextureSourceOGL doesn't own any gl texture
|
||||
virtual void DeallocateDeviceData() override {}
|
||||
|
||||
virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override;
|
||||
|
||||
gl::GLContext* gl() const;
|
||||
|
||||
protected:
|
||||
RefPtr<CompositorOGL> mCompositor;
|
||||
RefPtr<MacIOSurface> mSurface;
|
||||
};
|
||||
|
||||
/**
|
||||
* A TextureHost for shared MacIOSurface
|
||||
*
|
||||
|
@ -105,6 +62,10 @@ public:
|
|||
return mSurface;
|
||||
}
|
||||
|
||||
virtual void AddWRImage(wr::WebRenderAPI* aAPI,
|
||||
Range<const wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExtID) override;
|
||||
|
||||
protected:
|
||||
GLTextureSource* CreateTextureSourceForPlane(size_t aPlane);
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/layers/ScrollingLayersHelper.h"
|
||||
|
||||
#include "FrameMetrics.h"
|
||||
#include "mozilla/layers/StackingContextHelper.h"
|
||||
#include "mozilla/layers/WebRenderLayer.h"
|
||||
#include "mozilla/layers/WebRenderLayerManager.h"
|
||||
#include "mozilla/webrender/WebRenderAPI.h"
|
||||
#include "UnitTransforms.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
ScrollingLayersHelper::ScrollingLayersHelper(WebRenderLayer* aLayer,
|
||||
wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aStackingContext)
|
||||
: mLayer(aLayer)
|
||||
, mBuilder(&aBuilder)
|
||||
{
|
||||
if (!mLayer->WrManager()->AsyncPanZoomEnabled()) {
|
||||
// If APZ is disabled then we don't need to push the scrolling clips
|
||||
return;
|
||||
}
|
||||
|
||||
Layer* layer = mLayer->GetLayer();
|
||||
for (uint32_t i = layer->GetScrollMetadataCount(); i > 0; i--) {
|
||||
const FrameMetrics& fm = layer->GetFrameMetrics(i - 1);
|
||||
if (!fm.IsScrollable()) {
|
||||
return;
|
||||
}
|
||||
LayoutDeviceRect contentRect = fm.GetExpandedScrollableRect()
|
||||
* fm.GetDevPixelsPerCSSPixel();
|
||||
// TODO: check coordinate systems are sane here
|
||||
LayerRect clipBounds = ViewAs<LayerPixel>(
|
||||
fm.GetCompositionBounds(),
|
||||
PixelCastJustification::MovingDownToChildren);
|
||||
mBuilder->PushScrollLayer(fm.GetScrollId(),
|
||||
aStackingContext.ToRelativeWrRect(contentRect),
|
||||
aStackingContext.ToRelativeWrRect(clipBounds));
|
||||
}
|
||||
}
|
||||
|
||||
ScrollingLayersHelper::~ScrollingLayersHelper()
|
||||
{
|
||||
if (!mLayer->WrManager()->AsyncPanZoomEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Layer* layer = mLayer->GetLayer();
|
||||
for (int32_t i = layer->GetScrollMetadataCount(); i > 0; i--) {
|
||||
const FrameMetrics& fm = layer->GetFrameMetrics(i - 1);
|
||||
if (!fm.IsScrollable()) {
|
||||
return;
|
||||
}
|
||||
mBuilder->PopScrollLayer();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_SCROLLINGLAYERSHELPER_H
|
||||
#define GFX_SCROLLINGLAYERSHELPER_H
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace wr {
|
||||
class DisplayListBuilder;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
|
||||
class StackingContextHelper;
|
||||
class WebRenderLayer;
|
||||
|
||||
class MOZ_RAII ScrollingLayersHelper
|
||||
{
|
||||
public:
|
||||
ScrollingLayersHelper(WebRenderLayer* aLayer,
|
||||
wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aSc);
|
||||
~ScrollingLayersHelper();
|
||||
|
||||
private:
|
||||
WebRenderLayer* mLayer;
|
||||
wr::DisplayListBuilder* mBuilder;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -24,8 +24,6 @@ StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParen
|
|||
: mBuilder(&aBuilder)
|
||||
{
|
||||
WrRect scBounds = aParentSC.ToRelativeWrRect(aLayer->BoundsForStackingContext());
|
||||
mOffsetToParent.x = scBounds.x;
|
||||
mOffsetToParent.y = scBounds.y;
|
||||
Layer* layer = aLayer->GetLayer();
|
||||
mTransform = aTransform.valueOr(layer->GetTransform());
|
||||
mBuilder->PushStackingContext(scBounds,
|
||||
|
@ -44,8 +42,6 @@ StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParen
|
|||
: mBuilder(&aBuilder)
|
||||
{
|
||||
WrRect scBounds = aParentSC.ToRelativeWrRect(aLayer->BoundsForStackingContext());
|
||||
mOffsetToParent.x = scBounds.x;
|
||||
mOffsetToParent.y = scBounds.y;
|
||||
if (aTransformPtr) {
|
||||
mTransform = *aTransformPtr;
|
||||
}
|
||||
|
@ -89,10 +85,10 @@ StackingContextHelper::ToRelativeWrRectRounded(const LayoutDeviceRect& aRect) co
|
|||
}
|
||||
|
||||
gfx::Matrix4x4
|
||||
StackingContextHelper::TransformToParentSC() const
|
||||
StackingContextHelper::TransformToRoot() const
|
||||
{
|
||||
gfx::Matrix4x4 inv = mTransform.Inverse();
|
||||
inv.PostTranslate(-mOffsetToParent.x, -mOffsetToParent.y, 0);
|
||||
inv.PostTranslate(-mOrigin.x, -mOrigin.y, 0);
|
||||
return inv;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,13 +65,12 @@ public:
|
|||
WrRect ToRelativeWrRectRounded(const LayoutDeviceRect& aRect) const;
|
||||
|
||||
// Produce a transform that converts points from the coordinate space of this
|
||||
// stacking context to the coordinate space of the parent stacking context.
|
||||
gfx::Matrix4x4 TransformToParentSC() const;
|
||||
// stacking context to the coordinate space of the root of the layer tree.
|
||||
gfx::Matrix4x4 TransformToRoot() const;
|
||||
|
||||
private:
|
||||
wr::DisplayListBuilder* mBuilder;
|
||||
LayerPoint mOrigin;
|
||||
WrPoint mOffsetToParent;
|
||||
gfx::Matrix4x4 mTransform;
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
WebRenderBridgeChild::WebRenderBridgeChild(const wr::PipelineId& aPipelineId)
|
||||
: mReadLockSequenceNumber(0)
|
||||
, mIsInTransaction(false)
|
||||
|
@ -100,16 +102,17 @@ WebRenderBridgeChild::DPEnd(wr::DisplayListBuilder &aBuilder,
|
|||
MOZ_ASSERT(!mDestroyed);
|
||||
MOZ_ASSERT(mIsInTransaction);
|
||||
|
||||
wr::BuiltDisplayList dl = aBuilder.Finalize();
|
||||
wr::BuiltDisplayList dl;
|
||||
WrSize contentSize;
|
||||
aBuilder.Finalize(contentSize, dl);
|
||||
ByteBuffer dlData(Move(dl.dl));
|
||||
ByteBuffer auxData(Move(dl.aux));
|
||||
|
||||
if (aIsSync) {
|
||||
this->SendDPSyncEnd(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId,
|
||||
dlData, dl.dl_desc, auxData, dl.aux_desc, aScrollData);
|
||||
contentSize, dlData, dl.dl_desc, aScrollData);
|
||||
} else {
|
||||
this->SendDPEnd(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId,
|
||||
dlData, dl.dl_desc, auxData, dl.aux_desc, aScrollData);
|
||||
contentSize, dlData, dl.dl_desc, aScrollData);
|
||||
}
|
||||
|
||||
mParentCommands.Clear();
|
||||
|
@ -188,8 +191,6 @@ WebRenderBridgeChild::PushGlyphs(wr::DisplayListBuilder& aBuilder, const nsTArra
|
|||
WrFontKey key = GetFontKeyForScaledFont(aFont);
|
||||
MOZ_ASSERT(key.mNamespace && key.mHandle);
|
||||
|
||||
WrClipRegion clipRegion = aBuilder.BuildClipRegion(aSc.ToRelativeWrRect(aClip));
|
||||
|
||||
for (size_t i = 0; i < aGlyphs.Length(); i++) {
|
||||
GlyphArray glyph_array = aGlyphs[i];
|
||||
nsTArray<gfx::Glyph>& glyphs = glyph_array.glyphs();
|
||||
|
@ -202,6 +203,8 @@ WebRenderBridgeChild::PushGlyphs(wr::DisplayListBuilder& aBuilder, const nsTArra
|
|||
wr_glyph_instances[j].point = aSc.ToRelativeWrPoint(
|
||||
LayerPoint::FromUnknownPoint(glyphs[j].mPosition));
|
||||
}
|
||||
|
||||
WrClipRegionToken clipRegion = aBuilder.PushClipRegion(aSc.ToRelativeWrRect(aClip));
|
||||
aBuilder.PushText(aSc.ToRelativeWrRect(aBounds),
|
||||
clipRegion,
|
||||
glyph_array.color().value(),
|
||||
|
@ -323,6 +326,11 @@ WebRenderBridgeChild::AddOpDestroy(const OpDestroy& aOp)
|
|||
void
|
||||
WebRenderBridgeChild::ReleaseCompositable(const CompositableHandle& aHandle)
|
||||
{
|
||||
if (!IPCOpen()) {
|
||||
// This can happen if the IPC connection was torn down, because, e.g.
|
||||
// the GPU process died.
|
||||
return;
|
||||
}
|
||||
if (!DestroyInTransaction(aHandle)) {
|
||||
SendReleaseCompositable(aHandle);
|
||||
}
|
||||
|
|
|
@ -119,9 +119,10 @@ WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompos
|
|||
, mChildLayerObserverEpoch(0)
|
||||
, mParentLayerObserverEpoch(0)
|
||||
, mWrEpoch(0)
|
||||
, mIdNameSpace(++sIdNameSpace)
|
||||
, mIdNameSpace(AllocIdNameSpace())
|
||||
, mPaused(false)
|
||||
, mDestroyed(false)
|
||||
, mIsSnapshotting(false)
|
||||
{
|
||||
MOZ_ASSERT(mCompositableHolder);
|
||||
mCompositableHolder->AddPipeline(mPipelineId);
|
||||
|
@ -157,12 +158,10 @@ WebRenderBridgeParent::RecvCreate(const gfx::IntSize& aSize)
|
|||
mozilla::ipc::IPCResult
|
||||
WebRenderBridgeParent::RecvShutdown()
|
||||
{
|
||||
if (mDestroyed) {
|
||||
return IPC_OK();
|
||||
}
|
||||
Destroy();
|
||||
IProtocol* mgr = Manager();
|
||||
if (!Send__delete__(this)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
return IPC_FAIL_NO_REASON(mgr);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
@ -304,10 +303,9 @@ WebRenderBridgeParent::HandleDPEnd(const gfx::IntSize& aSize,
|
|||
InfallibleTArray<OpDestroy>&& aToDestroy,
|
||||
const uint64_t& aFwdTransactionId,
|
||||
const uint64_t& aTransactionId,
|
||||
const WrSize& aContentSize,
|
||||
const ByteBuffer& dl,
|
||||
const WrBuiltDisplayListDescriptor& dlDesc,
|
||||
const ByteBuffer& aux,
|
||||
const WrAuxiliaryListsDescriptor& auxDesc,
|
||||
const WebRenderScrollData& aScrollData)
|
||||
{
|
||||
UpdateFwdTransactionId(aFwdTransactionId);
|
||||
|
@ -325,45 +323,45 @@ WebRenderBridgeParent::HandleDPEnd(const gfx::IntSize& aSize,
|
|||
|
||||
++mWrEpoch; // Update webrender epoch
|
||||
ProcessWebRenderCommands(aSize, aCommands, wr::NewEpoch(mWrEpoch),
|
||||
dl, dlDesc, aux, auxDesc);
|
||||
aContentSize, dl, dlDesc);
|
||||
HoldPendingTransactionId(mWrEpoch, aTransactionId);
|
||||
|
||||
mScrollData = aScrollData;
|
||||
UpdateAPZ();
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderBridgeParent::UpdateAPZ()
|
||||
CompositorBridgeParent*
|
||||
WebRenderBridgeParent::GetRootCompositorBridgeParent() const
|
||||
{
|
||||
if (!mCompositorBridge) {
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CompositorBridgeParent* cbp;
|
||||
uint64_t rootLayersId;
|
||||
WebRenderBridgeParent* rootWrbp;
|
||||
if (mWidget) {
|
||||
// This WebRenderBridgeParent is attached to the root
|
||||
// CompositorBridgeParent.
|
||||
cbp = static_cast<CompositorBridgeParent*>(mCompositorBridge);
|
||||
rootLayersId = wr::AsUint64(mPipelineId);
|
||||
rootWrbp = this;
|
||||
} else {
|
||||
// This WebRenderBridgeParent is attached to a
|
||||
// CrossProcessCompositorBridgeParent so we have an extra level of
|
||||
// indirection to unravel.
|
||||
uint64_t layersId = wr::AsUint64(mPipelineId);
|
||||
CompositorBridgeParent::LayerTreeState* lts =
|
||||
CompositorBridgeParent::GetIndirectShadowTree(layersId);
|
||||
MOZ_ASSERT(lts);
|
||||
cbp = lts->mParent;
|
||||
rootLayersId = cbp->RootLayerTreeId();
|
||||
lts = CompositorBridgeParent::GetIndirectShadowTree(rootLayersId);
|
||||
MOZ_ASSERT(lts);
|
||||
rootWrbp = lts->mWrBridge.get();
|
||||
return static_cast<CompositorBridgeParent*>(mCompositorBridge);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(cbp);
|
||||
// Otherwise, this WebRenderBridgeParent is attached to a
|
||||
// CrossProcessCompositorBridgeParent so we have an extra level of
|
||||
// indirection to unravel.
|
||||
uint64_t layersId = wr::AsUint64(mPipelineId);
|
||||
CompositorBridgeParent::LayerTreeState* lts =
|
||||
CompositorBridgeParent::GetIndirectShadowTree(layersId);
|
||||
MOZ_ASSERT(lts);
|
||||
return lts->mParent;
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderBridgeParent::UpdateAPZ()
|
||||
{
|
||||
CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
|
||||
if (!cbp) {
|
||||
return;
|
||||
}
|
||||
uint64_t rootLayersId = cbp->RootLayerTreeId();
|
||||
RefPtr<WebRenderBridgeParent> rootWrbp = cbp->GetWebRenderBridgeParent();
|
||||
if (!rootWrbp) {
|
||||
return;
|
||||
}
|
||||
|
@ -374,6 +372,26 @@ WebRenderBridgeParent::UpdateAPZ()
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebRenderBridgeParent::PushAPZStateToWR()
|
||||
{
|
||||
CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
|
||||
if (!cbp) {
|
||||
return false;
|
||||
}
|
||||
if (RefPtr<APZCTreeManager> apzc = cbp->GetAPZCTreeManager()) {
|
||||
TimeStamp animationTime = mCompositorScheduler->GetLastComposeTime();
|
||||
TimeDuration frameInterval = cbp->GetVsyncInterval();
|
||||
// As with the non-webrender codepath in AsyncCompositionManager, we want to
|
||||
// use the timestamp for the next vsync when advancing animations.
|
||||
if (frameInterval != TimeDuration::Forever()) {
|
||||
animationTime += frameInterval;
|
||||
}
|
||||
return apzc->PushStateToWR(mApi, animationTime);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const WebRenderScrollData&
|
||||
WebRenderBridgeParent::GetScrollData() const
|
||||
{
|
||||
|
@ -387,14 +405,13 @@ WebRenderBridgeParent::RecvDPEnd(const gfx::IntSize& aSize,
|
|||
InfallibleTArray<OpDestroy>&& aToDestroy,
|
||||
const uint64_t& aFwdTransactionId,
|
||||
const uint64_t& aTransactionId,
|
||||
const WrSize& aContentSize,
|
||||
const ByteBuffer& dl,
|
||||
const WrBuiltDisplayListDescriptor& dlDesc,
|
||||
const ByteBuffer& aux,
|
||||
const WrAuxiliaryListsDescriptor& auxDesc,
|
||||
const WebRenderScrollData& aScrollData)
|
||||
{
|
||||
HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
|
||||
dl, dlDesc, aux, auxDesc, aScrollData);
|
||||
aContentSize, dl, dlDesc, aScrollData);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -404,24 +421,21 @@ WebRenderBridgeParent::RecvDPSyncEnd(const gfx::IntSize &aSize,
|
|||
InfallibleTArray<OpDestroy>&& aToDestroy,
|
||||
const uint64_t& aFwdTransactionId,
|
||||
const uint64_t& aTransactionId,
|
||||
const WrSize& aContentSize,
|
||||
const ByteBuffer& dl,
|
||||
const WrBuiltDisplayListDescriptor& dlDesc,
|
||||
const ByteBuffer& aux,
|
||||
const WrAuxiliaryListsDescriptor& auxDesc,
|
||||
const WebRenderScrollData& aScrollData)
|
||||
{
|
||||
HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
|
||||
dl, dlDesc, aux, auxDesc, aScrollData);
|
||||
aContentSize, dl, dlDesc, aScrollData);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize,
|
||||
InfallibleTArray<WebRenderParentCommand>& aCommands, const wr::Epoch& aEpoch,
|
||||
const ByteBuffer& dl,
|
||||
const WrBuiltDisplayListDescriptor& dlDesc,
|
||||
const ByteBuffer& aux,
|
||||
const WrAuxiliaryListsDescriptor& auxDesc)
|
||||
const WrSize& aContentSize, const ByteBuffer& dl,
|
||||
const WrBuiltDisplayListDescriptor& dlDesc)
|
||||
{
|
||||
mCompositableHolder->SetCompositionTime(TimeStamp::Now());
|
||||
|
||||
|
@ -430,10 +444,10 @@ WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize,
|
|||
switch (cmd.type()) {
|
||||
case WebRenderParentCommand::TOpAddExternalImage: {
|
||||
const OpAddExternalImage& op = cmd.get_OpAddExternalImage();
|
||||
wr::ImageKey key = op.key();
|
||||
Range<const wr::ImageKey> keys(&op.key(), 1);
|
||||
MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(op.externalImageId())).get());
|
||||
MOZ_ASSERT(!mActiveKeys.Get(wr::AsUint64(key), nullptr));
|
||||
mActiveKeys.Put(wr::AsUint64(key), key);
|
||||
MOZ_ASSERT(!mActiveKeys.Get(wr::AsUint64(keys[0]), nullptr));
|
||||
mActiveKeys.Put(wr::AsUint64(keys[0]), keys[0]);
|
||||
|
||||
RefPtr<WebRenderImageHost> host = mExternalImageIds.Get(wr::AsUint64(op.externalImageId()));
|
||||
if (!host) {
|
||||
|
@ -448,25 +462,7 @@ WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize,
|
|||
}
|
||||
WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost();
|
||||
if (wrTexture) {
|
||||
if (wrTexture->IsWrappingNativeHandle()) {
|
||||
// XXX only for MacIOSurface right now.
|
||||
// XXX remove the redundant codes for both native handle and yuv case.
|
||||
wr::ImageDescriptor descriptor(wrTexture->GetSize(), wrTexture->GetReadFormat());
|
||||
mApi->AddExternalImageHandle(key,
|
||||
descriptor,
|
||||
wrTexture->GetExternalImageKey());
|
||||
mCompositableHolder->HoldExternalImage(mPipelineId, aEpoch, texture->AsWebRenderTextureHost());
|
||||
} else {
|
||||
// XXX handling YUV
|
||||
gfx::SurfaceFormat format =
|
||||
wrTexture->GetFormat() == SurfaceFormat::YUV ? SurfaceFormat::B8G8R8A8 : wrTexture->GetFormat();
|
||||
wr::ImageDescriptor descriptor(wrTexture->GetSize(), wrTexture->GetRGBStride(), format);
|
||||
mApi->AddExternalImageBuffer(key,
|
||||
descriptor,
|
||||
wrTexture->GetExternalImageKey());
|
||||
mCompositableHolder->HoldExternalImage(mPipelineId, aEpoch, texture->AsWebRenderTextureHost());
|
||||
}
|
||||
|
||||
wrTexture->AddWRImage(mApi, keys, wrTexture->GetExternalImageKey());
|
||||
break;
|
||||
}
|
||||
RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
|
||||
|
@ -482,7 +478,52 @@ WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize,
|
|||
IntSize size = dSurf->GetSize();
|
||||
wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
|
||||
auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
|
||||
mApi->AddImage(key, descriptor, slice);
|
||||
mApi->AddImage(keys[0], descriptor, slice);
|
||||
|
||||
dSurf->Unmap();
|
||||
break;
|
||||
}
|
||||
case WebRenderParentCommand::TOpAddExternalVideoImage: {
|
||||
const OpAddExternalVideoImage& op = cmd.get_OpAddExternalVideoImage();
|
||||
MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(op.externalImageId())).get());
|
||||
MOZ_ASSERT(op.keys().Length() > 0);
|
||||
Range<const wr::ImageKey> keys(&(op.keys())[0], op.keys().Length());
|
||||
for (auto key : keys) {
|
||||
MOZ_ASSERT(!mActiveKeys.Get(wr::AsUint64(key), nullptr));
|
||||
mActiveKeys.Put(wr::AsUint64(key), key);
|
||||
}
|
||||
|
||||
RefPtr<WebRenderImageHost> host = mExternalImageIds.Get(wr::AsUint64(op.externalImageId()));
|
||||
if (!host) {
|
||||
NS_ERROR("CompositableHost does not exist");
|
||||
break;
|
||||
}
|
||||
// XXX select Texture for video in CompositeToTarget().
|
||||
TextureHost* texture = host->GetAsTextureHostForComposite();
|
||||
if (!texture) {
|
||||
NS_ERROR("TextureHost does not exist");
|
||||
break;
|
||||
}
|
||||
WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost();
|
||||
if (wrTexture) {
|
||||
wrTexture->AddWRImage(mApi, keys, wrTexture->GetExternalImageKey());
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(keys.length() == 1);
|
||||
RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
|
||||
if (!dSurf) {
|
||||
break;
|
||||
}
|
||||
DataSourceSurface::MappedSurface map;
|
||||
if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
|
||||
break;
|
||||
}
|
||||
|
||||
IntSize size = dSurf->GetSize();
|
||||
wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
|
||||
auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
|
||||
mApi->AddImage(keys[0], descriptor, slice);
|
||||
|
||||
dSurf->Unmap();
|
||||
break;
|
||||
|
@ -526,9 +567,8 @@ WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize,
|
|||
mApi->SetWindowParameters(size);
|
||||
}
|
||||
mApi->SetRootDisplayList(gfx::Color(0.3f, 0.f, 0.f, 1.f), aEpoch, LayerSize(aSize.width, aSize.height),
|
||||
mPipelineId,
|
||||
dlDesc, dl.mData, dl.mLength,
|
||||
auxDesc, aux.mData, aux.mLength);
|
||||
mPipelineId, aContentSize,
|
||||
dlDesc, dl.mData, dl.mLength);
|
||||
|
||||
ScheduleComposition();
|
||||
DeleteOldImages();
|
||||
|
@ -577,6 +617,8 @@ WebRenderBridgeParent::RecvDPGetSnapshot(PTextureParent* aTexture)
|
|||
// Assert the stride of the buffer is what webrender expects
|
||||
MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
|
||||
|
||||
mIsSnapshotting = true;
|
||||
|
||||
if (mCompositorScheduler->NeedsComposite()) {
|
||||
mCompositorScheduler->CancelCurrentCompositeTask();
|
||||
mCompositorScheduler->ForceComposeToTarget(nullptr, nullptr);
|
||||
|
@ -584,6 +626,8 @@ WebRenderBridgeParent::RecvDPGetSnapshot(PTextureParent* aTexture)
|
|||
|
||||
mApi->Readback(size, buffer, buffer_size);
|
||||
|
||||
mIsSnapshotting = false;
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -613,7 +657,7 @@ WebRenderBridgeParent::RecvAddExternalImageId(const ExternalImageId& aImageId,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
wrHost->SetWrCompositableHolder(mCompositableHolder);
|
||||
wrHost->SetWrBridge(this);
|
||||
mExternalImageIds.Put(wr::AsUint64(aImageId), wrHost);
|
||||
|
||||
return IPC_OK();
|
||||
|
@ -636,7 +680,7 @@ WebRenderBridgeParent::RecvAddExternalImageIdForCompositable(const ExternalImage
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
wrHost->SetWrCompositableHolder(mCompositableHolder);
|
||||
wrHost->SetWrBridge(this);
|
||||
mExternalImageIds.Put(wr::AsUint64(aImageId), wrHost);
|
||||
|
||||
return IPC_OK();
|
||||
|
@ -651,7 +695,7 @@ WebRenderBridgeParent::RecvRemoveExternalImageId(const ExternalImageId& aImageId
|
|||
MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(aImageId)).get());
|
||||
WebRenderImageHost* wrHost = mExternalImageIds.Get(wr::AsUint64(aImageId)).get();
|
||||
if (wrHost) {
|
||||
wrHost->SetWrCompositableHolder(nullptr);
|
||||
wrHost->ClearWrBridge();
|
||||
}
|
||||
mExternalImageIds.Remove(wr::AsUint64(aImageId));
|
||||
|
||||
|
@ -723,6 +767,19 @@ WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::In
|
|||
return;
|
||||
}
|
||||
|
||||
const uint32_t maxPendingFrameCount = 2;
|
||||
|
||||
if (!mIsSnapshotting &&
|
||||
wr::RenderThread::Get()->GetPendingFrameCount(mApi->GetId()) > maxPendingFrameCount) {
|
||||
// Render thread is busy, try next time.
|
||||
ScheduleComposition();
|
||||
return;
|
||||
}
|
||||
|
||||
if (PushAPZStateToWR()) {
|
||||
ScheduleComposition();
|
||||
}
|
||||
|
||||
if (gfxPrefs::WebRenderOMTAEnabled()) {
|
||||
nsTArray<WrOpacityProperty> opacityArray;
|
||||
nsTArray<WrTransformProperty> transformArray;
|
||||
|
@ -847,26 +904,26 @@ WebRenderBridgeParent::Resume()
|
|||
void
|
||||
WebRenderBridgeParent::ClearResources()
|
||||
{
|
||||
if (mApi) {
|
||||
++mWrEpoch; // Update webrender epoch
|
||||
mApi->ClearRootDisplayList(wr::NewEpoch(mWrEpoch), mPipelineId);
|
||||
for (auto iter = mActiveKeys.Iter(); !iter.Done(); iter.Next()) {
|
||||
mKeysToDelete.push_back(iter.Data());
|
||||
iter.Remove();
|
||||
}
|
||||
if (!mKeysToDelete.empty()) {
|
||||
// XXX Sync wait.
|
||||
mApi->WaitFlushed();
|
||||
DeleteOldImages();
|
||||
}
|
||||
if (!mApi) {
|
||||
return;
|
||||
}
|
||||
mCompositableHolder->RemovePipeline(mPipelineId);
|
||||
|
||||
++mWrEpoch; // Update webrender epoch
|
||||
mApi->ClearRootDisplayList(wr::NewEpoch(mWrEpoch), mPipelineId);
|
||||
// Schedule composition to clean up Pipeline
|
||||
mCompositorScheduler->ScheduleComposition();
|
||||
for (auto iter = mActiveKeys.Iter(); !iter.Done(); iter.Next()) {
|
||||
mKeysToDelete.push_back(iter.Data());
|
||||
iter.Remove();
|
||||
}
|
||||
DeleteOldImages();
|
||||
for (auto iter = mExternalImageIds.Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.Data()->SetWrCompositableHolder(nullptr);
|
||||
iter.Data()->ClearWrBridge();
|
||||
}
|
||||
mExternalImageIds.Clear();
|
||||
mCompositableHolder->RemovePipeline(mPipelineId, wr::NewEpoch(mWrEpoch));
|
||||
|
||||
if (mWidget && mCompositorScheduler) {
|
||||
if (mWidget) {
|
||||
mCompositorScheduler->Destroy();
|
||||
}
|
||||
mCompositorScheduler = nullptr;
|
||||
|
|
|
@ -53,6 +53,7 @@ public:
|
|||
|
||||
wr::PipelineId PipelineId() { return mPipelineId; }
|
||||
wr::WebRenderAPI* GetWebRenderAPI() { return mApi; }
|
||||
wr::Epoch WrEpoch() { return wr::NewEpoch(mWrEpoch); }
|
||||
WebRenderCompositableHolder* CompositableHolder() { return mCompositableHolder; }
|
||||
CompositorVsyncScheduler* CompositorScheduler() { return mCompositorScheduler.get(); }
|
||||
|
||||
|
@ -90,20 +91,18 @@ public:
|
|||
InfallibleTArray<OpDestroy>&& aToDestroy,
|
||||
const uint64_t& aFwdTransactionId,
|
||||
const uint64_t& aTransactionId,
|
||||
const WrSize& aContentSize,
|
||||
const ByteBuffer& dl,
|
||||
const WrBuiltDisplayListDescriptor& dlDesc,
|
||||
const ByteBuffer& aux,
|
||||
const WrAuxiliaryListsDescriptor& auxDesc,
|
||||
const WebRenderScrollData& aScrollData) override;
|
||||
mozilla::ipc::IPCResult RecvDPSyncEnd(const gfx::IntSize& aSize,
|
||||
InfallibleTArray<WebRenderParentCommand>&& aCommands,
|
||||
InfallibleTArray<OpDestroy>&& aToDestroy,
|
||||
const uint64_t& aFwdTransactionId,
|
||||
const uint64_t& aTransactionId,
|
||||
const WrSize& aContentSize,
|
||||
const ByteBuffer& dl,
|
||||
const WrBuiltDisplayListDescriptor& dlDesc,
|
||||
const ByteBuffer& aux,
|
||||
const WrAuxiliaryListsDescriptor& auxDesc,
|
||||
const WebRenderScrollData& aScrollData) override;
|
||||
mozilla::ipc::IPCResult RecvDPGetSnapshot(PTextureParent* aTexture) override;
|
||||
|
||||
|
@ -165,15 +164,20 @@ public:
|
|||
void UpdateAPZ();
|
||||
const WebRenderScrollData& GetScrollData() const;
|
||||
|
||||
static uint32_t AllocIdNameSpace() {
|
||||
return ++sIdNameSpace;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~WebRenderBridgeParent();
|
||||
|
||||
void DeleteOldImages();
|
||||
void ProcessWebRenderCommands(const gfx::IntSize &aSize, InfallibleTArray<WebRenderParentCommand>& commands, const wr::Epoch& aEpoch,
|
||||
const ByteBuffer& dl,
|
||||
const WrBuiltDisplayListDescriptor& dlDesc,
|
||||
const ByteBuffer& aux,
|
||||
const WrAuxiliaryListsDescriptor& auxDesc);
|
||||
void ProcessWebRenderCommands(const gfx::IntSize &aSize,
|
||||
InfallibleTArray<WebRenderParentCommand>& commands,
|
||||
const wr::Epoch& aEpoch,
|
||||
const WrSize& aContentSize,
|
||||
const ByteBuffer& dl,
|
||||
const WrBuiltDisplayListDescriptor& dlDesc);
|
||||
void ScheduleComposition();
|
||||
void ClearResources();
|
||||
uint64_t GetChildLayerObserverEpoch() const { return mChildLayerObserverEpoch; }
|
||||
|
@ -183,15 +187,20 @@ private:
|
|||
InfallibleTArray<OpDestroy>&& aToDestroy,
|
||||
const uint64_t& aFwdTransactionId,
|
||||
const uint64_t& aTransactionId,
|
||||
const WrSize& aContentSize,
|
||||
const ByteBuffer& dl,
|
||||
const WrBuiltDisplayListDescriptor& dlDesc,
|
||||
const ByteBuffer& aux,
|
||||
const WrAuxiliaryListsDescriptor& auxDesc,
|
||||
const WebRenderScrollData& aScrollData);
|
||||
|
||||
void SampleAnimations(nsTArray<WrOpacityProperty>& aOpacityArray,
|
||||
nsTArray<WrTransformProperty>& aTransformArray);
|
||||
|
||||
CompositorBridgeParent* GetRootCompositorBridgeParent() const;
|
||||
|
||||
// Have APZ push the async scroll state to WR. Returns true if an APZ
|
||||
// animation is in effect and we need to schedule another composition.
|
||||
bool PushAPZStateToWR();
|
||||
|
||||
private:
|
||||
struct PendingTransactionId {
|
||||
PendingTransactionId(wr::Epoch aEpoch, uint64_t aId)
|
||||
|
@ -227,6 +236,7 @@ private:
|
|||
|
||||
bool mPaused;
|
||||
bool mDestroyed;
|
||||
bool mIsSnapshotting;
|
||||
|
||||
// Can only be accessed on the compositor thread.
|
||||
WebRenderScrollData mScrollData;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "GLScreenBuffer.h"
|
||||
#include "LayersLogging.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/layers/ScrollingLayersHelper.h"
|
||||
#include "mozilla/layers/StackingContextHelper.h"
|
||||
#include "mozilla/layers/TextureClientSharedSurface.h"
|
||||
#include "mozilla/layers/WebRenderBridgeChild.h"
|
||||
|
@ -62,6 +63,7 @@ WebRenderCanvasLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
transform = Some(GetTransform().PreTranslate(0, mBounds.height, 0).PreScale(1, -1, 1));
|
||||
}
|
||||
|
||||
ScrollingLayersHelper scroller(this, aBuilder, aSc);
|
||||
StackingContextHelper sc(aSc, aBuilder, this, transform);
|
||||
|
||||
LayerRect rect(0, 0, mBounds.width, mBounds.height);
|
||||
|
@ -69,7 +71,7 @@ WebRenderCanvasLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
|
||||
LayerRect clipRect = ClipRect().valueOr(rect);
|
||||
Maybe<WrImageMask> mask = BuildWrMaskLayer(&sc);
|
||||
WrClipRegion clip = aBuilder.BuildClipRegion(
|
||||
WrClipRegionToken clip = aBuilder.PushClipRegion(
|
||||
sc.ToRelativeWrRect(clipRect),
|
||||
mask.ptrOr(nullptr));
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "LayersLogging.h"
|
||||
#include "mozilla/webrender/webrender_ffi.h"
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
#include "mozilla/layers/ScrollingLayersHelper.h"
|
||||
#include "mozilla/layers/StackingContextHelper.h"
|
||||
#include "mozilla/layers/WebRenderBridgeChild.h"
|
||||
|
||||
|
@ -21,6 +22,7 @@ void
|
|||
WebRenderColorLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aSc)
|
||||
{
|
||||
ScrollingLayersHelper scroller(this, aBuilder, aSc);
|
||||
StackingContextHelper sc(aSc, aBuilder, this);
|
||||
|
||||
LayerRect rect = Bounds();
|
||||
|
@ -28,7 +30,7 @@ WebRenderColorLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
|
||||
LayerRect clipRect = ClipRect().valueOr(rect);
|
||||
Maybe<WrImageMask> mask = BuildWrMaskLayer(&sc);
|
||||
WrClipRegion clip = aBuilder.BuildClipRegion(
|
||||
WrClipRegionToken clip = aBuilder.PushClipRegion(
|
||||
sc.ToRelativeWrRect(clipRect),
|
||||
mask.ptrOr(nullptr));
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "CompositableHost.h"
|
||||
#include "mozilla/layers/WebRenderImageHost.h"
|
||||
#include "mozilla/layers/WebRenderTextureHost.h"
|
||||
#include "mozilla/webrender/WebRenderAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -15,7 +16,9 @@ using namespace gfx;
|
|||
|
||||
namespace layers {
|
||||
|
||||
WebRenderCompositableHolder::WebRenderCompositableHolder()
|
||||
WebRenderCompositableHolder::WebRenderCompositableHolder(uint32_t aIdNamespace)
|
||||
: mIdNamespace(aIdNamespace)
|
||||
, mResourceId(0)
|
||||
{
|
||||
MOZ_COUNT_CTOR(WebRenderCompositableHolder);
|
||||
}
|
||||
|
@ -23,7 +26,6 @@ WebRenderCompositableHolder::WebRenderCompositableHolder()
|
|||
WebRenderCompositableHolder::~WebRenderCompositableHolder()
|
||||
{
|
||||
MOZ_COUNT_DTOR(WebRenderCompositableHolder);
|
||||
MOZ_ASSERT(mPipelineTexturesHolders.IsEmpty());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -37,18 +39,22 @@ WebRenderCompositableHolder::AddPipeline(const wr::PipelineId& aPipelineId)
|
|||
}
|
||||
|
||||
void
|
||||
WebRenderCompositableHolder::RemovePipeline(const wr::PipelineId& aPipelineId)
|
||||
WebRenderCompositableHolder::RemovePipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch)
|
||||
{
|
||||
uint64_t id = wr::AsUint64(aPipelineId);
|
||||
if (mPipelineTexturesHolders.Get(id)) {
|
||||
mPipelineTexturesHolders.Remove(id);
|
||||
PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
|
||||
MOZ_ASSERT(holder);
|
||||
if (!holder) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(holder->mDestroyedEpoch.isNothing());
|
||||
holder->mDestroyedEpoch = Some(aEpoch);
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderCompositableHolder::HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture)
|
||||
{
|
||||
MOZ_ASSERT(aTexture);
|
||||
|
||||
PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
|
||||
MOZ_ASSERT(holder);
|
||||
if (!holder) {
|
||||
|
@ -62,10 +68,17 @@ void
|
|||
WebRenderCompositableHolder::Update(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch)
|
||||
{
|
||||
PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
|
||||
if (!holder || holder->mTextureHosts.empty()) {
|
||||
if (!holder) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove Pipeline
|
||||
if (holder->mDestroyedEpoch.isSome() && holder->mDestroyedEpoch.ref() <= aEpoch) {
|
||||
mPipelineTexturesHolders.Remove(wr::AsUint64(aPipelineId));
|
||||
return;
|
||||
}
|
||||
|
||||
// Release TextureHosts based on Epoch
|
||||
while (!holder->mTextureHosts.empty()) {
|
||||
if (aEpoch <= holder->mTextureHosts.front().mEpoch) {
|
||||
break;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <queue>
|
||||
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
|
@ -28,14 +29,14 @@ class WebRenderCompositableHolder final
|
|||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebRenderCompositableHolder)
|
||||
|
||||
explicit WebRenderCompositableHolder();
|
||||
explicit WebRenderCompositableHolder(uint32_t aIdNamespace);
|
||||
|
||||
protected:
|
||||
~WebRenderCompositableHolder();
|
||||
|
||||
public:
|
||||
void AddPipeline(const wr::PipelineId& aPipelineId);
|
||||
void RemovePipeline(const wr::PipelineId& aPipelineId);
|
||||
void RemovePipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch);
|
||||
void HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture);
|
||||
void Update(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch);
|
||||
|
||||
|
@ -59,6 +60,16 @@ public:
|
|||
return mCompositeUntilTime;
|
||||
}
|
||||
|
||||
uint32_t GetNextResourceId() { return ++mResourceId; }
|
||||
uint32_t GetNamespace() { return mIdNamespace; }
|
||||
wr::ImageKey GetImageKey()
|
||||
{
|
||||
wr::ImageKey key;
|
||||
key.mNamespace = GetNamespace();
|
||||
key.mHandle = GetNextResourceId();
|
||||
return key;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct ForwardingTextureHost {
|
||||
|
@ -73,8 +84,11 @@ private:
|
|||
struct PipelineTexturesHolder {
|
||||
// Holds forwarding WebRenderTextureHosts.
|
||||
std::queue<ForwardingTextureHost> mTextureHosts;
|
||||
Maybe<wr::Epoch> mDestroyedEpoch;
|
||||
};
|
||||
|
||||
uint32_t mIdNamespace;
|
||||
uint32_t mResourceId;
|
||||
nsClassHashtable<nsUint64HashKey, PipelineTexturesHolder> mPipelineTexturesHolders;
|
||||
|
||||
// Render time for the current composition.
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <inttypes.h>
|
||||
#include "gfxPrefs.h"
|
||||
#include "LayersLogging.h"
|
||||
#include "mozilla/layers/ScrollingLayersHelper.h"
|
||||
#include "mozilla/layers/StackingContextHelper.h"
|
||||
#include "mozilla/layers/WebRenderBridgeChild.h"
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
|
@ -89,6 +90,7 @@ WebRenderContainerLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
WrBridge()->AddWebRenderParentCommand(anim);
|
||||
}
|
||||
|
||||
ScrollingLayersHelper scroller(this, aBuilder, aSc);
|
||||
StackingContextHelper sc(aSc, aBuilder, this, animationsId, opacityForSC, transformForSC);
|
||||
|
||||
LayerRect rect = Bounds();
|
||||
|
@ -110,6 +112,8 @@ void
|
|||
WebRenderRefLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aSc)
|
||||
{
|
||||
ScrollingLayersHelper scroller(this, aBuilder, aSc);
|
||||
|
||||
ParentLayerRect bounds = GetLocalTransformTyped().TransformBounds(Bounds());
|
||||
// As with WebRenderTextLayer, because we don't push a stacking context for
|
||||
// this layer, WR doesn't know about the transform on this layer. Therefore
|
||||
|
@ -121,7 +125,7 @@ WebRenderRefLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
PixelCastJustification::MovingDownToChildren);
|
||||
DumpLayerInfo("RefLayer", rect);
|
||||
|
||||
WrClipRegion clipRegion = aBuilder.BuildClipRegion(aSc.ToRelativeWrRect(rect));
|
||||
WrClipRegionToken clipRegion = aBuilder.PushClipRegion(aSc.ToRelativeWrRect(rect));
|
||||
aBuilder.PushIFrame(aSc.ToRelativeWrRect(rect), clipRegion, wr::AsPipelineId(mId));
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "LayersLogging.h"
|
||||
#include "mozilla/webrender/webrender_ffi.h"
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
#include "mozilla/layers/ScrollingLayersHelper.h"
|
||||
#include "mozilla/layers/StackingContextHelper.h"
|
||||
#include "mozilla/layers/WebRenderBridgeChild.h"
|
||||
#include "nsDisplayList.h"
|
||||
|
@ -37,35 +38,41 @@ WebRenderDisplayItemLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
return;
|
||||
}
|
||||
|
||||
ScrollingLayersHelper scroller(this, aBuilder, aSc);
|
||||
|
||||
Maybe<WrImageMask> mask = BuildWrMaskLayer(nullptr);
|
||||
WrImageMask* imageMask = mask.ptrOr(nullptr);
|
||||
if (imageMask) {
|
||||
ParentLayerRect clip = GetLocalTransformTyped().TransformBounds(Bounds());
|
||||
// As with WebRenderTextLayer, I'm not 100% sure this is correct, but I
|
||||
// think it is. Because we don't push a stacking context for this layer,
|
||||
// WR doesn't know about the transform on this layer. The display items
|
||||
// that we push as part of this layer already take the transform into
|
||||
// account. When we set the clip rect we also need to explicitly apply
|
||||
// the transform to make sure it gets taken into account.
|
||||
// In a sense this is the opposite of what WebRenderLayer::ClipRect() does,
|
||||
// because there we remove the transform from the clip rect to bring it
|
||||
// into the coordinate space of the local stacking context, but here we
|
||||
// need to apply the transform to the bounds to take it into the coordinate
|
||||
// space of the enclosing stacking context.
|
||||
// The conversion from ParentLayerPixel to LayerPixel below is a result of
|
||||
// changing the reference layer from "this layer" to the "the layer that
|
||||
// created aSc".
|
||||
LayerRect clipInParentLayerSpace = ViewAs<LayerPixel>(clip,
|
||||
PixelCastJustification::MovingDownToChildren);
|
||||
aBuilder.PushClip(aSc.ToRelativeWrRect(clipInParentLayerSpace), imageMask);
|
||||
|
||||
ParentLayerRect clip = GetLocalTransformTyped().TransformBounds(Bounds());
|
||||
if (GetClipRect()) {
|
||||
clip = ParentLayerRect(GetClipRect().ref());
|
||||
}
|
||||
|
||||
// As with WebRenderTextLayer, I'm not 100% sure this is correct, but I
|
||||
// think it is. Because we don't push a stacking context for this layer,
|
||||
// WR doesn't know about the transform on this layer. The display items
|
||||
// that we push as part of this layer already take the transform into
|
||||
// account. When we set the clip rect we also need to explicitly apply
|
||||
// the transform to make sure it gets taken into account.
|
||||
// In a sense this is the opposite of what WebRenderLayer::ClipRect() does,
|
||||
// because there we remove the transform from the clip rect to bring it
|
||||
// into the coordinate space of the local stacking context, but here we
|
||||
// need to apply the transform to the bounds to take it into the coordinate
|
||||
// space of the enclosing stacking context.
|
||||
// The conversion from ParentLayerPixel to LayerPixel below is a result of
|
||||
// changing the reference layer from "this layer" to the "the layer that
|
||||
// created aSc".
|
||||
LayerRect clipInParentLayerSpace = ViewAs<LayerPixel>(clip,
|
||||
PixelCastJustification::MovingDownToChildren);
|
||||
aBuilder.PushClip(aSc.ToRelativeWrRect(clipInParentLayerSpace), imageMask);
|
||||
|
||||
if (mItem) {
|
||||
wr::DisplayListBuilder builder(WrBridge()->GetPipeline());
|
||||
WrSize contentSize; // this won't actually be used by anything
|
||||
wr::DisplayListBuilder builder(WrBridge()->GetPipeline(), contentSize);
|
||||
// We might have recycled this layer. Throw away the old commands.
|
||||
mParentCommands.Clear();
|
||||
mItem->CreateWebRenderCommands(builder, aSc, mParentCommands, this);
|
||||
mBuiltDisplayList = builder.Finalize();
|
||||
builder.Finalize(contentSize, mBuiltDisplayList);
|
||||
} else {
|
||||
// else we have an empty transaction and just use the
|
||||
// old commands.
|
||||
|
@ -83,9 +90,7 @@ WebRenderDisplayItemLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
aBuilder.PushBuiltDisplayList(Move(mBuiltDisplayList));
|
||||
WrBridge()->AddWebRenderParentCommands(mParentCommands);
|
||||
|
||||
if (imageMask) {
|
||||
aBuilder.PopClip();
|
||||
}
|
||||
aBuilder.PopClip();
|
||||
}
|
||||
|
||||
Maybe<wr::ImageKey>
|
||||
|
@ -166,7 +171,7 @@ WebRenderDisplayItemLayer::PushItemAsBlobImage(wr::DisplayListBuilder& aBuilder,
|
|||
MOZ_ASSERT(ok);
|
||||
|
||||
WrRect dest = aSc.ToRelativeWrRect(imageRect + offset);
|
||||
WrClipRegion clipRegion = aBuilder.BuildClipRegion(dest);
|
||||
WrClipRegionToken clipRegion = aBuilder.PushClipRegion(dest);
|
||||
WrImageKey key = GetImageKey();
|
||||
WrBridge()->SendAddBlobImage(key, imageSize.ToUnknownSize(), imageSize.width * 4, dt->GetFormat(), bytes);
|
||||
WrManager()->AddImageKeyForDiscard(key);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "mozilla/layers/Compositor.h" // for Compositor
|
||||
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
|
||||
#include "mozilla/layers/LayerManagerComposite.h" // for TexturedEffect, Effect, etc
|
||||
#include "mozilla/layers/WebRenderBridgeParent.h"
|
||||
#include "mozilla/layers/WebRenderCompositableHolder.h"
|
||||
#include "nsAString.h"
|
||||
#include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
|
||||
|
@ -26,12 +27,13 @@ class ISurfaceAllocator;
|
|||
WebRenderImageHost::WebRenderImageHost(const TextureInfo& aTextureInfo)
|
||||
: CompositableHost(aTextureInfo)
|
||||
, ImageComposite()
|
||||
, mWrCompositableHolder(nullptr)
|
||||
, mWrBridge(nullptr)
|
||||
, mWrBridgeBindings(0)
|
||||
{}
|
||||
|
||||
WebRenderImageHost::~WebRenderImageHost()
|
||||
{
|
||||
MOZ_ASSERT(!mWrCompositableHolder);
|
||||
MOZ_ASSERT(!mWrBridge);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -70,12 +72,13 @@ WebRenderImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
|
|||
// slightly different timestamps in order to sync with the audio clock. This
|
||||
// means that any CompositeUntil() call we made in Composite() may no longer
|
||||
// guarantee that we'll composite until the next frame is ready. Fix that here.
|
||||
if (mWrCompositableHolder && mLastFrameID >= 0) {
|
||||
if (mWrBridge && mLastFrameID >= 0) {
|
||||
MOZ_ASSERT(mWrBridge->CompositableHolder());
|
||||
for (size_t i = 0; i < mImages.Length(); ++i) {
|
||||
bool frameComesAfter = mImages[i].mFrameID > mLastFrameID ||
|
||||
mImages[i].mProducerID != mLastProducerID;
|
||||
if (frameComesAfter && !mImages[i].mTimeStamp.IsNull()) {
|
||||
mWrCompositableHolder->CompositeUntil(mImages[i].mTimeStamp +
|
||||
mWrBridge->CompositableHolder()->CompositeUntil(mImages[i].mTimeStamp +
|
||||
TimeDuration::FromMilliseconds(BIAS_TIME_MS));
|
||||
break;
|
||||
}
|
||||
|
@ -96,6 +99,7 @@ WebRenderImageHost::CleanupResources()
|
|||
nsTArray<TimedImage> newImages;
|
||||
mImages.SwapElements(newImages);
|
||||
newImages.Clear();
|
||||
SetCurrentTextureHost(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -115,8 +119,9 @@ TimeStamp
|
|||
WebRenderImageHost::GetCompositionTime() const
|
||||
{
|
||||
TimeStamp time;
|
||||
if (mWrCompositableHolder) {
|
||||
time = mWrCompositableHolder->GetCompositionTime();
|
||||
if (mWrBridge) {
|
||||
MOZ_ASSERT(mWrBridge->CompositableHolder());
|
||||
time = mWrBridge->CompositableHolder()->GetCompositionTime();
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
@ -136,11 +141,13 @@ WebRenderImageHost::GetAsTextureHostForComposite()
|
|||
{
|
||||
int imageIndex = ChooseImageIndex();
|
||||
if (imageIndex < 0) {
|
||||
SetCurrentTextureHost(nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mWrCompositableHolder && uint32_t(imageIndex) + 1 < mImages.Length()) {
|
||||
mWrCompositableHolder->CompositeUntil(mImages[imageIndex + 1].mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
|
||||
if (mWrBridge && uint32_t(imageIndex) + 1 < mImages.Length()) {
|
||||
MOZ_ASSERT(mWrBridge->CompositableHolder());
|
||||
mWrBridge->CompositableHolder()->CompositeUntil(mImages[imageIndex + 1].mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
|
||||
}
|
||||
|
||||
TimedImage* img = &mImages[imageIndex];
|
||||
|
@ -149,7 +156,31 @@ WebRenderImageHost::GetAsTextureHostForComposite()
|
|||
mLastFrameID = img->mFrameID;
|
||||
mLastProducerID = img->mProducerID;
|
||||
}
|
||||
return img->mTextureHost;
|
||||
SetCurrentTextureHost(img->mTextureHost);
|
||||
return mCurrentTextureHost;
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderImageHost::SetCurrentTextureHost(TextureHost* aTexture)
|
||||
{
|
||||
if (aTexture == mCurrentTextureHost.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWrBridge &&
|
||||
!!mCurrentTextureHost &&
|
||||
mCurrentTextureHost != aTexture &&
|
||||
mCurrentTextureHost->AsWebRenderTextureHost()) {
|
||||
MOZ_ASSERT(mWrBridge->CompositableHolder());
|
||||
wr::PipelineId piplineId = mWrBridge->PipelineId();
|
||||
wr::Epoch epoch = mWrBridge->WrEpoch();
|
||||
mWrBridge->CompositableHolder()->HoldExternalImage(
|
||||
piplineId,
|
||||
epoch,
|
||||
mCurrentTextureHost->AsWebRenderTextureHost());
|
||||
}
|
||||
|
||||
mCurrentTextureHost = aTexture;
|
||||
}
|
||||
|
||||
void WebRenderImageHost::Attach(Layer* aLayer,
|
||||
|
@ -246,5 +277,29 @@ WebRenderImageHost::GetImageSize() const
|
|||
return IntSize();
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderImageHost::SetWrBridge(WebRenderBridgeParent* aWrBridge)
|
||||
{
|
||||
// For image hosts created through ImageBridgeParent, there may be multiple
|
||||
// references to it due to the order of creation and freeing of layers by
|
||||
// the layer tree. However this should be limited to things such as video
|
||||
// which will not be reused across different WebRenderBridgeParent objects.
|
||||
MOZ_ASSERT(aWrBridge);
|
||||
MOZ_ASSERT(!mWrBridge || mWrBridge == aWrBridge);
|
||||
mWrBridge = aWrBridge;
|
||||
++mWrBridgeBindings;
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderImageHost::ClearWrBridge()
|
||||
{
|
||||
MOZ_ASSERT(mWrBridgeBindings > 0);
|
||||
--mWrBridgeBindings;
|
||||
if (mWrBridgeBindings == 0) {
|
||||
SetCurrentTextureHost(nullptr);
|
||||
mWrBridge = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class WebRenderCompositableHolder;
|
||||
class WebRenderBridgeParent;
|
||||
|
||||
/**
|
||||
* ImageHost. Works with ImageClientSingle and ImageClientBuffered
|
||||
|
@ -69,16 +69,21 @@ public:
|
|||
|
||||
TextureHost* GetAsTextureHostForComposite();
|
||||
|
||||
void SetWrCompositableHolder(WebRenderCompositableHolder* aWrCompositableHolder)
|
||||
{
|
||||
mWrCompositableHolder = aWrCompositableHolder;
|
||||
}
|
||||
void SetWrBridge(WebRenderBridgeParent* aWrBridge);
|
||||
|
||||
void ClearWrBridge();
|
||||
|
||||
protected:
|
||||
// ImageComposite
|
||||
virtual TimeStamp GetCompositionTime() const override;
|
||||
|
||||
WebRenderCompositableHolder* MOZ_NON_OWNING_REF mWrCompositableHolder;
|
||||
void SetCurrentTextureHost(TextureHost* aTexture);
|
||||
|
||||
WebRenderBridgeParent* MOZ_NON_OWNING_REF mWrBridge;
|
||||
|
||||
uint32_t mWrBridgeBindings;
|
||||
|
||||
CompositableTextureHostRef mCurrentTextureHost;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
|
||||
#include "gfxPrefs.h"
|
||||
#include "LayersLogging.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/layers/ImageClient.h"
|
||||
#include "mozilla/layers/ScrollingLayersHelper.h"
|
||||
#include "mozilla/layers/StackingContextHelper.h"
|
||||
#include "mozilla/layers/TextureClientRecycleAllocator.h"
|
||||
#include "mozilla/layers/TextureWrapperImage.h"
|
||||
|
@ -30,9 +32,14 @@ WebRenderImageLayer::~WebRenderImageLayer()
|
|||
{
|
||||
MOZ_COUNT_DTOR(WebRenderImageLayer);
|
||||
mPipelineIdRequest.DisconnectIfExists();
|
||||
|
||||
for (auto key : mVideoKeys) {
|
||||
WrManager()->AddImageKeyForDiscard(key);
|
||||
}
|
||||
if (mKey.isSome()) {
|
||||
WrManager()->AddImageKeyForDiscard(mKey.value());
|
||||
}
|
||||
|
||||
if (mExternalImageId.isSome()) {
|
||||
WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
|
||||
}
|
||||
|
@ -83,6 +90,17 @@ WebRenderImageLayer::ClearCachedResources()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderImageLayer::AddWRVideoImage(size_t aChannelNumber)
|
||||
{
|
||||
for (size_t i = 0; i < aChannelNumber; ++i) {
|
||||
WrImageKey key = GetImageKey();
|
||||
WrManager()->AddImageKeyForDiscard(key);
|
||||
mVideoKeys.AppendElement(key);
|
||||
}
|
||||
WrBridge()->AddWebRenderParentCommand(OpAddExternalVideoImage(mExternalImageId.value(), mVideoKeys));
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aSc)
|
||||
|
@ -146,25 +164,43 @@ WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
}
|
||||
gfx::IntSize size = image->GetSize();
|
||||
|
||||
if (GetImageClientType() == CompositableType::IMAGE_BRIDGE) {
|
||||
// Always allocate key
|
||||
WrImageKey key = GetImageKey();
|
||||
WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId.value(), key));
|
||||
WrManager()->AddImageKeyForDiscard(key);
|
||||
mKey = Some(key);
|
||||
} else {
|
||||
if (GetImageClientType() != CompositableType::IMAGE_BRIDGE) {
|
||||
// Handle CompositableType::IMAGE case
|
||||
MOZ_ASSERT(mImageClient->AsImageClientSingle());
|
||||
mKey = UpdateImageKey(mImageClient->AsImageClientSingle(),
|
||||
mContainer,
|
||||
mKey,
|
||||
mExternalImageId.ref());
|
||||
if (mKey.isNothing()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Always allocate key.
|
||||
mVideoKeys.Clear();
|
||||
|
||||
// XXX (Jerry): Remove the hardcode image format setting.
|
||||
#if defined(XP_WIN)
|
||||
// Use libyuv to convert the buffer to rgba format. So, use 1 image key here.
|
||||
AddWRVideoImage(1);
|
||||
#elif defined(XP_MACOSX)
|
||||
if (gfx::gfxVars::CanUseHardwareVideoDecoding()) {
|
||||
// Use the hardware MacIOSurface with YCbCr interleaved format. It uses 1
|
||||
// image key.
|
||||
AddWRVideoImage(1);
|
||||
} else {
|
||||
// Use libyuv.
|
||||
AddWRVideoImage(1);
|
||||
}
|
||||
#elif defined(MOZ_WIDGET_GTK)
|
||||
// Use libyuv.
|
||||
AddWRVideoImage(1);
|
||||
#elif defined(ANDROID)
|
||||
// Use libyuv.
|
||||
AddWRVideoImage(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (mKey.isNothing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScrollingLayersHelper scroller(this, aBuilder, aSc);
|
||||
StackingContextHelper sc(aSc, aBuilder, this);
|
||||
|
||||
LayerRect rect(0, 0, size.width, size.height);
|
||||
|
@ -176,7 +212,7 @@ WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
|
||||
LayerRect clipRect = ClipRect().valueOr(rect);
|
||||
Maybe<WrImageMask> mask = BuildWrMaskLayer(&sc);
|
||||
WrClipRegion clip = aBuilder.BuildClipRegion(
|
||||
WrClipRegionToken clip = aBuilder.PushClipRegion(
|
||||
sc.ToRelativeWrRect(clipRect),
|
||||
mask.ptrOr(nullptr));
|
||||
|
||||
|
@ -189,7 +225,36 @@ WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
Stringify(filter).c_str());
|
||||
}
|
||||
|
||||
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, filter, mKey.value());
|
||||
if (GetImageClientType() != CompositableType::IMAGE_BRIDGE) {
|
||||
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, filter, mKey.value());
|
||||
} else {
|
||||
// XXX (Jerry): Remove the hardcode image format setting. The format of
|
||||
// textureClient could change from time to time. So, we just set the most
|
||||
// usable format here.
|
||||
#if defined(XP_WIN)
|
||||
// Use libyuv to convert the buffer to rgba format.
|
||||
MOZ_ASSERT(mVideoKeys.Length() == 1);
|
||||
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, filter, mVideoKeys[0]);
|
||||
#elif defined(XP_MACOSX)
|
||||
if (gfx::gfxVars::CanUseHardwareVideoDecoding()) {
|
||||
// Use the hardware MacIOSurface with YCbCr interleaved format.
|
||||
MOZ_ASSERT(mVideoKeys.Length() == 1);
|
||||
aBuilder.PushYCbCrInterleavedImage(sc.ToRelativeWrRect(rect), clip, mVideoKeys[0], WrYuvColorSpace::Rec601);
|
||||
} else {
|
||||
// Use libyuv to convert the buffer to rgba format.
|
||||
MOZ_ASSERT(mVideoKeys.Length() == 1);
|
||||
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, filter, mVideoKeys[0]);
|
||||
}
|
||||
#elif defined(MOZ_WIDGET_GTK)
|
||||
// Use libyuv to convert the buffer to rgba format.
|
||||
MOZ_ASSERT(mVideoKeys.Length() == 1);
|
||||
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, filter, mVideoKeys[0]);
|
||||
#elif defined(ANDROID)
|
||||
// Use libyuv to convert the buffer to rgba format.
|
||||
MOZ_ASSERT(mVideoKeys.Length() == 1);
|
||||
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, filter, mVideoKeys[0]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<WrImageMask>
|
||||
|
|
|
@ -36,6 +36,8 @@ public:
|
|||
protected:
|
||||
CompositableType GetImageClientType();
|
||||
|
||||
void AddWRVideoImage(size_t aChannelNumber);
|
||||
|
||||
class Holder {
|
||||
public:
|
||||
explicit Holder(WebRenderImageLayer* aLayer)
|
||||
|
@ -47,6 +49,9 @@ protected:
|
|||
};
|
||||
|
||||
wr::MaybeExternalImageId mExternalImageId;
|
||||
// Some video image format contains multiple channel data.
|
||||
nsTArray<wr::ImageKey> mVideoKeys;
|
||||
// The regular single channel image.
|
||||
Maybe<wr::ImageKey> mKey;
|
||||
RefPtr<ImageClient> mImageClient;
|
||||
CompositableType mImageClientTypeContainer;
|
||||
|
|
|
@ -52,7 +52,7 @@ WebRenderLayer::BuildWrMaskLayer(const StackingContextHelper* aUnapplySc)
|
|||
// context.
|
||||
gfx::Matrix4x4 transform = maskLayer->GetLayer()->GetTransform();
|
||||
if (aUnapplySc) {
|
||||
transform = transform * aUnapplySc->TransformToParentSC();
|
||||
transform = transform * aUnapplySc->TransformToRoot();
|
||||
}
|
||||
|
||||
return maskLayer->RenderMaskLayer(transform);
|
||||
|
|
|
@ -107,7 +107,7 @@ WebRenderLayerManager::~WebRenderLayerManager()
|
|||
CompositorBridgeChild*
|
||||
WebRenderLayerManager::GetCompositorBridgeChild()
|
||||
{
|
||||
return mWidget ? mWidget->GetRemoteRenderer() : nullptr;
|
||||
return WrBridge()->GetCompositorBridgeChild();
|
||||
}
|
||||
|
||||
int32_t
|
||||
|
@ -192,7 +192,8 @@ WebRenderLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback
|
|||
mRoot->StartPendingAnimations(mAnimationReadyTime);
|
||||
|
||||
StackingContextHelper sc;
|
||||
wr::DisplayListBuilder builder(WrBridge()->GetPipeline());
|
||||
WrSize contentSize { (float)size.width, (float)size.height };
|
||||
wr::DisplayListBuilder builder(WrBridge()->GetPipeline(), contentSize);
|
||||
WebRenderLayer::ToWebRenderLayer(mRoot)->RenderLayer(builder, sc);
|
||||
WrBridge()->ClearReadLocks();
|
||||
|
||||
|
@ -205,7 +206,7 @@ WebRenderLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback
|
|||
}
|
||||
|
||||
WebRenderScrollData scrollData;
|
||||
if (mWidget->AsyncPanZoomEnabled()) {
|
||||
if (AsyncPanZoomEnabled()) {
|
||||
if (mIsFirstPaint) {
|
||||
scrollData.SetIsFirstPaint();
|
||||
mIsFirstPaint = false;
|
||||
|
@ -233,6 +234,12 @@ WebRenderLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebRenderLayerManager::AsyncPanZoomEnabled() const
|
||||
{
|
||||
return mWidget->AsyncPanZoomEnabled();
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderLayerManager::MakeSnapshotIfRequired(LayoutDeviceIntSize aSize)
|
||||
{
|
||||
|
@ -304,7 +311,7 @@ WebRenderLayerManager::AddImageKeyForDiscard(wr::ImageKey key)
|
|||
void
|
||||
WebRenderLayerManager::DiscardImages()
|
||||
{
|
||||
if (!WrBridge()->IsDestroyed()) {
|
||||
if (WrBridge()->IPCOpen()) {
|
||||
for (auto key : mImageKeys) {
|
||||
WrBridge()->SendDeleteImage(key);
|
||||
}
|
||||
|
@ -321,11 +328,11 @@ WebRenderLayerManager::AddCompositorAnimationsIdForDiscard(uint64_t aId)
|
|||
void
|
||||
WebRenderLayerManager::DiscardCompositorAnimations()
|
||||
{
|
||||
if (!mDiscardedCompositorAnimationsIds.IsEmpty()) {
|
||||
if (WrBridge()->IPCOpen() && !mDiscardedCompositorAnimationsIds.IsEmpty()) {
|
||||
WrBridge()->
|
||||
SendDeleteCompositorAnimations(mDiscardedCompositorAnimationsIds);
|
||||
mDiscardedCompositorAnimationsIds.Clear();
|
||||
}
|
||||
mDiscardedCompositorAnimationsIds.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -465,6 +472,15 @@ WebRenderLayerManager::FlushRendering()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderLayerManager::WaitOnTransactionProcessed()
|
||||
{
|
||||
CompositorBridgeChild* bridge = GetCompositorBridgeChild();
|
||||
if (bridge) {
|
||||
bridge->SendWaitOnTransactionProcessed();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderLayerManager::SendInvalidRegion(const nsIntRegion& aRegion)
|
||||
{
|
||||
|
|
|
@ -88,6 +88,7 @@ public:
|
|||
virtual void RemoveDidCompositeObserver(DidCompositeObserver* aObserver) override;
|
||||
|
||||
virtual void FlushRendering() override;
|
||||
virtual void WaitOnTransactionProcessed() override;
|
||||
|
||||
virtual void SendInvalidRegion(const nsIntRegion& aRegion) override;
|
||||
|
||||
|
@ -100,6 +101,8 @@ public:
|
|||
virtual bool NeedsComposite() const override { return mNeedsComposite; }
|
||||
virtual void SetIsFirstPaint() override { mIsFirstPaint = true; }
|
||||
|
||||
bool AsyncPanZoomEnabled() const override;
|
||||
|
||||
DrawPaintedLayerCallback GetPaintedLayerCallback() const
|
||||
{ return mPaintedLayerCallback; }
|
||||
|
||||
|
|
|
@ -192,28 +192,6 @@ struct ParamTraits<WrBuiltDisplayListDescriptor>
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<WrAuxiliaryListsDescriptor>
|
||||
{
|
||||
static void
|
||||
Write(Message* aMsg, const WrAuxiliaryListsDescriptor& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.gradient_stops_size);
|
||||
WriteParam(aMsg, aParam.complex_clip_regions_size);
|
||||
WriteParam(aMsg, aParam.filters_size);
|
||||
WriteParam(aMsg, aParam.glyph_instances_size);
|
||||
}
|
||||
|
||||
static bool
|
||||
Read(const Message* aMsg, PickleIterator* aIter, WrAuxiliaryListsDescriptor* aResult)
|
||||
{
|
||||
return ReadParam(aMsg, aIter, &aResult->gradient_stops_size)
|
||||
&& ReadParam(aMsg, aIter, &aResult->complex_clip_regions_size)
|
||||
&& ReadParam(aMsg, aIter, &aResult->filters_size)
|
||||
&& ReadParam(aMsg, aIter, &aResult->glyph_instances_size);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // GFX_WEBRENDERMESSAGEUTILS_H
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "LayersLogging.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/layers/ScrollingLayersHelper.h"
|
||||
#include "mozilla/layers/StackingContextHelper.h"
|
||||
#include "mozilla/layers/WebRenderBridgeChild.h"
|
||||
#include "mozilla/layers/UpdateImageHelper.h"
|
||||
|
@ -92,6 +93,7 @@ void
|
|||
WebRenderPaintedLayer::CreateWebRenderDisplayList(wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aSc)
|
||||
{
|
||||
ScrollingLayersHelper scroller(this, aBuilder, aSc);
|
||||
StackingContextHelper sc(aSc, aBuilder, this);
|
||||
|
||||
LayerRect rect = Bounds();
|
||||
|
@ -99,7 +101,7 @@ WebRenderPaintedLayer::CreateWebRenderDisplayList(wr::DisplayListBuilder& aBuild
|
|||
|
||||
LayerRect clipRect = ClipRect().valueOr(rect);
|
||||
Maybe<WrImageMask> mask = BuildWrMaskLayer(&sc);
|
||||
WrClipRegion clip = aBuilder.BuildClipRegion(
|
||||
WrClipRegionToken clip = aBuilder.PushClipRegion(
|
||||
sc.ToRelativeWrRect(clipRect),
|
||||
mask.ptrOr(nullptr));
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "LayersLogging.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/gfx/DrawEventRecorder.h"
|
||||
#include "mozilla/layers/ScrollingLayersHelper.h"
|
||||
#include "mozilla/layers/StackingContextHelper.h"
|
||||
#include "mozilla/layers/WebRenderBridgeChild.h"
|
||||
#include "mozilla/layers/UpdateImageHelper.h"
|
||||
|
@ -46,11 +47,11 @@ WebRenderPaintedLayerBlob::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
}
|
||||
|
||||
IntSize imageSize(size.ToUnknownSize());
|
||||
RefPtr<gfx::DrawEventRecorderMemory> recorder = MakeAndAddRef<gfx::DrawEventRecorderMemory>();
|
||||
RefPtr<gfx::DrawTarget> dummyDt = gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, imageSize, gfx::SurfaceFormat::B8G8R8X8);
|
||||
RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt);
|
||||
|
||||
if (!regionToPaint.IsEmpty() && WrManager()->GetPaintedLayerCallback()) {
|
||||
RefPtr<gfx::DrawEventRecorderMemory> recorder = MakeAndAddRef<gfx::DrawEventRecorderMemory>();
|
||||
RefPtr<gfx::DrawTarget> dummyDt = gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, imageSize, gfx::SurfaceFormat::B8G8R8X8);
|
||||
RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt);
|
||||
|
||||
dt->ClearRect(Rect(0, 0, imageSize.width, imageSize.height));
|
||||
dt->SetTransform(Matrix().PreTranslate(-bounds.x, -bounds.y));
|
||||
RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(dt);
|
||||
|
@ -66,33 +67,34 @@ WebRenderPaintedLayerBlob::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
dt->FillRect(Rect(0, 0, imageSize.width, imageSize.height), ColorPattern(Color(1.0, 0.0, 0.0, 0.5)));
|
||||
}
|
||||
|
||||
wr::ByteBuffer bytes;
|
||||
bytes.Allocate(recorder->RecordingSize());
|
||||
DebugOnly<bool> ok = recorder->CopyRecording((char*)bytes.AsSlice().begin().get(), bytes.AsSlice().length());
|
||||
MOZ_ASSERT(ok);
|
||||
|
||||
//XXX: We should switch to updating the blob image instead of adding a new one
|
||||
// That will get rid of this discard bit
|
||||
if (mImageKey.isSome()) {
|
||||
WrManager()->AddImageKeyForDiscard(mImageKey.value());
|
||||
}
|
||||
mImageKey = Some(GetImageKey());
|
||||
WrBridge()->SendAddBlobImage(mImageKey.value(), imageSize, size.width * 4, dt->GetFormat(), bytes);
|
||||
} else {
|
||||
// we need to reuse the blob image
|
||||
MOZ_ASSERT(mExternalImageId);
|
||||
MOZ_ASSERT(mImageContainer->HasCurrentImage());
|
||||
MOZ_ASSERT(GetInvalidRegion().IsEmpty());
|
||||
}
|
||||
|
||||
wr::ByteBuffer bytes;
|
||||
bytes.Allocate(recorder->RecordingSize());
|
||||
DebugOnly<bool> ok = recorder->CopyRecording((char*)bytes.AsSlice().begin().get(), bytes.AsSlice().length());
|
||||
MOZ_ASSERT(ok);
|
||||
|
||||
ScrollingLayersHelper scroller(this, aBuilder, aSc);
|
||||
StackingContextHelper sc(aSc, aBuilder, this);
|
||||
LayerRect rect = Bounds();
|
||||
DumpLayerInfo("PaintedLayer", rect);
|
||||
|
||||
LayerRect clipRect = ClipRect().valueOr(rect);
|
||||
Maybe<WrImageMask> mask = BuildWrMaskLayer(&sc);
|
||||
WrClipRegion clip = aBuilder.BuildClipRegion(
|
||||
WrClipRegionToken clip = aBuilder.PushClipRegion(
|
||||
sc.ToRelativeWrRect(clipRect),
|
||||
mask.ptrOr(nullptr));
|
||||
|
||||
WrImageKey key = GetImageKey();
|
||||
WrBridge()->SendAddBlobImage(key, imageSize, size.width * 4, dt->GetFormat(), bytes);
|
||||
WrManager()->AddImageKeyForDiscard(key);
|
||||
|
||||
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, wr::ImageRendering::Auto, key);
|
||||
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, wr::ImageRendering::Auto, mImageKey.value());
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -35,6 +35,9 @@ protected:
|
|||
if (mExternalImageId.isSome()) {
|
||||
WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
|
||||
}
|
||||
if (mImageKey.isSome()) {
|
||||
WrManager()->AddImageKeyForDiscard(mImageKey.value());
|
||||
}
|
||||
}
|
||||
|
||||
wr::MaybeExternalImageId mExternalImageId;
|
||||
|
@ -52,7 +55,7 @@ public:
|
|||
private:
|
||||
RefPtr<ImageContainer> mImageContainer;
|
||||
RefPtr<ImageClient> mImageClient;
|
||||
|
||||
Maybe<WrImageKey> mImageKey;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "gfxPrefs.h"
|
||||
#include "LayersLogging.h"
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
#include "mozilla/layers/ScrollingLayersHelper.h"
|
||||
#include "mozilla/layers/WebRenderBridgeChild.h"
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
@ -25,6 +26,8 @@ WebRenderTextLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
return;
|
||||
}
|
||||
|
||||
ScrollingLayersHelper scroller(this, aBuilder, aSc);
|
||||
|
||||
LayerRect rect = LayerRect::FromUnknownRect(
|
||||
// I am not 100% sure this is correct, but it probably is. Because:
|
||||
// the bounds are in layer space, and when gecko composites layers it
|
||||
|
|
|
@ -156,5 +156,16 @@ WebRenderTextureHost::GetRGBStride()
|
|||
return ImageDataSerializer::ComputeRGBStride(format, GetSize().width);
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderTextureHost::AddWRImage(wr::WebRenderAPI* aAPI,
|
||||
Range<const wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExtID)
|
||||
{
|
||||
MOZ_ASSERT(mWrappedTextureHost);
|
||||
MOZ_ASSERT(mExternalImageId == aExtID);
|
||||
|
||||
mWrappedTextureHost->AddWRImage(aAPI, aImageKeys, aExtID);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -65,6 +65,10 @@ public:
|
|||
|
||||
bool IsWrappingNativeHandle() { return mIsWrappingNativeHandle; }
|
||||
|
||||
virtual void AddWRImage(wr::WebRenderAPI* aAPI,
|
||||
Range<const wr::ImageKey>& aImageKeys,
|
||||
const wr::ExternalImageId& aExtID) override;
|
||||
|
||||
protected:
|
||||
void CreateRenderTextureHost(const SurfaceDescriptor& aDesc, TextureHost* aTexture);
|
||||
|
||||
|
|
|
@ -311,3 +311,8 @@ bool gfxPrefs::OverrideBase_WebRender()
|
|||
{
|
||||
return gfx::gfxVars::UseWebRender();
|
||||
}
|
||||
|
||||
bool gfxPrefs::OverrideBase_WebRendest()
|
||||
{
|
||||
return gfx::gfxVars::UseWebRender() && gfxPrefs::WebRendestEnabled();
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче