mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Merge m-c to autoland. a=merge
This commit is contained in:
commit
4a76c08262
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
|||||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||||
# don't change CLOBBER for WebIDL changes any more.
|
# don't change CLOBBER for WebIDL changes any more.
|
||||||
|
|
||||||
Bug 1297276 - renaming a file with a different case needed a clobber on case insensitive filesystem
|
Bug 1294660 - CSS properties regeneration needs a clobber
|
||||||
|
@ -240,21 +240,6 @@ appUpdater.prototype =
|
|||||||
Components.interfaces.nsIAppStartup.eRestart);
|
Components.interfaces.nsIAppStartup.eRestart);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles oncommand for the "Apply Update…" button
|
|
||||||
* which is presented if we need to show the billboard.
|
|
||||||
*/
|
|
||||||
buttonApplyBillboard: function() {
|
|
||||||
const URI_UPDATE_PROMPT_DIALOG = "chrome://mozapps/content/update/updates.xul";
|
|
||||||
var ary = null;
|
|
||||||
ary = Components.classes["@mozilla.org/supports-array;1"].
|
|
||||||
createInstance(Components.interfaces.nsISupportsArray);
|
|
||||||
ary.AppendElement(this.update);
|
|
||||||
var openFeatures = "chrome,centerscreen,dialog=no,resizable=no,titlebar,toolbar=no";
|
|
||||||
Services.ww.openWindow(null, URI_UPDATE_PROMPT_DIALOG, "", openFeatures, ary);
|
|
||||||
window.close(); // close the "About" window; updates.xul takes over.
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements nsIUpdateCheckListener. The methods implemented by
|
* Implements nsIUpdateCheckListener. The methods implemented by
|
||||||
* nsIUpdateCheckListener are in a different scope from nsIIncrementalDownload
|
* nsIUpdateCheckListener are in a different scope from nsIIncrementalDownload
|
||||||
@ -287,11 +272,6 @@ appUpdater.prototype =
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gAppUpdater.update.billboardURL) {
|
|
||||||
gAppUpdater.selectPanel("applyBillboard");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gAppUpdater.updateAuto) // automatically download and install
|
if (gAppUpdater.updateAuto) // automatically download and install
|
||||||
gAppUpdater.startDownload();
|
gAppUpdater.startDownload();
|
||||||
else // ask
|
else // ask
|
||||||
|
@ -78,13 +78,6 @@
|
|||||||
oncommand="gAppUpdater.buttonRestartAfterDownload();"/>
|
oncommand="gAppUpdater.buttonRestartAfterDownload();"/>
|
||||||
<spacer flex="1"/>
|
<spacer flex="1"/>
|
||||||
</hbox>
|
</hbox>
|
||||||
<hbox id="applyBillboard" align="center">
|
|
||||||
<button id="applyButtonBillboard" align="start"
|
|
||||||
label="&update.applyButtonBillboard.label;"
|
|
||||||
accesskey="&update.applyButtonBillboard.accesskey;"
|
|
||||||
oncommand="gAppUpdater.buttonApplyBillboard();"/>
|
|
||||||
<spacer flex="1"/>
|
|
||||||
</hbox>
|
|
||||||
<hbox id="checkingForUpdates" align="center">
|
<hbox id="checkingForUpdates" align="center">
|
||||||
<image class="update-throbber"/><label>&update.checkingForUpdates;</label>
|
<image class="update-throbber"/><label>&update.checkingForUpdates;</label>
|
||||||
</hbox>
|
</hbox>
|
||||||
|
@ -538,20 +538,6 @@ Sanitizer.prototype = {
|
|||||||
seenException = ex;
|
seenException = ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
// Clear "Never remember passwords for this site", which is not handled by
|
|
||||||
// the permission manager
|
|
||||||
// (Note the login manager doesn't support date ranges yet, and bug
|
|
||||||
// 1058438 is calling for loginSaving stuff to end up in the
|
|
||||||
// permission manager)
|
|
||||||
let hosts = Services.logins.getAllDisabledHosts();
|
|
||||||
for (let host of hosts) {
|
|
||||||
Services.logins.setLoginSavingEnabled(host, true);
|
|
||||||
}
|
|
||||||
} catch (ex) {
|
|
||||||
seenException = ex;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Clear site security settings - no support for ranges in this
|
// Clear site security settings - no support for ranges in this
|
||||||
// interface either, so we clearAll().
|
// interface either, so we clearAll().
|
||||||
|
@ -484,7 +484,7 @@ skip-if = (os == "win" && !debug)
|
|||||||
[browser_windowopen_reflows.js]
|
[browser_windowopen_reflows.js]
|
||||||
skip-if = buildapp == 'mulet'
|
skip-if = buildapp == 'mulet'
|
||||||
[browser_zbug569342.js]
|
[browser_zbug569342.js]
|
||||||
skip-if = e10s # Bug 1094240 - has findbar-related failures
|
skip-if = e10s || debug # Bug 1094240 - has findbar-related failures
|
||||||
[browser_registerProtocolHandler_notification.js]
|
[browser_registerProtocolHandler_notification.js]
|
||||||
[browser_no_mcb_on_http_site.js]
|
[browser_no_mcb_on_http_site.js]
|
||||||
tags = mcb
|
tags = mcb
|
||||||
|
@ -91,6 +91,14 @@ XPCOMUtils.defineLazyGetter(this, "standaloneStylesheets", () => {
|
|||||||
return stylesheets;
|
return stylesheets;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* eslint-disable mozilla/balanced-listeners */
|
||||||
|
extensions.on("page-shutdown", (type, context) => {
|
||||||
|
if (context.type == "popup" && context.active) {
|
||||||
|
context.contentWindow.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/* eslint-enable mozilla/balanced-listeners */
|
||||||
|
|
||||||
class BasePopup {
|
class BasePopup {
|
||||||
constructor(extension, viewNode, popupURL, browserStyle, fixedWidth = false) {
|
constructor(extension, viewNode, popupURL, browserStyle, fixedWidth = false) {
|
||||||
this.extension = extension;
|
this.extension = extension;
|
||||||
@ -129,8 +137,10 @@ class BasePopup {
|
|||||||
this.viewNode.removeEventListener(this.DESTROY_EVENT, this);
|
this.viewNode.removeEventListener(this.DESTROY_EVENT, this);
|
||||||
this.viewNode.style.maxHeight = "";
|
this.viewNode.style.maxHeight = "";
|
||||||
|
|
||||||
this.panel.style.removeProperty("--panel-arrowcontent-background");
|
if (this.panel) {
|
||||||
this.panel.style.removeProperty("--panel-arrow-image-vertical");
|
this.panel.style.removeProperty("--panel-arrowcontent-background");
|
||||||
|
this.panel.style.removeProperty("--panel-arrow-image-vertical");
|
||||||
|
}
|
||||||
|
|
||||||
this.browser = null;
|
this.browser = null;
|
||||||
this.viewNode = null;
|
this.viewNode = null;
|
||||||
@ -154,7 +164,7 @@ class BasePopup {
|
|||||||
|
|
||||||
get panel() {
|
get panel() {
|
||||||
let panel = this.viewNode;
|
let panel = this.viewNode;
|
||||||
while (panel.localName != "panel") {
|
while (panel && panel.localName != "panel") {
|
||||||
panel = panel.parentNode;
|
panel = panel.parentNode;
|
||||||
}
|
}
|
||||||
return panel;
|
return panel;
|
||||||
|
@ -49,6 +49,7 @@ tags = webextensions
|
|||||||
[browser_ext_popup_api_injection.js]
|
[browser_ext_popup_api_injection.js]
|
||||||
[browser_ext_popup_background.js]
|
[browser_ext_popup_background.js]
|
||||||
[browser_ext_popup_corners.js]
|
[browser_ext_popup_corners.js]
|
||||||
|
[browser_ext_popup_shutdown.js]
|
||||||
[browser_ext_runtime_openOptionsPage.js]
|
[browser_ext_runtime_openOptionsPage.js]
|
||||||
[browser_ext_runtime_openOptionsPage_uninstall.js]
|
[browser_ext_runtime_openOptionsPage_uninstall.js]
|
||||||
[browser_ext_runtime_setUninstallURL.js]
|
[browser_ext_runtime_setUninstallURL.js]
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||||
|
/* vim: set sts=2 sw=2 et tw=80: */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let getExtension = () => {
|
||||||
|
return ExtensionTestUtils.loadExtension({
|
||||||
|
background() {
|
||||||
|
browser.tabs.query({active: true, currentWindow: true}, tabs => {
|
||||||
|
browser.pageAction.show(tabs[0].id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
manifest: {
|
||||||
|
"browser_action": {
|
||||||
|
"default_popup": "popup.html",
|
||||||
|
"browser_style": false,
|
||||||
|
},
|
||||||
|
|
||||||
|
"page_action": {
|
||||||
|
"default_popup": "popup.html",
|
||||||
|
"browser_style": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
files: {
|
||||||
|
"popup.html": `<!DOCTYPE html>
|
||||||
|
<html><head><meta charset="utf-8"></head></html>`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
add_task(function* testStandaloneBrowserAction() {
|
||||||
|
info("Test stand-alone browserAction popup");
|
||||||
|
|
||||||
|
let extension = getExtension();
|
||||||
|
yield extension.startup();
|
||||||
|
|
||||||
|
clickBrowserAction(extension);
|
||||||
|
let browser = yield awaitExtensionPanel(extension);
|
||||||
|
let panel = getPanelForNode(browser);
|
||||||
|
|
||||||
|
yield extension.unload();
|
||||||
|
|
||||||
|
is(panel.parentNode, null, "Panel should be removed from the document");
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(function* testMenuPanelBrowserAction() {
|
||||||
|
let extension = getExtension();
|
||||||
|
yield extension.startup();
|
||||||
|
|
||||||
|
let widget = getBrowserActionWidget(extension);
|
||||||
|
CustomizableUI.addWidgetToArea(widget.id, CustomizableUI.AREA_PANEL);
|
||||||
|
|
||||||
|
clickBrowserAction(extension);
|
||||||
|
let browser = yield awaitExtensionPanel(extension);
|
||||||
|
let panel = getPanelForNode(browser);
|
||||||
|
|
||||||
|
yield extension.unload();
|
||||||
|
|
||||||
|
is(panel.state, "closed", "Panel should be closed");
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(function* testPageAction() {
|
||||||
|
let extension = getExtension();
|
||||||
|
yield extension.startup();
|
||||||
|
|
||||||
|
clickPageAction(extension);
|
||||||
|
let browser = yield awaitExtensionPanel(extension);
|
||||||
|
let panel = getPanelForNode(browser);
|
||||||
|
|
||||||
|
yield extension.unload();
|
||||||
|
|
||||||
|
is(panel.parentNode, null, "Panel should be removed from the document");
|
||||||
|
});
|
@ -3,17 +3,15 @@
|
|||||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
<!ENTITY aboutDialog.title "About &brandFullName;">
|
<!ENTITY aboutDialog.title "About &brandFullName;">
|
||||||
|
|
||||||
<!-- LOCALIZATION NOTE (update.checkForUpdatesButton.*, update.updateButton.*, update.applyButtonBillboard.*):
|
<!-- LOCALIZATION NOTE (update.checkForUpdatesButton.*, update.updateButton.*):
|
||||||
# Only one button is present at a time.
|
# Only one button is present at a time.
|
||||||
# The button when displayed is located directly under the Firefox version in
|
# The button when displayed is located directly under the Firefox version in
|
||||||
# the about dialog (see bug 596813 for screenshots).
|
# the about dialog (see bug 596813 for screenshots).
|
||||||
-->
|
-->
|
||||||
<!ENTITY update.checkForUpdatesButton.label "Check for updates">
|
<!ENTITY update.checkForUpdatesButton.label "Check for updates">
|
||||||
<!ENTITY update.checkForUpdatesButton.accesskey "C">
|
<!ENTITY update.checkForUpdatesButton.accesskey "C">
|
||||||
<!ENTITY update.updateButton.label2 "Restart &brandShortName; to Update">
|
<!ENTITY update.updateButton.label2 "Restart &brandShortName; to Update">
|
||||||
<!ENTITY update.updateButton.accesskey "R">
|
<!ENTITY update.updateButton.accesskey "R">
|
||||||
<!ENTITY update.applyButtonBillboard.label "Apply Update…">
|
|
||||||
<!ENTITY update.applyButtonBillboard.accesskey "A">
|
|
||||||
|
|
||||||
|
|
||||||
<!-- LOCALIZATION NOTE (warningDesc.version): This is a warning about the experimental nature of Nightly and Aurora builds. It is only shown in those versions. -->
|
<!-- LOCALIZATION NOTE (warningDesc.version): This is a warning about the experimental nature of Nightly and Aurora builds. It is only shown in those versions. -->
|
||||||
|
@ -64,8 +64,6 @@
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
list-style-image: url(chrome://browser/skin/identity-icon.svg#normal);
|
list-style-image: url(chrome://browser/skin/identity-icon.svg#normal);
|
||||||
filter: url(chrome://browser/skin/filters.svg#fill);
|
|
||||||
fill: currentColor;
|
|
||||||
opacity: .5;
|
opacity: .5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,8 +149,6 @@
|
|||||||
margin-inline-start: 2px;
|
margin-inline-start: 2px;
|
||||||
margin-inline-end: 0;
|
margin-inline-end: 0;
|
||||||
list-style-image: url(chrome://browser/skin/tracking-protection-16.svg);
|
list-style-image: url(chrome://browser/skin/tracking-protection-16.svg);
|
||||||
filter: url(chrome://browser/skin/filters.svg#fill);
|
|
||||||
fill: currentColor;
|
|
||||||
opacity: .5;
|
opacity: .5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<style>
|
<style>
|
||||||
path {
|
path {
|
||||||
fill-rule: evenodd;
|
fill-rule: evenodd;
|
||||||
|
fill: -moz-fieldtext;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</defs>
|
</defs>
|
||||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.9 KiB |
@ -17,5 +17,5 @@
|
|||||||
</mask>
|
</mask>
|
||||||
</defs>
|
</defs>
|
||||||
|
|
||||||
<use xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
|
<use xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)" fill="-moz-fieldtext"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@ -17,7 +17,7 @@
|
|||||||
<form id="options-panel">
|
<form id="options-panel">
|
||||||
<div id="tools-box" class="options-vertical-pane">
|
<div id="tools-box" class="options-vertical-pane">
|
||||||
<fieldset id="default-tools-box" class="options-groupbox">
|
<fieldset id="default-tools-box" class="options-groupbox">
|
||||||
<legend>&options.selectDefaultTools.label;</legend>
|
<legend>&options.selectDefaultTools.label2;</legend>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset id="additional-tools-box" class="options-groupbox">
|
<fieldset id="additional-tools-box" class="options-groupbox">
|
||||||
@ -171,7 +171,7 @@
|
|||||||
data-pref="devtools.chrome.enabled"/>
|
data-pref="devtools.chrome.enabled"/>
|
||||||
<span>&options.enableChrome.label5;</span>
|
<span>&options.enableChrome.label5;</span>
|
||||||
</label>
|
</label>
|
||||||
<label title="&options.enableRemote.tooltip;">
|
<label title="&options.enableRemote.tooltip2;">
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
data-pref="devtools.debugger.remote-enabled"/>
|
data-pref="devtools.debugger.remote-enabled"/>
|
||||||
<span>&options.enableRemote.label3;</span>
|
<span>&options.enableRemote.label3;</span>
|
||||||
|
@ -240,16 +240,17 @@ InspectorPanel.prototype = {
|
|||||||
|
|
||||||
// All the components are initialized. Let's select a node.
|
// All the components are initialized. Let's select a node.
|
||||||
this.selection.setNodeFront(defaultSelection, "inspector-open");
|
this.selection.setNodeFront(defaultSelection, "inspector-open");
|
||||||
|
|
||||||
this.markup.expandNode(this.selection.nodeFront);
|
this.markup.expandNode(this.selection.nodeFront);
|
||||||
|
|
||||||
|
// And setup the toolbar only now because it may depend on the document.
|
||||||
|
this.setupToolbar();
|
||||||
|
|
||||||
this.emit("ready");
|
this.emit("ready");
|
||||||
deferred.resolve(this);
|
deferred.resolve(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setupSearchBox();
|
this.setupSearchBox();
|
||||||
this.setupSidebar();
|
this.setupSidebar();
|
||||||
this.setupToolbar();
|
|
||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
},
|
},
|
||||||
@ -509,6 +510,8 @@ InspectorPanel.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
setupToolbar: function () {
|
setupToolbar: function () {
|
||||||
|
this.teardownToolbar();
|
||||||
|
|
||||||
// Setup the sidebar toggle button.
|
// Setup the sidebar toggle button.
|
||||||
let SidebarToggle = this.React.createFactory(this.browserRequire(
|
let SidebarToggle = this.React.createFactory(this.browserRequire(
|
||||||
"devtools/client/shared/components/sidebar-toggle"));
|
"devtools/client/shared/components/sidebar-toggle"));
|
||||||
@ -528,21 +531,28 @@ InspectorPanel.prototype = {
|
|||||||
this.addNodeButton = this.panelDoc.getElementById("inspector-element-add-button");
|
this.addNodeButton = this.panelDoc.getElementById("inspector-element-add-button");
|
||||||
this.addNodeButton.addEventListener("click", this.addNode);
|
this.addNodeButton.addEventListener("click", this.addNode);
|
||||||
|
|
||||||
// Setup the eye-dropper icon.
|
// Setup the eye-dropper icon if we're in an HTML document and we have actor support.
|
||||||
this.toolbox.target.actorHasMethod("inspector", "pickColorFromPage").then(value => {
|
if (this.selection.nodeFront && this.selection.nodeFront.isInHTMLDocument) {
|
||||||
if (!value) {
|
this.toolbox.target.actorHasMethod("inspector", "pickColorFromPage").then(value => {
|
||||||
return;
|
if (!value) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.onEyeDropperDone = this.onEyeDropperDone.bind(this);
|
this.onEyeDropperDone = this.onEyeDropperDone.bind(this);
|
||||||
this.onEyeDropperButtonClicked = this.onEyeDropperButtonClicked.bind(this);
|
this.onEyeDropperButtonClicked = this.onEyeDropperButtonClicked.bind(this);
|
||||||
this.eyeDropperButton = this.panelDoc.getElementById("inspector-eyedropper-toggle");
|
this.eyeDropperButton = this.panelDoc
|
||||||
this.eyeDropperButton.style.display = "initial";
|
.getElementById("inspector-eyedropper-toggle");
|
||||||
this.eyeDropperButton.addEventListener("click", this.onEyeDropperButtonClicked);
|
this.eyeDropperButton.style.display = "initial";
|
||||||
}, e => console.error(e));
|
this.eyeDropperButton.addEventListener("click", this.onEyeDropperButtonClicked);
|
||||||
|
}, e => console.error(e));
|
||||||
|
} else {
|
||||||
|
this.panelDoc.getElementById("inspector-eyedropper-toggle").style.display = "none";
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
teardownToolbar: function () {
|
teardownToolbar: function () {
|
||||||
|
this._sidebarToggle = null;
|
||||||
|
|
||||||
if (this.addNodeButton) {
|
if (this.addNodeButton) {
|
||||||
this.addNodeButton.removeEventListener("click", this.addNode);
|
this.addNodeButton.removeEventListener("click", this.addNode);
|
||||||
this.addNodeButton = null;
|
this.addNodeButton = null;
|
||||||
@ -580,6 +590,9 @@ InspectorPanel.prototype = {
|
|||||||
this.markup.expandNode(this.selection.nodeFront);
|
this.markup.expandNode(this.selection.nodeFront);
|
||||||
this.emit("new-root");
|
this.emit("new-root");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Setup the toolbar again, since its content may depend on the current document.
|
||||||
|
this.setupToolbar();
|
||||||
};
|
};
|
||||||
this._pendingSelection = onNodeSelected;
|
this._pendingSelection = onNodeSelected;
|
||||||
this._getDefaultNodeForSelection()
|
this._getDefaultNodeForSelection()
|
||||||
@ -1301,6 +1314,12 @@ InspectorPanel.prototype = {
|
|||||||
* @return {Promise} resolves when the eyedropper is visible.
|
* @return {Promise} resolves when the eyedropper is visible.
|
||||||
*/
|
*/
|
||||||
showEyeDropper: function () {
|
showEyeDropper: function () {
|
||||||
|
// The eyedropper button doesn't exist, most probably because the actor doesn't
|
||||||
|
// support the pickColorFromPage, or because the page isn't HTML.
|
||||||
|
if (!this.eyeDropperButton) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
this.telemetry.toolOpened("toolbareyedropper");
|
this.telemetry.toolOpened("toolbareyedropper");
|
||||||
this.eyeDropperButton.setAttribute("checked", "true");
|
this.eyeDropperButton.setAttribute("checked", "true");
|
||||||
this.startEyeDropperListeners();
|
this.startEyeDropperListeners();
|
||||||
@ -1313,6 +1332,12 @@ InspectorPanel.prototype = {
|
|||||||
* @return {Promise} resolves when the eyedropper is hidden.
|
* @return {Promise} resolves when the eyedropper is hidden.
|
||||||
*/
|
*/
|
||||||
hideEyeDropper: function () {
|
hideEyeDropper: function () {
|
||||||
|
// The eyedropper button doesn't exist, most probably because the actor doesn't
|
||||||
|
// support the pickColorFromPage, or because the page isn't HTML.
|
||||||
|
if (!this.eyeDropperButton) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
this.eyeDropperButton.removeAttribute("checked");
|
this.eyeDropperButton.removeAttribute("checked");
|
||||||
this.stopEyeDropperListeners();
|
this.stopEyeDropperListeners();
|
||||||
return this.inspector.cancelPickColorFromPage()
|
return this.inspector.cancelPickColorFromPage()
|
||||||
|
@ -75,6 +75,7 @@ subsuite = clipboard
|
|||||||
[browser_inspector_highlighter-eyedropper-events.js]
|
[browser_inspector_highlighter-eyedropper-events.js]
|
||||||
[browser_inspector_highlighter-eyedropper-label.js]
|
[browser_inspector_highlighter-eyedropper-label.js]
|
||||||
[browser_inspector_highlighter-eyedropper-show-hide.js]
|
[browser_inspector_highlighter-eyedropper-show-hide.js]
|
||||||
|
[browser_inspector_highlighter-eyedropper-xul.js]
|
||||||
[browser_inspector_highlighter-geometry_01.js]
|
[browser_inspector_highlighter-geometry_01.js]
|
||||||
[browser_inspector_highlighter-geometry_02.js]
|
[browser_inspector_highlighter-geometry_02.js]
|
||||||
[browser_inspector_highlighter-geometry_03.js]
|
[browser_inspector_highlighter-geometry_03.js]
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Test that the eyedropper icons in the toolbar and in the color picker aren't displayed
|
||||||
|
// when the page isn't an HTML one.
|
||||||
|
|
||||||
|
const TEST_URL = URL_ROOT + "doc_inspector_highlighter_xbl.xul";
|
||||||
|
|
||||||
|
add_task(function* () {
|
||||||
|
let {inspector} = yield openInspectorForURL(TEST_URL);
|
||||||
|
|
||||||
|
info("Check the inspector toolbar");
|
||||||
|
let button = inspector.panelDoc.querySelector("#inspector-eyedropper-toggle");
|
||||||
|
ok(!isVisible(button), "The button is hidden in the toolbar");
|
||||||
|
|
||||||
|
info("Check the color picker");
|
||||||
|
yield selectNode("#scale", inspector);
|
||||||
|
|
||||||
|
// Find the color swatch in the rule-view.
|
||||||
|
let ruleView = inspector.ruleview.view;
|
||||||
|
let ruleViewDocument = ruleView.styleDocument;
|
||||||
|
let swatchEl = ruleViewDocument.querySelector(".ruleview-colorswatch");
|
||||||
|
|
||||||
|
info("Open the color picker");
|
||||||
|
let cPicker = ruleView.tooltips.colorPicker;
|
||||||
|
let onColorPickerReady = cPicker.once("ready");
|
||||||
|
swatchEl.click();
|
||||||
|
yield onColorPickerReady;
|
||||||
|
|
||||||
|
button = cPicker.tooltip.doc.querySelector("#eyedropper-button");
|
||||||
|
ok(!isVisible(button), "The button is hidden in the color picker");
|
||||||
|
});
|
||||||
|
|
||||||
|
function isVisible(button) {
|
||||||
|
return button.getBoxQuads().length !== 0;
|
||||||
|
}
|
@ -4,6 +4,6 @@
|
|||||||
<window title="Test that the picker works correctly with XBL anonymous nodes"
|
<window title="Test that the picker works correctly with XBL anonymous nodes"
|
||||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||||
|
|
||||||
<scale id="scale"/>
|
<scale id="scale" style="background:red"/>
|
||||||
|
|
||||||
</window>
|
</window>
|
||||||
|
@ -93,7 +93,7 @@
|
|||||||
- checkbox that toggles remote debugging, i.e. devtools.debugger.remote-enabled
|
- checkbox that toggles remote debugging, i.e. devtools.debugger.remote-enabled
|
||||||
- boolean preference in about:config, in the options panel. -->
|
- boolean preference in about:config, in the options panel. -->
|
||||||
<!ENTITY options.enableRemote.label3 "Enable remote debugging">
|
<!ENTITY options.enableRemote.label3 "Enable remote debugging">
|
||||||
<!ENTITY options.enableRemote.tooltip "Turning this option on will allow the developer tools to debug remote Firefox instance like Firefox OS">
|
<!ENTITY options.enableRemote.tooltip2 "Turning this option on will allow the developer tools to debug a remote instance like Firefox OS">
|
||||||
|
|
||||||
<!-- LOCALIZATION NOTE (options.enableWorkers.label): This is the label for the
|
<!-- LOCALIZATION NOTE (options.enableWorkers.label): This is the label for the
|
||||||
- checkbox that toggles worker debugging, i.e. devtools.debugger.workers
|
- checkbox that toggles worker debugging, i.e. devtools.debugger.workers
|
||||||
@ -119,10 +119,10 @@
|
|||||||
<!ENTITY options.enableServiceWorkersHTTP.label "Enable Service Workers over HTTP (when toolbox is open)">
|
<!ENTITY options.enableServiceWorkersHTTP.label "Enable Service Workers over HTTP (when toolbox is open)">
|
||||||
<!ENTITY options.enableServiceWorkersHTTP.tooltip "Turning this option on will enable the service workers over HTTP for all tabs that have the toolbox open.">
|
<!ENTITY options.enableServiceWorkersHTTP.tooltip "Turning this option on will enable the service workers over HTTP for all tabs that have the toolbox open.">
|
||||||
|
|
||||||
<!-- LOCALIZATION NOTE (options.selectDefaultTools.label): This is the label for
|
<!-- LOCALIZATION NOTE (options.selectDefaultTools.label2): This is the label for
|
||||||
- the heading of group of checkboxes corresponding to the default developer
|
- the heading of group of checkboxes corresponding to the default developer
|
||||||
- tools. -->
|
- tools. -->
|
||||||
<!ENTITY options.selectDefaultTools.label "Default Firefox Developer Tools">
|
<!ENTITY options.selectDefaultTools.label2 "Default Developer Tools">
|
||||||
|
|
||||||
<!-- LOCALIZATION NOTE (options.selectAdditionalTools.label): This is the label for
|
<!-- LOCALIZATION NOTE (options.selectAdditionalTools.label): This is the label for
|
||||||
- the heading of group of checkboxes corresponding to the developer tools
|
- the heading of group of checkboxes corresponding to the developer tools
|
||||||
|
@ -745,7 +745,7 @@ Heritage.extend(SwatchBasedEditorTooltip.prototype, {
|
|||||||
target.actorHasMethod("inspector", "pickColorFromPage").then(value => {
|
target.actorHasMethod("inspector", "pickColorFromPage").then(value => {
|
||||||
let tooltipDoc = this.tooltip.doc;
|
let tooltipDoc = this.tooltip.doc;
|
||||||
let eyeButton = tooltipDoc.querySelector("#eyedropper-button");
|
let eyeButton = tooltipDoc.querySelector("#eyedropper-button");
|
||||||
if (value) {
|
if (value && this.inspector.selection.nodeFront.isInHTMLDocument) {
|
||||||
eyeButton.addEventListener("click", this._openEyeDropper);
|
eyeButton.addEventListener("click", this._openEyeDropper);
|
||||||
} else {
|
} else {
|
||||||
eyeButton.style.display = "none";
|
eyeButton.style.display = "none";
|
||||||
|
@ -580,6 +580,10 @@ HighlighterEnvironment.prototype = {
|
|||||||
return this._win || this._tabActor;
|
return this._win || this._tabActor;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get isXUL() {
|
||||||
|
return isXUL(this.window);
|
||||||
|
},
|
||||||
|
|
||||||
get window() {
|
get window() {
|
||||||
if (!this.isInitialized) {
|
if (!this.isInitialized) {
|
||||||
throw new Error("Initialize HighlighterEnvironment with a tabActor " +
|
throw new Error("Initialize HighlighterEnvironment with a tabActor " +
|
||||||
|
@ -126,6 +126,10 @@ EyeDropper.prototype = {
|
|||||||
* - {Boolean} copyOnSelect Whether selecting a color should copy it to the clipboard.
|
* - {Boolean} copyOnSelect Whether selecting a color should copy it to the clipboard.
|
||||||
*/
|
*/
|
||||||
show(node, options = {}) {
|
show(node, options = {}) {
|
||||||
|
if (this.highlighterEnv.isXUL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
|
||||||
// Get the page's current zoom level.
|
// Get the page's current zoom level.
|
||||||
@ -167,6 +171,10 @@ EyeDropper.prototype = {
|
|||||||
* Hide the eye-dropper highlighter.
|
* Hide the eye-dropper highlighter.
|
||||||
*/
|
*/
|
||||||
hide() {
|
hide() {
|
||||||
|
if (this.highlighterEnv.isXUL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.pageImage = null;
|
this.pageImage = null;
|
||||||
|
|
||||||
let {pageListenerTarget} = this.highlighterEnv;
|
let {pageListenerTarget} = this.highlighterEnv;
|
||||||
|
File diff suppressed because one or more lines are too long
@ -12,6 +12,7 @@
|
|||||||
#include "mozilla/dom/ShadowRoot.h"
|
#include "mozilla/dom/ShadowRoot.h"
|
||||||
#include "nsIAnonymousContentCreator.h"
|
#include "nsIAnonymousContentCreator.h"
|
||||||
#include "nsIFrame.h"
|
#include "nsIFrame.h"
|
||||||
|
#include "nsCSSAnonBoxes.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
@ -375,6 +376,31 @@ AllChildrenIterator::Seek(nsIContent* aChildToFind)
|
|||||||
return child == aChildToFind;
|
return child == aChildToFind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AllChildrenIterator::AppendNativeAnonymousChildren()
|
||||||
|
{
|
||||||
|
AppendNativeAnonymousChildrenFromFrame(mOriginalContent->GetPrimaryFrame());
|
||||||
|
|
||||||
|
// The root scroll frame is not the primary frame of the root element.
|
||||||
|
// Detect and handle this case.
|
||||||
|
if (mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
|
||||||
|
nsIPresShell* presShell = mOriginalContent->OwnerDoc()->GetShell();
|
||||||
|
nsIFrame* scrollFrame = presShell ? presShell->GetRootScrollFrame() : nullptr;
|
||||||
|
if (scrollFrame) {
|
||||||
|
AppendNativeAnonymousChildrenFromFrame(scrollFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AllChildrenIterator::AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame)
|
||||||
|
{
|
||||||
|
nsIAnonymousContentCreator* ac = do_QueryFrame(aFrame);
|
||||||
|
if (ac) {
|
||||||
|
ac->AppendAnonymousContentTo(mAnonKids, mFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nsIContent*
|
nsIContent*
|
||||||
AllChildrenIterator::GetNextChild()
|
AllChildrenIterator::GetNextChild()
|
||||||
{
|
{
|
||||||
@ -406,11 +432,7 @@ AllChildrenIterator::GetNextChild()
|
|||||||
if (mPhase == eAtAnonKids) {
|
if (mPhase == eAtAnonKids) {
|
||||||
if (mAnonKids.IsEmpty()) {
|
if (mAnonKids.IsEmpty()) {
|
||||||
MOZ_ASSERT(mAnonKidsIdx == UINT32_MAX);
|
MOZ_ASSERT(mAnonKidsIdx == UINT32_MAX);
|
||||||
nsIAnonymousContentCreator* ac =
|
AppendNativeAnonymousChildren();
|
||||||
do_QueryFrame(mOriginalContent->GetPrimaryFrame());
|
|
||||||
if (ac) {
|
|
||||||
ac->AppendAnonymousContentTo(mAnonKids, mFlags);
|
|
||||||
}
|
|
||||||
mAnonKidsIdx = 0;
|
mAnonKidsIdx = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -462,12 +484,8 @@ AllChildrenIterator::GetPreviousChild()
|
|||||||
|
|
||||||
if (mPhase == eAtAnonKids) {
|
if (mPhase == eAtAnonKids) {
|
||||||
if (mAnonKids.IsEmpty()) {
|
if (mAnonKids.IsEmpty()) {
|
||||||
nsIAnonymousContentCreator* ac =
|
AppendNativeAnonymousChildren();
|
||||||
do_QueryFrame(mOriginalContent->GetPrimaryFrame());
|
mAnonKidsIdx = mAnonKids.Length();
|
||||||
if (ac) {
|
|
||||||
ac->AppendAnonymousContentTo(mAnonKids, mFlags);
|
|
||||||
mAnonKidsIdx = mAnonKids.Length();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If 0 then it turns into UINT32_MAX, which indicates the iterator is
|
// If 0 then it turns into UINT32_MAX, which indicates the iterator is
|
||||||
@ -499,5 +517,100 @@ AllChildrenIterator::GetPreviousChild()
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
IsNativeAnonymousImplementationOfPseudoElement(nsIContent* aContent)
|
||||||
|
{
|
||||||
|
// First, we need a frame. This leads to the tricky issue of what we can
|
||||||
|
// infer if the frame is null.
|
||||||
|
//
|
||||||
|
// Unlike regular nodes, native anonymous content (NAC) gets created during
|
||||||
|
// frame construction, which happens after the main style traversal. This
|
||||||
|
// means that we have to manually resolve style for those nodes shortly after
|
||||||
|
// they're created, either by (a) invoking ResolvePseudoElementStyle (for PE
|
||||||
|
// NAC), or (b) handing the subtree off to Servo for a mini-traversal (for
|
||||||
|
// non-PE NAC). We have assertions in nsCSSFrameConstructor that we don't do
|
||||||
|
// both.
|
||||||
|
//
|
||||||
|
// Once that happens, the NAC has a frame. So if we have no frame here,
|
||||||
|
// we're either not NAC, or in the process of doing (b). Either way, this
|
||||||
|
// isn't a PE.
|
||||||
|
nsIFrame* f = aContent->GetPrimaryFrame();
|
||||||
|
if (!f) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the pseudo type.
|
||||||
|
CSSPseudoElementType pseudoType = f->StyleContext()->GetPseudoType();
|
||||||
|
|
||||||
|
// In general nodes never get anonymous box style. However, there are a few
|
||||||
|
// special cases:
|
||||||
|
//
|
||||||
|
// * We somewhat-confusingly give text nodes a style context tagged with
|
||||||
|
// ":-moz-text", so we need to check for the anonymous box case here.
|
||||||
|
// * The primary frame for table elements is an anonymous box that inherits
|
||||||
|
// from the table's style.
|
||||||
|
if (pseudoType == CSSPseudoElementType::AnonBox) {
|
||||||
|
MOZ_ASSERT(f->StyleContext()->GetPseudo() == nsCSSAnonBoxes::mozText ||
|
||||||
|
f->StyleContext()->GetPseudo() == nsCSSAnonBoxes::tableWrapper);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally check the actual pseudo type.
|
||||||
|
bool isImpl = pseudoType != CSSPseudoElementType::NotPseudo;
|
||||||
|
MOZ_ASSERT_IF(isImpl, aContent->IsRootOfNativeAnonymousSubtree());
|
||||||
|
return isImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
StyleChildrenIterator::IsNeeded(Element* aElement)
|
||||||
|
{
|
||||||
|
// If the node is in an anonymous subtree, we conservatively return true to
|
||||||
|
// handle insertion points.
|
||||||
|
if (aElement->IsInAnonymousSubtree()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the node has an XBL binding with anonymous content return true.
|
||||||
|
if (aElement->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
||||||
|
nsBindingManager* manager = aElement->OwnerDoc()->BindingManager();
|
||||||
|
nsXBLBinding* binding = manager->GetBindingWithContent(aElement);
|
||||||
|
if (binding && binding->GetAnonymousContent()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the node has native anonymous content, return true.
|
||||||
|
nsIAnonymousContentCreator* ac = do_QueryFrame(aElement->GetPrimaryFrame());
|
||||||
|
if (ac) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The root element has a scroll frame that is not the primary frame, so we
|
||||||
|
// need to do special checking for that case.
|
||||||
|
if (aElement == aElement->OwnerDoc()->GetRootElement()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
nsIContent*
|
||||||
|
StyleChildrenIterator::GetNextChild()
|
||||||
|
{
|
||||||
|
while (nsIContent* child = AllChildrenIterator::GetNextChild()) {
|
||||||
|
if (IsNativeAnonymousImplementationOfPseudoElement(child)) {
|
||||||
|
// Skip any native-anonymous children that are used to implement pseudo-
|
||||||
|
// elements. These match pseudo-element selectors instead of being
|
||||||
|
// considered a child of their host, and thus the style system needs to
|
||||||
|
// handle them separately.
|
||||||
|
} else {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -225,6 +225,10 @@ public:
|
|||||||
IteratorPhase Phase() const { return mPhase; }
|
IteratorPhase Phase() const { return mPhase; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Helpers.
|
||||||
|
void AppendNativeAnonymousChildren();
|
||||||
|
void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame);
|
||||||
|
|
||||||
nsIContent* mOriginalContent;
|
nsIContent* mOriginalContent;
|
||||||
|
|
||||||
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
|
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
|
||||||
@ -245,6 +249,33 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StyleChildrenIterator traverses the children of the element from the
|
||||||
|
* perspective of the style system, particularly the children we need to traverse
|
||||||
|
* during restyle. This is identical to AllChildrenIterator with eAllChildren,
|
||||||
|
* _except_ that we detect and skip any native anonymous children that are used
|
||||||
|
* to implement pseudo-elements (since the style system needs to cascade those
|
||||||
|
* using different algorithms).
|
||||||
|
*
|
||||||
|
* Note: it assumes that no mutation of the DOM or frame tree takes place during
|
||||||
|
* iteration, and will break horribly if that is not true.
|
||||||
|
*/
|
||||||
|
class StyleChildrenIterator : private AllChildrenIterator {
|
||||||
|
public:
|
||||||
|
explicit StyleChildrenIterator(nsIContent* aContent)
|
||||||
|
: AllChildrenIterator(aContent, nsIContent::eAllChildren)
|
||||||
|
{
|
||||||
|
MOZ_COUNT_CTOR(StyleChildrenIterator);
|
||||||
|
}
|
||||||
|
~StyleChildrenIterator() { MOZ_COUNT_DTOR(StyleChildrenIterator); }
|
||||||
|
|
||||||
|
nsIContent* GetNextChild();
|
||||||
|
|
||||||
|
// Returns true if we cannot find all the children we need to style by
|
||||||
|
// traversing the siblings of the first child.
|
||||||
|
static bool IsNeeded(Element* aParent);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
@ -1732,6 +1732,18 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It would be cleanest to mark nodes as dirty when (a) they're created and
|
||||||
|
// (b) they're unbound from a tree. However, we can't easily do (a) right now,
|
||||||
|
// because IsStyledByServo() is not always easy to check at node creation time,
|
||||||
|
// and the bits have different meaning in the non-IsStyledByServo case.
|
||||||
|
//
|
||||||
|
// So for now, we just mark nodes as dirty when they're inserted into a
|
||||||
|
// document or shadow tree.
|
||||||
|
if (IsStyledByServo() && IsInComposedDoc()) {
|
||||||
|
MOZ_ASSERT(!ServoData().get());
|
||||||
|
SetIsDirtyForServo();
|
||||||
|
}
|
||||||
|
|
||||||
// XXXbz script execution during binding can trigger some of these
|
// XXXbz script execution during binding can trigger some of these
|
||||||
// postcondition asserts.... But we do want that, since things will
|
// postcondition asserts.... But we do want that, since things will
|
||||||
// generally be quite broken when that happens.
|
// generally be quite broken when that happens.
|
||||||
@ -1840,11 +1852,15 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||||||
|
|
||||||
ClearInDocument();
|
ClearInDocument();
|
||||||
|
|
||||||
|
// Computed styled data isn't useful for detached nodes, and we'll need to
|
||||||
|
// recomputed it anyway if we ever insert the nodes back into a document.
|
||||||
|
if (IsStyledByServo()) {
|
||||||
|
ServoData().reset();
|
||||||
|
} else {
|
||||||
#ifdef MOZ_STYLO
|
#ifdef MOZ_STYLO
|
||||||
// Drop any servo node data, since it will generally need to be recomputed on
|
MOZ_ASSERT(!ServoData());
|
||||||
// re-insertion anyway.
|
|
||||||
ServoData().reset();
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Editable descendant count only counts descendants that
|
// Editable descendant count only counts descendants that
|
||||||
// are in the uncomposed document.
|
// are in the uncomposed document.
|
||||||
|
@ -2387,3 +2387,51 @@ FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
|
|||||||
shadowRoot = shadowRoot->GetOlderShadowRoot();
|
shadowRoot = shadowRoot->GetOlderShadowRoot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
static void
|
||||||
|
AssertDirtyDescendantsBitPropagated(nsINode* aNode)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aNode->HasDirtyDescendantsForServo());
|
||||||
|
nsINode* parent = aNode->GetFlattenedTreeParentNode();
|
||||||
|
if (!parent->IsContent()) {
|
||||||
|
MOZ_ASSERT(parent == aNode->OwnerDoc());
|
||||||
|
MOZ_ASSERT(parent->HasDirtyDescendantsForServo());
|
||||||
|
} else {
|
||||||
|
AssertDirtyDescendantsBitPropagated(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void AssertDirtyDescendantsBitPropagated(nsINode* aNode) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
nsIContent::MarkAncestorsAsHavingDirtyDescendantsForServo()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(IsInComposedDoc());
|
||||||
|
|
||||||
|
// Get the parent in the flattened tree.
|
||||||
|
nsINode* parent = GetFlattenedTreeParentNode();
|
||||||
|
|
||||||
|
// Loop until we hit a base case.
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
// Base case: the document.
|
||||||
|
if (!parent->IsContent()) {
|
||||||
|
MOZ_ASSERT(parent == OwnerDoc());
|
||||||
|
parent->SetHasDirtyDescendantsForServo();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base case: the parent is already marked, and therefore
|
||||||
|
// so are all its ancestors.
|
||||||
|
if (parent->HasDirtyDescendantsForServo()) {
|
||||||
|
AssertDirtyDescendantsBitPropagated(parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the parent and iterate.
|
||||||
|
parent->SetHasDirtyDescendantsForServo();
|
||||||
|
parent = parent->GetFlattenedTreeParentNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1468,7 +1468,7 @@ nsIDocument::nsIDocument()
|
|||||||
mHasScrollLinkedEffect(false),
|
mHasScrollLinkedEffect(false),
|
||||||
mUserHasInteracted(false)
|
mUserHasInteracted(false)
|
||||||
{
|
{
|
||||||
SetIsDocument();
|
SetIsInDocument();
|
||||||
|
|
||||||
PR_INIT_CLIST(&mDOMMediaQueryLists);
|
PR_INIT_CLIST(&mDOMMediaQueryLists);
|
||||||
}
|
}
|
||||||
|
@ -559,6 +559,18 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||||||
|
|
||||||
UpdateEditableState(false);
|
UpdateEditableState(false);
|
||||||
|
|
||||||
|
// It would be cleanest to mark nodes as dirty when (a) they're created and
|
||||||
|
// (b) they're unbound from a tree. However, we can't easily do (a) right now,
|
||||||
|
// because IsStyledByServo() is not always easy to check at node creation time,
|
||||||
|
// and the bits have different meaning in the non-IsStyledByServo case.
|
||||||
|
//
|
||||||
|
// So for now, we just mark nodes as dirty when they're inserted into a
|
||||||
|
// document or shadow tree.
|
||||||
|
if (IsStyledByServo() && IsInComposedDoc()) {
|
||||||
|
MOZ_ASSERT(!ServoData().get());
|
||||||
|
SetIsDirtyForServo();
|
||||||
|
}
|
||||||
|
|
||||||
NS_POSTCONDITION(aDocument == GetUncomposedDoc(), "Bound to wrong document");
|
NS_POSTCONDITION(aDocument == GetUncomposedDoc(), "Bound to wrong document");
|
||||||
NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
|
NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
|
||||||
NS_POSTCONDITION(aBindingParent == GetBindingParent(),
|
NS_POSTCONDITION(aBindingParent == GetBindingParent(),
|
||||||
@ -590,11 +602,15 @@ nsGenericDOMDataNode::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||||||
}
|
}
|
||||||
ClearInDocument();
|
ClearInDocument();
|
||||||
|
|
||||||
|
// Computed styled data isn't useful for detached nodes, and we'll need to
|
||||||
|
// recomputed it anyway if we ever insert the nodes back into a document.
|
||||||
|
if (IsStyledByServo()) {
|
||||||
|
ServoData().reset();
|
||||||
|
} else {
|
||||||
#ifdef MOZ_STYLO
|
#ifdef MOZ_STYLO
|
||||||
// Drop any servo node data, since it will generally need to be recomputed on
|
MOZ_ASSERT(!ServoData());
|
||||||
// re-insertion anyway.
|
|
||||||
ServoData().reset();
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (aNullParent || !mParent->IsInShadowTree()) {
|
if (aNullParent || !mParent->IsInShadowTree()) {
|
||||||
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
|
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||||
|
@ -938,6 +938,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
mozilla::dom::Element* GetEditingHost();
|
mozilla::dom::Element* GetEditingHost();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO all the way up the flattened
|
||||||
|
* parent chain to the document. If an ancestor is found with the bit already
|
||||||
|
* set, this method asserts that all of its ancestors also have the bit set.
|
||||||
|
*/
|
||||||
|
void MarkAncestorsAsHavingDirtyDescendantsForServo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determining language. Look at the nearest ancestor element that has a lang
|
* Determining language. Look at the nearest ancestor element that has a lang
|
||||||
* attribute in the XML namespace or is an HTML/SVG element and has a lang in
|
* attribute in the XML namespace or is an HTML/SVG element and has a lang in
|
||||||
|
@ -1000,33 +1000,48 @@ public:
|
|||||||
bool IsStyledByServo() const { return false; }
|
bool IsStyledByServo() const { return false; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline bool IsDirtyForServo() const
|
bool IsDirtyForServo() const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsStyledByServo());
|
MOZ_ASSERT(IsStyledByServo());
|
||||||
return HasFlag(NODE_IS_DIRTY_FOR_SERVO);
|
return HasFlag(NODE_IS_DIRTY_FOR_SERVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool HasDirtyDescendantsForServo() const
|
bool HasDirtyDescendantsForServo() const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsStyledByServo());
|
MOZ_ASSERT(IsStyledByServo());
|
||||||
return HasFlag(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
|
return HasFlag(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SetIsDirtyForServo() {
|
void SetIsDirtyForServo() {
|
||||||
MOZ_ASSERT(IsStyledByServo());
|
MOZ_ASSERT(IsStyledByServo());
|
||||||
SetFlags(NODE_IS_DIRTY_FOR_SERVO);
|
SetFlags(NODE_IS_DIRTY_FOR_SERVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SetHasDirtyDescendantsForServo() {
|
void SetHasDirtyDescendantsForServo() {
|
||||||
MOZ_ASSERT(IsStyledByServo());
|
MOZ_ASSERT(IsStyledByServo());
|
||||||
SetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
|
SetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SetIsDirtyAndHasDirtyDescendantsForServo() {
|
void SetIsDirtyAndHasDirtyDescendantsForServo() {
|
||||||
MOZ_ASSERT(IsStyledByServo());
|
MOZ_ASSERT(IsStyledByServo());
|
||||||
SetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO | NODE_IS_DIRTY_FOR_SERVO);
|
SetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO | NODE_IS_DIRTY_FOR_SERVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UnsetIsDirtyForServo() {
|
||||||
|
MOZ_ASSERT(IsStyledByServo());
|
||||||
|
UnsetFlags(NODE_IS_DIRTY_FOR_SERVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnsetHasDirtyDescendantsForServo() {
|
||||||
|
MOZ_ASSERT(IsStyledByServo());
|
||||||
|
UnsetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnsetIsDirtyAndHasDirtyDescendantsForServo() {
|
||||||
|
MOZ_ASSERT(IsStyledByServo());
|
||||||
|
UnsetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO | NODE_IS_DIRTY_FOR_SERVO);
|
||||||
|
}
|
||||||
|
|
||||||
inline void UnsetRestyleFlagsIfGecko();
|
inline void UnsetRestyleFlagsIfGecko();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1751,17 +1766,7 @@ public:
|
|||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
|
void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
|
||||||
/**
|
void SetIsInDocument() { SetBoolFlag(IsInDocument); }
|
||||||
* This is a special case of SetIsInDocument used to special-case it for the
|
|
||||||
* document constructor (which can't do the IsStyledByServo() check).
|
|
||||||
*/
|
|
||||||
void SetIsDocument() { SetBoolFlag(IsInDocument); }
|
|
||||||
void SetIsInDocument() {
|
|
||||||
if (IsStyledByServo()) {
|
|
||||||
SetIsDirtyAndHasDirtyDescendantsForServo();
|
|
||||||
}
|
|
||||||
SetBoolFlag(IsInDocument);
|
|
||||||
}
|
|
||||||
void SetNodeIsContent() { SetBoolFlag(NodeIsContent); }
|
void SetNodeIsContent() { SetBoolFlag(NodeIsContent); }
|
||||||
void ClearInDocument() { ClearBoolFlag(IsInDocument); }
|
void ClearInDocument() { ClearBoolFlag(IsInDocument); }
|
||||||
void SetIsElement() { SetBoolFlag(NodeIsElement); }
|
void SetIsElement() { SetBoolFlag(NodeIsElement); }
|
||||||
|
@ -226,6 +226,8 @@ HTMLMenuElement::TraverseContent(nsIContent* aContent,
|
|||||||
aBuilder->AddItemFor(menuitem, CanLoadIcon(child, icon));
|
aBuilder->AddItemFor(menuitem, CanLoadIcon(child, icon));
|
||||||
|
|
||||||
aSeparator = ST_FALSE;
|
aSeparator = ST_FALSE;
|
||||||
|
} else if (child->IsHTMLElement(nsGkAtoms::hr)) {
|
||||||
|
aBuilder->AddSeparator();
|
||||||
} else if (child->IsHTMLElement(nsGkAtoms::menu) && !element->IsHidden()) {
|
} else if (child->IsHTMLElement(nsGkAtoms::menu) && !element->IsHidden()) {
|
||||||
if (child->HasAttr(kNameSpaceID_None, nsGkAtoms::label)) {
|
if (child->HasAttr(kNameSpaceID_None, nsGkAtoms::label)) {
|
||||||
nsAutoString label;
|
nsAutoString label;
|
||||||
|
@ -23,7 +23,12 @@ add_task(function* () {
|
|||||||
let pageMenuSep = document.getElementById("page-menu-separator");
|
let pageMenuSep = document.getElementById("page-menu-separator");
|
||||||
ok(pageMenuSep && !pageMenuSep.hidden,
|
ok(pageMenuSep && !pageMenuSep.hidden,
|
||||||
"Page menu separator should be shown");
|
"Page menu separator should be shown");
|
||||||
let testMenuItem = pageMenuSep.previousSibling;
|
|
||||||
|
let testMenuSep = pageMenuSep.previousSibling;
|
||||||
|
ok(testMenuSep && !testMenuSep.hidden,
|
||||||
|
"User-added menu separator should be shown");
|
||||||
|
|
||||||
|
let testMenuItem = testMenuSep.previousSibling;
|
||||||
is(testMenuItem.label, "Test Context Menu Click", "Got context menu item");
|
is(testMenuItem.label, "Test Context Menu Click", "Got context menu item");
|
||||||
|
|
||||||
let promiseCtxMenuClick = ContentTask.spawn(aBrowser, null, function*() {
|
let promiseCtxMenuClick = ContentTask.spawn(aBrowser, null, function*() {
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
</head>
|
</head>
|
||||||
<body contextmenu="testmenu">
|
<body contextmenu="testmenu">
|
||||||
<menu type="context" id="testmenu">
|
<menu type="context" id="testmenu">
|
||||||
<menuitem label="Test Context Menu Click" id="menuitem">
|
<menuitem label="Test Context Menu Click" id="menuitem"></menuitem>
|
||||||
|
<hr>
|
||||||
</menu>
|
</menu>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -304,10 +304,8 @@ nsPluginHost::nsPluginHost()
|
|||||||
Preferences::GetBool("plugin.override_internal_types", false);
|
Preferences::GetBool("plugin.override_internal_types", false);
|
||||||
|
|
||||||
mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
|
mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
|
||||||
mPluginsClickToPlay = Preferences::GetBool("plugins.click_to_play", false);
|
|
||||||
|
|
||||||
Preferences::AddStrongObserver(this, "plugin.disable");
|
Preferences::AddStrongObserver(this, "plugin.disable");
|
||||||
Preferences::AddStrongObserver(this, "plugins.click_to_play");
|
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> obsService =
|
nsCOMPtr<nsIObserverService> obsService =
|
||||||
mozilla::services::GetObserverService();
|
mozilla::services::GetObserverService();
|
||||||
@ -3624,7 +3622,6 @@ NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
|
|||||||
}
|
}
|
||||||
if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
|
if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
|
||||||
mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
|
mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
|
||||||
mPluginsClickToPlay = Preferences::GetBool("plugins.click_to_play", false);
|
|
||||||
// Unload or load plugins as needed
|
// Unload or load plugins as needed
|
||||||
if (mPluginsDisabled) {
|
if (mPluginsDisabled) {
|
||||||
UnloadPlugins();
|
UnloadPlugins();
|
||||||
|
@ -386,8 +386,6 @@ private:
|
|||||||
|
|
||||||
// set by pref plugin.disable
|
// set by pref plugin.disable
|
||||||
bool mPluginsDisabled;
|
bool mPluginsDisabled;
|
||||||
// set by pref plugins.click_to_play
|
|
||||||
bool mPluginsClickToPlay;
|
|
||||||
|
|
||||||
// Any instances in this array will have valid plugin objects via GetPlugin().
|
// Any instances in this array will have valid plugin objects via GetPlugin().
|
||||||
// When removing an instance it might not die - be sure to null out it's plugin.
|
// When removing an instance it might not die - be sure to null out it's plugin.
|
||||||
|
@ -65,10 +65,55 @@ function compileManySuccess() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function compileInWorker() {
|
||||||
|
var w = new Worker(`data:text/plain,
|
||||||
|
onmessage = e => {
|
||||||
|
WebAssembly.compile(e.data).then(m => {
|
||||||
|
var i = new WebAssembly.Instance(m);
|
||||||
|
if (i.exports.foo() !== 42)
|
||||||
|
throw "bad i.exports.foo() result";
|
||||||
|
postMessage("ok");
|
||||||
|
close();
|
||||||
|
}).catch(err => { throw err });
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
w.postMessage(fooModuleCode);
|
||||||
|
w.onmessage = e => {
|
||||||
|
ok(e.data === "ok", "worker test");
|
||||||
|
runTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function terminateCompileInWorker() {
|
||||||
|
var w = new Worker(`data:text/plain,
|
||||||
|
var fooModuleCode;
|
||||||
|
function spawnWork() {
|
||||||
|
const N = 100;
|
||||||
|
var arr = [];
|
||||||
|
for (var i = 0; i < N; i++)
|
||||||
|
arr.push(WebAssembly.compile(fooModuleCode));
|
||||||
|
Promise.all(arr).then(spawnWork);
|
||||||
|
}
|
||||||
|
onmessage = e => {
|
||||||
|
fooModuleCode = e.data;
|
||||||
|
spawnWork();
|
||||||
|
postMessage("ok");
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
w.postMessage(fooModuleCode);
|
||||||
|
w.onmessage = e => {
|
||||||
|
ok(e.data === "ok", "worker finished first step");
|
||||||
|
w.terminate();
|
||||||
|
runTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var tests = [ propertiesExist,
|
var tests = [ propertiesExist,
|
||||||
compileFail,
|
compileFail,
|
||||||
compileSuccess,
|
compileSuccess,
|
||||||
compileManySuccess
|
compileManySuccess,
|
||||||
|
compileInWorker,
|
||||||
|
terminateCompileInWorker
|
||||||
];
|
];
|
||||||
|
|
||||||
function runTest() {
|
function runTest() {
|
||||||
|
@ -269,16 +269,6 @@ SVGUseElement::CreateAnonymousContent()
|
|||||||
if (!newcontent)
|
if (!newcontent)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
// Our anonymous clone can get restyled by various things
|
|
||||||
// (e.g. SMIL). Reconstructing its frame is OK, though, because
|
|
||||||
// it's going to be our _only_ child in the frame tree, so can't get
|
|
||||||
// mis-ordered with anything.
|
|
||||||
newcontent->SetProperty(nsGkAtoms::restylableAnonymousNode,
|
|
||||||
reinterpret_cast<void*>(true));
|
|
||||||
#endif // DEBUG
|
|
||||||
|
|
||||||
|
|
||||||
if (newcontent->IsSVGElement(nsGkAtoms::symbol)) {
|
if (newcontent->IsSVGElement(nsGkAtoms::symbol)) {
|
||||||
nsIDocument *document = GetComposedDoc();
|
nsIDocument *document = GetComposedDoc();
|
||||||
if (!document)
|
if (!document)
|
||||||
@ -341,6 +331,16 @@ SVGUseElement::CreateAnonymousContent()
|
|||||||
|
|
||||||
targetContent->AddMutationObserver(this);
|
targetContent->AddMutationObserver(this);
|
||||||
mClone = newcontent;
|
mClone = newcontent;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Our anonymous clone can get restyled by various things
|
||||||
|
// (e.g. SMIL). Reconstructing its frame is OK, though, because
|
||||||
|
// it's going to be our _only_ child in the frame tree, so can't get
|
||||||
|
// mis-ordered with anything.
|
||||||
|
mClone->SetProperty(nsGkAtoms::restylableAnonymousNode,
|
||||||
|
reinterpret_cast<void*>(true));
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
return mClone;
|
return mClone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
dom/svg/crashtests/1250725.html
Normal file
16
dom/svg/crashtests/1250725.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function boom()
|
||||||
|
{
|
||||||
|
document.getElementById("u").setAttribute("width", "30");
|
||||||
|
document.getElementById("p").remove();
|
||||||
|
}
|
||||||
|
window.addEventListener("load", boom, false);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<symbol id="p" viewBox="0 0 100 20"/>
|
||||||
|
|
||||||
|
<use id="u" xlink:href="#p"/>
|
||||||
|
|
||||||
|
</svg>
|
After Width: | Height: | Size: 393 B |
@ -75,6 +75,7 @@ load 898915-1.svg
|
|||||||
load 1035248-1.svg
|
load 1035248-1.svg
|
||||||
load 1035248-2.svg
|
load 1035248-2.svg
|
||||||
load 1244898-1.xhtml
|
load 1244898-1.xhtml
|
||||||
|
load 1250725.html
|
||||||
load 1267272-1.svg
|
load 1267272-1.svg
|
||||||
load 1282985-1.svg
|
load 1282985-1.svg
|
||||||
# Disabled for now due to it taking a very long time to run - bug 1259356
|
# Disabled for now due to it taking a very long time to run - bug 1259356
|
||||||
|
@ -352,7 +352,7 @@ VRPose::GetLinearAcceleration(JSContext* aCx,
|
|||||||
JS::MutableHandle<JSObject*> aRetval,
|
JS::MutableHandle<JSObject*> aRetval,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
if (!mLinearAcceleration && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position) {
|
if (!mLinearAcceleration && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_LinearAcceleration) {
|
||||||
// Lazily create the Float32Array
|
// Lazily create the Float32Array
|
||||||
mLinearAcceleration = dom::Float32Array::Create(aCx, this, 3, mVRState.linearAcceleration);
|
mLinearAcceleration = dom::Float32Array::Create(aCx, this, 3, mVRState.linearAcceleration);
|
||||||
if (!mLinearAcceleration) {
|
if (!mLinearAcceleration) {
|
||||||
@ -409,7 +409,7 @@ VRPose::GetAngularAcceleration(JSContext* aCx,
|
|||||||
JS::MutableHandle<JSObject*> aRetval,
|
JS::MutableHandle<JSObject*> aRetval,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
if (!mAngularAcceleration && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation) {
|
if (!mAngularAcceleration && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_AngularAcceleration) {
|
||||||
// Lazily create the Float32Array
|
// Lazily create the Float32Array
|
||||||
mAngularAcceleration = dom::Float32Array::Create(aCx, this, 3, mVRState.angularAcceleration);
|
mAngularAcceleration = dom::Float32Array::Create(aCx, this, 3, mVRState.angularAcceleration);
|
||||||
if (!mAngularAcceleration) {
|
if (!mAngularAcceleration) {
|
||||||
@ -441,9 +441,15 @@ VRDisplay::VRDisplay(nsPIDOMWindowInner* aWindow, gfx::VRDisplayClient* aClient)
|
|||||||
, mDepthNear(0.01f) // Default value from WebVR Spec
|
, mDepthNear(0.01f) // Default value from WebVR Spec
|
||||||
, mDepthFar(10000.0f) // Default value from WebVR Spec
|
, mDepthFar(10000.0f) // Default value from WebVR Spec
|
||||||
{
|
{
|
||||||
mDisplayId = aClient->GetDisplayInfo().GetDisplayID();
|
const gfx::VRDisplayInfo& info = aClient->GetDisplayInfo();
|
||||||
mDisplayName = NS_ConvertASCIItoUTF16(aClient->GetDisplayInfo().GetDisplayName());
|
mDisplayId = info.GetDisplayID();
|
||||||
mCapabilities = new VRDisplayCapabilities(aWindow, aClient->GetDisplayInfo().GetCapabilities());
|
mDisplayName = NS_ConvertASCIItoUTF16(info.GetDisplayName());
|
||||||
|
mCapabilities = new VRDisplayCapabilities(aWindow, info.GetCapabilities());
|
||||||
|
if (info.GetCapabilities() & gfx::VRDisplayCapabilityFlags::Cap_StageParameters) {
|
||||||
|
mStageParameters = new VRStageParameters(aWindow,
|
||||||
|
info.GetSittingToStandingTransform(),
|
||||||
|
info.GetStageSize());
|
||||||
|
}
|
||||||
mozilla::HoldJSObjects(this);
|
mozilla::HoldJSObjects(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,9 +488,7 @@ VRDisplay::Capabilities()
|
|||||||
VRStageParameters*
|
VRStageParameters*
|
||||||
VRDisplay::GetStageParameters()
|
VRDisplay::GetStageParameters()
|
||||||
{
|
{
|
||||||
// XXX When we implement room scale experiences for OpenVR, we should return
|
return mStageParameters;
|
||||||
// something here.
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<VRPose>
|
already_AddRefed<VRPose>
|
||||||
@ -645,7 +649,7 @@ VRDisplay::IsConnected() const
|
|||||||
return mClient->GetIsConnected();
|
return mClient->GetIsConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(VRDisplay, DOMEventTargetHelper, mCapabilities)
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(VRDisplay, DOMEventTargetHelper, mCapabilities, mStageParameters)
|
||||||
|
|
||||||
NS_IMPL_ADDREF_INHERITED(VRDisplay, DOMEventTargetHelper)
|
NS_IMPL_ADDREF_INHERITED(VRDisplay, DOMEventTargetHelper)
|
||||||
NS_IMPL_RELEASE_INHERITED(VRDisplay, DOMEventTargetHelper)
|
NS_IMPL_RELEASE_INHERITED(VRDisplay, DOMEventTargetHelper)
|
||||||
|
@ -283,6 +283,7 @@ protected:
|
|||||||
nsString mDisplayName;
|
nsString mDisplayName;
|
||||||
|
|
||||||
RefPtr<VRDisplayCapabilities> mCapabilities;
|
RefPtr<VRDisplayCapabilities> mCapabilities;
|
||||||
|
RefPtr<VRStageParameters> mStageParameters;
|
||||||
|
|
||||||
double mDepthNear;
|
double mDepthNear;
|
||||||
double mDepthFar;
|
double mDepthFar;
|
||||||
|
@ -713,6 +713,185 @@ AsmJSCacheOpenEntryForWrite(JS::Handle<JSObject*> aGlobal,
|
|||||||
aSize, aMemory, aHandle);
|
aSize, aMemory, aHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AsyncTaskWorkerHolder final : public WorkerHolder
|
||||||
|
{
|
||||||
|
bool Notify(Status aStatus) override
|
||||||
|
{
|
||||||
|
// The async task must complete in bounded time and there is not (currently)
|
||||||
|
// a clean way to cancel it. Async tasks do not run arbitrary content.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
WorkerPrivate* Worker() const
|
||||||
|
{
|
||||||
|
return mWorkerPrivate;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class RunnableBase>
|
||||||
|
class AsyncTaskBase : public RunnableBase
|
||||||
|
{
|
||||||
|
UniquePtr<AsyncTaskWorkerHolder> mHolder;
|
||||||
|
|
||||||
|
// Disable the usual pre/post-dispatch thread assertions since we are
|
||||||
|
// dispatching from some random JS engine internal thread:
|
||||||
|
|
||||||
|
bool PreDispatch(WorkerPrivate* aWorkerPrivate) override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit AsyncTaskBase(UniquePtr<AsyncTaskWorkerHolder> aHolder)
|
||||||
|
: RunnableBase(aHolder->Worker(),
|
||||||
|
WorkerRunnable::WorkerThreadUnchangedBusyCount)
|
||||||
|
, mHolder(Move(aHolder))
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncTaskBase()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyHolder()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mHolder);
|
||||||
|
mHolder.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
UniquePtr<AsyncTaskWorkerHolder> StealHolder()
|
||||||
|
{
|
||||||
|
return Move(mHolder);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncTaskRunnable final : public AsyncTaskBase<WorkerRunnable>
|
||||||
|
{
|
||||||
|
JS::AsyncTask* mTask;
|
||||||
|
|
||||||
|
~AsyncTaskRunnable()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
|
||||||
|
{
|
||||||
|
// For the benefit of the destructor assert.
|
||||||
|
if (!aDispatchResult) {
|
||||||
|
mTask = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncTaskRunnable(UniquePtr<AsyncTaskWorkerHolder> aHolder,
|
||||||
|
JS::AsyncTask* aTask)
|
||||||
|
: AsyncTaskBase<WorkerRunnable>(Move(aHolder))
|
||||||
|
, mTask(aTask)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aWorkerPrivate == mWorkerPrivate);
|
||||||
|
MOZ_ASSERT(aCx == mWorkerPrivate->GetJSContext());
|
||||||
|
MOZ_ASSERT(mTask);
|
||||||
|
|
||||||
|
AutoJSAPI jsapi;
|
||||||
|
jsapi.Init();
|
||||||
|
|
||||||
|
mTask->finish(mWorkerPrivate->GetJSContext());
|
||||||
|
mTask = nullptr; // mTask may delete itself
|
||||||
|
|
||||||
|
DestroyHolder();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult Cancel() override
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mTask);
|
||||||
|
|
||||||
|
AutoJSAPI jsapi;
|
||||||
|
jsapi.Init();
|
||||||
|
|
||||||
|
mTask->cancel(mWorkerPrivate->GetJSContext());
|
||||||
|
mTask = nullptr; // mTask may delete itself
|
||||||
|
|
||||||
|
DestroyHolder();
|
||||||
|
|
||||||
|
return WorkerRunnable::Cancel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncTaskControlRunnable final
|
||||||
|
: public AsyncTaskBase<WorkerControlRunnable>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AsyncTaskControlRunnable(UniquePtr<AsyncTaskWorkerHolder> aHolder)
|
||||||
|
: AsyncTaskBase<WorkerControlRunnable>(Move(aHolder))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||||
|
{
|
||||||
|
// See comment in FinishAsyncTaskCallback.
|
||||||
|
DestroyHolder();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool
|
||||||
|
StartAsyncTaskCallback(JSContext* aCx, JS::AsyncTask* aTask)
|
||||||
|
{
|
||||||
|
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
|
||||||
|
worker->AssertIsOnWorkerThread();
|
||||||
|
|
||||||
|
auto holder = MakeUnique<AsyncTaskWorkerHolder>();
|
||||||
|
if (!holder->HoldWorker(worker, Status::Closing)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matched by a UniquePtr in FinishAsyncTaskCallback which, by
|
||||||
|
// interface contract, must be called in the future.
|
||||||
|
aTask->user = holder.release();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
FinishAsyncTaskCallback(JS::AsyncTask* aTask)
|
||||||
|
{
|
||||||
|
// May execute either on the worker thread or a random JS-internal helper
|
||||||
|
// thread.
|
||||||
|
|
||||||
|
// Match the release() in StartAsyncTaskCallback.
|
||||||
|
UniquePtr<AsyncTaskWorkerHolder> holder(
|
||||||
|
static_cast<AsyncTaskWorkerHolder*>(aTask->user));
|
||||||
|
|
||||||
|
RefPtr<AsyncTaskRunnable> r = new AsyncTaskRunnable(Move(holder), aTask);
|
||||||
|
|
||||||
|
// WorkerRunnable::Dispatch() can fail during worker shutdown. In that case,
|
||||||
|
// report failure back to the JS engine but make sure to release the
|
||||||
|
// WorkerHolder on the worker thread using a control runnable. Control
|
||||||
|
// runables aren't suitable for calling AsyncTask::finish() since they are run
|
||||||
|
// via the interrupt callback which breaks JS run-to-completion.
|
||||||
|
if (!r->Dispatch()) {
|
||||||
|
RefPtr<AsyncTaskControlRunnable> cr =
|
||||||
|
new AsyncTaskControlRunnable(r->StealHolder());
|
||||||
|
|
||||||
|
MOZ_ALWAYS_TRUE(cr->Dispatch());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
class WorkerJSRuntime;
|
class WorkerJSRuntime;
|
||||||
|
|
||||||
class WorkerThreadContextPrivate : private PerThreadAtomCache
|
class WorkerThreadContextPrivate : private PerThreadAtomCache
|
||||||
@ -808,6 +987,8 @@ InitJSContextForWorker(WorkerPrivate* aWorkerPrivate, JSContext* aWorkerCx)
|
|||||||
};
|
};
|
||||||
JS::SetAsmJSCacheOps(aWorkerCx, &asmJSCacheOps);
|
JS::SetAsmJSCacheOps(aWorkerCx, &asmJSCacheOps);
|
||||||
|
|
||||||
|
JS::SetAsyncTaskCallbacks(aWorkerCx, StartAsyncTaskCallback, FinishAsyncTaskCallback);
|
||||||
|
|
||||||
if (!JS::InitSelfHostedCode(aWorkerCx)) {
|
if (!JS::InitSelfHostedCode(aWorkerCx)) {
|
||||||
NS_WARNING("Could not init self-hosted code!");
|
NS_WARNING("Could not init self-hosted code!");
|
||||||
return false;
|
return false;
|
||||||
|
@ -206,10 +206,6 @@ nsXBLBinding::InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElem
|
|||||||
// (2) The children's parent back pointer should not be to this synthetic root
|
// (2) The children's parent back pointer should not be to this synthetic root
|
||||||
// but should instead point to the enclosing parent element.
|
// but should instead point to the enclosing parent element.
|
||||||
nsIDocument* doc = aElement->GetUncomposedDoc();
|
nsIDocument* doc = aElement->GetUncomposedDoc();
|
||||||
ServoStyleSet* servoStyleSet = nullptr;
|
|
||||||
if (nsIPresShell* presShell = aElement->OwnerDoc()->GetShell()) {
|
|
||||||
servoStyleSet = presShell->StyleSet()->GetAsServo();
|
|
||||||
}
|
|
||||||
bool allowScripts = AllowScripts();
|
bool allowScripts = AllowScripts();
|
||||||
|
|
||||||
nsAutoScriptBlocker scriptBlocker;
|
nsAutoScriptBlocker scriptBlocker;
|
||||||
@ -240,10 +236,6 @@ nsXBLBinding::InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElem
|
|||||||
if (xuldoc)
|
if (xuldoc)
|
||||||
xuldoc->AddSubtreeToDocument(child);
|
xuldoc->AddSubtreeToDocument(child);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (servoStyleSet) {
|
|
||||||
servoStyleSet->RestyleSubtree(child);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,6 +420,15 @@ nsXBLBinding::GenerateAnonymousContent()
|
|||||||
if (mContent)
|
if (mContent)
|
||||||
mContent->UnsetAttr(namespaceID, name, false);
|
mContent->UnsetAttr(namespaceID, name, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now that we've finished shuffling the tree around, go ahead and restyle it
|
||||||
|
// since frame construction is about to happen.
|
||||||
|
nsIPresShell* presShell = mBoundElement->OwnerDoc()->GetShell();
|
||||||
|
ServoStyleSet* servoSet = presShell->StyleSet()->GetAsServo();
|
||||||
|
if (servoSet) {
|
||||||
|
mBoundElement->SetHasDirtyDescendantsForServo();
|
||||||
|
servoSet->StyleNewChildren(mBoundElement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XBLChildrenElement*
|
XBLChildrenElement*
|
||||||
|
@ -116,6 +116,12 @@ struct BarrierMethods<nsXBLMaybeCompiled<UncompiledT>>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct IsHeapConstructibleType<nsXBLMaybeCompiled<T>>
|
||||||
|
{ // Yes, this is the exception to the rule. Sorry.
|
||||||
|
static constexpr bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
template <class UncompiledT>
|
template <class UncompiledT>
|
||||||
class HeapBase<nsXBLMaybeCompiled<UncompiledT>>
|
class HeapBase<nsXBLMaybeCompiled<UncompiledT>>
|
||||||
{
|
{
|
||||||
|
@ -311,7 +311,7 @@ DrawTargetSkia::ReleaseBits(uint8_t* aData)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
|
SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0, Point aOffset = Point(0, 0))
|
||||||
{
|
{
|
||||||
switch (aPattern.GetType()) {
|
switch (aPattern.GetType()) {
|
||||||
case PatternType::COLOR: {
|
case PatternType::COLOR: {
|
||||||
@ -333,6 +333,7 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
|
|||||||
|
|
||||||
SkMatrix mat;
|
SkMatrix mat;
|
||||||
GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
|
GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
|
||||||
|
mat.postTranslate(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y));
|
||||||
sk_sp<SkShader> shader = SkGradientShader::MakeLinear(points,
|
sk_sp<SkShader> shader = SkGradientShader::MakeLinear(points,
|
||||||
&stops->mColors.front(),
|
&stops->mColors.front(),
|
||||||
&stops->mPositions.front(),
|
&stops->mPositions.front(),
|
||||||
@ -357,6 +358,7 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
|
|||||||
|
|
||||||
SkMatrix mat;
|
SkMatrix mat;
|
||||||
GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
|
GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
|
||||||
|
mat.postTranslate(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y));
|
||||||
sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(points[0],
|
sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(points[0],
|
||||||
SkFloatToScalar(pat.mRadius1),
|
SkFloatToScalar(pat.mRadius1),
|
||||||
points[1],
|
points[1],
|
||||||
@ -375,6 +377,7 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
|
|||||||
|
|
||||||
SkMatrix mat;
|
SkMatrix mat;
|
||||||
GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
|
GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
|
||||||
|
mat.postTranslate(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y));
|
||||||
|
|
||||||
if (!pat.mSamplingRect.IsEmpty()) {
|
if (!pat.mSamplingRect.IsEmpty()) {
|
||||||
SkIRect rect = IntRectToSkIRect(pat.mSamplingRect);
|
SkIRect rect = IntRectToSkIRect(pat.mSamplingRect);
|
||||||
@ -415,17 +418,17 @@ GetClipBounds(SkCanvas *aCanvas)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct AutoPaintSetup {
|
struct AutoPaintSetup {
|
||||||
AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Pattern& aPattern, const Rect* aMaskBounds = nullptr)
|
AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Pattern& aPattern, const Rect* aMaskBounds = nullptr, Point aOffset = Point(0, 0))
|
||||||
: mNeedsRestore(false), mAlpha(1.0)
|
: mNeedsRestore(false), mAlpha(1.0)
|
||||||
{
|
{
|
||||||
Init(aCanvas, aOptions, aMaskBounds);
|
Init(aCanvas, aOptions, aMaskBounds, false);
|
||||||
SetPaintPattern(mPaint, aPattern, mAlpha);
|
SetPaintPattern(mPaint, aPattern, mAlpha, aOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Rect* aMaskBounds = nullptr)
|
AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Rect* aMaskBounds = nullptr, bool aForceGroup = false)
|
||||||
: mNeedsRestore(false), mAlpha(1.0)
|
: mNeedsRestore(false), mAlpha(1.0)
|
||||||
{
|
{
|
||||||
Init(aCanvas, aOptions, aMaskBounds);
|
Init(aCanvas, aOptions, aMaskBounds, aForceGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
~AutoPaintSetup()
|
~AutoPaintSetup()
|
||||||
@ -435,7 +438,7 @@ struct AutoPaintSetup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init(SkCanvas *aCanvas, const DrawOptions& aOptions, const Rect* aMaskBounds)
|
void Init(SkCanvas *aCanvas, const DrawOptions& aOptions, const Rect* aMaskBounds, bool aForceGroup)
|
||||||
{
|
{
|
||||||
mPaint.setXfermodeMode(GfxOpToSkiaOp(aOptions.mCompositionOp));
|
mPaint.setXfermodeMode(GfxOpToSkiaOp(aOptions.mCompositionOp));
|
||||||
mCanvas = aCanvas;
|
mCanvas = aCanvas;
|
||||||
@ -447,8 +450,9 @@ struct AutoPaintSetup {
|
|||||||
mPaint.setAntiAlias(false);
|
mPaint.setAntiAlias(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsGroup = !IsOperatorBoundByMask(aOptions.mCompositionOp) &&
|
bool needsGroup = aForceGroup ||
|
||||||
(!aMaskBounds || !aMaskBounds->Contains(GetClipBounds(aCanvas)));
|
(!IsOperatorBoundByMask(aOptions.mCompositionOp) &&
|
||||||
|
(!aMaskBounds || !aMaskBounds->Contains(GetClipBounds(aCanvas))));
|
||||||
|
|
||||||
// TODO: We could skip the temporary for operator_source and just
|
// TODO: We could skip the temporary for operator_source and just
|
||||||
// clear the clip rect. The other operators would be harder
|
// clear the clip rect. The other operators would be harder
|
||||||
@ -507,10 +511,11 @@ DrawTargetSkia::DrawSurface(SourceSurface *aSurface,
|
|||||||
|
|
||||||
SkRect destRect = RectToSkRect(aDest);
|
SkRect destRect = RectToSkRect(aDest);
|
||||||
SkRect sourceRect = RectToSkRect(aSource);
|
SkRect sourceRect = RectToSkRect(aSource);
|
||||||
|
|
||||||
SkBitmap bitmap = GetBitmapForSurface(aSurface);
|
SkBitmap bitmap = GetBitmapForSurface(aSurface);
|
||||||
|
bool forceGroup = bitmap.colorType() == kAlpha_8_SkColorType &&
|
||||||
|
aOptions.mCompositionOp != CompositionOp::OP_OVER;
|
||||||
|
|
||||||
AutoPaintSetup paint(mCanvas.get(), aOptions, &aDest);
|
AutoPaintSetup paint(mCanvas.get(), aOptions, &aDest, forceGroup);
|
||||||
if (aSurfOptions.mSamplingFilter == SamplingFilter::POINT) {
|
if (aSurfOptions.mSamplingFilter == SamplingFilter::POINT) {
|
||||||
paint.mPaint.setFilterQuality(kNone_SkFilterQuality);
|
paint.mPaint.setFilterQuality(kNone_SkFilterQuality);
|
||||||
}
|
}
|
||||||
@ -1311,7 +1316,7 @@ DrawTargetSkia::MaskSurface(const Pattern &aSource,
|
|||||||
const DrawOptions &aOptions)
|
const DrawOptions &aOptions)
|
||||||
{
|
{
|
||||||
MarkChanged();
|
MarkChanged();
|
||||||
AutoPaintSetup paint(mCanvas.get(), aOptions, aSource);
|
AutoPaintSetup paint(mCanvas.get(), aOptions, aSource, nullptr, -aOffset);
|
||||||
|
|
||||||
SkBitmap bitmap = GetBitmapForSurface(aMask);
|
SkBitmap bitmap = GetBitmapForSurface(aMask);
|
||||||
if (bitmap.colorType() != kAlpha_8_SkColorType &&
|
if (bitmap.colorType() != kAlpha_8_SkColorType &&
|
||||||
@ -1320,14 +1325,6 @@ DrawTargetSkia::MaskSurface(const Pattern &aSource,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aOffset != Point(0, 0) &&
|
|
||||||
paint.mPaint.getShader()) {
|
|
||||||
SkMatrix transform;
|
|
||||||
transform.setTranslate(PointToSkPoint(-aOffset));
|
|
||||||
sk_sp<SkShader> matrixShader = paint.mPaint.getShader()->makeWithLocalMatrix(transform);
|
|
||||||
paint.mPaint.setShader(matrixShader);
|
|
||||||
}
|
|
||||||
|
|
||||||
mCanvas->drawBitmap(bitmap, aOffset.x, aOffset.y, &paint.mPaint);
|
mCanvas->drawBitmap(bitmap, aOffset.x, aOffset.y, &paint.mPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,9 @@ class gfxVarReceiver;
|
|||||||
_(ContentBackend, BackendType, BackendType::NONE) \
|
_(ContentBackend, BackendType, BackendType::NONE) \
|
||||||
_(TileSize, IntSize, IntSize(-1, -1)) \
|
_(TileSize, IntSize, IntSize(-1, -1)) \
|
||||||
_(UseXRender, bool, false) \
|
_(UseXRender, bool, false) \
|
||||||
|
_(OffscreenFormat, gfxImageFormat, mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32) \
|
||||||
|
_(RequiresAcceleratedGLContextForCompositorOGL, bool, false) \
|
||||||
|
|
||||||
/* Add new entries above this line. */
|
/* Add new entries above this line. */
|
||||||
|
|
||||||
// Some graphics settings are computed on the UI process and must be
|
// Some graphics settings are computed on the UI process and must be
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "mozilla/layers/ImageBridgeParent.h"
|
#include "mozilla/layers/ImageBridgeParent.h"
|
||||||
#include "nsDebugImpl.h"
|
#include "nsDebugImpl.h"
|
||||||
#include "mozilla/layers/LayerTreeOwnerTracker.h"
|
#include "mozilla/layers/LayerTreeOwnerTracker.h"
|
||||||
|
#include "ProcessUtils.h"
|
||||||
#include "VRManager.h"
|
#include "VRManager.h"
|
||||||
#include "VRManagerParent.h"
|
#include "VRManagerParent.h"
|
||||||
#include "VsyncBridgeParent.h"
|
#include "VsyncBridgeParent.h"
|
||||||
@ -64,6 +65,7 @@ GPUParent::Init(base::ProcessId aParentPid,
|
|||||||
CompositorThreadHolder::Start();
|
CompositorThreadHolder::Start();
|
||||||
VRManager::ManagerInit();
|
VRManager::ManagerInit();
|
||||||
LayerTreeOwnerTracker::Initialize();
|
LayerTreeOwnerTracker::Initialize();
|
||||||
|
mozilla::ipc::SetThisProcessName("GPU Process");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
|
|||||||
using mozilla::gfx::FeatureStatus from "gfxTelemetry.h";
|
using mozilla::gfx::FeatureStatus from "gfxTelemetry.h";
|
||||||
using mozilla::gfx::BackendType from "mozilla/gfx/Types.h";
|
using mozilla::gfx::BackendType from "mozilla/gfx/Types.h";
|
||||||
using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
|
using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
|
||||||
|
using gfxImageFormat from "mozilla/gfx/Types.h";
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace gfx {
|
namespace gfx {
|
||||||
@ -65,6 +66,7 @@ union GfxVarValue
|
|||||||
{
|
{
|
||||||
BackendType;
|
BackendType;
|
||||||
bool;
|
bool;
|
||||||
|
gfxImageFormat;
|
||||||
IntSize;
|
IntSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,6 +64,8 @@ IPDL_SOURCES = [
|
|||||||
'PVsyncBridge.ipdl',
|
'PVsyncBridge.ipdl',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
LOCAL_INCLUDES += ['/dom/ipc']
|
||||||
|
|
||||||
include('/ipc/chromium/chromium-config.mozbuild')
|
include('/ipc/chromium/chromium-config.mozbuild')
|
||||||
|
|
||||||
FINAL_LIBRARY = 'xul'
|
FINAL_LIBRARY = 'xul'
|
||||||
|
@ -133,6 +133,11 @@ public:
|
|||||||
|
|
||||||
void SetSupportsComponentAlphaChildren(bool aSupports) { mSupportsComponentAlphaChildren = aSupports; }
|
void SetSupportsComponentAlphaChildren(bool aSupports) { mSupportsComponentAlphaChildren = aSupports; }
|
||||||
|
|
||||||
|
virtual void Disconnect() override
|
||||||
|
{
|
||||||
|
ClientLayer::Disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ClientLayerManager* ClientManager()
|
ClientLayerManager* ClientManager()
|
||||||
{
|
{
|
||||||
|
@ -795,34 +795,6 @@ ClientLayerManager::GetBackendName(nsAString& aName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
ClientLayerManager::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent,
|
|
||||||
FrameMetrics& aMetrics,
|
|
||||||
bool aDrawingCritical)
|
|
||||||
{
|
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
MOZ_ASSERT(aMetrics.IsScrollable());
|
|
||||||
// This is derived from the code in
|
|
||||||
// gfx/layers/ipc/CompositorBridgeParent.cpp::TransformShadowTree.
|
|
||||||
CSSToLayerScale paintScale = aMetrics.LayersPixelsPerCSSPixel().ToScaleFactor();
|
|
||||||
const CSSRect& metricsDisplayPort =
|
|
||||||
(aDrawingCritical && !aMetrics.GetCriticalDisplayPort().IsEmpty()) ?
|
|
||||||
aMetrics.GetCriticalDisplayPort() : aMetrics.GetDisplayPort();
|
|
||||||
LayerRect displayPort = (metricsDisplayPort + aMetrics.GetScrollOffset()) * paintScale;
|
|
||||||
|
|
||||||
ParentLayerPoint scrollOffset;
|
|
||||||
CSSToParentLayerScale zoom;
|
|
||||||
bool ret = AndroidBridge::Bridge()->ProgressiveUpdateCallback(
|
|
||||||
aHasPendingNewThebesContent, displayPort, paintScale.scale, aDrawingCritical,
|
|
||||||
scrollOffset, zoom);
|
|
||||||
aMetrics.SetScrollOffset(scrollOffset / zoom);
|
|
||||||
aMetrics.SetZoom(CSSToParentLayerScale2D(zoom));
|
|
||||||
return ret;
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ClientLayerManager::AsyncPanZoomEnabled() const
|
ClientLayerManager::AsyncPanZoomEnabled() const
|
||||||
{
|
{
|
||||||
|
@ -155,22 +155,6 @@ public:
|
|||||||
// Disable component alpha layers with the software compositor.
|
// Disable component alpha layers with the software compositor.
|
||||||
virtual bool ShouldAvoidComponentAlphaLayers() override { return !IsCompositingCheap(); }
|
virtual bool ShouldAvoidComponentAlphaLayers() override { return !IsCompositingCheap(); }
|
||||||
|
|
||||||
/**
|
|
||||||
* Called for each iteration of a progressive tile update. Updates
|
|
||||||
* aMetrics with the current scroll offset and scale being used to composite
|
|
||||||
* the primary scrollable layer in this manager, to determine what area
|
|
||||||
* intersects with the target composition bounds.
|
|
||||||
* aDrawingCritical will be true if the current drawing operation is using
|
|
||||||
* the critical displayport.
|
|
||||||
* Returns true if the update should continue, or false if it should be
|
|
||||||
* cancelled.
|
|
||||||
* This is only called if gfxPlatform::UseProgressiveTilePainting() returns
|
|
||||||
* true.
|
|
||||||
*/
|
|
||||||
bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent,
|
|
||||||
FrameMetrics& aMetrics,
|
|
||||||
bool aDrawingCritical);
|
|
||||||
|
|
||||||
bool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
|
bool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
bool InDrawing() { return mPhase == PHASE_DRAWING; }
|
bool InDrawing() { return mPhase == PHASE_DRAWING; }
|
||||||
|
@ -47,7 +47,6 @@
|
|||||||
#include "mozilla/layers/LayersTypes.h"
|
#include "mozilla/layers/LayersTypes.h"
|
||||||
#include "mozilla/layers/PLayerTransactionParent.h"
|
#include "mozilla/layers/PLayerTransactionParent.h"
|
||||||
#include "mozilla/layers/RemoteContentController.h"
|
#include "mozilla/layers/RemoteContentController.h"
|
||||||
#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
|
|
||||||
#include "mozilla/layout/RenderFrameParent.h"
|
#include "mozilla/layout/RenderFrameParent.h"
|
||||||
#include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
|
#include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
|
||||||
#include "mozilla/mozalloc.h" // for operator new, etc
|
#include "mozilla/mozalloc.h" // for operator new, etc
|
||||||
@ -103,6 +102,82 @@ using namespace std;
|
|||||||
using base::ProcessId;
|
using base::ProcessId;
|
||||||
using base::Thread;
|
using base::Thread;
|
||||||
|
|
||||||
|
ProcessId
|
||||||
|
CompositorBridgeParentBase::GetChildProcessId()
|
||||||
|
{
|
||||||
|
return OtherPid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CompositorBridgeParentBase::NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId)
|
||||||
|
{
|
||||||
|
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
|
||||||
|
if (!texture) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(texture->GetFlags() & TextureFlags::RECYCLE) &&
|
||||||
|
!texture->NeedsFenceHandle()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture->GetFlags() & TextureFlags::RECYCLE) {
|
||||||
|
SendFenceHandleIfPresent(aTexture);
|
||||||
|
uint64_t textureId = TextureHost::GetTextureSerial(aTexture);
|
||||||
|
mPendingAsyncMessage.push_back(
|
||||||
|
OpNotifyNotUsed(textureId, aTransactionId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gralloc requests to deliver fence to client side.
|
||||||
|
// If client side does not use TextureFlags::RECYCLE flag,
|
||||||
|
// The fence can not be delivered via LayerTransactionParent.
|
||||||
|
// TextureClient might wait the fence delivery on main thread.
|
||||||
|
|
||||||
|
MOZ_ASSERT(ImageBridgeParent::GetInstance(GetChildProcessId()));
|
||||||
|
if (ImageBridgeParent::GetInstance(GetChildProcessId())) {
|
||||||
|
// Send message back via PImageBridge.
|
||||||
|
ImageBridgeParent::NotifyNotUsedToNonRecycle(
|
||||||
|
GetChildProcessId(),
|
||||||
|
aTexture,
|
||||||
|
aTransactionId);
|
||||||
|
} else {
|
||||||
|
NS_ERROR("ImageBridgeParent should exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsAboutToSendAsyncMessages()) {
|
||||||
|
SendPendingAsyncMessages();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CompositorBridgeParentBase::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
|
||||||
|
{
|
||||||
|
Unused << SendParentAsyncMessages(aMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CompositorBridgeParentBase::AllocShmem(size_t aSize,
|
||||||
|
ipc::SharedMemory::SharedMemoryType aType,
|
||||||
|
ipc::Shmem* aShmem)
|
||||||
|
{
|
||||||
|
return PCompositorBridgeParent::AllocShmem(aSize, aType, aShmem);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CompositorBridgeParentBase::AllocUnsafeShmem(size_t aSize,
|
||||||
|
ipc::SharedMemory::SharedMemoryType aType,
|
||||||
|
ipc::Shmem* aShmem)
|
||||||
|
{
|
||||||
|
return PCompositorBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CompositorBridgeParentBase::DeallocShmem(ipc::Shmem& aShmem)
|
||||||
|
{
|
||||||
|
PCompositorBridgeParent::DeallocShmem(aShmem);
|
||||||
|
}
|
||||||
|
|
||||||
CompositorBridgeParent::LayerTreeState::LayerTreeState()
|
CompositorBridgeParent::LayerTreeState::LayerTreeState()
|
||||||
: mApzcTreeManagerParent(nullptr)
|
: mApzcTreeManagerParent(nullptr)
|
||||||
, mParent(nullptr)
|
, mParent(nullptr)
|
||||||
@ -2005,10 +2080,7 @@ CompositorBridgeParent::FinishPendingComposite()
|
|||||||
* these updates, it doesn't actually drive compositing itself. For that it
|
* these updates, it doesn't actually drive compositing itself. For that it
|
||||||
* hands off work to the CompositorBridgeParent it's associated with.
|
* hands off work to the CompositorBridgeParent it's associated with.
|
||||||
*/
|
*/
|
||||||
class CrossProcessCompositorBridgeParent final : public PCompositorBridgeParent,
|
class CrossProcessCompositorBridgeParent final : public CompositorBridgeParentBase
|
||||||
public ShadowLayersManager,
|
|
||||||
public CompositorBridgeParentIPCAllocator,
|
|
||||||
public ShmemAllocator
|
|
||||||
{
|
{
|
||||||
friend class CompositorBridgeParent;
|
friend class CompositorBridgeParent;
|
||||||
|
|
||||||
@ -2152,28 +2224,6 @@ public:
|
|||||||
|
|
||||||
virtual bool IsSameProcess() const override;
|
virtual bool IsSameProcess() const override;
|
||||||
|
|
||||||
virtual ShmemAllocator* AsShmemAllocator() override { return this; }
|
|
||||||
|
|
||||||
virtual bool AllocShmem(size_t aSize,
|
|
||||||
mozilla::ipc::SharedMemory::SharedMemoryType aType,
|
|
||||||
mozilla::ipc::Shmem* aShmem) override;
|
|
||||||
|
|
||||||
virtual bool AllocUnsafeShmem(size_t aSize,
|
|
||||||
mozilla::ipc::SharedMemory::SharedMemoryType aType,
|
|
||||||
mozilla::ipc::Shmem* aShmem) override;
|
|
||||||
|
|
||||||
virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
|
|
||||||
|
|
||||||
virtual base::ProcessId GetChildProcessId() override
|
|
||||||
{
|
|
||||||
return OtherPid();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override
|
|
||||||
{
|
|
||||||
Unused << SendParentAsyncMessages(aMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
PCompositorWidgetParent* AllocPCompositorWidgetParent(const CompositorWidgetInitData& aInitData) override {
|
PCompositorWidgetParent* AllocPCompositorWidgetParent(const CompositorWidgetInitData& aInitData) override {
|
||||||
// Not allowed.
|
// Not allowed.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -2191,8 +2241,6 @@ public:
|
|||||||
virtual PAPZParent* AllocPAPZParent(const uint64_t& aLayersId) override;
|
virtual PAPZParent* AllocPAPZParent(const uint64_t& aLayersId) override;
|
||||||
virtual bool DeallocPAPZParent(PAPZParent* aActor) override;
|
virtual bool DeallocPAPZParent(PAPZParent* aActor) override;
|
||||||
|
|
||||||
virtual CompositorBridgeParentIPCAllocator* AsCompositorBridgeParentIPCAllocator() override { return this; }
|
|
||||||
|
|
||||||
virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) override {
|
virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) override {
|
||||||
uint64_t id = aLayerTree->GetId();
|
uint64_t id = aLayerTree->GetId();
|
||||||
MOZ_ASSERT(id != 0);
|
MOZ_ASSERT(id != 0);
|
||||||
@ -2423,34 +2471,6 @@ CompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor)
|
|||||||
return TextureHost::DestroyIPDLActor(actor);
|
return TextureHost::DestroyIPDLActor(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
CompositorBridgeParent::AllocShmem(size_t aSize,
|
|
||||||
ipc::SharedMemory::SharedMemoryType aType,
|
|
||||||
ipc::Shmem* aShmem)
|
|
||||||
{
|
|
||||||
return PCompositorBridgeParent::AllocShmem(aSize, aType, aShmem);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CompositorBridgeParent::AllocUnsafeShmem(size_t aSize,
|
|
||||||
ipc::SharedMemory::SharedMemoryType aType,
|
|
||||||
ipc::Shmem* aShmem)
|
|
||||||
{
|
|
||||||
return PCompositorBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CompositorBridgeParent::DeallocShmem(ipc::Shmem& aShmem)
|
|
||||||
{
|
|
||||||
PCompositorBridgeParent::DeallocShmem(aShmem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CompositorBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
|
|
||||||
{
|
|
||||||
Unused << SendParentAsyncMessages(aMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CompositorBridgeParent::IsSameProcess() const
|
CompositorBridgeParent::IsSameProcess() const
|
||||||
{
|
{
|
||||||
@ -3087,28 +3107,6 @@ CrossProcessCompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor)
|
|||||||
return TextureHost::DestroyIPDLActor(actor);
|
return TextureHost::DestroyIPDLActor(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
CrossProcessCompositorBridgeParent::AllocShmem(size_t aSize,
|
|
||||||
ipc::SharedMemory::SharedMemoryType aType,
|
|
||||||
ipc::Shmem* aShmem)
|
|
||||||
{
|
|
||||||
return PCompositorBridgeParent::AllocShmem(aSize, aType, aShmem);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CrossProcessCompositorBridgeParent::AllocUnsafeShmem(size_t aSize,
|
|
||||||
ipc::SharedMemory::SharedMemoryType aType,
|
|
||||||
ipc::Shmem* aShmem)
|
|
||||||
{
|
|
||||||
return PCompositorBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CrossProcessCompositorBridgeParent::DeallocShmem(ipc::Shmem& aShmem)
|
|
||||||
{
|
|
||||||
PCompositorBridgeParent::DeallocShmem(aShmem);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CrossProcessCompositorBridgeParent::IsSameProcess() const
|
CrossProcessCompositorBridgeParent::IsSameProcess() const
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
#include "mozilla/layers/ISurfaceAllocator.h" // for ShmemAllocator
|
#include "mozilla/layers/ISurfaceAllocator.h" // for ShmemAllocator
|
||||||
#include "mozilla/layers/LayersMessages.h" // for TargetConfig
|
#include "mozilla/layers/LayersMessages.h" // for TargetConfig
|
||||||
#include "mozilla/layers/PCompositorBridgeParent.h"
|
#include "mozilla/layers/PCompositorBridgeParent.h"
|
||||||
#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
|
|
||||||
#include "mozilla/layers/APZTestData.h"
|
#include "mozilla/layers/APZTestData.h"
|
||||||
#include "mozilla/widget/CompositorWidget.h"
|
#include "mozilla/widget/CompositorWidget.h"
|
||||||
#include "nsISupportsImpl.h"
|
#include "nsISupportsImpl.h"
|
||||||
@ -203,10 +202,57 @@ protected:
|
|||||||
virtual ~CompositorUpdateObserver() {}
|
virtual ~CompositorUpdateObserver() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CompositorBridgeParent final : public PCompositorBridgeParent,
|
class CompositorBridgeParentBase : public PCompositorBridgeParent,
|
||||||
public ShadowLayersManager,
|
public HostIPCAllocator,
|
||||||
public CompositorBridgeParentIPCAllocator,
|
public ShmemAllocator
|
||||||
public ShmemAllocator
|
{
|
||||||
|
public:
|
||||||
|
virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
|
||||||
|
const uint64_t& aTransactionId,
|
||||||
|
const TargetConfig& aTargetConfig,
|
||||||
|
const InfallibleTArray<PluginWindowData>& aPlugins,
|
||||||
|
bool aIsFirstPaint,
|
||||||
|
bool aScheduleComposite,
|
||||||
|
uint32_t aPaintSequenceNumber,
|
||||||
|
bool aIsRepeatTransaction,
|
||||||
|
int32_t aPaintSyncId,
|
||||||
|
bool aHitTestUpdate) = 0;
|
||||||
|
|
||||||
|
virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) { return nullptr; }
|
||||||
|
|
||||||
|
virtual void NotifyClearCachedResources(LayerTransactionParent* aLayerTree) { }
|
||||||
|
|
||||||
|
virtual void ForceComposite(LayerTransactionParent* aLayerTree) { }
|
||||||
|
virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
|
||||||
|
const TimeStamp& aTime) { return true; }
|
||||||
|
virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) { }
|
||||||
|
virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree) = 0;
|
||||||
|
virtual void FlushApzRepaints(const LayerTransactionParent* aLayerTree) = 0;
|
||||||
|
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
|
||||||
|
APZTestData* aOutData) { }
|
||||||
|
virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
|
||||||
|
const uint64_t& aInputBlockId,
|
||||||
|
const nsTArray<ScrollableLayerGuid>& aTargets) = 0;
|
||||||
|
virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) {}
|
||||||
|
|
||||||
|
virtual ShmemAllocator* AsShmemAllocator() override { return this; }
|
||||||
|
|
||||||
|
// HostIPCAllocator
|
||||||
|
virtual base::ProcessId GetChildProcessId() override;
|
||||||
|
virtual void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
|
||||||
|
virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
|
||||||
|
|
||||||
|
// ShmemAllocator
|
||||||
|
virtual bool AllocShmem(size_t aSize,
|
||||||
|
mozilla::ipc::SharedMemory::SharedMemoryType aType,
|
||||||
|
mozilla::ipc::Shmem* aShmem) override;
|
||||||
|
virtual bool AllocUnsafeShmem(size_t aSize,
|
||||||
|
mozilla::ipc::SharedMemory::SharedMemoryType aType,
|
||||||
|
mozilla::ipc::Shmem* aShmem) override;
|
||||||
|
virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CompositorBridgeParent final : public CompositorBridgeParentBase
|
||||||
{
|
{
|
||||||
friend class CompositorVsyncScheduler;
|
friend class CompositorVsyncScheduler;
|
||||||
friend class CompositorThreadHolder;
|
friend class CompositorThreadHolder;
|
||||||
@ -306,30 +352,10 @@ public:
|
|||||||
|
|
||||||
virtual bool IsSameProcess() const override;
|
virtual bool IsSameProcess() const override;
|
||||||
|
|
||||||
virtual ShmemAllocator* AsShmemAllocator() override { return this; }
|
|
||||||
|
|
||||||
virtual bool AllocShmem(size_t aSize,
|
|
||||||
mozilla::ipc::SharedMemory::SharedMemoryType aType,
|
|
||||||
mozilla::ipc::Shmem* aShmem) override;
|
|
||||||
|
|
||||||
virtual bool AllocUnsafeShmem(size_t aSize,
|
|
||||||
mozilla::ipc::SharedMemory::SharedMemoryType aType,
|
|
||||||
mozilla::ipc::Shmem* aShmem) override;
|
|
||||||
|
|
||||||
virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
|
|
||||||
|
|
||||||
PCompositorWidgetParent* AllocPCompositorWidgetParent(const CompositorWidgetInitData& aInitData) override;
|
PCompositorWidgetParent* AllocPCompositorWidgetParent(const CompositorWidgetInitData& aInitData) override;
|
||||||
bool DeallocPCompositorWidgetParent(PCompositorWidgetParent* aActor) override;
|
bool DeallocPCompositorWidgetParent(PCompositorWidgetParent* aActor) override;
|
||||||
|
|
||||||
virtual base::ProcessId GetChildProcessId() override
|
|
||||||
{
|
|
||||||
return OtherPid();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
|
|
||||||
|
|
||||||
virtual CompositorBridgeParentIPCAllocator* AsCompositorBridgeParentIPCAllocator() override { return this; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request that the compositor be recreated due to a shared device reset.
|
* Request that the compositor be recreated due to a shared device reset.
|
||||||
* This must be called on the main thread, and blocks until a task posted
|
* This must be called on the main thread, and blocks until a task posted
|
||||||
|
@ -87,48 +87,6 @@ HostIPCAllocator::SendPendingAsyncMessages()
|
|||||||
mPendingAsyncMessage.clear();
|
mPendingAsyncMessage.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CompositorBridgeParentIPCAllocator::NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId)
|
|
||||||
{
|
|
||||||
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
|
|
||||||
if (!texture) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(texture->GetFlags() & TextureFlags::RECYCLE) &&
|
|
||||||
!texture->NeedsFenceHandle()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (texture->GetFlags() & TextureFlags::RECYCLE) {
|
|
||||||
SendFenceHandleIfPresent(aTexture);
|
|
||||||
uint64_t textureId = TextureHost::GetTextureSerial(aTexture);
|
|
||||||
mPendingAsyncMessage.push_back(
|
|
||||||
OpNotifyNotUsed(textureId, aTransactionId));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gralloc requests to deliver fence to client side.
|
|
||||||
// If client side does not use TextureFlags::RECYCLE flag,
|
|
||||||
// The fence can not be delivered via LayerTransactionParent.
|
|
||||||
// TextureClient might wait the fence delivery on main thread.
|
|
||||||
|
|
||||||
MOZ_ASSERT(ImageBridgeParent::GetInstance(GetChildProcessId()));
|
|
||||||
if (ImageBridgeParent::GetInstance(GetChildProcessId())) {
|
|
||||||
// Send message back via PImageBridge.
|
|
||||||
ImageBridgeParent::NotifyNotUsedToNonRecycle(
|
|
||||||
GetChildProcessId(),
|
|
||||||
aTexture,
|
|
||||||
aTransactionId);
|
|
||||||
} else {
|
|
||||||
NS_ERROR("ImageBridgeParent should exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsAboutToSendAsyncMessages()) {
|
|
||||||
SendPendingAsyncMessages();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX - We should actually figure out the minimum shmem allocation size on
|
// XXX - We should actually figure out the minimum shmem allocation size on
|
||||||
// a certain platform and use that.
|
// a certain platform and use that.
|
||||||
const uint32_t sShmemPageSize = 4096;
|
const uint32_t sShmemPageSize = 4096;
|
||||||
|
@ -169,14 +169,6 @@ protected:
|
|||||||
bool mAboutToSendAsyncMessages = false;
|
bool mAboutToSendAsyncMessages = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Specific to the CompositorBridgeParent/CrossProcessCompositorBridgeParent.
|
|
||||||
class CompositorBridgeParentIPCAllocator : public HostIPCAllocator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CompositorBridgeParentIPCAllocator() {}
|
|
||||||
virtual void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// An allocator can provide shared memory.
|
/// An allocator can provide shared memory.
|
||||||
///
|
///
|
||||||
/// The allocated shmems can be deallocated on either process, as long as they
|
/// The allocated shmems can be deallocated on either process, as long as they
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "Layers.h" // for Layer, ContainerLayer, etc
|
#include "Layers.h" // for Layer, ContainerLayer, etc
|
||||||
#include "ShadowLayerParent.h" // for ShadowLayerParent
|
#include "ShadowLayerParent.h" // for ShadowLayerParent
|
||||||
#include "CompositableTransactionParent.h" // for EditReplyVector
|
#include "CompositableTransactionParent.h" // for EditReplyVector
|
||||||
|
#include "CompositorBridgeParent.h"
|
||||||
#include "gfxPrefs.h"
|
#include "gfxPrefs.h"
|
||||||
#include "mozilla/gfx/BasePoint3D.h" // for BasePoint3D
|
#include "mozilla/gfx/BasePoint3D.h" // for BasePoint3D
|
||||||
#include "mozilla/layers/CanvasLayerComposite.h"
|
#include "mozilla/layers/CanvasLayerComposite.h"
|
||||||
@ -29,7 +30,6 @@
|
|||||||
#include "mozilla/layers/PLayerParent.h" // for PLayerParent
|
#include "mozilla/layers/PLayerParent.h" // for PLayerParent
|
||||||
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
|
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
|
||||||
#include "mozilla/layers/PaintedLayerComposite.h"
|
#include "mozilla/layers/PaintedLayerComposite.h"
|
||||||
#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
|
|
||||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
#include "nsCoord.h" // for NSAppUnitsToFloatPixels
|
#include "nsCoord.h" // for NSAppUnitsToFloatPixels
|
||||||
@ -144,10 +144,10 @@ ShadowChild(const OpRaiseToTopChild& op)
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// LayerTransactionParent
|
// LayerTransactionParent
|
||||||
LayerTransactionParent::LayerTransactionParent(LayerManagerComposite* aManager,
|
LayerTransactionParent::LayerTransactionParent(LayerManagerComposite* aManager,
|
||||||
ShadowLayersManager* aLayersManager,
|
CompositorBridgeParentBase* aBridge,
|
||||||
uint64_t aId)
|
uint64_t aId)
|
||||||
: mLayerManager(aManager)
|
: mLayerManager(aManager)
|
||||||
, mShadowLayersManager(aLayersManager)
|
, mCompositorBridge(aBridge)
|
||||||
, mId(aId)
|
, mId(aId)
|
||||||
, mPendingTransaction(0)
|
, mPendingTransaction(0)
|
||||||
, mPendingCompositorUpdates(0)
|
, mPendingCompositorUpdates(0)
|
||||||
@ -232,7 +232,7 @@ bool
|
|||||||
LayerTransactionParent::RecvPaintTime(const uint64_t& aTransactionId,
|
LayerTransactionParent::RecvPaintTime(const uint64_t& aTransactionId,
|
||||||
const TimeDuration& aPaintTime)
|
const TimeDuration& aPaintTime)
|
||||||
{
|
{
|
||||||
mShadowLayersManager->UpdatePaintTime(this, aPaintTime);
|
mCompositorBridge->UpdatePaintTime(this, aPaintTime);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +274,7 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
|
|||||||
EditReplyVector replyv;
|
EditReplyVector replyv;
|
||||||
|
|
||||||
{
|
{
|
||||||
AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this));
|
AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this));
|
||||||
layer_manager()->BeginTransaction();
|
layer_manager()->BeginTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -657,13 +657,13 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mShadowLayersManager->ShadowLayersUpdated(this, aTransactionId, targetConfig,
|
mCompositorBridge->ShadowLayersUpdated(this, aTransactionId, targetConfig,
|
||||||
aPlugins, isFirstPaint, scheduleComposite,
|
aPlugins, isFirstPaint, scheduleComposite,
|
||||||
paintSequenceNumber, isRepeatTransaction,
|
paintSequenceNumber, isRepeatTransaction,
|
||||||
aPaintSyncId, updateHitTestingTree);
|
aPaintSyncId, updateHitTestingTree);
|
||||||
|
|
||||||
{
|
{
|
||||||
AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this));
|
AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this));
|
||||||
layer_manager()->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW);
|
layer_manager()->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,13 +714,13 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
|
|||||||
bool
|
bool
|
||||||
LayerTransactionParent::RecvSetTestSampleTime(const TimeStamp& aTime)
|
LayerTransactionParent::RecvSetTestSampleTime(const TimeStamp& aTime)
|
||||||
{
|
{
|
||||||
return mShadowLayersManager->SetTestSampleTime(this, aTime);
|
return mCompositorBridge->SetTestSampleTime(this, aTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LayerTransactionParent::RecvLeaveTestMode()
|
LayerTransactionParent::RecvLeaveTestMode()
|
||||||
{
|
{
|
||||||
mShadowLayersManager->LeaveTestMode(this);
|
mCompositorBridge->LeaveTestMode(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,7 +739,7 @@ LayerTransactionParent::RecvGetAnimationOpacity(PLayerParent* aParent,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mShadowLayersManager->ApplyAsyncProperties(this);
|
mCompositorBridge->ApplyAsyncProperties(this);
|
||||||
|
|
||||||
if (!layer->AsLayerComposite()->GetShadowOpacitySetByAnimation()) {
|
if (!layer->AsLayerComposite()->GetShadowOpacitySetByAnimation()) {
|
||||||
return true;
|
return true;
|
||||||
@ -767,7 +767,7 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent,
|
|||||||
// a race between when we temporarily clear the animation transform (in
|
// a race between when we temporarily clear the animation transform (in
|
||||||
// CompositorBridgeParent::SetShadowProperties) and when animation recalculates
|
// CompositorBridgeParent::SetShadowProperties) and when animation recalculates
|
||||||
// the value.
|
// the value.
|
||||||
mShadowLayersManager->ApplyAsyncProperties(this);
|
mCompositorBridge->ApplyAsyncProperties(this);
|
||||||
|
|
||||||
// This method is specific to transforms applied by animation.
|
// This method is specific to transforms applied by animation.
|
||||||
// This is because this method uses the information stored with an animation
|
// This is because this method uses the information stored with an animation
|
||||||
@ -885,14 +885,14 @@ LayerTransactionParent::RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollID,
|
|||||||
bool
|
bool
|
||||||
LayerTransactionParent::RecvFlushApzRepaints()
|
LayerTransactionParent::RecvFlushApzRepaints()
|
||||||
{
|
{
|
||||||
mShadowLayersManager->FlushApzRepaints(this);
|
mCompositorBridge->FlushApzRepaints(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LayerTransactionParent::RecvGetAPZTestData(APZTestData* aOutData)
|
LayerTransactionParent::RecvGetAPZTestData(APZTestData* aOutData)
|
||||||
{
|
{
|
||||||
mShadowLayersManager->GetAPZTestData(this, aOutData);
|
mCompositorBridge->GetAPZTestData(this, aOutData);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -913,7 +913,7 @@ bool
|
|||||||
LayerTransactionParent::RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
|
LayerTransactionParent::RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
|
||||||
nsTArray<ScrollableLayerGuid>&& aTargets)
|
nsTArray<ScrollableLayerGuid>&& aTargets)
|
||||||
{
|
{
|
||||||
mShadowLayersManager->SetConfirmedTargetAPZC(this, aBlockId, aTargets);
|
mCompositorBridge->SetConfirmedTargetAPZC(this, aBlockId, aTargets);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -960,14 +960,14 @@ LayerTransactionParent::RecvClearCachedResources()
|
|||||||
// of resources to exactly that subtree, so we specify it here.
|
// of resources to exactly that subtree, so we specify it here.
|
||||||
mLayerManager->ClearCachedResources(mRoot);
|
mLayerManager->ClearCachedResources(mRoot);
|
||||||
}
|
}
|
||||||
mShadowLayersManager->NotifyClearCachedResources(this);
|
mCompositorBridge->NotifyClearCachedResources(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LayerTransactionParent::RecvForceComposite()
|
LayerTransactionParent::RecvForceComposite()
|
||||||
{
|
{
|
||||||
mShadowLayersManager->ForceComposite(this);
|
mCompositorBridge->ForceComposite(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1047,13 +1047,13 @@ LayerTransactionParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessa
|
|||||||
void
|
void
|
||||||
LayerTransactionParent::SendPendingAsyncMessages()
|
LayerTransactionParent::SendPendingAsyncMessages()
|
||||||
{
|
{
|
||||||
mShadowLayersManager->AsCompositorBridgeParentIPCAllocator()->SendPendingAsyncMessages();
|
mCompositorBridge->SendPendingAsyncMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerTransactionParent::SetAboutToSendAsyncMessages()
|
LayerTransactionParent::SetAboutToSendAsyncMessages()
|
||||||
{
|
{
|
||||||
mShadowLayersManager->AsCompositorBridgeParentIPCAllocator()->SetAboutToSendAsyncMessages();
|
mCompositorBridge->SetAboutToSendAsyncMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -32,7 +32,7 @@ class Layer;
|
|||||||
class LayerManagerComposite;
|
class LayerManagerComposite;
|
||||||
class ShadowLayerParent;
|
class ShadowLayerParent;
|
||||||
class CompositableParent;
|
class CompositableParent;
|
||||||
class ShadowLayersManager;
|
class CompositorBridgeParentBase;
|
||||||
|
|
||||||
class LayerTransactionParent final : public PLayerTransactionParent,
|
class LayerTransactionParent final : public PLayerTransactionParent,
|
||||||
public CompositableParentManager,
|
public CompositableParentManager,
|
||||||
@ -46,7 +46,7 @@ class LayerTransactionParent final : public PLayerTransactionParent,
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
LayerTransactionParent(LayerManagerComposite* aManager,
|
LayerTransactionParent(LayerManagerComposite* aManager,
|
||||||
ShadowLayersManager* aLayersManager,
|
CompositorBridgeParentBase* aBridge,
|
||||||
uint64_t aId);
|
uint64_t aId);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -187,7 +187,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
RefPtr<LayerManagerComposite> mLayerManager;
|
RefPtr<LayerManagerComposite> mLayerManager;
|
||||||
ShadowLayersManager* mShadowLayersManager;
|
CompositorBridgeParentBase* mCompositorBridge;
|
||||||
// Hold the root because it might be grafted under various
|
// Hold the root because it might be grafted under various
|
||||||
// containers in the "real" layer tree
|
// containers in the "real" layer tree
|
||||||
RefPtr<Layer> mRoot;
|
RefPtr<Layer> mRoot;
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
||||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
|
||||||
/* 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 mozilla_layers_ShadowLayersManager_h
|
|
||||||
#define mozilla_layers_ShadowLayersManager_h
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace layers {
|
|
||||||
|
|
||||||
class TargetConfig;
|
|
||||||
class LayerTransactionParent;
|
|
||||||
class AsyncCompositionManager;
|
|
||||||
class APZTestData;
|
|
||||||
class CompositorBridgeParentIPCAllocator;
|
|
||||||
|
|
||||||
class ShadowLayersManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
|
|
||||||
const uint64_t& aTransactionId,
|
|
||||||
const TargetConfig& aTargetConfig,
|
|
||||||
const InfallibleTArray<PluginWindowData>& aPlugins,
|
|
||||||
bool aIsFirstPaint,
|
|
||||||
bool aScheduleComposite,
|
|
||||||
uint32_t aPaintSequenceNumber,
|
|
||||||
bool aIsRepeatTransaction,
|
|
||||||
int32_t aPaintSyncId,
|
|
||||||
bool aHitTestUpdate) = 0;
|
|
||||||
|
|
||||||
virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) { return nullptr; }
|
|
||||||
|
|
||||||
virtual void NotifyClearCachedResources(LayerTransactionParent* aLayerTree) { }
|
|
||||||
|
|
||||||
virtual void ForceComposite(LayerTransactionParent* aLayerTree) { }
|
|
||||||
virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
|
|
||||||
const TimeStamp& aTime) { return true; }
|
|
||||||
virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) { }
|
|
||||||
virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree) = 0;
|
|
||||||
virtual void FlushApzRepaints(const LayerTransactionParent* aLayerTree) = 0;
|
|
||||||
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
|
|
||||||
APZTestData* aOutData) { }
|
|
||||||
virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
|
|
||||||
const uint64_t& aInputBlockId,
|
|
||||||
const nsTArray<ScrollableLayerGuid>& aTargets) = 0;
|
|
||||||
virtual CompositorBridgeParentIPCAllocator* AsCompositorBridgeParentIPCAllocator() { return nullptr; }
|
|
||||||
virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace layers
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // mozilla_layers_ShadowLayersManager_h
|
|
@ -178,7 +178,6 @@ EXPORTS.mozilla.layers += [
|
|||||||
'ipc/RemoteContentController.h',
|
'ipc/RemoteContentController.h',
|
||||||
'ipc/ShadowLayerChild.h',
|
'ipc/ShadowLayerChild.h',
|
||||||
'ipc/ShadowLayers.h',
|
'ipc/ShadowLayers.h',
|
||||||
'ipc/ShadowLayersManager.h',
|
|
||||||
'ipc/SharedBufferManagerChild.h',
|
'ipc/SharedBufferManagerChild.h',
|
||||||
'ipc/SharedBufferManagerParent.h',
|
'ipc/SharedBufferManagerParent.h',
|
||||||
'ipc/SharedPlanarYCbCrImage.h',
|
'ipc/SharedPlanarYCbCrImage.h',
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "mozilla/Preferences.h" // for Preferences
|
#include "mozilla/Preferences.h" // for Preferences
|
||||||
#include "mozilla/gfx/BasePoint.h" // for BasePoint
|
#include "mozilla/gfx/BasePoint.h" // for BasePoint
|
||||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix
|
#include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix
|
||||||
|
#include "mozilla/gfx/gfxVars.h" // for gfxVars
|
||||||
#include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite, etc
|
#include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite, etc
|
||||||
#include "mozilla/layers/CompositingRenderTargetOGL.h"
|
#include "mozilla/layers/CompositingRenderTargetOGL.h"
|
||||||
#include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc
|
#include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc
|
||||||
@ -108,7 +109,8 @@ CompositorOGL::CreateContext()
|
|||||||
RefPtr<GLContext> context;
|
RefPtr<GLContext> context;
|
||||||
|
|
||||||
// Used by mock widget to create an offscreen context
|
// Used by mock widget to create an offscreen context
|
||||||
void* widgetOpenGLContext = mWidget->RealWidget()->GetNativeData(NS_NATIVE_OPENGL_CONTEXT);
|
nsIWidget* widget = mWidget->RealWidget();
|
||||||
|
void* widgetOpenGLContext = widget ? widget->GetNativeData(NS_NATIVE_OPENGL_CONTEXT) : nullptr;
|
||||||
if (widgetOpenGLContext) {
|
if (widgetOpenGLContext) {
|
||||||
GLContext* alreadyRefed = reinterpret_cast<GLContext*>(widgetOpenGLContext);
|
GLContext* alreadyRefed = reinterpret_cast<GLContext*>(widgetOpenGLContext);
|
||||||
return already_AddRefed<GLContext>(alreadyRefed);
|
return already_AddRefed<GLContext>(alreadyRefed);
|
||||||
@ -125,7 +127,7 @@ CompositorOGL::CreateContext()
|
|||||||
if (!context && gfxEnv::LayersPreferOffscreen()) {
|
if (!context && gfxEnv::LayersPreferOffscreen()) {
|
||||||
SurfaceCaps caps = SurfaceCaps::ForRGB();
|
SurfaceCaps caps = SurfaceCaps::ForRGB();
|
||||||
caps.preserve = false;
|
caps.preserve = false;
|
||||||
caps.bpp16 = gfxPlatform::GetPlatform()->GetOffscreenFormat() == SurfaceFormat::R5G6B5_UINT16;
|
caps.bpp16 = gfxVars::OffscreenFormat() == SurfaceFormat::R5G6B5_UINT16;
|
||||||
|
|
||||||
nsCString discardFailureId;
|
nsCString discardFailureId;
|
||||||
context = GLContextProvider::CreateOffscreen(mSurfaceSize,
|
context = GLContextProvider::CreateOffscreen(mSurfaceSize,
|
||||||
@ -135,7 +137,7 @@ CompositorOGL::CreateContext()
|
|||||||
|
|
||||||
if (!context) {
|
if (!context) {
|
||||||
context = gl::GLContextProvider::CreateForCompositorWidget(mWidget,
|
context = gl::GLContextProvider::CreateForCompositorWidget(mWidget,
|
||||||
gfxPlatform::GetPlatform()->RequiresAcceleratedGLContextForCompositorOGL());
|
gfxVars::RequiresAcceleratedGLContextForCompositorOGL());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context) {
|
if (!context) {
|
||||||
@ -143,7 +145,8 @@ CompositorOGL::CreateContext()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MOZ_WIDGET_GONK
|
#ifdef MOZ_WIDGET_GONK
|
||||||
mWidget->RealWidget()->SetNativeData(
|
MOZ_ASSERT(widget);
|
||||||
|
widget->SetNativeData(
|
||||||
NS_NATIVE_OPENGL_CONTEXT, reinterpret_cast<uintptr_t>(context.get()));
|
NS_NATIVE_OPENGL_CONTEXT, reinterpret_cast<uintptr_t>(context.get()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2110,6 +2110,9 @@ gfxPlatform::InitAcceleration()
|
|||||||
|
|
||||||
if (XRE_IsParentProcess()) {
|
if (XRE_IsParentProcess()) {
|
||||||
gfxVars::SetBrowserTabsRemoteAutostart(BrowserTabsRemoteAutostart());
|
gfxVars::SetBrowserTabsRemoteAutostart(BrowserTabsRemoteAutostart());
|
||||||
|
gfxVars::SetOffscreenFormat(GetOffscreenFormat());
|
||||||
|
gfxVars::SetRequiresAcceleratedGLContextForCompositorOGL(
|
||||||
|
RequiresAcceleratedGLContextForCompositorOGL());
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||||
|
@ -309,6 +309,7 @@ private:
|
|||||||
DECL_GFX_PREF(Live, "dom.meta-viewport.enabled", MetaViewportEnabled, bool, false);
|
DECL_GFX_PREF(Live, "dom.meta-viewport.enabled", MetaViewportEnabled, bool, false);
|
||||||
DECL_GFX_PREF(Once, "dom.vr.enabled", VREnabled, bool, false);
|
DECL_GFX_PREF(Once, "dom.vr.enabled", VREnabled, bool, false);
|
||||||
DECL_GFX_PREF(Once, "dom.vr.oculus.enabled", VROculusEnabled, bool, true);
|
DECL_GFX_PREF(Once, "dom.vr.oculus.enabled", VROculusEnabled, bool, true);
|
||||||
|
DECL_GFX_PREF(Once, "dom.vr.openvr.enabled", VROpenVREnabled, bool, false);
|
||||||
DECL_GFX_PREF(Once, "dom.vr.osvr.enabled", VROSVREnabled, bool, false);
|
DECL_GFX_PREF(Once, "dom.vr.osvr.enabled", VROSVREnabled, bool, false);
|
||||||
DECL_GFX_PREF(Live, "dom.vr.poseprediction.enabled", VRPosePredictionEnabled, bool, false);
|
DECL_GFX_PREF(Live, "dom.vr.poseprediction.enabled", VRPosePredictionEnabled, bool, false);
|
||||||
DECL_GFX_PREF(Live, "dom.w3c_pointer_events.enabled", PointerEventsEnabled, bool, false);
|
DECL_GFX_PREF(Live, "dom.w3c_pointer_events.enabled", PointerEventsEnabled, bool, false);
|
||||||
|
@ -1816,16 +1816,22 @@ public:
|
|||||||
// In these error cases, normalize to Now();
|
// In these error cases, normalize to Now();
|
||||||
if (vsync >= now) {
|
if (vsync >= now) {
|
||||||
vsync = vsync - mVsyncRate;
|
vsync = vsync - mVsyncRate;
|
||||||
return vsync <= now ? vsync : now;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// On Windows 7 and 8, DwmFlush wakes up AFTER qpcVBlankTime
|
// On Windows 7 and 8, DwmFlush wakes up AFTER qpcVBlankTime
|
||||||
// from DWMGetCompositionTimingInfo. We can return the adjusted vsync.
|
// from DWMGetCompositionTimingInfo. We can return the adjusted vsync.
|
||||||
// If we got here on Windows 10, it means we got a weird timestamp.
|
|
||||||
if (vsync >= now) {
|
if (vsync >= now) {
|
||||||
vsync = now;
|
vsync = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Our vsync time is some time very far in the past, adjust to Now.
|
||||||
|
// 4 ms is arbitrary, so feel free to pick something else if this isn't
|
||||||
|
// working. See the comment above within IsWin10OrLater().
|
||||||
|
if ((now - vsync).ToMilliseconds() > 4.0) {
|
||||||
|
vsync = now;
|
||||||
|
}
|
||||||
|
|
||||||
return vsync;
|
return vsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1891,6 +1897,12 @@ public:
|
|||||||
vsync = TimeStamp::Now();
|
vsync = TimeStamp::Now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((now - vsync).ToMilliseconds() > 2.0) {
|
||||||
|
// Account for time drift here where vsync never quite catches up to
|
||||||
|
// Now and we'd fall ever so slightly further behind Now().
|
||||||
|
vsync = GetVBlankTime();
|
||||||
|
}
|
||||||
|
|
||||||
mPrevVsync = vsync;
|
mPrevVsync = vsync;
|
||||||
}
|
}
|
||||||
} // end for
|
} // end for
|
||||||
|
@ -12,9 +12,7 @@
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace gfx {
|
namespace gfx {
|
||||||
class VRDisplayClient;
|
class VRDisplayClient;
|
||||||
namespace vr {
|
|
||||||
class VRLayerChild;
|
class VRLayerChild;
|
||||||
} // namepsace vr
|
|
||||||
|
|
||||||
class VRDisplayPresentation final
|
class VRDisplayPresentation final
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "VRManager.h"
|
#include "VRManager.h"
|
||||||
#include "VRManagerParent.h"
|
#include "VRManagerParent.h"
|
||||||
#include "gfxVR.h"
|
#include "gfxVR.h"
|
||||||
|
#include "gfxVROpenVR.h"
|
||||||
#include "mozilla/ClearOnShutdown.h"
|
#include "mozilla/ClearOnShutdown.h"
|
||||||
#include "mozilla/dom/VRDisplay.h"
|
#include "mozilla/dom/VRDisplay.h"
|
||||||
#include "mozilla/layers/TextureHost.h"
|
#include "mozilla/layers/TextureHost.h"
|
||||||
@ -51,6 +52,20 @@ VRManager::VRManager()
|
|||||||
|
|
||||||
RefPtr<VRDisplayManager> mgr;
|
RefPtr<VRDisplayManager> mgr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We must add the VRDisplayManager's to mManagers in a careful order to
|
||||||
|
* ensure that we don't detect the same VRDisplay from multiple API's.
|
||||||
|
*
|
||||||
|
* Oculus comes first, as it will only enumerate Oculus HMD's and is the
|
||||||
|
* native interface for Oculus HMD's.
|
||||||
|
*
|
||||||
|
* OpenvR comes second, as it is the native interface for HTC Vive
|
||||||
|
* which is the most common HMD at this time.
|
||||||
|
*
|
||||||
|
* OSVR will be used if Oculus SDK and OpenVR don't detect any HMDS,
|
||||||
|
* to support everyone else.
|
||||||
|
*/
|
||||||
|
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN)
|
||||||
// The Oculus runtime is supported only on Windows
|
// The Oculus runtime is supported only on Windows
|
||||||
mgr = VRDisplayManagerOculus::Create();
|
mgr = VRDisplayManagerOculus::Create();
|
||||||
@ -60,9 +75,15 @@ VRManager::VRManager()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
|
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
|
||||||
|
// OpenVR is cross platform compatible
|
||||||
|
mgr = VRDisplayManagerOpenVR::Create();
|
||||||
|
if (mgr) {
|
||||||
|
mManagers.AppendElement(mgr);
|
||||||
|
}
|
||||||
|
|
||||||
// OSVR is cross platform compatible
|
// OSVR is cross platform compatible
|
||||||
mgr = VRDisplayManagerOSVR::Create();
|
mgr = VRDisplayManagerOSVR::Create();
|
||||||
if (mgr){
|
if (mgr) {
|
||||||
mManagers.AppendElement(mgr);
|
mManagers.AppendElement(mgr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -172,7 +193,15 @@ VRManager::RefreshVRDisplays(bool aMustDispatch)
|
|||||||
{
|
{
|
||||||
nsTArray<RefPtr<gfx::VRDisplayHost> > displays;
|
nsTArray<RefPtr<gfx::VRDisplayHost> > displays;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
|
/** We don't wish to enumerate the same display from multiple managers,
|
||||||
|
* so stop as soon as we get a display.
|
||||||
|
* It is still possible to get multiple displays from a single manager,
|
||||||
|
* but do not wish to mix-and-match for risk of reporting a duplicate.
|
||||||
|
*
|
||||||
|
* XXX - Perhaps there will be a better way to detect duplicate displays
|
||||||
|
* in the future.
|
||||||
|
*/
|
||||||
|
for (uint32_t i = 0; i < mManagers.Length() && displays.Length() == 0; ++i) {
|
||||||
mManagers[i]->GetHMDs(displays);
|
mManagers[i]->GetHMDs(displays);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ class VRDisplayHost;
|
|||||||
|
|
||||||
enum class VRDisplayType : uint16_t {
|
enum class VRDisplayType : uint16_t {
|
||||||
Oculus,
|
Oculus,
|
||||||
|
OpenVR,
|
||||||
OSVR,
|
OSVR,
|
||||||
NumVRDisplayTypes
|
NumVRDisplayTypes
|
||||||
};
|
};
|
||||||
@ -56,10 +57,25 @@ enum class VRDisplayCapabilityFlags : uint16_t {
|
|||||||
* or update non-VR UI because that content will not be visible.
|
* or update non-VR UI because that content will not be visible.
|
||||||
*/
|
*/
|
||||||
Cap_External = 1 << 4,
|
Cap_External = 1 << 4,
|
||||||
|
/**
|
||||||
|
* Cap_AngularAcceleration is set if the VRDisplay is capable of tracking its
|
||||||
|
* angular acceleration.
|
||||||
|
*/
|
||||||
|
Cap_AngularAcceleration = 1 << 5,
|
||||||
|
/**
|
||||||
|
* Cap_LinearAcceleration is set if the VRDisplay is capable of tracking its
|
||||||
|
* linear acceleration.
|
||||||
|
*/
|
||||||
|
Cap_LinearAcceleration = 1 << 6,
|
||||||
|
/**
|
||||||
|
* Cap_StageParameters is set if the VRDisplay is capable of room scale VR
|
||||||
|
* and can report the StageParameters to describe the space.
|
||||||
|
*/
|
||||||
|
Cap_StageParameters = 1 << 7,
|
||||||
/**
|
/**
|
||||||
* Cap_All used for validity checking during IPC serialization
|
* Cap_All used for validity checking during IPC serialization
|
||||||
*/
|
*/
|
||||||
Cap_All = (1 << 5) - 1
|
Cap_All = (1 << 8) - 1
|
||||||
};
|
};
|
||||||
|
|
||||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(VRDisplayCapabilityFlags)
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(VRDisplayCapabilityFlags)
|
||||||
@ -70,6 +86,14 @@ struct VRFieldOfView {
|
|||||||
: upDegrees(up), rightDegrees(right), downDegrees(down), leftDegrees(left)
|
: upDegrees(up), rightDegrees(right), downDegrees(down), leftDegrees(left)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
void SetFromTanRadians(double up, double right, double down, double left)
|
||||||
|
{
|
||||||
|
upDegrees = atan(up) * 180.0 / M_PI;
|
||||||
|
rightDegrees = atan(right) * 180.0 / M_PI;
|
||||||
|
downDegrees = atan(down) * 180.0 / M_PI;
|
||||||
|
leftDegrees = atan(left) * 180.0 / M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const VRFieldOfView& other) const {
|
bool operator==(const VRFieldOfView& other) const {
|
||||||
return other.upDegrees == upDegrees &&
|
return other.upDegrees == upDegrees &&
|
||||||
other.downDegrees == downDegrees &&
|
other.downDegrees == downDegrees &&
|
||||||
@ -108,6 +132,8 @@ struct VRDisplayInfo
|
|||||||
const VRFieldOfView& GetEyeFOV(uint32_t whichEye) const { return mEyeFOV[whichEye]; }
|
const VRFieldOfView& GetEyeFOV(uint32_t whichEye) const { return mEyeFOV[whichEye]; }
|
||||||
bool GetIsConnected() const { return mIsConnected; }
|
bool GetIsConnected() const { return mIsConnected; }
|
||||||
bool GetIsPresenting() const { return mIsPresenting; }
|
bool GetIsPresenting() const { return mIsPresenting; }
|
||||||
|
const Size& GetStageSize() const { return mStageSize; }
|
||||||
|
const Matrix4x4& GetSittingToStandingTransform() const { return mSittingToStandingTransform; }
|
||||||
|
|
||||||
enum Eye {
|
enum Eye {
|
||||||
Eye_Left,
|
Eye_Left,
|
||||||
@ -124,6 +150,8 @@ struct VRDisplayInfo
|
|||||||
IntSize mEyeResolution;
|
IntSize mEyeResolution;
|
||||||
bool mIsConnected;
|
bool mIsConnected;
|
||||||
bool mIsPresenting;
|
bool mIsPresenting;
|
||||||
|
Size mStageSize;
|
||||||
|
Matrix4x4 mSittingToStandingTransform;
|
||||||
|
|
||||||
bool operator==(const VRDisplayInfo& other) const {
|
bool operator==(const VRDisplayInfo& other) const {
|
||||||
return mType == other.mType &&
|
return mType == other.mType &&
|
||||||
@ -136,7 +164,9 @@ struct VRDisplayInfo
|
|||||||
mEyeFOV[0] == other.mEyeFOV[0] &&
|
mEyeFOV[0] == other.mEyeFOV[0] &&
|
||||||
mEyeFOV[1] == other.mEyeFOV[1] &&
|
mEyeFOV[1] == other.mEyeFOV[1] &&
|
||||||
mEyeTranslation[0] == other.mEyeTranslation[0] &&
|
mEyeTranslation[0] == other.mEyeTranslation[0] &&
|
||||||
mEyeTranslation[1] == other.mEyeTranslation[1];
|
mEyeTranslation[1] == other.mEyeTranslation[1] &&
|
||||||
|
mStageSize == other.mStageSize &&
|
||||||
|
mSittingToStandingTransform == other.mSittingToStandingTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const VRDisplayInfo& other) const {
|
bool operator!=(const VRDisplayInfo& other) const {
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
#include "mozilla/gfx/Quaternion.h"
|
#include "mozilla/gfx/Quaternion.h"
|
||||||
|
|
||||||
#include <d3d11.h>
|
#include <d3d11.h>
|
||||||
#include "../layers/d3d11/CompositorD3D11.h"
|
#include "CompositorD3D11.h"
|
||||||
#include "mozilla/layers/TextureD3D11.h"
|
#include "TextureD3D11.h"
|
||||||
|
|
||||||
#include "gfxVROculus.h"
|
#include "gfxVROculus.h"
|
||||||
|
|
||||||
@ -337,9 +337,11 @@ VRDisplayOculus::VRDisplayOculus(ovrSession aSession)
|
|||||||
mDisplayInfo.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None;
|
mDisplayInfo.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None;
|
||||||
if (mDesc.AvailableTrackingCaps & ovrTrackingCap_Orientation) {
|
if (mDesc.AvailableTrackingCaps & ovrTrackingCap_Orientation) {
|
||||||
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Orientation;
|
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Orientation;
|
||||||
|
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration;
|
||||||
}
|
}
|
||||||
if (mDesc.AvailableTrackingCaps & ovrTrackingCap_Position) {
|
if (mDesc.AvailableTrackingCaps & ovrTrackingCap_Position) {
|
||||||
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Position;
|
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Position;
|
||||||
|
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
|
||||||
}
|
}
|
||||||
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_External;
|
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_External;
|
||||||
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Present;
|
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Present;
|
||||||
@ -441,6 +443,8 @@ VRDisplayOculus::GetSensorState(double timeOffset)
|
|||||||
result.angularVelocity[1] = pose.AngularVelocity.y;
|
result.angularVelocity[1] = pose.AngularVelocity.y;
|
||||||
result.angularVelocity[2] = pose.AngularVelocity.z;
|
result.angularVelocity[2] = pose.AngularVelocity.z;
|
||||||
|
|
||||||
|
result.flags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration;
|
||||||
|
|
||||||
result.angularAcceleration[0] = pose.AngularAcceleration.x;
|
result.angularAcceleration[0] = pose.AngularAcceleration.x;
|
||||||
result.angularAcceleration[1] = pose.AngularAcceleration.y;
|
result.angularAcceleration[1] = pose.AngularAcceleration.y;
|
||||||
result.angularAcceleration[2] = pose.AngularAcceleration.z;
|
result.angularAcceleration[2] = pose.AngularAcceleration.z;
|
||||||
@ -457,6 +461,8 @@ VRDisplayOculus::GetSensorState(double timeOffset)
|
|||||||
result.linearVelocity[1] = pose.LinearVelocity.y;
|
result.linearVelocity[1] = pose.LinearVelocity.y;
|
||||||
result.linearVelocity[2] = pose.LinearVelocity.z;
|
result.linearVelocity[2] = pose.LinearVelocity.z;
|
||||||
|
|
||||||
|
result.flags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
|
||||||
|
|
||||||
result.linearAcceleration[0] = pose.LinearAcceleration.x;
|
result.linearAcceleration[0] = pose.LinearAcceleration.x;
|
||||||
result.linearAcceleration[1] = pose.LinearAcceleration.y;
|
result.linearAcceleration[1] = pose.LinearAcceleration.y;
|
||||||
result.linearAcceleration[2] = pose.LinearAcceleration.z;
|
result.linearAcceleration[2] = pose.LinearAcceleration.z;
|
||||||
|
442
gfx/vr/gfxVROpenVR.cpp
Normal file
442
gfx/vr/gfxVROpenVR.cpp
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 20; 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 <math.h>
|
||||||
|
|
||||||
|
#include "prlink.h"
|
||||||
|
#include "prmem.h"
|
||||||
|
#include "prenv.h"
|
||||||
|
#include "gfxPrefs.h"
|
||||||
|
#include "nsString.h"
|
||||||
|
#include "mozilla/Preferences.h"
|
||||||
|
|
||||||
|
#include "mozilla/gfx/Quaternion.h"
|
||||||
|
|
||||||
|
#ifdef XP_WIN
|
||||||
|
#include "CompositorD3D11.h"
|
||||||
|
#include "TextureD3D11.h"
|
||||||
|
#endif // XP_WIN
|
||||||
|
|
||||||
|
#include "gfxVROpenVR.h"
|
||||||
|
|
||||||
|
#include "nsServiceManagerUtils.h"
|
||||||
|
#include "nsIScreenManager.h"
|
||||||
|
#include "openvr/openvr.h"
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
# define M_PI 3.14159265358979323846
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::gfx;
|
||||||
|
using namespace mozilla::gfx::impl;
|
||||||
|
using namespace mozilla::layers;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
extern "C" {
|
||||||
|
typedef uint32_t (VR_CALLTYPE * pfn_VR_InitInternal)(::vr::HmdError *peError, ::vr::EVRApplicationType eApplicationType);
|
||||||
|
typedef void (VR_CALLTYPE * pfn_VR_ShutdownInternal)();
|
||||||
|
typedef bool (VR_CALLTYPE * pfn_VR_IsHmdPresent)();
|
||||||
|
typedef bool (VR_CALLTYPE * pfn_VR_IsRuntimeInstalled)();
|
||||||
|
typedef const char * (VR_CALLTYPE * pfn_VR_GetStringForHmdError)(::vr::HmdError error);
|
||||||
|
typedef void * (VR_CALLTYPE * pfn_VR_GetGenericInterface)(const char *pchInterfaceVersion, ::vr::HmdError *peError);
|
||||||
|
} // extern "C"
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
static pfn_VR_InitInternal vr_InitInternal = nullptr;
|
||||||
|
static pfn_VR_ShutdownInternal vr_ShutdownInternal = nullptr;
|
||||||
|
static pfn_VR_IsHmdPresent vr_IsHmdPresent = nullptr;
|
||||||
|
static pfn_VR_IsRuntimeInstalled vr_IsRuntimeInstalled = nullptr;
|
||||||
|
static pfn_VR_GetStringForHmdError vr_GetStringForHmdError = nullptr;
|
||||||
|
static pfn_VR_GetGenericInterface vr_GetGenericInterface = nullptr;
|
||||||
|
|
||||||
|
bool
|
||||||
|
LoadOpenVRRuntime()
|
||||||
|
{
|
||||||
|
static PRLibrary *openvrLib = nullptr;
|
||||||
|
|
||||||
|
nsAdoptingCString openvrPath = Preferences::GetCString("gfx.vr.openvr-runtime");
|
||||||
|
if (!openvrPath)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
openvrLib = PR_LoadLibrary(openvrPath.BeginReading());
|
||||||
|
if (!openvrLib)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#define REQUIRE_FUNCTION(_x) do { \
|
||||||
|
*(void **)&vr_##_x = (void *) PR_FindSymbol(openvrLib, "VR_" #_x); \
|
||||||
|
if (!vr_##_x) { printf_stderr("VR_" #_x " symbol missing\n"); return false; } \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
REQUIRE_FUNCTION(InitInternal);
|
||||||
|
REQUIRE_FUNCTION(ShutdownInternal);
|
||||||
|
REQUIRE_FUNCTION(IsHmdPresent);
|
||||||
|
REQUIRE_FUNCTION(IsRuntimeInstalled);
|
||||||
|
REQUIRE_FUNCTION(GetStringForHmdError);
|
||||||
|
REQUIRE_FUNCTION(GetGenericInterface);
|
||||||
|
|
||||||
|
#undef REQUIRE_FUNCTION
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VRDisplayOpenVR::VRDisplayOpenVR(::vr::IVRSystem *aVRSystem,
|
||||||
|
::vr::IVRChaperone *aVRChaperone,
|
||||||
|
::vr::IVRCompositor *aVRCompositor)
|
||||||
|
: VRDisplayHost(VRDisplayType::OpenVR)
|
||||||
|
, mVRSystem(aVRSystem)
|
||||||
|
, mVRChaperone(aVRChaperone)
|
||||||
|
, mVRCompositor(aVRCompositor)
|
||||||
|
, mIsPresenting(false)
|
||||||
|
{
|
||||||
|
MOZ_COUNT_CTOR_INHERITED(VRDisplayOpenVR, VRDisplayHost);
|
||||||
|
|
||||||
|
mDisplayInfo.mDisplayName.AssignLiteral("OpenVR HMD");
|
||||||
|
mDisplayInfo.mIsConnected = true;
|
||||||
|
mDisplayInfo.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None |
|
||||||
|
VRDisplayCapabilityFlags::Cap_Orientation |
|
||||||
|
VRDisplayCapabilityFlags::Cap_Position |
|
||||||
|
VRDisplayCapabilityFlags::Cap_External |
|
||||||
|
VRDisplayCapabilityFlags::Cap_Present |
|
||||||
|
VRDisplayCapabilityFlags::Cap_StageParameters;
|
||||||
|
|
||||||
|
mVRCompositor->SetTrackingSpace(::vr::TrackingUniverseSeated);
|
||||||
|
|
||||||
|
uint32_t w, h;
|
||||||
|
mVRSystem->GetRecommendedRenderTargetSize(&w, &h);
|
||||||
|
mDisplayInfo.mEyeResolution.width = w;
|
||||||
|
mDisplayInfo.mEyeResolution.height = h;
|
||||||
|
|
||||||
|
// SteamVR gives the application a single FOV to use; it's not configurable as with Oculus
|
||||||
|
for (uint32_t eye = 0; eye < 2; ++eye) {
|
||||||
|
// get l/r/t/b clip plane coordinates
|
||||||
|
float l, r, t, b;
|
||||||
|
mVRSystem->GetProjectionRaw(static_cast<::vr::Hmd_Eye>(eye), &l, &r, &t, &b);
|
||||||
|
mDisplayInfo.mEyeFOV[eye].SetFromTanRadians(-t, r, b, -l);
|
||||||
|
|
||||||
|
::vr::HmdMatrix34_t eyeToHead = mVRSystem->GetEyeToHeadTransform(static_cast<::vr::Hmd_Eye>(eye));
|
||||||
|
|
||||||
|
mDisplayInfo.mEyeTranslation[eye].x = eyeToHead.m[0][3];
|
||||||
|
mDisplayInfo.mEyeTranslation[eye].y = eyeToHead.m[1][3];
|
||||||
|
mDisplayInfo.mEyeTranslation[eye].z = eyeToHead.m[2][3];
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateStageParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
VRDisplayOpenVR::~VRDisplayOpenVR()
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
MOZ_COUNT_DTOR_INHERITED(VRDisplayOpenVR, VRDisplayHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VRDisplayOpenVR::Destroy()
|
||||||
|
{
|
||||||
|
StopPresentation();
|
||||||
|
vr_ShutdownInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VRDisplayOpenVR::UpdateStageParameters()
|
||||||
|
{
|
||||||
|
float sizeX = 0.0f;
|
||||||
|
float sizeZ = 0.0f;
|
||||||
|
if (mVRChaperone->GetPlayAreaSize(&sizeX, &sizeZ)) {
|
||||||
|
::vr::HmdMatrix34_t t = mVRSystem->GetSeatedZeroPoseToStandingAbsoluteTrackingPose();
|
||||||
|
mDisplayInfo.mStageSize.width = sizeX;
|
||||||
|
mDisplayInfo.mStageSize.height = sizeZ;
|
||||||
|
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._11 = t.m[0][0];
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._12 = t.m[1][0];
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._13 = t.m[2][0];
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._14 = 0.0f;
|
||||||
|
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._21 = t.m[0][1];
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._22 = t.m[1][1];
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._23 = t.m[2][1];
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._24 = 0.0f;
|
||||||
|
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._31 = t.m[0][2];
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._32 = t.m[1][2];
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._33 = t.m[2][2];
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._34 = 0.0f;
|
||||||
|
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._41 = t.m[0][3];
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._42 = t.m[1][3];
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._43 = t.m[2][3];
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._44 = 1.0f;
|
||||||
|
} else {
|
||||||
|
// If we fail, fall back to reasonable defaults.
|
||||||
|
// 1m x 1m space, 0.75m high in seated position
|
||||||
|
|
||||||
|
mDisplayInfo.mStageSize.width = 1.0f;
|
||||||
|
mDisplayInfo.mStageSize.height = 1.0f;
|
||||||
|
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._11 = 1.0f;
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._12 = 0.0f;
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._13 = 0.0f;
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._14 = 0.0f;
|
||||||
|
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._21 = 0.0f;
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._22 = 1.0f;
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._23 = 0.0f;
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._24 = 0.0f;
|
||||||
|
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._31 = 0.0f;
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._32 = 0.0f;
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._33 = 1.0f;
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._34 = 0.0f;
|
||||||
|
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._41 = 0.0f;
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._42 = 0.75f;
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._43 = 0.0f;
|
||||||
|
mDisplayInfo.mSittingToStandingTransform._44 = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VRDisplayOpenVR::ZeroSensor()
|
||||||
|
{
|
||||||
|
mVRSystem->ResetSeatedZeroPose();
|
||||||
|
UpdateStageParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
VRHMDSensorState
|
||||||
|
VRDisplayOpenVR::GetSensorState()
|
||||||
|
{
|
||||||
|
return GetSensorState(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
VRHMDSensorState
|
||||||
|
VRDisplayOpenVR::GetImmediateSensorState()
|
||||||
|
{
|
||||||
|
return GetSensorState(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
VRHMDSensorState
|
||||||
|
VRDisplayOpenVR::GetSensorState(double timeOffset)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
::vr::VREvent_t event;
|
||||||
|
while (mVRSystem->PollNextEvent(&event, sizeof(event))) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::vr::TrackedDevicePose_t poses[::vr::k_unMaxTrackedDeviceCount];
|
||||||
|
// Note: We *must* call WaitGetPoses in order for any rendering to happen at all
|
||||||
|
mVRCompositor->WaitGetPoses(poses, ::vr::k_unMaxTrackedDeviceCount, nullptr, 0);
|
||||||
|
|
||||||
|
VRHMDSensorState result;
|
||||||
|
result.Clear();
|
||||||
|
result.timestamp = PR_Now();
|
||||||
|
|
||||||
|
if (poses[::vr::k_unTrackedDeviceIndex_Hmd].bDeviceIsConnected &&
|
||||||
|
poses[::vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid &&
|
||||||
|
poses[::vr::k_unTrackedDeviceIndex_Hmd].eTrackingResult == ::vr::TrackingResult_Running_OK)
|
||||||
|
{
|
||||||
|
const ::vr::TrackedDevicePose_t& pose = poses[::vr::k_unTrackedDeviceIndex_Hmd];
|
||||||
|
|
||||||
|
gfx::Matrix4x4 m;
|
||||||
|
// NOTE! mDeviceToAbsoluteTracking is a 3x4 matrix, not 4x4. But
|
||||||
|
// because of its arrangement, we can copy the 12 elements in and
|
||||||
|
// then transpose them to the right place. We do this so we can
|
||||||
|
// pull out a Quaternion.
|
||||||
|
memcpy(&m._11, &pose.mDeviceToAbsoluteTracking, sizeof(float) * 12);
|
||||||
|
m.Transpose();
|
||||||
|
|
||||||
|
gfx::Quaternion rot;
|
||||||
|
rot.SetFromRotationMatrix(m);
|
||||||
|
rot.Invert();
|
||||||
|
|
||||||
|
result.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
|
||||||
|
result.orientation[0] = rot.x;
|
||||||
|
result.orientation[1] = rot.y;
|
||||||
|
result.orientation[2] = rot.z;
|
||||||
|
result.orientation[3] = rot.w;
|
||||||
|
result.angularVelocity[0] = pose.vAngularVelocity.v[0];
|
||||||
|
result.angularVelocity[1] = pose.vAngularVelocity.v[1];
|
||||||
|
result.angularVelocity[2] = pose.vAngularVelocity.v[2];
|
||||||
|
|
||||||
|
result.flags |= VRDisplayCapabilityFlags::Cap_Position;
|
||||||
|
result.position[0] = m._41;
|
||||||
|
result.position[1] = m._42;
|
||||||
|
result.position[2] = m._43;
|
||||||
|
result.linearVelocity[0] = pose.vVelocity.v[0];
|
||||||
|
result.linearVelocity[1] = pose.vVelocity.v[1];
|
||||||
|
result.linearVelocity[2] = pose.vVelocity.v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VRDisplayOpenVR::StartPresentation()
|
||||||
|
{
|
||||||
|
if (mIsPresenting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mIsPresenting = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VRDisplayOpenVR::StopPresentation()
|
||||||
|
{
|
||||||
|
if (!mIsPresenting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mVRCompositor->ClearLastSubmittedFrame();
|
||||||
|
|
||||||
|
mIsPresenting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
|
||||||
|
void
|
||||||
|
VRDisplayOpenVR::SubmitFrame(TextureSourceD3D11* aSource,
|
||||||
|
const IntSize& aSize,
|
||||||
|
const VRHMDSensorState& aSensorState,
|
||||||
|
const gfx::Rect& aLeftEyeRect,
|
||||||
|
const gfx::Rect& aRightEyeRect)
|
||||||
|
{
|
||||||
|
if (!mIsPresenting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
::vr::Texture_t tex;
|
||||||
|
tex.handle = (void *)aSource->GetD3D11Texture();
|
||||||
|
tex.eType = ::vr::EGraphicsAPIConvention::API_DirectX;
|
||||||
|
tex.eColorSpace = ::vr::EColorSpace::ColorSpace_Auto;
|
||||||
|
|
||||||
|
::vr::VRTextureBounds_t bounds;
|
||||||
|
bounds.uMin = aLeftEyeRect.x;
|
||||||
|
bounds.vMin = 1.0 - aLeftEyeRect.y;
|
||||||
|
bounds.uMax = aLeftEyeRect.x + aLeftEyeRect.width;
|
||||||
|
bounds.vMax = 1.0 - aLeftEyeRect.y - aLeftEyeRect.height;
|
||||||
|
|
||||||
|
::vr::EVRCompositorError err;
|
||||||
|
err = mVRCompositor->Submit(::vr::EVREye::Eye_Left, &tex, &bounds);
|
||||||
|
if (err != ::vr::EVRCompositorError::VRCompositorError_None) {
|
||||||
|
printf_stderr("OpenVR Compositor Submit() failed.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bounds.uMin = aRightEyeRect.x;
|
||||||
|
bounds.vMin = 1.0 - aRightEyeRect.y;
|
||||||
|
bounds.uMax = aRightEyeRect.x + aRightEyeRect.width;
|
||||||
|
bounds.vMax = 1.0 - aRightEyeRect.y - aRightEyeRect.height;
|
||||||
|
|
||||||
|
err = mVRCompositor->Submit(::vr::EVREye::Eye_Right, &tex, &bounds);
|
||||||
|
if (err != ::vr::EVRCompositorError::VRCompositorError_None) {
|
||||||
|
printf_stderr("OpenVR Compositor Submit() failed.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
mVRCompositor->PostPresentHandoff();
|
||||||
|
|
||||||
|
// Trigger the next VSync immediately
|
||||||
|
VRManager *vm = VRManager::Get();
|
||||||
|
MOZ_ASSERT(vm);
|
||||||
|
vm->NotifyVRVsync(mDisplayInfo.mDisplayID);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
VRDisplayOpenVR::NotifyVSync()
|
||||||
|
{
|
||||||
|
// We update mIsConneced once per frame.
|
||||||
|
mDisplayInfo.mIsConnected = vr_IsHmdPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
VRDisplayManagerOpenVR::VRDisplayManagerOpenVR()
|
||||||
|
: mOpenVRInstalled(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static*/ already_AddRefed<VRDisplayManagerOpenVR>
|
||||||
|
VRDisplayManagerOpenVR::Create()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (!gfxPrefs::VREnabled() || !gfxPrefs::VROpenVREnabled()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!LoadOpenVRRuntime()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<VRDisplayManagerOpenVR> manager = new VRDisplayManagerOpenVR();
|
||||||
|
return manager.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
VRDisplayManagerOpenVR::Init()
|
||||||
|
{
|
||||||
|
if (mOpenVRInstalled)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!vr_IsRuntimeInstalled())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mOpenVRInstalled = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VRDisplayManagerOpenVR::Destroy()
|
||||||
|
{
|
||||||
|
if (mOpenVRInstalled) {
|
||||||
|
if (mOpenVRHMD) {
|
||||||
|
mOpenVRHMD = nullptr;
|
||||||
|
}
|
||||||
|
mOpenVRInstalled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VRDisplayManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
|
||||||
|
{
|
||||||
|
if (!mOpenVRInstalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vr_IsHmdPresent()) {
|
||||||
|
if (mOpenVRHMD) {
|
||||||
|
mOpenVRHMD = nullptr;
|
||||||
|
}
|
||||||
|
} else if (mOpenVRHMD == nullptr) {
|
||||||
|
::vr::HmdError err;
|
||||||
|
|
||||||
|
vr_InitInternal(&err, ::vr::EVRApplicationType::VRApplication_Scene);
|
||||||
|
if (err) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
::vr::IVRSystem *system = (::vr::IVRSystem *)vr_GetGenericInterface(::vr::IVRSystem_Version, &err);
|
||||||
|
if (err || !system) {
|
||||||
|
vr_ShutdownInternal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
::vr::IVRChaperone *chaperone = (::vr::IVRChaperone *)vr_GetGenericInterface(::vr::IVRChaperone_Version, &err);
|
||||||
|
if (err || !chaperone) {
|
||||||
|
vr_ShutdownInternal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
::vr::IVRCompositor *compositor = (::vr::IVRCompositor*)vr_GetGenericInterface(::vr::IVRCompositor_Version, &err);
|
||||||
|
if (err || !compositor) {
|
||||||
|
vr_ShutdownInternal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpenVRHMD = new VRDisplayOpenVR(system, chaperone, compositor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mOpenVRHMD) {
|
||||||
|
aHMDResult.AppendElement(mOpenVRHMD);
|
||||||
|
}
|
||||||
|
}
|
93
gfx/vr/gfxVROpenVR.h
Normal file
93
gfx/vr/gfxVROpenVR.h
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 20; 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_VR_OPENVR_H
|
||||||
|
#define GFX_VR_OPENVR_H
|
||||||
|
|
||||||
|
#include "nsTArray.h"
|
||||||
|
#include "nsIScreen.h"
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "mozilla/RefPtr.h"
|
||||||
|
|
||||||
|
#include "mozilla/gfx/2D.h"
|
||||||
|
#include "mozilla/EnumeratedArray.h"
|
||||||
|
|
||||||
|
#include "gfxVR.h"
|
||||||
|
|
||||||
|
// OpenVR Interfaces
|
||||||
|
namespace vr {
|
||||||
|
class IVRChaperone;
|
||||||
|
class IVRCompositor;
|
||||||
|
class IVRSystem;
|
||||||
|
struct TrackedDevicePose_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace gfx {
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
class VRDisplayOpenVR : public VRDisplayHost
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void NotifyVSync() override;
|
||||||
|
virtual VRHMDSensorState GetSensorState() override;
|
||||||
|
virtual VRHMDSensorState GetImmediateSensorState() override;
|
||||||
|
void ZeroSensor() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void StartPresentation() override;
|
||||||
|
virtual void StopPresentation() override;
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
virtual void SubmitFrame(mozilla::layers::TextureSourceD3D11* aSource,
|
||||||
|
const IntSize& aSize,
|
||||||
|
const VRHMDSensorState& aSensorState,
|
||||||
|
const gfx::Rect& aLeftEyeRect,
|
||||||
|
const gfx::Rect& aRightEyeRect) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit VRDisplayOpenVR(::vr::IVRSystem *aVRSystem,
|
||||||
|
::vr::IVRChaperone *aVRChaperone,
|
||||||
|
::vr::IVRCompositor *aVRCompositor);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~VRDisplayOpenVR();
|
||||||
|
void Destroy();
|
||||||
|
|
||||||
|
VRHMDSensorState GetSensorState(double timeOffset);
|
||||||
|
|
||||||
|
// not owned by us; global from OpenVR
|
||||||
|
::vr::IVRSystem *mVRSystem;
|
||||||
|
::vr::IVRChaperone *mVRChaperone;
|
||||||
|
::vr::IVRCompositor *mVRCompositor;
|
||||||
|
|
||||||
|
bool mIsPresenting;
|
||||||
|
|
||||||
|
void UpdateStageParameters();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
|
class VRDisplayManagerOpenVR : public VRDisplayManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static already_AddRefed<VRDisplayManagerOpenVR> Create();
|
||||||
|
|
||||||
|
virtual bool Init() override;
|
||||||
|
virtual void Destroy() override;
|
||||||
|
virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
|
||||||
|
protected:
|
||||||
|
VRDisplayManagerOpenVR();
|
||||||
|
|
||||||
|
// there can only be one
|
||||||
|
RefPtr<impl::VRDisplayOpenVR> mOpenVRHMD;
|
||||||
|
bool mOpenVRInstalled;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gfx
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* GFX_VR_OPENVR_H */
|
@ -40,6 +40,8 @@ struct ParamTraits<mozilla::gfx::VRDisplayInfo>
|
|||||||
WriteParam(aMsg, aParam.mEyeResolution);
|
WriteParam(aMsg, aParam.mEyeResolution);
|
||||||
WriteParam(aMsg, aParam.mIsConnected);
|
WriteParam(aMsg, aParam.mIsConnected);
|
||||||
WriteParam(aMsg, aParam.mIsPresenting);
|
WriteParam(aMsg, aParam.mIsPresenting);
|
||||||
|
WriteParam(aMsg, aParam.mStageSize);
|
||||||
|
WriteParam(aMsg, aParam.mSittingToStandingTransform);
|
||||||
for (int i = 0; i < mozilla::gfx::VRDisplayInfo::NumEyes; i++) {
|
for (int i = 0; i < mozilla::gfx::VRDisplayInfo::NumEyes; i++) {
|
||||||
WriteParam(aMsg, aParam.mEyeFOV[i]);
|
WriteParam(aMsg, aParam.mEyeFOV[i]);
|
||||||
WriteParam(aMsg, aParam.mEyeTranslation[i]);
|
WriteParam(aMsg, aParam.mEyeTranslation[i]);
|
||||||
@ -54,7 +56,9 @@ struct ParamTraits<mozilla::gfx::VRDisplayInfo>
|
|||||||
!ReadParam(aMsg, aIter, &(aResult->mCapabilityFlags)) ||
|
!ReadParam(aMsg, aIter, &(aResult->mCapabilityFlags)) ||
|
||||||
!ReadParam(aMsg, aIter, &(aResult->mEyeResolution)) ||
|
!ReadParam(aMsg, aIter, &(aResult->mEyeResolution)) ||
|
||||||
!ReadParam(aMsg, aIter, &(aResult->mIsConnected)) ||
|
!ReadParam(aMsg, aIter, &(aResult->mIsConnected)) ||
|
||||||
!ReadParam(aMsg, aIter, &(aResult->mIsPresenting))) {
|
!ReadParam(aMsg, aIter, &(aResult->mIsPresenting)) ||
|
||||||
|
!ReadParam(aMsg, aIter, &(aResult->mStageSize)) ||
|
||||||
|
!ReadParam(aMsg, aIter, &(aResult->mSittingToStandingTransform))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < mozilla::gfx::VRDisplayInfo::NumEyes; i++) {
|
for (int i = 0; i < mozilla::gfx::VRDisplayInfo::NumEyes; i++) {
|
||||||
|
@ -16,11 +16,13 @@ EXPORTS += [
|
|||||||
]
|
]
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
LOCAL_INCLUDES += [
|
||||||
|
'/gfx/layers/d3d11',
|
||||||
'/gfx/thebes',
|
'/gfx/thebes',
|
||||||
]
|
]
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'gfxVR.cpp',
|
'gfxVR.cpp',
|
||||||
|
'gfxVROpenVR.cpp',
|
||||||
'gfxVROSVR.cpp',
|
'gfxVROSVR.cpp',
|
||||||
'ipc/VRLayerChild.cpp',
|
'ipc/VRLayerChild.cpp',
|
||||||
'ipc/VRLayerParent.cpp',
|
'ipc/VRLayerParent.cpp',
|
||||||
|
27
gfx/vr/openvr/LICENSE
Normal file
27
gfx/vr/openvr/LICENSE
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2015, Valve Corporation
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
2
gfx/vr/openvr/README
Normal file
2
gfx/vr/openvr/README
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
See https://github.com/ValveSoftware/openvr/
|
||||||
|
|
3352
gfx/vr/openvr/openvr.h
Normal file
3352
gfx/vr/openvr/openvr.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -67,12 +67,6 @@ static StaticRefPtr<SurfaceCacheImpl> sInstance;
|
|||||||
*/
|
*/
|
||||||
typedef size_t Cost;
|
typedef size_t Cost;
|
||||||
|
|
||||||
// Placeholders do not have surfaces, but need to be given a trivial cost for
|
|
||||||
// our invariants to hold.
|
|
||||||
// XXX(seth): This is only true of old-style placeholders inserted via
|
|
||||||
// InsertPlaceholder().
|
|
||||||
static const Cost sPlaceholderCost = 1;
|
|
||||||
|
|
||||||
static Cost
|
static Cost
|
||||||
ComputeCost(const IntSize& aSize, uint32_t aBytesPerPixel)
|
ComputeCost(const IntSize& aSize, uint32_t aBytesPerPixel)
|
||||||
{
|
{
|
||||||
@ -94,14 +88,12 @@ ComputeCost(const IntSize& aSize, uint32_t aBytesPerPixel)
|
|||||||
class CostEntry
|
class CostEntry
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CostEntry(CachedSurface* aSurface, Cost aCost)
|
CostEntry(NotNull<CachedSurface*> aSurface, Cost aCost)
|
||||||
: mSurface(aSurface)
|
: mSurface(aSurface)
|
||||||
, mCost(aCost)
|
, mCost(aCost)
|
||||||
{
|
{ }
|
||||||
MOZ_ASSERT(aSurface, "Must have a surface");
|
|
||||||
}
|
|
||||||
|
|
||||||
CachedSurface* GetSurface() const { return mSurface; }
|
NotNull<CachedSurface*> Surface() const { return mSurface; }
|
||||||
Cost GetCost() const { return mCost; }
|
Cost GetCost() const { return mCost; }
|
||||||
|
|
||||||
bool operator==(const CostEntry& aOther) const
|
bool operator==(const CostEntry& aOther) const
|
||||||
@ -117,8 +109,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CachedSurface* mSurface;
|
NotNull<CachedSurface*> mSurface;
|
||||||
Cost mCost;
|
Cost mCost;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -132,17 +124,15 @@ public:
|
|||||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(CachedSurface)
|
MOZ_DECLARE_REFCOUNTED_TYPENAME(CachedSurface)
|
||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CachedSurface)
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CachedSurface)
|
||||||
|
|
||||||
CachedSurface(ISurfaceProvider* aProvider,
|
CachedSurface(NotNull<ISurfaceProvider*> aProvider,
|
||||||
const Cost aCost,
|
const Cost aCost,
|
||||||
const ImageKey aImageKey,
|
const ImageKey aImageKey,
|
||||||
const SurfaceKey& aSurfaceKey)
|
const SurfaceKey& aSurfaceKey)
|
||||||
: mProvider(aProvider)
|
: mProvider(aProvider)
|
||||||
, mCost(aCost)
|
, mCost(aCost)
|
||||||
, mImageKey(aImageKey)
|
, mImageKey(aImageKey)
|
||||||
, mSurfaceKey(aSurfaceKey)
|
, mSurfaceKey(aSurfaceKey)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aProvider || mCost == sPlaceholderCost,
|
|
||||||
"Old-style placeholders should have trivial cost");
|
|
||||||
MOZ_ASSERT(mImageKey, "Must have a valid image key");
|
MOZ_ASSERT(mImageKey, "Must have a valid image key");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,23 +155,15 @@ public:
|
|||||||
mProvider->SetLocked(aLocked);
|
mProvider->SetLocked(aLocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsPlaceholder() const
|
|
||||||
{
|
|
||||||
return !mProvider || mProvider->Availability().IsPlaceholder();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsLocked() const { return !IsPlaceholder() && mProvider->IsLocked(); }
|
bool IsLocked() const { return !IsPlaceholder() && mProvider->IsLocked(); }
|
||||||
|
bool IsPlaceholder() const { return mProvider->Availability().IsPlaceholder(); }
|
||||||
|
bool IsDecoded() const { return !IsPlaceholder() && mProvider->IsFinished(); }
|
||||||
|
|
||||||
ImageKey GetImageKey() const { return mImageKey; }
|
ImageKey GetImageKey() const { return mImageKey; }
|
||||||
SurfaceKey GetSurfaceKey() const { return mSurfaceKey; }
|
SurfaceKey GetSurfaceKey() const { return mSurfaceKey; }
|
||||||
CostEntry GetCostEntry() { return image::CostEntry(this, mCost); }
|
CostEntry GetCostEntry() { return image::CostEntry(WrapNotNull(this), mCost); }
|
||||||
nsExpirationState* GetExpirationState() { return &mExpirationState; }
|
nsExpirationState* GetExpirationState() { return &mExpirationState; }
|
||||||
|
|
||||||
bool IsDecoded() const
|
|
||||||
{
|
|
||||||
return !IsPlaceholder() && mProvider->IsFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
// A helper type used by SurfaceCacheImpl::CollectSizeOfSurfaces.
|
// A helper type used by SurfaceCacheImpl::CollectSizeOfSurfaces.
|
||||||
struct MOZ_STACK_CLASS SurfaceMemoryReport
|
struct MOZ_STACK_CLASS SurfaceMemoryReport
|
||||||
{
|
{
|
||||||
@ -191,10 +173,8 @@ public:
|
|||||||
, mMallocSizeOf(aMallocSizeOf)
|
, mMallocSizeOf(aMallocSizeOf)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void Add(CachedSurface* aCachedSurface)
|
void Add(NotNull<CachedSurface*> aCachedSurface)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aCachedSurface, "Should have a CachedSurface");
|
|
||||||
|
|
||||||
SurfaceMemoryCounter counter(aCachedSurface->GetSurfaceKey(),
|
SurfaceMemoryCounter counter(aCachedSurface->GetSurfaceKey(),
|
||||||
aCachedSurface->IsLocked());
|
aCachedSurface->IsLocked());
|
||||||
|
|
||||||
@ -222,11 +202,11 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsExpirationState mExpirationState;
|
nsExpirationState mExpirationState;
|
||||||
RefPtr<ISurfaceProvider> mProvider;
|
NotNull<RefPtr<ISurfaceProvider>> mProvider;
|
||||||
const Cost mCost;
|
const Cost mCost;
|
||||||
const ImageKey mImageKey;
|
const ImageKey mImageKey;
|
||||||
const SurfaceKey mSurfaceKey;
|
const SurfaceKey mSurfaceKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int64_t
|
static int64_t
|
||||||
@ -257,17 +237,15 @@ public:
|
|||||||
|
|
||||||
bool IsEmpty() const { return mSurfaces.Count() == 0; }
|
bool IsEmpty() const { return mSurfaces.Count() == 0; }
|
||||||
|
|
||||||
void Insert(const SurfaceKey& aKey, CachedSurface* aSurface)
|
void Insert(const SurfaceKey& aKey, NotNull<CachedSurface*> aSurface)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aSurface, "Should have a surface");
|
|
||||||
MOZ_ASSERT(!mLocked || aSurface->IsPlaceholder() || aSurface->IsLocked(),
|
MOZ_ASSERT(!mLocked || aSurface->IsPlaceholder() || aSurface->IsLocked(),
|
||||||
"Inserting an unlocked surface for a locked image");
|
"Inserting an unlocked surface for a locked image");
|
||||||
mSurfaces.Put(aKey, aSurface);
|
mSurfaces.Put(aKey, aSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Remove(CachedSurface* aSurface)
|
void Remove(NotNull<CachedSurface*> aSurface)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aSurface, "Should have a surface");
|
|
||||||
MOZ_ASSERT(mSurfaces.GetWeak(aSurface->GetSurfaceKey()),
|
MOZ_ASSERT(mSurfaces.GetWeak(aSurface->GetSurfaceKey()),
|
||||||
"Should not be removing a surface we don't have");
|
"Should not be removing a surface we don't have");
|
||||||
|
|
||||||
@ -294,7 +272,7 @@ public:
|
|||||||
// There's no perfect match, so find the best match we can.
|
// There's no perfect match, so find the best match we can.
|
||||||
RefPtr<CachedSurface> bestMatch;
|
RefPtr<CachedSurface> bestMatch;
|
||||||
for (auto iter = ConstIter(); !iter.Done(); iter.Next()) {
|
for (auto iter = ConstIter(); !iter.Done(); iter.Next()) {
|
||||||
CachedSurface* current = iter.UserData();
|
NotNull<CachedSurface*> current = WrapNotNull(iter.UserData());
|
||||||
const SurfaceKey& currentKey = current->GetSurfaceKey();
|
const SurfaceKey& currentKey = current->GetSurfaceKey();
|
||||||
|
|
||||||
// We never match a placeholder.
|
// We never match a placeholder.
|
||||||
@ -367,7 +345,7 @@ public:
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (exactMatch) {
|
if (exactMatch) {
|
||||||
// We found an "exact match", it must have been a placeholder.
|
// We found an "exact match"; it must have been a placeholder.
|
||||||
MOZ_ASSERT(exactMatch->IsPlaceholder());
|
MOZ_ASSERT(exactMatch->IsPlaceholder());
|
||||||
matchType = MatchType::PENDING;
|
matchType = MatchType::PENDING;
|
||||||
} else {
|
} else {
|
||||||
@ -438,11 +416,11 @@ public:
|
|||||||
|
|
||||||
Mutex& GetMutex() { return mMutex; }
|
Mutex& GetMutex() { return mMutex; }
|
||||||
|
|
||||||
InsertOutcome Insert(ISurfaceProvider* aProvider,
|
InsertOutcome Insert(NotNull<ISurfaceProvider*> aProvider,
|
||||||
const Cost aCost,
|
const Cost aCost,
|
||||||
const ImageKey aImageKey,
|
const ImageKey aImageKey,
|
||||||
const SurfaceKey& aSurfaceKey,
|
const SurfaceKey& aSurfaceKey,
|
||||||
bool aSetAvailable)
|
bool aSetAvailable)
|
||||||
{
|
{
|
||||||
// If this is a duplicate surface, refuse to replace the original.
|
// If this is a duplicate surface, refuse to replace the original.
|
||||||
// XXX(seth): Calling Lookup() and then RemoveEntry() does the lookup
|
// XXX(seth): Calling Lookup() and then RemoveEntry() does the lookup
|
||||||
@ -472,7 +450,7 @@ public:
|
|||||||
while (aCost > mAvailableCost) {
|
while (aCost > mAvailableCost) {
|
||||||
MOZ_ASSERT(!mCosts.IsEmpty(),
|
MOZ_ASSERT(!mCosts.IsEmpty(),
|
||||||
"Removed everything and it still won't fit");
|
"Removed everything and it still won't fit");
|
||||||
Remove(mCosts.LastElement().GetSurface());
|
Remove(mCosts.LastElement().Surface());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locate the appropriate per-image cache. If there's not an existing cache
|
// Locate the appropriate per-image cache. If there's not an existing cache
|
||||||
@ -488,8 +466,8 @@ public:
|
|||||||
aProvider->Availability().SetAvailable();
|
aProvider->Availability().SetAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<CachedSurface> surface =
|
NotNull<RefPtr<CachedSurface>> surface =
|
||||||
new CachedSurface(aProvider, aCost, aImageKey, aSurfaceKey);
|
WrapNotNull(new CachedSurface(aProvider, aCost, aImageKey, aSurfaceKey));
|
||||||
|
|
||||||
// We require that locking succeed if the image is locked and we're not
|
// We require that locking succeed if the image is locked and we're not
|
||||||
// inserting a placeholder; the caller may need to know this to handle
|
// inserting a placeholder; the caller may need to know this to handle
|
||||||
@ -509,9 +487,8 @@ public:
|
|||||||
return InsertOutcome::SUCCESS;
|
return InsertOutcome::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Remove(CachedSurface* aSurface)
|
void Remove(NotNull<CachedSurface*> aSurface)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aSurface, "Should have a surface");
|
|
||||||
ImageKey imageKey = aSurface->GetImageKey();
|
ImageKey imageKey = aSurface->GetImageKey();
|
||||||
|
|
||||||
RefPtr<ImageSurfaceCache> cache = GetImageCache(imageKey);
|
RefPtr<ImageSurfaceCache> cache = GetImageCache(imageKey);
|
||||||
@ -532,7 +509,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartTracking(CachedSurface* aSurface)
|
void StartTracking(NotNull<CachedSurface*> aSurface)
|
||||||
{
|
{
|
||||||
CostEntry costEntry = aSurface->GetCostEntry();
|
CostEntry costEntry = aSurface->GetCostEntry();
|
||||||
MOZ_ASSERT(costEntry.GetCost() <= mAvailableCost,
|
MOZ_ASSERT(costEntry.GetCost() <= mAvailableCost,
|
||||||
@ -551,9 +528,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopTracking(CachedSurface* aSurface)
|
void StopTracking(NotNull<CachedSurface*> aSurface)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aSurface, "Should have a surface");
|
|
||||||
CostEntry costEntry = aSurface->GetCostEntry();
|
CostEntry costEntry = aSurface->GetCostEntry();
|
||||||
|
|
||||||
if (aSurface->IsLocked()) {
|
if (aSurface->IsLocked()) {
|
||||||
@ -605,12 +581,12 @@ public:
|
|||||||
if (!drawableSurface) {
|
if (!drawableSurface) {
|
||||||
// The surface was released by the operating system. Remove the cache
|
// The surface was released by the operating system. Remove the cache
|
||||||
// entry as well.
|
// entry as well.
|
||||||
Remove(surface);
|
Remove(WrapNotNull(surface));
|
||||||
return LookupResult(MatchType::NOT_FOUND);
|
return LookupResult(MatchType::NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aMarkUsed) {
|
if (aMarkUsed) {
|
||||||
MarkUsed(surface, cache);
|
MarkUsed(WrapNotNull(surface), WrapNotNull(cache));
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(surface->GetSurfaceKey() == aSurfaceKey,
|
MOZ_ASSERT(surface->GetSurfaceKey() == aSurfaceKey,
|
||||||
@ -650,7 +626,7 @@ public:
|
|||||||
|
|
||||||
// The surface was released by the operating system. Remove the cache
|
// The surface was released by the operating system. Remove the cache
|
||||||
// entry as well.
|
// entry as well.
|
||||||
Remove(surface);
|
Remove(WrapNotNull(surface));
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT_IF(matchType == MatchType::EXACT,
|
MOZ_ASSERT_IF(matchType == MatchType::EXACT,
|
||||||
@ -662,7 +638,7 @@ public:
|
|||||||
surface->GetSurfaceKey().Flags() == aSurfaceKey.Flags());
|
surface->GetSurfaceKey().Flags() == aSurfaceKey.Flags());
|
||||||
|
|
||||||
if (matchType == MatchType::EXACT) {
|
if (matchType == MatchType::EXACT) {
|
||||||
MarkUsed(surface, cache);
|
MarkUsed(WrapNotNull(surface), WrapNotNull(cache));
|
||||||
}
|
}
|
||||||
|
|
||||||
return LookupResult(Move(drawableSurface), matchType);
|
return LookupResult(Move(drawableSurface), matchType);
|
||||||
@ -719,7 +695,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
cache->SetLocked(false);
|
cache->SetLocked(false);
|
||||||
DoUnlockSurfaces(cache);
|
DoUnlockSurfaces(WrapNotNull(cache));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnlockEntries(const ImageKey aImageKey)
|
void UnlockEntries(const ImageKey aImageKey)
|
||||||
@ -731,7 +707,7 @@ public:
|
|||||||
|
|
||||||
// (Note that we *don't* unlock the per-image cache here; that's the
|
// (Note that we *don't* unlock the per-image cache here; that's the
|
||||||
// difference between this and UnlockImage.)
|
// difference between this and UnlockImage.)
|
||||||
DoUnlockSurfaces(cache);
|
DoUnlockSurfaces(WrapNotNull(cache));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveImage(const ImageKey aImageKey)
|
void RemoveImage(const ImageKey aImageKey)
|
||||||
@ -747,7 +723,7 @@ public:
|
|||||||
// small, performance should be good, but if usage patterns change we should
|
// small, performance should be good, but if usage patterns change we should
|
||||||
// change the data structure used for mCosts.
|
// change the data structure used for mCosts.
|
||||||
for (auto iter = cache->ConstIter(); !iter.Done(); iter.Next()) {
|
for (auto iter = cache->ConstIter(); !iter.Done(); iter.Next()) {
|
||||||
StopTracking(iter.UserData());
|
StopTracking(WrapNotNull(iter.UserData()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The per-image cache isn't needed anymore, so remove it as well.
|
// The per-image cache isn't needed anymore, so remove it as well.
|
||||||
@ -761,7 +737,7 @@ public:
|
|||||||
// structures are all hash tables. Note that locked surfaces are not
|
// structures are all hash tables. Note that locked surfaces are not
|
||||||
// removed, since they aren't present in mCosts.
|
// removed, since they aren't present in mCosts.
|
||||||
while (!mCosts.IsEmpty()) {
|
while (!mCosts.IsEmpty()) {
|
||||||
Remove(mCosts.LastElement().GetSurface());
|
Remove(mCosts.LastElement().Surface());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -787,11 +763,11 @@ public:
|
|||||||
// Discard surfaces until we've reduced our cost to our target cost.
|
// Discard surfaces until we've reduced our cost to our target cost.
|
||||||
while (mAvailableCost < targetCost) {
|
while (mAvailableCost < targetCost) {
|
||||||
MOZ_ASSERT(!mCosts.IsEmpty(), "Removed everything and still not done");
|
MOZ_ASSERT(!mCosts.IsEmpty(), "Removed everything and still not done");
|
||||||
Remove(mCosts.LastElement().GetSurface());
|
Remove(mCosts.LastElement().Surface());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LockSurface(CachedSurface* aSurface)
|
void LockSurface(NotNull<CachedSurface*> aSurface)
|
||||||
{
|
{
|
||||||
if (aSurface->IsPlaceholder() || aSurface->IsLocked()) {
|
if (aSurface->IsPlaceholder() || aSurface->IsLocked()) {
|
||||||
return;
|
return;
|
||||||
@ -845,7 +821,7 @@ public:
|
|||||||
// Report all surfaces in the per-image cache.
|
// Report all surfaces in the per-image cache.
|
||||||
CachedSurface::SurfaceMemoryReport report(aCounters, aMallocSizeOf);
|
CachedSurface::SurfaceMemoryReport report(aCounters, aMallocSizeOf);
|
||||||
for (auto iter = cache->ConstIter(); !iter.Done(); iter.Next()) {
|
for (auto iter = cache->ConstIter(); !iter.Done(); iter.Next()) {
|
||||||
report.Add(iter.UserData());
|
report.Add(WrapNotNull(iter.UserData()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -867,7 +843,8 @@ private:
|
|||||||
return aCost <= mMaxCost - mLockedCost;
|
return aCost <= mMaxCost - mLockedCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkUsed(CachedSurface* aSurface, ImageSurfaceCache* aCache)
|
void MarkUsed(NotNull<CachedSurface*> aSurface,
|
||||||
|
NotNull<ImageSurfaceCache*> aCache)
|
||||||
{
|
{
|
||||||
if (aCache->IsLocked()) {
|
if (aCache->IsLocked()) {
|
||||||
LockSurface(aSurface);
|
LockSurface(aSurface);
|
||||||
@ -876,11 +853,11 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoUnlockSurfaces(ImageSurfaceCache* aCache)
|
void DoUnlockSurfaces(NotNull<ImageSurfaceCache*> aCache)
|
||||||
{
|
{
|
||||||
// Unlock all the surfaces the per-image cache is holding.
|
// Unlock all the surfaces the per-image cache is holding.
|
||||||
for (auto iter = aCache->ConstIter(); !iter.Done(); iter.Next()) {
|
for (auto iter = aCache->ConstIter(); !iter.Done(); iter.Next()) {
|
||||||
CachedSurface* surface = iter.UserData();
|
NotNull<CachedSurface*> surface = WrapNotNull(iter.UserData());
|
||||||
if (surface->IsPlaceholder() || !surface->IsLocked()) {
|
if (surface->IsPlaceholder() || !surface->IsLocked()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -903,7 +880,7 @@ private:
|
|||||||
return; // Lookup in the per-image cache missed.
|
return; // Lookup in the per-image cache missed.
|
||||||
}
|
}
|
||||||
|
|
||||||
Remove(surface);
|
Remove(WrapNotNull(surface));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SurfaceTracker : public nsExpirationTracker<CachedSurface, 2>
|
struct SurfaceTracker : public nsExpirationTracker<CachedSurface, 2>
|
||||||
@ -918,7 +895,7 @@ private:
|
|||||||
{
|
{
|
||||||
if (sInstance) {
|
if (sInstance) {
|
||||||
MutexAutoLock lock(sInstance->GetMutex());
|
MutexAutoLock lock(sInstance->GetMutex());
|
||||||
sInstance->Remove(aSurface);
|
sInstance->Remove(WrapNotNull(aSurface));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1061,20 +1038,7 @@ SurfaceCache::Insert(NotNull<ISurfaceProvider*> aProvider,
|
|||||||
|
|
||||||
MutexAutoLock lock(sInstance->GetMutex());
|
MutexAutoLock lock(sInstance->GetMutex());
|
||||||
Cost cost = aProvider->LogicalSizeInBytes();
|
Cost cost = aProvider->LogicalSizeInBytes();
|
||||||
return sInstance->Insert(aProvider.get(), cost, aImageKey, aSurfaceKey,
|
return sInstance->Insert(aProvider, cost, aImageKey, aSurfaceKey,
|
||||||
/* aSetAvailable = */ false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ InsertOutcome
|
|
||||||
SurfaceCache::InsertPlaceholder(const ImageKey aImageKey,
|
|
||||||
const SurfaceKey& aSurfaceKey)
|
|
||||||
{
|
|
||||||
if (!sInstance) {
|
|
||||||
return InsertOutcome::FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
MutexAutoLock lock(sInstance->GetMutex());
|
|
||||||
return sInstance->Insert(nullptr, sPlaceholderCost, aImageKey, aSurfaceKey,
|
|
||||||
/* aSetAvailable = */ false);
|
/* aSetAvailable = */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,8 +240,8 @@ struct SurfaceCache
|
|||||||
/**
|
/**
|
||||||
* Insert an ISurfaceProvider into the cache. If an entry with the same
|
* Insert an ISurfaceProvider into the cache. If an entry with the same
|
||||||
* ImageKey and SurfaceKey is already in the cache, Insert returns
|
* ImageKey and SurfaceKey is already in the cache, Insert returns
|
||||||
* FAILURE_ALREADY_PRESENT. If a matching placeholder is already present, the
|
* FAILURE_ALREADY_PRESENT. If a matching placeholder is already present, it
|
||||||
* placeholder is removed.
|
* is replaced.
|
||||||
*
|
*
|
||||||
* Cache entries will never expire as long as they remain locked, but if they
|
* Cache entries will never expire as long as they remain locked, but if they
|
||||||
* become unlocked, they can expire either because the SurfaceCache runs out
|
* become unlocked, they can expire either because the SurfaceCache runs out
|
||||||
@ -285,33 +285,6 @@ struct SurfaceCache
|
|||||||
const ImageKey aImageKey,
|
const ImageKey aImageKey,
|
||||||
const SurfaceKey& aSurfaceKey);
|
const SurfaceKey& aSurfaceKey);
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert a placeholder entry into the cache. If an entry with the same
|
|
||||||
* ImageKey and SurfaceKey is already in the cache, InsertPlaceholder()
|
|
||||||
* returns FAILURE_ALREADY_PRESENT.
|
|
||||||
*
|
|
||||||
* Placeholders exist to allow lazy allocation of surfaces. The Lookup*()
|
|
||||||
* methods will report whether a placeholder for an exactly matching cache
|
|
||||||
* entry existed by returning a MatchType of PENDING or
|
|
||||||
* SUBSTITUTE_BECAUSE_PENDING, but they will never return a placeholder
|
|
||||||
* directly. (They couldn't, since placeholders don't have an associated
|
|
||||||
* surface.)
|
|
||||||
*
|
|
||||||
* Placeholders are automatically removed when a real entry that matches the
|
|
||||||
* placeholder is inserted with Insert(), or when RemoveImage() is called.
|
|
||||||
*
|
|
||||||
* @param aImageKey Key data identifying which image the cache entry
|
|
||||||
* belongs to.
|
|
||||||
* @param aSurfaceKey Key data which uniquely identifies the requested
|
|
||||||
* cache entry.
|
|
||||||
* @return SUCCESS if the placeholder was inserted successfully.
|
|
||||||
* FAILURE if the placeholder could not be inserted for some reason.
|
|
||||||
* FAILURE_ALREADY_PRESENT if an entry with the same ImageKey and
|
|
||||||
* SurfaceKey already exists in the cache.
|
|
||||||
*/
|
|
||||||
static InsertOutcome InsertPlaceholder(const ImageKey aImageKey,
|
|
||||||
const SurfaceKey& aSurfaceKey);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark the cache entry @aProvider as having an available surface. This turns
|
* Mark the cache entry @aProvider as having an available surface. This turns
|
||||||
* a placeholder cache entry into a normal cache entry. The cache entry
|
* a placeholder cache entry into a normal cache entry. The cache entry
|
||||||
@ -325,14 +298,6 @@ struct SurfaceCache
|
|||||||
* definition, non-placeholder ISurfaceProviders should have a surface
|
* definition, non-placeholder ISurfaceProviders should have a surface
|
||||||
* available already.
|
* available already.
|
||||||
*
|
*
|
||||||
* XXX(seth): We're currently in a transitional state where two notions of
|
|
||||||
* placeholder exist: the old one (placeholders are an "empty" cache entry
|
|
||||||
* inserted via InsertPlaceholder(), which then gets replaced by inserting a
|
|
||||||
* real cache entry with the same keys via Insert()) and the new one (where
|
|
||||||
* the same cache entry, inserted via Insert(), starts in a placeholder state
|
|
||||||
* and then transitions to being a normal cache entry via this function). The
|
|
||||||
* old mechanism will be removed in bug 1292392.
|
|
||||||
*
|
|
||||||
* @param aProvider The cache entry that now has a surface available.
|
* @param aProvider The cache entry that now has a surface available.
|
||||||
* @param aImageKey Key data identifying which image the cache entry
|
* @param aImageKey Key data identifying which image the cache entry
|
||||||
* belongs to.
|
* belongs to.
|
||||||
@ -423,7 +388,7 @@ struct SurfaceCache
|
|||||||
static void UnlockEntries(const ImageKey aImageKey);
|
static void UnlockEntries(const ImageKey aImageKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all cache entries (both real and placeholder) associated with the
|
* Removes all cache entries (including placeholders) associated with the
|
||||||
* given image from the cache. If the image is locked, it is automatically
|
* given image from the cache. If the image is locked, it is automatically
|
||||||
* unlocked.
|
* unlocked.
|
||||||
*
|
*
|
||||||
|
@ -87,7 +87,7 @@ fuzzy(20,999) != downscale-2c.html?205,53,bottom about:blank
|
|||||||
fuzzy(20,999) != downscale-2d.html?205,53,bottom about:blank
|
fuzzy(20,999) != downscale-2d.html?205,53,bottom about:blank
|
||||||
fuzzy(20,999) fails-if(OSX>=1008&&!skiaContent) != downscale-2e.html?205,53,bottom about:blank
|
fuzzy(20,999) fails-if(OSX>=1008&&!skiaContent) != downscale-2e.html?205,53,bottom about:blank
|
||||||
|
|
||||||
fuzzy(52,3386) == downscale-moz-icon-1.html downscale-moz-icon-1-ref.html
|
fuzzy(63,3386) == downscale-moz-icon-1.html downscale-moz-icon-1-ref.html
|
||||||
|
|
||||||
== downscale-png.html?16,16,interlaced downscale-png.html?16,16,normal
|
== downscale-png.html?16,16,interlaced downscale-png.html?16,16,normal
|
||||||
== downscale-png.html?24,24,interlaced downscale-png.html?24,24,normal
|
== downscale-png.html?24,24,interlaced downscale-png.html?24,24,normal
|
||||||
@ -170,7 +170,8 @@ fuzzy(20,999) != downscale-2d.html?205,53,bottom about:blank
|
|||||||
fuzzy(20,999) != downscale-2e.html?205,53,bottom about:blank
|
fuzzy(20,999) != downscale-2e.html?205,53,bottom about:blank
|
||||||
fuzzy(20,999) != downscale-2f.html?205,53,bottom about:blank
|
fuzzy(20,999) != downscale-2f.html?205,53,bottom about:blank
|
||||||
|
|
||||||
fuzzy(71,4439) == downscale-moz-icon-1.html downscale-moz-icon-1-ref.html
|
# Skip on WinXP with skia content
|
||||||
|
fuzzy(71,4439) fails-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == downscale-moz-icon-1.html downscale-moz-icon-1-ref.html
|
||||||
|
|
||||||
== downscale-png.html?16,16,interlaced downscale-png.html?16,16,normal
|
== downscale-png.html?16,16,interlaced downscale-png.html?16,16,normal
|
||||||
== downscale-png.html?24,24,interlaced downscale-png.html?24,24,normal
|
== downscale-png.html?24,24,interlaced downscale-png.html?24,24,normal
|
||||||
|
@ -109,6 +109,41 @@ class UTF8CharsZ : public mozilla::RangedPtr<unsigned char>
|
|||||||
char* c_str() { return reinterpret_cast<char*>(get()); }
|
char* c_str() { return reinterpret_cast<char*>(get()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A wrapper for a "const char*" that is encoded using UTF-8.
|
||||||
|
* This class does not manage ownership of the data; that is left
|
||||||
|
* to others. This differs from UTF8CharsZ in that the chars are
|
||||||
|
* const and it allows assignment.
|
||||||
|
*/
|
||||||
|
class ConstUTF8CharsZ
|
||||||
|
{
|
||||||
|
const char* data_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ConstUTF8CharsZ() : data_(nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
ConstUTF8CharsZ(const char* aBytes, size_t aLength)
|
||||||
|
: data_(aBytes)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aBytes[aLength] == '\0');
|
||||||
|
#ifdef DEBUG
|
||||||
|
validate(aLength);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* get() const { return data_; }
|
||||||
|
|
||||||
|
const char* c_str() const { return data_; }
|
||||||
|
|
||||||
|
explicit operator bool() const { return data_ != nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef DEBUG
|
||||||
|
void validate(size_t aLength);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SpiderMonkey uses a 2-byte character representation: it is a
|
* SpiderMonkey uses a 2-byte character representation: it is a
|
||||||
* 2-byte-at-a-time view of a UTF-16 byte stream. This is similar to UCS-2,
|
* 2-byte-at-a-time view of a UTF-16 byte stream. This is similar to UCS-2,
|
||||||
@ -197,6 +232,12 @@ Utf8ToOneUcs4Char(const uint8_t* utf8Buffer, int utf8Length);
|
|||||||
extern TwoByteCharsZ
|
extern TwoByteCharsZ
|
||||||
UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen);
|
UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like UTF8CharsToNewTwoByteCharsZ, but for ConstUTF8CharsZ.
|
||||||
|
*/
|
||||||
|
extern TwoByteCharsZ
|
||||||
|
UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The same as UTF8CharsToNewTwoByteCharsZ(), except that any malformed UTF-8 characters
|
* The same as UTF8CharsToNewTwoByteCharsZ(), except that any malformed UTF-8 characters
|
||||||
* will be replaced by \uFFFD. No exception will be thrown for malformed UTF-8
|
* will be replaced by \uFFFD. No exception will be thrown for malformed UTF-8
|
||||||
@ -205,6 +246,9 @@ UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen)
|
|||||||
extern TwoByteCharsZ
|
extern TwoByteCharsZ
|
||||||
LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen);
|
LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen);
|
||||||
|
|
||||||
|
extern TwoByteCharsZ
|
||||||
|
LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the length of the char buffer required to encode |s| as UTF8.
|
* Returns the length of the char buffer required to encode |s| as UTF8.
|
||||||
* Does not include the null-terminator.
|
* Does not include the null-terminator.
|
||||||
|
@ -45,6 +45,23 @@
|
|||||||
#include "js/TraceKind.h"
|
#include "js/TraceKind.h"
|
||||||
#include "js/TracingAPI.h"
|
#include "js/TracingAPI.h"
|
||||||
|
|
||||||
|
// Expand the given macro D for each public GC pointer.
|
||||||
|
#define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \
|
||||||
|
D(JS::Symbol*) \
|
||||||
|
D(JSAtom*) \
|
||||||
|
D(JSFunction*) \
|
||||||
|
D(JSObject*) \
|
||||||
|
D(JSScript*) \
|
||||||
|
D(JSString*)
|
||||||
|
|
||||||
|
// Expand the given macro D for each public tagged GC pointer type.
|
||||||
|
#define FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(D) \
|
||||||
|
D(JS::Value) \
|
||||||
|
D(jsid)
|
||||||
|
|
||||||
|
#define FOR_EACH_PUBLIC_AGGREGATE_GC_POINTER_TYPE(D) \
|
||||||
|
D(JSPropertyDescriptor)
|
||||||
|
|
||||||
class JSAtom;
|
class JSAtom;
|
||||||
class JSFunction;
|
class JSFunction;
|
||||||
class JSObject;
|
class JSObject;
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#include "mozilla/Move.h"
|
#include "mozilla/Move.h"
|
||||||
#include "mozilla/TypeTraits.h"
|
#include "mozilla/TypeTraits.h"
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "jspubtd.h"
|
#include "jspubtd.h"
|
||||||
|
|
||||||
#include "js/GCAnnotations.h"
|
#include "js/GCAnnotations.h"
|
||||||
@ -123,6 +125,14 @@ class MutableHandleBase {};
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
class HeapBase {};
|
class HeapBase {};
|
||||||
|
|
||||||
|
// Cannot use FOR_EACH_HEAP_ABLE_GC_POINTER_TYPE, as this would import too many macros into scope
|
||||||
|
template <typename T> struct IsHeapConstructibleType { static constexpr bool value = false; };
|
||||||
|
#define DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE(T) \
|
||||||
|
template <> struct IsHeapConstructibleType<T> { static constexpr bool value = true; };
|
||||||
|
FOR_EACH_PUBLIC_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
|
||||||
|
FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
|
||||||
|
#undef DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class PersistentRootedBase {};
|
class PersistentRootedBase {};
|
||||||
|
|
||||||
@ -214,11 +224,14 @@ AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell) {}
|
|||||||
* Heap<T> objects should only be used on the heap. GC references stored on the
|
* Heap<T> objects should only be used on the heap. GC references stored on the
|
||||||
* C/C++ stack must use Rooted/Handle/MutableHandle instead.
|
* C/C++ stack must use Rooted/Handle/MutableHandle instead.
|
||||||
*
|
*
|
||||||
* Type T must be one of: JS::Value, jsid, JSObject*, JSString*, JSScript*
|
* Type T must be a public GC pointer type.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Heap : public js::HeapBase<T>
|
class Heap : public js::HeapBase<T>
|
||||||
{
|
{
|
||||||
|
// Please note: this can actually also be used by nsXBLMaybeCompiled<T>, for legacy reasons.
|
||||||
|
static_assert(js::IsHeapConstructibleType<T>::value,
|
||||||
|
"Type T must be a public GC pointer type");
|
||||||
public:
|
public:
|
||||||
Heap() {
|
Heap() {
|
||||||
static_assert(sizeof(T) == sizeof(Heap<T>),
|
static_assert(sizeof(T) == sizeof(Heap<T>),
|
||||||
|
@ -2791,9 +2791,12 @@ EdgeNeedsSweep(JS::Heap<T>* thingp)
|
|||||||
template bool IsMarked<type>(WriteBarrieredBase<type>*); \
|
template bool IsMarked<type>(WriteBarrieredBase<type>*); \
|
||||||
template bool IsAboutToBeFinalizedUnbarriered<type>(type*); \
|
template bool IsAboutToBeFinalizedUnbarriered<type>(type*); \
|
||||||
template bool IsAboutToBeFinalized<type>(WriteBarrieredBase<type>*); \
|
template bool IsAboutToBeFinalized<type>(WriteBarrieredBase<type>*); \
|
||||||
template bool IsAboutToBeFinalized<type>(ReadBarrieredBase<type>*); \
|
template bool IsAboutToBeFinalized<type>(ReadBarrieredBase<type>*);
|
||||||
|
#define INSTANTIATE_ALL_VALID_HEAP_TRACE_FUNCTIONS(type) \
|
||||||
template JS_PUBLIC_API(bool) EdgeNeedsSweep<type>(JS::Heap<type>*);
|
template JS_PUBLIC_API(bool) EdgeNeedsSweep<type>(JS::Heap<type>*);
|
||||||
FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)
|
FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)
|
||||||
|
FOR_EACH_PUBLIC_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_HEAP_TRACE_FUNCTIONS)
|
||||||
|
FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_HEAP_TRACE_FUNCTIONS)
|
||||||
#undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS
|
#undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS
|
||||||
|
|
||||||
} /* namespace gc */
|
} /* namespace gc */
|
||||||
|
@ -58,23 +58,6 @@ class JitCode;
|
|||||||
} // namespace jit
|
} // namespace jit
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
// Expand the given macro D for each public GC pointer.
|
|
||||||
#define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \
|
|
||||||
D(JS::Symbol*) \
|
|
||||||
D(JSAtom*) \
|
|
||||||
D(JSFunction*) \
|
|
||||||
D(JSObject*) \
|
|
||||||
D(JSScript*) \
|
|
||||||
D(JSString*)
|
|
||||||
|
|
||||||
// Expand the given macro D for each public tagged GC pointer type.
|
|
||||||
#define FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(D) \
|
|
||||||
D(JS::Value) \
|
|
||||||
D(jsid)
|
|
||||||
|
|
||||||
#define FOR_EACH_PUBLIC_AGGREGATE_GC_POINTER_TYPE(D) \
|
|
||||||
D(JSPropertyDescriptor)
|
|
||||||
|
|
||||||
// Expand the given macro D for each valid GC reference type.
|
// Expand the given macro D for each valid GC reference type.
|
||||||
#define FOR_EACH_INTERNAL_GC_POINTER_TYPE(D) \
|
#define FOR_EACH_INTERNAL_GC_POINTER_TYPE(D) \
|
||||||
D(JSFlatString*) \
|
D(JSFlatString*) \
|
||||||
|
8
js/src/jit-test/tests/debug/Frame-eval-32.js
Normal file
8
js/src/jit-test/tests/debug/Frame-eval-32.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// |jit-test| error: ReferenceError
|
||||||
|
|
||||||
|
// Test the TDZ works for glbao lexicals through Debugger environments in
|
||||||
|
// compound assignments.
|
||||||
|
load(libdir + "evalInFrame.js");
|
||||||
|
|
||||||
|
evalInFrame(0, "x |= 0");
|
||||||
|
let x;
|
@ -1,3 +1,5 @@
|
|||||||
|
// |jit-test| error: ReferenceError
|
||||||
|
|
||||||
load(libdir + "evalInFrame.js");
|
load(libdir + "evalInFrame.js");
|
||||||
evalInFrame(1, "a = 43");
|
evalInFrame(1, "a = 43");
|
||||||
let a = 42;
|
let a = 42;
|
||||||
|
10
js/src/jit-test/tests/promise/no-reentrant-drainjobqueue.js
Normal file
10
js/src/jit-test/tests/promise/no-reentrant-drainjobqueue.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
let thenCalled = false;
|
||||||
|
let p1 = new Promise(res => res('result')).then(val => {
|
||||||
|
Promise.resolve(1).then(_=>{thenCalled = true;});
|
||||||
|
// This reentrant call is ignored.
|
||||||
|
drainJobQueue();
|
||||||
|
assertEq(thenCalled, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
drainJobQueue();
|
||||||
|
assertEq(thenCalled, true);
|
@ -1113,7 +1113,7 @@ GenerateCallGetter(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
|||||||
|
|
||||||
// Note: this may clobber the object register if it's used as scratch.
|
// Note: this may clobber the object register if it's used as scratch.
|
||||||
if (obj != holder)
|
if (obj != holder)
|
||||||
GeneratePrototypeGuards(cx, ion, masm, obj, holder, object, scratchReg, failures);
|
GeneratePrototypeGuards(cx, ion, masm, obj, holder, object, scratchReg, maybePopAndFail);
|
||||||
|
|
||||||
// Guard on the holder's shape.
|
// Guard on the holder's shape.
|
||||||
Register holderReg = scratchReg;
|
Register holderReg = scratchReg;
|
||||||
|
@ -4518,7 +4518,8 @@ struct JS_PUBLIC_API(AsyncTask)
|
|||||||
*
|
*
|
||||||
* If this function succeeds, SpiderMonkey will call the FinishAsyncTaskCallback
|
* If this function succeeds, SpiderMonkey will call the FinishAsyncTaskCallback
|
||||||
* at some point in the future. Otherwise, FinishAsyncTaskCallback will *not*
|
* at some point in the future. Otherwise, FinishAsyncTaskCallback will *not*
|
||||||
* be called.
|
* be called. SpiderMonkey assumes that, if StartAsyncTaskCallback fails, it is
|
||||||
|
* because the JSContext is being shut down.
|
||||||
*/
|
*/
|
||||||
typedef bool
|
typedef bool
|
||||||
(*StartAsyncTaskCallback)(JSContext* cx, AsyncTask* task);
|
(*StartAsyncTaskCallback)(JSContext* cx, AsyncTask* task);
|
||||||
|
@ -2230,7 +2230,22 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e
|
|||||||
|
|
||||||
// See note above RuntimeLexicalErrorObject.
|
// See note above RuntimeLexicalErrorObject.
|
||||||
if (pobj == env) {
|
if (pobj == env) {
|
||||||
if (name != cx->names().dotThis && IsUninitializedLexicalSlot(env, shape)) {
|
bool isTDZ = false;
|
||||||
|
if (shape && name != cx->names().dotThis) {
|
||||||
|
// Treat Debugger environments specially for TDZ checks, as they
|
||||||
|
// look like non-native environments but in fact wrap native
|
||||||
|
// environments.
|
||||||
|
if (env->is<DebugEnvironmentProxy>()) {
|
||||||
|
RootedValue v(cx);
|
||||||
|
if (!env->as<DebugEnvironmentProxy>().getMaybeSentinelValue(cx, id, &v))
|
||||||
|
return false;
|
||||||
|
isTDZ = IsUninitializedLexical(v);
|
||||||
|
} else {
|
||||||
|
isTDZ = IsUninitializedLexicalSlot(env, shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTDZ) {
|
||||||
env = RuntimeLexicalErrorObject::create(cx, env, JSMSG_UNINITIALIZED_LEXICAL);
|
env = RuntimeLexicalErrorObject::create(cx, env, JSMSG_UNINITIALIZED_LEXICAL);
|
||||||
if (!env)
|
if (!env)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1218,7 +1218,7 @@ dnl Checks for library functions.
|
|||||||
dnl ========================================================
|
dnl ========================================================
|
||||||
AC_PROG_GCC_TRADITIONAL
|
AC_PROG_GCC_TRADITIONAL
|
||||||
AC_FUNC_MEMCMP
|
AC_FUNC_MEMCMP
|
||||||
AC_CHECK_FUNCS([getc_unlocked _getc_nolock gmtime_r localtime_r])
|
AC_CHECK_FUNCS([getc_unlocked _getc_nolock gmtime_r localtime_r pthread_getname_np])
|
||||||
|
|
||||||
dnl check for clock_gettime(), the CLOCK_MONOTONIC clock
|
dnl check for clock_gettime(), the CLOCK_MONOTONIC clock
|
||||||
AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC),
|
AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC),
|
||||||
|
@ -264,6 +264,7 @@ struct ShellContext
|
|||||||
JS::PersistentRootedValue promiseRejectionTrackerCallback;
|
JS::PersistentRootedValue promiseRejectionTrackerCallback;
|
||||||
JS::PersistentRooted<JobQueue> jobQueue;
|
JS::PersistentRooted<JobQueue> jobQueue;
|
||||||
ExclusiveData<ShellAsyncTasks> asyncTasks;
|
ExclusiveData<ShellAsyncTasks> asyncTasks;
|
||||||
|
bool drainingJobQueue;
|
||||||
#endif // SPIDERMONKEY_PROMISE
|
#endif // SPIDERMONKEY_PROMISE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -428,6 +429,7 @@ ShellContext::ShellContext(JSContext* cx)
|
|||||||
#ifdef SPIDERMONKEY_PROMISE
|
#ifdef SPIDERMONKEY_PROMISE
|
||||||
promiseRejectionTrackerCallback(cx, NullValue()),
|
promiseRejectionTrackerCallback(cx, NullValue()),
|
||||||
asyncTasks(cx),
|
asyncTasks(cx),
|
||||||
|
drainingJobQueue(false),
|
||||||
#endif // SPIDERMONKEY_PROMISE
|
#endif // SPIDERMONKEY_PROMISE
|
||||||
exitCode(0),
|
exitCode(0),
|
||||||
quitting(false),
|
quitting(false),
|
||||||
@ -771,7 +773,7 @@ DrainJobQueue(JSContext* cx)
|
|||||||
{
|
{
|
||||||
#ifdef SPIDERMONKEY_PROMISE
|
#ifdef SPIDERMONKEY_PROMISE
|
||||||
ShellContext* sc = GetShellContext(cx);
|
ShellContext* sc = GetShellContext(cx);
|
||||||
if (sc->quitting)
|
if (sc->quitting || sc->drainingJobQueue)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Wait for any outstanding async tasks to finish so that the
|
// Wait for any outstanding async tasks to finish so that the
|
||||||
@ -792,6 +794,12 @@ DrainJobQueue(JSContext* cx)
|
|||||||
asyncTasks->finished.clear();
|
asyncTasks->finished.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It doesn't make sense for job queue draining to be reentrant. At the
|
||||||
|
// same time we don't want to assert against it, because that'd make
|
||||||
|
// drainJobQueue unsafe for fuzzers. We do want fuzzers to test this, so
|
||||||
|
// we simply ignore nested calls of drainJobQueue.
|
||||||
|
sc->drainingJobQueue = true;
|
||||||
|
|
||||||
RootedObject job(cx);
|
RootedObject job(cx);
|
||||||
JS::HandleValueArray args(JS::HandleValueArray::empty());
|
JS::HandleValueArray args(JS::HandleValueArray::empty());
|
||||||
RootedValue rval(cx);
|
RootedValue rval(cx);
|
||||||
@ -808,6 +816,7 @@ DrainJobQueue(JSContext* cx)
|
|||||||
sc->jobQueue[i].set(nullptr);
|
sc->jobQueue[i].set(nullptr);
|
||||||
}
|
}
|
||||||
sc->jobQueue.clear();
|
sc->jobQueue.clear();
|
||||||
|
sc->drainingJobQueue = false;
|
||||||
#endif // SPIDERMONKEY_PROMISE
|
#endif // SPIDERMONKEY_PROMISE
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,12 @@ Thread::Id GetId();
|
|||||||
// nothing.
|
// nothing.
|
||||||
void SetName(const char* name);
|
void SetName(const char* name);
|
||||||
|
|
||||||
|
// Get the current thread name. As with SetName, not available on all
|
||||||
|
// platforms. On these platforms getName() will give back an empty string (by
|
||||||
|
// storing NUL in nameBuffer[0]). 'len' is the bytes available to be written in
|
||||||
|
// 'nameBuffer', including the terminating NUL.
|
||||||
|
void GetName(char* nameBuffer, size_t len);
|
||||||
|
|
||||||
} // namespace ThisThread
|
} // namespace ThisThread
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
@ -164,3 +164,24 @@ js::ThisThread::SetName(const char* name)
|
|||||||
#endif
|
#endif
|
||||||
MOZ_RELEASE_ASSERT(!rv);
|
MOZ_RELEASE_ASSERT(!rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
js::ThisThread::GetName(char* nameBuffer, size_t len)
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(len >= 16);
|
||||||
|
|
||||||
|
int rv;
|
||||||
|
#ifdef HAVE_PTHREAD_GETNAME_NP
|
||||||
|
rv = pthread_getname_np(pthread_self(), nameBuffer, len);
|
||||||
|
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
|
pthread_get_name_np(pthread_self(), nameBuffer, len);
|
||||||
|
rv = 0;
|
||||||
|
#elif defined(__linux__)
|
||||||
|
rv = prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(nameBuffer));
|
||||||
|
#else
|
||||||
|
# error "unsupported platform: no way to read thread name"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (rv)
|
||||||
|
nameBuffer[0] = '\0';
|
||||||
|
}
|
||||||
|
@ -155,3 +155,10 @@ js::ThisThread::SetName(const char* name)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
js::ThisThread::GetName(char* nameBuffer, size_t len)
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(len > 0);
|
||||||
|
*nameBuffer = '\0';
|
||||||
|
}
|
||||||
|
@ -249,6 +249,7 @@ ReportTooBigCharacter(JSContext* cx, uint32_t v)
|
|||||||
enum InflateUTF8Action {
|
enum InflateUTF8Action {
|
||||||
CountAndReportInvalids,
|
CountAndReportInvalids,
|
||||||
CountAndIgnoreInvalids,
|
CountAndIgnoreInvalids,
|
||||||
|
AssertNoInvalids,
|
||||||
Copy
|
Copy
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -256,12 +257,13 @@ static const uint32_t REPLACE_UTF8 = 0xFFFD;
|
|||||||
|
|
||||||
// If making changes to this algorithm, make sure to also update
|
// If making changes to this algorithm, make sure to also update
|
||||||
// LossyConvertUTF8toUTF16() in dom/wifi/WifiUtils.cpp
|
// LossyConvertUTF8toUTF16() in dom/wifi/WifiUtils.cpp
|
||||||
template <InflateUTF8Action action>
|
template <InflateUTF8Action Action>
|
||||||
static bool
|
static bool
|
||||||
InflateUTF8StringToBuffer(JSContext* cx, const UTF8Chars src, char16_t* dst, size_t* dstlenp,
|
InflateUTF8StringToBuffer(JSContext* cx, const UTF8Chars src, char16_t* dst, size_t* dstlenp,
|
||||||
bool* isAsciip)
|
bool* isAsciip)
|
||||||
{
|
{
|
||||||
*isAsciip = true;
|
if (Action != AssertNoInvalids)
|
||||||
|
*isAsciip = true;
|
||||||
|
|
||||||
// Count how many char16_t characters need to be in the inflated string.
|
// Count how many char16_t characters need to be in the inflated string.
|
||||||
// |i| is the index into |src|, and |j| is the the index into |dst|.
|
// |i| is the index into |src|, and |j| is the the index into |dst|.
|
||||||
@ -271,26 +273,29 @@ InflateUTF8StringToBuffer(JSContext* cx, const UTF8Chars src, char16_t* dst, siz
|
|||||||
uint32_t v = uint32_t(src[i]);
|
uint32_t v = uint32_t(src[i]);
|
||||||
if (!(v & 0x80)) {
|
if (!(v & 0x80)) {
|
||||||
// ASCII code unit. Simple copy.
|
// ASCII code unit. Simple copy.
|
||||||
if (action == Copy)
|
if (Action == Copy)
|
||||||
dst[j] = char16_t(v);
|
dst[j] = char16_t(v);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Non-ASCII code unit. Determine its length in bytes (n).
|
// Non-ASCII code unit. Determine its length in bytes (n).
|
||||||
*isAsciip = false;
|
if (Action != AssertNoInvalids)
|
||||||
|
*isAsciip = false;
|
||||||
uint32_t n = 1;
|
uint32_t n = 1;
|
||||||
while (v & (0x80 >> n))
|
while (v & (0x80 >> n))
|
||||||
n++;
|
n++;
|
||||||
|
|
||||||
#define INVALID(report, arg, n2) \
|
#define INVALID(report, arg, n2) \
|
||||||
do { \
|
do { \
|
||||||
if (action == CountAndReportInvalids) { \
|
if (Action == CountAndReportInvalids) { \
|
||||||
report(cx, arg); \
|
report(cx, arg); \
|
||||||
return false; \
|
return false; \
|
||||||
|
} else if (Action == AssertNoInvalids) { \
|
||||||
|
MOZ_CRASH("invalid UTF-8 string: " # report); \
|
||||||
} else { \
|
} else { \
|
||||||
if (action == Copy) \
|
if (Action == Copy) \
|
||||||
dst[j] = char16_t(REPLACE_UTF8); \
|
dst[j] = char16_t(REPLACE_UTF8); \
|
||||||
else \
|
else \
|
||||||
MOZ_ASSERT(action == CountAndIgnoreInvalids); \
|
MOZ_ASSERT(Action == CountAndIgnoreInvalids); \
|
||||||
n = n2; \
|
n = n2; \
|
||||||
goto invalidMultiByteCodeUnit; \
|
goto invalidMultiByteCodeUnit; \
|
||||||
} \
|
} \
|
||||||
@ -323,17 +328,17 @@ InflateUTF8StringToBuffer(JSContext* cx, const UTF8Chars src, char16_t* dst, siz
|
|||||||
v = JS::Utf8ToOneUcs4Char((uint8_t*)&src[i], n);
|
v = JS::Utf8ToOneUcs4Char((uint8_t*)&src[i], n);
|
||||||
if (v < 0x10000) {
|
if (v < 0x10000) {
|
||||||
// The n-byte UTF8 code unit will fit in a single char16_t.
|
// The n-byte UTF8 code unit will fit in a single char16_t.
|
||||||
if (action == Copy)
|
if (Action == Copy)
|
||||||
dst[j] = char16_t(v);
|
dst[j] = char16_t(v);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
v -= 0x10000;
|
v -= 0x10000;
|
||||||
if (v <= 0xFFFFF) {
|
if (v <= 0xFFFFF) {
|
||||||
// The n-byte UTF8 code unit will fit in two char16_t units.
|
// The n-byte UTF8 code unit will fit in two char16_t units.
|
||||||
if (action == Copy)
|
if (Action == Copy)
|
||||||
dst[j] = char16_t((v >> 10) + 0xD800);
|
dst[j] = char16_t((v >> 10) + 0xD800);
|
||||||
j++;
|
j++;
|
||||||
if (action == Copy)
|
if (Action == Copy)
|
||||||
dst[j] = char16_t((v & 0x3FF) + 0xDC00);
|
dst[j] = char16_t((v & 0x3FF) + 0xDC00);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -350,20 +355,20 @@ InflateUTF8StringToBuffer(JSContext* cx, const UTF8Chars src, char16_t* dst, siz
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*dstlenp = j;
|
if (Action != AssertNoInvalids)
|
||||||
|
*dstlenp = j;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef bool (*CountAction)(JSContext*, const UTF8Chars, char16_t*, size_t*, bool* isAsciip);
|
template <InflateUTF8Action Action>
|
||||||
|
|
||||||
static TwoByteCharsZ
|
static TwoByteCharsZ
|
||||||
InflateUTF8StringHelper(JSContext* cx, const UTF8Chars src, CountAction countAction, size_t* outlen)
|
InflateUTF8StringHelper(JSContext* cx, const UTF8Chars src, size_t* outlen)
|
||||||
{
|
{
|
||||||
*outlen = 0;
|
*outlen = 0;
|
||||||
|
|
||||||
bool isAscii;
|
bool isAscii;
|
||||||
if (!countAction(cx, src, /* dst = */ nullptr, outlen, &isAscii))
|
if (!InflateUTF8StringToBuffer<Action>(cx, src, /* dst = */ nullptr, outlen, &isAscii))
|
||||||
return TwoByteCharsZ();
|
return TwoByteCharsZ();
|
||||||
|
|
||||||
char16_t* dst = cx->pod_malloc<char16_t>(*outlen + 1); // +1 for NUL
|
char16_t* dst = cx->pod_malloc<char16_t>(*outlen + 1); // +1 for NUL
|
||||||
@ -390,14 +395,35 @@ InflateUTF8StringHelper(JSContext* cx, const UTF8Chars src, CountAction countAct
|
|||||||
TwoByteCharsZ
|
TwoByteCharsZ
|
||||||
JS::UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen)
|
JS::UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen)
|
||||||
{
|
{
|
||||||
return InflateUTF8StringHelper(cx, utf8, InflateUTF8StringToBuffer<CountAndReportInvalids>,
|
return InflateUTF8StringHelper<CountAndReportInvalids>(cx, utf8, outlen);
|
||||||
outlen);
|
}
|
||||||
|
|
||||||
|
TwoByteCharsZ
|
||||||
|
JS::UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen)
|
||||||
|
{
|
||||||
|
UTF8Chars chars(utf8.c_str(), strlen(utf8.c_str()));
|
||||||
|
return InflateUTF8StringHelper<CountAndReportInvalids>(cx, chars, outlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
TwoByteCharsZ
|
TwoByteCharsZ
|
||||||
JS::LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen)
|
JS::LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen)
|
||||||
{
|
{
|
||||||
return InflateUTF8StringHelper(cx, utf8, InflateUTF8StringToBuffer<CountAndIgnoreInvalids>,
|
return InflateUTF8StringHelper<CountAndIgnoreInvalids>(cx, utf8, outlen);
|
||||||
outlen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TwoByteCharsZ
|
||||||
|
JS::LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen)
|
||||||
|
{
|
||||||
|
UTF8Chars chars(utf8.c_str(), strlen(utf8.c_str()));
|
||||||
|
return InflateUTF8StringHelper<CountAndIgnoreInvalids>(cx, chars, outlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
void
|
||||||
|
JS::ConstUTF8CharsZ::validate(size_t aLength)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(data_);
|
||||||
|
UTF8Chars chars(data_, aLength);
|
||||||
|
InflateUTF8StringToBuffer<AssertNoInvalids>(nullptr, chars, nullptr, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -4845,7 +4845,7 @@ Debugger::setupTraceLogger(JSContext* cx, unsigned argc, Value* vp)
|
|||||||
|
|
||||||
uint32_t textId = TLStringToTextId(linear);
|
uint32_t textId = TLStringToTextId(linear);
|
||||||
|
|
||||||
if (!TLTextIdIsToggable(textId)) {
|
if (!TLTextIdIsTogglable(textId)) {
|
||||||
args.rval().setBoolean(false);
|
args.rval().setBoolean(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1587,14 +1587,20 @@ js::StartOffThreadCompression(ExclusiveContext* cx, SourceCompressionTask* task)
|
|||||||
bool
|
bool
|
||||||
js::StartPromiseTask(JSContext* cx, UniquePtr<PromiseTask> task)
|
js::StartPromiseTask(JSContext* cx, UniquePtr<PromiseTask> task)
|
||||||
{
|
{
|
||||||
|
// If we fail to start, by interface contract, it is because the JSContext
|
||||||
|
// is in the process of shutting down. Since promise handlers are not
|
||||||
|
// necessarily run while shutting down *anyway*, we simply ignore the error.
|
||||||
|
// This is symmetric with the handling of errors in finishAsyncTaskCallback
|
||||||
|
// which, since it is off the JSContext's owner thread, cannot report an
|
||||||
|
// error anyway.
|
||||||
|
if (!cx->startAsyncTaskCallback(cx, task.get())) {
|
||||||
|
MOZ_ASSERT(!cx->isExceptionPending());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Per interface contract, after startAsyncTaskCallback succeeds,
|
// Per interface contract, after startAsyncTaskCallback succeeds,
|
||||||
// finishAsyncTaskCallback *must* be called on all paths.
|
// finishAsyncTaskCallback *must* be called on all paths.
|
||||||
|
|
||||||
if (!cx->startAsyncTaskCallback(cx, task.get())) {
|
|
||||||
ReportOutOfMemory(cx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoLockHelperThreadState lock;
|
AutoLockHelperThreadState lock;
|
||||||
|
|
||||||
if (!HelperThreadState().promiseTasks(lock).append(task.get())) {
|
if (!HelperThreadState().promiseTasks(lock).append(task.get())) {
|
||||||
|
@ -81,14 +81,14 @@ IsUninitializedLexical(const Value& val)
|
|||||||
static inline bool
|
static inline bool
|
||||||
IsUninitializedLexicalSlot(HandleObject obj, HandleShape shape)
|
IsUninitializedLexicalSlot(HandleObject obj, HandleShape shape)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(shape);
|
||||||
if (obj->is<WithEnvironmentObject>())
|
if (obj->is<WithEnvironmentObject>())
|
||||||
return false;
|
return false;
|
||||||
// We check for IsImplicitDenseOrTypedArrayElement even though the shape
|
// We check for IsImplicitDenseOrTypedArrayElement even though the shape
|
||||||
// is always a non-indexed property because proxy hooks may return a
|
// is always a non-indexed property because proxy hooks may return a
|
||||||
// "non-native property found" shape, which happens to be encoded in the
|
// "non-native property found" shape, which happens to be encoded in the
|
||||||
// same way as the "dense element" shape. See MarkNonNativePropertyFound.
|
// same way as the "dense element" shape. See MarkNonNativePropertyFound.
|
||||||
if (!shape ||
|
if (IsImplicitDenseOrTypedArrayElement(shape) ||
|
||||||
IsImplicitDenseOrTypedArrayElement(shape) ||
|
|
||||||
!shape->hasSlot() ||
|
!shape->hasSlot() ||
|
||||||
!shape->hasDefaultGetter() ||
|
!shape->hasDefaultGetter() ||
|
||||||
!shape->hasDefaultSetter())
|
!shape->hasDefaultSetter())
|
||||||
|
@ -4428,10 +4428,9 @@ js::ThrowMsgOperation(JSContext* cx, const unsigned errorNum)
|
|||||||
bool
|
bool
|
||||||
js::GetAndClearException(JSContext* cx, MutableHandleValue res)
|
js::GetAndClearException(JSContext* cx, MutableHandleValue res)
|
||||||
{
|
{
|
||||||
bool status = cx->getPendingException(res);
|
if (!cx->getPendingException(res))
|
||||||
cx->clearPendingException();
|
|
||||||
if (!status)
|
|
||||||
return false;
|
return false;
|
||||||
|
cx->clearPendingException();
|
||||||
|
|
||||||
// Allow interrupting deeply nested exception handling.
|
// Allow interrupting deeply nested exception handling.
|
||||||
return CheckForInterrupt(cx);
|
return CheckForInterrupt(cx);
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
# include "asmjs/WasmSignalHandlers.h"
|
# include "asmjs/WasmSignalHandlers.h"
|
||||||
#endif
|
#endif
|
||||||
#include "builtin/AtomicsObject.h"
|
#include "builtin/AtomicsObject.h"
|
||||||
|
#include "builtin/Promise.h"
|
||||||
#include "ds/FixedSizeHash.h"
|
#include "ds/FixedSizeHash.h"
|
||||||
#include "frontend/NameCollections.h"
|
#include "frontend/NameCollections.h"
|
||||||
#include "gc/GCRuntime.h"
|
#include "gc/GCRuntime.h"
|
||||||
@ -66,8 +67,7 @@ class EnterDebuggeeNoExecute;
|
|||||||
class TraceLoggerThread;
|
class TraceLoggerThread;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class PromiseTask;
|
typedef Vector<UniquePtr<PromiseTask>, 0, SystemAllocPolicy> PromiseTaskPtrVector;
|
||||||
typedef Vector<PromiseTask*, 0, SystemAllocPolicy> PromiseTaskPtrVector;
|
|
||||||
|
|
||||||
/* Thread Local Storage slot for storing the runtime for a thread. */
|
/* Thread Local Storage slot for storing the runtime for a thread. */
|
||||||
extern MOZ_THREAD_LOCAL(PerThreadData*) TlsPerThreadData;
|
extern MOZ_THREAD_LOCAL(PerThreadData*) TlsPerThreadData;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user