mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-15 14:25:52 +00:00
Merge mozilla-central to b2g-inbound
This commit is contained in:
commit
31876c7e82
@ -858,7 +858,7 @@ public:
|
||||
bool IsDefunct() const { return mStateFlags & eIsDefunct; }
|
||||
|
||||
/**
|
||||
* Return true if the accessible is no longer in the document.
|
||||
* Return false if the accessible is no longer in the document.
|
||||
*/
|
||||
bool IsInDocument() const { return !(mStateFlags & eIsNotInDocument); }
|
||||
|
||||
|
@ -1983,7 +1983,8 @@ DocAccessible::ValidateARIAOwned()
|
||||
nsTArray<RefPtr<Accessible> >* children = it.UserData();
|
||||
|
||||
// Owner is about to die, put children back if applicable.
|
||||
if (!owner->IsInDocument()) {
|
||||
if (!mAccessibleCache.GetWeak(reinterpret_cast<void*>(owner)) ||
|
||||
!owner->IsInDocument()) {
|
||||
PutChildrenBack(children, 0);
|
||||
it.Remove();
|
||||
continue;
|
||||
|
@ -1336,7 +1336,7 @@ BrowserGlue.prototype = {
|
||||
if (AppConstants.E10S_TESTING_ONLY) {
|
||||
E10SUINotification.checkStatus();
|
||||
}
|
||||
if (AppConstants.XP_WIN) {
|
||||
if (AppConstants.platform == "win") {
|
||||
// Handles prompting to inform about incompatibilites when accessibility
|
||||
// and e10s are active together.
|
||||
E10SAccessibilityCheck.init();
|
||||
@ -3087,6 +3087,26 @@ var E10SUINotification = {
|
||||
CURRENT_PROMPT_PREF: "browser.displayedE10SPrompt.1",
|
||||
PREVIOUS_PROMPT_PREF: "browser.displayedE10SPrompt",
|
||||
|
||||
get forcedOn() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref("browser.tabs.remote.force-enable");
|
||||
} catch (e) {}
|
||||
return false;
|
||||
},
|
||||
|
||||
get a11yRecentlyRan() {
|
||||
try {
|
||||
if (Services.prefs.getBoolPref("accessibility.loadedInLastSession")) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {}
|
||||
try {
|
||||
Services.prefs.getBoolPref("accessibility.lastLoadDate");
|
||||
return true;
|
||||
} catch (e) {}
|
||||
return false;
|
||||
},
|
||||
|
||||
checkStatus: function() {
|
||||
let updateChannel = UpdateUtils.UpdateChannel;
|
||||
let channelAuthorized = updateChannel == "nightly" || updateChannel == "aurora";
|
||||
@ -3095,6 +3115,9 @@ var E10SUINotification = {
|
||||
}
|
||||
|
||||
if (Services.appinfo.browserTabsRemoteAutostart) {
|
||||
if (this.forcedOn) {
|
||||
return;
|
||||
}
|
||||
let notice = 0;
|
||||
try {
|
||||
notice = Services.prefs.getIntPref("browser.displayedE10SNotice");
|
||||
@ -3129,6 +3152,11 @@ var E10SUINotification = {
|
||||
return;
|
||||
}
|
||||
|
||||
// If accessibility recently ran, don't prompt about trying out e10s
|
||||
if (this.a11yRecentlyRan) {
|
||||
return;
|
||||
}
|
||||
|
||||
let e10sPromptShownCount = 0;
|
||||
try {
|
||||
e10sPromptShownCount = Services.prefs.getIntPref(this.CURRENT_PROMPT_PREF);
|
||||
|
@ -767,7 +767,7 @@ e10s.postActivationInfobar.message = You're now helping to test multi-process in
|
||||
e10s.postActivationInfobar.learnMore.label = Learn More
|
||||
e10s.postActivationInfobar.learnMore.accesskey = L
|
||||
e10s.accessibilityNotice.mainMessage2 = Accessibility support is partially disabled due to compatibility issues with new %S features.
|
||||
e10s.accessibilityNotice.acceptButton.label = Ok
|
||||
e10s.accessibilityNotice.acceptButton.label = OK
|
||||
e10s.accessibilityNotice.acceptButton.accesskey = O
|
||||
e10s.accessibilityNotice.enableAndRestart.label = Enable (Requires Restart)
|
||||
e10s.accessibilityNotice.enableAndRestart.accesskey = E
|
||||
|
@ -5,7 +5,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE = 1048576; // 1 MB in bytes
|
||||
const SOURCE_URL_DEFAULT_MAX_LENGTH = 64; // chars
|
||||
const STACK_FRAMES_SOURCE_URL_MAX_LENGTH = 15; // chars
|
||||
const STACK_FRAMES_SOURCE_URL_TRIM_SECTION = "center";
|
||||
@ -47,6 +46,13 @@ var constants = require('./content/constants');
|
||||
* Object defining the debugger view components.
|
||||
*/
|
||||
var DebuggerView = {
|
||||
|
||||
/**
|
||||
* This is attached so tests can change it without needing to load an
|
||||
* actual large file in automation
|
||||
*/
|
||||
LARGE_FILE_SIZE: 1048576, // 1 MB in bytes
|
||||
|
||||
/**
|
||||
* Initializes the debugger view.
|
||||
*
|
||||
@ -408,12 +414,6 @@ var DebuggerView = {
|
||||
* The source text content.
|
||||
*/
|
||||
_setEditorMode: function(aUrl, aContentType = "", aTextContent = "") {
|
||||
// Avoid setting the editor mode for very large files.
|
||||
// Is this still necessary? See bug 929225.
|
||||
if (aTextContent.length >= SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE) {
|
||||
return void this.editor.setMode(Editor.modes.text);
|
||||
}
|
||||
|
||||
// Use JS mode for files with .js and .jsm extensions.
|
||||
if (SourceUtils.isJavaScript(aUrl, aContentType)) {
|
||||
return void this.editor.setMode(Editor.modes.js);
|
||||
|
@ -446,6 +446,7 @@ skip-if = true # non-named eval sources turned off for now, bug 1124106
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_sources-labels.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_sources-large.js]
|
||||
[browser_dbg_sources-sorting.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_sources-bookmarklet.js]
|
||||
|
@ -0,0 +1,75 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that large files are treated differently in the debugger:
|
||||
* 1) No parsing to determine current symbol is attempted when
|
||||
* starting a search
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
const gTab = aTab;
|
||||
const gDebuggee = aDebuggee;
|
||||
const gPanel = aPanel;
|
||||
const gDebugger = gPanel.panelWin;
|
||||
|
||||
const gEditor = gDebugger.DebuggerView.editor;
|
||||
const gSources = gDebugger.DebuggerView.Sources;
|
||||
const Filtering = gDebugger.DebuggerView.Filtering;
|
||||
|
||||
// Setting max size so that code_function-search-01.js will be
|
||||
// considered a large file on first load
|
||||
gDebugger.DebuggerView.LARGE_FILE_SIZE = 1;
|
||||
|
||||
function testLargeFile() {
|
||||
ok(gEditor.getText().length > gDebugger.DebuggerView.LARGE_FILE_SIZE,
|
||||
"First source is considered a large file.");
|
||||
is(gEditor.getMode().name, "javascript",
|
||||
"Editor is syntax highlighting.");
|
||||
ok(gEditor.getText().includes("First source!"),
|
||||
"Editor text contents appears to be correct.");
|
||||
|
||||
// Press ctrl+f with the cursor in a token
|
||||
gEditor.focus();
|
||||
gEditor.setCursor({ line: 3, ch: 10});
|
||||
synthesizeKeyFromKeyTag(gDebugger.document.getElementById("tokenSearchKey"));
|
||||
is(Filtering._searchbox.value, "#",
|
||||
"Search box is NOT prefilled with current token");
|
||||
}
|
||||
|
||||
function testSmallFile() {
|
||||
ok(gEditor.getText().length < gDebugger.DebuggerView.LARGE_FILE_SIZE,
|
||||
"Second source is considered a small file.");
|
||||
is(gEditor.getMode().name, "javascript",
|
||||
"Editor is syntax highlighting.");
|
||||
ok(gEditor.getText().includes("First source!"),
|
||||
"Editor text contents appears to be correct.");
|
||||
|
||||
// Press ctrl+f with the cursor in a token
|
||||
gEditor.focus();
|
||||
gEditor.setCursor({ line: 3, ch: 10});
|
||||
synthesizeKeyFromKeyTag(gDebugger.document.getElementById("tokenSearchKey"));
|
||||
is(Filtering._searchbox.value, "#test",
|
||||
"Search box is prefilled with current token");
|
||||
}
|
||||
|
||||
Task.spawn(function*() {
|
||||
yield waitForSourceShown(gPanel, "-01.js");
|
||||
yield testLargeFile();
|
||||
|
||||
info("Making it appear as a small file and then reselecting 01.js");
|
||||
gDebugger.DebuggerView.LARGE_FILE_SIZE = 1000;
|
||||
gSources.selectedIndex = 1;
|
||||
yield waitForSourceShown(gPanel, "-02.js");
|
||||
gSources.selectedIndex = 0;
|
||||
yield waitForSourceShown(gPanel, "-01.js");
|
||||
|
||||
yield testSmallFile();
|
||||
|
||||
closeDebuggerAndFinish(gPanel);
|
||||
});
|
||||
});
|
||||
}
|
@ -443,9 +443,11 @@ FilterView.prototype = {
|
||||
this._searchbox.value = aOperator + this.DebuggerView.editor.getSelection();
|
||||
return;
|
||||
}
|
||||
if (SEARCH_AUTOFILL.indexOf(aOperator) != -1) {
|
||||
|
||||
let content = this.DebuggerView.editor.getText();
|
||||
if (content.length < this.DebuggerView.LARGE_FILE_SIZE &&
|
||||
SEARCH_AUTOFILL.indexOf(aOperator) != -1) {
|
||||
let cursor = this.DebuggerView.editor.getCursor();
|
||||
let content = this.DebuggerView.editor.getText();
|
||||
let location = this.DebuggerView.Sources.selectedItem.attachment.source.url;
|
||||
let source = this.Parser.get(content, location);
|
||||
let identifier = source.getIdentifierAt({ line: cursor.line+1, column: cursor.ch });
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.status2): This is the label displayed
|
||||
- in the network table toolbar, above the "status" column. -->
|
||||
<!ENTITY netmonitorUI.toolbar.status2 "✓">
|
||||
<!ENTITY netmonitorUI.toolbar.status3 "Status">
|
||||
|
||||
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.method): This is the label displayed
|
||||
- in the network table toolbar, above the "method" column. -->
|
||||
|
@ -39,8 +39,7 @@
|
||||
#details-pane-toggle,
|
||||
#details-pane[pane-collapsed],
|
||||
.requests-menu-waterfall,
|
||||
.requests-menu-footer-label,
|
||||
.requests-menu-status-code {
|
||||
.requests-menu-footer-label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@
|
||||
<button id="requests-menu-status-button"
|
||||
class="requests-menu-header-button requests-menu-status"
|
||||
data-key="status"
|
||||
label="&netmonitorUI.toolbar.status2;"
|
||||
label="&netmonitorUI.toolbar.status3;"
|
||||
flex="1">
|
||||
</button>
|
||||
</hbox>
|
||||
|
@ -9,7 +9,7 @@ function test() {
|
||||
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, L10N, NetMonitorView } = aMonitor.panelWin;
|
||||
let { document, L10N, NetMonitorView, NetMonitorController } = aMonitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
// Disable transferred size column support for this test.
|
||||
@ -31,6 +31,11 @@ function test() {
|
||||
"No 2d context should be created when the frontend is opened.");
|
||||
|
||||
waitForNetworkEvents(aMonitor, 1).then(() => {
|
||||
// Make sure the DOMContentLoaded and load markers don't interfere with
|
||||
// this test by removing them and redrawing the waterfall (bug 1224088).
|
||||
NetMonitorController.NetworkEventsHandler.clearMarkers();
|
||||
RequestsMenu._flushWaterfallViews(true);
|
||||
|
||||
ok(!document.querySelector("#requests-menu-waterfall-label"),
|
||||
"The timeline label should be hidden after the first request.");
|
||||
ok(document.querySelectorAll(".requests-menu-timings-division").length >= 3,
|
||||
|
@ -235,7 +235,8 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
cell.className = "plain call-tree-cell";
|
||||
cell.setAttribute("type", type);
|
||||
cell.setAttribute("crop", "end");
|
||||
cell.setAttribute("value", value);
|
||||
// Add a tabulation to the cell text in case it's is selected and copied.
|
||||
cell.textContent = value + "\t";
|
||||
return cell;
|
||||
},
|
||||
|
||||
@ -261,7 +262,7 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
nameNode.className = "plain call-tree-name";
|
||||
nameNode.setAttribute("flex", "1");
|
||||
nameNode.setAttribute("crop", "end");
|
||||
nameNode.setAttribute("value", frameName);
|
||||
nameNode.textContent = frameName;
|
||||
cell.appendChild(nameNode);
|
||||
}
|
||||
|
||||
@ -276,6 +277,17 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
arrowNode.setAttribute("invisible", "");
|
||||
}
|
||||
|
||||
// Add a line break to the last description of the row in case it's selected
|
||||
// and copied.
|
||||
let lastDescription = cell.querySelector('description:last-of-type');
|
||||
lastDescription.textContent = lastDescription.textContent + "\n";
|
||||
|
||||
// Add spaces as frameLevel indicators in case the row is selected and
|
||||
// copied. These spaces won't be displayed in the cell content.
|
||||
let firstDescription = cell.querySelector('description:first-of-type');
|
||||
let levelIndicator = frameLevel > 0 ? " ".repeat(frameLevel) : "";
|
||||
firstDescription.textContent = levelIndicator + firstDescription.textContent;
|
||||
|
||||
return cell;
|
||||
},
|
||||
|
||||
@ -285,7 +297,7 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
urlNode.className = "plain call-tree-url";
|
||||
urlNode.setAttribute("flex", "1");
|
||||
urlNode.setAttribute("crop", "end");
|
||||
urlNode.setAttribute("value", frameInfo.fileName);
|
||||
urlNode.textContent = frameInfo.fileName;
|
||||
urlNode.setAttribute("tooltiptext", URL_LABEL_TOOLTIP + " → " + frameInfo.url);
|
||||
urlNode.addEventListener("mousedown", this._onUrlClick);
|
||||
cell.appendChild(urlNode);
|
||||
@ -294,21 +306,21 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
if (frameInfo.line) {
|
||||
let lineNode = doc.createElement("description");
|
||||
lineNode.className = "plain call-tree-line";
|
||||
lineNode.setAttribute("value", ":" + frameInfo.line);
|
||||
lineNode.textContent = ":" + frameInfo.line;
|
||||
cell.appendChild(lineNode);
|
||||
}
|
||||
|
||||
if (frameInfo.column) {
|
||||
let columnNode = doc.createElement("description");
|
||||
columnNode.className = "plain call-tree-column";
|
||||
columnNode.setAttribute("value", ":" + frameInfo.column);
|
||||
columnNode.textContent = ":" + frameInfo.column;
|
||||
cell.appendChild(columnNode);
|
||||
}
|
||||
|
||||
if (frameInfo.host) {
|
||||
let hostNode = doc.createElement("description");
|
||||
hostNode.className = "plain call-tree-host";
|
||||
hostNode.setAttribute("value", frameInfo.host);
|
||||
hostNode.textContent = frameInfo.host;
|
||||
cell.appendChild(hostNode);
|
||||
}
|
||||
|
||||
@ -320,7 +332,7 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
let categoryNode = doc.createElement("description");
|
||||
categoryNode.className = "plain call-tree-category";
|
||||
categoryNode.style.color = frameInfo.categoryData.color;
|
||||
categoryNode.setAttribute("value", frameInfo.categoryData.label);
|
||||
categoryNode.textContent = frameInfo.categoryData.label;
|
||||
cell.appendChild(categoryNode);
|
||||
}
|
||||
},
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
function* spawnTest() {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, $, DetailsView, JsCallTreeView } = panel.panelWin;
|
||||
let { EVENTS, $, $$, DetailsView, JsCallTreeView } = panel.panelWin;
|
||||
|
||||
// Enable platform data to show the categories.
|
||||
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
|
||||
@ -22,17 +22,26 @@ function* spawnTest() {
|
||||
|
||||
is($(".call-tree-cells-container").hasAttribute("categories-hidden"), false,
|
||||
"The call tree cells container should show the categories now.");
|
||||
ok($(".call-tree-category[value=Gecko]"),
|
||||
"A category node with the label `Gecko` is displayed in the tree.");
|
||||
ok(geckoCategoryPresent($$),
|
||||
"A category node with the text `Gecko` is displayed in the tree.");
|
||||
|
||||
// Disable platform data to show the categories.
|
||||
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
|
||||
|
||||
is($(".call-tree-cells-container").getAttribute("categories-hidden"), "",
|
||||
"The call tree cells container should hide the categories now.");
|
||||
ok(!$(".call-tree-category[value=Gecko]"),
|
||||
"A category node with the label `Gecko` doesn't exist in the tree anymore.");
|
||||
ok(!geckoCategoryPresent($$),
|
||||
"A category node with the text `Gecko` doesn't exist in the tree anymore.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
||||
function geckoCategoryPresent($$) {
|
||||
for (let elem of $$('.call-tree-category')) {
|
||||
if (elem.textContent.trim() == 'Gecko') {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -31,27 +31,27 @@ function test() {
|
||||
|
||||
is(container.childNodes[0].childNodes[0].getAttribute("type"), "duration",
|
||||
"The root node in the tree has a duration cell.");
|
||||
is(container.childNodes[0].childNodes[0].getAttribute("value"), "20 ms",
|
||||
is(container.childNodes[0].childNodes[0].textContent.trim(), "20 ms",
|
||||
"The root node in the tree has the correct duration cell value.");
|
||||
|
||||
is(container.childNodes[0].childNodes[1].getAttribute("type"), "percentage",
|
||||
"The root node in the tree has a percentage cell.");
|
||||
is(container.childNodes[0].childNodes[1].getAttribute("value"), "100%",
|
||||
is(container.childNodes[0].childNodes[1].textContent.trim(), "100%",
|
||||
"The root node in the tree has the correct percentage cell value.");
|
||||
|
||||
is(container.childNodes[0].childNodes[2].getAttribute("type"), "self-duration",
|
||||
"The root node in the tree has a self-duration cell.");
|
||||
is(container.childNodes[0].childNodes[2].getAttribute("value"), "0 ms",
|
||||
is(container.childNodes[0].childNodes[2].textContent.trim(), "0 ms",
|
||||
"The root node in the tree has the correct self-duration cell value.");
|
||||
|
||||
is(container.childNodes[0].childNodes[3].getAttribute("type"), "self-percentage",
|
||||
"The root node in the tree has a self-percentage cell.");
|
||||
is(container.childNodes[0].childNodes[3].getAttribute("value"), "0%",
|
||||
is(container.childNodes[0].childNodes[3].textContent.trim(), "0%",
|
||||
"The root node in the tree has the correct self-percentage cell value.");
|
||||
|
||||
is(container.childNodes[0].childNodes[4].getAttribute("type"), "samples",
|
||||
"The root node in the tree has an samples cell.");
|
||||
is(container.childNodes[0].childNodes[4].getAttribute("value"), "0",
|
||||
is(container.childNodes[0].childNodes[4].textContent.trim(), "0",
|
||||
"The root node in the tree has the correct samples cell value.");
|
||||
|
||||
is(container.childNodes[0].childNodes[5].getAttribute("type"), "function",
|
||||
|
@ -33,13 +33,13 @@ function test() {
|
||||
is(container.childNodes[0].className, "call-tree-item",
|
||||
"The root node in the tree has the correct class name.");
|
||||
|
||||
is($$dur(0).getAttribute("value"), "20 ms",
|
||||
is($$dur(0).textContent.trim(), "20 ms",
|
||||
"The root's duration cell displays the correct value.");
|
||||
is($$perc(0).getAttribute("value"), "100%",
|
||||
is($$perc(0).textContent.trim(), "100%",
|
||||
"The root's percentage cell displays the correct value.");
|
||||
is($$sampl(0).getAttribute("value"), "0",
|
||||
is($$sampl(0).textContent.trim(), "0",
|
||||
"The root's samples cell displays the correct value.");
|
||||
is($$fun(".call-tree-name")[0].getAttribute("value"), "(root)",
|
||||
is($$fun(".call-tree-name")[0].textContent.trim(), "(root)",
|
||||
"The root's function cell displays the correct name.");
|
||||
is($$fun(".call-tree-url")[0], null,
|
||||
"The root's function cell displays no url.");
|
||||
@ -59,23 +59,23 @@ function test() {
|
||||
is(container.childNodes[1].className, "call-tree-item",
|
||||
"The .A node in the tree has the correct class name.");
|
||||
|
||||
is($$dur(1).getAttribute("value"), "20 ms",
|
||||
is($$dur(1).textContent.trim(), "20 ms",
|
||||
"The .A node's duration cell displays the correct value.");
|
||||
is($$perc(1).getAttribute("value"), "100%",
|
||||
is($$perc(1).textContent.trim(), "100%",
|
||||
"The .A node's percentage cell displays the correct value.");
|
||||
is($$sampl(1).getAttribute("value"), "0",
|
||||
is($$sampl(1).textContent.trim(), "0",
|
||||
"The .A node's samples cell displays the correct value.");
|
||||
is($fun(".call-tree-name", $$(".call-tree-item")[1]).getAttribute("value"), "A",
|
||||
is($fun(".call-tree-name", $$(".call-tree-item")[1]).textContent.trim(), "A",
|
||||
"The .A node's function cell displays the correct name.");
|
||||
is($fun(".call-tree-url", $$(".call-tree-item")[1]).getAttribute("value"), "baz",
|
||||
is($fun(".call-tree-url", $$(".call-tree-item")[1]).textContent.trim(), "baz",
|
||||
"The .A node's function cell displays the correct url.");
|
||||
ok($fun(".call-tree-url", $$(".call-tree-item")[1]).getAttribute("tooltiptext").includes("http://foo/bar/baz"),
|
||||
"The .A node's function cell displays the correct url tooltiptext.");
|
||||
is($fun(".call-tree-line", $$(".call-tree-item")[1]).getAttribute("value"), ":12",
|
||||
is($fun(".call-tree-line", $$(".call-tree-item")[1]).textContent.trim(), ":12",
|
||||
"The .A node's function cell displays the correct line.");
|
||||
is($fun(".call-tree-host", $$(".call-tree-item")[1]).getAttribute("value"), "foo",
|
||||
is($fun(".call-tree-host", $$(".call-tree-item")[1]).textContent.trim(), "foo",
|
||||
"The .A node's function cell displays the correct host.");
|
||||
is($fun(".call-tree-category", $$(".call-tree-item")[1]).getAttribute("value"), "Gecko",
|
||||
is($fun(".call-tree-category", $$(".call-tree-item")[1]).textContent.trim(), "Gecko",
|
||||
"The .A node's function cell displays the correct category.");
|
||||
|
||||
let A = treeRoot.getChild();
|
||||
@ -88,42 +88,42 @@ function test() {
|
||||
is(container.childNodes[3].className, "call-tree-item",
|
||||
"The .E node in the tree has the correct class name.");
|
||||
|
||||
is($$dur(2).getAttribute("value"), "15 ms",
|
||||
is($$dur(2).textContent.trim(), "15 ms",
|
||||
"The .A.B node's duration cell displays the correct value.");
|
||||
is($$perc(2).getAttribute("value"), "75%",
|
||||
is($$perc(2).textContent.trim(), "75%",
|
||||
"The .A.B node's percentage cell displays the correct value.");
|
||||
is($$sampl(2).getAttribute("value"), "0",
|
||||
is($$sampl(2).textContent.trim(), "0",
|
||||
"The .A.B node's samples cell displays the correct value.");
|
||||
is($fun(".call-tree-name", $$(".call-tree-item")[2]).getAttribute("value"), "B",
|
||||
is($fun(".call-tree-name", $$(".call-tree-item")[2]).textContent.trim(), "B",
|
||||
"The .A.B node's function cell displays the correct name.");
|
||||
is($fun(".call-tree-url", $$(".call-tree-item")[2]).getAttribute("value"), "baz",
|
||||
is($fun(".call-tree-url", $$(".call-tree-item")[2]).textContent.trim(), "baz",
|
||||
"The .A.B node's function cell displays the correct url.");
|
||||
ok($fun(".call-tree-url", $$(".call-tree-item")[2]).getAttribute("tooltiptext").includes("http://foo/bar/baz"),
|
||||
"The .A.B node's function cell displays the correct url tooltiptext.");
|
||||
is($fun(".call-tree-line", $$(".call-tree-item")[2]).getAttribute("value"), ":34",
|
||||
is($fun(".call-tree-line", $$(".call-tree-item")[2]).textContent.trim(), ":34",
|
||||
"The .A.B node's function cell displays the correct line.");
|
||||
is($fun(".call-tree-host", $$(".call-tree-item")[2]).getAttribute("value"), "foo",
|
||||
is($fun(".call-tree-host", $$(".call-tree-item")[2]).textContent.trim(), "foo",
|
||||
"The .A.B node's function cell displays the correct host.");
|
||||
is($fun(".call-tree-category", $$(".call-tree-item")[2]).getAttribute("value"), "Styles",
|
||||
is($fun(".call-tree-category", $$(".call-tree-item")[2]).textContent.trim(), "Styles",
|
||||
"The .A.B node's function cell displays the correct category.");
|
||||
|
||||
is($$dur(3).getAttribute("value"), "5 ms",
|
||||
is($$dur(3).textContent.trim(), "5 ms",
|
||||
"The .A.E node's duration cell displays the correct value.");
|
||||
is($$perc(3).getAttribute("value"), "25%",
|
||||
is($$perc(3).textContent.trim(), "25%",
|
||||
"The .A.E node's percentage cell displays the correct value.");
|
||||
is($$sampl(3).getAttribute("value"), "0",
|
||||
is($$sampl(3).textContent.trim(), "0",
|
||||
"The .A.E node's samples cell displays the correct value.");
|
||||
is($fun(".call-tree-name", $$(".call-tree-item")[3]).getAttribute("value"), "E",
|
||||
is($fun(".call-tree-name", $$(".call-tree-item")[3]).textContent.trim(), "E",
|
||||
"The .A.E node's function cell displays the correct name.");
|
||||
is($fun(".call-tree-url", $$(".call-tree-item")[3]).getAttribute("value"), "baz",
|
||||
is($fun(".call-tree-url", $$(".call-tree-item")[3]).textContent.trim(), "baz",
|
||||
"The .A.E node's function cell displays the correct url.");
|
||||
ok($fun(".call-tree-url", $$(".call-tree-item")[3]).getAttribute("tooltiptext").includes("http://foo/bar/baz"),
|
||||
"The .A.E node's function cell displays the correct url tooltiptext.");
|
||||
is($fun(".call-tree-line", $$(".call-tree-item")[3]).getAttribute("value"), ":90",
|
||||
is($fun(".call-tree-line", $$(".call-tree-item")[3]).textContent.trim(), ":90",
|
||||
"The .A.E node's function cell displays the correct line.");
|
||||
is($fun(".call-tree-host", $$(".call-tree-item")[3]).getAttribute("value"), "foo",
|
||||
is($fun(".call-tree-host", $$(".call-tree-item")[3]).textContent.trim(), "foo",
|
||||
"The .A.E node's function cell displays the correct host.");
|
||||
is($fun(".call-tree-category", $$(".call-tree-item")[3]).getAttribute("value"), "GC",
|
||||
is($fun(".call-tree-category", $$(".call-tree-item")[3]).textContent.trim(), "GC",
|
||||
"The .A.E node's function cell displays the correct category.");
|
||||
|
||||
finish();
|
||||
|
@ -42,34 +42,34 @@ function test() {
|
||||
is($$fun(6).style.MozMarginStart, "48px",
|
||||
"The .A.E.F node's function cell has the correct indentation.");
|
||||
|
||||
is($$name(0).getAttribute("value"), "(root)",
|
||||
is($$name(0).textContent.trim(), "(root)",
|
||||
"The root node's function cell displays the correct name.");
|
||||
is($$name(1).getAttribute("value"), "A",
|
||||
is($$name(1).textContent.trim(), "A",
|
||||
"The .A node's function cell displays the correct name.");
|
||||
is($$name(2).getAttribute("value"), "B",
|
||||
is($$name(2).textContent.trim(), "B",
|
||||
"The .A.B node's function cell displays the correct name.");
|
||||
is($$name(3).getAttribute("value"), "D",
|
||||
is($$name(3).textContent.trim(), "D",
|
||||
"The .A.B.D node's function cell displays the correct name.");
|
||||
is($$name(4).getAttribute("value"), "C",
|
||||
is($$name(4).textContent.trim(), "C",
|
||||
"The .A.B.C node's function cell displays the correct name.");
|
||||
is($$name(5).getAttribute("value"), "E",
|
||||
is($$name(5).textContent.trim(), "E",
|
||||
"The .A.E node's function cell displays the correct name.");
|
||||
is($$name(6).getAttribute("value"), "F",
|
||||
is($$name(6).textContent.trim(), "F",
|
||||
"The .A.E.F node's function cell displays the correct name.");
|
||||
|
||||
is($$duration(0).getAttribute("value"), "20 ms",
|
||||
is($$duration(0).textContent.trim(), "20 ms",
|
||||
"The root node's function cell displays the correct duration.");
|
||||
is($$duration(1).getAttribute("value"), "20 ms",
|
||||
is($$duration(1).textContent.trim(), "20 ms",
|
||||
"The .A node's function cell displays the correct duration.");
|
||||
is($$duration(2).getAttribute("value"), "15 ms",
|
||||
is($$duration(2).textContent.trim(), "15 ms",
|
||||
"The .A.B node's function cell displays the correct duration.");
|
||||
is($$duration(3).getAttribute("value"), "10 ms",
|
||||
is($$duration(3).textContent.trim(), "10 ms",
|
||||
"The .A.B.D node's function cell displays the correct duration.");
|
||||
is($$duration(4).getAttribute("value"), "5 ms",
|
||||
is($$duration(4).textContent.trim(), "5 ms",
|
||||
"The .A.B.C node's function cell displays the correct duration.");
|
||||
is($$duration(5).getAttribute("value"), "5 ms",
|
||||
is($$duration(5).textContent.trim(), "5 ms",
|
||||
"The .A.E node's function cell displays the correct duration.");
|
||||
is($$duration(6).getAttribute("value"), "5 ms",
|
||||
is($$duration(6).textContent.trim(), "5 ms",
|
||||
"The .A.E.F node's function cell displays the correct duration.");
|
||||
|
||||
finish();
|
||||
@ -108,4 +108,3 @@ var gThread = synthesizeProfileForTest([{
|
||||
{ category: 256, location: "F (http://foo/bar/baz:99)" }
|
||||
]
|
||||
}]);
|
||||
|
||||
|
@ -43,21 +43,21 @@ function test() {
|
||||
"Generalized JS node has correct category");
|
||||
is(JS.target.getAttribute("tooltiptext"), "JIT",
|
||||
"Generalized JS node has correct category");
|
||||
is(JS.target.querySelector(".call-tree-name").getAttribute("value"), "JIT",
|
||||
is(JS.target.querySelector(".call-tree-name").textContent.trim(), "JIT",
|
||||
"Generalized JS node has correct display value as just the category name.");
|
||||
|
||||
is(JS2.target.getAttribute("category"), "js",
|
||||
"Generalized second JS node has correct category");
|
||||
is(JS2.target.getAttribute("tooltiptext"), "JIT",
|
||||
"Generalized second JS node has correct category");
|
||||
is(JS2.target.querySelector(".call-tree-name").getAttribute("value"), "JIT",
|
||||
is(JS2.target.querySelector(".call-tree-name").textContent.trim(), "JIT",
|
||||
"Generalized second JS node has correct display value as just the category name.");
|
||||
|
||||
is(GC.target.getAttribute("category"), "gc",
|
||||
"Generalized GC node has correct category");
|
||||
is(GC.target.getAttribute("tooltiptext"), "GC",
|
||||
"Generalized GC node has correct category");
|
||||
is(GC.target.querySelector(".call-tree-name").getAttribute("value"), "GC",
|
||||
is(GC.target.querySelector(".call-tree-name").textContent.trim(), "GC",
|
||||
"Generalized GC node has correct display value as just the category name.");
|
||||
|
||||
finish();
|
||||
|
@ -63,9 +63,9 @@ function test() {
|
||||
let [total, self, name] = def;
|
||||
name = name.trim();
|
||||
|
||||
is($$name(i).getAttribute("value"), name, `${name} has correct name.`);
|
||||
is($$percentage(i).getAttribute("value"), `${total}%`, `${name} has correct total percent.`);
|
||||
is($$selfpercentage(i).getAttribute("value"), `${self}%`, `${name} has correct self percent.`);
|
||||
is($$name(i).textContent.trim(), name, `${name} has correct name.`);
|
||||
is($$percentage(i).textContent.trim(), `${total}%`, `${name} has correct total percent.`);
|
||||
is($$selfpercentage(i).textContent.trim(), `${self}%`, `${name} has correct self percent.`);
|
||||
});
|
||||
|
||||
finish();
|
||||
|
@ -31,7 +31,7 @@ function* spawnTest() {
|
||||
let rows = $$("#js-calltree-view .call-tree-item");
|
||||
is(rows.length, 4, "4 call tree rows exist");
|
||||
for (let row of rows) {
|
||||
let name = $(".call-tree-name", row).value;
|
||||
let name = $(".call-tree-name", row).textContent.trim();
|
||||
switch (name) {
|
||||
case "A":
|
||||
ok($(".opt-icon", row), "found an opt icon on a leaf node with opt data");
|
||||
|
@ -29,6 +29,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
var { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
|
||||
var { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
var { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
|
||||
var { LoadContextInfo } = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {});
|
||||
var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
var promise = require("promise");
|
||||
@ -186,20 +187,17 @@ AppCacheUtils.prototype = {
|
||||
.createInstance(Ci.nsIScriptableInputStream);
|
||||
let deferred = promise.defer();
|
||||
let buffer = "";
|
||||
let channel = Services.io.newChannel2(uri,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
var channel = NetUtil.newChannel({
|
||||
uri: uri,
|
||||
loadUsingSystemPrincipal: true,
|
||||
securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL
|
||||
});
|
||||
|
||||
// Avoid the cache:
|
||||
channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
|
||||
channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
|
||||
|
||||
channel.asyncOpen({
|
||||
channel.asyncOpen2({
|
||||
onStartRequest: function (request, context) {
|
||||
// This empty method is needed in order for onDataAvailable to be
|
||||
// called.
|
||||
@ -245,7 +243,7 @@ AppCacheUtils.prototype = {
|
||||
});
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
});
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
|
@ -522,7 +522,6 @@ AbstractTreeItem.prototype = {
|
||||
* Handler for the "click" event on the element displaying this tree item.
|
||||
*/
|
||||
_onClick: function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.focus();
|
||||
},
|
||||
|
@ -116,11 +116,7 @@
|
||||
|
||||
/* Network requests table: specific column dimensions */
|
||||
|
||||
.requests-menu-status {
|
||||
max-width: 4em;
|
||||
width: 4vw;
|
||||
}
|
||||
|
||||
.requests-menu-status,
|
||||
.requests-menu-method-box,
|
||||
.requests-menu-method {
|
||||
max-width: 6em;
|
||||
@ -183,10 +179,6 @@
|
||||
width: 8vw;
|
||||
}
|
||||
|
||||
.requests-menu-transferred {
|
||||
width: 8vw;
|
||||
}
|
||||
|
||||
/* Network requests table: status codes */
|
||||
|
||||
.requests-menu-status-code {
|
||||
@ -795,11 +787,12 @@
|
||||
}
|
||||
|
||||
.requests-menu-status {
|
||||
width: 4vw;
|
||||
max-width: none;
|
||||
width: 12vw;
|
||||
}
|
||||
|
||||
#requests-menu-status-button {
|
||||
min-width: 26px;
|
||||
.requests-menu-status-code {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.requests-menu-method,
|
||||
@ -809,20 +802,20 @@
|
||||
}
|
||||
|
||||
.requests-menu-icon-and-file {
|
||||
width: 30vw;
|
||||
width: 22vw;
|
||||
}
|
||||
|
||||
.requests-menu-security-and-domain {
|
||||
width: 28vw;
|
||||
width: 18vw;
|
||||
}
|
||||
|
||||
.requests-menu-type,
|
||||
.requests-menu-transferred {
|
||||
width: 12vw;
|
||||
.requests-menu-type {
|
||||
width: 10vw;
|
||||
}
|
||||
|
||||
.requests-menu-transferred,
|
||||
.requests-menu-size {
|
||||
width: 16vw;
|
||||
width: 12vw;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,6 +269,16 @@
|
||||
background-color: var(--theme-tab-toolbar-background);
|
||||
}
|
||||
|
||||
.call-tree-item .call-tree-cell,
|
||||
.call-tree-item .call-tree-cell[type=function] description {
|
||||
-moz-user-select: text;
|
||||
}
|
||||
|
||||
.call-tree-item .call-tree-cell::-moz-selection,
|
||||
.call-tree-item .call-tree-cell[type=function] description::-moz-selection {
|
||||
background-color: var(--theme-highlight-orange);
|
||||
}
|
||||
|
||||
.call-tree-item:last-child {
|
||||
border-bottom: 1px solid var(--cell-border-color);
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ var SimulatorEditor = {
|
||||
// Select an available option, or set the "custom" option.
|
||||
updateSelector(selector, value) {
|
||||
selector.value = value;
|
||||
if (selector[selector.selectedIndex].value !== value) {
|
||||
if (selector.selectedIndex == -1) {
|
||||
selector.value = "custom";
|
||||
selector.classList.add("custom");
|
||||
selector[selector.selectedIndex].textContent = value;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "mozilla/StartupTimeline.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "Navigator.h"
|
||||
#include "URIUtils.h"
|
||||
|
||||
#include "nsIContent.h"
|
||||
@ -3128,6 +3129,38 @@ nsDocShell::NameEquals(const char16_t* aName, bool* aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetCustomUserAgent(nsAString& aCustomUserAgent)
|
||||
{
|
||||
aCustomUserAgent = mCustomUserAgent;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::SetCustomUserAgent(const nsAString& aCustomUserAgent)
|
||||
{
|
||||
mCustomUserAgent = aCustomUserAgent;
|
||||
RefPtr<nsGlobalWindow> win = mScriptGlobal ?
|
||||
mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
|
||||
if (win) {
|
||||
ErrorResult ignored;
|
||||
Navigator* navigator = win->GetNavigator(ignored);
|
||||
ignored.SuppressException();
|
||||
if (navigator) {
|
||||
navigator->ClearUserAgentCache();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t childCount = mChildList.Length();
|
||||
for (uint32_t i = 0; i < childCount; ++i) {
|
||||
nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i));
|
||||
if (childShell) {
|
||||
childShell->SetCustomUserAgent(aCustomUserAgent);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* virtual */ int32_t
|
||||
nsDocShell::ItemType()
|
||||
{
|
||||
@ -3255,6 +3288,7 @@ nsDocShell::SetDocLoaderParent(nsDocLoader* aParent)
|
||||
// If parent is another docshell, we inherit all their flags for
|
||||
// allowing plugins, scripting etc.
|
||||
bool value;
|
||||
nsString customUserAgent;
|
||||
nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
|
||||
if (parentAsDocShell) {
|
||||
if (mAllowPlugins && NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value))) {
|
||||
@ -3284,6 +3318,10 @@ nsDocShell::SetDocLoaderParent(nsDocLoader* aParent)
|
||||
if (parentAsDocShell->GetIsPrerendered()) {
|
||||
SetIsPrerendered(true);
|
||||
}
|
||||
if (NS_SUCCEEDED(parentAsDocShell->GetCustomUserAgent(customUserAgent)) &&
|
||||
!customUserAgent.IsEmpty()) {
|
||||
SetCustomUserAgent(customUserAgent);
|
||||
}
|
||||
if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
|
||||
value = false;
|
||||
}
|
||||
|
@ -793,6 +793,7 @@ protected:
|
||||
nsIntRect mBounds;
|
||||
nsString mName;
|
||||
nsString mTitle;
|
||||
nsString mCustomUserAgent;
|
||||
|
||||
/**
|
||||
* Content-Type Hint of the most-recently initiated load. Used for
|
||||
|
@ -43,7 +43,7 @@ interface nsITabParent;
|
||||
|
||||
typedef unsigned long nsLoadFlags;
|
||||
|
||||
[scriptable, builtinclass, uuid(63adb599-6dc9-4746-972e-c22e9018020b)]
|
||||
[scriptable, builtinclass, uuid(bc3524bd-023c-4fc8-ace1-472bc999fb12)]
|
||||
interface nsIDocShell : nsIDocShellTreeItem
|
||||
{
|
||||
/**
|
||||
@ -237,6 +237,11 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
*/
|
||||
attribute nsIDOMEventTarget chromeEventHandler;
|
||||
|
||||
/**
|
||||
* This allows chrome to set a custom User agent on a specific docshell
|
||||
*/
|
||||
attribute DOMString customUserAgent;
|
||||
|
||||
/**
|
||||
* Whether to allow plugin execution
|
||||
*/
|
||||
@ -250,7 +255,7 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
/**
|
||||
* Attribute stating if refresh based redirects can be allowed
|
||||
*/
|
||||
attribute boolean allowMetaRedirects;
|
||||
attribute boolean allowMetaRedirects;
|
||||
|
||||
/**
|
||||
* Attribute stating if it should allow subframes (framesets/iframes) or not
|
||||
|
@ -84,6 +84,7 @@ skip-if = e10s # Bug 1220927 - Test tries to do addSHistoryListener on content.
|
||||
[browser_multiple_pushState.js]
|
||||
[browser_onbeforeunload_navigation.js]
|
||||
[browser_search_notification.js]
|
||||
[browser_ua_emulation.js]
|
||||
[browser_timelineMarkers-01.js]
|
||||
[browser_timelineMarkers-02.js]
|
||||
[browser_timelineMarkers-03.js]
|
||||
|
52
docshell/test/browser/browser_ua_emulation.js
Normal file
52
docshell/test/browser/browser_ua_emulation.js
Normal file
@ -0,0 +1,52 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the docShell UA emulation works
|
||||
add_task(function*() {
|
||||
yield openUrl("data:text/html;charset=utf-8,<iframe id='test-iframe'></iframe>");
|
||||
|
||||
let docshell = content.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
is(docshell.customUserAgent, "", "There should initially be no customUserAgent");
|
||||
|
||||
docshell.customUserAgent = "foo";
|
||||
is(content.navigator.userAgent, "foo", "The user agent should be changed to foo");
|
||||
|
||||
let frameWin = content.document.querySelector("#test-iframe").contentWindow;
|
||||
is(frameWin.navigator.userAgent, "foo", "The UA should be passed on to frames.");
|
||||
|
||||
let newFrame = content.document.createElement("iframe");
|
||||
content.document.body.appendChild(newFrame);
|
||||
|
||||
let newFrameWin = newFrame.contentWindow;
|
||||
is(newFrameWin.navigator.userAgent, "foo", "Newly created frames should use the new UA");
|
||||
|
||||
newFrameWin.location.reload();
|
||||
yield waitForEvent(newFrameWin, "load");
|
||||
|
||||
is(newFrameWin.navigator.userAgent, "foo", "New UA should persist across reloads");
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
function waitForEvent(target, event) {
|
||||
return new Promise(function(resolve) {
|
||||
target.addEventListener(event, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function openUrl(url) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
window.focus();
|
||||
|
||||
let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
linkedBrowser.addEventListener("load", function onload() {
|
||||
linkedBrowser.removeEventListener("load", onload, true);
|
||||
resolve(tab);
|
||||
}, true);
|
||||
});
|
||||
}
|
@ -6,11 +6,7 @@
|
||||
|
||||
#include "AudioChannelAgent.h"
|
||||
#include "AudioChannelService.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIAppsService.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
@ -81,81 +77,6 @@ AudioChannelAgent::InitWithWeakCallback(nsIDOMWindow* aWindow,
|
||||
/* useWeakRef = */ true);
|
||||
}
|
||||
|
||||
nsresult
|
||||
AudioChannelAgent::FindCorrectWindow(nsIDOMWindow* aWindow)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
|
||||
MOZ_ASSERT(window->IsInnerWindow());
|
||||
|
||||
mWindow = window->GetScriptableTop();
|
||||
if (NS_WARN_IF(!mWindow)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mWindow = mWindow->GetOuterWindow();
|
||||
if (NS_WARN_IF(!mWindow)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// From here we do an hack for nested iframes.
|
||||
// The system app doesn't have access to the nested iframe objects so it
|
||||
// cannot control the volume of the agents running in nested apps. What we do
|
||||
// here is to assign those Agents to the top scriptable window of the parent
|
||||
// iframe (what is controlled by the system app).
|
||||
// For doing this we go recursively back into the chain of windows until we
|
||||
// find apps that are not the system one.
|
||||
window = mWindow->GetParent();
|
||||
if (!window || window == mWindow) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
window = window->GetCurrentInnerWindow();
|
||||
if (!window) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
|
||||
if (!doc) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
|
||||
|
||||
uint32_t appId;
|
||||
nsresult rv = principal->GetAppId(&appId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (appId == nsIScriptSecurityManager::NO_APP_ID ||
|
||||
appId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
|
||||
if (NS_WARN_IF(!appsService)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAdoptingString systemAppManifest =
|
||||
mozilla::Preferences::GetString("b2g.system_manifest_url");
|
||||
if (!systemAppManifest) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t systemAppId;
|
||||
rv = appsService->GetAppLocalIdByManifestURL(systemAppManifest, &systemAppId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (systemAppId == appId) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return FindCorrectWindow(window);
|
||||
}
|
||||
|
||||
nsresult
|
||||
AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
|
||||
nsIAudioChannelAgentCallback *aCallback,
|
||||
@ -187,9 +108,18 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
|
||||
MOZ_ASSERT(pInnerWindow->IsInnerWindow());
|
||||
mInnerWindowID = pInnerWindow->WindowID();
|
||||
|
||||
nsresult rv = FindCorrectWindow(aWindow);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
nsCOMPtr<nsPIDOMWindow> topWindow = pInnerWindow->GetScriptableTop();
|
||||
if (NS_WARN_IF(!topWindow)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mWindow = do_QueryInterface(topWindow);
|
||||
if (mWindow) {
|
||||
mWindow = mWindow->GetOuterWindow();
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mWindow)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mAudioChannelType = aChannelType;
|
||||
|
@ -56,8 +56,6 @@ private:
|
||||
|
||||
void Shutdown();
|
||||
|
||||
nsresult FindCorrectWindow(nsIDOMWindow* aWindow);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
nsCOMPtr<nsIAudioChannelAgentCallback> mCallback;
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
@ -220,7 +219,6 @@ AudioChannelService::Shutdown()
|
||||
|
||||
gAudioChannelService->mWindows.Clear();
|
||||
gAudioChannelService->mPlayingChildren.Clear();
|
||||
gAudioChannelService->mTabParents.Clear();
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
gAudioChannelService->mSpeakerManager.Clear();
|
||||
#endif
|
||||
@ -343,21 +341,6 @@ AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
MaybeSendStatusUpdate();
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::RegisterTabParent(TabParent* aTabParent)
|
||||
{
|
||||
MOZ_ASSERT(aTabParent);
|
||||
MOZ_ASSERT(!mTabParents.Contains(aTabParent));
|
||||
mTabParents.AppendElement(aTabParent);
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::UnregisterTabParent(TabParent* aTabParent)
|
||||
{
|
||||
MOZ_ASSERT(aTabParent);
|
||||
mTabParents.RemoveElement(aTabParent);
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::GetState(nsPIDOMWindow* aWindow, uint32_t aAudioChannel,
|
||||
float* aVolume, bool* aMuted)
|
||||
@ -577,32 +560,6 @@ AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::RefreshAgentsVolumeAndPropagate(AudioChannel aAudioChannel,
|
||||
nsPIDOMWindow* aWindow)
|
||||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(aWindow->IsOuterWindow());
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> topWindow = aWindow->GetScriptableTop();
|
||||
if (!topWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
AudioChannelWindow* winData = GetWindowData(topWindow->WindowID());
|
||||
if (!winData) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mTabParents.Length(); ++i) {
|
||||
mTabParents[i]->AudioChannelChangeNotification(aWindow, aAudioChannel,
|
||||
winData->mChannels[(uint32_t)aAudioChannel].mVolume,
|
||||
winData->mChannels[(uint32_t)aAudioChannel].mMuted);
|
||||
}
|
||||
|
||||
RefreshAgentsVolume(aWindow);
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::RefreshAgentsVolume(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
@ -794,7 +751,7 @@ AudioChannelService::SetAudioChannelVolume(nsPIDOMWindow* aWindow,
|
||||
|
||||
AudioChannelWindow* winData = GetOrCreateWindowData(aWindow);
|
||||
winData->mChannels[(uint32_t)aAudioChannel].mVolume = aVolume;
|
||||
RefreshAgentsVolumeAndPropagate(aAudioChannel, aWindow);
|
||||
RefreshAgentsVolume(aWindow);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -857,7 +814,7 @@ AudioChannelService::SetAudioChannelMuted(nsPIDOMWindow* aWindow,
|
||||
|
||||
AudioChannelWindow* winData = GetOrCreateWindowData(aWindow);
|
||||
winData->mChannels[(uint32_t)aAudioChannel].mMuted = aMuted;
|
||||
RefreshAgentsVolumeAndPropagate(aAudioChannel, aWindow);
|
||||
RefreshAgentsVolume(aWindow);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -23,13 +23,10 @@ struct PRLogModuleInfo;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
class SpeakerManagerService;
|
||||
#endif
|
||||
|
||||
class TabParent;
|
||||
|
||||
#define NUMBER_OF_AUDIO_CHANNELS (uint32_t)AudioChannel::EndGuard_
|
||||
|
||||
class AudioChannelService final : public nsIAudioChannelService
|
||||
@ -66,12 +63,6 @@ public:
|
||||
void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
uint32_t aNotifyPlayback);
|
||||
|
||||
/**
|
||||
* For nested iframes.
|
||||
*/
|
||||
void RegisterTabParent(TabParent* aTabParent);
|
||||
void UnregisterTabParent(TabParent* aTabParent);
|
||||
|
||||
/**
|
||||
* Return the state to indicate this audioChannel for his window should keep
|
||||
* playing/muted.
|
||||
@ -117,9 +108,6 @@ public:
|
||||
|
||||
void RefreshAgentsVolume(nsPIDOMWindow* aWindow);
|
||||
|
||||
void RefreshAgentsVolumeAndPropagate(AudioChannel aAudioChannel,
|
||||
nsPIDOMWindow* aWindow);
|
||||
|
||||
// This method needs to know the inner window that wants to capture audio. We
|
||||
// group agents per top outer window, but we can have multiple innerWindow per
|
||||
// top outerWindow (subiframes, etc.) and we have to identify all the agents
|
||||
@ -235,9 +223,6 @@ private:
|
||||
nsTArray<SpeakerManagerService*> mSpeakerManager;
|
||||
#endif
|
||||
|
||||
// Raw pointers because TabParents must unregister themselves.
|
||||
nsTArray<TabParent*> mTabParents;
|
||||
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
|
||||
uint64_t mDefChannelChildID;
|
||||
|
@ -332,8 +332,7 @@ public:
|
||||
virtual void SetLazyData(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aLastModifiedDate,
|
||||
BlobDirState aDirState) = 0;
|
||||
int64_t aLastModifiedDate) = 0;
|
||||
|
||||
virtual bool IsMemoryFile() const = 0;
|
||||
|
||||
@ -498,8 +497,7 @@ public:
|
||||
|
||||
virtual void
|
||||
SetLazyData(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, int64_t aLastModifiedDate,
|
||||
BlobDirState aDirState) override
|
||||
uint64_t aLength, int64_t aLastModifiedDate) override
|
||||
{
|
||||
mName = aName;
|
||||
mContentType = aContentType;
|
||||
|
@ -372,11 +372,22 @@ Navigator::GetUserAgent(nsAString& aUserAgent)
|
||||
nsCOMPtr<nsIURI> codebaseURI;
|
||||
nsCOMPtr<nsPIDOMWindow> window;
|
||||
|
||||
if (mWindow && mWindow->GetDocShell()) {
|
||||
if (mWindow) {
|
||||
window = mWindow;
|
||||
nsIDocument* doc = mWindow->GetExtantDoc();
|
||||
if (doc) {
|
||||
doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
|
||||
nsIDocShell* docshell = window->GetDocShell();
|
||||
nsString customUserAgent;
|
||||
if (docshell) {
|
||||
docshell->GetCustomUserAgent(customUserAgent);
|
||||
|
||||
if (!customUserAgent.IsEmpty()) {
|
||||
aUserAgent = customUserAgent;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIDocument* doc = mWindow->GetExtantDoc();
|
||||
if (doc) {
|
||||
doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2741,6 +2752,12 @@ Navigator::AppName(nsAString& aAppName, bool aUsePrefOverriddenValue)
|
||||
aAppName.AssignLiteral("Netscape");
|
||||
}
|
||||
|
||||
void
|
||||
Navigator::ClearUserAgentCache()
|
||||
{
|
||||
NavigatorBinding::ClearCachedUserAgentValue(this);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Navigator::GetUserAgent(nsPIDOMWindow* aWindow, nsIURI* aURI,
|
||||
bool aIsCallerChrome,
|
||||
|
@ -182,6 +182,10 @@ public:
|
||||
bool aIsCallerChrome,
|
||||
nsAString& aUserAgent);
|
||||
|
||||
// Clears the user agent cache by calling:
|
||||
// NavigatorBinding::ClearCachedUserAgentValue(this);
|
||||
void ClearUserAgentCache();
|
||||
|
||||
already_AddRefed<Promise> GetDataStores(const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
ErrorResult& aRv);
|
||||
|
@ -1435,6 +1435,7 @@ nsIDocument::nsIDocument()
|
||||
mPostedFlushUserFontSet(false),
|
||||
mPartID(0),
|
||||
mDidFireDOMContentLoaded(true),
|
||||
mHasScrollLinkedEffect(false),
|
||||
mUserHasInteracted(false)
|
||||
{
|
||||
SetInDocument();
|
||||
@ -1555,6 +1556,8 @@ nsDocument::~nsDocument()
|
||||
mixedContentLevel = MIXED_DISPLAY_CONTENT;
|
||||
}
|
||||
Accumulate(Telemetry::MIXED_CONTENT_PAGE_LOAD, mixedContentLevel);
|
||||
|
||||
Accumulate(Telemetry::SCROLL_LINKED_EFFECT_FOUND, mHasScrollLinkedEffect);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2678,6 +2681,16 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
nsAutoCString tCspHeaderValue, tCspROHeaderValue;
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
||||
if (!httpChannel) {
|
||||
// check baseChannel for CSP when loading a multipart channel
|
||||
nsCOMPtr<nsIMultiPartChannel> multipart = do_QueryInterface(aChannel);
|
||||
if (multipart) {
|
||||
nsCOMPtr<nsIChannel> baseChannel;
|
||||
multipart->GetBaseChannel(getter_AddRefs(baseChannel));
|
||||
httpChannel = do_QueryInterface(baseChannel);
|
||||
}
|
||||
}
|
||||
|
||||
if (httpChannel) {
|
||||
httpChannel->GetResponseHeader(
|
||||
NS_LITERAL_CSTRING("content-security-policy"),
|
||||
@ -13276,3 +13289,17 @@ nsIDocument::Fonts()
|
||||
}
|
||||
return mFontFaceSet;
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::ReportHasScrollLinkedEffect()
|
||||
{
|
||||
if (mHasScrollLinkedEffect) {
|
||||
// We already did this once for this document, don't do it again.
|
||||
return;
|
||||
}
|
||||
mHasScrollLinkedEffect = true;
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("Async Pan/Zoom"),
|
||||
this, nsContentUtils::eLAYOUT_PROPERTIES,
|
||||
"ScrollLinkedEffectFound");
|
||||
}
|
||||
|
@ -155,8 +155,8 @@ typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
|
||||
} // namespace mozilla
|
||||
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0x13011a82, 0x46cd, 0x4c33, \
|
||||
{ 0x9d, 0x4e, 0x31, 0x41, 0xbb, 0x3f, 0x18, 0xe9 } }
|
||||
{ 0xce1f7627, 0x7109, 0x4977, \
|
||||
{ 0xba, 0x77, 0x49, 0x0f, 0xfd, 0xe0, 0x7a, 0xaa } }
|
||||
|
||||
// Enum for requesting a particular type of document when creating a doc
|
||||
enum DocumentFlavor {
|
||||
@ -2652,6 +2652,8 @@ public:
|
||||
return mUserHasInteracted;
|
||||
}
|
||||
|
||||
void ReportHasScrollLinkedEffect();
|
||||
|
||||
protected:
|
||||
bool GetUseCounter(mozilla::UseCounter aUseCounter)
|
||||
{
|
||||
@ -3052,6 +3054,8 @@ protected:
|
||||
uint32_t mBlockDOMContentLoaded;
|
||||
bool mDidFireDOMContentLoaded:1;
|
||||
|
||||
bool mHasScrollLinkedEffect:1;
|
||||
|
||||
// Our live MediaQueryLists
|
||||
PRCList mDOMMediaQueryLists;
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface mozIApplication;
|
||||
interface nsFrameLoader;
|
||||
interface nsIDocShell;
|
||||
interface nsIURI;
|
||||
@ -215,7 +214,7 @@ class nsFrameLoader;
|
||||
|
||||
native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
|
||||
|
||||
[scriptable, uuid(adc1b3ba-8deb-4943-8045-e6de0044f2ce)]
|
||||
[scriptable, uuid(c4abebcf-55f3-47d4-af15-151311971255)]
|
||||
interface nsIFrameLoaderOwner : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -224,12 +223,6 @@ interface nsIFrameLoaderOwner : nsISupports
|
||||
readonly attribute nsIFrameLoader frameLoader;
|
||||
[noscript, notxpcom] alreadyAddRefed_nsFrameLoader GetFrameLoader();
|
||||
|
||||
/**
|
||||
* The principal of parent mozIApplication in case of nested mozbrowser
|
||||
* iframes.
|
||||
*/
|
||||
readonly attribute mozIApplication parentApplication;
|
||||
|
||||
/**
|
||||
* Puts the FrameLoaderOwner in prerendering mode.
|
||||
*/
|
||||
|
@ -1215,17 +1215,6 @@ nsObjectLoadingContent::GetFrameLoader()
|
||||
return loader.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObjectLoadingContent::GetParentApplication(mozIApplication** aApplication)
|
||||
{
|
||||
if (!aApplication) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aApplication = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObjectLoadingContent::SetIsPrerendered()
|
||||
{
|
||||
|
@ -770,7 +770,7 @@ CouldBeDOMBinding(nsWrapperCache* aCache)
|
||||
}
|
||||
|
||||
inline bool
|
||||
TryToOuterize(JSContext* cx, JS::MutableHandle<JS::Value> rval)
|
||||
TryToOuterize(JS::MutableHandle<JS::Value> rval)
|
||||
{
|
||||
if (js::IsWindow(&rval.toObject())) {
|
||||
JSObject* obj = js::ToWindowProxyIfWindow(&rval.toObject());
|
||||
@ -812,7 +812,7 @@ MaybeWrapObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
|
||||
// We're same-compartment, but even then we might need to wrap
|
||||
// objects specially. Check for that.
|
||||
if (IsDOMObject(obj)) {
|
||||
return TryToOuterize(cx, rval);
|
||||
return TryToOuterize(rval);
|
||||
}
|
||||
|
||||
// It's not a WebIDL object. But it might be an XPConnect one, in which case
|
||||
@ -1005,13 +1005,13 @@ DoGetOrCreateDOMReflector(JSContext* cx, T* value,
|
||||
bool sameCompartment =
|
||||
js::GetObjectCompartment(obj) == js::GetContextCompartment(cx);
|
||||
if (sameCompartment && couldBeDOMBinding) {
|
||||
return TypeNeedsOuterization<T>::value ? TryToOuterize(cx, rval) : true;
|
||||
return TypeNeedsOuterization<T>::value ? TryToOuterize(rval) : true;
|
||||
}
|
||||
|
||||
if (wrapBehavior == eDontWrapIntoContextCompartment) {
|
||||
if (TypeNeedsOuterization<T>::value) {
|
||||
JSAutoCompartment ac(cx, obj);
|
||||
return TryToOuterize(cx, rval);
|
||||
return TryToOuterize(rval);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -7,8 +7,6 @@
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/dom/BrowserElementAudioChannelBinding.h"
|
||||
#include "mozilla/dom/DOMRequest.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
@ -25,6 +23,16 @@
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
AssertIsInMainProcess()
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@ -81,6 +89,7 @@ BrowserElementAudioChannel::BrowserElementAudioChannel(
|
||||
, mState(eStateUnknown)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
AssertIsInMainProcess();
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
@ -98,6 +107,7 @@ BrowserElementAudioChannel::BrowserElementAudioChannel(
|
||||
BrowserElementAudioChannel::~BrowserElementAudioChannel()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
AssertIsInMainProcess();
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
@ -163,6 +173,8 @@ AudioChannel
|
||||
BrowserElementAudioChannel::Name() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
AssertIsInMainProcess();
|
||||
|
||||
return mAudioChannel;
|
||||
}
|
||||
|
||||
@ -349,6 +361,7 @@ already_AddRefed<dom::DOMRequest>
|
||||
BrowserElementAudioChannel::GetVolume(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
AssertIsInMainProcess();
|
||||
|
||||
if (!mFrameWindow) {
|
||||
nsCOMPtr<nsIDOMDOMRequest> request;
|
||||
@ -374,6 +387,7 @@ already_AddRefed<dom::DOMRequest>
|
||||
BrowserElementAudioChannel::SetVolume(float aVolume, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
AssertIsInMainProcess();
|
||||
|
||||
if (!mFrameWindow) {
|
||||
nsCOMPtr<nsIDOMDOMRequest> request;
|
||||
@ -406,6 +420,7 @@ already_AddRefed<dom::DOMRequest>
|
||||
BrowserElementAudioChannel::GetMuted(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
AssertIsInMainProcess();
|
||||
|
||||
if (!mFrameWindow) {
|
||||
nsCOMPtr<nsIDOMDOMRequest> request;
|
||||
@ -431,6 +446,7 @@ already_AddRefed<dom::DOMRequest>
|
||||
BrowserElementAudioChannel::SetMuted(bool aMuted, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
AssertIsInMainProcess();
|
||||
|
||||
if (!mFrameWindow) {
|
||||
nsCOMPtr<nsIDOMDOMRequest> request;
|
||||
@ -463,6 +479,7 @@ already_AddRefed<dom::DOMRequest>
|
||||
BrowserElementAudioChannel::IsActive(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
AssertIsInMainProcess();
|
||||
|
||||
if (mState != eStateUnknown) {
|
||||
RefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
|
||||
@ -576,29 +593,8 @@ BrowserElementAudioChannel::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
|
||||
// This can be a nested iframe.
|
||||
if (!wrapper) {
|
||||
nsCOMPtr<nsITabParent> iTabParent = do_QueryInterface(aSubject);
|
||||
if (!iTabParent) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<TabParent> tabParent = TabParent::GetFrom(iTabParent);
|
||||
if (!tabParent) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
Element* element = tabParent->GetOwnerElement();
|
||||
if (!element) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = element->OwnerDoc()->GetWindow();
|
||||
if (window == mFrameWindow) {
|
||||
ProcessStateChanged(aData);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
if (NS_WARN_IF(!wrapper)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint64_t windowID;
|
||||
|
@ -597,6 +597,7 @@ BrowserElementChild.prototype = {
|
||||
let handlers = {
|
||||
'icon': this._iconChangedHandler.bind(this),
|
||||
'apple-touch-icon': this._iconChangedHandler.bind(this),
|
||||
'apple-touch-icon-precomposed': this._iconChangedHandler.bind(this),
|
||||
'search': this._openSearchHandler,
|
||||
'manifest': this._manifestChangedHandler
|
||||
};
|
||||
|
@ -192,10 +192,7 @@ function runTests() {
|
||||
}
|
||||
|
||||
|
||||
addEventListener('testready', function() {
|
||||
SpecialPowers.pushPrefEnv({'set': [["b2g.system_manifest_url", "http://mochi.test:8888/manifest.webapp"]]},
|
||||
function() {
|
||||
SimpleTest.executeSoon(runTests);
|
||||
});
|
||||
addEventListener('load', function() {
|
||||
SimpleTest.executeSoon(runTests);
|
||||
});
|
||||
|
||||
|
@ -1,79 +0,0 @@
|
||||
/* Any copyright is dedicated to the public domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Bug 1113086 - tests for AudioChannel API into BrowserElement
|
||||
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
browserElementTestHelpers.setEnabledPref(true);
|
||||
browserElementTestHelpers.addPermission();
|
||||
|
||||
function runTests() {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('mozbrowser', 'true');
|
||||
iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
|
||||
|
||||
var listener = function(e) {
|
||||
var message = e.detail.message;
|
||||
if (/^OK/.exec(message)) {
|
||||
ok(true, "Message from app: " + message);
|
||||
} else if (/^KO/.exec(message)) {
|
||||
ok(false, "Message from app: " + message);
|
||||
} else if (/DONE/.exec(message)) {
|
||||
ok(true, "Messaging from app complete");
|
||||
iframe.removeEventListener('mozbrowsershowmodalprompt', listener);
|
||||
}
|
||||
}
|
||||
|
||||
function audio_loadend() {
|
||||
ok("mute" in iframe, "iframe.mute exists");
|
||||
ok("unmute" in iframe, "iframe.unmute exists");
|
||||
ok("getMuted" in iframe, "iframe.getMuted exists");
|
||||
ok("getVolume" in iframe, "iframe.getVolume exists");
|
||||
ok("setVolume" in iframe, "iframe.setVolume exists");
|
||||
|
||||
ok("allowedAudioChannels" in iframe, "allowedAudioChannels exist");
|
||||
var channels = iframe.allowedAudioChannels;
|
||||
is(channels.length, 1, "1 audio channel by default");
|
||||
|
||||
var ac = channels[0];
|
||||
|
||||
ok(ac instanceof BrowserElementAudioChannel, "Correct class");
|
||||
ok("getVolume" in ac, "ac.getVolume exists");
|
||||
ok("setVolume" in ac, "ac.setVolume exists");
|
||||
ok("getMuted" in ac, "ac.getMuted exists");
|
||||
ok("setMuted" in ac, "ac.setMuted exists");
|
||||
ok("isActive" in ac, "ac.isActive exists");
|
||||
|
||||
info("Setting the volume...");
|
||||
ac.setVolume(0.5);
|
||||
|
||||
ac.onactivestatechanged = function() {
|
||||
ok(true, "activestatechanged event received.");
|
||||
ac.onactivestatechanged = null;
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
iframe.addEventListener('mozbrowserloadend', audio_loadend);
|
||||
iframe.addEventListener('mozbrowsershowmodalprompt', listener, false);
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
var context = { 'url': 'http://example.org',
|
||||
'appId': SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
|
||||
'isInBrowserElement': true };
|
||||
SpecialPowers.pushPermissions([
|
||||
{'type': 'browser', 'allow': 1, 'context': context},
|
||||
{'type': 'embed-apps', 'allow': 1, 'context': context}
|
||||
], function() {
|
||||
iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_AudioChannel_nested.html';
|
||||
});
|
||||
}
|
||||
|
||||
addEventListener('testready', function() {
|
||||
SpecialPowers.pushPrefEnv({'set': [["b2g.system_manifest_url", "http://mochi.test:8888/manifest.webapp"]]},
|
||||
function() {
|
||||
SimpleTest.executeSoon(runTests);
|
||||
});
|
||||
});
|
@ -68,9 +68,4 @@ function runTest() {
|
||||
iframe.src = browserElementTestHelpers.emptyPage1;
|
||||
}
|
||||
|
||||
addEventListener('testready', function() {
|
||||
SpecialPowers.pushPrefEnv({'set': [["b2g.system_manifest_url", "http://mochi.test:8888/manifest.webapp"]]},
|
||||
function() {
|
||||
SimpleTest.executeSoon(runTest);
|
||||
});
|
||||
});
|
||||
addEventListener('testready', runTest);
|
||||
|
@ -102,6 +102,12 @@ function runTest() {
|
||||
is(e.detail.href, 'http://example.com/testapple1.png');
|
||||
is(e.detail.rel, 'apple-touch-icon');
|
||||
is(e.detail.sizes, '100x100');
|
||||
|
||||
iframe1.src = createHtml(createLink('testapple2', '100x100', 'apple-touch-icon-precomposed'));
|
||||
} else if (numIconChanges == 9) {
|
||||
is(e.detail.href, 'http://example.com/testapple2.png');
|
||||
is(e.detail.rel, 'apple-touch-icon-precomposed');
|
||||
is(e.detail.sizes, '100x100');
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
ok(false, 'Too many iconchange events.');
|
||||
|
@ -1,63 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((!!a ? "OK" : "KO") + " " + msg);
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
ok(a === b, msg);
|
||||
}
|
||||
|
||||
function finish(a, b, msg) {
|
||||
alert("DONE");
|
||||
}
|
||||
|
||||
addEventListener('load', function(e) {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('mozbrowser', 'true');
|
||||
// set 'remote' to true here will make the the iframe remote in _inproc_
|
||||
// test and in-process in _oop_ test.
|
||||
iframe.setAttribute('remote', 'true');
|
||||
iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
|
||||
|
||||
iframe.addEventListener('mozbrowserloadend', function(e) {
|
||||
ok("mute" in iframe, "iframe.mute exists");
|
||||
ok("unmute" in iframe, "iframe.unmute exists");
|
||||
ok("getMuted" in iframe, "iframe.getMuted exists");
|
||||
ok("getVolume" in iframe, "iframe.getVolume exists");
|
||||
ok("setVolume" in iframe, "iframe.setVolume exists");
|
||||
|
||||
ok("allowedAudioChannels" in iframe, "allowedAudioChannels exist");
|
||||
var channels = iframe.allowedAudioChannels;
|
||||
is(channels.length, 1, "1 audio channel by default");
|
||||
|
||||
var ac = channels[0];
|
||||
|
||||
ok(ac instanceof BrowserElementAudioChannel, "Correct class");
|
||||
ok("getVolume" in ac, "ac.getVolume exists");
|
||||
ok("setVolume" in ac, "ac.setVolume exists");
|
||||
ok("getMuted" in ac, "ac.getMuted exists");
|
||||
ok("setMuted" in ac, "ac.setMuted exists");
|
||||
ok("isActive" in ac, "ac.isActive exists");
|
||||
|
||||
ac.onactivestatechanged = function() {
|
||||
ok("activestatechanged event received.");
|
||||
|
||||
ac.getVolume().onsuccess = function(e) {
|
||||
ok(e.target.result, 1, "Default volume is 1");
|
||||
};
|
||||
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_audio.html';
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
@ -121,7 +121,6 @@ disabled = bug 924771
|
||||
disabled = bug 924771
|
||||
[test_browserElement_oop_GetContentDimensions.html]
|
||||
[test_browserElement_oop_AudioChannel.html]
|
||||
[test_browserElement_oop_AudioChannel_nested.html]
|
||||
[test_browserElement_oop_SetNFCFocus.html]
|
||||
[test_browserElement_oop_getWebManifest.html]
|
||||
[test_browserElement_oop_OpenWindowEmpty.html]
|
||||
|
@ -83,13 +83,11 @@ support-files =
|
||||
browserElement_XFrameOptionsSameOrigin.js
|
||||
browserElement_GetContentDimensions.js
|
||||
browserElement_AudioChannel.js
|
||||
browserElement_AudioChannel_nested.js
|
||||
file_browserElement_AlertInFrame.html
|
||||
file_browserElement_AlertInFrame_Inner.html
|
||||
file_browserElement_AllowEmbedAppsInNestedOOIframe.html
|
||||
file_browserElement_AppFramePermission.html
|
||||
file_browserElement_AppWindowNamespace.html
|
||||
file_browserElement_AudioChannel_nested.html
|
||||
file_browserElement_Viewmode.html
|
||||
file_browserElement_ThemeColor.html
|
||||
file_browserElement_BrowserWindowNamespace.html
|
||||
@ -252,7 +250,6 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
||||
disabled = bug 774100
|
||||
[test_browserElement_inproc_GetContentDimensions.html]
|
||||
[test_browserElement_inproc_AudioChannel.html]
|
||||
[test_browserElement_inproc_AudioChannel_nested.html]
|
||||
[test_browserElement_inproc_SetNFCFocus.html]
|
||||
[test_browserElement_inproc_getStructuredData.html]
|
||||
[test_browserElement_inproc_OpenWindowEmpty.html]
|
||||
|
@ -1,13 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test of browser element audioChannel in nested mozbrowser iframes.</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7" src="browserElement_AudioChannel_nested.js">
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,13 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test of browser element audioChannel.</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7" src="browserElement_AudioChannel_nested.js">
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -14,19 +14,12 @@
|
||||
namespace mozilla {
|
||||
|
||||
static bool
|
||||
GetFBInfoForBlit(const WebGLFramebuffer* fb, WebGLContext* webgl,
|
||||
const char* const fbInfo, GLsizei* const out_samples,
|
||||
GetFBInfoForBlit(const WebGLFramebuffer* fb, const char* const fbInfo,
|
||||
GLsizei* const out_samples,
|
||||
const webgl::FormatInfo** const out_colorFormat,
|
||||
const webgl::FormatInfo** const out_depthFormat,
|
||||
const webgl::FormatInfo** const out_stencilFormat)
|
||||
{
|
||||
auto status = fb->PrecheckFramebufferStatus();
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
webgl->ErrorInvalidOperation("blitFramebuffer: %s is not"
|
||||
" framebuffer-complete.", fbInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_samples = 1; // TODO
|
||||
*out_colorFormat = nullptr;
|
||||
*out_depthFormat = nullptr;
|
||||
@ -85,6 +78,9 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
|
||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||
GLbitfield mask, GLenum filter)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
const GLbitfield validBits = LOCAL_GL_COLOR_BUFFER_BIT |
|
||||
LOCAL_GL_DEPTH_BUFFER_BIT |
|
||||
LOCAL_GL_STENCIL_BUFFER_BIT;
|
||||
@ -122,15 +118,20 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mBoundReadFramebuffer->ValidateAndInitAttachments("blitFramebuffer's READ_FRAMEBUFFER") ||
|
||||
!mBoundDrawFramebuffer->ValidateAndInitAttachments("blitFramebuffer's DRAW_FRAMEBUFFER"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GLsizei srcSamples;
|
||||
const webgl::FormatInfo* srcColorFormat = nullptr;
|
||||
const webgl::FormatInfo* srcDepthFormat = nullptr;
|
||||
const webgl::FormatInfo* srcStencilFormat = nullptr;
|
||||
|
||||
if (mBoundReadFramebuffer) {
|
||||
if (!GetFBInfoForBlit(mBoundReadFramebuffer, this, "READ_FRAMEBUFFER",
|
||||
&srcSamples, &srcColorFormat, &srcDepthFormat,
|
||||
&srcStencilFormat))
|
||||
if (!GetFBInfoForBlit(mBoundReadFramebuffer, "READ_FRAMEBUFFER", &srcSamples,
|
||||
&srcColorFormat, &srcDepthFormat, &srcStencilFormat))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -147,9 +148,8 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
|
||||
const webgl::FormatInfo* dstStencilFormat = nullptr;
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!GetFBInfoForBlit(mBoundDrawFramebuffer, this, "DRAW_FRAMEBUFFER",
|
||||
&dstSamples, &dstColorFormat, &dstDepthFormat,
|
||||
&dstStencilFormat))
|
||||
if (!GetFBInfoForBlit(mBoundDrawFramebuffer, "DRAW_FRAMEBUFFER", &dstSamples,
|
||||
&dstColorFormat, &dstDepthFormat, &dstStencilFormat))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -104,14 +104,18 @@ WebGL2Context::VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_INT;
|
||||
|
||||
if (index || gl->IsGLES()) {
|
||||
MakeContextCurrent();
|
||||
MakeContextCurrent();
|
||||
|
||||
if (index) {
|
||||
gl->fVertexAttribI4i(index, x, y, z, w);
|
||||
} else {
|
||||
mVertexAttrib0Vector[0] = BitwiseCast<GLfloat>(x);
|
||||
mVertexAttrib0Vector[1] = BitwiseCast<GLfloat>(y);
|
||||
mVertexAttrib0Vector[2] = BitwiseCast<GLfloat>(z);
|
||||
mVertexAttrib0Vector[3] = BitwiseCast<GLfloat>(w);
|
||||
if (gl->IsGLES()) {
|
||||
gl->fVertexAttribI4i(index, x, y, z, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,14 +130,18 @@ WebGL2Context::VertexAttribI4iv(GLuint index, size_t length, const GLint* v)
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_INT;
|
||||
|
||||
if (index || gl->IsGLES()) {
|
||||
MakeContextCurrent();
|
||||
MakeContextCurrent();
|
||||
|
||||
if (index) {
|
||||
gl->fVertexAttribI4iv(index, v);
|
||||
} else {
|
||||
mVertexAttrib0Vector[0] = BitwiseCast<GLfloat>(v[0]);
|
||||
mVertexAttrib0Vector[1] = BitwiseCast<GLfloat>(v[1]);
|
||||
mVertexAttrib0Vector[2] = BitwiseCast<GLfloat>(v[2]);
|
||||
mVertexAttrib0Vector[3] = BitwiseCast<GLfloat>(v[3]);
|
||||
if (gl->IsGLES()) {
|
||||
gl->fVertexAttribI4iv(index, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,14 +162,18 @@ WebGL2Context::VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLui
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_UNSIGNED_INT;
|
||||
|
||||
if (index || gl->IsGLES()) {
|
||||
MakeContextCurrent();
|
||||
MakeContextCurrent();
|
||||
|
||||
if (index) {
|
||||
gl->fVertexAttribI4ui(index, x, y, z, w);
|
||||
} else {
|
||||
mVertexAttrib0Vector[0] = BitwiseCast<GLfloat>(x);
|
||||
mVertexAttrib0Vector[1] = BitwiseCast<GLfloat>(y);
|
||||
mVertexAttrib0Vector[2] = BitwiseCast<GLfloat>(z);
|
||||
mVertexAttrib0Vector[3] = BitwiseCast<GLfloat>(w);
|
||||
if (gl->IsGLES()) {
|
||||
gl->fVertexAttribI4ui(index, x, y, z, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,14 +191,18 @@ WebGL2Context::VertexAttribI4uiv(GLuint index, size_t length, const GLuint* v)
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_UNSIGNED_INT;
|
||||
|
||||
if (index || gl->IsGLES()) {
|
||||
MakeContextCurrent();
|
||||
MakeContextCurrent();
|
||||
|
||||
if (index) {
|
||||
gl->fVertexAttribI4uiv(index, v);
|
||||
} else {
|
||||
mVertexAttrib0Vector[0] = BitwiseCast<GLfloat>(v[0]);
|
||||
mVertexAttrib0Vector[1] = BitwiseCast<GLfloat>(v[1]);
|
||||
mVertexAttrib0Vector[2] = BitwiseCast<GLfloat>(v[2]);
|
||||
mVertexAttrib0Vector[3] = BitwiseCast<GLfloat>(v[3]);
|
||||
if (gl->IsGLES()) {
|
||||
gl->fVertexAttribI4uiv(index, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1414,12 +1414,23 @@ WebGLContext::PresentScreenBuffer()
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DummyFramebufferOperation(const char* funcName)
|
||||
WebGLContext::DummyReadFramebufferOperation(const char* funcName)
|
||||
{
|
||||
FBStatus status = CheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
if (!mBoundReadFramebuffer)
|
||||
return; // Infallible.
|
||||
|
||||
nsCString fbStatusInfo;
|
||||
const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(&fbStatusInfo);
|
||||
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer",
|
||||
funcName);
|
||||
nsCString errorText("Incomplete framebuffer");
|
||||
|
||||
if (fbStatusInfo.Length()) {
|
||||
errorText += ": ";
|
||||
errorText += fbStatusInfo;
|
||||
}
|
||||
|
||||
ErrorInvalidFramebufferOperation("%s: %s.", funcName, errorText.BeginReading());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1884,9 +1895,70 @@ Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize,
|
||||
*out_intSize = std::max<int32_t>(0, intEndInSrc - *out_intStartInSrc);
|
||||
}
|
||||
|
||||
static bool
|
||||
ZeroTexImageWithClear(WebGLContext* webgl, GLContext* gl, TexImageTarget target,
|
||||
GLuint tex, uint32_t level, const webgl::FormatUsageInfo* usage,
|
||||
uint32_t width, uint32_t height)
|
||||
{
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
||||
ScopedFramebuffer scopedFB(gl);
|
||||
ScopedBindFramebuffer scopedBindFB(gl, scopedFB.FB());
|
||||
|
||||
const auto format = usage->format;
|
||||
|
||||
GLenum attachPoint = 0;
|
||||
GLbitfield clearBits = 0;
|
||||
|
||||
if (format->isColorFormat) {
|
||||
attachPoint = LOCAL_GL_COLOR_ATTACHMENT0;
|
||||
clearBits = LOCAL_GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
|
||||
if (format->hasDepth) {
|
||||
attachPoint = LOCAL_GL_DEPTH_ATTACHMENT;
|
||||
clearBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
|
||||
}
|
||||
|
||||
if (format->hasStencil) {
|
||||
attachPoint = (format->hasDepth ? LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
|
||||
: LOCAL_GL_STENCIL_ATTACHMENT);
|
||||
clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(attachPoint && clearBits);
|
||||
|
||||
{
|
||||
gl::GLContext::LocalErrorScope errorScope(*gl);
|
||||
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachPoint, target.get(), tex,
|
||||
level);
|
||||
if (errorScope.GetError()) {
|
||||
MOZ_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
|
||||
return false;
|
||||
|
||||
{
|
||||
gl::GLContext::LocalErrorScope errorScope(*gl);
|
||||
|
||||
const bool fakeNoAlpha = false;
|
||||
webgl->ForceClearFramebufferWithDefaultValues(clearBits, fakeNoAlpha);
|
||||
if (errorScope.GetError()) {
|
||||
MOZ_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ZeroTextureData(WebGLContext* webgl, const char* funcName, bool respecifyTexture,
|
||||
TexImageTarget target, uint32_t level,
|
||||
GLuint tex, TexImageTarget target, uint32_t level,
|
||||
const webgl::FormatUsageInfo* usage, uint32_t xOffset, uint32_t yOffset,
|
||||
uint32_t zOffset, uint32_t width, uint32_t height, uint32_t depth)
|
||||
{
|
||||
@ -1906,9 +1978,6 @@ ZeroTextureData(WebGLContext* webgl, const char* funcName, bool respecifyTexture
|
||||
gl::GLContext* gl = webgl->GL();
|
||||
gl->MakeCurrent();
|
||||
|
||||
ScopedUnpackReset scopedReset(webgl);
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it well.
|
||||
|
||||
auto compression = usage->format->compression;
|
||||
if (compression) {
|
||||
MOZ_RELEASE_ASSERT(!xOffset && !yOffset && !zOffset);
|
||||
@ -1938,6 +2007,10 @@ ZeroTextureData(WebGLContext* webgl, const char* funcName, bool respecifyTexture
|
||||
if (!zeros)
|
||||
return false;
|
||||
|
||||
ScopedUnpackReset scopedReset(webgl);
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it
|
||||
// well.
|
||||
|
||||
GLenum error = DoCompressedTexSubImage(gl, target.get(), level, xOffset, yOffset,
|
||||
zOffset, width, height, depth, sizedFormat,
|
||||
byteCount, zeros.get());
|
||||
@ -1950,6 +2023,27 @@ ZeroTextureData(WebGLContext* webgl, const char* funcName, bool respecifyTexture
|
||||
const auto driverUnpackInfo = usage->idealUnpack;
|
||||
MOZ_RELEASE_ASSERT(driverUnpackInfo);
|
||||
|
||||
if (usage->isRenderable && depth == 1 &&
|
||||
!xOffset && !yOffset && !zOffset)
|
||||
{
|
||||
// While we would like to skip the extra complexity of trying to zero with an FB
|
||||
// clear, ANGLE_depth_texture requires this.
|
||||
do {
|
||||
if (respecifyTexture) {
|
||||
const auto error = DoTexImage(gl, target, level, driverUnpackInfo, width,
|
||||
height, depth, nullptr);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ZeroTexImageWithClear(webgl, gl, target, tex, level, usage, width,
|
||||
height))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
} while (false);
|
||||
}
|
||||
|
||||
const webgl::PackingInfo packing = driverUnpackInfo->ToPacking();
|
||||
|
||||
const auto bytesPerPixel = webgl::BytesPerPixel(packing);
|
||||
@ -1968,6 +2062,9 @@ ZeroTextureData(WebGLContext* webgl, const char* funcName, bool respecifyTexture
|
||||
if (!zeros)
|
||||
return false;
|
||||
|
||||
ScopedUnpackReset scopedReset(webgl);
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it well.
|
||||
|
||||
GLenum error;
|
||||
if (respecifyTexture) {
|
||||
MOZ_RELEASE_ASSERT(!xOffset && !yOffset && !zOffset);
|
||||
|
@ -303,7 +303,7 @@ public:
|
||||
// Returns hex formatted version of glenum if glenum is unknown.
|
||||
static void EnumName(GLenum glenum, nsACString* out_name);
|
||||
|
||||
void DummyFramebufferOperation(const char* funcName);
|
||||
void DummyReadFramebufferOperation(const char* funcName);
|
||||
|
||||
WebGLTexture* ActiveBoundTextureForTarget(const TexTarget texTarget) const {
|
||||
switch (texTarget.get()) {
|
||||
@ -1756,7 +1756,7 @@ Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize,
|
||||
|
||||
bool
|
||||
ZeroTextureData(WebGLContext* webgl, const char* funcName, bool respecifyTexture,
|
||||
TexImageTarget target, uint32_t level,
|
||||
GLuint tex, TexImageTarget target, uint32_t level,
|
||||
const webgl::FormatUsageInfo* usage, uint32_t xOffset, uint32_t yOffset,
|
||||
uint32_t zOffset, uint32_t width, uint32_t height, uint32_t depth);
|
||||
|
||||
|
@ -50,7 +50,7 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
|
||||
//typedef nsTArray<WebGLRefPtr<WebGLTexture>> TexturesT;
|
||||
typedef decltype(WebGLContext::mBound2DTextures) TexturesT;
|
||||
|
||||
const auto fnResolveAll = [this, funcName, out_error](const TexturesT& textures)
|
||||
const auto fnResolveAll = [this, funcName](const TexturesT& textures)
|
||||
{
|
||||
const auto len = textures.Length();
|
||||
for (uint32_t texUnit = 0; texUnit < len; ++texUnit) {
|
||||
@ -59,7 +59,8 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
|
||||
continue;
|
||||
|
||||
FakeBlackType fakeBlack;
|
||||
*out_error |= !tex->ResolveForDraw(funcName, texUnit, &fakeBlack);
|
||||
if (!tex->ResolveForDraw(funcName, texUnit, &fakeBlack))
|
||||
return false;
|
||||
|
||||
if (fakeBlack == FakeBlackType::None)
|
||||
continue;
|
||||
@ -67,14 +68,16 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
|
||||
mWebGL->BindFakeBlack(texUnit, tex->Target(), fakeBlack);
|
||||
mRebindRequests.push_back({texUnit, tex});
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
*out_error = false;
|
||||
|
||||
fnResolveAll(mWebGL->mBound2DTextures);
|
||||
fnResolveAll(mWebGL->mBoundCubeMapTextures);
|
||||
fnResolveAll(mWebGL->mBound3DTextures);
|
||||
fnResolveAll(mWebGL->mBound2DArrayTextures);
|
||||
*out_error |= !fnResolveAll(mWebGL->mBound2DTextures);
|
||||
*out_error |= !fnResolveAll(mWebGL->mBoundCubeMapTextures);
|
||||
*out_error |= !fnResolveAll(mWebGL->mBound3DTextures);
|
||||
*out_error |= !fnResolveAll(mWebGL->mBound2DArrayTextures);
|
||||
|
||||
if (*out_error) {
|
||||
mWebGL->ErrorOutOfMemory("%s: Failed to resolve textures for draw.", funcName);
|
||||
@ -220,10 +223,8 @@ WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
|
||||
MakeContextCurrent();
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
|
||||
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ClearBackbufferIfNeeded();
|
||||
}
|
||||
@ -411,10 +412,8 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
||||
MakeContextCurrent();
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
|
||||
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ClearBackbufferIfNeeded();
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ namespace mozilla {
|
||||
void
|
||||
WebGLContext::Clear(GLbitfield mask)
|
||||
{
|
||||
const char funcName[] = "clear";
|
||||
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
@ -22,7 +24,7 @@ WebGLContext::Clear(GLbitfield mask)
|
||||
|
||||
uint32_t m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT);
|
||||
if (mask != m)
|
||||
return ErrorInvalidValue("clear: invalid mask bits");
|
||||
return ErrorInvalidValue("%s: invalid mask bits", funcName);
|
||||
|
||||
if (mask == 0) {
|
||||
GenerateWarning("Calling gl.clear(0) has no effect.");
|
||||
@ -31,8 +33,8 @@ WebGLContext::Clear(GLbitfield mask)
|
||||
}
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->CheckAndInitializeAttachments())
|
||||
return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
|
||||
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
|
||||
return;
|
||||
|
||||
gl->fClear(mask);
|
||||
return;
|
||||
|
@ -279,7 +279,8 @@ WebGLContext::CheckFramebufferStatus(GLenum target)
|
||||
if (!fb)
|
||||
return LOCAL_GL_FRAMEBUFFER_COMPLETE;
|
||||
|
||||
return fb->CheckFramebufferStatus().get();
|
||||
nsCString fbErrorInfo;
|
||||
return fb->CheckFramebufferStatus(&fbErrorInfo).get();
|
||||
}
|
||||
|
||||
already_AddRefed<WebGLProgram>
|
||||
@ -1572,7 +1573,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
|
||||
|
||||
if (!rwWidth || !rwHeight) {
|
||||
// There aren't any, so we're 'done'.
|
||||
DummyFramebufferOperation("readPixels");
|
||||
DummyReadFramebufferOperation("readPixels");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,8 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
}
|
||||
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
|
||||
if (mBoundReadFramebuffer) {
|
||||
FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus();
|
||||
nsCString fbStatusInfoIgnored;
|
||||
const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(&fbStatusInfoIgnored);
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
ErrorInvalidOperation("getParameter: Read framebuffer must be"
|
||||
" complete before querying"
|
||||
@ -313,7 +314,8 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
}
|
||||
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: {
|
||||
if (mBoundReadFramebuffer) {
|
||||
FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus();
|
||||
nsCString fbStatusInfoIgnored;
|
||||
const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(&fbStatusInfoIgnored);
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
ErrorInvalidOperation("getParameter: Read framebuffer must be"
|
||||
" complete before querying"
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLContextUtils.h"
|
||||
#include "WebGLExtensions.h"
|
||||
@ -218,48 +219,114 @@ WebGLFBAttachPoint::OnBackingStoreRespecified() const
|
||||
mFB->InvalidateFramebufferStatus();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFBAttachPoint::AttachmentName(nsCString* out) const
|
||||
{
|
||||
switch (mAttachmentPoint) {
|
||||
case LOCAL_GL_DEPTH_ATTACHMENT:
|
||||
out->AssignLiteral("DEPTH_ATTACHMENT");
|
||||
return;
|
||||
|
||||
case LOCAL_GL_STENCIL_ATTACHMENT:
|
||||
out->AssignLiteral("STENCIL_ATTACHMENT");
|
||||
return;
|
||||
|
||||
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
|
||||
out->AssignLiteral("DEPTH_STENCIL_ATTACHMENT");
|
||||
return;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0);
|
||||
out->AssignLiteral("COLOR_ATTACHMENT");
|
||||
const uint32_t n = mAttachmentPoint - LOCAL_GL_COLOR_ATTACHMENT0;
|
||||
out->AppendInt(n);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLFBAttachPoint::IsComplete(WebGLContext* webgl) const
|
||||
WebGLFBAttachPoint::IsComplete(WebGLContext* webgl, nsCString* const out_info) const
|
||||
{
|
||||
MOZ_ASSERT(IsDefined());
|
||||
|
||||
if (!HasImage())
|
||||
if (!HasImage()) {
|
||||
AttachmentName(out_info);
|
||||
out_info->AppendLiteral("'s image is not defined");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
Size(&width, &height);
|
||||
if (!width || !height)
|
||||
if (!width || !height) {
|
||||
AttachmentName(out_info);
|
||||
out_info->AppendLiteral(" has no width or height");
|
||||
return false;
|
||||
|
||||
auto formatUsage = Format();
|
||||
if (!formatUsage->isRenderable)
|
||||
return false;
|
||||
|
||||
auto format = formatUsage->format;
|
||||
|
||||
if (webgl->IsWebGL2()) {
|
||||
if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
|
||||
return format->hasDepth;
|
||||
|
||||
if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
|
||||
return format->hasStencil;
|
||||
|
||||
if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
|
||||
MOZ_CRASH("No DEPTH_STENCIL_ATTACHMENT in WebGL 2.");
|
||||
} else {
|
||||
if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
|
||||
return format->hasDepth && !format->hasStencil;
|
||||
|
||||
if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
|
||||
return !format->hasDepth && format->hasStencil;
|
||||
|
||||
if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
|
||||
return format->hasDepth && format->hasStencil;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0);
|
||||
return format->isColorFormat;
|
||||
const auto formatUsage = Format();
|
||||
if (!formatUsage->isRenderable) {
|
||||
nsAutoCString attachName;
|
||||
AttachmentName(&attachName);
|
||||
|
||||
*out_info = nsPrintfCString("%s has an effective format of %s, which is not"
|
||||
" renderable",
|
||||
attachName.BeginReading(), formatUsage->format->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto format = formatUsage->format;
|
||||
|
||||
bool hasRequiredBits;
|
||||
|
||||
switch (mAttachmentPoint) {
|
||||
case LOCAL_GL_DEPTH_ATTACHMENT:
|
||||
hasRequiredBits = format->hasDepth;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_STENCIL_ATTACHMENT:
|
||||
hasRequiredBits = format->hasStencil;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
|
||||
MOZ_ASSERT(!webgl->IsWebGL2());
|
||||
hasRequiredBits = (format->hasDepth && format->hasStencil);
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0);
|
||||
hasRequiredBits = format->isColorFormat;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hasRequiredBits) {
|
||||
AttachmentName(out_info);
|
||||
out_info->AppendLiteral("'s format is missing required color/depth/stencil bits");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!webgl->IsWebGL2()) {
|
||||
bool hasSurplusPlanes = false;
|
||||
|
||||
switch (mAttachmentPoint) {
|
||||
case LOCAL_GL_DEPTH_ATTACHMENT:
|
||||
hasSurplusPlanes = format->hasStencil;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_STENCIL_ATTACHMENT:
|
||||
hasSurplusPlanes = format->hasDepth;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hasSurplusPlanes) {
|
||||
AttachmentName(out_info);
|
||||
out_info->AppendLiteral("'s format has depth or stencil bits when it"
|
||||
" shouldn't");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -696,13 +763,13 @@ WebGLFramebuffer::HasDefinedAttachments() const
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLFramebuffer::HasIncompleteAttachments() const
|
||||
WebGLFramebuffer::HasIncompleteAttachments(nsCString* const out_info) const
|
||||
{
|
||||
const auto fnIsIncomplete = [this](const WebGLFBAttachPoint& cur) {
|
||||
const auto fnIsIncomplete = [this, out_info](const WebGLFBAttachPoint& cur) {
|
||||
if (!cur.IsDefined())
|
||||
return false; // Not defined, so can't count as incomplete.
|
||||
|
||||
return !cur.IsComplete(this->mContext);
|
||||
return !cur.IsComplete(this->mContext, out_info);
|
||||
};
|
||||
|
||||
bool hasIncomplete = false;
|
||||
@ -745,7 +812,8 @@ bool
|
||||
WebGLFramebuffer::AllImageRectsMatch() const
|
||||
{
|
||||
MOZ_ASSERT(HasDefinedAttachments());
|
||||
MOZ_ASSERT(!HasIncompleteAttachments());
|
||||
DebugOnly<nsCString> fbStatusInfo;
|
||||
MOZ_ASSERT(!HasIncompleteAttachments(&fbStatusInfo));
|
||||
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
@ -764,7 +832,7 @@ WebGLFramebuffer::AllImageRectsMatch() const
|
||||
}
|
||||
|
||||
FBStatus
|
||||
WebGLFramebuffer::PrecheckFramebufferStatus() const
|
||||
WebGLFramebuffer::PrecheckFramebufferStatus(nsCString* const out_info) const
|
||||
{
|
||||
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
|
||||
mContext->mBoundReadFramebuffer == this);
|
||||
@ -772,7 +840,7 @@ WebGLFramebuffer::PrecheckFramebufferStatus() const
|
||||
if (!HasDefinedAttachments())
|
||||
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // No attachments
|
||||
|
||||
if (HasIncompleteAttachments())
|
||||
if (HasIncompleteAttachments(out_info))
|
||||
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
|
||||
|
||||
if (!mContext->IsWebGL2()) {
|
||||
@ -791,12 +859,12 @@ WebGLFramebuffer::PrecheckFramebufferStatus() const
|
||||
}
|
||||
|
||||
FBStatus
|
||||
WebGLFramebuffer::CheckFramebufferStatus() const
|
||||
WebGLFramebuffer::CheckFramebufferStatus(nsCString* const out_info) const
|
||||
{
|
||||
if (mIsKnownFBComplete)
|
||||
return LOCAL_GL_FRAMEBUFFER_COMPLETE;
|
||||
|
||||
FBStatus ret = PrecheckFramebufferStatus();
|
||||
FBStatus ret = PrecheckFramebufferStatus(out_info);
|
||||
if (ret != LOCAL_GL_FRAMEBUFFER_COMPLETE)
|
||||
return ret;
|
||||
|
||||
@ -809,46 +877,35 @@ WebGLFramebuffer::CheckFramebufferStatus() const
|
||||
// TODO: This should not be unconditionally GL_FRAMEBUFFER.
|
||||
ret = mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
|
||||
if (ret == LOCAL_GL_FRAMEBUFFER_COMPLETE)
|
||||
if (ret == LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
mIsKnownFBComplete = true;
|
||||
} else {
|
||||
out_info->AssignLiteral("Bad status according to the driver");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLFramebuffer::HasCompletePlanes(GLbitfield mask)
|
||||
{
|
||||
if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
|
||||
mContext->mBoundReadFramebuffer == this);
|
||||
|
||||
bool hasPlanes = true;
|
||||
if (mask & LOCAL_GL_COLOR_BUFFER_BIT)
|
||||
hasPlanes &= mColorAttachment0.IsDefined();
|
||||
|
||||
if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
|
||||
hasPlanes &= mDepthAttachment.IsDefined() ||
|
||||
mDepthStencilAttachment.IsDefined();
|
||||
}
|
||||
|
||||
if (mask & LOCAL_GL_STENCIL_BUFFER_BIT) {
|
||||
hasPlanes &= mStencilAttachment.IsDefined() ||
|
||||
mDepthStencilAttachment.IsDefined();
|
||||
}
|
||||
|
||||
return hasPlanes;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLFramebuffer::CheckAndInitializeAttachments()
|
||||
WebGLFramebuffer::ValidateAndInitAttachments(const char* funcName)
|
||||
{
|
||||
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
|
||||
mContext->mBoundReadFramebuffer == this);
|
||||
|
||||
if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
|
||||
nsCString fbStatusInfo;
|
||||
const auto fbStatus = CheckFramebufferStatus(&fbStatusInfo);
|
||||
if (fbStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
nsCString errorText = nsPrintfCString("Incomplete framebuffer: Status 0x%04x",
|
||||
fbStatus.get());
|
||||
if (fbStatusInfo.Length()) {
|
||||
errorText += ": ";
|
||||
errorText += fbStatusInfo;
|
||||
}
|
||||
|
||||
mContext->ErrorInvalidFramebufferOperation("%s: %s.", funcName,
|
||||
errorText.BeginReading());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cool! We've checked out ok. Just need to initialize.
|
||||
|
||||
@ -1019,11 +1076,8 @@ WebGLFramebuffer::ValidateForRead(const char* funcName,
|
||||
const webgl::FormatUsageInfo** const out_format,
|
||||
uint32_t* const out_width, uint32_t* const out_height)
|
||||
{
|
||||
if (!CheckAndInitializeAttachments()) {
|
||||
mContext->ErrorInvalidFramebufferOperation("%s: Incomplete framebuffer.",
|
||||
funcName);
|
||||
if (!ValidateAndInitAttachments(funcName))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mReadBufferMode == LOCAL_GL_NONE) {
|
||||
mContext->ErrorInvalidOperation("%s: Read buffer mode must not be"
|
||||
|
@ -92,6 +92,7 @@ public:
|
||||
GLint MipLevel() const {
|
||||
return mTexImageLevel;
|
||||
}
|
||||
void AttachmentName(nsCString* out) const;
|
||||
|
||||
bool HasUninitializedImageData() const;
|
||||
void SetImageDataStatus(WebGLImageDataStatus x);
|
||||
@ -100,7 +101,7 @@ public:
|
||||
//const WebGLRectangleObject& RectangleObject() const;
|
||||
|
||||
bool HasImage() const;
|
||||
bool IsComplete(WebGLContext* webgl) const;
|
||||
bool IsComplete(WebGLContext* webgl, nsCString* const out_info) const;
|
||||
|
||||
void FinalizeAttachment(gl::GLContext* gl, GLenum attachmentLoc) const;
|
||||
|
||||
@ -226,10 +227,10 @@ public:
|
||||
GLint layer);
|
||||
|
||||
bool HasDefinedAttachments() const;
|
||||
bool HasIncompleteAttachments() const;
|
||||
bool HasIncompleteAttachments(nsCString* const out_info) const;
|
||||
bool AllImageRectsMatch() const;
|
||||
FBStatus PrecheckFramebufferStatus() const;
|
||||
FBStatus CheckFramebufferStatus() const;
|
||||
FBStatus PrecheckFramebufferStatus(nsCString* const out_info) const;
|
||||
FBStatus CheckFramebufferStatus(nsCString* const out_info) const;
|
||||
|
||||
const webgl::FormatUsageInfo*
|
||||
GetFormatForAttachment(const WebGLFBAttachPoint& attachment) const;
|
||||
@ -271,10 +272,7 @@ public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
|
||||
|
||||
// mask mirrors glClear.
|
||||
bool HasCompletePlanes(GLbitfield mask);
|
||||
|
||||
bool CheckAndInitializeAttachments();
|
||||
bool ValidateAndInitAttachments(const char* funcName);
|
||||
|
||||
void InvalidateFramebufferStatus() const {
|
||||
mIsKnownFBComplete = false;
|
||||
|
@ -40,6 +40,9 @@ WebGLQuery::Delete()
|
||||
bool
|
||||
WebGLQuery::IsActive() const
|
||||
{
|
||||
if (!HasEverBeenActive())
|
||||
return false;
|
||||
|
||||
WebGLRefPtr<WebGLQuery>& targetSlot = mContext->GetQuerySlotByTarget(mType);
|
||||
|
||||
return targetSlot.get() == this;
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
|
||||
bool IsActive() const;
|
||||
|
||||
bool HasEverBeenActive() {
|
||||
bool HasEverBeenActive() const {
|
||||
return mType != 0;
|
||||
}
|
||||
|
||||
|
@ -164,9 +164,11 @@ WebGLTexture::MemoryUsage() const
|
||||
if (IsDeleted())
|
||||
return 0;
|
||||
|
||||
size_t result = 0;
|
||||
MOZ_CRASH("todo");
|
||||
return result;
|
||||
size_t accum = 0;
|
||||
for (const auto& cur : mImageInfoArr) {
|
||||
accum += cur.MemoryUsage();
|
||||
}
|
||||
return accum;
|
||||
}
|
||||
|
||||
void
|
||||
@ -588,8 +590,8 @@ WebGLTexture::InitializeImageData(const char* funcName, TexImageTarget target,
|
||||
const auto& height = imageInfo.mHeight;
|
||||
const auto& depth = imageInfo.mDepth;
|
||||
|
||||
if (!ZeroTextureData(mContext, funcName, respecifyTexture, target, level, usage, 0, 0,
|
||||
0, width, height, depth))
|
||||
if (!ZeroTextureData(mContext, funcName, respecifyTexture, mGLName, target, level,
|
||||
usage, 0, 0, 0, width, height, depth))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1778,7 +1778,7 @@ WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internal
|
||||
|
||||
const bool respecifyTexture = true;
|
||||
const uint8_t zOffset = 0;
|
||||
if (!ZeroTextureData(mContext, funcName, respecifyTexture, target, level,
|
||||
if (!ZeroTextureData(mContext, funcName, respecifyTexture, mGLName, target, level,
|
||||
dstUsage, 0, 0, zOffset, width, height, depth))
|
||||
{
|
||||
mContext->ErrorOutOfMemory("%s: Failed to zero texture data.", funcName);
|
||||
@ -1788,7 +1788,7 @@ WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internal
|
||||
|
||||
if (!rwWidth || !rwHeight) {
|
||||
// There aren't any, so we're 'done'.
|
||||
mContext->DummyFramebufferOperation(funcName);
|
||||
mContext->DummyReadFramebufferOperation(funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1879,7 +1879,7 @@ WebGLTexture::CopyTexSubImage(const char* funcName, TexImageTarget target, GLint
|
||||
|
||||
if (!rwWidth || !rwHeight) {
|
||||
// There aren't any, so we're 'done'.
|
||||
mContext->DummyFramebufferOperation(funcName);
|
||||
mContext->DummyReadFramebufferOperation(funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1148,9 +1148,11 @@ HTMLSelectElement::SetValue(const nsAString& aValue)
|
||||
option->GetValue(optionVal);
|
||||
if (optionVal.Equals(aValue)) {
|
||||
SetSelectedIndexInternal(int32_t(i), true);
|
||||
break;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// No matching option was found.
|
||||
SetSelectedIndexInternal(-1, true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -563,18 +563,12 @@ nsBrowserElement::GetAllowedAudioChannels(
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIApplication> parentApp;
|
||||
aRv = GetParentApplication(getter_AddRefs(parentApp));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
||||
("nsBrowserElement, GetAllowedAudioChannels, this = %p\n", this));
|
||||
|
||||
GenerateAllowedAudioChannels(window, frameLoader, mBrowserElementAPI,
|
||||
manifestURL, parentApp,
|
||||
mBrowserElementAudioChannels, aRv);
|
||||
manifestURL, mBrowserElementAudioChannels,
|
||||
aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
@ -589,7 +583,6 @@ nsBrowserElement::GenerateAllowedAudioChannels(
|
||||
nsIFrameLoader* aFrameLoader,
|
||||
nsIBrowserElementAPI* aAPI,
|
||||
const nsAString& aManifestURL,
|
||||
mozIApplication* aParentApp,
|
||||
nsTArray<RefPtr<BrowserElementAudioChannel>>& aAudioChannels,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
@ -632,19 +625,6 @@ nsBrowserElement::GenerateAllowedAudioChannels(
|
||||
permissionName.AssignASCII("audio-channel-");
|
||||
permissionName.AppendASCII(audioChannelTable[i].tag);
|
||||
|
||||
// In case of nested iframes we want to check if the parent has the
|
||||
// permission to use this AudioChannel.
|
||||
if (aParentApp) {
|
||||
aRv = aParentApp->HasPermission(permissionName.get(), &allowed);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!allowed) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
aRv = app->HasPermission(permissionName.get(), &allowed);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
|
@ -125,14 +125,11 @@ public:
|
||||
nsIFrameLoader* aFrameLoader,
|
||||
nsIBrowserElementAPI* aAPI,
|
||||
const nsAString& aManifestURL,
|
||||
mozIApplication* aParentApp,
|
||||
nsTArray<RefPtr<dom::BrowserElementAudioChannel>>& aAudioChannels,
|
||||
ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
NS_IMETHOD_(already_AddRefed<nsFrameLoader>) GetFrameLoader() = 0;
|
||||
NS_IMETHOD GetParentApplication(mozIApplication** aApplication) = 0;
|
||||
|
||||
void InitBrowserElementAPI();
|
||||
nsCOMPtr<nsIBrowserElementAPI> mBrowserElementAPI;
|
||||
nsTArray<RefPtr<dom::BrowserElementAudioChannel>> mBrowserElementAudioChannels;
|
||||
|
@ -191,35 +191,6 @@ nsGenericHTMLFrameElement::GetFrameLoader()
|
||||
return loader.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericHTMLFrameElement::GetParentApplication(mozIApplication** aApplication)
|
||||
{
|
||||
if (!aApplication) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aApplication = nullptr;
|
||||
|
||||
uint32_t appId;
|
||||
nsIPrincipal *principal = NodePrincipal();
|
||||
nsresult rv = principal->GetAppId(&appId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
|
||||
if (NS_WARN_IF(!appsService)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = appsService->GetAppByLocalId(appId, aApplication);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericHTMLFrameElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
|
||||
{
|
||||
|
@ -598,4 +598,5 @@ skip-if = buildapp == 'b2g' # bug 1129014
|
||||
[test_viewport_resize.html]
|
||||
[test_extapp.html]
|
||||
[test_image_clone_load.html]
|
||||
[test_bug1203668.html]
|
||||
[test_bug1166138.html]
|
||||
|
62
dom/html/test/test_bug1203668.html
Normal file
62
dom/html/test/test_bug1203668.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1203668
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1203668</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1203668">Mozilla Bug 1203668</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<select class="select" multiple>
|
||||
<option value="foo" selected>foo</option>
|
||||
<option value="bar" selected>bar</option>
|
||||
</select>
|
||||
<select class="select" multiple>
|
||||
<option value="foo">foo</option>
|
||||
<option value="bar" selected>bar</option>
|
||||
</select>
|
||||
<select class="select" multiple>
|
||||
<option value="foo">foo</option>
|
||||
<option value="bar">bar</option>
|
||||
</select>
|
||||
<select class="select" size=1>
|
||||
<option value="foo">foo</option>
|
||||
<option value="bar" selected>bar</option>
|
||||
</select>
|
||||
<select class="select" size=1>
|
||||
<option value="foo">foo</option>
|
||||
<option value="bar">bar</option>
|
||||
</select>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1203668 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTest()
|
||||
{
|
||||
var selects = document.querySelectorAll('.select');
|
||||
for (i=0; i < selects.length; i++) {
|
||||
var select = selects[i];
|
||||
select.value = "bogus"
|
||||
is(select.selectedIndex, -1, "no option is selected");
|
||||
is(select.children[0].selected, false, "first option is not selected");
|
||||
is(select.children[1].selected, false, "second option is not selected");
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(runTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -157,8 +157,7 @@ private:
|
||||
SetLazyData(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aLastModifiedDate,
|
||||
BlobDirState aDirState) override
|
||||
int64_t aLastModifiedDate) override
|
||||
{
|
||||
MOZ_CRASH("This should never be called!");
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "domstubs.idl"
|
||||
|
||||
[builtinclass, scriptable, uuid(8e49f7b0-1f98-4939-bf91-e9c39cd56434)]
|
||||
[scriptable, uuid(7615408c-1fb3-4128-8dd5-a3e2f3fa8842)]
|
||||
interface nsITabParent : nsISupports
|
||||
{
|
||||
void injectTouchEvent(in AString aType,
|
||||
|
@ -2039,8 +2039,7 @@ public:
|
||||
SetLazyData(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aLastModifiedDate,
|
||||
BlobDirState aDirState) override;
|
||||
int64_t aLastModifiedDate) override;
|
||||
|
||||
virtual bool
|
||||
IsMemoryFile() const override;
|
||||
@ -2782,8 +2781,7 @@ BlobParent::
|
||||
RemoteBlobImpl::SetLazyData(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aLastModifiedDate,
|
||||
BlobDirState aDirState)
|
||||
int64_t aLastModifiedDate)
|
||||
{
|
||||
MOZ_CRASH("This should never be called!");
|
||||
}
|
||||
@ -3487,8 +3485,7 @@ BlobChild::SetMysteryBlobInfo(const nsString& aName,
|
||||
MOZ_ASSERT(mRemoteBlobImpl);
|
||||
MOZ_ASSERT(aLastModifiedDate != INT64_MAX);
|
||||
|
||||
mBlobImpl->SetLazyData(aName, aContentType, aLength, aLastModifiedDate,
|
||||
aDirState);
|
||||
mBlobImpl->SetLazyData(aName, aContentType, aLength, aLastModifiedDate);
|
||||
|
||||
FileBlobConstructorParams params(aName,
|
||||
aContentType,
|
||||
@ -3509,8 +3506,7 @@ BlobChild::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength)
|
||||
nsString voidString;
|
||||
voidString.SetIsVoid(true);
|
||||
|
||||
mBlobImpl->SetLazyData(voidString, aContentType, aLength, INT64_MAX,
|
||||
BlobDirState::eUnknownIfDir);
|
||||
mBlobImpl->SetLazyData(voidString, aContentType, aLength, INT64_MAX);
|
||||
|
||||
NormalBlobConstructorParams params(aContentType,
|
||||
aLength,
|
||||
@ -4336,8 +4332,7 @@ BlobParent::RecvResolveMystery(const ResolveMysteryParams& aParams)
|
||||
mBlobImpl->SetLazyData(voidString,
|
||||
params.contentType(),
|
||||
params.length(),
|
||||
INT64_MAX,
|
||||
BlobDirState::eUnknownIfDir);
|
||||
INT64_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -4362,8 +4357,7 @@ BlobParent::RecvResolveMystery(const ResolveMysteryParams& aParams)
|
||||
mBlobImpl->SetLazyData(params.name(),
|
||||
params.contentType(),
|
||||
params.length(),
|
||||
params.modDate(),
|
||||
BlobDirState(params.dirState()));
|
||||
params.modDate());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -760,13 +760,6 @@ child:
|
||||
*/
|
||||
HandleAccessKey(uint32_t[] charCodes, bool isTrusted, int32_t modifierMask);
|
||||
|
||||
/**
|
||||
* Propagate a refresh to the child process
|
||||
*/
|
||||
AudioChannelChangeNotification(uint32_t aAudioChannel,
|
||||
float aVolume,
|
||||
bool aMuted);
|
||||
|
||||
/*
|
||||
* FIXME: write protocol!
|
||||
|
||||
|
@ -2254,27 +2254,6 @@ TabChild::RecvHandleAccessKey(nsTArray<uint32_t>&& aCharCodes,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvAudioChannelChangeNotification(const uint32_t& aAudioChannel,
|
||||
const float& aVolume,
|
||||
const bool& aMuted)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(WebNavigation());
|
||||
if (window) {
|
||||
RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
|
||||
MOZ_ASSERT(service);
|
||||
|
||||
service->SetAudioChannelVolume(window,
|
||||
static_cast<AudioChannel>(aAudioChannel),
|
||||
aVolume);
|
||||
service->SetAudioChannelMuted(window,
|
||||
static_cast<AudioChannel>(aAudioChannel),
|
||||
aMuted);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvDestroy()
|
||||
{
|
||||
|
@ -504,10 +504,6 @@ public:
|
||||
const bool& aIsTrusted,
|
||||
const int32_t& aModifierMask) override;
|
||||
|
||||
virtual bool RecvAudioChannelChangeNotification(const uint32_t& aAudioChannel,
|
||||
const float& aVolume,
|
||||
const bool& aMuted) override;
|
||||
|
||||
/**
|
||||
* Native widget remoting protocol for use with windowed plugins with e10s.
|
||||
*/
|
||||
|
@ -184,7 +184,7 @@ private:
|
||||
// Our TabParent may have been destroyed already. If so, don't send any
|
||||
// fds over, just go back to the IO thread and close them.
|
||||
if (!tabParent->IsDestroyed()) {
|
||||
Unused << tabParent->SendCacheFileDescriptor(mPath, fd);
|
||||
mozilla::Unused << tabParent->SendCacheFileDescriptor(mPath, fd);
|
||||
}
|
||||
|
||||
if (!mFD) {
|
||||
@ -232,7 +232,7 @@ private:
|
||||
// Intentionally leak the runnable (but not the fd) rather
|
||||
// than crash when trying to release a main thread object
|
||||
// off the main thread.
|
||||
Unused << mTabParent.forget();
|
||||
mozilla::Unused << mTabParent.forget();
|
||||
CloseFile();
|
||||
}
|
||||
}
|
||||
@ -387,11 +387,6 @@ TabParent::AddWindowListeners()
|
||||
mPresShellWithRefreshListener = shell;
|
||||
shell->AddPostRefreshObserver(this);
|
||||
}
|
||||
|
||||
RefPtr<AudioChannelService> acs = AudioChannelService::GetOrCreate();
|
||||
if (acs) {
|
||||
acs->RegisterTabParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -410,11 +405,6 @@ TabParent::RemoveWindowListeners()
|
||||
mPresShellWithRefreshListener->RemovePostRefreshObserver(this);
|
||||
mPresShellWithRefreshListener = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<AudioChannelService> acs = AudioChannelService::GetOrCreate();
|
||||
if (acs) {
|
||||
acs->UnregisterTabParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -2646,6 +2636,7 @@ TabParent::RecvAudioChannelActivityNotification(const uint32_t& aAudioChannel,
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os) {
|
||||
RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
|
||||
nsAutoCString topic;
|
||||
topic.Assign("audiochannel-activity-");
|
||||
topic.Append(AudioChannelService::GetAudioChannelTable()[aAudioChannel].tag);
|
||||
@ -3406,33 +3397,6 @@ TabParent::GetShowInfo()
|
||||
mDPI, mDefaultScale.scale);
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::AudioChannelChangeNotification(nsPIDOMWindow* aWindow,
|
||||
AudioChannel aAudioChannel,
|
||||
float aVolume,
|
||||
bool aMuted)
|
||||
{
|
||||
if (!mFrameElement || !mFrameElement->OwnerDoc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = mFrameElement->OwnerDoc()->GetWindow();
|
||||
while (window) {
|
||||
if (window == aWindow) {
|
||||
Unused << SendAudioChannelChangeNotification(static_cast<uint32_t>(aAudioChannel),
|
||||
aVolume, aMuted);
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> win = window->GetScriptableParent();
|
||||
if (window == win) {
|
||||
break;
|
||||
}
|
||||
|
||||
window = win;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeChannel::OnAuthAvailable(nsISupports *aContext, nsIAuthInformation *aAuthInfo)
|
||||
{
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/ContentCache.h"
|
||||
#include "mozilla/dom/AudioChannelBinding.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/dom/PBrowserParent.h"
|
||||
#include "mozilla/dom/PContent.h"
|
||||
@ -456,11 +455,6 @@ public:
|
||||
void OnStartSignedPackageRequest(nsIChannel* aChannel,
|
||||
const nsACString& aPackageId);
|
||||
|
||||
void AudioChannelChangeNotification(nsPIDOMWindow* aWindow,
|
||||
AudioChannel aAudioChannel,
|
||||
float aVolume,
|
||||
bool aMuted);
|
||||
|
||||
protected:
|
||||
bool ReceiveMessage(const nsString& aMessage,
|
||||
bool aSync,
|
||||
|
@ -9,3 +9,4 @@ ImageMapPolyWrongNumberOfCoords=The "coords" attribute of the <area shape="poly"
|
||||
ImageMapPolyOddNumberOfCoords=The "coords" attribute of the <area shape="poly"> tag is missing the last "y" coordinate (the correct format is "x1,y1,x2,y2 …").
|
||||
|
||||
TablePartRelPosWarning=Relative positioning of table rows and row groups is now supported. This site may need to be updated because it may depend on this feature having no effect.
|
||||
ScrollLinkedEffectFound=This site appears to use a scroll-linked positioning effect. This may not work well with asynchronous panning; see https://developers.mozilla.org/docs/Mozilla/Performance/ScrollLinkedEffects for further details and to join the discussion on related tools and features!
|
||||
|
@ -2174,7 +2174,6 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
RefPtr<ShutdownPromise>
|
||||
MediaDecoderStateMachine::BeginShutdown()
|
||||
{
|
||||
mStreamSink->BeginShutdown();
|
||||
return InvokeAsync(OwnerThread(), this, __func__,
|
||||
&MediaDecoderStateMachine::Shutdown);
|
||||
}
|
||||
|
@ -1,573 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/GMPVideoDecoderTrialCreator.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "prsystem.h"
|
||||
#include "GMPVideoHost.h"
|
||||
#include "mozilla/EMEUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "GMPService.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static already_AddRefed<nsIThread>
|
||||
GetGMPThread()
|
||||
{
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> gmps =
|
||||
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
if (!gmps) {
|
||||
return nullptr;
|
||||
}
|
||||
nsCOMPtr<nsIThread> gmpThread;
|
||||
nsresult rv = gmps->GetThread(getter_AddRefs(gmpThread));
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
return gmpThread.forget();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool
|
||||
OnGMPThread()
|
||||
{
|
||||
nsCOMPtr<nsIThread> currentThread;
|
||||
NS_GetCurrentThread(getter_AddRefs(currentThread));
|
||||
nsCOMPtr<nsIThread> gmpThread(GetGMPThread());
|
||||
return !!gmpThread && !!currentThread && gmpThread == currentThread;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char*
|
||||
TrialCreatePrefName(const nsAString& aKeySystem)
|
||||
{
|
||||
if (aKeySystem.EqualsLiteral("com.adobe.primetime")) {
|
||||
return "media.gmp-eme-adobe.trial-create";
|
||||
}
|
||||
if (aKeySystem.EqualsLiteral("org.w3.clearkey")) {
|
||||
return "media.gmp-eme-clearkey.trial-create";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */
|
||||
GMPVideoDecoderTrialCreator::TrialCreateState
|
||||
GMPVideoDecoderTrialCreator::GetCreateTrialState(const nsAString& aKeySystem)
|
||||
{
|
||||
if (Preferences::GetBool("media.gmp.always-trial-create", false)) {
|
||||
return Pending;
|
||||
}
|
||||
|
||||
const char* pref = TrialCreatePrefName(aKeySystem);
|
||||
if (!pref) {
|
||||
return Pending;
|
||||
}
|
||||
switch (Preferences::GetInt(pref, (int)Pending)) {
|
||||
case 0: return Pending;
|
||||
case 1: return Succeeded;
|
||||
case 2: return Failed;
|
||||
default: return Pending;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
GMPVideoDecoderTrialCreator::UpdateTrialCreateState(const nsAString& aKeySystem,
|
||||
uint32_t aState)
|
||||
{
|
||||
UpdateTrialCreateState(aKeySystem, (TrialCreateState)aState);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
GMPVideoDecoderTrialCreator::UpdateTrialCreateState(const nsAString& aKeySystem,
|
||||
TrialCreateState aState)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
// Pref has to be set from the chrome process. Dispatch to chrome via
|
||||
// GMPService.
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> service =
|
||||
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
NS_ENSURE_TRUE_VOID(service);
|
||||
|
||||
service->UpdateTrialCreateState(aKeySystem, (uint32_t)aState);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* pref = TrialCreatePrefName(aKeySystem);
|
||||
if (pref) {
|
||||
Preferences::SetInt(pref, (int)aState);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderFailed(const nsAString& aKeySystem,
|
||||
const nsACString& aReason)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
EME_LOG("GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderFailed(%s)",
|
||||
NS_ConvertUTF16toUTF8(aKeySystem).get());
|
||||
|
||||
TrialCreateData* data = mTestCreate.Get(aKeySystem);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
data->mStatus = Failed;
|
||||
UpdateTrialCreateState(aKeySystem, Failed);
|
||||
|
||||
for (RefPtr<AbstractPromiseLike>& promise: data->mPending) {
|
||||
promise->Reject(NS_ERROR_DOM_NOT_SUPPORTED_ERR, aReason);
|
||||
}
|
||||
data->mPending.Clear();
|
||||
data->mTest = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderSucceeded(const nsAString& aKeySystem)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
EME_LOG("GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderSucceeded(%s)",
|
||||
NS_ConvertUTF16toUTF8(aKeySystem).get());
|
||||
|
||||
TrialCreateData* data = mTestCreate.Get(aKeySystem);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
data->mStatus = Succeeded;
|
||||
UpdateTrialCreateState(aKeySystem, Succeeded);
|
||||
|
||||
for (RefPtr<AbstractPromiseLike>& promise : data->mPending) {
|
||||
promise->Resolve();
|
||||
}
|
||||
data->mPending.Clear();
|
||||
data->mTest = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestGMPVideoDecoder::Start()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mGMPService = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
if (!mGMPService) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> thread(GetGMPThread());
|
||||
if (!thread) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
RefPtr<nsIRunnable> task(NS_NewRunnableMethod(this, &TestGMPVideoDecoder::CreateGMPVideoDecoder));
|
||||
return thread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
struct ExpectedPlaneDecodePlane {
|
||||
GMPPlaneType mPlane;
|
||||
size_t mLength;
|
||||
uint8_t mValue;
|
||||
int32_t mSize; // width & height
|
||||
};
|
||||
|
||||
static const ExpectedPlaneDecodePlane sExpectedPlanes[3] = {
|
||||
{
|
||||
kGMPYPlane,
|
||||
112 * 112, // 12544
|
||||
0x4c,
|
||||
112
|
||||
},
|
||||
{ // U
|
||||
kGMPUPlane,
|
||||
56 * 56, // 3136
|
||||
0x55,
|
||||
56,
|
||||
},
|
||||
{ // V
|
||||
kGMPVPlane,
|
||||
56 * 56, // 3136
|
||||
0xff,
|
||||
56,
|
||||
}
|
||||
};
|
||||
|
||||
static bool TestDecodedFrame(GMPVideoi420Frame* aDecodedFrame)
|
||||
{
|
||||
MOZ_ASSERT(OnGMPThread());
|
||||
|
||||
if (aDecodedFrame->Width() != 112 || aDecodedFrame->Height() != 112) {
|
||||
EME_LOG("TestDecodedFrame() - Invalid decoded frame dimensions");
|
||||
return false;
|
||||
}
|
||||
for (const ExpectedPlaneDecodePlane& plane : sExpectedPlanes) {
|
||||
int32_t stride = aDecodedFrame->Stride(plane.mPlane);
|
||||
if (stride < plane.mSize) {
|
||||
EME_LOG("TestDecodedFrame() - Insufficient decoded frame stride");
|
||||
return false;
|
||||
}
|
||||
int32_t length = plane.mSize * plane.mSize;
|
||||
if (aDecodedFrame->AllocatedSize(plane.mPlane) < length) {
|
||||
EME_LOG("TestDecodedFrame() - Insufficient decoded frame allocated size");
|
||||
return false;
|
||||
}
|
||||
const uint8_t* data = aDecodedFrame->Buffer(plane.mPlane);
|
||||
for (int32_t row = 0; row < plane.mSize; row++) {
|
||||
for (int32_t i = 0; i < plane.mSize; i++) {
|
||||
size_t off = (stride * row) + i;
|
||||
if (data[off] != plane.mValue) {
|
||||
EME_LOG("TestDecodedFrame() - Invalid decoded frame contents");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TestGMPVideoDecoder::Decoded(GMPVideoi420Frame* aDecodedFrame)
|
||||
{
|
||||
MOZ_ASSERT(OnGMPThread());
|
||||
|
||||
if (!mReceivedDecoded) {
|
||||
mReceivedDecoded = true;
|
||||
} else {
|
||||
EME_LOG("Received multiple decoded frames");
|
||||
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder received multiple decoded frames"));
|
||||
return;
|
||||
}
|
||||
|
||||
GMPUniquePtr<GMPVideoi420Frame> decodedFrame(aDecodedFrame);
|
||||
if (!TestDecodedFrame(aDecodedFrame)) {
|
||||
EME_LOG("decoded frame failed verification");
|
||||
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder decoded frame failed verification"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TestGMPVideoDecoder::DrainComplete()
|
||||
{
|
||||
EME_LOG("TestGMPVideoDecoder::DrainComplete()");
|
||||
MOZ_ASSERT(OnGMPThread());
|
||||
ReportSuccess();
|
||||
}
|
||||
|
||||
void
|
||||
TestGMPVideoDecoder::Error(GMPErr aErr)
|
||||
{
|
||||
EME_LOG("TestGMPVideoDecoder::ReceivedDecodedFrame()");
|
||||
MOZ_ASSERT(OnGMPThread());
|
||||
ReportFailure(nsPrintfCString("TestGMPVideoDecoder error %d", aErr));
|
||||
}
|
||||
|
||||
void
|
||||
TestGMPVideoDecoder::Terminated()
|
||||
{
|
||||
EME_LOG("TestGMPVideoDecoder::Terminated()");
|
||||
MOZ_ASSERT(OnGMPThread());
|
||||
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder GMP terminated"));
|
||||
}
|
||||
|
||||
void
|
||||
TestGMPVideoDecoder::ReportFailure(const nsACString& aReason)
|
||||
{
|
||||
MOZ_ASSERT(OnGMPThread());
|
||||
|
||||
if (mGMP) {
|
||||
mGMP->Close();
|
||||
mGMP = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArgs<nsString, nsCString>(mInstance,
|
||||
&GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderFailed,
|
||||
mKeySystem,
|
||||
aReason);
|
||||
NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
TestGMPVideoDecoder::ReportSuccess()
|
||||
{
|
||||
MOZ_ASSERT(OnGMPThread());
|
||||
|
||||
if (mGMP) {
|
||||
mGMP->Close();
|
||||
mGMP = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArg<nsString>(mInstance,
|
||||
&GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderSucceeded,
|
||||
mKeySystem);
|
||||
NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
// A solid red, 112x112 frame. Display size 100x100 pixels.
|
||||
// Generated with ImageMagick/ffmpeg
|
||||
// $ convert -size 100x100 xc:rgb\(255, 0, 0\) red.png
|
||||
// $ ffmpeg -f image2 -i red.png -r 24 -b:v 200k -c:v libx264 -profile:v baseline -level 1 -v:r 24 red.mp4 -y
|
||||
static const uint8_t sTestH264Frame[] = {
|
||||
0x00, 0x00, 0x02, 0x81, 0x06, 0x05, 0xff, 0xff, 0x7d, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9,
|
||||
0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20,
|
||||
0x2d, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x31, 0x33, 0x35, 0x20, 0x72, 0x32, 0x33, 0x34,
|
||||
0x35, 0x20, 0x66, 0x30, 0x63, 0x31, 0x63, 0x35, 0x33, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32,
|
||||
0x36, 0x34, 0x2f, 0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63,
|
||||
0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74,
|
||||
0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30, 0x31, 0x33, 0x20, 0x2d, 0x20, 0x68, 0x74,
|
||||
0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c,
|
||||
0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d,
|
||||
0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61,
|
||||
0x62, 0x61, 0x63, 0x3d, 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x33, 0x20, 0x64, 0x65, 0x62,
|
||||
0x6c, 0x6f, 0x63, 0x6b, 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c,
|
||||
0x79, 0x73, 0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d,
|
||||
0x65, 0x3d, 0x68, 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70,
|
||||
0x73, 0x79, 0x3d, 0x31, 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30,
|
||||
0x30, 0x3a, 0x30, 0x2e, 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65,
|
||||
0x66, 0x3d, 0x31, 0x20, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36,
|
||||
0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72,
|
||||
0x65, 0x6c, 0x6c, 0x69, 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d,
|
||||
0x30, 0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e,
|
||||
0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73,
|
||||
0x6b, 0x69, 0x70, 0x3d, 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70,
|
||||
0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65,
|
||||
0x61, 0x64, 0x73, 0x3d, 0x31, 0x32, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61,
|
||||
0x64, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x31, 0x20, 0x73, 0x6c, 0x69,
|
||||
0x63, 0x65, 0x64, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e,
|
||||
0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20,
|
||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c,
|
||||
0x75, 0x72, 0x61, 0x79, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63,
|
||||
0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72,
|
||||
0x61, 0x3d, 0x30, 0x20, 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77,
|
||||
0x65, 0x69, 0x67, 0x68, 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74,
|
||||
0x3d, 0x32, 0x35, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e,
|
||||
0x3d, 0x32, 0x34, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63, 0x75, 0x74, 0x3d, 0x34, 0x30,
|
||||
0x20, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x3d,
|
||||
0x30, 0x20, 0x72, 0x63, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x3d,
|
||||
0x34, 0x30, 0x20, 0x72, 0x63, 0x3d, 0x61, 0x62, 0x72, 0x20, 0x6d, 0x62, 0x74, 0x72, 0x65,
|
||||
0x65, 0x3d, 0x31, 0x20, 0x62, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x32, 0x30, 0x30,
|
||||
0x20, 0x72, 0x61, 0x74, 0x65, 0x74, 0x6f, 0x6c, 0x3d, 0x31, 0x2e, 0x30, 0x20, 0x71, 0x63,
|
||||
0x6f, 0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69, 0x6e, 0x3d,
|
||||
0x30, 0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x36, 0x39, 0x20, 0x71, 0x70, 0x73, 0x74,
|
||||
0x65, 0x70, 0x3d, 0x34, 0x20, 0x69, 0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31,
|
||||
0x2e, 0x34, 0x30, 0x20, 0x61, 0x71, 0x3d, 0x31, 0x3a, 0x31, 0x2e, 0x30, 0x30, 0x00, 0x80,
|
||||
0x00, 0x00, 0x00, 0x39, 0x65, 0x88, 0x84, 0x0c, 0xf1, 0x18, 0xa0, 0x00, 0x23, 0xbf, 0x1c,
|
||||
0x00, 0x04, 0x3c, 0x63, 0x80, 0x00, 0x98, 0x44, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x75,
|
||||
0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75,
|
||||
0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75,
|
||||
0xe0
|
||||
};
|
||||
|
||||
static GMPUniquePtr<GMPVideoEncodedFrame>
|
||||
CreateFrame(GMPVideoHost* aHost)
|
||||
{
|
||||
MOZ_ASSERT(OnGMPThread());
|
||||
|
||||
GMPVideoFrame* ftmp = nullptr;
|
||||
GMPErr err = aHost->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
|
||||
if (GMP_FAILED(err)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GMPUniquePtr<GMPVideoEncodedFrame> frame(static_cast<GMPVideoEncodedFrame*>(ftmp));
|
||||
err = frame->CreateEmptyFrame(MOZ_ARRAY_LENGTH(sTestH264Frame));
|
||||
if (GMP_FAILED(err)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memcpy(frame->Buffer(), sTestH264Frame, MOZ_ARRAY_LENGTH(sTestH264Frame));
|
||||
frame->SetBufferType(GMP_BufferLength32);
|
||||
|
||||
frame->SetEncodedWidth(100);
|
||||
frame->SetEncodedHeight(100);
|
||||
frame->SetTimeStamp(0);
|
||||
frame->SetCompleteFrame(true);
|
||||
frame->SetDuration(41666);
|
||||
frame->SetFrameType(kGMPKeyFrame);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
static const uint8_t sTestH264CodecSpecific[] = {
|
||||
0x01, 0x42, 0xc0, 0x0a, 0xff, 0xe1, 0x00, 0x18, 0x67, 0x42, 0xc0, 0x0a, 0xd9, 0x07, 0x3f,
|
||||
0x9e, 0x79, 0xb2, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x60, 0x1e, 0x24,
|
||||
0x4c, 0x90, 0x01, 0x00, 0x04, 0x68, 0xcb, 0x8c, 0xb2
|
||||
};
|
||||
|
||||
void
|
||||
TestGMPVideoDecoder::Callback::Done(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost)
|
||||
{
|
||||
MOZ_ASSERT(OnGMPThread());
|
||||
|
||||
if (!aHost || !aGMP) {
|
||||
mInstance->ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder null host or GMP on Get"));
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArgs<GMPVideoDecoderProxy*, GMPVideoHost*>(mInstance,
|
||||
&TestGMPVideoDecoder::ActorCreated,
|
||||
aGMP, aHost);
|
||||
NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
TestGMPVideoDecoder::ActorCreated(GMPVideoDecoderProxy* aGMP,
|
||||
GMPVideoHost* aHost)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aHost && aGMP);
|
||||
|
||||
// Add crash handler.
|
||||
RefPtr<gmp::GeckoMediaPluginService> service =
|
||||
gmp::GeckoMediaPluginService::GetGeckoMediaPluginService();
|
||||
service->AddPluginCrashedEventTarget(aGMP->GetPluginId(), mWindow);
|
||||
|
||||
nsCOMPtr<nsIThread> thread(GetGMPThread());
|
||||
if (!thread) {
|
||||
mInstance->TrialCreateGMPVideoDecoderFailed(mKeySystem,
|
||||
NS_LITERAL_CSTRING("Failed to get GMP thread in TestGMPVideoDecoder::ActorCreated"));
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArgs<GMPVideoDecoderProxy*, GMPVideoHost*>(this,
|
||||
&TestGMPVideoDecoder::InitGMPDone,
|
||||
aGMP, aHost);
|
||||
thread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
TestGMPVideoDecoder::InitGMPDone(GMPVideoDecoderProxy* aGMP,
|
||||
GMPVideoHost* aHost)
|
||||
{
|
||||
MOZ_ASSERT(OnGMPThread());
|
||||
MOZ_ASSERT(aHost && aGMP);
|
||||
|
||||
mGMP = aGMP;
|
||||
mHost = aHost;
|
||||
|
||||
GMPVideoCodec codec;
|
||||
memset(&codec, 0, sizeof(codec));
|
||||
|
||||
codec.mGMPApiVersion = kGMPVersion33;
|
||||
|
||||
codec.mCodecType = kGMPVideoCodecH264;
|
||||
codec.mWidth = 100;
|
||||
codec.mHeight = 100;
|
||||
|
||||
nsTArray<uint8_t> codecSpecific;
|
||||
codecSpecific.AppendElement(0); // mPacketizationMode.
|
||||
codecSpecific.AppendElements(sTestH264CodecSpecific,
|
||||
MOZ_ARRAY_LENGTH(sTestH264CodecSpecific));
|
||||
|
||||
nsresult rv = mGMP->InitDecode(codec,
|
||||
codecSpecific,
|
||||
this,
|
||||
PR_GetNumberOfProcessors());
|
||||
if (NS_FAILED(rv)) {
|
||||
EME_LOG("InitGMPDone() - InitDecode() failed!");
|
||||
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder InitDecode() returned failure"));
|
||||
return;
|
||||
}
|
||||
|
||||
GMPUniquePtr<GMPVideoEncodedFrame> frame = CreateFrame(aHost);
|
||||
if (!frame) {
|
||||
EME_LOG("InitGMPDone() - Decode() failed to create frame!");
|
||||
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder Decode() failed to create frame"));
|
||||
return;
|
||||
}
|
||||
nsTArray<uint8_t> info; // No codec specific per-frame info to pass.
|
||||
rv = mGMP->Decode(Move(frame), false, info, 0);
|
||||
if (NS_FAILED(rv)) {
|
||||
EME_LOG("InitGMPDone() - Decode() failed to send Decode message!");
|
||||
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder Decode() returned failure"));
|
||||
return;
|
||||
}
|
||||
|
||||
rv = mGMP->Drain();
|
||||
if (NS_FAILED(rv)) {
|
||||
EME_LOG("InitGMPDone() - Drain() failed to send Drain message!");
|
||||
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder Drain() returned failure"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TestGMPVideoDecoder::CreateGMPVideoDecoder()
|
||||
{
|
||||
MOZ_ASSERT(OnGMPThread());
|
||||
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem));
|
||||
|
||||
UniquePtr<GetGMPVideoDecoderCallback> callback(new Callback(this));
|
||||
if (NS_FAILED(mGMPService->GetGMPVideoDecoder(&tags,
|
||||
NS_LITERAL_CSTRING("fakeNodeId1234567890fakeNodeId12"),
|
||||
Move(callback)))) {
|
||||
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder GMPService GetGMPVideoDecoder returned failure"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GMPVideoDecoderTrialCreator::MaybeAwaitTrialCreate(const nsAString& aKeySystem,
|
||||
AbstractPromiseLike* aPromisey,
|
||||
nsPIDOMWindow* aParent)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mTestCreate.Contains(aKeySystem)) {
|
||||
mTestCreate.Put(aKeySystem, new TrialCreateData(aKeySystem));
|
||||
}
|
||||
TrialCreateData* data = mTestCreate.Get(aKeySystem);
|
||||
MOZ_ASSERT(data);
|
||||
|
||||
switch (data->mStatus) {
|
||||
case TrialCreateState::Succeeded: {
|
||||
EME_LOG("GMPVideoDecoderTrialCreator::MaybeAwaitTrialCreate(%s) already succeeded",
|
||||
NS_ConvertUTF16toUTF8(aKeySystem).get());
|
||||
aPromisey->Resolve();
|
||||
break;
|
||||
}
|
||||
case TrialCreateState::Failed: {
|
||||
// Something is broken about this configuration. Report as unsupported.
|
||||
EME_LOG("GMPVideoDecoderTrialCreator::MaybeAwaitTrialCreate(%s) already failed",
|
||||
NS_ConvertUTF16toUTF8(aKeySystem).get());
|
||||
aPromisey->Reject(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
||||
NS_LITERAL_CSTRING("navigator.requestMediaKeySystemAccess trial CDM creation failed"));
|
||||
break;
|
||||
}
|
||||
case TrialCreateState::Pending: {
|
||||
EME_LOG("GMPVideoDecoderTrialCreator::MaybeAwaitTrialCreate(%s) pending",
|
||||
NS_ConvertUTF16toUTF8(aKeySystem).get());
|
||||
// Add request to the list of pending items waiting.
|
||||
data->mPending.AppendElement(aPromisey);
|
||||
if (!data->mTest) {
|
||||
// Not already waiting for CDM to be created. Create and Init
|
||||
// a CDM, to test whether it will work.
|
||||
data->mTest = new TestGMPVideoDecoder(this, aKeySystem, aParent);
|
||||
if (NS_FAILED(data->mTest->Start())) {
|
||||
TrialCreateGMPVideoDecoderFailed(aKeySystem,
|
||||
NS_LITERAL_CSTRING("TestGMPVideoDecoder::Start() failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Promise will call InitMediaKeysPromiseHandler when Init()
|
||||
// succeeds/fails.
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -1,179 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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_dom_GMPVideoDecoderTrialCreator_h
|
||||
#define mozilla_dom_GMPVideoDecoderTrialCreator_h
|
||||
|
||||
#include "mozilla/dom/MediaKeySystemAccess.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "mozilla/dom/MediaKeys.h"
|
||||
#include "GMPVideoDecoderProxy.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class TestGMPVideoDecoder;
|
||||
|
||||
class GMPVideoDecoderTrialCreator {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPVideoDecoderTrialCreator);
|
||||
|
||||
void TrialCreateGMPVideoDecoderFailed(const nsAString& aKeySystem,
|
||||
const nsACString& aReason);
|
||||
void TrialCreateGMPVideoDecoderSucceeded(const nsAString& aKeySystem);
|
||||
|
||||
template<class T>
|
||||
void MaybeAwaitTrialCreate(const nsAString& aKeySystem,
|
||||
MediaKeySystemAccess* aAccess,
|
||||
T* aPromiseLike,
|
||||
nsPIDOMWindow* aParent)
|
||||
{
|
||||
RefPtr<PromiseLike<T>> p(new PromiseLike<T>(aPromiseLike, aAccess));
|
||||
MaybeAwaitTrialCreate(aKeySystem, p, aParent);
|
||||
}
|
||||
|
||||
static void UpdateTrialCreateState(const nsAString& aKeySystem, uint32_t aState);
|
||||
|
||||
private:
|
||||
|
||||
class AbstractPromiseLike {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AbstractPromiseLike);
|
||||
|
||||
virtual void Resolve() = 0;
|
||||
virtual void Reject(nsresult aResult, const nsACString& aMessage) = 0;
|
||||
protected:
|
||||
virtual ~AbstractPromiseLike() {}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class PromiseLike : public AbstractPromiseLike
|
||||
{
|
||||
public:
|
||||
explicit PromiseLike(T* aPromiseLike, MediaKeySystemAccess* aAccess)
|
||||
: mPromiseLike(aPromiseLike)
|
||||
, mAccess(aAccess)
|
||||
{
|
||||
}
|
||||
void Resolve() override {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mPromiseLike->MaybeResolve(mAccess);
|
||||
}
|
||||
void Reject(nsresult aResult, const nsACString& aMessage) override {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mPromiseLike->MaybeReject(aResult, aMessage);
|
||||
}
|
||||
protected:
|
||||
~PromiseLike() {}
|
||||
RefPtr<T> mPromiseLike;
|
||||
RefPtr<MediaKeySystemAccess> mAccess;
|
||||
};
|
||||
|
||||
void MaybeAwaitTrialCreate(const nsAString& aKeySystem,
|
||||
AbstractPromiseLike* aPromisey,
|
||||
nsPIDOMWindow* aParent);
|
||||
|
||||
~GMPVideoDecoderTrialCreator() {}
|
||||
|
||||
// Note: Keep this in sync with GetCreateTrialState.
|
||||
enum TrialCreateState {
|
||||
Pending = 0,
|
||||
Succeeded = 1,
|
||||
Failed = 2,
|
||||
};
|
||||
|
||||
static TrialCreateState GetCreateTrialState(const nsAString& aKeySystem);
|
||||
static void UpdateTrialCreateState(const nsAString& aKeySystem,
|
||||
TrialCreateState aState);
|
||||
|
||||
struct TrialCreateData {
|
||||
explicit TrialCreateData(const nsAString& aKeySystem)
|
||||
: mKeySystem(aKeySystem)
|
||||
, mStatus(GetCreateTrialState(aKeySystem))
|
||||
{}
|
||||
~TrialCreateData() {}
|
||||
const nsString mKeySystem;
|
||||
RefPtr<TestGMPVideoDecoder> mTest;
|
||||
nsTArray<RefPtr<AbstractPromiseLike>> mPending;
|
||||
TrialCreateState mStatus;
|
||||
private:
|
||||
TrialCreateData(const TrialCreateData& aOther) = delete;
|
||||
TrialCreateData() = delete;
|
||||
TrialCreateData& operator =(const TrialCreateData&) = delete;
|
||||
};
|
||||
|
||||
nsClassHashtable<nsStringHashKey, TrialCreateData> mTestCreate;
|
||||
|
||||
};
|
||||
|
||||
class TestGMPVideoDecoder : public GMPVideoDecoderCallbackProxy {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestGMPVideoDecoder);
|
||||
|
||||
TestGMPVideoDecoder(GMPVideoDecoderTrialCreator* aInstance,
|
||||
const nsAString& aKeySystem,
|
||||
nsPIDOMWindow* aParent)
|
||||
: mKeySystem(aKeySystem)
|
||||
, mInstance(aInstance)
|
||||
, mWindow(aParent)
|
||||
, mGMP(nullptr)
|
||||
, mHost(nullptr)
|
||||
, mReceivedDecoded(false)
|
||||
{}
|
||||
|
||||
nsresult Start();
|
||||
|
||||
// GMPVideoDecoderCallbackProxy
|
||||
virtual void Decoded(GMPVideoi420Frame* aDecodedFrame) override;
|
||||
virtual void ReceivedDecodedReferenceFrame(const uint64_t aPictureId) override {}
|
||||
virtual void ReceivedDecodedFrame(const uint64_t aPictureId) override {}
|
||||
virtual void InputDataExhausted() override {}
|
||||
virtual void DrainComplete() override;
|
||||
virtual void ResetComplete() override {}
|
||||
virtual void Error(GMPErr aErr) override;
|
||||
virtual void Terminated() override;
|
||||
|
||||
void ActorCreated(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost); // Main thread.
|
||||
|
||||
class Callback : public GetGMPVideoDecoderCallback
|
||||
{
|
||||
public:
|
||||
explicit Callback(TestGMPVideoDecoder* aInstance)
|
||||
: mInstance(aInstance)
|
||||
{}
|
||||
~Callback() {}
|
||||
void Done(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost) override;
|
||||
private:
|
||||
RefPtr<TestGMPVideoDecoder> mInstance;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
void InitGMPDone(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost); // GMP thread.
|
||||
void CreateGMPVideoDecoder();
|
||||
~TestGMPVideoDecoder() {}
|
||||
|
||||
void ReportFailure(const nsACString& aReason);
|
||||
void ReportSuccess();
|
||||
|
||||
const nsString mKeySystem;
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mGMPService;
|
||||
|
||||
RefPtr<GMPVideoDecoderTrialCreator> mInstance;
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
GMPVideoDecoderProxy* mGMP;
|
||||
GMPVideoHost* mHost;
|
||||
bool mReceivedDecoded;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -33,6 +33,9 @@
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "gmp-audio-decode.h"
|
||||
#include "gmp-video-decode.h"
|
||||
#ifdef XP_WIN
|
||||
#include "WMFDecoderModule.h"
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN) || defined(XP_MACOSX)
|
||||
#define PRIMETIME_EME_SUPPORTED 1
|
||||
@ -316,7 +319,16 @@ GMPDecryptsAndDecodesAAC(mozIGeckoMediaPluginService* aGMPS,
|
||||
return HaveGMPFor(aGMPS,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
|
||||
NS_LITERAL_CSTRING("aac"));
|
||||
NS_LITERAL_CSTRING("aac"))
|
||||
#ifdef XP_WIN
|
||||
// Clearkey on Windows advertises that it can decode in its GMP info
|
||||
// file, but uses Windows Media Foundation to decode. That's not present
|
||||
// on Windows XP, and on some Vista, Windows N, and KN variants without
|
||||
// certain services packs. So for ClearKey we must check that WMF will
|
||||
// work.
|
||||
&& (!aKeySystem.EqualsLiteral("org.w3.clearkey") || WMFDecoderModule::HasAAC())
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -328,8 +340,17 @@ GMPDecryptsAndDecodesH264(mozIGeckoMediaPluginService* aGMPS,
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
|
||||
return HaveGMPFor(aGMPS,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
|
||||
NS_LITERAL_CSTRING("aac"));
|
||||
NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
|
||||
NS_LITERAL_CSTRING("h264"))
|
||||
#ifdef XP_WIN
|
||||
// Clearkey on Windows advertises that it can decode in its GMP info
|
||||
// file, but uses Windows Media Foundation to decode. That's not present
|
||||
// on Windows XP, and on some Vista, Windows N, and KN variants without
|
||||
// certain services packs. So for ClearKey we must check that WMF will
|
||||
// work.
|
||||
&& (!aKeySystem.EqualsLiteral("org.w3.clearkey") || WMFDecoderModule::HasH264())
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
// If this keysystem's CDM explicitly says it doesn't support decoding,
|
||||
@ -352,9 +373,12 @@ GMPDecryptsAndGeckoDecodesH264(mozIGeckoMediaPluginService* aGMPService,
|
||||
NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
|
||||
NS_LITERAL_CSTRING("h264"))
|
||||
#ifdef XP_WIN
|
||||
// Clearkey on Windows XP can't decode, but advertises that it can
|
||||
// in its GMP info file.
|
||||
|| (aKeySystem.EqualsLiteral("org.w3.clearkey") && !IsVistaOrLater())
|
||||
// Clearkey on Windows advertises that it can decode in its GMP info
|
||||
// file, but uses Windows Media Foundation to decode. That's not present
|
||||
// on Windows XP, and on some Vista, Windows N, and KN variants without
|
||||
// certain services packs. So don't try to use gmp-clearkey for decoding
|
||||
// if we don't have a decoder here.
|
||||
|| (aKeySystem.EqualsLiteral("org.w3.clearkey") && !WMFDecoderModule::HasH264())
|
||||
#endif
|
||||
) && MP4Decoder::CanHandleMediaType(aContentType);
|
||||
}
|
||||
@ -374,9 +398,12 @@ GMPDecryptsAndGeckoDecodesAAC(mozIGeckoMediaPluginService* aGMPService,
|
||||
NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
|
||||
NS_LITERAL_CSTRING("aac"))
|
||||
#ifdef XP_WIN
|
||||
// Clearkey on Windows XP can't decode, but advertises that it can
|
||||
// in its GMP info file.
|
||||
|| (aKeySystem.EqualsLiteral("org.w3.clearkey") && !IsVistaOrLater())
|
||||
// Clearkey on Windows advertises that it can decode in its GMP info
|
||||
// file, but uses Windows Media Foundation to decode. That's not present
|
||||
// on Windows XP, and on some Vista, Windows N, and KN variants without
|
||||
// certain services packs. So don't try to use gmp-clearkey for decoding
|
||||
// if we don't have a decoder here.
|
||||
|| (aKeySystem.EqualsLiteral("org.w3.clearkey") && !WMFDecoderModule::HasAAC())
|
||||
#endif
|
||||
) && MP4Decoder::CanHandleMediaType(aContentType);
|
||||
}
|
||||
|
@ -51,7 +51,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
MediaKeySystemAccessManager::MediaKeySystemAccessManager(nsPIDOMWindow* aWindow)
|
||||
: mWindow(aWindow)
|
||||
, mAddedObservers(false)
|
||||
, mTrialCreator(new GMPVideoDecoderTrialCreator())
|
||||
{
|
||||
}
|
||||
|
||||
@ -73,19 +72,6 @@ MediaKeySystemAccessManager::Request(DetailedPromise* aPromise,
|
||||
Request(aPromise, aKeySystem, aConfigs, RequestType::Initial);
|
||||
}
|
||||
|
||||
static bool
|
||||
ShouldTrialCreateGMP(const nsAString& aKeySystem)
|
||||
{
|
||||
// Trial create where the CDM has a Windows Media Foundation decoder.
|
||||
#ifdef XP_WIN
|
||||
return Preferences::GetBool("media.gmp.trial-create.enabled", false) &&
|
||||
aKeySystem.EqualsLiteral("org.w3.clearkey") &&
|
||||
IsVistaOrLater();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySystemAccessManager::Request(DetailedPromise* aPromise,
|
||||
const nsAString& aKeySystem,
|
||||
@ -179,13 +165,6 @@ MediaKeySystemAccessManager::Request(DetailedPromise* aPromise,
|
||||
MediaKeySystemAccess::IsSupported(keySystem, aConfigs)) {
|
||||
RefPtr<MediaKeySystemAccess> access(
|
||||
new MediaKeySystemAccess(mWindow, keySystem, NS_ConvertUTF8toUTF16(cdmVersion), config));
|
||||
if (ShouldTrialCreateGMP(keySystem)) {
|
||||
// Ensure we have tried creating a GMPVideoDecoder for this
|
||||
// keySystem, and that we can use it to decode. This ensures that we only
|
||||
// report that we support this keySystem when the CDM us usable.
|
||||
mTrialCreator->MaybeAwaitTrialCreate(keySystem, access, aPromise, mWindow);
|
||||
return;
|
||||
}
|
||||
aPromise->MaybeResolve(access);
|
||||
return;
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define mozilla_dom_MediaKeySystemAccessManager_h
|
||||
|
||||
#include "mozilla/dom/MediaKeySystemAccess.h"
|
||||
#include "mozilla/dom/GMPVideoDecoderTrialCreator.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
@ -76,8 +75,6 @@ private:
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
bool mAddedObservers;
|
||||
|
||||
RefPtr<GMPVideoDecoderTrialCreator> mTrialCreator;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -5,7 +5,6 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'GMPVideoDecoderTrialCreator.h',
|
||||
'MediaEncryptedEvent.h',
|
||||
'MediaKeyError.h',
|
||||
'MediaKeyMessageEvent.h',
|
||||
@ -30,7 +29,6 @@ UNIFIED_SOURCES += [
|
||||
'CDMProxy.cpp',
|
||||
'DetailedPromise.cpp',
|
||||
'EMEUtils.cpp',
|
||||
'GMPVideoDecoderTrialCreator.cpp',
|
||||
'MediaEncryptedEvent.cpp',
|
||||
'MediaKeyError.cpp',
|
||||
'MediaKeyMessageEvent.cpp',
|
||||
|
@ -73,8 +73,6 @@ GMPParent::GMPParent()
|
||||
|
||||
GMPParent::~GMPParent()
|
||||
{
|
||||
// Can't Close or Destroy the process here, since destruction is MainThread only
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
LOGD("GMPParent dtor");
|
||||
|
||||
MOZ_ASSERT(!mProcess);
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIFile.h"
|
||||
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
|
||||
|
||||
class nsIThread;
|
||||
|
||||
@ -72,7 +71,7 @@ public:
|
||||
class GMPParent final : public PGMPParent
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(GMPParent)
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPParent)
|
||||
|
||||
GMPParent();
|
||||
|
||||
|
@ -186,40 +186,6 @@ GeckoMediaPluginServiceChild::GetNodeId(const nsAString& aOrigin,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginServiceChild::UpdateTrialCreateState(const nsAString& aKeySystem,
|
||||
uint32_t aState)
|
||||
{
|
||||
if (NS_GetCurrentThread() != mGMPThread) {
|
||||
mGMPThread->Dispatch(NS_NewRunnableMethodWithArgs<nsString, uint32_t>(
|
||||
this, &GeckoMediaPluginServiceChild::UpdateTrialCreateState,
|
||||
aKeySystem, aState), NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class Callback : public GetServiceChildCallback
|
||||
{
|
||||
public:
|
||||
Callback(const nsAString& aKeySystem, uint32_t aState)
|
||||
: mKeySystem(aKeySystem)
|
||||
, mState(aState)
|
||||
{ }
|
||||
|
||||
virtual void Done(GMPServiceChild* aService) override
|
||||
{
|
||||
aService->SendUpdateGMPTrialCreateState(mKeySystem, mState);
|
||||
}
|
||||
|
||||
private:
|
||||
nsString mKeySystem;
|
||||
uint32_t mState;
|
||||
};
|
||||
|
||||
UniquePtr<GetServiceChildCallback> callback(new Callback(aKeySystem, aState));
|
||||
GetServiceChild(Move(callback));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginServiceChild::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
|
@ -50,8 +50,6 @@ public:
|
||||
const nsAString& aGMPName,
|
||||
bool aInPrivateBrowsingMode,
|
||||
UniquePtr<GetNodeIdCallback>&& aCallback) override;
|
||||
NS_IMETHOD UpdateTrialCreateState(const nsAString& aKeySystem,
|
||||
uint32_t aState) override;
|
||||
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
|
@ -9,9 +9,6 @@
|
||||
#include "mozilla/Logging.h"
|
||||
#include "GMPParent.h"
|
||||
#include "GMPVideoDecoderParent.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/dom/GMPVideoDecoderTrialCreator.h"
|
||||
#endif
|
||||
#include "nsIObserverService.h"
|
||||
#include "GeckoChildProcessHost.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -84,7 +81,8 @@ NS_IMPL_ISUPPORTS_INHERITED(GeckoMediaPluginServiceParent,
|
||||
mozIGeckoMediaPluginChromeService)
|
||||
|
||||
static int32_t sMaxAsyncShutdownWaitMs = 0;
|
||||
static bool sHaveSetTimeoutPrefCache = false;
|
||||
static bool sAllowInsecureGMP = false;
|
||||
static bool sHaveSetGMPServiceParentPrefCaches = false;
|
||||
|
||||
GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent()
|
||||
: mShuttingDown(false)
|
||||
@ -95,11 +93,13 @@ GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent()
|
||||
, mWaitingForPluginsSyncShutdown(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!sHaveSetTimeoutPrefCache) {
|
||||
sHaveSetTimeoutPrefCache = true;
|
||||
if (!sHaveSetGMPServiceParentPrefCaches) {
|
||||
sHaveSetGMPServiceParentPrefCaches = true;
|
||||
Preferences::AddIntVarCache(&sMaxAsyncShutdownWaitMs,
|
||||
"media.gmp.async-shutdown-timeout",
|
||||
GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT);
|
||||
Preferences::AddBoolVarCache(&sAllowInsecureGMP,
|
||||
"media.gmp.insecure.allow", false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ GeckoMediaPluginServiceParent::~GeckoMediaPluginServiceParent()
|
||||
int32_t
|
||||
GeckoMediaPluginServiceParent::AsyncShutdownTimeoutMs()
|
||||
{
|
||||
MOZ_ASSERT(sHaveSetTimeoutPrefCache);
|
||||
MOZ_ASSERT(sHaveSetGMPServiceParentPrefCaches);
|
||||
return sMaxAsyncShutdownWaitMs;
|
||||
}
|
||||
|
||||
@ -945,45 +945,28 @@ GeckoMediaPluginServiceParent::SelectPluginForAPI(const nsACString& aNodeId,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
class CreateGMPParentTask : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
RefPtr<GMPParent>
|
||||
CreateGMPParent()
|
||||
{
|
||||
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
||||
if (!SandboxInfo::Get().CanSandboxMedia()) {
|
||||
if (!Preferences::GetBool("media.gmp.insecure.allow")) {
|
||||
NS_WARNING("Denying media plugin load due to lack of sandboxing.");
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
NS_WARNING("Loading media plugin despite lack of sandboxing.");
|
||||
if (!SandboxInfo::Get().CanSandboxMedia()) {
|
||||
if (!sAllowInsecureGMP) {
|
||||
NS_WARNING("Denying media plugin load due to lack of sandboxing.");
|
||||
return nullptr;
|
||||
}
|
||||
NS_WARNING("Loading media plugin despite lack of sandboxing.");
|
||||
}
|
||||
#endif
|
||||
mParent = new GMPParent();
|
||||
return NS_OK;
|
||||
}
|
||||
already_AddRefed<GMPParent> GetParent() {
|
||||
return mParent.forget();
|
||||
}
|
||||
private:
|
||||
RefPtr<GMPParent> mParent;
|
||||
};
|
||||
return new GMPParent();
|
||||
}
|
||||
|
||||
GMPParent*
|
||||
GeckoMediaPluginServiceParent::ClonePlugin(const GMPParent* aOriginal)
|
||||
{
|
||||
MOZ_ASSERT(aOriginal);
|
||||
|
||||
// The GMPParent inherits from IToplevelProtocol, which must be created
|
||||
// on the main thread to be threadsafe. See Bug 1035653.
|
||||
RefPtr<CreateGMPParentTask> task(new CreateGMPParentTask());
|
||||
if (!NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
MOZ_ASSERT(mainThread);
|
||||
mozilla::SyncRunnable::DispatchToThread(mainThread, task);
|
||||
}
|
||||
|
||||
RefPtr<GMPParent> gmp = task->GetParent();
|
||||
nsresult rv = gmp->CloneFrom(aOriginal);
|
||||
RefPtr<GMPParent> gmp = CreateGMPParent();
|
||||
nsresult rv = gmp ? gmp->CloneFrom(aOriginal) : NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Can't Create GMPParent");
|
||||
@ -1008,13 +991,7 @@ GeckoMediaPluginServiceParent::AddOnGMPThread(const nsAString& aDirectory)
|
||||
return;
|
||||
}
|
||||
|
||||
// The GMPParent inherits from IToplevelProtocol, which must be created
|
||||
// on the main thread to be threadsafe. See Bug 1035653.
|
||||
RefPtr<CreateGMPParentTask> task(new CreateGMPParentTask());
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
MOZ_ASSERT(mainThread);
|
||||
mozilla::SyncRunnable::DispatchToThread(mainThread, task);
|
||||
RefPtr<GMPParent> gmp = task->GetParent();
|
||||
RefPtr<GMPParent> gmp = CreateGMPParent();
|
||||
rv = gmp ? gmp->Init(this, directory) : NS_ERROR_NOT_AVAILABLE;
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Can't Create GMPParent");
|
||||
@ -1412,22 +1389,6 @@ GeckoMediaPluginServiceParent::GetNodeId(const nsAString& aOrigin,
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginServiceParent::UpdateTrialCreateState(const nsAString& aKeySystem,
|
||||
uint32_t aState)
|
||||
{
|
||||
#ifdef MOZ_EME
|
||||
nsString keySystem(aKeySystem);
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction([keySystem, aState] {
|
||||
mozilla::dom::GMPVideoDecoderTrialCreator::UpdateTrialCreateState(keySystem, aState);
|
||||
}));
|
||||
|
||||
return NS_OK;
|
||||
#else
|
||||
return NS_ERROR_FAILURE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
ExtractHostName(const nsACString& aOrigin, nsACString& aOutData)
|
||||
{
|
||||
@ -1756,14 +1717,6 @@ GMPServiceParent::RecvGetGMPNodeId(const nsString& aOrigin,
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPServiceParent::RecvUpdateGMPTrialCreateState(const nsString& aKeySystem,
|
||||
const uint32_t& aState)
|
||||
{
|
||||
mService->UpdateTrialCreateState(aKeySystem, aState);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
GMPServiceParent::RecvGetGMPPluginVersionForAPI(const nsCString& aAPI,
|
||||
|
@ -44,8 +44,6 @@ public:
|
||||
const nsAString& aGMPName,
|
||||
bool aInPrivateBrowsingMode,
|
||||
UniquePtr<GetNodeIdCallback>&& aCallback) override;
|
||||
NS_IMETHOD UpdateTrialCreateState(const nsAString& aKeySystem,
|
||||
uint32_t aState) override;
|
||||
|
||||
NS_DECL_MOZIGECKOMEDIAPLUGINCHROMESERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
@ -225,9 +223,6 @@ public:
|
||||
nsTArray<nsCString>&& aTags,
|
||||
bool* aHasPlugin,
|
||||
nsCString* aVersion);
|
||||
virtual bool RecvUpdateGMPTrialCreateState(const nsString& aKeySystem,
|
||||
const uint32_t& aState) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
static PGMPServiceParent* Create(Transport* aTransport, ProcessId aOtherPid);
|
||||
|
@ -22,8 +22,6 @@ parent:
|
||||
nsString gmpName,
|
||||
bool inPrivateBrowsing)
|
||||
returns (nsCString id);
|
||||
|
||||
async UpdateGMPTrialCreateState(nsString keySystem, uint32_t status);
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
@ -52,7 +52,7 @@ native GetGMPVideoDecoderCallback(mozilla::UniquePtr<GetGMPVideoDecoderCallback>
|
||||
native GetGMPVideoEncoderCallback(mozilla::UniquePtr<GetGMPVideoEncoderCallback>&&);
|
||||
native GetNodeIdCallback(mozilla::UniquePtr<GetNodeIdCallback>&&);
|
||||
|
||||
[scriptable, uuid(b5492915-2f0e-4973-9f91-a6fe61ac4749)]
|
||||
[scriptable, uuid(44d362ae-937a-4803-bee6-f2512a0149d1)]
|
||||
interface mozIGeckoMediaPluginService : nsISupports
|
||||
{
|
||||
|
||||
@ -148,10 +148,4 @@ interface mozIGeckoMediaPluginService : nsISupports
|
||||
in AString gmpName,
|
||||
in bool inPrivateBrowsingMode,
|
||||
in GetNodeIdCallback callback);
|
||||
|
||||
/**
|
||||
* Stores the result of trying to create a decoder for the given keysystem.
|
||||
*/
|
||||
[noscript]
|
||||
void updateTrialCreateState(in AString keySystem, in uint32_t status);
|
||||
};
|
||||
|
@ -13,11 +13,6 @@
|
||||
#include "GMPVideoEncoderProxy.h"
|
||||
#include "GMPDecryptorProxy.h"
|
||||
#include "GMPServiceParent.h"
|
||||
#ifdef XP_WIN
|
||||
#include "GMPVideoDecoderTrialCreator.h"
|
||||
#include "mozilla/dom/MediaKeySystemAccess.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#endif
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
@ -1494,65 +1489,3 @@ TEST(GeckoMediaPlugins, GMPStorageLongRecordNames) {
|
||||
RefPtr<GMPStorageTest> runner = new GMPStorageTest();
|
||||
runner->DoTest(&GMPStorageTest::TestLongRecordNames);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
class GMPTrialCreateTest
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPStorageTest)
|
||||
|
||||
void DoTest() {
|
||||
EnsureNSSInitializedChromeOrContent();
|
||||
mCreator = new mozilla::dom::GMPVideoDecoderTrialCreator();
|
||||
mCreator->MaybeAwaitTrialCreate(NS_LITERAL_STRING("broken"), nullptr, this, nullptr);
|
||||
AwaitFinished();
|
||||
}
|
||||
|
||||
GMPTrialCreateTest()
|
||||
: mMonitor("GMPTrialCreateTest")
|
||||
, mFinished(false)
|
||||
, mPassed(false)
|
||||
{
|
||||
}
|
||||
|
||||
void MaybeResolve(mozilla::dom::MediaKeySystemAccess* aAccess) {
|
||||
mPassed = false;
|
||||
SetFinished();
|
||||
}
|
||||
|
||||
void MaybeReject(nsresult aResult, const nsACString& aUnusedMessage) {
|
||||
mPassed = true;
|
||||
SetFinished();
|
||||
}
|
||||
|
||||
private:
|
||||
~GMPTrialCreateTest() { }
|
||||
|
||||
void Dummy() {
|
||||
// Intentionally left blank.
|
||||
}
|
||||
|
||||
void SetFinished() {
|
||||
mFinished = true;
|
||||
NS_DispatchToMainThread(NS_NewRunnableMethod(this, &GMPTrialCreateTest::Dummy));
|
||||
}
|
||||
|
||||
void AwaitFinished() {
|
||||
while (!mFinished) {
|
||||
NS_ProcessNextEvent(nullptr, true);
|
||||
}
|
||||
mFinished = false;
|
||||
}
|
||||
|
||||
RefPtr<mozilla::dom::GMPVideoDecoderTrialCreator> mCreator;
|
||||
|
||||
Monitor mMonitor;
|
||||
Atomic<bool> mFinished;
|
||||
bool mPassed;
|
||||
};
|
||||
|
||||
TEST(GeckoMediaPlugins, GMPTrialCreateFail) {
|
||||
RefPtr<GMPTrialCreateTest> runner = new GMPTrialCreateTest();
|
||||
runner->DoTest();
|
||||
}
|
||||
|
||||
#endif // XP_WIN
|
@ -314,7 +314,6 @@ DecodedStream::DecodedStream(AbstractThread* aOwnerThread,
|
||||
MediaQueue<MediaData>& aAudioQueue,
|
||||
MediaQueue<MediaData>& aVideoQueue)
|
||||
: mOwnerThread(aOwnerThread)
|
||||
, mShuttingDown(false)
|
||||
, mPlaying(false)
|
||||
, mSameOrigin(false)
|
||||
, mAudioQueue(aAudioQueue)
|
||||
@ -357,13 +356,6 @@ DecodedStream::OnEnded(TrackType aType)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
DecodedStream::BeginShutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mShuttingDown = true;
|
||||
}
|
||||
|
||||
void
|
||||
DecodedStream::Start(int64_t aStartTime, const MediaInfo& aInfo)
|
||||
{
|
||||
@ -455,8 +447,7 @@ DecodedStream::CreateData(MozPromiseHolder<GenericPromise>&& aPromise)
|
||||
|
||||
// No need to create a source stream when there are no output streams. This
|
||||
// happens when RemoveOutput() is called immediately after StartPlayback().
|
||||
// Also we don't create a source stream when MDSM has begun shutdown.
|
||||
if (!mOutputStreamManager.Graph() || mShuttingDown) {
|
||||
if (!mOutputStreamManager.Graph()) {
|
||||
// Resolve the promise to indicate the end of playback.
|
||||
aPromise.Resolve(true, __func__);
|
||||
return;
|
||||
@ -477,16 +468,30 @@ DecodedStream::CreateData(MozPromiseHolder<GenericPromise>&& aPromise)
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
virtual ~R()
|
||||
{
|
||||
// mData is not transferred when dispatch fails and Run() is not called.
|
||||
// We need to dispatch a task to ensure DecodedStreamData is destroyed
|
||||
// properly on the main thread.
|
||||
if (mData) {
|
||||
DecodedStreamData* data = mData.release();
|
||||
RefPtr<DecodedStream> self = mThis.forget();
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
||||
self->mOutputStreamManager.Disconnect();
|
||||
delete data;
|
||||
});
|
||||
AbstractThread::MainThread()->Dispatch(r.forget());
|
||||
}
|
||||
}
|
||||
RefPtr<DecodedStream> mThis;
|
||||
Method mMethod;
|
||||
UniquePtr<DecodedStreamData> mData;
|
||||
};
|
||||
|
||||
// Post a message to ensure |mData| is only updated on the worker thread.
|
||||
// Note this must be done before MDSM's shutdown since dispatch could fail
|
||||
// when the worker thread is shut down.
|
||||
// Note this could fail when MDSM begin to shut down the worker thread.
|
||||
nsCOMPtr<nsIRunnable> r = new R(this, &DecodedStream::OnDataCreated, data);
|
||||
mOwnerThread->Dispatch(r.forget());
|
||||
mOwnerThread->Dispatch(r.forget(), AbstractThread::DontAssertDispatchSuccess);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -120,7 +120,6 @@ public:
|
||||
bool IsPlaying() const override;
|
||||
|
||||
// TODO: fix these functions that don't fit into the interface of MediaSink.
|
||||
void BeginShutdown();
|
||||
void AddOutput(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
|
||||
void RemoveOutput(MediaStream* aStream);
|
||||
void SetSameOrigin(bool aSameOrigin);
|
||||
@ -154,8 +153,6 @@ private:
|
||||
*/
|
||||
// Data about MediaStreams that are being fed by the decoder.
|
||||
OutputStreamManager mOutputStreamManager;
|
||||
// True if MDSM has begun shutdown.
|
||||
bool mShuttingDown;
|
||||
|
||||
/*
|
||||
* Worker thread only members.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user