зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to b2g-inbound
This commit is contained in:
Коммит
88c5f9d0a7
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1164310 requires a clobber due to bug 1177844
|
||||
Bug 1186003 needed a CLOBBER
|
||||
|
|
|
@ -93,12 +93,19 @@ this.FxAccountsMgmtService = {
|
|||
delete data.accountId;
|
||||
}
|
||||
|
||||
// XXX dirty hack because Gaia is sending getAccounts.
|
||||
if (data.method == "getAccounts") {
|
||||
data.method = "getAccount";
|
||||
}
|
||||
|
||||
switch(data.method) {
|
||||
case "getAccounts":
|
||||
FxAccountsManager.getAccount().then(
|
||||
account => {
|
||||
// We only expose the email and verification status so far.
|
||||
self._onFulfill(msg.id, account);
|
||||
case "getAccount":
|
||||
case "getKeys":
|
||||
FxAccountsManager[data.method]().then(
|
||||
result => {
|
||||
// For the getAccounts case, we only expose the email and
|
||||
// verification status so far.
|
||||
self._onFulfill(msg.id, result);
|
||||
},
|
||||
reason => {
|
||||
self._onReject(msg.id, reason);
|
||||
|
|
|
@ -432,6 +432,9 @@ pref("browser.search.redirectWindowsSearch", true);
|
|||
pref("browser.search.redirectWindowsSearch", false);
|
||||
#endif
|
||||
|
||||
pref("browser.usedOnWindows10", false);
|
||||
pref("browser.usedOnWindows10.introURL", "https://www.mozilla.org/%LOCALE%/firefox/windows-10/welcome/?utm_source=firefox-browser&utm_medium=firefox-browser");
|
||||
|
||||
pref("browser.sessionhistory.max_entries", 50);
|
||||
|
||||
// Built-in default permissions.
|
||||
|
@ -1927,6 +1930,12 @@ pref("browser.tabs.remote.autostart.1", false);
|
|||
pref("browser.tabs.remote.autostart.2", true);
|
||||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
#if defined(XP_MACOSX)
|
||||
pref("layers.async-pan-zoom.enabled", true);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
// Enable e10s add-on interposition by default.
|
||||
pref("extensions.interposition.enabled", true);
|
||||
|
|
|
@ -465,8 +465,6 @@ input[type=button] {
|
|||
position: absolute;
|
||||
top: 100%;
|
||||
right: -25px;
|
||||
background-color: white;
|
||||
border-radius: 6px;
|
||||
filter: drop-shadow(0 0 1px rgba(0,0,0,0.4)) drop-shadow(0 3px 4px rgba(0,0,0,0.4));
|
||||
transition: all 200ms ease-in-out;
|
||||
transform-origin: top right;
|
||||
|
@ -512,6 +510,12 @@ input[type=button] {
|
|||
border-top: none;
|
||||
}
|
||||
|
||||
#newtab-customize-panel-inner-wrapper {
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#newtab-customize-title > label {
|
||||
cursor: default;
|
||||
}
|
||||
|
|
|
@ -23,11 +23,12 @@
|
|||
<div class="newtab-customize-panel-container">
|
||||
<div id="newtab-customize-panel" orient="vertical">
|
||||
<div id="newtab-customize-panel-anchor"></div>
|
||||
<div id="newtab-customize-title" class="newtab-customize-panel-item">
|
||||
<div id="newtab-customize-panel-inner-wrapper">
|
||||
<div id="newtab-customize-title" class="newtab-customize-panel-item">
|
||||
<label>&newtab.customize.cog.title2;</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="newtab-customize-complex-option">
|
||||
<div class="newtab-customize-complex-option">
|
||||
<div id="newtab-customize-classic" class="newtab-customize-panel-superitem newtab-customize-panel-item selectable">
|
||||
<label>&newtab.customize.classic;</label>
|
||||
</div>
|
||||
|
@ -35,12 +36,13 @@
|
|||
<label class="checkbox"></label>
|
||||
<label>&newtab.customize.cog.enhanced;</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="newtab-customize-blank" class="newtab-customize-panel-item selectable">
|
||||
</div>
|
||||
<div id="newtab-customize-blank" class="newtab-customize-panel-item selectable">
|
||||
<label>&newtab.customize.blank2;</label>
|
||||
</div>
|
||||
<div id="newtab-customize-learn" class="newtab-customize-panel-item">
|
||||
</div>
|
||||
<div id="newtab-customize-learn" class="newtab-customize-panel-item">
|
||||
<label>&newtab.customize.cog.learn;</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -18,36 +18,21 @@ function getFocusedLocalName(browser) {
|
|||
}
|
||||
|
||||
add_task(function* () {
|
||||
gBrowser.selectedTab = gBrowser.addTab(URL);
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
let testTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
|
||||
|
||||
let browser = testTab.linkedBrowser;
|
||||
|
||||
is((yield getFocusedLocalName(browser)), "button", "button is focused");
|
||||
|
||||
let promiseFocused = ContentTask.spawn(browser, null, function* () {
|
||||
return new Promise(resolve => {
|
||||
content.addEventListener("focus", function onFocus({target}) {
|
||||
if (String(target.location).startsWith("data:")) {
|
||||
content.removeEventListener("focus", onFocus);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
let blankTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
|
||||
|
||||
// The test page loaded, so open an empty tab, select it, then restore
|
||||
// the test tab. This causes the test page's focused element to be removed
|
||||
// from its document.
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
// Wait until the original tab is focused again.
|
||||
yield promiseFocused;
|
||||
yield BrowserTestUtils.switchTab(gBrowser, testTab);
|
||||
|
||||
// Make sure focus is given to the window because the element is now gone.
|
||||
is((yield getFocusedLocalName(browser)), "body", "body is focused");
|
||||
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(blankTab);
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
});
|
||||
|
|
|
@ -552,10 +552,9 @@ nsBrowserContentHandler.prototype = {
|
|||
let platformVersion = Services.sysinfo.getProperty("version");
|
||||
if (AppConstants.platform == "win" &&
|
||||
Services.vc.compare(platformVersion, "10") == 0 &&
|
||||
Services.prefs.getPrefType("browser.usedOnWindows10") == Services.prefs.PREF_BOOL &&
|
||||
!Services.prefs.getBoolPref("browser.usedOnWindows10")) {
|
||||
Services.prefs.setBoolPref("browser.usedOnWindows10", true);
|
||||
let firstUseOnWindows10URL = Services.urlFormatter.formatURL("https://www.mozilla.org/%LOCALE%/firefox/windows10/");
|
||||
let firstUseOnWindows10URL = Services.urlFormatter.formatURLPref("browser.usedOnWindows10.introURL");
|
||||
|
||||
if (firstUseOnWindows10URL && firstUseOnWindows10URL.length) {
|
||||
if (overridePage) {
|
||||
|
|
|
@ -88,7 +88,7 @@ var gPermissionManager = {
|
|||
// If the uri doesn't successfully parse, try adding a http:// and parsing again
|
||||
let uri;
|
||||
try {
|
||||
let uri = Services.io.newURI(input_url, null, null);
|
||||
uri = Services.io.newURI(input_url, null, null);
|
||||
} catch(ex) {
|
||||
uri = Services.io.newURI("http://" + input_url, null, null);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ var testRunner = {
|
|||
params.url.value = "test.com";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://test.com",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission text should be set correctly");
|
||||
params.btnApplyChanges.doCommand();
|
||||
|
@ -27,6 +29,8 @@ var testRunner = {
|
|||
test: function(params) {
|
||||
params.url.value = "test.com";
|
||||
params.btnBlock.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://test.com",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
|
||||
"permission should change to deny in UI");
|
||||
params.btnApplyChanges.doCommand();
|
||||
|
@ -38,6 +42,8 @@ var testRunner = {
|
|||
test: function(params) {
|
||||
params.url.value = "test.com";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://test.com",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission should revert back to allow");
|
||||
params.btnApplyChanges.doCommand();
|
||||
|
@ -68,6 +74,55 @@ var testRunner = {
|
|||
params.pm.remove(uri, "popup");
|
||||
},
|
||||
},
|
||||
{
|
||||
test: function(params) {
|
||||
params.url.value = "https://test.com:12345";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "https://test.com:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission text should be set correctly");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "https://test.com:12345", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
|
||||
},
|
||||
{
|
||||
test: function(params) {
|
||||
params.url.value = "https://test.com:12345";
|
||||
params.btnBlock.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "https://test.com:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
|
||||
"permission should change to deny in UI");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "https://test.com:12345", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.DENY_ACTION }],
|
||||
},
|
||||
{
|
||||
test: function(params) {
|
||||
params.url.value = "https://test.com:12345";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "https://test.com:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission should revert back to allow");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "https://test.com:12345", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
|
||||
},
|
||||
{
|
||||
test: function(params) {
|
||||
params.url.value = "https://test.com:12345";
|
||||
params.btnRemove.doCommand();
|
||||
is(params.tree.view.rowCount, 0, "exception should be removed");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "https://test.com:12345", data: "deleted" }],
|
||||
},
|
||||
],
|
||||
|
||||
_currentTest: -1,
|
||||
|
@ -127,6 +182,7 @@ var testRunner = {
|
|||
let params = {
|
||||
doc: event.target,
|
||||
tree: event.target.getElementById("permissionsTree"),
|
||||
nameCol: event.target.getElementById("permissionsTree").treeBoxObject.columns.getColumnAt(0),
|
||||
statusCol: event.target.getElementById("permissionsTree").treeBoxObject.columns.getColumnAt(1),
|
||||
url: event.target.getElementById("url"),
|
||||
btnAllow: event.target.getElementById("btnAllow"),
|
||||
|
|
|
@ -7,7 +7,6 @@ let gTests;
|
|||
function test() {
|
||||
waitForExplicitFinish();
|
||||
requestLongerTimeout(2);
|
||||
requestCompleteLog();
|
||||
gTests = runTest();
|
||||
gTests.next();
|
||||
}
|
||||
|
|
|
@ -7,6 +7,13 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 4079256,
|
||||
"digest": "bb5238558bcf6db2ca395513c8dccaa15dd61b3c375598eb6a685356b0c1a2d9840e3bf81bc00242b872fd798541f53d723777c754412abf0e772b7cc284937c",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
|
|
|
@ -7,6 +7,13 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 4431740,
|
||||
"digest": "68fc56b0fb0cdba629b95683d6649ff76b00dccf97af90960c3d7716f6108b2162ffd5ffcd5c3a60a21b28674df688fe4dabc67345e2da35ec5abeae3d48c8e3",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
|
|
|
@ -2186,7 +2186,8 @@ let Prefs = new ViewHelpers.Prefs("devtools", {
|
|||
autoPrettyPrint: ["Bool", "debugger.auto-pretty-print"],
|
||||
workersEnabled: ["Bool", "debugger.workers"],
|
||||
editorTabSize: ["Int", "editor.tabsize"],
|
||||
autoBlackBox: ["Bool", "debugger.auto-black-box"]
|
||||
autoBlackBox: ["Bool", "debugger.auto-black-box"],
|
||||
promiseDebuggerEnabled: ["Bool", "debugger.promise"]
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -110,6 +110,7 @@ let DebuggerView = {
|
|||
this._workersAndSourcesPane = document.getElementById("workers-and-sources-pane");
|
||||
this._instrumentsPane = document.getElementById("instruments-pane");
|
||||
this._instrumentsPaneToggleButton = document.getElementById("instruments-pane-toggle");
|
||||
this._promisePane = document.getElementById("promise-debugger-pane");
|
||||
|
||||
this.showEditor = this.showEditor.bind(this);
|
||||
this.showBlackBoxMessage = this.showBlackBoxMessage.bind(this);
|
||||
|
@ -146,6 +147,7 @@ let DebuggerView = {
|
|||
this._workersAndSourcesPane = null;
|
||||
this._instrumentsPane = null;
|
||||
this._instrumentsPaneToggleButton = null;
|
||||
this._promisePane = null;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -601,7 +603,6 @@ let DebuggerView = {
|
|||
* Switches the debugger widgets to a horizontal layout.
|
||||
*/
|
||||
_enterVerticalLayout: function() {
|
||||
let normContainer = document.getElementById("debugger-widgets");
|
||||
let vertContainer = document.getElementById("vertical-layout-panes-container");
|
||||
|
||||
// Move the soruces and instruments panes in a different container.
|
||||
|
@ -620,13 +621,13 @@ let DebuggerView = {
|
|||
*/
|
||||
_enterHorizontalLayout: function() {
|
||||
let normContainer = document.getElementById("debugger-widgets");
|
||||
let vertContainer = document.getElementById("vertical-layout-panes-container");
|
||||
let editorPane = document.getElementById("editor-and-instruments-pane");
|
||||
|
||||
// The sources and instruments pane need to be inserted at their
|
||||
// previous locations in their normal container.
|
||||
let splitter = document.getElementById("sources-and-editor-splitter");
|
||||
normContainer.insertBefore(this._workersAndSourcesPane, splitter);
|
||||
normContainer.appendChild(this._instrumentsPane);
|
||||
editorPane.appendChild(this._instrumentsPane);
|
||||
|
||||
// Revert to the preferred sources and instruments widths, because
|
||||
// they flexed in the vertical layout.
|
||||
|
|
|
@ -341,6 +341,11 @@
|
|||
<toolbarbutton id="toggle-pause-exceptions"
|
||||
class="devtools-toolbarbutton"
|
||||
command="togglePauseOnExceptionsCommand"/>
|
||||
<toolbarbutton id="toggle-promise-debugger"
|
||||
class="devtools-toolbarbutton"
|
||||
tooltiptext="&debuggerUI.sources.togglePromiseDebugger;"
|
||||
command="togglePromiseDebuggerCommand"
|
||||
hidden="true"/>
|
||||
</toolbar>
|
||||
</tabpanel>
|
||||
<tabpanel id="callstack-tabpanel">
|
||||
|
@ -351,46 +356,56 @@
|
|||
</vbox>
|
||||
<splitter id="sources-and-editor-splitter"
|
||||
class="devtools-side-splitter"/>
|
||||
<deck id="editor-deck" flex="1" class="devtools-main-content">
|
||||
<vbox id="editor"/>
|
||||
<vbox id="black-boxed-message"
|
||||
align="center"
|
||||
pack="center">
|
||||
<description id="black-boxed-message-label">
|
||||
&debuggerUI.blackBoxMessage.label;
|
||||
</description>
|
||||
<button id="black-boxed-message-button"
|
||||
class="devtools-toolbarbutton"
|
||||
label="&debuggerUI.blackBoxMessage.unBlackBoxButton;"
|
||||
command="unBlackBoxCommand"/>
|
||||
</vbox>
|
||||
<html:div id="source-progress-container"
|
||||
align="center">
|
||||
<html:div id="hbox">
|
||||
<html:progress id="source-progress"></html:progress>
|
||||
</html:div>
|
||||
</html:div>
|
||||
</deck>
|
||||
<splitter id="editor-and-instruments-splitter"
|
||||
class="devtools-side-splitter"/>
|
||||
<tabbox id="instruments-pane"
|
||||
class="devtools-sidebar-tabs"
|
||||
<vbox id="debugger-content" flex="1">
|
||||
<hbox id="editor-and-instruments-pane" flex="1">
|
||||
<deck id="editor-deck" flex="1" class="devtools-main-content">
|
||||
<vbox id="editor"/>
|
||||
<vbox id="black-boxed-message"
|
||||
align="center"
|
||||
pack="center">
|
||||
<description id="black-boxed-message-label">
|
||||
&debuggerUI.blackBoxMessage.label;
|
||||
</description>
|
||||
<button id="black-boxed-message-button"
|
||||
class="devtools-toolbarbutton"
|
||||
label="&debuggerUI.blackBoxMessage.unBlackBoxButton;"
|
||||
command="unBlackBoxCommand"/>
|
||||
</vbox>
|
||||
<html:div id="source-progress-container"
|
||||
align="center">
|
||||
<html:div id="hbox">
|
||||
<html:progress id="source-progress"></html:progress>
|
||||
</html:div>
|
||||
</html:div>
|
||||
</deck>
|
||||
<splitter id="editor-and-instruments-splitter"
|
||||
class="devtools-side-splitter"/>
|
||||
<tabbox id="instruments-pane"
|
||||
class="devtools-sidebar-tabs"
|
||||
hidden="true">
|
||||
<tabs>
|
||||
<tab id="variables-tab" label="&debuggerUI.tabs.variables;"/>
|
||||
<tab id="events-tab" label="&debuggerUI.tabs.events;"/>
|
||||
</tabs>
|
||||
<tabpanels flex="1">
|
||||
<tabpanel id="variables-tabpanel">
|
||||
<vbox id="expressions"/>
|
||||
<splitter class="devtools-horizontal-splitter"/>
|
||||
<vbox id="variables" flex="1"/>
|
||||
</tabpanel>
|
||||
<tabpanel id="events-tabpanel">
|
||||
<vbox id="event-listeners" flex="1"/>
|
||||
</tabpanel>
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
</hbox>
|
||||
<splitter id="editor-and-promise-splitter"
|
||||
class="devtools-horizontal-splitter"/>
|
||||
<vbox id="promise-debugger-pane"
|
||||
flex="1"
|
||||
hidden="true">
|
||||
<tabs>
|
||||
<tab id="variables-tab" label="&debuggerUI.tabs.variables;"/>
|
||||
<tab id="events-tab" label="&debuggerUI.tabs.events;"/>
|
||||
</tabs>
|
||||
<tabpanels flex="1">
|
||||
<tabpanel id="variables-tabpanel">
|
||||
<vbox id="expressions"/>
|
||||
<splitter class="devtools-horizontal-splitter"/>
|
||||
<vbox id="variables" flex="1"/>
|
||||
</tabpanel>
|
||||
<tabpanel id="events-tabpanel">
|
||||
<vbox id="event-listeners" flex="1"/>
|
||||
</tabpanel>
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
<splitter id="vertical-layout-splitter"
|
||||
class="devtools-horizontal-splitter"/>
|
||||
<hbox id="vertical-layout-panes-container">
|
||||
|
|
|
@ -73,27 +73,45 @@ function testHost(aTab, aPanel, aHostType, aLayoutType) {
|
|||
if (aLayoutType == "horizontal") {
|
||||
is(gView._workersAndSourcesPane.parentNode.id, "debugger-widgets",
|
||||
"The workers and sources pane's parent is correct for the horizontal layout.");
|
||||
is(gView._instrumentsPane.parentNode.id, "debugger-widgets",
|
||||
is(gView._instrumentsPane.parentNode.id, "editor-and-instruments-pane",
|
||||
"The instruments pane's parent is correct for the horizontal layout.");
|
||||
is(gDebugger.document.getElementById("promise-debugger-pane").parentNode.id,
|
||||
"debugger-content",
|
||||
"The promise pane's parent is correct for the horizontal layout.");
|
||||
} else {
|
||||
is(gView._workersAndSourcesPane.parentNode.id, "vertical-layout-panes-container",
|
||||
"The workers and sources pane's parent is correct for the vertical layout.");
|
||||
is(gView._instrumentsPane.parentNode.id, "vertical-layout-panes-container",
|
||||
"The instruments pane's parent is correct for the vertical layout.");
|
||||
is(gDebugger.document.getElementById("promise-debugger-pane").parentNode.id,
|
||||
"debugger-content",
|
||||
"The promise pane's parent is correct for the horizontal layout.");
|
||||
}
|
||||
|
||||
let widgets = gDebugger.document.getElementById("debugger-widgets").childNodes;
|
||||
let panes = gDebugger.document.getElementById("vertical-layout-panes-container").childNodes;
|
||||
let content = gDebugger.document.getElementById("debugger-content").childNodes;
|
||||
let editorPane =
|
||||
gDebugger.document.getElementById("editor-and-instruments-pane").childNodes;
|
||||
let verticalPane =
|
||||
gDebugger.document.getElementById("vertical-layout-panes-container").childNodes;
|
||||
|
||||
if (aLayoutType == "horizontal") {
|
||||
is(widgets.length, 7, // 2 panes, 1 editor, 3 splitters and a phantom box.
|
||||
is(widgets.length, 5, // 1 pane, 1 content box, 2 splitters and a phantom box.
|
||||
"Found the correct number of debugger widgets.");
|
||||
is(panes.length, 1, // 1 lonely splitter in the phantom box.
|
||||
is(content.length, 3, // 2 panes, 1 splitter.
|
||||
"Found the correct number of debugger content.");
|
||||
is(editorPane.length, 3, // 2 panes, 1 splitter
|
||||
"Found the correct number of debugger panes.");
|
||||
is(verticalPane.length, 1, // 1 lonely splitter in the phantom box.
|
||||
"Found the correct number of debugger panes.");
|
||||
} else {
|
||||
is(widgets.length, 5, // 1 editor, 3 splitters and a phantom box.
|
||||
is(widgets.length, 4, // 1 content box, 2 splitters and a phantom box.
|
||||
"Found the correct number of debugger widgets.");
|
||||
is(panes.length, 3, // 2 panes and 1 splitter in the phantom box.
|
||||
is(content.length, 3, // 2 panes, 1 splitter.
|
||||
"Found the correct number of debugger content.");
|
||||
is(editorPane.length, 2, // 1 pane, 1 splitter
|
||||
"Found the correct number of debugger panes.");
|
||||
is(verticalPane.length, 3, // 2 panes and 1 splitter in the phantom box.
|
||||
"Found the correct number of debugger panes.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that creating, collpasing and expanding variables in the
|
||||
* Tests that creating, collapsing and expanding variables in the
|
||||
* variables view works as expected.
|
||||
*/
|
||||
|
||||
|
@ -22,7 +22,7 @@ function test() {
|
|||
|
||||
ok(testScope,
|
||||
"Should have created a scope.");
|
||||
is(duplVar, null,
|
||||
is(duplVar, testVar,
|
||||
"Shouldn't be able to duplicate variables in the same scope.");
|
||||
|
||||
ok(testVar,
|
||||
|
|
|
@ -96,8 +96,10 @@ function testVariablesAndPropertiesFiltering() {
|
|||
}
|
||||
|
||||
function firstFilter() {
|
||||
let expanded = once(gVariables, "fetched");
|
||||
typeText(gSearchBox, "constructor");
|
||||
testFiltered();
|
||||
gSearchBox.doCommand();
|
||||
return expanded.then(testFiltered);
|
||||
}
|
||||
|
||||
function secondFilter() {
|
||||
|
@ -128,13 +130,13 @@ function testVariablesAndPropertiesFiltering() {
|
|||
is(constr2Var.expanded, false,
|
||||
"The constr2Var should not be expanded.");
|
||||
|
||||
let expanded = once(gVariables, "fetched");
|
||||
clearText(gSearchBox);
|
||||
typeText(gSearchBox, "constructor");
|
||||
testFiltered();
|
||||
expanded.then(testFiltered);
|
||||
}
|
||||
|
||||
firstFilter();
|
||||
secondFilter();
|
||||
firstFilter().then(secondFilter);
|
||||
}
|
||||
|
||||
function prepareVariablesAndProperties() {
|
||||
|
|
|
@ -103,8 +103,10 @@ function testVariablesAndPropertiesFiltering() {
|
|||
}
|
||||
|
||||
function firstFilter() {
|
||||
let expanded = once(gVariables, "fetched");
|
||||
typeText(gSearchBox, "\"Function\"");
|
||||
testFiltered();
|
||||
gSearchBox.doCommand();
|
||||
return expanded.then(testFiltered);
|
||||
}
|
||||
|
||||
function secondFilter() {
|
||||
|
@ -136,12 +138,13 @@ function testVariablesAndPropertiesFiltering() {
|
|||
"The constr2Var should not be expanded.");
|
||||
|
||||
backspaceText(gSearchBox, 10);
|
||||
let expanded = once(gVariables, "fetched");
|
||||
typeText(gSearchBox, "\"Function\"");
|
||||
testFiltered();
|
||||
gSearchBox.doCommand();
|
||||
expanded.then(testFiltered);
|
||||
}
|
||||
|
||||
firstFilter();
|
||||
secondFilter();
|
||||
firstFilter().then(secondFilter);
|
||||
}
|
||||
|
||||
function prepareVariablesAndProperties() {
|
||||
|
|
|
@ -151,6 +151,7 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
prettyPrintCommand: () => this.togglePrettyPrint(),
|
||||
toggleBreakpointsCommand: () =>this.toggleBreakpoints(),
|
||||
togglePauseOnExceptionsCommand: () => this.togglePauseOnExceptions(),
|
||||
togglePromiseDebuggerCommand: () => this.togglePromiseDebugger(),
|
||||
nextSourceCommand: () => this.selectNextItem(),
|
||||
prevSourceCommand: () => this.selectPrevItem()
|
||||
});
|
||||
|
@ -659,6 +660,13 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
this._togglePauseOnExceptionsButton.setAttribute("state", state);
|
||||
},
|
||||
|
||||
togglePromiseDebugger: function() {
|
||||
if (Prefs.promiseDebuggerEnabled) {
|
||||
let promisePane = this.DebuggerView._promisePane;
|
||||
promisePane.hidden = !promisePane.hidden;
|
||||
}
|
||||
},
|
||||
|
||||
hidePrettyPrinting: function() {
|
||||
this._prettyPrintButton.style.display = 'none';
|
||||
|
||||
|
|
|
@ -21,7 +21,9 @@ function test() {
|
|||
"-H 'X-Custom-Header-2: 8.8.8.8'",
|
||||
"-H 'X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT'",
|
||||
"-H 'Referer: " + CURL_URL + "'",
|
||||
"-H 'Connection: keep-alive'"
|
||||
"-H 'Connection: keep-alive'",
|
||||
"-H 'Pragma: no-cache'",
|
||||
"-H 'Cache-Control: no-cache'"
|
||||
].join(" ");
|
||||
|
||||
const EXPECTED_WIN_RESULT = [
|
||||
|
@ -36,7 +38,9 @@ function test() {
|
|||
'-H "X-Custom-Header-2: 8.8.8.8"',
|
||||
'-H "X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT"',
|
||||
'-H "Referer: ' + CURL_URL + '"',
|
||||
'-H "Connection: keep-alive"'
|
||||
'-H "Connection: keep-alive"',
|
||||
'-H "Pragma: no-cache"',
|
||||
'-H "Cache-Control: no-cache"'
|
||||
].join(" ");
|
||||
|
||||
const EXPECTED_RESULT = Services.appinfo.OS == "WINNT"
|
||||
|
|
|
@ -453,7 +453,7 @@ VariablesView.prototype = {
|
|||
searchbox.setAttribute("placeholder", this._searchboxPlaceholder);
|
||||
searchbox.setAttribute("type", "search");
|
||||
searchbox.setAttribute("flex", "1");
|
||||
searchbox.addEventListener("input", this._onSearchboxInput, false);
|
||||
searchbox.addEventListener("command", this._onSearchboxInput, false);
|
||||
searchbox.addEventListener("keypress", this._onSearchboxKeyPress, false);
|
||||
|
||||
container.appendChild(searchbox);
|
||||
|
@ -470,7 +470,7 @@ VariablesView.prototype = {
|
|||
return;
|
||||
}
|
||||
this._searchboxContainer.remove();
|
||||
this._searchboxNode.removeEventListener("input", this._onSearchboxInput, false);
|
||||
this._searchboxNode.removeEventListener("command", this._onSearchboxInput, false);
|
||||
this._searchboxNode.removeEventListener("keypress", this._onSearchboxKeyPress, false);
|
||||
|
||||
this._searchboxContainer = null;
|
||||
|
@ -550,11 +550,22 @@ VariablesView.prototype = {
|
|||
*/
|
||||
_doSearch: function(aToken) {
|
||||
if (this.controller.supportsSearch()) {
|
||||
this.empty();
|
||||
let scope = this.addScope(aToken);
|
||||
scope.expanded = true; // Expand the scope by default.
|
||||
scope.locked = true; // Prevent collapsing the scope.
|
||||
// Retrieve the main Scope in which we add attributes
|
||||
let scope = this._store[0]._store.get("");
|
||||
if (!aToken) {
|
||||
// Prune the view from old previous content
|
||||
// so that we delete the intermediate search results
|
||||
// we created in previous searches
|
||||
for (let property of scope._store.values()) {
|
||||
property.remove();
|
||||
}
|
||||
}
|
||||
// Retrieve new attributes eventually hidden in splits
|
||||
this.controller.performSearch(scope, aToken);
|
||||
// Filter already displayed attributes
|
||||
if (aToken) {
|
||||
scope._performSearch(aToken.toLowerCase());
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (let scope of this._store) {
|
||||
|
@ -1288,7 +1299,7 @@ Scope.prototype = {
|
|||
*/
|
||||
addItem: function(aName = "", aDescriptor = {}, aRelaxed = false) {
|
||||
if (this._store.has(aName) && !aRelaxed) {
|
||||
return null;
|
||||
return this._store.get(aName);
|
||||
}
|
||||
|
||||
let child = this._createChild(aName, aDescriptor);
|
||||
|
|
|
@ -637,7 +637,10 @@ VariablesViewController.prototype = {
|
|||
* The query string
|
||||
*/
|
||||
performSearch: function(aScope, aToken) {
|
||||
this._populateFromObjectWithIterator(aScope, this.objectActor, aToken);
|
||||
this._populateFromObjectWithIterator(aScope, this.objectActor, aToken)
|
||||
.then(() => {
|
||||
this.view.emit("fetched", "search", aScope);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -173,6 +173,7 @@ skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
|
|||
skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests
|
||||
[browser_console_variables_view.js]
|
||||
skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
|
||||
[browser_console_variables_view_filter.js]
|
||||
[browser_console_variables_view_dom_nodes.js]
|
||||
[browser_console_variables_view_dont_sort_non_sortable_classes_properties.js]
|
||||
skip-if = buildapp == 'mulet'
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Check that variables view filter feature works fine in the console.
|
||||
|
||||
function props(view, prefix = "") {
|
||||
// First match only the visible one, not hidden by a search
|
||||
let visible = [...view].filter(([id, prop]) => prop._isMatch);
|
||||
// Then flatten the list into a list of strings
|
||||
// being the jsonpath of each attribute being visible in the view
|
||||
return visible.reduce((list, [id, prop]) => {
|
||||
list.push(prefix + id);
|
||||
return list.concat(props(prop, prefix + id + "."));
|
||||
}, []);
|
||||
}
|
||||
|
||||
function assertAttrs(view, expected, message) {
|
||||
is(props(view).join(","), expected, message);
|
||||
}
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
yield loadTab("data:text/html;charset=utf-8,webconsole-filter");
|
||||
|
||||
let hud = yield openConsole();
|
||||
|
||||
let jsterm = hud.jsterm;
|
||||
|
||||
let fetched = jsterm.once("variablesview-fetched");
|
||||
|
||||
yield jsterm.execute("inspect({ foo: { bar : \"baz\" } })");
|
||||
|
||||
let view = yield fetched;
|
||||
let variablesView = view._variablesView;
|
||||
let searchbox = variablesView._searchboxNode;
|
||||
|
||||
assertAttrs(view, "foo,__proto__", "To start with, we just see the top level foo attr");
|
||||
|
||||
fetched = jsterm.once("variablesview-fetched");
|
||||
searchbox.value = "bar";
|
||||
searchbox.doCommand();
|
||||
view = yield fetched;
|
||||
|
||||
assertAttrs(view, "", "If we don't manually expand nested attr, we don't see them in search");
|
||||
|
||||
fetched = jsterm.once("variablesview-fetched");
|
||||
searchbox.value = "";
|
||||
searchbox.doCommand();
|
||||
view = yield fetched;
|
||||
|
||||
assertAttrs(view, "foo", "If we reset the search, we get back to original state");
|
||||
|
||||
yield [...view][0][1].expand();
|
||||
|
||||
fetched = jsterm.once("variablesview-fetched");
|
||||
searchbox.value = "bar";
|
||||
searchbox.doCommand();
|
||||
view = yield fetched;
|
||||
|
||||
assertAttrs(view, "foo,foo.bar", "Now if we expand, we see the nested attr");
|
||||
|
||||
fetched = jsterm.once("variablesview-fetched");
|
||||
searchbox.value = "baz";
|
||||
searchbox.doCommand();
|
||||
view = yield fetched;
|
||||
|
||||
assertAttrs(view, "foo,foo.bar", "We can also search for attr values");
|
||||
|
||||
fetched = jsterm.once("variablesview-fetched");
|
||||
searchbox.value = "";
|
||||
searchbox.doCommand();
|
||||
view = yield fetched;
|
||||
|
||||
assertAttrs(view, "foo", "If we reset again, we get back to original state again");
|
||||
});
|
|
@ -50,6 +50,10 @@
|
|||
- button that toggles all breakpoints for all sources. -->
|
||||
<!ENTITY debuggerUI.sources.toggleBreakpoints "Enable/disable all breakpoints">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.sources.togglePromiseDebugger): This is the
|
||||
- tooltip for the button that toggles the promise debugger. -->
|
||||
<!ENTITY debuggerUI.sources.togglePromiseDebugger "Toggle Promise Debugger">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.startTracing): This is the text displayed in
|
||||
- the button to start execution tracing. -->
|
||||
<!ENTITY debuggerUI.startTracing "Start Tracing">
|
||||
|
|
|
@ -580,12 +580,12 @@ PluginContent.prototype = {
|
|||
}
|
||||
|
||||
let runID = plugin.runID;
|
||||
let submitURLOptIn = this.getPluginUI(plugin, "submitURLOptIn");
|
||||
let submitURLOptIn = this.getPluginUI(plugin, "submitURLOptIn").checked;
|
||||
let keyVals = {};
|
||||
let userComment = this.getPluginUI(plugin, "submitComment").value.trim();
|
||||
if (userComment)
|
||||
keyVals.PluginUserComment = userComment;
|
||||
if (this.getPluginUI(plugin, "submitURLOptIn").checked)
|
||||
if (submitURLOptIn)
|
||||
keyVals.PluginContentURL = plugin.ownerDocument.URL;
|
||||
|
||||
this.global.sendAsyncMessage("PluginContent:SubmitReport",
|
||||
|
|
|
@ -122,6 +122,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
#toggle-promise-debugger {
|
||||
/* TODO Bug 1186119: Add a toggle promise debugger image */
|
||||
}
|
||||
|
||||
#sources-toolbar .devtools-toolbarbutton:not([label]) {
|
||||
-moz-image-region: rect(0px,16px,16px,0px);
|
||||
}
|
||||
|
|
|
@ -311,15 +311,22 @@
|
|||
}
|
||||
|
||||
#nav-bar {
|
||||
border-top: 1px solid @toolbarShadowColor@ !important;
|
||||
background-clip: padding-box;
|
||||
background-image: linear-gradient(@toolbarHighlight@, transparent);
|
||||
box-shadow: 0 1px 0 @toolbarHighlight@ inset;
|
||||
}
|
||||
|
||||
@media not all and (-moz-windows-compositor) {
|
||||
#TabsToolbar[collapsed="true"] + #nav-bar {
|
||||
border-top-style: none !important;
|
||||
@media (-moz-os-version: windows-xp),
|
||||
(-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7),
|
||||
(-moz-os-version: windows-win8) {
|
||||
#nav-bar {
|
||||
border-top: 1px solid @toolbarShadowColor@ !important;
|
||||
}
|
||||
@media not all and (-moz-windows-compositor) {
|
||||
#TabsToolbar[collapsed="true"] + #nav-bar {
|
||||
border-top-style: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2067,6 +2074,30 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
}
|
||||
}
|
||||
|
||||
/* Remove border between tab strip and navigation toolbar on Windows 10+ */
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
@media not all and (-moz-os-version: windows-vista) {
|
||||
@media not all and (-moz-os-version: windows-win7) {
|
||||
@media not all and (-moz-os-version: windows-win8) {
|
||||
.tab-background-end[visuallyselected=true]::after,
|
||||
.tab-background-start[visuallyselected=true]::after {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.tab-background-middle[visuallyselected=true] {
|
||||
/* Setting background-size to "0 0" for the first
|
||||
background-image to remove the stroke. */
|
||||
background-size: 0 0, auto 100%, auto 100%;
|
||||
}
|
||||
|
||||
:root {
|
||||
--tab-toolbar-navbar-overlap: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Use solid tab separators for Windows 8+ */
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
@media not all and (-moz-os-version: windows-vista) {
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Use "build-gtk.sh" or "build-gtk.sh 64" to build a 64-bits tarball for tooltool.
|
||||
# Use "build-gtk.sh 32" to build a 32-bits tarball for tooltool.
|
||||
|
||||
# Mock environments used:
|
||||
# - 64-bits:
|
||||
# https://s3.amazonaws.com/mozilla-releng-mock-archive/67b65e51eb091fba7941a04d249343924a3ee653
|
||||
# + libxml2-devel.x86_64 gettext.x86_64 libjpeg-devel.x86_64
|
||||
# - 32-bits:
|
||||
# https://s3.amazonaws.com/mozilla-releng-mock-archive/58d76c6acca148a1aedcbec7fc1b8212e12807b4
|
||||
# + libxml2-devel.i686 gettext.i686 libjpeg-devel.i686
|
||||
|
||||
set -e
|
||||
|
||||
pkg_config_version=0.28
|
||||
fontconfig_version=2.8.0
|
||||
libffi_version=3.0.13
|
||||
glib_version=2.34.3
|
||||
gdk_pixbuf_version=2.26.5
|
||||
pixman_version=0.20.2
|
||||
cairo_version=1.10.2
|
||||
pango_version=1.30.1
|
||||
atk_version=2.2.0
|
||||
gtk__version=3.4.4
|
||||
|
||||
pkg_config_url=http://pkgconfig.freedesktop.org/releases/pkg-config-${pkg_config_version}.tar.gz
|
||||
fontconfig_url=http://www.freedesktop.org/software/fontconfig/release/fontconfig-${fontconfig_version}.tar.gz
|
||||
libffi_url=ftp://sourceware.org/pub/libffi/libffi-${libffi_version}.tar.gz
|
||||
glib_url=http://ftp.gnome.org/pub/gnome/sources/glib/${glib_version%.*}/glib-${glib_version}.tar.xz
|
||||
gdk_pixbuf_url=http://ftp.gnome.org/pub/gnome/sources/gdk-pixbuf/${gdk_pixbuf_version%.*}/gdk-pixbuf-${gdk_pixbuf_version}.tar.xz
|
||||
pixman_url=http://cairographics.org/releases/pixman-${pixman_version}.tar.gz
|
||||
cairo_url=http://cairographics.org/releases/cairo-${cairo_version}.tar.gz
|
||||
pango_url=http://ftp.gnome.org/pub/GNOME/sources/pango/${pango_version%.*}/pango-${pango_version}.tar.xz
|
||||
atk_url=http://ftp.gnome.org/pub/GNOME/sources/atk/${atk_version%.*}/atk-${atk_version}.tar.xz
|
||||
gtk__url=http://ftp.gnome.org/pub/gnome/sources/gtk+/${gtk__version%.*}/gtk+-${gtk__version}.tar.xz
|
||||
|
||||
cwd=$(pwd)
|
||||
root_dir=$(mktemp -d)
|
||||
cd $root_dir
|
||||
|
||||
if test -z $TMPDIR; then
|
||||
TMPDIR=/tmp/
|
||||
fi
|
||||
|
||||
make_flags=-j12
|
||||
|
||||
build() {
|
||||
name=$1
|
||||
shift
|
||||
pkg=$(echo $name | tr '+-' '__')
|
||||
version=$(eval echo \$${pkg}_version)
|
||||
url=$(eval echo \$${pkg}_url)
|
||||
wget -c -P $TMPDIR $url
|
||||
tar -axf $TMPDIR/$name-$version.tar.*
|
||||
mkdir -p build/$name
|
||||
cd build/$name
|
||||
eval ../../$name-$version/configure --disable-static $* $configure_args
|
||||
make $make_flags
|
||||
make install-strip DESTDIR=$root_dir/gtk3
|
||||
find $root_dir/gtk3 -name \*.la -delete
|
||||
cd ../..
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
32)
|
||||
configure_args='--host=i686-pc-linux --build=i686-pc-linux CC="gcc -m32" CXX="g++ -m32"'
|
||||
lib=lib
|
||||
;;
|
||||
*)
|
||||
configure_args=
|
||||
lib=lib64
|
||||
;;
|
||||
esac
|
||||
|
||||
export PKG_CONFIG_LIBDIR=/usr/$lib/pkgconfig:/usr/share/pkgconfig
|
||||
|
||||
# The pkg-config version in the mock images is buggy is how it handles
|
||||
# PKG_CONFIG_SYSROOT_DIR. So we need our own.
|
||||
build pkg-config
|
||||
|
||||
ln -sf /usr/include $root_dir/gtk3/usr/
|
||||
ln -sf /usr/$lib $root_dir/gtk3/usr/
|
||||
if [ "$lib" = lib64 ]; then
|
||||
ln -s lib $root_dir/gtk3/usr/local/lib64
|
||||
fi
|
||||
export PKG_CONFIG_PATH=$root_dir/gtk3/usr/local/lib/pkgconfig
|
||||
export PKG_CONFIG_SYSROOT_DIR=$root_dir/gtk3
|
||||
export LD_LIBRARY_PATH=$root_dir/gtk3/usr/local/lib
|
||||
export PATH=$root_dir/gtk3/usr/local/bin:${PATH}
|
||||
|
||||
build fontconfig
|
||||
build libffi
|
||||
build glib
|
||||
build gdk-pixbuf --without-libtiff
|
||||
build pixman --disable-gtk
|
||||
build cairo --enable-tee
|
||||
build pango
|
||||
build atk
|
||||
make_flags="$make_flags GLIB_COMPILE_SCHEMAS=glib-compile-schemas"
|
||||
build gtk+
|
||||
|
||||
rm -rf $root_dir/gtk3/usr/local/share/gtk-doc
|
||||
rm -rf $root_dir/gtk3/usr/local/share/locale
|
||||
|
||||
cd $cwd
|
||||
tar -C $root_dir -Jcf gtk3.tar.xz gtk3
|
|
@ -8,6 +8,11 @@ MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']
|
|||
MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini']
|
||||
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
|
||||
|
||||
# Hack to make this file available as a resource:// URI.
|
||||
TESTING_JS_MODULES += [
|
||||
'tests/mochitest/resource_test_file.html',
|
||||
]
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIAddonPolicyService.idl',
|
||||
'nsIDomainPolicy.idl',
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
* This interface allows the security manager to query custom per-addon security
|
||||
* policy.
|
||||
*/
|
||||
[scriptable,uuid(fedf126c-988e-42df-82c9-f2ac99cd65f3)]
|
||||
[scriptable,uuid(8a034ef9-9d14-4c5d-8319-06c1ab574baa)]
|
||||
interface nsIAddonPolicyService : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -19,4 +19,14 @@ interface nsIAddonPolicyService : nsISupports
|
|||
* data from |aURI|.
|
||||
*/
|
||||
boolean addonMayLoadURI(in AString aAddonId, in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* Returns true if a given extension:// URI is web-accessible.
|
||||
*/
|
||||
boolean extensionURILoadableByAnyone(in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* Maps an extension URI to the ID of the addon it belongs to.
|
||||
*/
|
||||
AString extensionURIToAddonId(in nsIURI aURI);
|
||||
};
|
||||
|
|
|
@ -360,6 +360,20 @@ nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
|
|||
return GetChannelURIPrincipal(aChannel, aPrincipal);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsScriptSecurityManager::MaybeSetAddonIdFromURI(OriginAttributes& aAttrs, nsIURI* aURI)
|
||||
{
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = aURI->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (scheme.EqualsLiteral("moz-extension") && GetAddonPolicyService()) {
|
||||
rv = GetAddonPolicyService()->ExtensionURIToAddonId(aURI, aAttrs.mAddonId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* The principal of the URI that this channel is loading. This is never
|
||||
* affected by things like sandboxed loads, or loads where we forcefully
|
||||
* inherit the principal. Think of this as the principal of the server
|
||||
|
@ -391,6 +405,8 @@ nsScriptSecurityManager::GetChannelURIPrincipal(nsIChannel* aChannel,
|
|||
}
|
||||
|
||||
OriginAttributes attrs(UNKNOWN_APP_ID, false);
|
||||
rv = MaybeSetAddonIdFromURI(attrs, uri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
|
||||
prin.forget(aPrincipal);
|
||||
return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
@ -745,6 +761,16 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
|
|||
// the methods that work on chains of nested URIs and they will only look
|
||||
// at the flags for our one URI.
|
||||
|
||||
// Special case: moz-extension has a whitelist of URIs that are loadable by
|
||||
// anyone.
|
||||
if (targetScheme.EqualsLiteral("moz-extension") && GetAddonPolicyService()) {
|
||||
bool loadable = false;
|
||||
rv = GetAddonPolicyService()->ExtensionURILoadableByAnyone(targetBaseURI, &loadable);
|
||||
if (NS_SUCCEEDED(rv) && loadable) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for system target URI
|
||||
rv = DenyAccessIfURIHasFlags(targetBaseURI,
|
||||
nsIProtocolHandler::URI_DANGEROUS_TO_LOAD);
|
||||
|
@ -1087,6 +1113,8 @@ nsScriptSecurityManager::
|
|||
OriginAttributes attrs;
|
||||
aLoadContext->GetAppId(&attrs.mAppId);
|
||||
aLoadContext->GetIsInBrowserElement(&attrs.mInBrowser);
|
||||
nsresult rv = MaybeSetAddonIdFromURI(attrs, aURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
|
||||
prin.forget(aPrincipal);
|
||||
return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
@ -1099,6 +1127,8 @@ nsScriptSecurityManager::GetDocShellCodebasePrincipal(nsIURI* aURI,
|
|||
{
|
||||
// XXXbholley - Make this more general in bug 1165466.
|
||||
OriginAttributes attrs(aDocShell->GetAppId(), aDocShell->GetIsInBrowserElement());
|
||||
nsresult rv = MaybeSetAddonIdFromURI(attrs, aURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
|
||||
prin.forget(aPrincipal);
|
||||
return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
|
|
@ -8,10 +8,15 @@
|
|||
#define nsScriptSecurityManager_h__
|
||||
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
|
||||
#include "nsIAddonPolicyService.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsIAddonPolicyService.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "plstr.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
|
@ -115,6 +120,9 @@ private:
|
|||
inline void
|
||||
AddSitesToFileURIWhitelist(const nsCString& aSiteList);
|
||||
|
||||
// If aURI is a moz-extension:// URI, set mAddonId to the associated addon.
|
||||
nsresult MaybeSetAddonIdFromURI(mozilla::OriginAttributes& aAttrs, nsIURI* aURI);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mSystemPrincipal;
|
||||
bool mPrefInitialized;
|
||||
bool mIsJavaScriptEnabled;
|
||||
|
@ -124,6 +132,17 @@ private:
|
|||
// policy machinery will be removed soon.
|
||||
nsCOMPtr<nsIDomainPolicy> mDomainPolicy;
|
||||
|
||||
// Cached addon policy service. We can't generate this in Init() because
|
||||
// that's too early to get a service.
|
||||
mozilla::Maybe<nsCOMPtr<nsIAddonPolicyService>> mAddonPolicyService;
|
||||
nsIAddonPolicyService* GetAddonPolicyService()
|
||||
{
|
||||
if (mAddonPolicyService.isNothing()) {
|
||||
mAddonPolicyService.emplace(do_GetService("@mozilla.org/addons/policy-service;1"));
|
||||
}
|
||||
return mAddonPolicyService.ref();
|
||||
}
|
||||
|
||||
static bool sStrictFileOriginPolicy;
|
||||
|
||||
static nsIIOService *sIOService;
|
||||
|
|
|
@ -11,3 +11,5 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
|
|||
[test_bug423375.html]
|
||||
[test_bug470804.html]
|
||||
[test_disallowInheritPrincipal.html]
|
||||
[test_extensionURL.html]
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # Bug 1185773 for android, nonsensical on b2g
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head><title>resource test file</title></head><body></body></html>
|
|
@ -0,0 +1,144 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1161831
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1161831</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1161831 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var aps = SpecialPowers.Cc["@mozilla.org/addons/policy-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIAddonPolicyService).wrappedJSObject;
|
||||
var oldLoadCallback = aps.setExtensionURILoadCallback(null);
|
||||
var oldMapCallback = aps.setExtensionURIToAddonIdCallback(null);
|
||||
var resourceHandler = SpecialPowers.Services.io.getProtocolHandler("resource")
|
||||
.QueryInterface(SpecialPowers.Ci.nsISubstitutingProtocolHandler);
|
||||
var extensionHandler = SpecialPowers.Services.io.getProtocolHandler("moz-extension")
|
||||
.QueryInterface(SpecialPowers.Ci.nsISubstitutingProtocolHandler);
|
||||
|
||||
SimpleTest.registerCleanupFunction(function() {
|
||||
extensionHandler.setSubstitution('cherise', null);
|
||||
extensionHandler.setSubstitution('liebchen', null);
|
||||
aps.setExtensionURILoadCallback(oldLoadCallback);
|
||||
aps.setExtensionURIToAddonIdCallback(oldMapCallback);
|
||||
});
|
||||
|
||||
addLoadEvent(function() {
|
||||
|
||||
// First, get a file:// URI to something - open to suggestions on how to do
|
||||
// this more easily.
|
||||
var resURI = SpecialPowers.Services.io.newURI('resource://testing-common/resource_test_file.html', null, null);
|
||||
var filePath = resourceHandler.resolveURI(resURI);
|
||||
ok(filePath.startsWith('file://'), 'resource:// URI resolves where we expect: ' + filePath);
|
||||
var fileURI = SpecialPowers.Services.io.newURI(filePath, null, null);
|
||||
|
||||
// Register a moz-extension:// URI.
|
||||
extensionHandler.setSubstitution('cherise', fileURI);
|
||||
|
||||
// Alias the above.
|
||||
extensionHandler.setSubstitution('liebchen', SpecialPowers.Services.io.newURI('moz-extension://cherise', null, null));
|
||||
|
||||
//
|
||||
// Make sure that non-file:// URIs don't work.
|
||||
//
|
||||
|
||||
// resource://
|
||||
try {
|
||||
extensionHandler.setSubstitution('interdit', resURI);
|
||||
ok(false, "Should have thrown for mapping moz-extension to resource");
|
||||
} catch (e) {
|
||||
ok(true, "Threw correctly: " + e);
|
||||
}
|
||||
|
||||
// chrome://
|
||||
try {
|
||||
var chromeURI = SpecialPowers.Services.io.newURI('chrome://global/content/mozilla.xhtml', null, null);
|
||||
extensionHandler.setSubstitution('verboten', chromeURI);
|
||||
ok(false, "Should have thrown for mapping moz-extension to chrome");
|
||||
} catch (e) {
|
||||
ok(true, "Threw correctly: " + e);
|
||||
}
|
||||
|
||||
function navigateWithLocation(ifr, url) { ifr.contentWindow.location = url; }
|
||||
function navigateWithSrc(ifr, url) { ifr.setAttribute('src', url); }
|
||||
function navigateFromChromeWithLocation(ifr, url) { SpecialPowers.wrap(ifr).contentWindow.location = url; }
|
||||
function navigateFromChromeWithWebNav(ifr, url) {
|
||||
SpecialPowers.wrap(ifr).contentWindow
|
||||
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
|
||||
.getInterface(SpecialPowers.Ci.nsIWebNavigation)
|
||||
.loadURI(url, 0, null, null, null);
|
||||
}
|
||||
|
||||
|
||||
function setWhitelistCallback(rgxp) {
|
||||
var cb = SpecialPowers.wrapCallback(function(uri) { return rgxp.test(uri.spec); });
|
||||
aps.setExtensionURILoadCallback(cb);
|
||||
}
|
||||
|
||||
aps.setExtensionURIToAddonIdCallback(SpecialPowers.wrapCallback(function (uri) { return 'imaginaryaddon-' + uri.host[0]; }));
|
||||
|
||||
function testLoad(url, navigate, shouldThrow) {
|
||||
var ifr = document.createElement('iframe');
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
ifr.onload = function() {
|
||||
ok(true, 'Loaded ' + url);
|
||||
var prin = SpecialPowers.wrap(ifr.contentWindow).document.nodePrincipal;
|
||||
is(prin.originNoSuffix, url, 'Principal origin is correct: ' + url);
|
||||
is(prin.originAttributes.addonId, 'imaginaryaddon-' + url[url.indexOf('/') + 2], 'addonId is correct');
|
||||
is(SpecialPowers.wrap(ifr.contentWindow).document.title, 'resource test file',
|
||||
'document looks right');
|
||||
ifr.remove();
|
||||
resolve();
|
||||
};
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
var threw = false;
|
||||
try {
|
||||
navigate(ifr, url);
|
||||
} catch (e) {
|
||||
ifr.remove();
|
||||
threw = true;
|
||||
ok(/denied|insecure/.test(e), "exceiton correct: " + e);
|
||||
}
|
||||
is(threw, !!shouldThrow, "Correct throwing behavior for: " + url);
|
||||
!threw || resolve();
|
||||
});
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
//
|
||||
// Perform some loads and make sure they work correctly.
|
||||
//
|
||||
testLoad.bind(null, 'moz-extension://cherise', navigateFromChromeWithLocation)()
|
||||
.then(testLoad.bind(null, 'moz-extension://cherise', navigateFromChromeWithWebNav))
|
||||
.then(testLoad.bind(null, 'moz-extension://cherise', navigateWithLocation, /* shouldThrow = */ true))
|
||||
.then(setWhitelistCallback.bind(null, /cherise/))
|
||||
.then(testLoad.bind(null, 'moz-extension://cherise', navigateWithLocation))
|
||||
.then(testLoad.bind(null, 'moz-extension://liebchen', navigateWithLocation, /* shouldThrow = */ true))
|
||||
.then(setWhitelistCallback.bind(null, /cherise|liebchen/))
|
||||
.then(testLoad.bind(null, 'moz-extension://liebchen', navigateWithLocation))
|
||||
.then(testLoad.bind(null, 'moz-extension://liebchen', navigateWithSrc))
|
||||
.then(testLoad.bind(null, 'moz-extension://cherise', navigateWithSrc))
|
||||
.then(SimpleTest.finish.bind(SimpleTest),
|
||||
function(e) { ok(false, "rejected promise: " + e); SimpleTest.finish() }
|
||||
);
|
||||
});
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1161831">Mozilla Bug 1161831</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -39,14 +39,16 @@ struct ChromePackage
|
|||
}
|
||||
};
|
||||
|
||||
struct ResourceMapping
|
||||
struct SubstitutionMapping
|
||||
{
|
||||
nsCString resource;
|
||||
nsCString scheme;
|
||||
nsCString path;
|
||||
SerializedURI resolvedURI;
|
||||
|
||||
bool operator ==(const ResourceMapping& rhs) const
|
||||
bool operator ==(const SubstitutionMapping& rhs) const
|
||||
{
|
||||
return resource.Equals(rhs.resource) &&
|
||||
return scheme.Equals(rhs.scheme) &&
|
||||
path.Equals(rhs.path) &&
|
||||
resolvedURI == rhs.resolvedURI;
|
||||
}
|
||||
};
|
||||
|
@ -134,24 +136,27 @@ struct ParamTraits<ChromePackage>
|
|||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<ResourceMapping>
|
||||
struct ParamTraits<SubstitutionMapping>
|
||||
{
|
||||
typedef ResourceMapping paramType;
|
||||
typedef SubstitutionMapping paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.resource);
|
||||
WriteParam(aMsg, aParam.scheme);
|
||||
WriteParam(aMsg, aParam.path);
|
||||
WriteParam(aMsg, aParam.resolvedURI);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
nsCString resource;
|
||||
nsCString scheme, path;
|
||||
SerializedURI resolvedURI;
|
||||
|
||||
if (ReadParam(aMsg, aIter, &resource) &&
|
||||
if (ReadParam(aMsg, aIter, &scheme) &&
|
||||
ReadParam(aMsg, aIter, &path) &&
|
||||
ReadParam(aMsg, aIter, &resolvedURI)) {
|
||||
aResult->resource = resource;
|
||||
aResult->scheme = scheme;
|
||||
aResult->path = path;
|
||||
aResult->resolvedURI = resolvedURI;
|
||||
return true;
|
||||
}
|
||||
|
@ -160,7 +165,9 @@ struct ParamTraits<ResourceMapping>
|
|||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%s, %s, %u]", aParam.resource.get(),
|
||||
aLog->append(StringPrintf(L"[%s://%s, %s, %u]",
|
||||
aParam.scheme.get(),
|
||||
aParam.path.get(),
|
||||
aParam.resolvedURI.spec.get()));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -445,7 +445,7 @@ nsChromeRegistryChrome::SendRegisteredChrome(
|
|||
mozilla::dom::PContentParent* aParent)
|
||||
{
|
||||
InfallibleTArray<ChromePackage> packages;
|
||||
InfallibleTArray<ResourceMapping> resources;
|
||||
InfallibleTArray<SubstitutionMapping> resources;
|
||||
InfallibleTArray<OverrideMapping> overrides;
|
||||
|
||||
EnumerationArgs args = {
|
||||
|
|
|
@ -17,7 +17,7 @@ nsChromeRegistryContent::nsChromeRegistryContent()
|
|||
void
|
||||
nsChromeRegistryContent::RegisterRemoteChrome(
|
||||
const InfallibleTArray<ChromePackage>& aPackages,
|
||||
const InfallibleTArray<ResourceMapping>& aResources,
|
||||
const InfallibleTArray<SubstitutionMapping>& aSubstitutions,
|
||||
const InfallibleTArray<OverrideMapping>& aOverrides,
|
||||
const nsACString& aLocale,
|
||||
bool aReset)
|
||||
|
@ -36,9 +36,9 @@ nsChromeRegistryContent::RegisterRemoteChrome(
|
|||
RegisterPackage(aPackages[i]);
|
||||
}
|
||||
|
||||
for (uint32_t i = aResources.Length(); i > 0; ) {
|
||||
for (uint32_t i = aSubstitutions.Length(); i > 0; ) {
|
||||
--i;
|
||||
RegisterResource(aResources[i]);
|
||||
RegisterSubstitution(aSubstitutions[i]);
|
||||
}
|
||||
|
||||
for (uint32_t i = aOverrides.Length(); i > 0; ) {
|
||||
|
@ -94,32 +94,32 @@ nsChromeRegistryContent::RegisterPackage(const ChromePackage& aPackage)
|
|||
}
|
||||
|
||||
void
|
||||
nsChromeRegistryContent::RegisterResource(const ResourceMapping& aResource)
|
||||
nsChromeRegistryContent::RegisterSubstitution(const SubstitutionMapping& aSubstitution)
|
||||
{
|
||||
nsCOMPtr<nsIIOService> io (do_GetIOService());
|
||||
if (!io)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIProtocolHandler> ph;
|
||||
nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
|
||||
nsresult rv = io->GetProtocolHandler(aSubstitution.scheme.get(), getter_AddRefs(ph));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIResProtocolHandler> rph (do_QueryInterface(ph));
|
||||
if (!rph)
|
||||
nsCOMPtr<nsISubstitutingProtocolHandler> sph (do_QueryInterface(ph));
|
||||
if (!sph)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIURI> resolvedURI;
|
||||
if (aResource.resolvedURI.spec.Length()) {
|
||||
if (aSubstitution.resolvedURI.spec.Length()) {
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(resolvedURI),
|
||||
aResource.resolvedURI.spec,
|
||||
aResource.resolvedURI.charset.get(),
|
||||
aSubstitution.resolvedURI.spec,
|
||||
aSubstitution.resolvedURI.charset.get(),
|
||||
nullptr, io);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
}
|
||||
|
||||
rv = rph->SetSubstitution(aResource.resource, resolvedURI);
|
||||
rv = sph->SetSubstitution(aSubstitution.path, resolvedURI);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "nsClassHashtable.h"
|
||||
|
||||
struct ChromePackage;
|
||||
struct ResourceMapping;
|
||||
struct SubstitutionMapping;
|
||||
struct OverrideMapping;
|
||||
|
||||
class nsChromeRegistryContent : public nsChromeRegistry
|
||||
|
@ -19,7 +19,7 @@ class nsChromeRegistryContent : public nsChromeRegistry
|
|||
nsChromeRegistryContent();
|
||||
|
||||
void RegisterRemoteChrome(const InfallibleTArray<ChromePackage>& aPackages,
|
||||
const InfallibleTArray<ResourceMapping>& aResources,
|
||||
const InfallibleTArray<SubstitutionMapping>& aResources,
|
||||
const InfallibleTArray<OverrideMapping>& aOverrides,
|
||||
const nsACString& aLocale,
|
||||
bool aReset);
|
||||
|
@ -41,7 +41,7 @@ class nsChromeRegistryContent : public nsChromeRegistry
|
|||
|
||||
void RegisterPackage(const ChromePackage& aPackage);
|
||||
void RegisterOverride(const OverrideMapping& aOverride);
|
||||
void RegisterResource(const ResourceMapping& aResource);
|
||||
void RegisterSubstitution(const SubstitutionMapping& aResource);
|
||||
|
||||
private:
|
||||
struct PackageEntry
|
||||
|
|
|
@ -300,6 +300,7 @@ GK_ATOM(digit, "digit")
|
|||
GK_ATOM(dir, "dir")
|
||||
GK_ATOM(dirAutoSetBy, "dirAutoSetBy")
|
||||
GK_ATOM(directionality, "directionality")
|
||||
GK_ATOM(directory, "directory")
|
||||
GK_ATOM(disableOutputEscaping, "disable-output-escaping")
|
||||
GK_ATOM(disabled, "disabled")
|
||||
GK_ATOM(disablehistory, "disablehistory")
|
||||
|
@ -2291,7 +2292,6 @@ GK_ATOM(containerRelevant, "container-relevant")
|
|||
GK_ATOM(contentinfo, "contentinfo")
|
||||
GK_ATOM(cycles, "cycles")
|
||||
GK_ATOM(datatable, "datatable")
|
||||
GK_ATOM(directory, "directory")
|
||||
GK_ATOM(eventFromInput, "event-from-input")
|
||||
GK_ATOM(grammar, "grammar")
|
||||
GK_ATOM(gridcell, "gridcell")
|
||||
|
|
|
@ -3778,10 +3778,10 @@ nsGlobalWindow::GetParent(ErrorResult& aError)
|
|||
NS_IMETHODIMP
|
||||
nsGlobalWindow::GetScriptableParent(nsIDOMWindow** aParent)
|
||||
{
|
||||
FORWARD_TO_INNER(GetScriptableParent, (aParent), NS_ERROR_UNEXPECTED);
|
||||
FORWARD_TO_OUTER(GetScriptableParent, (aParent), NS_ERROR_UNEXPECTED);
|
||||
|
||||
ErrorResult rv;
|
||||
nsCOMPtr<nsIDOMWindow> parent = GetParent(rv);
|
||||
nsCOMPtr<nsIDOMWindow> parent = GetParentOuter(rv);
|
||||
parent.forget(aParent);
|
||||
|
||||
return rv.StealNSResult();
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace mozilla {
|
|||
void
|
||||
WebGL2Context::DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLintptr offset)
|
||||
{
|
||||
MOZ_CRASH("Not Implemented.");
|
||||
GenerateWarning("drawRangeElements: Not Implemented.");
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -333,13 +333,13 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
|
|||
void
|
||||
WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
|
||||
{
|
||||
MOZ_CRASH("Not Implemented.");
|
||||
GenerateWarning("framebufferTextureLayer: Not Implemented.");
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat, GLenum pname, JS::MutableHandleValue retval)
|
||||
{
|
||||
MOZ_CRASH("Not Implemented.");
|
||||
GenerateWarning("getInternalformatParameter: Not Implemented.");
|
||||
}
|
||||
|
||||
// Map attachments intended for the default buffer, to attachments for a non-
|
||||
|
|
|
@ -431,7 +431,7 @@ WebGL2Context::TexSubImage3D(GLenum target, GLint level,
|
|||
GLenum format, GLenum type, dom::ImageData* data,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
MOZ_CRASH("Not Implemented.");
|
||||
GenerateWarning("texSubImage3D: Not implemented.");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -439,7 +439,7 @@ WebGL2Context::CopyTexSubImage3D(GLenum target, GLint level,
|
|||
GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
GLint x, GLint y, GLsizei width, GLsizei height)
|
||||
{
|
||||
MOZ_CRASH("Not Implemented.");
|
||||
GenerateWarning("copyTexSubImage3D: Not implemented.");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -447,7 +447,7 @@ WebGL2Context::CompressedTexImage3D(GLenum target, GLint level, GLenum internalf
|
|||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLint border, GLsizei imageSize, const dom::ArrayBufferView& data)
|
||||
{
|
||||
MOZ_CRASH("Not Implemented.");
|
||||
GenerateWarning("compressedTexImage3D: Not implemented.");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -455,7 +455,7 @@ WebGL2Context::CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset
|
|||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLenum format, GLsizei imageSize, const dom::ArrayBufferView& data)
|
||||
{
|
||||
MOZ_CRASH("Not Implemented.");
|
||||
GenerateWarning("compressedTexSubImage3D: Not implemented.");
|
||||
}
|
||||
|
||||
JS::Value
|
||||
|
|
|
@ -16,66 +16,6 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
typedef union { GLint i; GLfloat f; GLuint u; } fi_t;
|
||||
|
||||
static inline
|
||||
GLfloat PuntToFloat(GLint i)
|
||||
{
|
||||
fi_t tmp;
|
||||
tmp.i = i;
|
||||
return tmp.f;
|
||||
}
|
||||
|
||||
static inline
|
||||
GLfloat PuntToFloat(GLuint u)
|
||||
{
|
||||
fi_t tmp;
|
||||
tmp.u = u;
|
||||
return tmp.f;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGL2Context::ValidateAttribPointerType(bool integerMode, GLenum type,
|
||||
GLsizei* out_alignment, const char* info)
|
||||
{
|
||||
MOZ_ASSERT(out_alignment);
|
||||
|
||||
switch (type) {
|
||||
case LOCAL_GL_BYTE:
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
*out_alignment = 1;
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_SHORT:
|
||||
case LOCAL_GL_UNSIGNED_SHORT:
|
||||
*out_alignment = 2;
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_INT:
|
||||
case LOCAL_GL_UNSIGNED_INT:
|
||||
*out_alignment = 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!integerMode) {
|
||||
switch (type) {
|
||||
case LOCAL_GL_HALF_FLOAT:
|
||||
*out_alignment = 2;
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_FLOAT:
|
||||
case LOCAL_GL_FIXED:
|
||||
case LOCAL_GL_INT_2_10_10_10_REV:
|
||||
case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
|
||||
*out_alignment = 4;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorInvalidEnum("%s: invalid enum value 0x%x", info, type);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGL2Context::ValidateUniformMatrixTranspose(bool /*transpose*/, const char* /*info*/)
|
||||
{
|
||||
|
@ -83,42 +23,7 @@ WebGL2Context::ValidateUniformMatrixTranspose(bool /*transpose*/, const char* /*
|
|||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Uniforms and attributes
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride,
|
||||
GLintptr offset)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateAttribIndex(index, "vertexAttribIPointer"))
|
||||
return;
|
||||
|
||||
if (!ValidateAttribPointer(true, index, size, type, LOCAL_GL_FALSE, stride, offset,
|
||||
"vertexAttribIPointer"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mBoundVertexArray);
|
||||
mBoundVertexArray->EnsureAttrib(index);
|
||||
|
||||
InvalidateBufferFetching();
|
||||
|
||||
WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
|
||||
|
||||
vd.buf = mBoundArrayBuffer;
|
||||
vd.stride = stride;
|
||||
vd.size = size;
|
||||
vd.byteOffset = offset;
|
||||
vd.type = type;
|
||||
vd.normalized = false;
|
||||
vd.integer = true;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fVertexAttribIPointer(index, size, type, stride, reinterpret_cast<void*>(offset));
|
||||
}
|
||||
// Uniforms
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform1ui(WebGLUniformLocation* loc, GLuint v0)
|
||||
|
@ -339,85 +244,6 @@ WebGL2Context::UniformMatrix4x3fv_base(WebGLUniformLocation* loc, bool transpose
|
|||
gl->fUniformMatrix4x3fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (index || gl->IsGLES()) {
|
||||
MakeContextCurrent();
|
||||
gl->fVertexAttribI4i(index, x, y, z, w);
|
||||
} else {
|
||||
mVertexAttrib0Vector[0] = PuntToFloat(x);
|
||||
mVertexAttrib0Vector[1] = PuntToFloat(y);
|
||||
mVertexAttrib0Vector[2] = PuntToFloat(z);
|
||||
mVertexAttrib0Vector[3] = PuntToFloat(w);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribI4iv(GLuint index, size_t length, const GLint* v)
|
||||
{
|
||||
if (!ValidateAttribArraySetter("vertexAttribI4iv", 4, length))
|
||||
return;
|
||||
|
||||
if (index || gl->IsGLES()) {
|
||||
MakeContextCurrent();
|
||||
gl->fVertexAttribI4iv(index, v);
|
||||
} else {
|
||||
mVertexAttrib0Vector[0] = PuntToFloat(v[0]);
|
||||
mVertexAttrib0Vector[1] = PuntToFloat(v[1]);
|
||||
mVertexAttrib0Vector[2] = PuntToFloat(v[2]);
|
||||
mVertexAttrib0Vector[3] = PuntToFloat(v[3]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribI4iv(GLuint index, const dom::Sequence<GLint>& v)
|
||||
{
|
||||
VertexAttribI4iv(index, v.Length(), v.Elements());
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (index || gl->IsGLES()) {
|
||||
MakeContextCurrent();
|
||||
gl->fVertexAttribI4ui(index, x, y, z, w);
|
||||
} else {
|
||||
mVertexAttrib0Vector[0] = PuntToFloat(x);
|
||||
mVertexAttrib0Vector[1] = PuntToFloat(y);
|
||||
mVertexAttrib0Vector[2] = PuntToFloat(z);
|
||||
mVertexAttrib0Vector[3] = PuntToFloat(w);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribI4uiv(GLuint index, size_t length, const GLuint* v)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (index || gl->IsGLES()) {
|
||||
MakeContextCurrent();
|
||||
gl->fVertexAttribI4uiv(index, v);
|
||||
} else {
|
||||
mVertexAttrib0Vector[0] = PuntToFloat(v[0]);
|
||||
mVertexAttrib0Vector[1] = PuntToFloat(v[1]);
|
||||
mVertexAttrib0Vector[2] = PuntToFloat(v[2]);
|
||||
mVertexAttrib0Vector[3] = PuntToFloat(v[3]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribI4uiv(GLuint index, const dom::Sequence<GLuint>& v)
|
||||
{
|
||||
VertexAttribI4uiv(index, v.Length(), v.Elements());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Uniform Buffer Objects and Transform Feedback Buffers
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGL2Context.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
#include "WebGLVertexAttribData.h"
|
||||
|
||||
#include "mozilla/Casting.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
bool
|
||||
WebGL2Context::ValidateAttribPointerType(bool integerMode, GLenum type,
|
||||
GLsizei* out_alignment, const char* info)
|
||||
{
|
||||
MOZ_ASSERT(out_alignment);
|
||||
|
||||
switch (type) {
|
||||
case LOCAL_GL_BYTE:
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
*out_alignment = 1;
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_SHORT:
|
||||
case LOCAL_GL_UNSIGNED_SHORT:
|
||||
*out_alignment = 2;
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_INT:
|
||||
case LOCAL_GL_UNSIGNED_INT:
|
||||
*out_alignment = 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!integerMode) {
|
||||
switch (type) {
|
||||
case LOCAL_GL_HALF_FLOAT:
|
||||
*out_alignment = 2;
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_FLOAT:
|
||||
case LOCAL_GL_FIXED:
|
||||
case LOCAL_GL_INT_2_10_10_10_REV:
|
||||
case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
|
||||
*out_alignment = 4;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorInvalidEnum("%s: invalid enum value 0x%x", info, type);
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Vertex Attributes
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride,
|
||||
GLintptr offset)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateAttribIndex(index, "vertexAttribIPointer"))
|
||||
return;
|
||||
|
||||
if (!ValidateAttribPointer(true, index, size, type, LOCAL_GL_FALSE, stride, offset,
|
||||
"vertexAttribIPointer"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mBoundVertexArray);
|
||||
mBoundVertexArray->EnsureAttrib(index);
|
||||
|
||||
InvalidateBufferFetching();
|
||||
|
||||
WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
|
||||
vd.buf = mBoundArrayBuffer;
|
||||
vd.stride = stride;
|
||||
vd.size = size;
|
||||
vd.byteOffset = offset;
|
||||
vd.type = type;
|
||||
vd.normalized = false;
|
||||
vd.integer = true;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fVertexAttribIPointer(index, size, type, stride, reinterpret_cast<void*>(offset));
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateAttribIndex(index, "vertexAttribI4i"))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_INT;
|
||||
|
||||
if (index || gl->IsGLES()) {
|
||||
MakeContextCurrent();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribI4iv(GLuint index, size_t length, const GLint* v)
|
||||
{
|
||||
if (!ValidateAttribIndex(index, "vertexAttribI4iv"))
|
||||
return;
|
||||
|
||||
if (!ValidateAttribArraySetter("vertexAttribI4iv", 4, length))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_INT;
|
||||
|
||||
if (index || gl->IsGLES()) {
|
||||
MakeContextCurrent();
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribI4iv(GLuint index, const dom::Sequence<GLint>& v)
|
||||
{
|
||||
VertexAttribI4iv(index, v.Length(), v.Elements());
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateAttribIndex(index, "vertexAttribI4ui"))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_UNSIGNED_INT;
|
||||
|
||||
if (index || gl->IsGLES()) {
|
||||
MakeContextCurrent();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribI4uiv(GLuint index, size_t length, const GLuint* v)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateAttribIndex(index, "vertexAttribI4uiv"))
|
||||
return;
|
||||
|
||||
if (!ValidateAttribIndex(index, "vertexAttribI4uiv"))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_UNSIGNED_INT;
|
||||
|
||||
if (index || gl->IsGLES()) {
|
||||
MakeContextCurrent();
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::VertexAttribI4uiv(GLuint index, const dom::Sequence<GLuint>& v)
|
||||
{
|
||||
VertexAttribI4uiv(index, v.Length(), v.Elements());
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -901,6 +901,11 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
|
|||
return NS_ERROR_FAILURE; // exit without changing the value of mGeneration
|
||||
}
|
||||
|
||||
// increment the generation number - Do this early because later
|
||||
// in CreateOffscreenGL(), "default" objects are created that will
|
||||
// pick up the old generation.
|
||||
++mGeneration;
|
||||
|
||||
// Get some prefs for some preferred/overriden things
|
||||
NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
|
||||
|
||||
|
@ -949,9 +954,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
|
|||
mResetLayer = true;
|
||||
mOptionsFrozen = true;
|
||||
|
||||
// increment the generation number
|
||||
++mGeneration;
|
||||
|
||||
// Update our internal stuff:
|
||||
if (gl->WorkAroundDriverBugs() && gl->IsANGLE()) {
|
||||
if (!mOptions.alpha && gl->Caps().alpha)
|
||||
|
|
|
@ -1461,12 +1461,21 @@ protected:
|
|||
UniquePtr<FakeBlackTexture>& opaqueTextureScopedPtr,
|
||||
UniquePtr<FakeBlackTexture>& transparentTextureScopedPtr);
|
||||
|
||||
// Generic Vertex Attributes
|
||||
UniquePtr<GLenum[]> mVertexAttribType;
|
||||
GLfloat mVertexAttrib0Vector[4];
|
||||
GLfloat mFakeVertexAttrib0BufferObjectVector[4];
|
||||
size_t mFakeVertexAttrib0BufferObjectSize;
|
||||
GLuint mFakeVertexAttrib0BufferObject;
|
||||
WebGLVertexAttrib0Status mFakeVertexAttrib0BufferStatus;
|
||||
|
||||
void GetVertexAttribFloat(GLuint index, GLfloat* out_result);
|
||||
void GetVertexAttribInt(GLuint index, GLint* out_result);
|
||||
void GetVertexAttribUint(GLuint index, GLuint* out_result);
|
||||
JSObject* GetVertexAttribFloat32Array(JSContext* cx, GLuint index);
|
||||
JSObject* GetVertexAttribInt32Array(JSContext* cx, GLuint index);
|
||||
JSObject* GetVertexAttribUint32Array(JSContext* cx, GLuint index);
|
||||
|
||||
GLint mStencilRefFront;
|
||||
GLint mStencilRefBack;
|
||||
GLuint mStencilValueMaskFront;
|
||||
|
|
|
@ -159,6 +159,20 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
|
|||
return gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_dxt1) &&
|
||||
gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt3) &&
|
||||
gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt5);
|
||||
|
||||
case WebGLExtensionID::WEBGL_debug_renderer_info:
|
||||
{
|
||||
bool isEnabled = true;
|
||||
|
||||
#ifdef RELEASE_BUILD
|
||||
// Keep this disabled on Release and Beta for now. (see bug 1171228)
|
||||
isEnabled = false;
|
||||
#endif
|
||||
if (Preferences::GetBool("webgl.disable-debug-renderer-info", false))
|
||||
isEnabled = false;
|
||||
|
||||
return isEnabled;
|
||||
}
|
||||
case WebGLExtensionID::WEBGL_depth_texture:
|
||||
// WEBGL_depth_texture supports DEPTH_STENCIL textures
|
||||
if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil))
|
||||
|
|
|
@ -4,16 +4,19 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLContextUtils.h"
|
||||
#include "WebGLBuffer.h"
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLProgram.h"
|
||||
#include "WebGLFramebuffer.h"
|
||||
#include "WebGLRenderbuffer.h"
|
||||
#include "WebGLTexture.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsString.h"
|
||||
#include "WebGLBuffer.h"
|
||||
#include "WebGLContextUtils.h"
|
||||
#include "WebGLFramebuffer.h"
|
||||
#include "WebGLProgram.h"
|
||||
#include "WebGLRenderbuffer.h"
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLTexture.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -57,6 +60,18 @@ WebGLContext::Enable(GLenum cap)
|
|||
gl->fEnable(cap);
|
||||
}
|
||||
|
||||
static JS::Value
|
||||
StringValue(JSContext* cx, const nsAString& str, ErrorResult& rv)
|
||||
{
|
||||
JSString* jsStr = JS_NewUCStringCopyN(cx, str.BeginReading(), str.Length());
|
||||
if (!jsStr) {
|
||||
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
return JS::StringValue(jsStr);
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::GetStencilBits(GLint* out_stencilBits)
|
||||
{
|
||||
|
@ -176,19 +191,47 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
|||
}
|
||||
}
|
||||
|
||||
// Privileged string params exposed by WEBGL_debug_renderer_info:
|
||||
// Privileged string params exposed by WEBGL_debug_renderer_info.
|
||||
// The privilege check is done in WebGLContext::IsExtensionSupported.
|
||||
// So here we just have to check that the extension is enabled.
|
||||
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_debug_renderer_info)) {
|
||||
switch (pname) {
|
||||
case UNMASKED_VENDOR_WEBGL:
|
||||
case UNMASKED_RENDERER_WEBGL:
|
||||
GLenum glstringname = LOCAL_GL_NONE;
|
||||
if (pname == UNMASKED_VENDOR_WEBGL) {
|
||||
glstringname = LOCAL_GL_VENDOR;
|
||||
} else if (pname == UNMASKED_RENDERER_WEBGL) {
|
||||
glstringname = LOCAL_GL_RENDERER;
|
||||
{
|
||||
const char* overridePref = nullptr;
|
||||
GLenum driverEnum = LOCAL_GL_NONE;
|
||||
|
||||
switch (pname) {
|
||||
case UNMASKED_RENDERER_WEBGL:
|
||||
overridePref = "webgl.renderer-string-override";
|
||||
driverEnum = LOCAL_GL_RENDERER;
|
||||
break;
|
||||
case UNMASKED_VENDOR_WEBGL:
|
||||
overridePref = "webgl.vendor-string-override";
|
||||
driverEnum = LOCAL_GL_VENDOR;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("bad `pname`");
|
||||
}
|
||||
|
||||
bool hasRetVal = false;
|
||||
|
||||
nsAutoString ret;
|
||||
if (overridePref) {
|
||||
nsresult res = Preferences::GetString(overridePref, &ret);
|
||||
if (NS_SUCCEEDED(res) && ret.Length() > 0)
|
||||
hasRetVal = true;
|
||||
}
|
||||
|
||||
if (!hasRetVal) {
|
||||
const char* chars = reinterpret_cast<const char*>(gl->fGetString(driverEnum));
|
||||
ret = NS_ConvertASCIItoUTF16(chars);
|
||||
hasRetVal = true;
|
||||
}
|
||||
|
||||
return StringValue(cx, ret, rv);
|
||||
}
|
||||
const GLchar* string = (const GLchar*) gl->fGetString(glstringname);
|
||||
return StringValue(cx, string, rv);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1941,7 +1941,9 @@ WebGLContext::InitAndValidateGL()
|
|||
}
|
||||
|
||||
// Default value for all disabled vertex attributes is [0, 0, 0, 1]
|
||||
mVertexAttribType = MakeUnique<GLenum[]>(mGLMaxVertexAttribs);
|
||||
for (int32_t index = 0; index < mGLMaxVertexAttribs; ++index) {
|
||||
mVertexAttribType[index] = LOCAL_GL_FLOAT;
|
||||
VertexAttrib4f(index, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,72 @@
|
|||
#include "WebGLVertexArray.h"
|
||||
#include "WebGLVertexAttribData.h"
|
||||
|
||||
#include "mozilla/Casting.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
void
|
||||
WebGLContext::GetVertexAttribFloat(GLuint index, GLfloat* out_result)
|
||||
{
|
||||
if (index) {
|
||||
gl->fGetVertexAttribfv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, out_result);
|
||||
} else {
|
||||
out_result[0] = mVertexAttrib0Vector[0];
|
||||
out_result[1] = mVertexAttrib0Vector[1];
|
||||
out_result[2] = mVertexAttrib0Vector[2];
|
||||
out_result[3] = mVertexAttrib0Vector[3];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::GetVertexAttribInt(GLuint index, GLint* out_result)
|
||||
{
|
||||
if (index) {
|
||||
gl->fGetVertexAttribIiv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, out_result);
|
||||
} else {
|
||||
out_result[0] = BitwiseCast<GLint>(mVertexAttrib0Vector[0]);
|
||||
out_result[1] = BitwiseCast<GLint>(mVertexAttrib0Vector[1]);
|
||||
out_result[2] = BitwiseCast<GLint>(mVertexAttrib0Vector[2]);
|
||||
out_result[3] = BitwiseCast<GLint>(mVertexAttrib0Vector[3]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::GetVertexAttribUint(GLuint index, GLuint* out_result)
|
||||
{
|
||||
if (index) {
|
||||
gl->fGetVertexAttribIuiv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, out_result);
|
||||
} else {
|
||||
out_result[0] = BitwiseCast<GLuint>(mVertexAttrib0Vector[0]);
|
||||
out_result[1] = BitwiseCast<GLuint>(mVertexAttrib0Vector[1]);
|
||||
out_result[2] = BitwiseCast<GLuint>(mVertexAttrib0Vector[2]);
|
||||
out_result[3] = BitwiseCast<GLuint>(mVertexAttrib0Vector[3]);
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WebGLContext::GetVertexAttribFloat32Array(JSContext* cx, GLuint index)
|
||||
{
|
||||
GLfloat attrib[4];
|
||||
GetVertexAttribFloat(index, &attrib[0]);
|
||||
return dom::Float32Array::Create(cx, this, 4, attrib);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WebGLContext::GetVertexAttribInt32Array(JSContext* cx, GLuint index)
|
||||
{
|
||||
GLint attrib[4];
|
||||
GetVertexAttribInt(index, &attrib[0]);
|
||||
return dom::Int32Array::Create(cx, this, 4, attrib);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WebGLContext::GetVertexAttribUint32Array(JSContext* cx, GLuint index) {
|
||||
GLuint attrib[4];
|
||||
GetVertexAttribUint(index, &attrib[0]);
|
||||
return dom::Uint32Array::Create(cx, this, 4, attrib);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
|
||||
{
|
||||
|
@ -27,6 +91,8 @@ WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
|
|||
if (!ValidateAttribIndex(index, "vertexAttrib1f"))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_FLOAT;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (index) {
|
||||
|
@ -50,6 +116,8 @@ WebGLContext::VertexAttrib2f(GLuint index, GLfloat x0, GLfloat x1)
|
|||
if (!ValidateAttribIndex(index, "vertexAttrib2f"))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_FLOAT;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (index) {
|
||||
|
@ -73,6 +141,8 @@ WebGLContext::VertexAttrib3f(GLuint index, GLfloat x0, GLfloat x1, GLfloat x2)
|
|||
if (!ValidateAttribIndex(index, "vertexAttrib3f"))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_FLOAT;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (index) {
|
||||
|
@ -97,6 +167,8 @@ WebGLContext::VertexAttrib4f(GLuint index, GLfloat x0, GLfloat x1,
|
|||
if (!ValidateAttribIndex(index, "vertexAttrib4f"))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_FLOAT;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (index) {
|
||||
|
@ -122,6 +194,8 @@ WebGLContext::VertexAttrib1fv_base(GLuint index, uint32_t arrayLength,
|
|||
if (!ValidateAttribIndex(index, "vertexAttrib1fv"))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_FLOAT;
|
||||
|
||||
MakeContextCurrent();
|
||||
if (index) {
|
||||
gl->fVertexAttrib1fv(index, ptr);
|
||||
|
@ -145,6 +219,8 @@ WebGLContext::VertexAttrib2fv_base(GLuint index, uint32_t arrayLength,
|
|||
if (!ValidateAttribIndex(index, "vertexAttrib2fv"))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_FLOAT;
|
||||
|
||||
MakeContextCurrent();
|
||||
if (index) {
|
||||
gl->fVertexAttrib2fv(index, ptr);
|
||||
|
@ -168,6 +244,8 @@ WebGLContext::VertexAttrib3fv_base(GLuint index, uint32_t arrayLength,
|
|||
if (!ValidateAttribIndex(index, "vertexAttrib3fv"))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_FLOAT;
|
||||
|
||||
MakeContextCurrent();
|
||||
if (index) {
|
||||
gl->fVertexAttrib3fv(index, ptr);
|
||||
|
@ -191,6 +269,8 @@ WebGLContext::VertexAttrib4fv_base(GLuint index, uint32_t arrayLength,
|
|||
if (!ValidateAttribIndex(index, "vertexAttrib4fv"))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_FLOAT;
|
||||
|
||||
MakeContextCurrent();
|
||||
if (index) {
|
||||
gl->fVertexAttrib4fv(index, ptr);
|
||||
|
@ -259,71 +339,59 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
|
|||
MakeContextCurrent();
|
||||
|
||||
switch (pname) {
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
|
||||
return WebGLObjectAsJSValue(cx, mBoundVertexArray->mAttribs[index].buf.get(), rv);
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE:
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribs[index].stride);
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE:
|
||||
if (!mBoundVertexArray->mAttribs[index].enabled)
|
||||
return JS::Int32Value(4);
|
||||
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribs[index].size);
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE:
|
||||
if (!mBoundVertexArray->mAttribs[index].enabled)
|
||||
return JS::NumberValue(uint32_t(LOCAL_GL_FLOAT));
|
||||
|
||||
return JS::NumberValue(uint32_t(mBoundVertexArray->mAttribs[index].type));
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
|
||||
if (IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays))
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribs[index].divisor);
|
||||
break;
|
||||
|
||||
case LOCAL_GL_CURRENT_VERTEX_ATTRIB:
|
||||
{
|
||||
return WebGLObjectAsJSValue(cx, mBoundVertexArray->mAttribs[index].buf.get(), rv);
|
||||
}
|
||||
JS::RootedObject obj(cx);
|
||||
switch (mVertexAttribType[index]) {
|
||||
case LOCAL_GL_FLOAT:
|
||||
obj = GetVertexAttribFloat32Array(cx, index);
|
||||
break;
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE:
|
||||
{
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribs[index].stride);
|
||||
}
|
||||
case LOCAL_GL_INT:
|
||||
obj = GetVertexAttribInt32Array(cx, index);
|
||||
break;
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE:
|
||||
{
|
||||
if (!mBoundVertexArray->mAttribs[index].enabled)
|
||||
return JS::Int32Value(4);
|
||||
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribs[index].size);
|
||||
}
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE:
|
||||
{
|
||||
if (!mBoundVertexArray->mAttribs[index].enabled)
|
||||
return JS::NumberValue(uint32_t(LOCAL_GL_FLOAT));
|
||||
|
||||
return JS::NumberValue(uint32_t(mBoundVertexArray->mAttribs[index].type));
|
||||
}
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
|
||||
{
|
||||
if (IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays))
|
||||
{
|
||||
return JS::Int32Value(mBoundVertexArray->mAttribs[index].divisor);
|
||||
case LOCAL_GL_UNSIGNED_INT:
|
||||
obj = GetVertexAttribUint32Array(cx, index);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case LOCAL_GL_CURRENT_VERTEX_ATTRIB:
|
||||
{
|
||||
GLfloat vec[4] = {0, 0, 0, 1};
|
||||
if (index) {
|
||||
gl->fGetVertexAttribfv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, &vec[0]);
|
||||
} else {
|
||||
vec[0] = mVertexAttrib0Vector[0];
|
||||
vec[1] = mVertexAttrib0Vector[1];
|
||||
vec[2] = mVertexAttrib0Vector[2];
|
||||
vec[3] = mVertexAttrib0Vector[3];
|
||||
}
|
||||
JSObject* obj = dom::Float32Array::Create(cx, this, 4, vec);
|
||||
if (!obj) {
|
||||
if (!obj)
|
||||
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
return JS::ObjectOrNullValue(obj);
|
||||
}
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED:
|
||||
{
|
||||
return JS::BooleanValue(mBoundVertexArray->mAttribs[index].enabled);
|
||||
}
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED:
|
||||
return JS::BooleanValue(mBoundVertexArray->mAttribs[index].enabled);
|
||||
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
|
||||
{
|
||||
return JS::BooleanValue(mBoundVertexArray->mAttribs[index].normalized);
|
||||
}
|
||||
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
|
||||
return JS::BooleanValue(mBoundVertexArray->mAttribs[index].normalized);
|
||||
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ErrorInvalidEnumInfo("getVertexAttrib: parameter", pname);
|
||||
|
|
|
@ -67,6 +67,7 @@ UNIFIED_SOURCES += [
|
|||
'WebGL2ContextTransformFeedback.cpp',
|
||||
'WebGL2ContextUniforms.cpp',
|
||||
'WebGL2ContextVAOs.cpp',
|
||||
'WebGL2ContextVertices.cpp',
|
||||
'WebGLActiveInfo.cpp',
|
||||
'WebGLBuffer.cpp',
|
||||
'WebGLContext.cpp',
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
<html>
|
||||
<script>
|
||||
|
||||
var Cu = parent.Components.utils;
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
// This gives us `AppConstants` in the global scope.
|
||||
// We need this because we only expose debug_renderer_info #ifndef MOZ_RELEASE_BUILD.
|
||||
// This should match AppConstants.RELEASE_BUILD.
|
||||
|
||||
// This file has the portion of the test_webgl_renderer_info chrome mochitest
|
||||
// that has to run as non-chrome to check that this WebGL extension is not exposed to content
|
||||
|
||||
|
@ -28,30 +34,58 @@ function run() {
|
|||
const UNMASKED_VENDOR_WEBGL = 0x9245;
|
||||
const UNMASKED_RENDERER_WEBGL = 0x9246;
|
||||
|
||||
var shouldHaveRendererInfo = false;
|
||||
if (!AppConstants.RELEASE_BUILD)
|
||||
shouldHaveRendererInfo = true;
|
||||
|
||||
var canvas = document.createElement("canvas");
|
||||
var gl = canvas.getContext("experimental-webgl");
|
||||
|
||||
ok(!gl.getError(), "getError on newly created WebGL context should return NO_ERROR");
|
||||
|
||||
ok(!gl.getParameter(UNMASKED_VENDOR_WEBGL) && gl.getError() == gl.INVALID_ENUM,
|
||||
"Should not be able to query UNMASKED_VENDOR_WEBGL without having enabled the WEBGL_debug_renderer_info extension");
|
||||
"Should not be able to query UNMASKED_VENDOR_WEBGL without having enabled the"
|
||||
+ " WEBGL_debug_renderer_info extension");
|
||||
ok(!gl.getParameter(UNMASKED_RENDERER_WEBGL) && gl.getError() == gl.INVALID_ENUM,
|
||||
"Should not be able to query UNMASKED_RENDERER_WEBGL without having enabled the WEBGL_debug_renderer_info extension");
|
||||
"Should not be able to query UNMASKED_RENDERER_WEBGL without having enabled the"
|
||||
+ " WEBGL_debug_renderer_info extension");
|
||||
|
||||
var exts = gl.getSupportedExtensions();
|
||||
ok(exts.indexOf("WEBGL_debug_renderer_info") == -1,
|
||||
"WEBGL_debug_renderer_info should not be listed by getSupportedExtensions in non-chrome contexts");
|
||||
var debugRendererInfoExtension = gl.getExtension("WEBGL_debug_renderer_info");
|
||||
ok(!debugRendererInfoExtension,
|
||||
"WEBGL_debug_renderer_info should not be available through getExtension in non-chrome contexts");
|
||||
if (shouldHaveRendererInfo) {
|
||||
ok(exts.indexOf("WEBGL_debug_renderer_info") != -1,
|
||||
"WEBGL_debug_renderer_info should be listed by getSupportedExtensions in"
|
||||
+ " non-chrome contexts on non-RELEASE_BUILDs");
|
||||
|
||||
ok(!gl.getParameter(UNMASKED_VENDOR_WEBGL) && gl.getError() == gl.INVALID_ENUM,
|
||||
"Should not be able to query UNMASKED_VENDOR_WEBGL if enabling WEBGL_debug_renderer_info failed");
|
||||
ok(!gl.getParameter(UNMASKED_RENDERER_WEBGL) && gl.getError() == gl.INVALID_ENUM,
|
||||
"Should not be able to query UNMASKED_RENDERER_WEBGL if enabling WEBGL_debug_renderer_info failed");
|
||||
var ext = gl.getExtension("WEBGL_debug_renderer_info");
|
||||
ok(!!ext,
|
||||
"WEBGL_debug_renderer_info should be available through getExtension in non-chrome"
|
||||
+ " contexts on non-RELEASE_BUILDs");
|
||||
|
||||
ok(gl.getParameter(UNMASKED_VENDOR_WEBGL) && gl.getError() == gl.NO_ERROR,
|
||||
"Should be able to query UNMASKED_VENDOR_WEBGL if enabling"
|
||||
+ " WEBGL_debug_renderer_info succeeded");
|
||||
ok(gl.getParameter(UNMASKED_RENDERER_WEBGL) && gl.getError() == gl.NO_ERROR,
|
||||
"Should be able to query UNMASKED_RENDERER_WEBGL if enabling"
|
||||
+ " WEBGL_debug_renderer_info succeeded");
|
||||
} else {
|
||||
ok(exts.indexOf("WEBGL_debug_renderer_info") == -1,
|
||||
"WEBGL_debug_renderer_info should not be listed by getSupportedExtensions in"
|
||||
+ " non-chrome contexts");
|
||||
var ext = gl.getExtension("WEBGL_debug_renderer_info");
|
||||
ok(!ext,
|
||||
"WEBGL_debug_renderer_info should not be available through getExtension in"
|
||||
+ " non-chrome contexts");
|
||||
|
||||
ok(!gl.getParameter(UNMASKED_VENDOR_WEBGL) && gl.getError() == gl.INVALID_ENUM,
|
||||
"Should not be able to query UNMASKED_VENDOR_WEBGL if enabling"
|
||||
+ " WEBGL_debug_renderer_info failed");
|
||||
ok(!gl.getParameter(UNMASKED_RENDERER_WEBGL) && gl.getError() == gl.INVALID_ENUM,
|
||||
"Should not be able to query UNMASKED_RENDERER_WEBGL if enabling"
|
||||
+ " WEBGL_debug_renderer_info failed");
|
||||
|
||||
}
|
||||
window.postMessage({allTestsFinished: true}, "*");
|
||||
}
|
||||
|
||||
</script>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -43,13 +43,13 @@ function checkChromeCase(canvas) {
|
|||
var exts = gl.getSupportedExtensions();
|
||||
ok(exts.indexOf("WEBGL_debug_renderer_info") != -1,
|
||||
"WEBGL_debug_renderer_info should be listed by getSupportedExtensions in chrome contexts");
|
||||
var debugRendererInfoExtension = gl.getExtension("WEBGL_debug_renderer_info");
|
||||
ok(debugRendererInfoExtension,
|
||||
var ext = gl.getExtension("WEBGL_debug_renderer_info");
|
||||
ok(ext,
|
||||
"WEBGL_debug_renderer_info should be available through getExtension in chrome contexts");
|
||||
|
||||
ok(debugRendererInfoExtension.UNMASKED_VENDOR_WEBGL == UNMASKED_VENDOR_WEBGL,
|
||||
ok(ext.UNMASKED_VENDOR_WEBGL == UNMASKED_VENDOR_WEBGL,
|
||||
"UNMASKED_VENDOR_WEBGL has the correct value");
|
||||
ok(debugRendererInfoExtension.UNMASKED_RENDERER_WEBGL == UNMASKED_RENDERER_WEBGL,
|
||||
ok(ext.UNMASKED_RENDERER_WEBGL == UNMASKED_RENDERER_WEBGL,
|
||||
"UNMASKED_RENDERER_WEBGL has the correct value");
|
||||
|
||||
ok(isNonEmptyString(gl.getParameter(UNMASKED_VENDOR_WEBGL)) && gl.getError() == gl.NO_ERROR,
|
||||
|
@ -67,7 +67,7 @@ function main()
|
|||
// Now run the non-chrome code to verify the security of this WebGL chrome-only extension.
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.src = "http://mochi.test:8888/chrome/dom/canvas/test/chrome/nonchrome_webgl_debug_renderer_info.html";
|
||||
iframe.src = "chrome://mochitests/content/chrome/dom/canvas/test/chrome/nonchrome_webgl_debug_renderer_info.html";
|
||||
|
||||
iframe.onload = function () {
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ skip-if = (os == 'b2g') || buildapp == 'mulet' # Mulet - bug 1093639 (crashes in
|
|||
skip-if = android_version == '10' || android_version == '18' #Android 2.3 and 4.3 aws only; bug 1030942
|
||||
[webgl-mochitest/test_noprog_draw.html]
|
||||
[webgl-mochitest/test_privileged_exts.html]
|
||||
[webgl-mochitest/test_renderer_strings.html]
|
||||
[webgl-mochitest/test_texsubimage_float.html]
|
||||
[webgl-mochitest/test_uninit_data.html]
|
||||
[webgl-mochitest/test_webgl_available.html]
|
||||
|
|
|
@ -24,7 +24,7 @@ function TestExt(gl, name) {
|
|||
}
|
||||
|
||||
// Privileged extensions:
|
||||
TestExt(gl, 'WEBGL_debug_renderer_info');
|
||||
TestExt(gl, 'WEBGL_debug_shaders');
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
|
||||
function AssertError(gl, expected, info) {
|
||||
var actual = gl.getError();
|
||||
while (gl.getError()) {}
|
||||
|
||||
ok(actual == expected,
|
||||
'For ' + info + ', expected 0x' + expected.toString(16) + ', got 0x'
|
||||
+ actual.toString(16));
|
||||
}
|
||||
|
||||
var gl;
|
||||
|
||||
var RENDERER_OVERRIDE = 'overridden renderer';
|
||||
var VENDOR_OVERRIDE = 'overridden vendor';
|
||||
|
||||
function TestExt() {
|
||||
var ext = gl.getExtension('WEBGL_debug_renderer_info');
|
||||
ok(ext, 'Should have access to \'WEBGL_debug_renderer_info\'.');
|
||||
AssertError(gl, 0, 'start of test');
|
||||
|
||||
var renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL);
|
||||
AssertError(gl, 0, 'UNMASKED_RENDERER_WEBGL');
|
||||
ok(renderer,
|
||||
'UNMASKED_RENDERER_WEBGL value should not be empty, was \'' + renderer + '\'');
|
||||
|
||||
var vendor = gl.getParameter(ext.UNMASKED_VENDOR_WEBGL);
|
||||
AssertError(gl, 0, 'UNMASKED_VENDOR_WEBGL');
|
||||
ok(vendor, 'UNMASKED_VENDOR_WEBGL value should not be empty, was \'' + vendor + '\'');
|
||||
|
||||
var prefArrArr = [
|
||||
['webgl.renderer-string-override', RENDERER_OVERRIDE],
|
||||
['webgl.vendor-string-override', VENDOR_OVERRIDE],
|
||||
];
|
||||
var prefEnv = {'set': prefArrArr};
|
||||
SpecialPowers.pushPrefEnv(prefEnv, TestOverrides);
|
||||
}
|
||||
|
||||
function TestOverrides() {
|
||||
var ext = gl.getExtension('WEBGL_debug_renderer_info');
|
||||
ok(ext, 'Should have access to \'WEBGL_debug_renderer_info\'.');
|
||||
AssertError(gl, 0, 'start of test');
|
||||
|
||||
var renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL);
|
||||
AssertError(gl, 0, 'UNMASKED_RENDERER_WEBGL');
|
||||
ok(renderer == RENDERER_OVERRIDE,
|
||||
'UNMASKED_RENDERER_WEBGL value should be \'' + RENDERER_OVERRIDE + '\', was \''
|
||||
+ renderer + '\'');
|
||||
|
||||
var vendor = gl.getParameter(ext.UNMASKED_VENDOR_WEBGL);
|
||||
AssertError(gl, 0, 'UNMASKED_VENDOR_WEBGL');
|
||||
ok(vendor == VENDOR_OVERRIDE,
|
||||
'UNMASKED_VENDOR_WEBGL value should be \'' + VENDOR_OVERRIDE + '\', was \'' + vendor
|
||||
+ '\'');
|
||||
|
||||
var prefArrArr = [
|
||||
['webgl.disable-debug-renderer-info', true],
|
||||
];
|
||||
var prefEnv = {'set': prefArrArr};
|
||||
SpecialPowers.pushPrefEnv(prefEnv, TestDisable);
|
||||
}
|
||||
|
||||
function TestDisable() {
|
||||
var ext = gl.getExtension('WEBGL_debug_renderer_info');
|
||||
ok(!ext, 'Should not have access to \'WEBGL_debug_renderer_info\'.');
|
||||
|
||||
ok(true, 'Test complete.');
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
(function() {
|
||||
var canvas = document.createElement('canvas');
|
||||
gl = canvas.getContext('experimental-webgl');
|
||||
if (!gl) {
|
||||
todo(gl, 'Get WebGL working here first.');
|
||||
ok(true, 'Test complete.');
|
||||
return;
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var prefArrArr = [
|
||||
['webgl.disable-debug-renderer-info', false],
|
||||
];
|
||||
var prefEnv = {'set': prefArrArr};
|
||||
SpecialPowers.pushPrefEnv(prefEnv, TestExt);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1074,10 +1074,8 @@ IMEContentObserver::SelectionChangeEvent::Run()
|
|||
}
|
||||
|
||||
IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE);
|
||||
notification.mSelectionChangeData.mOffset =
|
||||
selection.mReply.mOffset;
|
||||
notification.mSelectionChangeData.mLength =
|
||||
selection.mReply.mString.Length();
|
||||
notification.mSelectionChangeData.mOffset = selection.mReply.mOffset;
|
||||
*notification.mSelectionChangeData.mString = selection.mReply.mString;
|
||||
notification.mSelectionChangeData.SetWritingMode(
|
||||
selection.GetWritingMode());
|
||||
notification.mSelectionChangeData.mReversed = selection.mReply.mReversed;
|
||||
|
|
|
@ -4013,7 +4013,10 @@ HTMLMediaElement::NotifyOwnerDocumentActivityChangedInternal()
|
|||
mDecoder->NotifyOwnerActivityChanged();
|
||||
}
|
||||
|
||||
bool pauseElement = !IsActive() || ComputedMuted();
|
||||
bool pauseElement = !IsActive();
|
||||
#ifdef MOZ_B2G
|
||||
pauseElement |= ComputedMuted();
|
||||
#endif
|
||||
|
||||
SuspendOrResumeElement(pauseElement, !IsActive());
|
||||
|
||||
|
|
|
@ -12315,6 +12315,8 @@ Database::RegisterTransaction(TransactionBase* aTransaction)
|
|||
MOZ_ASSERT(aTransaction);
|
||||
MOZ_ASSERT(!mTransactions.GetEntry(aTransaction));
|
||||
MOZ_ASSERT(mDirectoryLock);
|
||||
MOZ_ASSERT(!mInvalidated);
|
||||
MOZ_ASSERT(!mClosed);
|
||||
|
||||
if (NS_WARN_IF(!mTransactions.PutEntry(aTransaction, fallible))) {
|
||||
return false;
|
||||
|
@ -18693,6 +18695,10 @@ FactoryOp::Run()
|
|||
SendResults();
|
||||
return NS_OK;
|
||||
|
||||
// We raced, no need to crash.
|
||||
case State_Completed:
|
||||
return NS_OK;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad state!");
|
||||
}
|
||||
|
@ -18750,6 +18756,14 @@ FactoryOp::ActorDestroy(ActorDestroyReason aWhy)
|
|||
AssertIsOnBackgroundThread();
|
||||
|
||||
NoteActorDestroyed();
|
||||
|
||||
if (mState == State_WaitingForTransactionsToComplete) {
|
||||
// We didn't get an opportunity to clean up. Do that now.
|
||||
mState = State_SendingResults;
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
SendResults();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -19346,9 +19360,10 @@ OpenDatabaseOp::NoteDatabaseClosed(Database* aDatabase)
|
|||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aDatabase);
|
||||
MOZ_ASSERT(mState == State_WaitingForOtherDatabasesToClose ||
|
||||
mState == State_WaitingForTransactionsToComplete ||
|
||||
mState == State_DatabaseWorkVersionChange);
|
||||
|
||||
if (mState == State_DatabaseWorkVersionChange) {
|
||||
if (mState != State_WaitingForOtherDatabasesToClose) {
|
||||
MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
|
||||
MOZ_ASSERT(mRequestedVersion >
|
||||
aDatabase->Metadata()->mCommonMetadata.version(),
|
||||
|
@ -19412,7 +19427,8 @@ OpenDatabaseOp::DispatchToWorkThread()
|
|||
MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
|
||||
|
||||
if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
|
||||
IsActorDestroyed()) {
|
||||
IsActorDestroyed() ||
|
||||
mDatabase->IsInvalidated()) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ function testSteps()
|
|||
ok(false, "Should not receive a blocked event");
|
||||
};
|
||||
|
||||
event = yield undefined;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Got success event");
|
||||
is(databases.length, 0, "All databases with version 1 were closed");
|
||||
|
@ -145,6 +145,35 @@ function testSteps()
|
|||
|
||||
is(event.type, "success", "Got success event");
|
||||
|
||||
// Test 3: A blocked database left in that state should not hang shutdown.
|
||||
info("Opening 1 database with version 1");
|
||||
|
||||
request = indexedDB.open(databaseName, 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onblocked = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Got success event");
|
||||
|
||||
db = request.result;
|
||||
is(db.version, 1, "Got version 1");
|
||||
|
||||
info("Opening database with version 2");
|
||||
|
||||
request = indexedDB.open(databaseName, 2);
|
||||
request.onerror = function(e) {
|
||||
e.preventDefault();
|
||||
};
|
||||
request.onsuccess = errorHandler;
|
||||
|
||||
request.onblocked = grabEventAndContinueHandler;
|
||||
|
||||
event = yield undefined;
|
||||
ok(true, "Got blocked");
|
||||
// Just allow this to remain blocked ...
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
||||
|
|
|
@ -1838,7 +1838,7 @@ ContentChild::DeallocPWebrtcGlobalChild(PWebrtcGlobalChild *aActor)
|
|||
|
||||
bool
|
||||
ContentChild::RecvRegisterChrome(InfallibleTArray<ChromePackage>&& packages,
|
||||
InfallibleTArray<ResourceMapping>&& resources,
|
||||
InfallibleTArray<SubstitutionMapping>&& resources,
|
||||
InfallibleTArray<OverrideMapping>&& overrides,
|
||||
const nsCString& locale,
|
||||
const bool& reset)
|
||||
|
@ -1866,8 +1866,8 @@ ContentChild::RecvRegisterChromeItem(const ChromeRegistryItem& item)
|
|||
chromeRegistry->RegisterOverride(item.get_OverrideMapping());
|
||||
break;
|
||||
|
||||
case ChromeRegistryItem::TResourceMapping:
|
||||
chromeRegistry->RegisterResource(item.get_ResourceMapping());
|
||||
case ChromeRegistryItem::TSubstitutionMapping:
|
||||
chromeRegistry->RegisterSubstitution(item.get_SubstitutionMapping());
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
struct ChromePackage;
|
||||
class nsIObserver;
|
||||
struct ResourceMapping;
|
||||
struct SubstitutionMapping;
|
||||
struct OverrideMapping;
|
||||
class nsIDomainPolicy;
|
||||
|
||||
|
@ -282,7 +282,7 @@ public:
|
|||
virtual bool DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor) override;
|
||||
|
||||
virtual bool RecvRegisterChrome(InfallibleTArray<ChromePackage>&& packages,
|
||||
InfallibleTArray<ResourceMapping>&& resources,
|
||||
InfallibleTArray<SubstitutionMapping>&& resources,
|
||||
InfallibleTArray<OverrideMapping>&& overrides,
|
||||
const nsCString& locale,
|
||||
const bool& reset) override;
|
||||
|
|
|
@ -260,13 +260,13 @@ parent:
|
|||
returns (bool noCompositionEvent, nsString composition);
|
||||
|
||||
/**
|
||||
* OnEventNeedingAckReceived() is called when a child process dispatches a
|
||||
* OnEventNeedingAckHandled() is called after a child process dispatches a
|
||||
* composition event or a selection event which is sent from the parent
|
||||
* process.
|
||||
*
|
||||
* message The message value of the received event.
|
||||
* message The message value of the handled event.
|
||||
*/
|
||||
prio(urgent) async OnEventNeedingAckReceived(uint32_t message);
|
||||
prio(urgent) async OnEventNeedingAckHandled(uint32_t message);
|
||||
|
||||
/**
|
||||
* Tells chrome to start plugin IME. If this results in a string getting
|
||||
|
|
|
@ -71,7 +71,7 @@ include "mozilla/dom/indexedDB/SerializationHelpers.h";
|
|||
using GeoPosition from "nsGeoPositionIPCSerialiser.h";
|
||||
|
||||
using struct ChromePackage from "mozilla/chrome/RegistryMessageUtils.h";
|
||||
using struct ResourceMapping from "mozilla/chrome/RegistryMessageUtils.h";
|
||||
using struct SubstitutionMapping from "mozilla/chrome/RegistryMessageUtils.h";
|
||||
using struct OverrideMapping from "mozilla/chrome/RegistryMessageUtils.h";
|
||||
using base::ChildPrivileges from "base/process_util.h";
|
||||
using base::ProcessId from "base/process.h";
|
||||
|
@ -94,7 +94,7 @@ union ChromeRegistryItem
|
|||
{
|
||||
ChromePackage;
|
||||
OverrideMapping;
|
||||
ResourceMapping;
|
||||
SubstitutionMapping;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -521,7 +521,7 @@ child:
|
|||
|
||||
PTestShell();
|
||||
|
||||
RegisterChrome(ChromePackage[] packages, ResourceMapping[] resources,
|
||||
RegisterChrome(ChromePackage[] packages, SubstitutionMapping[] substitutions,
|
||||
OverrideMapping[] overrides, nsCString locale, bool reset);
|
||||
RegisterChromeItem(ChromeRegistryItem item);
|
||||
|
||||
|
|
|
@ -2230,20 +2230,20 @@ TabChild::RecvKeyEvent(const nsString& aType,
|
|||
bool
|
||||
TabChild::RecvCompositionEvent(const WidgetCompositionEvent& event)
|
||||
{
|
||||
unused << SendOnEventNeedingAckReceived(event.message);
|
||||
WidgetCompositionEvent localEvent(event);
|
||||
localEvent.widget = mPuppetWidget;
|
||||
APZCCallbackHelper::DispatchWidgetEvent(localEvent);
|
||||
unused << SendOnEventNeedingAckHandled(event.message);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvSelectionEvent(const WidgetSelectionEvent& event)
|
||||
{
|
||||
unused << SendOnEventNeedingAckReceived(event.message);
|
||||
WidgetSelectionEvent localEvent(event);
|
||||
localEvent.widget = mPuppetWidget;
|
||||
APZCCallbackHelper::DispatchWidgetEvent(localEvent);
|
||||
unused << SendOnEventNeedingAckHandled(event.message);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2093,13 +2093,13 @@ TabParent::RecvNotifyIMEPositionChange(const ContentCache& aContentCache,
|
|||
const nsIMEUpdatePreference updatePreference =
|
||||
widget->GetIMEUpdatePreference();
|
||||
if (updatePreference.WantPositionChanged()) {
|
||||
IMEStateManager::NotifyIME(aIMENotification, widget, true);
|
||||
mContentCache.MaybeNotifyIME(widget, aIMENotification);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvOnEventNeedingAckReceived(const uint32_t& aMessage)
|
||||
TabParent::RecvOnEventNeedingAckHandled(const uint32_t& aMessage)
|
||||
{
|
||||
// This is called when the child process receives WidgetCompositionEvent or
|
||||
// WidgetSelectionEvent.
|
||||
|
@ -2108,10 +2108,10 @@ TabParent::RecvOnEventNeedingAckReceived(const uint32_t& aMessage)
|
|||
return true;
|
||||
}
|
||||
|
||||
// While calling OnEventNeedingAckReceived(), TabParent *might* be destroyed
|
||||
// While calling OnEventNeedingAckHandled(), TabParent *might* be destroyed
|
||||
// since it may send notifications to IME.
|
||||
nsRefPtr<TabParent> kungFuDeathGrip(this);
|
||||
mContentCache.OnEventNeedingAckReceived(widget, aMessage);
|
||||
mContentCache.OnEventNeedingAckHandled(widget, aMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ public:
|
|||
bool* aConsumedByIME) override;
|
||||
virtual bool RecvNotifyIMEPositionChange(const ContentCache& aContentCache,
|
||||
const widget::IMENotification& aEventMessage) override;
|
||||
virtual bool RecvOnEventNeedingAckReceived(const uint32_t& aMessage) override;
|
||||
virtual bool RecvOnEventNeedingAckHandled(const uint32_t& aMessage) override;
|
||||
virtual bool RecvEndIMEComposition(const bool& aCancel,
|
||||
bool* aNoCompositionEvent,
|
||||
nsString* aComposition) override;
|
||||
|
|
|
@ -38,26 +38,27 @@ AudioSink::AudioSink(MediaDecoderStateMachine* aStateMachine,
|
|||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRefPtr<GenericPromise>
|
||||
AudioSink::Init()
|
||||
{
|
||||
nsRefPtr<GenericPromise> p = mEndPromise.Ensure(__func__);
|
||||
nsresult rv = NS_NewNamedThread("Media Audio",
|
||||
getter_AddRefs(mThread),
|
||||
nullptr,
|
||||
MEDIA_THREAD_STACK_SIZE);
|
||||
if (NS_FAILED(rv)) {
|
||||
mStateMachine->OnAudioSinkError();
|
||||
return rv;
|
||||
mEndPromise.Reject(rv, __func__);
|
||||
return p;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &AudioSink::AudioLoop);
|
||||
rv = mThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
mStateMachine->OnAudioSinkError();
|
||||
return rv;
|
||||
mEndPromise.Reject(rv, __func__);
|
||||
return p;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return p;
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
@ -100,7 +101,10 @@ AudioSink::Shutdown()
|
|||
{
|
||||
mThread->Shutdown();
|
||||
mThread = nullptr;
|
||||
MOZ_ASSERT(!mAudioStream);
|
||||
if (mAudioStream) {
|
||||
mAudioStream->Shutdown();
|
||||
mAudioStream = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -142,9 +146,10 @@ AudioSink::AudioLoop()
|
|||
AssertOnAudioThread();
|
||||
SINK_LOG("AudioLoop started");
|
||||
|
||||
if (NS_FAILED(InitializeAudioStream())) {
|
||||
nsresult rv = InitializeAudioStream();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Initializing AudioStream failed.");
|
||||
mStateMachine->DispatchOnAudioSinkError();
|
||||
mEndPromise.Reject(rv, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -233,16 +238,10 @@ void
|
|||
AudioSink::Cleanup()
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
nsRefPtr<AudioStream> audioStream;
|
||||
audioStream.swap(mAudioStream);
|
||||
// Suppress the callback when the stop is requested by MediaDecoderStateMachine.
|
||||
// See Bug 115334.
|
||||
if (!mStopAudioThread) {
|
||||
mStateMachine->DispatchOnAudioSinkComplete();
|
||||
}
|
||||
|
||||
ReentrantMonitorAutoExit exit(GetReentrantMonitor());
|
||||
audioStream->Shutdown();
|
||||
mEndPromise.Resolve(true, __func__);
|
||||
// Since the promise if resolved asynchronously, we don't shutdown
|
||||
// AudioStream here so MDSM::ResyncAudioClock can get the correct
|
||||
// audio position.
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "MediaDecoderReader.h"
|
||||
#include "mozilla/dom/AudioChannelBinding.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -23,7 +24,9 @@ public:
|
|||
AudioSink(MediaDecoderStateMachine* aStateMachine,
|
||||
int64_t aStartTime, AudioInfo aInfo, dom::AudioChannel aChannel);
|
||||
|
||||
nsresult Init();
|
||||
// Return a promise which will be resolved when AudioSink finishes playing,
|
||||
// or rejected if any error.
|
||||
nsRefPtr<GenericPromise> Init();
|
||||
|
||||
int64_t GetPosition();
|
||||
|
||||
|
@ -140,6 +143,8 @@ private:
|
|||
bool mSetPreservesPitch;
|
||||
|
||||
bool mPlaying;
|
||||
|
||||
MozPromiseHolder<GenericPromise> mEndPromise;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -186,17 +186,20 @@ static char const *const gWebMCodecs[7] = {
|
|||
"opus",
|
||||
nullptr
|
||||
};
|
||||
#endif
|
||||
|
||||
/* static */ bool
|
||||
DecoderTraits::IsWebMType(const nsACString& aType)
|
||||
{
|
||||
#ifdef MOZ_WEBM
|
||||
if (!MediaDecoder::IsWebMEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return CodecListContains(gWebMTypes, aType);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef MOZ_GSTREAMER
|
||||
static bool
|
||||
|
@ -205,10 +208,9 @@ IsGStreamerSupportedType(const nsACString& aMimeType)
|
|||
if (!MediaDecoder::IsGStreamerEnabled())
|
||||
return false;
|
||||
|
||||
#ifdef MOZ_WEBM
|
||||
if (DecoderTraits::IsWebMType(aMimeType) && !Preferences::GetBool("media.prefer-gstreamer", false))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (IsOggType(aMimeType) && !Preferences::GetBool("media.prefer-gstreamer", false))
|
||||
return false;
|
||||
|
||||
|
@ -355,6 +357,16 @@ IsMP4SupportedType(const nsACString& aType,
|
|||
MP4Decoder::CanHandleMediaType(aType, aCodecs, haveAAC, haveH264, haveMP3);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* static */ bool
|
||||
DecoderTraits::IsMP4Type(const nsACString& aType)
|
||||
{
|
||||
#ifdef MOZ_FMP4
|
||||
return IsMP4SupportedType(aType);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsMP3SupportedType(const nsACString& aType,
|
||||
const nsAString& aCodecs = EmptyString())
|
||||
|
@ -412,56 +424,44 @@ bool DecoderTraits::ShouldHandleMediaType(const char* aMIMEType)
|
|||
|
||||
/* static */
|
||||
CanPlayStatus
|
||||
DecoderTraits::CanHandleMediaType(const char* aMIMEType,
|
||||
bool aHaveRequestedCodecs,
|
||||
const nsAString& aRequestedCodecs)
|
||||
DecoderTraits::CanHandleCodecsType(const char* aMIMEType,
|
||||
const nsAString& aRequestedCodecs)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
char const* const* codecList = nullptr;
|
||||
CanPlayStatus result = CANPLAY_NO;
|
||||
#ifdef MOZ_RAW
|
||||
if (IsRawType(nsDependentCString(aMIMEType))) {
|
||||
codecList = gRawCodecs;
|
||||
result = CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
if (IsOggType(nsDependentCString(aMIMEType))) {
|
||||
codecList = MediaDecoder::IsOpusEnabled() ? gOggCodecsWithOpus : gOggCodecs;
|
||||
result = CANPLAY_MAYBE;
|
||||
}
|
||||
#ifdef MOZ_WAVE
|
||||
if (IsWaveType(nsDependentCString(aMIMEType))) {
|
||||
codecList = gWaveCodecs;
|
||||
result = CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
#if defined(MOZ_WEBM) && !defined(MOZ_OMX_WEBM_DECODER)
|
||||
#if !defined(MOZ_OMX_WEBM_DECODER)
|
||||
if (IsWebMType(nsDependentCString(aMIMEType))) {
|
||||
codecList = gWebMCodecs;
|
||||
result = CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_FMP4
|
||||
if (IsMP4SupportedType(nsDependentCString(aMIMEType),
|
||||
aRequestedCodecs)) {
|
||||
return aHaveRequestedCodecs ? CANPLAY_YES : CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
if (IsMP3SupportedType(nsDependentCString(aMIMEType),
|
||||
aRequestedCodecs)) {
|
||||
return aHaveRequestedCodecs ? CANPLAY_YES : CANPLAY_MAYBE;
|
||||
}
|
||||
#ifdef MOZ_GSTREAMER
|
||||
if (GStreamerDecoder::CanHandleMediaType(nsDependentCString(aMIMEType),
|
||||
aHaveRequestedCodecs ? &aRequestedCodecs : nullptr)) {
|
||||
if (aHaveRequestedCodecs)
|
||||
if (IsMP4Type(nsDependentCString(aMIMEType))) {
|
||||
if (IsMP4SupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
|
||||
return CANPLAY_YES;
|
||||
return CANPLAY_MAYBE;
|
||||
} else {
|
||||
// We can only reach this position if a particular codec was requested,
|
||||
// fmp4 is supported and working: the codec must be invalid.
|
||||
return CANPLAY_NO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (IsMP3SupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
|
||||
return CANPLAY_YES;
|
||||
}
|
||||
#ifdef MOZ_OMX_DECODER
|
||||
if (IsOmxSupportedType(nsDependentCString(aMIMEType))) {
|
||||
result = CANPLAY_MAYBE;
|
||||
if (nsDependentCString(aMIMEType).EqualsASCII("audio/mpeg")) {
|
||||
codecList = gMpegAudioCodecs;
|
||||
#ifdef MOZ_OMX_WEBM_DECODER
|
||||
|
@ -475,27 +475,18 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
|
|||
}
|
||||
#endif
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
if (DirectShowDecoder::GetSupportedCodecs(nsDependentCString(aMIMEType), &codecList)) {
|
||||
result = CANPLAY_MAYBE;
|
||||
}
|
||||
DirectShowDecoder::GetSupportedCodecs(nsDependentCString(aMIMEType), &codecList);
|
||||
#endif
|
||||
#ifdef MOZ_APPLEMEDIA
|
||||
if (IsAppleMediaSupportedType(nsDependentCString(aMIMEType), &codecList)) {
|
||||
result = CANPLAY_MAYBE;
|
||||
}
|
||||
IsAppleMediaSupportedType(nsDependentCString(aMIMEType), &codecList);
|
||||
#endif
|
||||
#ifdef MOZ_ANDROID_OMX
|
||||
if (MediaDecoder::IsAndroidMediaEnabled() &&
|
||||
EnsureAndroidMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), &codecList))
|
||||
result = CANPLAY_MAYBE;
|
||||
#endif
|
||||
#ifdef NECKO_PROTOCOL_rtsp
|
||||
if (IsRtspSupportedType(nsDependentCString(aMIMEType))) {
|
||||
result = CANPLAY_MAYBE;
|
||||
if (MediaDecoder::IsAndroidMediaEnabled()) {
|
||||
EnsureAndroidMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), &codecList);
|
||||
}
|
||||
#endif
|
||||
if (result == CANPLAY_NO || !aHaveRequestedCodecs || !codecList) {
|
||||
return result;
|
||||
if (!codecList) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
|
||||
// See http://www.rfc-editor.org/rfc/rfc4281.txt for the description
|
||||
|
@ -515,9 +506,83 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
|
|||
// Last codec name was empty
|
||||
return CANPLAY_NO;
|
||||
}
|
||||
|
||||
return CANPLAY_YES;
|
||||
}
|
||||
|
||||
/* static */
|
||||
CanPlayStatus
|
||||
DecoderTraits::CanHandleMediaType(const char* aMIMEType,
|
||||
bool aHaveRequestedCodecs,
|
||||
const nsAString& aRequestedCodecs)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (aHaveRequestedCodecs) {
|
||||
CanPlayStatus result = CanHandleCodecsType(aMIMEType, aRequestedCodecs);
|
||||
if (result == CANPLAY_NO || result == CANPLAY_YES) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#ifdef MOZ_RAW
|
||||
if (IsRawType(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
if (IsOggType(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#ifdef MOZ_WAVE
|
||||
if (IsWaveType(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
if (IsMP4Type(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#if !defined(MOZ_OMX_WEBM_DECODER)
|
||||
if (IsWebMType(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
if (IsMP3SupportedType(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#ifdef MOZ_GSTREAMER
|
||||
if (GStreamerDecoder::CanHandleMediaType(nsDependentCString(aMIMEType),
|
||||
aHaveRequestedCodecs ? &aRequestedCodecs : nullptr)) {
|
||||
return aHaveRequestedCodecs ? CANPLAY_YES : CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_OMX_DECODER
|
||||
if (IsOmxSupportedType(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
if (DirectShowDecoder::GetSupportedCodecs(nsDependentCString(aMIMEType), nullptr)) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_APPLEMEDIA
|
||||
if (IsAppleMediaSupportedType(nsDependentCString(aMIMEType), nullptr)) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_ANDROID_OMX
|
||||
if (MediaDecoder::IsAndroidMediaEnabled() &&
|
||||
EnsureAndroidMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), nullptr)) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
#ifdef NECKO_PROTOCOL_rtsp
|
||||
if (IsRtspSupportedType(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
return CANPLAY_NO;
|
||||
}
|
||||
|
||||
// Instantiates but does not initialize decoder.
|
||||
static
|
||||
already_AddRefed<MediaDecoder>
|
||||
|
@ -604,12 +669,10 @@ InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
|||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_WEBM
|
||||
if (DecoderTraits::IsWebMType(aType)) {
|
||||
decoder = new WebMDecoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
// Note: DirectShow should come before WMF, so that we prefer DirectShow's
|
||||
// MP3 support over WMF's.
|
||||
|
@ -694,13 +757,11 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
|
|||
decoderReader = new AndroidMediaReader(aDecoder, aType);
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_WEBM
|
||||
if (IsWebMType(aType)) {
|
||||
decoderReader = Preferences::GetBool("media.format-reader.webm", true) ?
|
||||
static_cast<MediaDecoderReader*>(new MediaFormatReader(aDecoder, new WebMDemuxer(aDecoder->GetResource()))) :
|
||||
new WebMReader(aDecoder);
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
if (IsDirectShowSupportedType(aType)) {
|
||||
decoderReader = new DirectShowReader(aDecoder);
|
||||
|
@ -736,9 +797,7 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
|
|||
(IsOmxSupportedType(aType) &&
|
||||
!IsB2GSupportOnlyType(aType)) ||
|
||||
#endif
|
||||
#ifdef MOZ_WEBM
|
||||
IsWebMType(aType) ||
|
||||
#endif
|
||||
#ifdef MOZ_GSTREAMER
|
||||
IsGStreamerSupportedType(aType) ||
|
||||
#endif
|
||||
|
|
|
@ -29,7 +29,7 @@ class DecoderTraits {
|
|||
public:
|
||||
// Returns the CanPlayStatus indicating if we can handle this
|
||||
// MIME type. The MIME type should not include the codecs parameter.
|
||||
// That parameter should be passed in aCodecs, and will only be
|
||||
// That parameter should be passed in aRequestedCodecs, and will only be
|
||||
// used if whether a given MIME type being handled depends on the
|
||||
// codec that will be used. If the codecs parameter has not been
|
||||
// specified, pass false in aHaveRequestedCodecs.
|
||||
|
@ -37,6 +37,14 @@ public:
|
|||
bool aHaveRequestedCodecs,
|
||||
const nsAString& aRequestedCodecs);
|
||||
|
||||
// Returns the CanPlayStatus indicating if we can handle this MIME type and
|
||||
// codecs type natively, excluding any plugins-based reader (such as
|
||||
// GStreamer)
|
||||
// The MIME type should not include the codecs parameter.
|
||||
// That parameter is passed in aRequestedCodecs.
|
||||
static CanPlayStatus CanHandleCodecsType(const char* aMIMEType,
|
||||
const nsAString& aRequestedCodecs);
|
||||
|
||||
// Returns true if we should handle this MIME type when it appears
|
||||
// as an <object> or as a toplevel page. If, in practice, our support
|
||||
// for the type is more limited than appears in the wild, we should return
|
||||
|
@ -63,6 +71,7 @@ public:
|
|||
static bool DecoderWaitsForOnConnected(const nsACString& aType);
|
||||
|
||||
static bool IsWebMType(const nsACString& aType);
|
||||
static bool IsMP4Type(const nsACString& aType);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -1086,8 +1086,7 @@ void MediaDecoderStateMachine::MaybeStartPlayback()
|
|||
SetPlayStartTime(TimeStamp::Now());
|
||||
MOZ_ASSERT(IsPlaying());
|
||||
|
||||
nsresult rv = StartAudioThread();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
StartAudioThread();
|
||||
|
||||
// Tell DecodedStream to start playback with specified start time and media
|
||||
// info. This is consistent with how we create AudioSink in StartAudioThread().
|
||||
|
@ -1481,6 +1480,7 @@ void MediaDecoderStateMachine::StopAudioThread()
|
|||
}
|
||||
mAudioSink = nullptr;
|
||||
}
|
||||
mAudioSinkPromise.DisconnectIfExists();
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -1783,31 +1783,31 @@ MediaDecoderStateMachine::RequestVideoData()
|
|||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
MediaDecoderStateMachine::StartAudioThread()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
if (mAudioCaptured) {
|
||||
MOZ_ASSERT(!mAudioSink);
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasAudio() && !mAudioSink) {
|
||||
auto audioStartTime = GetMediaTime();
|
||||
mAudioCompleted = false;
|
||||
mAudioSink = new AudioSink(this, audioStartTime,
|
||||
mAudioSink = new AudioSink(this, GetMediaTime(),
|
||||
mInfo.mAudio, mDecoder->GetAudioChannel());
|
||||
// OnAudioSinkError() will be called before Init() returns if an error
|
||||
// occurs during initialization.
|
||||
nsresult rv = mAudioSink->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mAudioSinkPromise.Begin(
|
||||
mAudioSink->Init()->Then(
|
||||
OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnAudioSinkComplete,
|
||||
&MediaDecoderStateMachine::OnAudioSinkError));
|
||||
|
||||
mAudioSink->SetVolume(mVolume);
|
||||
mAudioSink->SetPlaybackRate(mPlaybackRate);
|
||||
mAudioSink->SetPreservesPitch(mPreservesPitch);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int64_t MediaDecoderStateMachine::AudioDecodedUsecs()
|
||||
|
@ -2456,12 +2456,12 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
AbstractThread::MainThread()->Dispatch(event.forget());
|
||||
|
||||
mSentPlaybackEndedEvent = true;
|
||||
}
|
||||
|
||||
// Stop audio sink after call to AudioEndTime() above, otherwise it will
|
||||
// return an incorrect value due to a null mAudioSink.
|
||||
StopAudioThread();
|
||||
mDecodedStream->StopPlayback();
|
||||
// Stop audio sink after call to AudioEndTime() above, otherwise it will
|
||||
// return an incorrect value due to a null mAudioSink.
|
||||
StopAudioThread();
|
||||
mDecodedStream->StopPlayback();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -3122,11 +3122,12 @@ void MediaDecoderStateMachine::OnAudioSinkComplete()
|
|||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (mAudioCaptured) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(!mAudioCaptured, "Should be disconnected when capturing audio.");
|
||||
|
||||
mAudioSinkPromise.Complete();
|
||||
ResyncAudioClock();
|
||||
mAudioCompleted = true;
|
||||
|
||||
// Kick the decode thread; it may be sleeping waiting for this to finish.
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
}
|
||||
|
@ -3135,11 +3136,9 @@ void MediaDecoderStateMachine::OnAudioSinkError()
|
|||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
// AudioSink not used with captured streams, so ignore errors in this case.
|
||||
if (mAudioCaptured) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(!mAudioCaptured, "Should be disconnected when capturing audio.");
|
||||
|
||||
mAudioSinkPromise.Complete();
|
||||
ResyncAudioClock();
|
||||
mAudioCompleted = true;
|
||||
|
||||
|
|
|
@ -517,7 +517,7 @@ protected:
|
|||
|
||||
// Starts the audio thread. The decoder monitor must be held with exactly
|
||||
// one lock count. Called on the state machine thread.
|
||||
nsresult StartAudioThread();
|
||||
void StartAudioThread();
|
||||
|
||||
// Notification method invoked when mPlayState changes.
|
||||
void PlayStateChanged();
|
||||
|
@ -679,28 +679,13 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
// Called by the AudioSink to signal that all outstanding work is complete
|
||||
// Resolved by the AudioSink to signal that all outstanding work is complete
|
||||
// and the sink is shutting down.
|
||||
void OnAudioSinkComplete();
|
||||
public:
|
||||
void DispatchOnAudioSinkComplete()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnAudioSinkComplete);
|
||||
OwnerThread()->Dispatch(runnable.forget());
|
||||
}
|
||||
private:
|
||||
|
||||
// Called by the AudioSink to signal errors.
|
||||
// Rejected by the AudioSink to signal errors.
|
||||
void OnAudioSinkError();
|
||||
|
||||
void DispatchOnAudioSinkError()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnAudioSinkError);
|
||||
OwnerThread()->Dispatch(runnable.forget());
|
||||
}
|
||||
|
||||
// Return true if the video decoder's decode speed can not catch up the
|
||||
// play time.
|
||||
bool NeedToSkipToNextKeyframe();
|
||||
|
@ -1317,6 +1302,8 @@ private:
|
|||
// Media data resource from the decoder.
|
||||
nsRefPtr<MediaResource> mResource;
|
||||
|
||||
MozPromiseRequestHolder<GenericPromise> mAudioSinkPromise;
|
||||
|
||||
private:
|
||||
// The buffered range. Mirrored from the decoder thread.
|
||||
Mirror<media::TimeIntervals> mBuffered;
|
||||
|
|
|
@ -1138,6 +1138,10 @@ MediaFormatReader::WaitForData(MediaData::Type aType)
|
|||
TrackType trackType = aType == MediaData::VIDEO_DATA ?
|
||||
TrackType::kVideoTrack : TrackType::kAudioTrack;
|
||||
auto& decoder = GetDecoderData(trackType);
|
||||
if (!decoder.mWaitingForData) {
|
||||
// We aren't waiting for data any longer.
|
||||
return WaitForDataPromise::CreateAndResolve(decoder.mType, __func__);
|
||||
}
|
||||
nsRefPtr<WaitForDataPromise> p = decoder.mWaitingPromise.Ensure(__func__);
|
||||
ScheduleUpdate(trackType);
|
||||
return p;
|
||||
|
|
|
@ -71,8 +71,9 @@ IsSupportedAudioCodec(const nsAString& aCodec,
|
|||
bool& aOutContainsMP3)
|
||||
{
|
||||
// AAC-LC or HE-AAC in M4A.
|
||||
aOutContainsAAC = aCodec.EqualsASCII("mp4a.40.2") ||
|
||||
aCodec.EqualsASCII("mp4a.40.5");
|
||||
aOutContainsAAC = aCodec.EqualsASCII("mp4a.40.2") // MPEG4 AAC-LC
|
||||
|| aCodec.EqualsASCII("mp4a.40.5") // MPEG4 HE-AAC
|
||||
|| aCodec.EqualsASCII("mp4a.67"); // MPEG2 AAC-LC
|
||||
if (aOutContainsAAC) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -83,46 +83,41 @@ IsTypeSupported(const nsAString& aType)
|
|||
nsAutoString mimeType;
|
||||
nsresult rv = parser.GetType(mimeType);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
bool found = false;
|
||||
NS_ConvertUTF16toUTF8 mimeTypeUTF8(mimeType);
|
||||
|
||||
nsAutoString codecs;
|
||||
bool hasCodecs = NS_SUCCEEDED(parser.GetParameter("codecs", codecs));
|
||||
|
||||
for (uint32_t i = 0; gMediaSourceTypes[i]; ++i) {
|
||||
if (mimeType.EqualsASCII(gMediaSourceTypes[i])) {
|
||||
if ((mimeType.EqualsASCII("video/mp4") ||
|
||||
mimeType.EqualsASCII("audio/mp4")) &&
|
||||
(!Preferences::GetBool("media.mediasource.mp4.enabled", false)
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// MP4 won't work unless we have JellyBean+
|
||||
|| AndroidBridge::Bridge()->GetAPIVersion() < 16
|
||||
#endif
|
||||
)) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
if (DecoderTraits::IsMP4Type(mimeTypeUTF8)) {
|
||||
if (!Preferences::GetBool("media.mediasource.mp4.enabled", false)) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
if (hasCodecs &&
|
||||
DecoderTraits::CanHandleCodecsType(mimeTypeUTF8.get(),
|
||||
codecs) == CANPLAY_NO) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
return NS_OK;
|
||||
} else if (DecoderTraits::IsWebMType(mimeTypeUTF8)) {
|
||||
if (!Preferences::GetBool("media.mediasource.webm.enabled", false) ||
|
||||
Preferences::GetBool("media.mediasource.format-reader", false)) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
if (hasCodecs &&
|
||||
DecoderTraits::CanHandleCodecsType(mimeTypeUTF8.get(),
|
||||
codecs) == CANPLAY_NO) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
if ((mimeType.EqualsASCII("video/webm") ||
|
||||
mimeType.EqualsASCII("audio/webm")) &&
|
||||
!Preferences::GetBool("media.mediasource.webm.enabled", false)) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
// Check aType against HTMLMediaElement list of MIME types. Since we've
|
||||
// already restricted the container format, this acts as a specific check
|
||||
// of any specified "codecs" parameter of aType.
|
||||
if (dom::HTMLMediaElement::GetCanPlay(aType) == CANPLAY_NO) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
|
||||
if (Preferences::GetBool("media.mediasource.format-reader", false) &&
|
||||
!mimeType.EqualsASCII("video/mp4") && !mimeType.EqualsASCII("audio/mp4")) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
|
|
@ -35,54 +35,68 @@ support-files =
|
|||
bipbop/bipbop13.m4s^headers^ bipbop/bipbop_video13.m4s^headers^
|
||||
|
||||
[test_BufferedSeek.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_BufferedSeek_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_BufferingWait.html]
|
||||
skip-if = true # bug 1093133
|
||||
skip-if = true # bug 1182946
|
||||
[test_BufferingWait_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_EndOfStream.html]
|
||||
skip-if = (toolkit == 'android' || buildapp == 'mulet') #timeout android/mulet only bug 1101187
|
||||
skip-if = (true || toolkit == 'android' || buildapp == 'mulet') #timeout android/mulet only bug 1101187 and bug 1182946
|
||||
[test_EndOfStream_mp4.html]
|
||||
skip-if = (toolkit == 'android' || buildapp == 'mulet') || ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_DurationUpdated.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_DurationUpdated_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_FrameSelection.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_HaveMetadataUnbufferedSeek.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_HaveMetadataUnbufferedSeek_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_LoadedMetadataFired.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_LoadedMetadataFired_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_MediaSource.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_MediaSource_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_MediaSource_disabled.html]
|
||||
[test_SeekableAfterEndOfStream.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_SeekableAfterEndOfStream_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_SeekableAfterEndOfStreamSplit.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_SeekableAfterEndOfStreamSplit_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_SeekableBeforeEndOfStream.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_SeekableBeforeEndOfStream_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_SeekableBeforeEndOfStreamSplit.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_SeekableBeforeEndOfStreamSplit_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_SeekTwice_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_SetModeThrows.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_SplitAppendDelay.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_SplitAppendDelay_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_SplitAppend.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_SplitAppend_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_TimestampOffset_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_TruncatedDuration.html]
|
||||
skip-if = true # bug 1182946
|
||||
[test_TruncatedDuration_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_WaitingOnMissingData.html]
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
const KEYSYSTEM_TYPE = "org.w3.clearkey";
|
||||
|
||||
function IsMacOSSnowLeopardOrEarlier() {
|
||||
var re = /Mac OS X (\d+)\.(\d+)/;
|
||||
var ver = navigator.userAgent.match(re);
|
||||
if (!ver || ver.length != 3) {
|
||||
return false;
|
||||
}
|
||||
var major = ver[1] | 0;
|
||||
var minor = ver[2] | 0;
|
||||
return major == 10 && minor <= 6;
|
||||
}
|
||||
|
||||
function bail(message)
|
||||
{
|
||||
return function(err) {
|
||||
|
|
|
@ -46,8 +46,12 @@ function beginTest() {
|
|||
manager.runTests(gEMETests, startTest);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
if (!IsMacOSSnowLeopardOrEarlier()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
} else {
|
||||
todo(false, "Test disabled on this platform.");
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -89,8 +89,12 @@ function beginTest() {
|
|||
manager.runTests(gEMENonMSEFailTests, startTest);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
if (!IsMacOSSnowLeopardOrEarlier()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
} else {
|
||||
todo(false, "Test disabled on this platform.");
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -154,8 +154,12 @@ function beginTest() {
|
|||
manager.runTests(gEMETests.filter(t => t.sessionCount === 1), startTest);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
if (!IsMacOSSnowLeopardOrEarlier()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
} else {
|
||||
todo(false, "Test disabled on this platform.");
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -111,8 +111,12 @@ function beginTest() {
|
|||
manager.runTests(gEMETests, startTest);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
if (!IsMacOSSnowLeopardOrEarlier()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
} else {
|
||||
todo(false, "Test disabled on this platform.");
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -292,8 +292,12 @@ function beginTest() {
|
|||
Promise.all(tests.map(Test)).then(function() { SimpleTest.finish(); });
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
if (!IsMacOSSnowLeopardOrEarlier()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
} else {
|
||||
todo(false, "Test disabled on this platform.");
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
|
|
@ -40,8 +40,12 @@ function beginTest() {
|
|||
manager.runTests(gEMETests, startTest);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
if (!IsMacOSSnowLeopardOrEarlier()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
} else {
|
||||
todo(false, "Test disabled on this platform.");
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -43,8 +43,12 @@ function beginTest() {
|
|||
manager.runTests(gEMETests, startTest);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
if (!IsMacOSSnowLeopardOrEarlier()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
} else {
|
||||
todo(false, "Test disabled on this platform.");
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -42,8 +42,12 @@ function beginTest() {
|
|||
manager.runTests(gEMETests, startTest);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
if (!IsMacOSSnowLeopardOrEarlier()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
} else {
|
||||
todo(false, "Test disabled on this platform.");
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -130,16 +130,6 @@ mozilla::plugins::SetupBridge(uint32_t aPluginId,
|
|||
return true;
|
||||
}
|
||||
*rv = PPluginModule::Bridge(aContentParent, chromeParent);
|
||||
if (NS_FAILED(*rv)) {
|
||||
#if defined(MOZ_CRASHREPORTER)
|
||||
// We are going to abort due to the failure, lets note the cause
|
||||
// in the report for diagnosing.
|
||||
nsAutoCString error;
|
||||
error.AppendPrintf("%X %d", *rv, chromeParent->GetIPCChannel()->GetChannelState__TotallyRacy());
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BridgePluginError"), error);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1261,6 +1261,8 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
|||
|
||||
if (IsSupported(GLFeature::gpu_shader4)) {
|
||||
SymLoadStruct gpuShader4Symbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fGetVertexAttribIiv, { "GetVertexAttribIiv", "GetVertexAttribIivEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetVertexAttribIuiv, { "GetVertexAttribIuiv", "GetVertexAttribIuivEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fVertexAttribI4i, { "VertexAttribI4i", "VertexAttribI4iEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fVertexAttribI4iv, { "VertexAttribI4iv","VertexAttribI4ivEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fVertexAttribI4ui, { "VertexAttribI4ui", "VertexAttribI4uiEXT", nullptr } },
|
||||
|
|
|
@ -2376,6 +2376,22 @@ public:
|
|||
// -----------------------------------------------------------------------------
|
||||
// GL 3.0, GL ES 3.0 & EXT_gpu_shader4
|
||||
public:
|
||||
void fGetVertexAttribIiv(GLuint index, GLenum pname, GLint* params)
|
||||
{
|
||||
ASSERT_SYMBOL_PRESENT(fGetVertexAttribIiv);
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fGetVertexAttribIiv(index, pname, params);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params)
|
||||
{
|
||||
ASSERT_SYMBOL_PRESENT(fGetVertexAttribIuiv);
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fGetVertexAttribIuiv(index, pname, params);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
|
||||
{
|
||||
BEFORE_GL_CALL;
|
||||
|
|
|
@ -620,6 +620,10 @@ struct GLContextSymbols
|
|||
PFNGLUNIFORMBLOCKBINDINGPROC fUniformBlockBinding;
|
||||
|
||||
// EXT_gpu_shader4
|
||||
typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint* params);
|
||||
PFNGLGETVERTEXATTRIBIIVPROC fGetVertexAttribIiv;
|
||||
typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint* params);
|
||||
PFNGLGETVERTEXATTRIBIUIVPROC fGetVertexAttribIuiv;
|
||||
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);
|
||||
PFNGLVERTEXATTRIBI4IPROC fVertexAttribI4i;
|
||||
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint* v);
|
||||
|
|
|
@ -407,7 +407,7 @@ BufferTextureHost::UpdatedInternal(const nsIntRegion* aRegion)
|
|||
// If the last frame wasn't uploaded yet, and we -don't- have a partial update,
|
||||
// we still need to update the full surface.
|
||||
if (aRegion && !mNeedsFullUpdate) {
|
||||
mMaybeUpdatedRegion = mMaybeUpdatedRegion.Or(mMaybeUpdatedRegion, *aRegion);
|
||||
mMaybeUpdatedRegion.OrWith(*aRegion);
|
||||
} else {
|
||||
mNeedsFullUpdate = true;
|
||||
}
|
||||
|
|
|
@ -971,7 +971,7 @@ TestDataStructuresChild::Test18()
|
|||
ra.SetCapacity(nelements);
|
||||
for (int i = 0; i < nelements; ++i) {
|
||||
nsIntRegion r;
|
||||
r = r.Or(nsIntRect(0, 0, 10, 10), nsIntRect(10, 10, 10, 10));
|
||||
r.Or(nsIntRect(0, 0, 10, 10), nsIntRect(10, 10, 10, 10));
|
||||
ra.AppendElement(r);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/GuardObjects.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include "jspubtd.h"
|
||||
|
@ -643,7 +644,7 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
|||
|
||||
/* Note: CX is a subclass of either ContextFriendFields or PerThreadDataFriendFields. */
|
||||
template <typename CX>
|
||||
void init(CX* cx) {
|
||||
void registerWithRootLists(CX* cx) {
|
||||
js::ThingRootKind kind = js::RootKind<T>::rootKind();
|
||||
this->stack = &cx->roots.stackRoots_[kind];
|
||||
this->prev = *stack;
|
||||
|
@ -656,15 +657,16 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
|||
: ptr(js::GCMethods<T>::initial())
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(js::ContextFriendFields::get(cx));
|
||||
registerWithRootLists(js::ContextFriendFields::get(cx));
|
||||
}
|
||||
|
||||
Rooted(JSContext* cx, const T& initial
|
||||
template <typename S>
|
||||
Rooted(JSContext* cx, S&& initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(initial)
|
||||
: ptr(mozilla::Forward<S>(initial))
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(js::ContextFriendFields::get(cx));
|
||||
registerWithRootLists(js::ContextFriendFields::get(cx));
|
||||
}
|
||||
|
||||
explicit Rooted(js::ContextFriendFields* cx
|
||||
|
@ -672,15 +674,16 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
|||
: ptr(js::GCMethods<T>::initial())
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(cx);
|
||||
registerWithRootLists(cx);
|
||||
}
|
||||
|
||||
Rooted(js::ContextFriendFields* cx, const T& initial
|
||||
template <typename S>
|
||||
Rooted(js::ContextFriendFields* cx, S&& initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(initial)
|
||||
: ptr(mozilla::Forward<S>(initial))
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(cx);
|
||||
registerWithRootLists(cx);
|
||||
}
|
||||
|
||||
explicit Rooted(js::PerThreadDataFriendFields* pt
|
||||
|
@ -688,15 +691,16 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
|||
: ptr(js::GCMethods<T>::initial())
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(pt);
|
||||
registerWithRootLists(pt);
|
||||
}
|
||||
|
||||
Rooted(js::PerThreadDataFriendFields* pt, const T& initial
|
||||
template <typename S>
|
||||
Rooted(js::PerThreadDataFriendFields* pt, S&& initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(initial)
|
||||
: ptr(mozilla::Forward<S>(initial))
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(pt);
|
||||
registerWithRootLists(pt);
|
||||
}
|
||||
|
||||
explicit Rooted(JSRuntime* rt
|
||||
|
@ -704,15 +708,16 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
|||
: ptr(js::GCMethods<T>::initial())
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(js::PerThreadDataFriendFields::getMainThread(rt));
|
||||
registerWithRootLists(js::PerThreadDataFriendFields::getMainThread(rt));
|
||||
}
|
||||
|
||||
Rooted(JSRuntime* rt, const T& initial
|
||||
template <typename S>
|
||||
Rooted(JSRuntime* rt, S&& initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(initial)
|
||||
: ptr(mozilla::Forward<S>(initial))
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(js::PerThreadDataFriendFields::getMainThread(rt));
|
||||
registerWithRootLists(js::PerThreadDataFriendFields::getMainThread(rt));
|
||||
}
|
||||
|
||||
~Rooted() {
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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 gc_HashTable_h
|
||||
#define gc_HashTable_h
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "js/RootingAPI.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
template <typename> struct DefaultTracer;
|
||||
|
||||
// A TraceableHashMap is a HashMap with an additional trace method that knows
|
||||
// how to visit all keys and values in the table. HashMaps that contain GC
|
||||
// pointers that must be traced to be kept alive will generally want to use
|
||||
// this TraceableHashMap specializeation in lieu of HashMap.
|
||||
//
|
||||
// Most types of GC pointers as keys and values can be traced with no extra
|
||||
// infrastructure. For structs and non-gc-pointer members, ensure that there
|
||||
// is a specialization of DefaultTracer<T> with an appropriate trace method
|
||||
// available to handle the custom type.
|
||||
//
|
||||
// Note that although this HashMap's trace will deal correctly with moved keys,
|
||||
// it does not itself know when to barrier or trace keys. To function properly
|
||||
// it must either be used with Rooted, or barriered and traced manually.
|
||||
template <typename Key,
|
||||
typename Value,
|
||||
typename HashPolicy = DefaultHasher<Key>,
|
||||
typename AllocPolicy = TempAllocPolicy,
|
||||
typename KeyTraceFunc = DefaultTracer<Key>,
|
||||
typename ValueTraceFunc = DefaultTracer<Value>>
|
||||
class TraceableHashMap : public HashMap<Key, Value, HashPolicy, AllocPolicy>,
|
||||
public JS::DynamicTraceable
|
||||
{
|
||||
using Base = HashMap<Key, Value, HashPolicy, AllocPolicy>;
|
||||
|
||||
public:
|
||||
explicit TraceableHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {}
|
||||
|
||||
void trace(JSTracer* trc) override {
|
||||
if (!this->initialized())
|
||||
return;
|
||||
for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
|
||||
ValueTraceFunc::trace(trc, &e.front().value(), "hashmap value");
|
||||
Key key = e.front().key();
|
||||
KeyTraceFunc::trace(trc, &key, "hashmap key");
|
||||
if (key != e.front().key())
|
||||
e.rekeyFront(key);
|
||||
}
|
||||
}
|
||||
|
||||
// TraceableHashMap is movable
|
||||
TraceableHashMap(TraceableHashMap&& rhs) : Base(mozilla::Forward<TraceableHashMap>(rhs)) {}
|
||||
void operator=(TraceableHashMap&& rhs) {
|
||||
MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
|
||||
Base::operator=(mozilla::Forward<TraceableHashMap>(rhs));
|
||||
}
|
||||
|
||||
private:
|
||||
// TraceableHashMap is not copyable or assignable
|
||||
TraceableHashMap(const TraceableHashMap& hm) = delete;
|
||||
TraceableHashMap& operator=(const TraceableHashMap& hm) = delete;
|
||||
};
|
||||
|
||||
template <typename Outer, typename... MapArgs>
|
||||
class TraceableHashMapOperations
|
||||
{
|
||||
using Map = TraceableHashMap<MapArgs...>;
|
||||
using Lookup = typename Map::Lookup;
|
||||
using Ptr = typename Map::Ptr;
|
||||
using AddPtr = typename Map::AddPtr;
|
||||
using Range = typename Map::Range;
|
||||
using Enum = typename Map::Enum;
|
||||
|
||||
const Map& map() const { return static_cast<const Outer*>(this)->extract(); }
|
||||
|
||||
public:
|
||||
bool initialized() const { return map().initialized(); }
|
||||
Ptr lookup(const Lookup& l) const { return map().lookup(l); }
|
||||
AddPtr lookupForAdd(const Lookup& l) const { return map().lookupForAdd(l); }
|
||||
Range all() const { return map().all(); }
|
||||
bool empty() const { return map().empty(); }
|
||||
uint32_t count() const { return map().count(); }
|
||||
size_t capacity() const { return map().capacity(); }
|
||||
uint32_t generation() const { return map().generation(); }
|
||||
bool has(const Lookup& l) const { return map().lookup(l).found(); }
|
||||
};
|
||||
|
||||
template <typename Outer, typename... MapArgs>
|
||||
class MutableTraceableHashMapOperations
|
||||
: public TraceableHashMapOperations<Outer, MapArgs...>
|
||||
{
|
||||
using Map = TraceableHashMap<MapArgs...>;
|
||||
using Lookup = typename Map::Lookup;
|
||||
using Ptr = typename Map::Ptr;
|
||||
using AddPtr = typename Map::AddPtr;
|
||||
using Range = typename Map::Range;
|
||||
using Enum = typename Map::Enum;
|
||||
|
||||
Map& map() { return static_cast<Outer*>(this)->extract(); }
|
||||
|
||||
public:
|
||||
bool init(uint32_t len = 16) { return map().init(len); }
|
||||
void clear() { map().clear(); }
|
||||
void finish() { map().finish(); }
|
||||
void remove(Ptr p) { map().remove(p); }
|
||||
|
||||
template<typename KeyInput, typename ValueInput>
|
||||
bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) {
|
||||
return map().add(p, mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
|
||||
}
|
||||
|
||||
template<typename KeyInput>
|
||||
bool add(AddPtr& p, KeyInput&& k) {
|
||||
return map().add(p, mozilla::Forward<KeyInput>(k), Map::Value());
|
||||
}
|
||||
|
||||
template<typename KeyInput, typename ValueInput>
|
||||
bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) {
|
||||
return map().relookupOrAdd(p, k,
|
||||
mozilla::Forward<KeyInput>(k),
|
||||
mozilla::Forward<ValueInput>(v));
|
||||
}
|
||||
|
||||
template<typename KeyInput, typename ValueInput>
|
||||
bool put(KeyInput&& k, ValueInput&& v) {
|
||||
return map().put(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
|
||||
}
|
||||
|
||||
template<typename KeyInput, typename ValueInput>
|
||||
bool putNew(KeyInput&& k, ValueInput&& v) {
|
||||
return map().putNew(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename...> class TraceableHashMap, typename... MapArgs>
|
||||
class RootedBase<TraceableHashMap<MapArgs...>>
|
||||
: public MutableTraceableHashMapOperations<JS::Rooted<TraceableHashMap<MapArgs...>>, MapArgs...>
|
||||
{
|
||||
using Map = TraceableHashMap<MapArgs...>;
|
||||
|
||||
friend class TraceableHashMapOperations<JS::Rooted<Map>, MapArgs...>;
|
||||
const Map& extract() const { return *static_cast<const JS::Rooted<Map>*>(this)->address(); }
|
||||
|
||||
friend class MutableTraceableHashMapOperations<JS::Rooted<Map>, MapArgs...>;
|
||||
Map& extract() { return *static_cast<JS::Rooted<Map>*>(this)->address(); }
|
||||
};
|
||||
|
||||
template <template <typename...> class TraceableHashMap, typename... MapArgs>
|
||||
class MutableHandleBase<TraceableHashMap<MapArgs...>>
|
||||
: public MutableTraceableHashMapOperations<JS::MutableHandle<TraceableHashMap<MapArgs...>>,
|
||||
MapArgs...>
|
||||
{
|
||||
using Map = TraceableHashMap<MapArgs...>;
|
||||
|
||||
friend class TraceableHashMapOperations<JS::MutableHandle<Map>, MapArgs...>;
|
||||
const Map& extract() const {
|
||||
return *static_cast<const JS::MutableHandle<Map>*>(this)->address();
|
||||
}
|
||||
|
||||
friend class MutableTraceableHashMapOperations<JS::MutableHandle<Map>, MapArgs...>;
|
||||
Map& extract() { return *static_cast<JS::MutableHandle<Map>*>(this)->address(); }
|
||||
};
|
||||
|
||||
template <template <typename...> class TraceableHashMap, typename... MapArgs>
|
||||
class HandleBase<TraceableHashMap<MapArgs...>>
|
||||
: public TraceableHashMapOperations<JS::Handle<TraceableHashMap<MapArgs...>>, MapArgs...>
|
||||
{
|
||||
using Map = TraceableHashMap<MapArgs...>;
|
||||
friend class TraceableHashMapOperations<JS::Handle<Map>, MapArgs...>;
|
||||
const Map& extract() const { return *static_cast<const JS::Handle<Map>*>(this)->address(); }
|
||||
};
|
||||
|
||||
// The default implementation of DefaultTracer will leave alone POD types.
|
||||
template <typename T> struct DefaultTracer {
|
||||
static_assert(mozilla::IsPod<T>::value, "non-pod types must not be ignored");
|
||||
static void trace(JSTracer* trc, T* t, const char* name) {}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* gc_HashTable_h */
|
|
@ -4041,18 +4041,6 @@ CType::Finalize(JSFreeOp* fop, JSObject* obj)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
TraceFieldInfoHash(JSTracer* trc, FieldInfoHash* fields)
|
||||
{
|
||||
for (FieldInfoHash::Enum e(*fields); !e.empty(); e.popFront()) {
|
||||
JSString* key = e.front().key();
|
||||
JS_CallUnbarrieredStringTracer(trc, &key, "fieldName");
|
||||
if (key != e.front().key())
|
||||
e.rekeyFront(JS_ASSERT_STRING_IS_FLAT(key));
|
||||
JS_CallObjectTracer(trc, &e.front().value().mType, "fieldType");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CType::Trace(JSTracer* trc, JSObject* obj)
|
||||
{
|
||||
|
@ -4069,7 +4057,7 @@ CType::Trace(JSTracer* trc, JSObject* obj)
|
|||
return;
|
||||
|
||||
FieldInfoHash* fields = static_cast<FieldInfoHash*>(slot.toPrivate());
|
||||
TraceFieldInfoHash(trc, fields);
|
||||
fields->trace(trc);
|
||||
break;
|
||||
}
|
||||
case TYPE_function: {
|
||||
|
@ -5478,31 +5466,6 @@ PostBarrierCallback(JSTracer* trc, JSString* key, void* data)
|
|||
table->rekeyIfMoved(JS_ASSERT_STRING_IS_FLAT(prior), JS_ASSERT_STRING_IS_FLAT(key));
|
||||
}
|
||||
|
||||
// Holds a pointer to a FieldInfoHash while it is being constructed, tracing it
|
||||
// on GC and destroying it when it dies unless release() has been called first.
|
||||
class FieldInfoHolder : public JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
FieldInfoHolder(JSContext* cx, FieldInfoHash* fields)
|
||||
: CustomAutoRooter(cx), fields_(fields) {}
|
||||
~FieldInfoHolder() {
|
||||
delete fields_;
|
||||
}
|
||||
virtual void trace(JSTracer* trc) override {
|
||||
if (fields_)
|
||||
TraceFieldInfoHash(trc, fields_);
|
||||
}
|
||||
FieldInfoHash* operator->() { return fields_; }
|
||||
operator FieldInfoHash*() { return fields_; }
|
||||
FieldInfoHash* release() {
|
||||
FieldInfoHash* result = fields_;
|
||||
fields_ = nullptr;
|
||||
return result;
|
||||
}
|
||||
private:
|
||||
FieldInfoHash* fields_;
|
||||
};
|
||||
|
||||
bool
|
||||
StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsObj_)
|
||||
{
|
||||
|
@ -5529,12 +5492,9 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsOb
|
|||
JSPROP_READONLY | JSPROP_PERMANENT))
|
||||
return false;
|
||||
|
||||
// Create a FieldInfoHash to stash on the type object, and an array to root
|
||||
// its constituents. (We cannot simply stash the hash in a reserved slot now
|
||||
// to get GC safety for free, since if anything in this function fails we
|
||||
// do not want to mutate 'typeObj'.)
|
||||
FieldInfoHolder fields(cx, cx->new_<FieldInfoHash>());
|
||||
if (!fields || !fields->init(len)) {
|
||||
// Create a FieldInfoHash to stash on the type object.
|
||||
Rooted<FieldInfoHash> fields(cx);
|
||||
if (!fields.init(len)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
@ -5556,7 +5516,7 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsOb
|
|||
return false;
|
||||
|
||||
// Make sure each field name is unique
|
||||
FieldInfoHash::AddPtr entryPtr = fields->lookupForAdd(name);
|
||||
FieldInfoHash::AddPtr entryPtr = fields.lookupForAdd(name);
|
||||
if (entryPtr) {
|
||||
JS_ReportError(cx, "struct fields must have unique names");
|
||||
return false;
|
||||
|
@ -5606,8 +5566,8 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsOb
|
|||
info.mType = fieldType;
|
||||
info.mIndex = i;
|
||||
info.mOffset = fieldOffset;
|
||||
ASSERT_OK(fields->add(entryPtr, name, info));
|
||||
JS_StoreStringPostBarrierCallback(cx, PostBarrierCallback, name, fields);
|
||||
ASSERT_OK(fields.add(entryPtr, name, info));
|
||||
JS_StoreStringPostBarrierCallback(cx, PostBarrierCallback, name, fields.address());
|
||||
|
||||
structSize = fieldOffset + fieldSize;
|
||||
|
||||
|
@ -5636,7 +5596,14 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsOb
|
|||
if (!SizeTojsval(cx, structSize, &sizeVal))
|
||||
return false;
|
||||
|
||||
JS_SetReservedSlot(typeObj, SLOT_FIELDINFO, PrivateValue(fields.release()));
|
||||
// Move the field hash to the heap and store it in the typeObj.
|
||||
FieldInfoHash *heapHash = cx->new_<FieldInfoHash>(mozilla::Move(fields.get()));
|
||||
if (!heapHash) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(heapHash->initialized());
|
||||
JS_SetReservedSlot(typeObj, SLOT_FIELDINFO, PrivateValue(heapHash));
|
||||
|
||||
JS_SetReservedSlot(typeObj, SLOT_SIZE, sizeVal);
|
||||
JS_SetReservedSlot(typeObj, SLOT_ALIGN, Int32Value(structAlign));
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "prlink.h"
|
||||
|
||||
#include "ctypes/typedefs.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/TraceableHashTable.h"
|
||||
#include "js/Vector.h"
|
||||
#include "vm/String.h"
|
||||
|
||||
|
@ -279,7 +279,8 @@ struct FieldHashPolicy : DefaultHasher<JSFlatString*>
|
|||
}
|
||||
};
|
||||
|
||||
typedef HashMap<JSFlatString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash;
|
||||
typedef TraceableHashMap<JSFlatString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy>
|
||||
FieldInfoHash;
|
||||
|
||||
void
|
||||
TraceFieldInfoHash(JSTracer* trc, FieldInfoHash* fields);
|
||||
|
@ -533,6 +534,13 @@ namespace UInt64 {
|
|||
} // namespace UInt64
|
||||
|
||||
} // namespace ctypes
|
||||
|
||||
template <> struct DefaultTracer<ctypes::FieldInfo> {
|
||||
static void trace(JSTracer* trc, ctypes::FieldInfo* t, const char* name) {
|
||||
JS_CallObjectTracer(trc, &t->mType, "fieldType");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* ctypes_CTypes_h */
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче