Merge m-c to autoland. a=merge

This commit is contained in:
Ryan VanderMeulen 2016-08-26 09:38:49 -04:00
Родитель 0f34b42611 e1fdfb3b73
Коммит 4a76c08262
269 изменённых файлов: 7252 добавлений и 3626 удалений

Просмотреть файл

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# 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);
},
/**
* 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
* nsIUpdateCheckListener are in a different scope from nsIIncrementalDownload
@ -287,11 +272,6 @@ appUpdater.prototype =
return;
}
if (gAppUpdater.update.billboardURL) {
gAppUpdater.selectPanel("applyBillboard");
return;
}
if (gAppUpdater.updateAuto) // automatically download and install
gAppUpdater.startDownload();
else // ask

Просмотреть файл

@ -78,13 +78,6 @@
oncommand="gAppUpdater.buttonRestartAfterDownload();"/>
<spacer flex="1"/>
</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">
<image class="update-throbber"/><label>&update.checkingForUpdates;</label>
</hbox>

Просмотреть файл

@ -538,20 +538,6 @@ Sanitizer.prototype = {
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 {
// Clear site security settings - no support for ranges in this
// interface either, so we clearAll().

Просмотреть файл

@ -484,7 +484,7 @@ skip-if = (os == "win" && !debug)
[browser_windowopen_reflows.js]
skip-if = buildapp == 'mulet'
[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_no_mcb_on_http_site.js]
tags = mcb

Просмотреть файл

@ -91,6 +91,14 @@ XPCOMUtils.defineLazyGetter(this, "standaloneStylesheets", () => {
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 {
constructor(extension, viewNode, popupURL, browserStyle, fixedWidth = false) {
this.extension = extension;
@ -129,8 +137,10 @@ class BasePopup {
this.viewNode.removeEventListener(this.DESTROY_EVENT, this);
this.viewNode.style.maxHeight = "";
this.panel.style.removeProperty("--panel-arrowcontent-background");
this.panel.style.removeProperty("--panel-arrow-image-vertical");
if (this.panel) {
this.panel.style.removeProperty("--panel-arrowcontent-background");
this.panel.style.removeProperty("--panel-arrow-image-vertical");
}
this.browser = null;
this.viewNode = null;
@ -154,7 +164,7 @@ class BasePopup {
get panel() {
let panel = this.viewNode;
while (panel.localName != "panel") {
while (panel && panel.localName != "panel") {
panel = panel.parentNode;
}
return panel;

Просмотреть файл

@ -49,6 +49,7 @@ tags = webextensions
[browser_ext_popup_api_injection.js]
[browser_ext_popup_background.js]
[browser_ext_popup_corners.js]
[browser_ext_popup_shutdown.js]
[browser_ext_runtime_openOptionsPage.js]
[browser_ext_runtime_openOptionsPage_uninstall.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/. -->
<!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.
# The button when displayed is located directly under the Firefox version in
# the about dialog (see bug 596813 for screenshots).
-->
<!ENTITY update.checkForUpdatesButton.label "Check for updates">
<!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.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. -->

Просмотреть файл

@ -64,8 +64,6 @@
width: 16px;
height: 16px;
list-style-image: url(chrome://browser/skin/identity-icon.svg#normal);
filter: url(chrome://browser/skin/filters.svg#fill);
fill: currentColor;
opacity: .5;
}
@ -151,8 +149,6 @@
margin-inline-start: 2px;
margin-inline-end: 0;
list-style-image: url(chrome://browser/skin/tracking-protection-16.svg);
filter: url(chrome://browser/skin/filters.svg#fill);
fill: currentColor;
opacity: .5;
}

Просмотреть файл

@ -8,6 +8,7 @@
<style>
path {
fill-rule: evenodd;
fill: -moz-fieldtext;
}
</style>
</defs>

До

Ширина:  |  Высота:  |  Размер: 1.8 KiB

После

Ширина:  |  Высота:  |  Размер: 1.9 KiB

Просмотреть файл

@ -17,5 +17,5 @@
</mask>
</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>

До

Ширина:  |  Высота:  |  Размер: 1.3 KiB

После

Ширина:  |  Высота:  |  Размер: 1.3 KiB

Просмотреть файл

@ -17,7 +17,7 @@
<form id="options-panel">
<div id="tools-box" class="options-vertical-pane">
<fieldset id="default-tools-box" class="options-groupbox">
<legend>&options.selectDefaultTools.label;</legend>
<legend>&options.selectDefaultTools.label2;</legend>
</fieldset>
<fieldset id="additional-tools-box" class="options-groupbox">
@ -171,7 +171,7 @@
data-pref="devtools.chrome.enabled"/>
<span>&options.enableChrome.label5;</span>
</label>
<label title="&options.enableRemote.tooltip;">
<label title="&options.enableRemote.tooltip2;">
<input type="checkbox"
data-pref="devtools.debugger.remote-enabled"/>
<span>&options.enableRemote.label3;</span>

Просмотреть файл

@ -240,16 +240,17 @@ InspectorPanel.prototype = {
// All the components are initialized. Let's select a node.
this.selection.setNodeFront(defaultSelection, "inspector-open");
this.markup.expandNode(this.selection.nodeFront);
// And setup the toolbar only now because it may depend on the document.
this.setupToolbar();
this.emit("ready");
deferred.resolve(this);
});
this.setupSearchBox();
this.setupSidebar();
this.setupToolbar();
return deferred.promise;
},
@ -509,6 +510,8 @@ InspectorPanel.prototype = {
},
setupToolbar: function () {
this.teardownToolbar();
// Setup the sidebar toggle button.
let SidebarToggle = this.React.createFactory(this.browserRequire(
"devtools/client/shared/components/sidebar-toggle"));
@ -528,21 +531,28 @@ InspectorPanel.prototype = {
this.addNodeButton = this.panelDoc.getElementById("inspector-element-add-button");
this.addNodeButton.addEventListener("click", this.addNode);
// Setup the eye-dropper icon.
this.toolbox.target.actorHasMethod("inspector", "pickColorFromPage").then(value => {
if (!value) {
return;
}
// Setup the eye-dropper icon if we're in an HTML document and we have actor support.
if (this.selection.nodeFront && this.selection.nodeFront.isInHTMLDocument) {
this.toolbox.target.actorHasMethod("inspector", "pickColorFromPage").then(value => {
if (!value) {
return;
}
this.onEyeDropperDone = this.onEyeDropperDone.bind(this);
this.onEyeDropperButtonClicked = this.onEyeDropperButtonClicked.bind(this);
this.eyeDropperButton = this.panelDoc.getElementById("inspector-eyedropper-toggle");
this.eyeDropperButton.style.display = "initial";
this.eyeDropperButton.addEventListener("click", this.onEyeDropperButtonClicked);
}, e => console.error(e));
this.onEyeDropperDone = this.onEyeDropperDone.bind(this);
this.onEyeDropperButtonClicked = this.onEyeDropperButtonClicked.bind(this);
this.eyeDropperButton = this.panelDoc
.getElementById("inspector-eyedropper-toggle");
this.eyeDropperButton.style.display = "initial";
this.eyeDropperButton.addEventListener("click", this.onEyeDropperButtonClicked);
}, e => console.error(e));
} else {
this.panelDoc.getElementById("inspector-eyedropper-toggle").style.display = "none";
}
},
teardownToolbar: function () {
this._sidebarToggle = null;
if (this.addNodeButton) {
this.addNodeButton.removeEventListener("click", this.addNode);
this.addNodeButton = null;
@ -580,6 +590,9 @@ InspectorPanel.prototype = {
this.markup.expandNode(this.selection.nodeFront);
this.emit("new-root");
});
// Setup the toolbar again, since its content may depend on the current document.
this.setupToolbar();
};
this._pendingSelection = onNodeSelected;
this._getDefaultNodeForSelection()
@ -1301,6 +1314,12 @@ InspectorPanel.prototype = {
* @return {Promise} resolves when the eyedropper is visible.
*/
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.eyeDropperButton.setAttribute("checked", "true");
this.startEyeDropperListeners();
@ -1313,6 +1332,12 @@ InspectorPanel.prototype = {
* @return {Promise} resolves when the eyedropper is hidden.
*/
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.stopEyeDropperListeners();
return this.inspector.cancelPickColorFromPage()

Просмотреть файл

@ -75,6 +75,7 @@ subsuite = clipboard
[browser_inspector_highlighter-eyedropper-events.js]
[browser_inspector_highlighter-eyedropper-label.js]
[browser_inspector_highlighter-eyedropper-show-hide.js]
[browser_inspector_highlighter-eyedropper-xul.js]
[browser_inspector_highlighter-geometry_01.js]
[browser_inspector_highlighter-geometry_02.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"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<scale id="scale"/>
<scale id="scale" style="background:red"/>
</window>

Просмотреть файл

@ -93,7 +93,7 @@
- checkbox that toggles remote debugging, i.e. devtools.debugger.remote-enabled
- boolean preference in about:config, in the options panel. -->
<!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
- 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.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
- 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
- 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 => {
let tooltipDoc = this.tooltip.doc;
let eyeButton = tooltipDoc.querySelector("#eyedropper-button");
if (value) {
if (value && this.inspector.selection.nodeFront.isInHTMLDocument) {
eyeButton.addEventListener("click", this._openEyeDropper);
} else {
eyeButton.style.display = "none";

Просмотреть файл

@ -580,6 +580,10 @@ HighlighterEnvironment.prototype = {
return this._win || this._tabActor;
},
get isXUL() {
return isXUL(this.window);
},
get window() {
if (!this.isInitialized) {
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.
*/
show(node, options = {}) {
if (this.highlighterEnv.isXUL) {
return false;
}
this.options = options;
// Get the page's current zoom level.
@ -167,6 +171,10 @@ EyeDropper.prototype = {
* Hide the eye-dropper highlighter.
*/
hide() {
if (this.highlighterEnv.isXUL) {
return;
}
this.pageImage = null;
let {pageListenerTarget} = this.highlighterEnv;

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -12,6 +12,7 @@
#include "mozilla/dom/ShadowRoot.h"
#include "nsIAnonymousContentCreator.h"
#include "nsIFrame.h"
#include "nsCSSAnonBoxes.h"
namespace mozilla {
namespace dom {
@ -375,6 +376,31 @@ AllChildrenIterator::Seek(nsIContent* 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*
AllChildrenIterator::GetNextChild()
{
@ -406,11 +432,7 @@ AllChildrenIterator::GetNextChild()
if (mPhase == eAtAnonKids) {
if (mAnonKids.IsEmpty()) {
MOZ_ASSERT(mAnonKidsIdx == UINT32_MAX);
nsIAnonymousContentCreator* ac =
do_QueryFrame(mOriginalContent->GetPrimaryFrame());
if (ac) {
ac->AppendAnonymousContentTo(mAnonKids, mFlags);
}
AppendNativeAnonymousChildren();
mAnonKidsIdx = 0;
}
else {
@ -462,12 +484,8 @@ AllChildrenIterator::GetPreviousChild()
if (mPhase == eAtAnonKids) {
if (mAnonKids.IsEmpty()) {
nsIAnonymousContentCreator* ac =
do_QueryFrame(mOriginalContent->GetPrimaryFrame());
if (ac) {
ac->AppendAnonymousContentTo(mAnonKids, mFlags);
mAnonKidsIdx = mAnonKids.Length();
}
AppendNativeAnonymousChildren();
mAnonKidsIdx = mAnonKids.Length();
}
// If 0 then it turns into UINT32_MAX, which indicates the iterator is
@ -499,5 +517,100 @@ AllChildrenIterator::GetPreviousChild()
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 mozilla

Просмотреть файл

@ -225,6 +225,10 @@ public:
IteratorPhase Phase() const { return mPhase; }
private:
// Helpers.
void AppendNativeAnonymousChildren();
void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame);
nsIContent* mOriginalContent;
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
@ -245,6 +249,33 @@ private:
#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 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
// postcondition asserts.... But we do want that, since things will
// generally be quite broken when that happens.
@ -1840,11 +1852,15 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
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
// Drop any servo node data, since it will generally need to be recomputed on
// re-insertion anyway.
ServoData().reset();
MOZ_ASSERT(!ServoData());
#endif
}
// Editable descendant count only counts descendants that
// are in the uncomposed document.

Просмотреть файл

@ -2387,3 +2387,51 @@ FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
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),
mUserHasInteracted(false)
{
SetIsDocument();
SetIsInDocument();
PR_INIT_CLIST(&mDOMMediaQueryLists);
}

Просмотреть файл

@ -559,6 +559,18 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
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(aParent == GetParent(), "Bound to wrong parent");
NS_POSTCONDITION(aBindingParent == GetBindingParent(),
@ -590,11 +602,15 @@ nsGenericDOMDataNode::UnbindFromTree(bool aDeep, bool aNullParent)
}
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
// Drop any servo node data, since it will generally need to be recomputed on
// re-insertion anyway.
ServoData().reset();
MOZ_ASSERT(!ServoData());
#endif
}
if (aNullParent || !mParent->IsInShadowTree()) {
UnsetFlags(NODE_IS_IN_SHADOW_TREE);

Просмотреть файл

@ -938,6 +938,14 @@ public:
*/
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
* 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; }
#endif
inline bool IsDirtyForServo() const
bool IsDirtyForServo() const
{
MOZ_ASSERT(IsStyledByServo());
return HasFlag(NODE_IS_DIRTY_FOR_SERVO);
}
inline bool HasDirtyDescendantsForServo() const
bool HasDirtyDescendantsForServo() const
{
MOZ_ASSERT(IsStyledByServo());
return HasFlag(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
}
inline void SetIsDirtyForServo() {
void SetIsDirtyForServo() {
MOZ_ASSERT(IsStyledByServo());
SetFlags(NODE_IS_DIRTY_FOR_SERVO);
}
inline void SetHasDirtyDescendantsForServo() {
void SetHasDirtyDescendantsForServo() {
MOZ_ASSERT(IsStyledByServo());
SetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
}
inline void SetIsDirtyAndHasDirtyDescendantsForServo() {
void SetIsDirtyAndHasDirtyDescendantsForServo() {
MOZ_ASSERT(IsStyledByServo());
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();
/**
@ -1751,17 +1766,7 @@ public:
}
protected:
void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
/**
* 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 SetIsInDocument() { SetBoolFlag(IsInDocument); }
void SetNodeIsContent() { SetBoolFlag(NodeIsContent); }
void ClearInDocument() { ClearBoolFlag(IsInDocument); }
void SetIsElement() { SetBoolFlag(NodeIsElement); }

Просмотреть файл

@ -226,6 +226,8 @@ HTMLMenuElement::TraverseContent(nsIContent* aContent,
aBuilder->AddItemFor(menuitem, CanLoadIcon(child, icon));
aSeparator = ST_FALSE;
} else if (child->IsHTMLElement(nsGkAtoms::hr)) {
aBuilder->AddSeparator();
} else if (child->IsHTMLElement(nsGkAtoms::menu) && !element->IsHidden()) {
if (child->HasAttr(kNameSpaceID_None, nsGkAtoms::label)) {
nsAutoString label;

Просмотреть файл

@ -23,7 +23,12 @@ add_task(function* () {
let pageMenuSep = document.getElementById("page-menu-separator");
ok(pageMenuSep && !pageMenuSep.hidden,
"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");
let promiseCtxMenuClick = ContentTask.spawn(aBrowser, null, function*() {

Просмотреть файл

@ -13,7 +13,8 @@
</head>
<body contextmenu="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>
</body>
</html>

Просмотреть файл

@ -304,10 +304,8 @@ nsPluginHost::nsPluginHost()
Preferences::GetBool("plugin.override_internal_types", false);
mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
mPluginsClickToPlay = Preferences::GetBool("plugins.click_to_play", false);
Preferences::AddStrongObserver(this, "plugin.disable");
Preferences::AddStrongObserver(this, "plugins.click_to_play");
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
@ -3624,7 +3622,6 @@ NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
}
if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
mPluginsClickToPlay = Preferences::GetBool("plugins.click_to_play", false);
// Unload or load plugins as needed
if (mPluginsDisabled) {
UnloadPlugins();

Просмотреть файл

@ -386,8 +386,6 @@ private:
// set by pref plugin.disable
bool mPluginsDisabled;
// set by pref plugins.click_to_play
bool mPluginsClickToPlay;
// 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.

Просмотреть файл

@ -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,
compileFail,
compileSuccess,
compileManySuccess
compileManySuccess,
compileInWorker,
terminateCompileInWorker
];
function runTest() {

Просмотреть файл

@ -269,16 +269,6 @@ SVGUseElement::CreateAnonymousContent()
if (!newcontent)
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)) {
nsIDocument *document = GetComposedDoc();
if (!document)
@ -341,6 +331,16 @@ SVGUseElement::CreateAnonymousContent()
targetContent->AddMutationObserver(this);
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;
}

Просмотреть файл

@ -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>

После

Ширина:  |  Высота:  |  Размер: 393 B

Просмотреть файл

@ -75,6 +75,7 @@ load 898915-1.svg
load 1035248-1.svg
load 1035248-2.svg
load 1244898-1.xhtml
load 1250725.html
load 1267272-1.svg
load 1282985-1.svg
# 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,
ErrorResult& aRv)
{
if (!mLinearAcceleration && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position) {
if (!mLinearAcceleration && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_LinearAcceleration) {
// Lazily create the Float32Array
mLinearAcceleration = dom::Float32Array::Create(aCx, this, 3, mVRState.linearAcceleration);
if (!mLinearAcceleration) {
@ -409,7 +409,7 @@ VRPose::GetAngularAcceleration(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv)
{
if (!mAngularAcceleration && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation) {
if (!mAngularAcceleration && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_AngularAcceleration) {
// Lazily create the Float32Array
mAngularAcceleration = dom::Float32Array::Create(aCx, this, 3, mVRState.angularAcceleration);
if (!mAngularAcceleration) {
@ -441,9 +441,15 @@ VRDisplay::VRDisplay(nsPIDOMWindowInner* aWindow, gfx::VRDisplayClient* aClient)
, mDepthNear(0.01f) // Default value from WebVR Spec
, mDepthFar(10000.0f) // Default value from WebVR Spec
{
mDisplayId = aClient->GetDisplayInfo().GetDisplayID();
mDisplayName = NS_ConvertASCIItoUTF16(aClient->GetDisplayInfo().GetDisplayName());
mCapabilities = new VRDisplayCapabilities(aWindow, aClient->GetDisplayInfo().GetCapabilities());
const gfx::VRDisplayInfo& info = aClient->GetDisplayInfo();
mDisplayId = info.GetDisplayID();
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);
}
@ -482,9 +488,7 @@ VRDisplay::Capabilities()
VRStageParameters*
VRDisplay::GetStageParameters()
{
// XXX When we implement room scale experiences for OpenVR, we should return
// something here.
return nullptr;
return mStageParameters;
}
already_AddRefed<VRPose>
@ -645,7 +649,7 @@ VRDisplay::IsConnected() const
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_RELEASE_INHERITED(VRDisplay, DOMEventTargetHelper)

Просмотреть файл

@ -283,6 +283,7 @@ protected:
nsString mDisplayName;
RefPtr<VRDisplayCapabilities> mCapabilities;
RefPtr<VRStageParameters> mStageParameters;
double mDepthNear;
double mDepthFar;

Просмотреть файл

@ -713,6 +713,185 @@ AsmJSCacheOpenEntryForWrite(JS::Handle<JSObject*> aGlobal,
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 WorkerThreadContextPrivate : private PerThreadAtomCache
@ -808,6 +987,8 @@ InitJSContextForWorker(WorkerPrivate* aWorkerPrivate, JSContext* aWorkerCx)
};
JS::SetAsmJSCacheOps(aWorkerCx, &asmJSCacheOps);
JS::SetAsyncTaskCallbacks(aWorkerCx, StartAsyncTaskCallback, FinishAsyncTaskCallback);
if (!JS::InitSelfHostedCode(aWorkerCx)) {
NS_WARNING("Could not init self-hosted code!");
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
// but should instead point to the enclosing parent element.
nsIDocument* doc = aElement->GetUncomposedDoc();
ServoStyleSet* servoStyleSet = nullptr;
if (nsIPresShell* presShell = aElement->OwnerDoc()->GetShell()) {
servoStyleSet = presShell->StyleSet()->GetAsServo();
}
bool allowScripts = AllowScripts();
nsAutoScriptBlocker scriptBlocker;
@ -240,10 +236,6 @@ nsXBLBinding::InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElem
if (xuldoc)
xuldoc->AddSubtreeToDocument(child);
#endif
if (servoStyleSet) {
servoStyleSet->RestyleSubtree(child);
}
}
}
@ -428,6 +420,15 @@ nsXBLBinding::GenerateAnonymousContent()
if (mContent)
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*

Просмотреть файл

@ -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>
class HeapBase<nsXBLMaybeCompiled<UncompiledT>>
{

Просмотреть файл

@ -311,7 +311,7 @@ DrawTargetSkia::ReleaseBits(uint8_t* aData)
}
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()) {
case PatternType::COLOR: {
@ -333,6 +333,7 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
SkMatrix mat;
GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
mat.postTranslate(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y));
sk_sp<SkShader> shader = SkGradientShader::MakeLinear(points,
&stops->mColors.front(),
&stops->mPositions.front(),
@ -357,6 +358,7 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
SkMatrix mat;
GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
mat.postTranslate(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y));
sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(points[0],
SkFloatToScalar(pat.mRadius1),
points[1],
@ -375,6 +377,7 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
SkMatrix mat;
GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
mat.postTranslate(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y));
if (!pat.mSamplingRect.IsEmpty()) {
SkIRect rect = IntRectToSkIRect(pat.mSamplingRect);
@ -415,17 +418,17 @@ GetClipBounds(SkCanvas *aCanvas)
}
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)
{
Init(aCanvas, aOptions, aMaskBounds);
SetPaintPattern(mPaint, aPattern, mAlpha);
Init(aCanvas, aOptions, aMaskBounds, false);
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)
{
Init(aCanvas, aOptions, aMaskBounds);
Init(aCanvas, aOptions, aMaskBounds, aForceGroup);
}
~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));
mCanvas = aCanvas;
@ -447,8 +450,9 @@ struct AutoPaintSetup {
mPaint.setAntiAlias(false);
}
bool needsGroup = !IsOperatorBoundByMask(aOptions.mCompositionOp) &&
(!aMaskBounds || !aMaskBounds->Contains(GetClipBounds(aCanvas)));
bool needsGroup = aForceGroup ||
(!IsOperatorBoundByMask(aOptions.mCompositionOp) &&
(!aMaskBounds || !aMaskBounds->Contains(GetClipBounds(aCanvas))));
// TODO: We could skip the temporary for operator_source and just
// clear the clip rect. The other operators would be harder
@ -507,10 +511,11 @@ DrawTargetSkia::DrawSurface(SourceSurface *aSurface,
SkRect destRect = RectToSkRect(aDest);
SkRect sourceRect = RectToSkRect(aSource);
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) {
paint.mPaint.setFilterQuality(kNone_SkFilterQuality);
}
@ -1311,7 +1316,7 @@ DrawTargetSkia::MaskSurface(const Pattern &aSource,
const DrawOptions &aOptions)
{
MarkChanged();
AutoPaintSetup paint(mCanvas.get(), aOptions, aSource);
AutoPaintSetup paint(mCanvas.get(), aOptions, aSource, nullptr, -aOffset);
SkBitmap bitmap = GetBitmapForSurface(aMask);
if (bitmap.colorType() != kAlpha_8_SkColorType &&
@ -1320,14 +1325,6 @@ DrawTargetSkia::MaskSurface(const Pattern &aSource,
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);
}

Просмотреть файл

@ -27,6 +27,9 @@ class gfxVarReceiver;
_(ContentBackend, BackendType, BackendType::NONE) \
_(TileSize, IntSize, IntSize(-1, -1)) \
_(UseXRender, bool, false) \
_(OffscreenFormat, gfxImageFormat, mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32) \
_(RequiresAcceleratedGLContextForCompositorOGL, bool, false) \
/* Add new entries above this line. */
// Some graphics settings are computed on the UI process and must be

Просмотреть файл

@ -16,6 +16,7 @@
#include "mozilla/layers/ImageBridgeParent.h"
#include "nsDebugImpl.h"
#include "mozilla/layers/LayerTreeOwnerTracker.h"
#include "ProcessUtils.h"
#include "VRManager.h"
#include "VRManagerParent.h"
#include "VsyncBridgeParent.h"
@ -64,6 +65,7 @@ GPUParent::Init(base::ProcessId aParentPid,
CompositorThreadHolder::Start();
VRManager::ManagerInit();
LayerTreeOwnerTracker::Initialize();
mozilla::ipc::SetThisProcessName("GPU Process");
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::BackendType from "mozilla/gfx/Types.h";
using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
using gfxImageFormat from "mozilla/gfx/Types.h";
namespace mozilla {
namespace gfx {
@ -65,6 +66,7 @@ union GfxVarValue
{
BackendType;
bool;
gfxImageFormat;
IntSize;
};

Просмотреть файл

@ -64,6 +64,8 @@ IPDL_SOURCES = [
'PVsyncBridge.ipdl',
]
LOCAL_INCLUDES += ['/dom/ipc']
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -133,6 +133,11 @@ public:
void SetSupportsComponentAlphaChildren(bool aSupports) { mSupportsComponentAlphaChildren = aSupports; }
virtual void Disconnect() override
{
ClientLayer::Disconnect();
}
protected:
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
ClientLayerManager::AsyncPanZoomEnabled() const
{

Просмотреть файл

@ -155,22 +155,6 @@ public:
// Disable component alpha layers with the software compositor.
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; }
#ifdef DEBUG
bool InDrawing() { return mPhase == PHASE_DRAWING; }

Просмотреть файл

@ -47,7 +47,6 @@
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/PLayerTransactionParent.h"
#include "mozilla/layers/RemoteContentController.h"
#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
#include "mozilla/layout/RenderFrameParent.h"
#include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
#include "mozilla/mozalloc.h" // for operator new, etc
@ -103,6 +102,82 @@ using namespace std;
using base::ProcessId;
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()
: mApzcTreeManagerParent(nullptr)
, mParent(nullptr)
@ -2005,10 +2080,7 @@ CompositorBridgeParent::FinishPendingComposite()
* these updates, it doesn't actually drive compositing itself. For that it
* hands off work to the CompositorBridgeParent it's associated with.
*/
class CrossProcessCompositorBridgeParent final : public PCompositorBridgeParent,
public ShadowLayersManager,
public CompositorBridgeParentIPCAllocator,
public ShmemAllocator
class CrossProcessCompositorBridgeParent final : public CompositorBridgeParentBase
{
friend class CompositorBridgeParent;
@ -2152,28 +2224,6 @@ public:
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 {
// Not allowed.
return nullptr;
@ -2191,8 +2241,6 @@ public:
virtual PAPZParent* AllocPAPZParent(const uint64_t& aLayersId) override;
virtual bool DeallocPAPZParent(PAPZParent* aActor) override;
virtual CompositorBridgeParentIPCAllocator* AsCompositorBridgeParentIPCAllocator() override { return this; }
virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) override {
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
@ -2423,34 +2471,6 @@ CompositorBridgeParent::DeallocPTextureParent(PTextureParent* 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
CompositorBridgeParent::IsSameProcess() const
{
@ -3087,28 +3107,6 @@ CrossProcessCompositorBridgeParent::DeallocPTextureParent(PTextureParent* 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
CrossProcessCompositorBridgeParent::IsSameProcess() const
{

Просмотреть файл

@ -31,7 +31,6 @@
#include "mozilla/layers/ISurfaceAllocator.h" // for ShmemAllocator
#include "mozilla/layers/LayersMessages.h" // for TargetConfig
#include "mozilla/layers/PCompositorBridgeParent.h"
#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
#include "mozilla/layers/APZTestData.h"
#include "mozilla/widget/CompositorWidget.h"
#include "nsISupportsImpl.h"
@ -203,10 +202,57 @@ protected:
virtual ~CompositorUpdateObserver() {}
};
class CompositorBridgeParent final : public PCompositorBridgeParent,
public ShadowLayersManager,
public CompositorBridgeParentIPCAllocator,
public ShmemAllocator
class CompositorBridgeParentBase : public PCompositorBridgeParent,
public HostIPCAllocator,
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 CompositorThreadHolder;
@ -306,30 +352,10 @@ public:
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;
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.
* This must be called on the main thread, and blocks until a task posted

Просмотреть файл

@ -87,48 +87,6 @@ HostIPCAllocator::SendPendingAsyncMessages()
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
// a certain platform and use that.
const uint32_t sShmemPageSize = 4096;

Просмотреть файл

@ -169,14 +169,6 @@ protected:
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.
///
/// 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 "ShadowLayerParent.h" // for ShadowLayerParent
#include "CompositableTransactionParent.h" // for EditReplyVector
#include "CompositorBridgeParent.h"
#include "gfxPrefs.h"
#include "mozilla/gfx/BasePoint3D.h" // for BasePoint3D
#include "mozilla/layers/CanvasLayerComposite.h"
@ -29,7 +30,6 @@
#include "mozilla/layers/PLayerParent.h" // for PLayerParent
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
#include "mozilla/layers/PaintedLayerComposite.h"
#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "mozilla/Unused.h"
#include "nsCoord.h" // for NSAppUnitsToFloatPixels
@ -144,10 +144,10 @@ ShadowChild(const OpRaiseToTopChild& op)
//--------------------------------------------------
// LayerTransactionParent
LayerTransactionParent::LayerTransactionParent(LayerManagerComposite* aManager,
ShadowLayersManager* aLayersManager,
CompositorBridgeParentBase* aBridge,
uint64_t aId)
: mLayerManager(aManager)
, mShadowLayersManager(aLayersManager)
, mCompositorBridge(aBridge)
, mId(aId)
, mPendingTransaction(0)
, mPendingCompositorUpdates(0)
@ -232,7 +232,7 @@ bool
LayerTransactionParent::RecvPaintTime(const uint64_t& aTransactionId,
const TimeDuration& aPaintTime)
{
mShadowLayersManager->UpdatePaintTime(this, aPaintTime);
mCompositorBridge->UpdatePaintTime(this, aPaintTime);
return true;
}
@ -274,7 +274,7 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
EditReplyVector replyv;
{
AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this));
AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this));
layer_manager()->BeginTransaction();
}
@ -657,13 +657,13 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
}
}
mShadowLayersManager->ShadowLayersUpdated(this, aTransactionId, targetConfig,
aPlugins, isFirstPaint, scheduleComposite,
paintSequenceNumber, isRepeatTransaction,
aPaintSyncId, updateHitTestingTree);
mCompositorBridge->ShadowLayersUpdated(this, aTransactionId, targetConfig,
aPlugins, isFirstPaint, scheduleComposite,
paintSequenceNumber, isRepeatTransaction,
aPaintSyncId, updateHitTestingTree);
{
AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this));
AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this));
layer_manager()->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW);
}
@ -714,13 +714,13 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
bool
LayerTransactionParent::RecvSetTestSampleTime(const TimeStamp& aTime)
{
return mShadowLayersManager->SetTestSampleTime(this, aTime);
return mCompositorBridge->SetTestSampleTime(this, aTime);
}
bool
LayerTransactionParent::RecvLeaveTestMode()
{
mShadowLayersManager->LeaveTestMode(this);
mCompositorBridge->LeaveTestMode(this);
return true;
}
@ -739,7 +739,7 @@ LayerTransactionParent::RecvGetAnimationOpacity(PLayerParent* aParent,
return false;
}
mShadowLayersManager->ApplyAsyncProperties(this);
mCompositorBridge->ApplyAsyncProperties(this);
if (!layer->AsLayerComposite()->GetShadowOpacitySetByAnimation()) {
return true;
@ -767,7 +767,7 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent,
// a race between when we temporarily clear the animation transform (in
// CompositorBridgeParent::SetShadowProperties) and when animation recalculates
// the value.
mShadowLayersManager->ApplyAsyncProperties(this);
mCompositorBridge->ApplyAsyncProperties(this);
// This method is specific to transforms applied by animation.
// This is because this method uses the information stored with an animation
@ -885,14 +885,14 @@ LayerTransactionParent::RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollID,
bool
LayerTransactionParent::RecvFlushApzRepaints()
{
mShadowLayersManager->FlushApzRepaints(this);
mCompositorBridge->FlushApzRepaints(this);
return true;
}
bool
LayerTransactionParent::RecvGetAPZTestData(APZTestData* aOutData)
{
mShadowLayersManager->GetAPZTestData(this, aOutData);
mCompositorBridge->GetAPZTestData(this, aOutData);
return true;
}
@ -913,7 +913,7 @@ bool
LayerTransactionParent::RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
nsTArray<ScrollableLayerGuid>&& aTargets)
{
mShadowLayersManager->SetConfirmedTargetAPZC(this, aBlockId, aTargets);
mCompositorBridge->SetConfirmedTargetAPZC(this, aBlockId, aTargets);
return true;
}
@ -960,14 +960,14 @@ LayerTransactionParent::RecvClearCachedResources()
// of resources to exactly that subtree, so we specify it here.
mLayerManager->ClearCachedResources(mRoot);
}
mShadowLayersManager->NotifyClearCachedResources(this);
mCompositorBridge->NotifyClearCachedResources(this);
return true;
}
bool
LayerTransactionParent::RecvForceComposite()
{
mShadowLayersManager->ForceComposite(this);
mCompositorBridge->ForceComposite(this);
return true;
}
@ -1047,13 +1047,13 @@ LayerTransactionParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessa
void
LayerTransactionParent::SendPendingAsyncMessages()
{
mShadowLayersManager->AsCompositorBridgeParentIPCAllocator()->SendPendingAsyncMessages();
mCompositorBridge->SendPendingAsyncMessages();
}
void
LayerTransactionParent::SetAboutToSendAsyncMessages()
{
mShadowLayersManager->AsCompositorBridgeParentIPCAllocator()->SetAboutToSendAsyncMessages();
mCompositorBridge->SetAboutToSendAsyncMessages();
}
void

Просмотреть файл

@ -32,7 +32,7 @@ class Layer;
class LayerManagerComposite;
class ShadowLayerParent;
class CompositableParent;
class ShadowLayersManager;
class CompositorBridgeParentBase;
class LayerTransactionParent final : public PLayerTransactionParent,
public CompositableParentManager,
@ -46,7 +46,7 @@ class LayerTransactionParent final : public PLayerTransactionParent,
public:
LayerTransactionParent(LayerManagerComposite* aManager,
ShadowLayersManager* aLayersManager,
CompositorBridgeParentBase* aBridge,
uint64_t aId);
protected:
@ -187,7 +187,7 @@ protected:
private:
RefPtr<LayerManagerComposite> mLayerManager;
ShadowLayersManager* mShadowLayersManager;
CompositorBridgeParentBase* mCompositorBridge;
// Hold the root because it might be grafted under various
// containers in the "real" layer tree
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/ShadowLayerChild.h',
'ipc/ShadowLayers.h',
'ipc/ShadowLayersManager.h',
'ipc/SharedBufferManagerChild.h',
'ipc/SharedBufferManagerParent.h',
'ipc/SharedPlanarYCbCrImage.h',

Просмотреть файл

@ -22,6 +22,7 @@
#include "mozilla/Preferences.h" // for Preferences
#include "mozilla/gfx/BasePoint.h" // for BasePoint
#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/CompositingRenderTargetOGL.h"
#include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc
@ -108,7 +109,8 @@ CompositorOGL::CreateContext()
RefPtr<GLContext> 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) {
GLContext* alreadyRefed = reinterpret_cast<GLContext*>(widgetOpenGLContext);
return already_AddRefed<GLContext>(alreadyRefed);
@ -125,7 +127,7 @@ CompositorOGL::CreateContext()
if (!context && gfxEnv::LayersPreferOffscreen()) {
SurfaceCaps caps = SurfaceCaps::ForRGB();
caps.preserve = false;
caps.bpp16 = gfxPlatform::GetPlatform()->GetOffscreenFormat() == SurfaceFormat::R5G6B5_UINT16;
caps.bpp16 = gfxVars::OffscreenFormat() == SurfaceFormat::R5G6B5_UINT16;
nsCString discardFailureId;
context = GLContextProvider::CreateOffscreen(mSurfaceSize,
@ -135,7 +137,7 @@ CompositorOGL::CreateContext()
if (!context) {
context = gl::GLContextProvider::CreateForCompositorWidget(mWidget,
gfxPlatform::GetPlatform()->RequiresAcceleratedGLContextForCompositorOGL());
gfxVars::RequiresAcceleratedGLContextForCompositorOGL());
}
if (!context) {
@ -143,7 +145,8 @@ CompositorOGL::CreateContext()
}
#ifdef MOZ_WIDGET_GONK
mWidget->RealWidget()->SetNativeData(
MOZ_ASSERT(widget);
widget->SetNativeData(
NS_NATIVE_OPENGL_CONTEXT, reinterpret_cast<uintptr_t>(context.get()));
#endif

Просмотреть файл

@ -2110,6 +2110,9 @@ gfxPlatform::InitAcceleration()
if (XRE_IsParentProcess()) {
gfxVars::SetBrowserTabsRemoteAutostart(BrowserTabsRemoteAutostart());
gfxVars::SetOffscreenFormat(GetOffscreenFormat());
gfxVars::SetRequiresAcceleratedGLContextForCompositorOGL(
RequiresAcceleratedGLContextForCompositorOGL());
}
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();

Просмотреть файл

@ -309,6 +309,7 @@ private:
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.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(Live, "dom.vr.poseprediction.enabled", VRPosePredictionEnabled, 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();
if (vsync >= now) {
vsync = vsync - mVsyncRate;
return vsync <= now ? vsync : now;
}
}
// On Windows 7 and 8, DwmFlush wakes up AFTER qpcVBlankTime
// 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) {
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;
}
@ -1891,6 +1897,12 @@ public:
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;
}
} // end for

Просмотреть файл

@ -12,9 +12,7 @@
namespace mozilla {
namespace gfx {
class VRDisplayClient;
namespace vr {
class VRLayerChild;
} // namepsace vr
class VRDisplayPresentation final
{

Просмотреть файл

@ -7,6 +7,7 @@
#include "VRManager.h"
#include "VRManagerParent.h"
#include "gfxVR.h"
#include "gfxVROpenVR.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/VRDisplay.h"
#include "mozilla/layers/TextureHost.h"
@ -51,6 +52,20 @@ VRManager::VRManager()
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)
// The Oculus runtime is supported only on Windows
mgr = VRDisplayManagerOculus::Create();
@ -60,9 +75,15 @@ VRManager::VRManager()
#endif
#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
mgr = VRDisplayManagerOSVR::Create();
if (mgr){
if (mgr) {
mManagers.AppendElement(mgr);
}
#endif
@ -172,7 +193,15 @@ VRManager::RefreshVRDisplays(bool aMustDispatch)
{
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);
}

Просмотреть файл

@ -26,6 +26,7 @@ class VRDisplayHost;
enum class VRDisplayType : uint16_t {
Oculus,
OpenVR,
OSVR,
NumVRDisplayTypes
};
@ -56,10 +57,25 @@ enum class VRDisplayCapabilityFlags : uint16_t {
* or update non-VR UI because that content will not be visible.
*/
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 = (1 << 5) - 1
Cap_All = (1 << 8) - 1
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(VRDisplayCapabilityFlags)
@ -70,6 +86,14 @@ struct VRFieldOfView {
: 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 {
return other.upDegrees == upDegrees &&
other.downDegrees == downDegrees &&
@ -108,6 +132,8 @@ struct VRDisplayInfo
const VRFieldOfView& GetEyeFOV(uint32_t whichEye) const { return mEyeFOV[whichEye]; }
bool GetIsConnected() const { return mIsConnected; }
bool GetIsPresenting() const { return mIsPresenting; }
const Size& GetStageSize() const { return mStageSize; }
const Matrix4x4& GetSittingToStandingTransform() const { return mSittingToStandingTransform; }
enum Eye {
Eye_Left,
@ -124,6 +150,8 @@ struct VRDisplayInfo
IntSize mEyeResolution;
bool mIsConnected;
bool mIsPresenting;
Size mStageSize;
Matrix4x4 mSittingToStandingTransform;
bool operator==(const VRDisplayInfo& other) const {
return mType == other.mType &&
@ -136,7 +164,9 @@ struct VRDisplayInfo
mEyeFOV[0] == other.mEyeFOV[0] &&
mEyeFOV[1] == other.mEyeFOV[1] &&
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 {

Просмотреть файл

@ -24,8 +24,8 @@
#include "mozilla/gfx/Quaternion.h"
#include <d3d11.h>
#include "../layers/d3d11/CompositorD3D11.h"
#include "mozilla/layers/TextureD3D11.h"
#include "CompositorD3D11.h"
#include "TextureD3D11.h"
#include "gfxVROculus.h"
@ -337,9 +337,11 @@ VRDisplayOculus::VRDisplayOculus(ovrSession aSession)
mDisplayInfo.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None;
if (mDesc.AvailableTrackingCaps & ovrTrackingCap_Orientation) {
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Orientation;
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration;
}
if (mDesc.AvailableTrackingCaps & ovrTrackingCap_Position) {
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Position;
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
}
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_External;
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Present;
@ -441,6 +443,8 @@ VRDisplayOculus::GetSensorState(double timeOffset)
result.angularVelocity[1] = pose.AngularVelocity.y;
result.angularVelocity[2] = pose.AngularVelocity.z;
result.flags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration;
result.angularAcceleration[0] = pose.AngularAcceleration.x;
result.angularAcceleration[1] = pose.AngularAcceleration.y;
result.angularAcceleration[2] = pose.AngularAcceleration.z;
@ -457,6 +461,8 @@ VRDisplayOculus::GetSensorState(double timeOffset)
result.linearVelocity[1] = pose.LinearVelocity.y;
result.linearVelocity[2] = pose.LinearVelocity.z;
result.flags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
result.linearAcceleration[0] = pose.LinearAcceleration.x;
result.linearAcceleration[1] = pose.LinearAcceleration.y;
result.linearAcceleration[2] = pose.LinearAcceleration.z;

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
Просмотреть файл

@ -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.mIsConnected);
WriteParam(aMsg, aParam.mIsPresenting);
WriteParam(aMsg, aParam.mStageSize);
WriteParam(aMsg, aParam.mSittingToStandingTransform);
for (int i = 0; i < mozilla::gfx::VRDisplayInfo::NumEyes; i++) {
WriteParam(aMsg, aParam.mEyeFOV[i]);
WriteParam(aMsg, aParam.mEyeTranslation[i]);
@ -54,7 +56,9 @@ struct ParamTraits<mozilla::gfx::VRDisplayInfo>
!ReadParam(aMsg, aIter, &(aResult->mCapabilityFlags)) ||
!ReadParam(aMsg, aIter, &(aResult->mEyeResolution)) ||
!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;
}
for (int i = 0; i < mozilla::gfx::VRDisplayInfo::NumEyes; i++) {

Просмотреть файл

@ -16,11 +16,13 @@ EXPORTS += [
]
LOCAL_INCLUDES += [
'/gfx/layers/d3d11',
'/gfx/thebes',
]
UNIFIED_SOURCES += [
'gfxVR.cpp',
'gfxVROpenVR.cpp',
'gfxVROSVR.cpp',
'ipc/VRLayerChild.cpp',
'ipc/VRLayerParent.cpp',

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
Просмотреть файл

@ -0,0 +1,2 @@
See https://github.com/ValveSoftware/openvr/

3352
gfx/vr/openvr/openvr.h Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -67,12 +67,6 @@ static StaticRefPtr<SurfaceCacheImpl> sInstance;
*/
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
ComputeCost(const IntSize& aSize, uint32_t aBytesPerPixel)
{
@ -94,14 +88,12 @@ ComputeCost(const IntSize& aSize, uint32_t aBytesPerPixel)
class CostEntry
{
public:
CostEntry(CachedSurface* aSurface, Cost aCost)
CostEntry(NotNull<CachedSurface*> aSurface, Cost aCost)
: mSurface(aSurface)
, 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; }
bool operator==(const CostEntry& aOther) const
@ -117,8 +109,8 @@ public:
}
private:
CachedSurface* mSurface;
Cost mCost;
NotNull<CachedSurface*> mSurface;
Cost mCost;
};
/**
@ -132,17 +124,15 @@ public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(CachedSurface)
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CachedSurface)
CachedSurface(ISurfaceProvider* aProvider,
const Cost aCost,
const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey)
CachedSurface(NotNull<ISurfaceProvider*> aProvider,
const Cost aCost,
const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey)
: mProvider(aProvider)
, mCost(aCost)
, mImageKey(aImageKey)
, mSurfaceKey(aSurfaceKey)
{
MOZ_ASSERT(aProvider || mCost == sPlaceholderCost,
"Old-style placeholders should have trivial cost");
MOZ_ASSERT(mImageKey, "Must have a valid image key");
}
@ -165,23 +155,15 @@ public:
mProvider->SetLocked(aLocked);
}
bool IsPlaceholder() const
{
return !mProvider || mProvider->Availability().IsPlaceholder();
}
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; }
SurfaceKey GetSurfaceKey() const { return mSurfaceKey; }
CostEntry GetCostEntry() { return image::CostEntry(this, mCost); }
CostEntry GetCostEntry() { return image::CostEntry(WrapNotNull(this), mCost); }
nsExpirationState* GetExpirationState() { return &mExpirationState; }
bool IsDecoded() const
{
return !IsPlaceholder() && mProvider->IsFinished();
}
// A helper type used by SurfaceCacheImpl::CollectSizeOfSurfaces.
struct MOZ_STACK_CLASS SurfaceMemoryReport
{
@ -191,10 +173,8 @@ public:
, mMallocSizeOf(aMallocSizeOf)
{ }
void Add(CachedSurface* aCachedSurface)
void Add(NotNull<CachedSurface*> aCachedSurface)
{
MOZ_ASSERT(aCachedSurface, "Should have a CachedSurface");
SurfaceMemoryCounter counter(aCachedSurface->GetSurfaceKey(),
aCachedSurface->IsLocked());
@ -222,11 +202,11 @@ public:
};
private:
nsExpirationState mExpirationState;
RefPtr<ISurfaceProvider> mProvider;
const Cost mCost;
const ImageKey mImageKey;
const SurfaceKey mSurfaceKey;
nsExpirationState mExpirationState;
NotNull<RefPtr<ISurfaceProvider>> mProvider;
const Cost mCost;
const ImageKey mImageKey;
const SurfaceKey mSurfaceKey;
};
static int64_t
@ -257,17 +237,15 @@ public:
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(),
"Inserting an unlocked surface for a locked image");
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()),
"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.
RefPtr<CachedSurface> bestMatch;
for (auto iter = ConstIter(); !iter.Done(); iter.Next()) {
CachedSurface* current = iter.UserData();
NotNull<CachedSurface*> current = WrapNotNull(iter.UserData());
const SurfaceKey& currentKey = current->GetSurfaceKey();
// We never match a placeholder.
@ -367,7 +345,7 @@ public:
}
} else {
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());
matchType = MatchType::PENDING;
} else {
@ -438,11 +416,11 @@ public:
Mutex& GetMutex() { return mMutex; }
InsertOutcome Insert(ISurfaceProvider* aProvider,
const Cost aCost,
const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
bool aSetAvailable)
InsertOutcome Insert(NotNull<ISurfaceProvider*> aProvider,
const Cost aCost,
const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
bool aSetAvailable)
{
// If this is a duplicate surface, refuse to replace the original.
// XXX(seth): Calling Lookup() and then RemoveEntry() does the lookup
@ -472,7 +450,7 @@ public:
while (aCost > mAvailableCost) {
MOZ_ASSERT(!mCosts.IsEmpty(),
"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
@ -488,8 +466,8 @@ public:
aProvider->Availability().SetAvailable();
}
RefPtr<CachedSurface> surface =
new CachedSurface(aProvider, aCost, aImageKey, aSurfaceKey);
NotNull<RefPtr<CachedSurface>> surface =
WrapNotNull(new CachedSurface(aProvider, aCost, aImageKey, aSurfaceKey));
// 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
@ -509,9 +487,8 @@ public:
return InsertOutcome::SUCCESS;
}
void Remove(CachedSurface* aSurface)
void Remove(NotNull<CachedSurface*> aSurface)
{
MOZ_ASSERT(aSurface, "Should have a surface");
ImageKey imageKey = aSurface->GetImageKey();
RefPtr<ImageSurfaceCache> cache = GetImageCache(imageKey);
@ -532,7 +509,7 @@ public:
}
}
void StartTracking(CachedSurface* aSurface)
void StartTracking(NotNull<CachedSurface*> aSurface)
{
CostEntry costEntry = aSurface->GetCostEntry();
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();
if (aSurface->IsLocked()) {
@ -605,12 +581,12 @@ public:
if (!drawableSurface) {
// The surface was released by the operating system. Remove the cache
// entry as well.
Remove(surface);
Remove(WrapNotNull(surface));
return LookupResult(MatchType::NOT_FOUND);
}
if (aMarkUsed) {
MarkUsed(surface, cache);
MarkUsed(WrapNotNull(surface), WrapNotNull(cache));
}
MOZ_ASSERT(surface->GetSurfaceKey() == aSurfaceKey,
@ -650,7 +626,7 @@ public:
// The surface was released by the operating system. Remove the cache
// entry as well.
Remove(surface);
Remove(WrapNotNull(surface));
}
MOZ_ASSERT_IF(matchType == MatchType::EXACT,
@ -662,7 +638,7 @@ public:
surface->GetSurfaceKey().Flags() == aSurfaceKey.Flags());
if (matchType == MatchType::EXACT) {
MarkUsed(surface, cache);
MarkUsed(WrapNotNull(surface), WrapNotNull(cache));
}
return LookupResult(Move(drawableSurface), matchType);
@ -719,7 +695,7 @@ public:
}
cache->SetLocked(false);
DoUnlockSurfaces(cache);
DoUnlockSurfaces(WrapNotNull(cache));
}
void UnlockEntries(const ImageKey aImageKey)
@ -731,7 +707,7 @@ public:
// (Note that we *don't* unlock the per-image cache here; that's the
// difference between this and UnlockImage.)
DoUnlockSurfaces(cache);
DoUnlockSurfaces(WrapNotNull(cache));
}
void RemoveImage(const ImageKey aImageKey)
@ -747,7 +723,7 @@ public:
// small, performance should be good, but if usage patterns change we should
// change the data structure used for mCosts.
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.
@ -761,7 +737,7 @@ public:
// structures are all hash tables. Note that locked surfaces are not
// removed, since they aren't present in mCosts.
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.
while (mAvailableCost < targetCost) {
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()) {
return;
@ -845,7 +821,7 @@ public:
// Report all surfaces in the per-image cache.
CachedSurface::SurfaceMemoryReport report(aCounters, aMallocSizeOf);
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;
}
void MarkUsed(CachedSurface* aSurface, ImageSurfaceCache* aCache)
void MarkUsed(NotNull<CachedSurface*> aSurface,
NotNull<ImageSurfaceCache*> aCache)
{
if (aCache->IsLocked()) {
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.
for (auto iter = aCache->ConstIter(); !iter.Done(); iter.Next()) {
CachedSurface* surface = iter.UserData();
NotNull<CachedSurface*> surface = WrapNotNull(iter.UserData());
if (surface->IsPlaceholder() || !surface->IsLocked()) {
continue;
}
@ -903,7 +880,7 @@ private:
return; // Lookup in the per-image cache missed.
}
Remove(surface);
Remove(WrapNotNull(surface));
}
struct SurfaceTracker : public nsExpirationTracker<CachedSurface, 2>
@ -918,7 +895,7 @@ private:
{
if (sInstance) {
MutexAutoLock lock(sInstance->GetMutex());
sInstance->Remove(aSurface);
sInstance->Remove(WrapNotNull(aSurface));
}
}
};
@ -1061,20 +1038,7 @@ SurfaceCache::Insert(NotNull<ISurfaceProvider*> aProvider,
MutexAutoLock lock(sInstance->GetMutex());
Cost cost = aProvider->LogicalSizeInBytes();
return sInstance->Insert(aProvider.get(), 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,
return sInstance->Insert(aProvider, cost, aImageKey, aSurfaceKey,
/* aSetAvailable = */ false);
}

Просмотреть файл

@ -240,8 +240,8 @@ struct SurfaceCache
/**
* Insert an ISurfaceProvider into the cache. If an entry with the same
* ImageKey and SurfaceKey is already in the cache, Insert returns
* FAILURE_ALREADY_PRESENT. If a matching placeholder is already present, the
* placeholder is removed.
* FAILURE_ALREADY_PRESENT. If a matching placeholder is already present, it
* is replaced.
*
* 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
@ -285,33 +285,6 @@ struct SurfaceCache
const ImageKey aImageKey,
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
* 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
* 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 aImageKey Key data identifying which image the cache entry
* belongs to.
@ -423,7 +388,7 @@ struct SurfaceCache
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
* 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) 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?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-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?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()); }
};
/*
* 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
* 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
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
* 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
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.
* Does not include the null-terminator.

Просмотреть файл

@ -45,6 +45,23 @@
#include "js/TraceKind.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 JSFunction;
class JSObject;

Просмотреть файл

@ -14,6 +14,8 @@
#include "mozilla/Move.h"
#include "mozilla/TypeTraits.h"
#include <type_traits>
#include "jspubtd.h"
#include "js/GCAnnotations.h"
@ -123,6 +125,14 @@ class MutableHandleBase {};
template <typename T>
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>
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
* 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>
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:
Heap() {
static_assert(sizeof(T) == sizeof(Heap<T>),

Просмотреть файл

@ -2791,9 +2791,12 @@ EdgeNeedsSweep(JS::Heap<T>* thingp)
template bool IsMarked<type>(WriteBarrieredBase<type>*); \
template bool IsAboutToBeFinalizedUnbarriered<type>(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>*);
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
} /* namespace gc */

Просмотреть файл

@ -58,23 +58,6 @@ class JitCode;
} // namespace jit
} // 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.
#define FOR_EACH_INTERNAL_GC_POINTER_TYPE(D) \
D(JSFlatString*) \

Просмотреть файл

@ -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");
evalInFrame(1, "a = 43");
let a = 42;

Просмотреть файл

@ -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.
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.
Register holderReg = scratchReg;

Просмотреть файл

@ -4518,7 +4518,8 @@ struct JS_PUBLIC_API(AsyncTask)
*
* If this function succeeds, SpiderMonkey will call the FinishAsyncTaskCallback
* 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
(*StartAsyncTaskCallback)(JSContext* cx, AsyncTask* task);

Просмотреть файл

@ -2230,7 +2230,22 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e
// See note above RuntimeLexicalErrorObject.
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);
if (!env)
return false;

Просмотреть файл

@ -1218,7 +1218,7 @@ dnl Checks for library functions.
dnl ========================================================
AC_PROG_GCC_TRADITIONAL
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
AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC),

Просмотреть файл

@ -264,6 +264,7 @@ struct ShellContext
JS::PersistentRootedValue promiseRejectionTrackerCallback;
JS::PersistentRooted<JobQueue> jobQueue;
ExclusiveData<ShellAsyncTasks> asyncTasks;
bool drainingJobQueue;
#endif // SPIDERMONKEY_PROMISE
/*
@ -428,6 +429,7 @@ ShellContext::ShellContext(JSContext* cx)
#ifdef SPIDERMONKEY_PROMISE
promiseRejectionTrackerCallback(cx, NullValue()),
asyncTasks(cx),
drainingJobQueue(false),
#endif // SPIDERMONKEY_PROMISE
exitCode(0),
quitting(false),
@ -771,7 +773,7 @@ DrainJobQueue(JSContext* cx)
{
#ifdef SPIDERMONKEY_PROMISE
ShellContext* sc = GetShellContext(cx);
if (sc->quitting)
if (sc->quitting || sc->drainingJobQueue)
return true;
// Wait for any outstanding async tasks to finish so that the
@ -792,6 +794,12 @@ DrainJobQueue(JSContext* cx)
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);
JS::HandleValueArray args(JS::HandleValueArray::empty());
RootedValue rval(cx);
@ -808,6 +816,7 @@ DrainJobQueue(JSContext* cx)
sc->jobQueue[i].set(nullptr);
}
sc->jobQueue.clear();
sc->drainingJobQueue = false;
#endif // SPIDERMONKEY_PROMISE
return true;
}

Просмотреть файл

@ -185,6 +185,12 @@ Thread::Id GetId();
// nothing.
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 detail {

Просмотреть файл

@ -164,3 +164,24 @@ js::ThisThread::SetName(const char* name)
#endif
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
}
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 {
CountAndReportInvalids,
CountAndIgnoreInvalids,
AssertNoInvalids,
Copy
};
@ -256,12 +257,13 @@ static const uint32_t REPLACE_UTF8 = 0xFFFD;
// If making changes to this algorithm, make sure to also update
// LossyConvertUTF8toUTF16() in dom/wifi/WifiUtils.cpp
template <InflateUTF8Action action>
template <InflateUTF8Action Action>
static bool
InflateUTF8StringToBuffer(JSContext* cx, const UTF8Chars src, char16_t* dst, size_t* dstlenp,
bool* isAsciip)
{
*isAsciip = true;
if (Action != AssertNoInvalids)
*isAsciip = true;
// 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|.
@ -271,26 +273,29 @@ InflateUTF8StringToBuffer(JSContext* cx, const UTF8Chars src, char16_t* dst, siz
uint32_t v = uint32_t(src[i]);
if (!(v & 0x80)) {
// ASCII code unit. Simple copy.
if (action == Copy)
if (Action == Copy)
dst[j] = char16_t(v);
} else {
// Non-ASCII code unit. Determine its length in bytes (n).
*isAsciip = false;
if (Action != AssertNoInvalids)
*isAsciip = false;
uint32_t n = 1;
while (v & (0x80 >> n))
n++;
#define INVALID(report, arg, n2) \
do { \
if (action == CountAndReportInvalids) { \
if (Action == CountAndReportInvalids) { \
report(cx, arg); \
return false; \
} else if (Action == AssertNoInvalids) { \
MOZ_CRASH("invalid UTF-8 string: " # report); \
} else { \
if (action == Copy) \
if (Action == Copy) \
dst[j] = char16_t(REPLACE_UTF8); \
else \
MOZ_ASSERT(action == CountAndIgnoreInvalids); \
MOZ_ASSERT(Action == CountAndIgnoreInvalids); \
n = n2; \
goto invalidMultiByteCodeUnit; \
} \
@ -323,17 +328,17 @@ InflateUTF8StringToBuffer(JSContext* cx, const UTF8Chars src, char16_t* dst, siz
v = JS::Utf8ToOneUcs4Char((uint8_t*)&src[i], n);
if (v < 0x10000) {
// The n-byte UTF8 code unit will fit in a single char16_t.
if (action == Copy)
if (Action == Copy)
dst[j] = char16_t(v);
} else {
v -= 0x10000;
if (v <= 0xFFFFF) {
// 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);
j++;
if (action == Copy)
if (Action == Copy)
dst[j] = char16_t((v & 0x3FF) + 0xDC00);
} else {
@ -350,20 +355,20 @@ InflateUTF8StringToBuffer(JSContext* cx, const UTF8Chars src, char16_t* dst, siz
}
}
*dstlenp = j;
if (Action != AssertNoInvalids)
*dstlenp = j;
return true;
}
typedef bool (*CountAction)(JSContext*, const UTF8Chars, char16_t*, size_t*, bool* isAsciip);
template <InflateUTF8Action Action>
static TwoByteCharsZ
InflateUTF8StringHelper(JSContext* cx, const UTF8Chars src, CountAction countAction, size_t* outlen)
InflateUTF8StringHelper(JSContext* cx, const UTF8Chars src, size_t* outlen)
{
*outlen = 0;
bool isAscii;
if (!countAction(cx, src, /* dst = */ nullptr, outlen, &isAscii))
if (!InflateUTF8StringToBuffer<Action>(cx, src, /* dst = */ nullptr, outlen, &isAscii))
return TwoByteCharsZ();
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
JS::UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen)
{
return InflateUTF8StringHelper(cx, utf8, InflateUTF8StringToBuffer<CountAndReportInvalids>,
outlen);
return InflateUTF8StringHelper<CountAndReportInvalids>(cx, utf8, 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
JS::LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen)
{
return InflateUTF8StringHelper(cx, utf8, InflateUTF8StringToBuffer<CountAndIgnoreInvalids>,
outlen);
return InflateUTF8StringHelper<CountAndIgnoreInvalids>(cx, utf8, 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);
if (!TLTextIdIsToggable(textId)) {
if (!TLTextIdIsTogglable(textId)) {
args.rval().setBoolean(false);
return true;
}

Просмотреть файл

@ -1587,14 +1587,20 @@ js::StartOffThreadCompression(ExclusiveContext* cx, SourceCompressionTask* task)
bool
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,
// finishAsyncTaskCallback *must* be called on all paths.
if (!cx->startAsyncTaskCallback(cx, task.get())) {
ReportOutOfMemory(cx);
return false;
}
AutoLockHelperThreadState lock;
if (!HelperThreadState().promiseTasks(lock).append(task.get())) {

Просмотреть файл

@ -81,14 +81,14 @@ IsUninitializedLexical(const Value& val)
static inline bool
IsUninitializedLexicalSlot(HandleObject obj, HandleShape shape)
{
MOZ_ASSERT(shape);
if (obj->is<WithEnvironmentObject>())
return false;
// We check for IsImplicitDenseOrTypedArrayElement even though the shape
// is always a non-indexed property because proxy hooks may return a
// "non-native property found" shape, which happens to be encoded in the
// same way as the "dense element" shape. See MarkNonNativePropertyFound.
if (!shape ||
IsImplicitDenseOrTypedArrayElement(shape) ||
if (IsImplicitDenseOrTypedArrayElement(shape) ||
!shape->hasSlot() ||
!shape->hasDefaultGetter() ||
!shape->hasDefaultSetter())

Просмотреть файл

@ -4428,10 +4428,9 @@ js::ThrowMsgOperation(JSContext* cx, const unsigned errorNum)
bool
js::GetAndClearException(JSContext* cx, MutableHandleValue res)
{
bool status = cx->getPendingException(res);
cx->clearPendingException();
if (!status)
if (!cx->getPendingException(res))
return false;
cx->clearPendingException();
// Allow interrupting deeply nested exception handling.
return CheckForInterrupt(cx);

Просмотреть файл

@ -26,6 +26,7 @@
# include "asmjs/WasmSignalHandlers.h"
#endif
#include "builtin/AtomicsObject.h"
#include "builtin/Promise.h"
#include "ds/FixedSizeHash.h"
#include "frontend/NameCollections.h"
#include "gc/GCRuntime.h"
@ -66,8 +67,7 @@ class EnterDebuggeeNoExecute;
class TraceLoggerThread;
#endif
class PromiseTask;
typedef Vector<PromiseTask*, 0, SystemAllocPolicy> PromiseTaskPtrVector;
typedef Vector<UniquePtr<PromiseTask>, 0, SystemAllocPolicy> PromiseTaskPtrVector;
/* Thread Local Storage slot for storing the runtime for a thread. */
extern MOZ_THREAD_LOCAL(PerThreadData*) TlsPerThreadData;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше