Merge m-c to b2ginbound, a=merge

This commit is contained in:
Wes Kocher 2015-10-02 13:43:47 -07:00
commit 3666994150
161 changed files with 1740 additions and 982 deletions

View File

@ -218,10 +218,25 @@ public:
bool IsLinkValid();
// XXX checking mRole alone may not result in same behavior as Accessibles
// due to ARIA roles
inline bool IsTable() const { return mRole == roles::TABLE; }
inline bool IsTableRow() const { return mRole == roles::ROW; }
inline bool IsTableCell() const { return mRole == roles::CELL; }
// due to ARIA roles. See bug 1210477.
inline bool IsTable() const
{
return mRole == roles::TABLE || mRole == roles::MATHML_TABLE;
}
inline bool IsTableRow() const
{
return (mRole == roles::ROW ||
mRole == roles::MATHML_TABLE_ROW ||
mRole == roles::MATHML_LABELED_ROW);
}
inline bool IsTableCell() const
{
return (mRole == roles::CELL ||
mRole == roles::COLUMNHEADER ||
mRole == roles::ROWHEADER ||
mRole == roles::GRID_CELL ||
mRole == roles::MATHML_CELL);
}
uint32_t AnchorCount(bool* aOk);

View File

@ -101,7 +101,7 @@ this.FxAccountsMgmtService = {
switch(data.method) {
case "getAssertion":
let principal = Services.scriptSecurityManager.getSystemPrincipal();
let audience = msg.audience || principal.originNoSuffix;
let audience = data.audience || principal.originNoSuffix;
FxAccountsManager.getAssertion(audience, principal, {
silent: msg.silent || false
}).then(result => {

View File

@ -60,13 +60,13 @@ var LoopUI;
*/
promiseDocumentVisible(aDocument) {
if (!aDocument.hidden) {
return Promise.resolve();
return Promise.resolve(aDocument);
}
return new Promise((resolve) => {
aDocument.addEventListener("visibilitychange", function onVisibilityChanged() {
aDocument.removeEventListener("visibilitychange", onVisibilityChanged);
resolve();
resolve(aDocument);
});
});
},
@ -81,6 +81,15 @@ var LoopUI;
* @return {Promise}
*/
togglePanel: function(event, tabId = null) {
if (!this.panel) {
// We're on the hidden window! What fun!
let obs = win => {
Services.obs.removeObserver(obs, "browser-delayed-startup-finished");
win.LoopUI.togglePanel(event, tabId);
};
Services.obs.addObserver(obs, "browser-delayed-startup-finished", false);
return OpenBrowserWindow();
}
if (this.panel.state == "open") {
return new Promise(resolve => {
this.panel.hidePopup();
@ -88,7 +97,12 @@ var LoopUI;
});
}
return this.openCallPanel(event, tabId);
return this.openCallPanel(event, tabId).then(doc => {
let fm = Services.focus;
fm.moveFocus(doc.defaultView, null, fm.MOVEFOCUS_FIRST, fm.FLAG_NOSCROLL);
}).catch(err => {
Cu.reportError(x);
});
},
/**
@ -130,14 +144,14 @@ var LoopUI;
let documentDOMLoaded = () => {
iframe.removeEventListener("DOMContentLoaded", documentDOMLoaded, true);
this.injectLoopAPI(iframe.contentWindow);
iframe.contentWindow.addEventListener("loopPanelInitialized", function loopPanelInitialized() {
this.injectLoopAPI(iframe.contentWindow);
iframe.contentWindow.addEventListener("loopPanelInitialized", function loopPanelInitialized() {
iframe.contentWindow.removeEventListener("loopPanelInitialized",
loopPanelInitialized);
loopPanelInitialized);
showTab();
});
};
iframe.addEventListener("DOMContentLoaded", documentDOMLoaded, true);
});
};
iframe.addEventListener("DOMContentLoaded", documentDOMLoaded, true);
};
// Used to clear the temporary "login" state from the button.
@ -153,7 +167,9 @@ var LoopUI;
return;
}
this.PanelFrame.showPopup(window, event ? event.target : this.toolbarButton.node,
let anchor = event ? event.target : this.toolbarButton.anchor;
this.PanelFrame.showPopup(window, anchor,
"loop", null, "about:looppanel",
// Loop wants a fixed size for the panel. This also stops it dynamically resizing.
{ width: 330, height: 410 },

View File

@ -507,6 +507,12 @@
label="&webapps.label;"
accesskey="&webapps.accesskey;"
oncommand="BrowserOpenApps();"/>
<menuitem id="menu_openLoop"
label="&loopMenuItem.label;"
accesskey = "&loopMenuItem.accesskey;"
oncommand="LoopUI.togglePanel();"/>
#ifdef MOZ_SERVICES_SYNC
<!-- only one of sync-setup, sync-syncnowitem or sync-reauthitem will be showing at once -->
<menuitem id="sync-setup"

View File

@ -4960,6 +4960,10 @@ nsBrowserAccess.prototype = {
isTabContentWindow: function (aWindow) {
return gBrowser.browsers.some(browser => browser.contentWindow == aWindow);
},
canClose() {
return CanCloseWindow();
},
}
function getTogglableToolbars() {
@ -6424,6 +6428,26 @@ var IndexedDBPromptHelper = {
}
};
function CanCloseWindow()
{
// Avoid redundant calls to canClose from showing multiple
// PermitUnload dialogs.
if (window.skipNextCanClose) {
return true;
}
for (let browser of gBrowser.browsers) {
let {permitUnload, timedOut} = browser.permitUnload();
if (timedOut) {
return true;
}
if (!permitUnload) {
return false;
}
}
return true;
}
function WindowIsClosing()
{
if (TabView.isVisible()) {
@ -6434,27 +6458,19 @@ function WindowIsClosing()
if (!closeWindow(false, warnAboutClosingWindow))
return false;
// Bug 967873 - Proxy nsDocumentViewer::PermitUnload to the child process
if (gMultiProcessBrowser)
// In theory we should exit here and the Window's internal Close
// method should trigger canClose on nsBrowserAccess. However, by
// that point it's too late to be able to show a prompt for
// PermitUnload. So we do it here, when we still can.
if (CanCloseWindow()) {
// This flag ensures that the later canClose call does nothing.
// It's only needed to make tests pass, since they detect the
// prompt even when it's not actually shown.
window.skipNextCanClose = true;
return true;
for (let browser of gBrowser.browsers) {
let ds = browser.docShell;
// Passing true to permitUnload indicates we plan on closing the window.
// This means that once unload is permitted, all further calls to
// permitUnload will be ignored. This avoids getting multiple prompts
// to unload the page.
if (ds.contentViewer && !ds.contentViewer.permitUnload(true)) {
// ... however, if the user aborts closing, we need to undo that,
// to ensure they get prompted again when we next try to close the window.
// We do this on the window's toplevel docshell instead of on the tab, so
// that all tabs we iterated before will get this reset.
window.getInterface(Ci.nsIDocShell).contentViewer.resetCloseWindow();
return false;
}
}
return true;
return false;
}
/**

View File

@ -119,7 +119,7 @@
accesskey="&bookmarkAllTabs.accesskey;"
command="Browser:BookmarkAllTabs"/>
<menuitem id="context_closeTabsToTheEnd" label="&closeTabsToTheEnd.label;" accesskey="&closeTabsToTheEnd.accesskey;"
oncommand="gBrowser.removeTabsToTheEndFrom(TabContextMenu.contextTab);"/>
oncommand="gBrowser.removeTabsToTheEndFrom(TabContextMenu.contextTab, {animate: true});"/>
<menuitem id="context_closeOtherTabs" label="&closeOtherTabs.label;" accesskey="&closeOtherTabs.accesskey;"
oncommand="gBrowser.removeAllTabsBut(TabContextMenu.contextTab);"/>
<menuseparator/>

View File

@ -131,6 +131,11 @@ chatBrowserAccess.prototype = {
isTabContentWindow: function (aWindow) {
return this.contentWindow == aWindow;
},
canClose() {
let {BrowserUtils} = Cu.import("resource://gre/modules/BrowserUtils.jsm", {});
return BrowserUtils.canCloseWindow(window);
},
};
</script>

View File

@ -1,4 +1,4 @@
// -*- indent-tabs-mode: nil; js-indent-level: 4 -*-
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -567,28 +567,17 @@ Sanitizer.prototype = {
openWindows: {
privateStateForNewWindow: "non-private",
_canCloseWindow: function(aWindow) {
// Bug 967873 - Proxy nsDocumentViewer::PermitUnload to the child process
if (!aWindow.gMultiProcessBrowser) {
// Cargo-culted out of browser.js' WindowIsClosing because we don't care
// about TabView or the regular 'warn me before closing windows with N tabs'
// stuff here, and more importantly, we want to set aCallerClosesWindow to true
// when calling into permitUnload:
for (let browser of aWindow.gBrowser.browsers) {
let ds = browser.docShell;
// 'true' here means we will be closing the window soon, so please don't dispatch
// another onbeforeunload event when we do so. If unload is *not* permitted somewhere,
// we will reset the flag that this triggers everywhere so that we don't interfere
// with the browser after all:
if (ds.contentViewer && !ds.contentViewer.permitUnload(true)) {
return false;
}
}
if (aWindow.CanCloseWindow()) {
// We already showed PermitUnload for the window, so let's
// make sure we don't do it again when we actually close the
// window.
aWindow.skipNextCanClose = true;
return true;
}
return true;
},
_resetAllWindowClosures: function(aWindowList) {
for (let win of aWindowList) {
win.getInterface(Ci.nsIDocShell).contentViewer.resetCloseWindow();
win.skipNextCanClose = false;
}
},
clear: Task.async(function*() {

View File

@ -1190,25 +1190,29 @@
this._tabAttrModified(this.mCurrentTab, ["selected"]);
if (oldBrowser != newBrowser &&
oldBrowser.docShell &&
oldBrowser.docShell.contentViewer.inPermitUnload) {
// Since the user is switching away from a tab that has
// a beforeunload prompt active, we remove the prompt.
// This prevents confusing user flows like the following:
// 1. User attempts to close Firefox
// 2. User switches tabs (ingoring a beforeunload prompt)
// 3. User returns to tab, presses "Leave page"
let promptBox = this.getTabModalPromptBox(oldBrowser);
let prompts = promptBox.listPrompts();
// There might not be any prompts here if the tab was closed
// while in an onbeforeunload prompt, which will have
// destroyed aforementioned prompt already, so check there's
// something to remove, first:
if (prompts.length) {
// NB: This code assumes that the beforeunload prompt
// is the top-most prompt on the tab.
prompts[prompts.length - 1].abortPrompt();
}
oldBrowser.getInPermitUnload) {
oldBrowser.getInPermitUnload(inPermitUnload => {
if (!inPermitUnload) {
return;
}
// Since the user is switching away from a tab that has
// a beforeunload prompt active, we remove the prompt.
// This prevents confusing user flows like the following:
// 1. User attempts to close Firefox
// 2. User switches tabs (ingoring a beforeunload prompt)
// 3. User returns to tab, presses "Leave page"
let promptBox = this.getTabModalPromptBox(oldBrowser);
let prompts = promptBox.listPrompts();
// There might not be any prompts here if the tab was closed
// while in an onbeforeunload prompt, which will have
// destroyed aforementioned prompt already, so check there's
// something to remove, first:
if (prompts.length) {
// NB: This code assumes that the beforeunload prompt
// is the top-most prompt on the tab.
prompts[prompts.length - 1].abortPrompt();
}
});
}
oldBrowser._urlbarFocused = (gURLBar && gURLBar.focused);
@ -1843,7 +1847,10 @@
// If we open a new tab with the newtab URL in the default
// userContext, check if there is a preloaded browser ready.
if (aURI == BROWSER_NEW_TAB_URL && !aUserContextId) {
// Private windows are not included because both the label and the
// icon for the tab would be set incorrectly (see bug 1195981).
if (aURI == BROWSER_NEW_TAB_URL && !aUserContextId &&
!PrivateBrowsingUtils.isWindowPrivate(window)) {
b = this._getPreloadedBrowser();
usingPreloadedContent = !!b;
}
@ -2074,12 +2081,13 @@
<method name="removeTabsToTheEndFrom">
<parameter name="aTab"/>
<parameter name="aParams"/>
<body>
<![CDATA[
if (this.warnAboutClosingTabs(this.closingTabsEnum.TO_END, aTab)) {
let tabs = this.getTabsToTheEndFrom(aTab);
for (let i = tabs.length - 1; i >= 0; --i) {
this.removeTab(tabs[i], {animate: true});
this.removeTab(tabs[i], aParams);
}
}
]]>
@ -2127,6 +2135,7 @@
if (aParams) {
var animate = aParams.animate;
var byMouse = aParams.byMouse;
var skipPermitUnload = aParams.skipPermitUnload;
}
// Handle requests for synchronously removing an already
@ -2139,7 +2148,7 @@
var isLastTab = (this.tabs.length - this._removingTabs.length == 1);
if (!this._beginRemoveTab(aTab, false, null, true))
if (!this._beginRemoveTab(aTab, false, null, true, skipPermitUnload))
return;
if (!aTab.pinned && !aTab.hidden && aTab._fullyOpen && byMouse)
@ -2187,6 +2196,7 @@
<parameter name="aTabWillBeMoved"/>
<parameter name="aCloseWindowWithLastTab"/>
<parameter name="aCloseWindowFastpath"/>
<parameter name="aSkipPermitUnload"/>
<body>
<![CDATA[
if (aTab.closing ||
@ -2217,23 +2227,20 @@
newTab = true;
}
if (!aTab._pendingPermitUnload && !aTabWillBeMoved) {
let ds = browser.docShell;
if (ds && ds.contentViewer) {
// We need to block while calling permitUnload() because it
// processes the event queue and may lead to another removeTab()
// call before permitUnload() returns.
aTab._pendingPermitUnload = true;
let permitUnload = ds.contentViewer.permitUnload();
delete aTab._pendingPermitUnload;
// If we were closed during onbeforeunload, we return false now
// so we don't (try to) close the same tab again. Of course, we
// also stop if the unload was cancelled by the user:
if (aTab.closing || !permitUnload) {
// NB: deliberately keep the _closedDuringPermitUnload set to
// true so we keep exiting early in case of multiple calls.
return false;
}
if (!aTab._pendingPermitUnload && !aTabWillBeMoved && !aSkipPermitUnload) {
// We need to block while calling permitUnload() because it
// processes the event queue and may lead to another removeTab()
// call before permitUnload() returns.
aTab._pendingPermitUnload = true;
let {permitUnload} = browser.permitUnload();
delete aTab._pendingPermitUnload;
// If we were closed during onbeforeunload, we return false now
// so we don't (try to) close the same tab again. Of course, we
// also stop if the unload was cancelled by the user:
if (aTab.closing || !permitUnload) {
// NB: deliberately keep the _closedDuringPermitUnload set to
// true so we keep exiting early in case of multiple calls.
return false;
}
}
@ -4051,13 +4058,19 @@
}
case "DOMWindowClose": {
if (this.tabs.length == 1) {
// We already did PermitUnload in the content process
// for this tab (the only one in the window). So we don't
// need to do it again for any tabs.
window.skipNextCanClose = true;
window.close();
return;
}
let tab = this.getTabForBrowser(browser);
if (tab) {
this.removeTab(tab);
// Skip running PermitUnload since it already happened in
// the content process.
this.removeTab(tab, {skipPermitUnload: true});
}
break;
}
@ -4341,12 +4354,18 @@
if (!event.isTrusted)
return;
if (this.tabs.length == 1)
if (this.tabs.length == 1) {
// We already did PermitUnload in nsGlobalWindow::Close
// for this tab. There are no other tabs we need to do
// PermitUnload for.
window.skipNextCanClose = true;
return;
}
var tab = this._getTabForContentWindow(event.target);
if (tab) {
this.removeTab(tab);
// Skip running PermitUnload since it already happened.
this.removeTab(tab, {skipPermitUnload: true});
event.preventDefault();
}
]]>

View File

@ -148,7 +148,6 @@ skip-if = e10s # Bug 1101993 - times out for unknown reasons when run in the dir
[browser_backButtonFitts.js]
skip-if = os == "mac" # The Fitt's Law back button is not supported on OS X
[browser_beforeunload_duplicate_dialogs.js]
skip-if = e10s # bug 967873 means permitUnload doesn't work in e10s mode
[browser_blob-channelname.js]
[browser_bookmark_titles.js]
skip-if = buildapp == 'mulet' || toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341)

View File

@ -22,7 +22,7 @@ function test() {
function addTab(aURI, aIndex) {
var tab = gBrowser.addTab(aURI);
if (aIndex == 0)
gBrowser.removeTab(gBrowser.tabs[0]);
gBrowser.removeTab(gBrowser.tabs[0], {skipPermitUnload: true});
tab.linkedBrowser.addEventListener("load", function (event) {
event.currentTarget.removeEventListener("load", arguments.callee, true);
@ -41,14 +41,14 @@ function doTabsTest() {
var scheme = closedTab.linkedBrowser.currentURI.scheme;
Array.slice(gBrowser.tabs).forEach(function (aTab) {
if (aTab != closedTab && aTab.linkedBrowser.currentURI.scheme == scheme)
gBrowser.removeTab(aTab);
gBrowser.removeTab(aTab, {skipPermitUnload: true});
});
}, true);
gBrowser.removeTab(gBrowser.tabs[0]);
gBrowser.removeTab(gBrowser.tabs[0], {skipPermitUnload: true});
is(gBrowser.tabs.length, 1, "Related tabs are not closed unexpectedly");
gBrowser.addTab("about:blank");
gBrowser.removeTab(gBrowser.tabs[0]);
gBrowser.removeTab(gBrowser.tabs[0], {skipPermitUnload: true});
finish();
}

View File

@ -99,7 +99,7 @@ function checkBookmarksPanel(invoker, phase)
if (currentInvoker < invokers.length) {
checkBookmarksPanel(invokers[currentInvoker], 1);
} else {
gBrowser.removeCurrentTab();
gBrowser.removeTab(gBrowser.selectedTab, {skipPermitUnload: true});
PlacesUtils.bookmarks.removeItem(bookmarkId);
executeSoon(finish);
}

View File

@ -1,4 +1,4 @@
function test() {
add_task(function*() {
is(gBrowser.tabs.length, 1, "one tab is open");
gBrowser.selectedBrowser.focus();
@ -6,11 +6,15 @@ function test() {
var tab = gBrowser.selectedTab;
gPrefService.setBoolPref("browser.tabs.closeWindowWithLastTab", false);
let tabClosedPromise = BrowserTestUtils.removeTab(tab, {dontRemove: true});
EventUtils.synthesizeKey("w", { accelKey: true });
yield tabClosedPromise;
is(tab.parentNode, null, "ctrl+w removes the tab");
is(gBrowser.tabs.length, 1, "a new tab has been opened");
is(document.activeElement, gURLBar.inputField, "location bar is focused for the new tab");
if (gPrefService.prefHasUserValue("browser.tabs.closeWindowWithLastTab"))
gPrefService.clearUserPref("browser.tabs.closeWindowWithLastTab");
}
});

View File

@ -18,10 +18,13 @@ function record(aName) {
if (actual.length == expected.length) {
is(actual.toString(), expected.toString(),
"got events and progress notifications in expected order");
gBrowser.removeTab(tab);
gBrowser.removeTabsProgressListener(progressListener);
gBrowser.tabContainer.removeEventListener("TabOpen", TabOpen, false);
finish();
executeSoon(function(tab) {
gBrowser.removeTab(tab);
gBrowser.removeTabsProgressListener(progressListener);
gBrowser.tabContainer.removeEventListener("TabOpen", TabOpen, false);
finish();
}.bind(null, tab));
}
}

View File

@ -6,14 +6,14 @@ function test() {
childTab1 = gBrowser.addTab("about:blank", { relatedToCurrent: true });
gBrowser.selectedTab = childTab1;
gBrowser.removeCurrentTab();
gBrowser.removeTab(gBrowser.selectedTab, { skipPermitUnload: true });
is(idx(gBrowser.selectedTab), idx(tab1),
"closing a tab next to its parent selects the parent");
childTab1 = gBrowser.addTab("about:blank", { relatedToCurrent: true });
gBrowser.selectedTab = tab2;
gBrowser.selectedTab = childTab1;
gBrowser.removeCurrentTab();
gBrowser.removeTab(gBrowser.selectedTab, { skipPermitUnload: true });
is(idx(gBrowser.selectedTab), idx(tab2),
"closing a tab next to its parent doesn't select the parent if another tab had been selected ad interim");
@ -21,14 +21,14 @@ function test() {
childTab1 = gBrowser.addTab("about:blank", { relatedToCurrent: true });
childTab2 = gBrowser.addTab("about:blank", { relatedToCurrent: true });
gBrowser.selectedTab = childTab1;
gBrowser.removeCurrentTab();
gBrowser.removeTab(gBrowser.selectedTab, { skipPermitUnload: true });
is(idx(gBrowser.selectedTab), idx(childTab2),
"closing a tab next to its parent selects the next tab with the same parent");
gBrowser.removeCurrentTab();
gBrowser.removeTab(gBrowser.selectedTab, { skipPermitUnload: true });
is(idx(gBrowser.selectedTab), idx(tab2),
"closing the last tab in a set of child tabs doesn't go back to the parent");
gBrowser.removeTab(tab2);
gBrowser.removeTab(tab2, { skipPermitUnload: true });
}
function idx(tab) {

View File

@ -14,6 +14,13 @@ function testAttrib(elem, attrib, attribValue, msg) {
function test() {
waitForExplicitFinish();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
TabView._initFrame(runTest);
}
function runTest() {
is(gBrowser.tabs.length, 1, "one tab is open initially");
// Add several new tabs in sequence, hiding some, to ensure that the

View File

@ -5,6 +5,12 @@
function test() {
waitForExplicitFinish();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
TabView._initFrame(runTest);
}
function runTest() {
// establish initial state
is(gBrowser.tabs.length, 1, "we start with one tab");

View File

@ -1,4 +1,5 @@
function test () {
requestLongerTimeout(2);
waitForExplicitFinish();
var isHTTPS = false;

View File

@ -7,6 +7,12 @@
function test() {
waitForExplicitFinish();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
TabView._initFrame(runTest);
}
function runTest() {
// Add a tab that will get removed and hidden
let testTab = gBrowser.addTab("about:blank", {skipAnimation: true});
is(gBrowser.visibleTabs.length, 2, "just added a tab, so 2 tabs");

View File

@ -2,7 +2,7 @@
* 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/. */
function test() {
add_task(function*() {
is(gBrowser.tabs.length, 1, "one tab is open initially");
// Add several new tabs in sequence, interrupted by selecting a
@ -10,26 +10,29 @@ function test() {
// returning a list of opened tabs for verifying the expected order.
// The new tab behaviour is documented in bug 465673
let tabs = [];
let promises = [];
function addTab(aURL, aReferrer) {
tabs.push(gBrowser.addTab(aURL, {referrerURI: aReferrer}));
let tab = gBrowser.addTab(aURL, {referrerURI: aReferrer});
tabs.push(tab);
return BrowserTestUtils.browserLoaded(tab.linkedBrowser);
}
addTab("http://mochi.test:8888/#0");
yield addTab("http://mochi.test:8888/#0");
gBrowser.selectedTab = tabs[0];
addTab("http://mochi.test:8888/#1");
addTab("http://mochi.test:8888/#2", gBrowser.currentURI);
addTab("http://mochi.test:8888/#3", gBrowser.currentURI);
yield addTab("http://mochi.test:8888/#1");
yield addTab("http://mochi.test:8888/#2", gBrowser.currentURI);
yield addTab("http://mochi.test:8888/#3", gBrowser.currentURI);
gBrowser.selectedTab = tabs[tabs.length - 1];
gBrowser.selectedTab = tabs[0];
addTab("http://mochi.test:8888/#4", gBrowser.currentURI);
yield addTab("http://mochi.test:8888/#4", gBrowser.currentURI);
gBrowser.selectedTab = tabs[3];
addTab("http://mochi.test:8888/#5", gBrowser.currentURI);
yield addTab("http://mochi.test:8888/#5", gBrowser.currentURI);
gBrowser.removeTab(tabs.pop());
addTab("about:blank", gBrowser.currentURI);
yield addTab("about:blank", gBrowser.currentURI);
gBrowser.moveTabTo(gBrowser.selectedTab, 1);
addTab("http://mochi.test:8888/#6", gBrowser.currentURI);
addTab();
addTab("http://mochi.test:8888/#7");
yield addTab("http://mochi.test:8888/#6", gBrowser.currentURI);
yield addTab();
yield addTab("http://mochi.test:8888/#7");
function testPosition(tabNum, expectedPosition, msg) {
is(Array.indexOf(gBrowser.tabs, tabs[tabNum]), expectedPosition, msg);
@ -46,4 +49,4 @@ function test() {
testPosition(8, 9, "tab without referrer opens at the end");
tabs.forEach(gBrowser.removeTab, gBrowser);
}
});

View File

@ -18,5 +18,5 @@ function test() {
"gBrowser.selectTabAtIndex(-3) selects expected tab");
for (let i = 0; i < 9; i++)
gBrowser.removeCurrentTab();
gBrowser.removeTab(gBrowser.selectedTab, {skipPermitUnload: true});
}

View File

@ -2,7 +2,11 @@
* 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/. */
function test() {
add_task(function* () {
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
yield new Promise(resolve => TabView._initFrame(resolve));
// There should be one tab when we start the test
let [origTab] = gBrowser.visibleTabs;
@ -100,4 +104,5 @@ function test() {
if (tabViewWindow)
tabViewWindow.GroupItems.groupItems[0].close();
}
});

View File

@ -5,6 +5,12 @@
function test() {
waitForExplicitFinish();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
TabView._initFrame(runTest);
}
function runTest() {
let tabOne = gBrowser.addTab("about:blank");
let tabTwo = gBrowser.addTab("http://mochi.test:8888/");
gBrowser.selectedTab = tabTwo;

View File

@ -5,6 +5,12 @@
function test() {
waitForExplicitFinish();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
TabView._initFrame(runTest);
}
function runTest() {
// There should be one tab when we start the test
let [origTab] = gBrowser.visibleTabs;
is(gBrowser.visibleTabs.length, 1, "1 tab should be open");

View File

@ -2,7 +2,11 @@
* 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/. */
function test() {
add_task(function* test() {
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
yield new Promise(resolve => TabView._initFrame(resolve));
// There should be one tab when we start the test
let [origTab] = gBrowser.visibleTabs;
is(gBrowser.visibleTabs.length, 1, "there is one visible tab");
@ -51,4 +55,5 @@ function test() {
gBrowser.removeTab(testTab);
gBrowser.removeTab(pinned);
}
});

View File

@ -2,7 +2,11 @@
* 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/. */
function test() {
add_task(function* test() {
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
yield new Promise(resolve => TabView._initFrame(resolve));
gPrefService.setBoolPref("browser.ctrlTab.previews", true);
let [origTab] = gBrowser.visibleTabs;
@ -30,7 +34,7 @@ function test() {
if (gPrefService.prefHasUserValue("browser.ctrlTab.previews"))
gPrefService.clearUserPref("browser.ctrlTab.previews");
}
});
function pressCtrlTab(aShiftKey) {
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true, shiftKey: !!aShiftKey });

View File

@ -416,7 +416,7 @@ function loadIntoTab(tab, url, callback) {
function ensureBrowserTabClosed(tab) {
let promise = ensureEventFired(gBrowser.tabContainer, "TabClose");
gBrowser.removeTab(tab);
gBrowser.removeTab(tab, {skipPermitUnload: true});
return promise;
}

View File

@ -313,6 +313,7 @@ p {
border-radius: 2px;
border-bottom-right-radius: 0;
border-top-right-radius: 0;
line-height: 0.9rem;
}
/* Alerts/Notifications */

View File

@ -430,16 +430,11 @@ html[dir="rtl"] .room-failure > .settings-control {
.screen-share-menu.dropdown-menu,
.settings-menu.dropdown-menu {
left: auto;
bottom: 3.1rem;
}
.screen-share-menu.dropdown-menu {
/*offset dropdown menu to be above menu button*/
right: 40px;
}
.settings-menu.dropdown-menu {
left: auto;
/*offset dropdown menu to be above menu button*/
right: 14px;
}

View File

@ -338,7 +338,10 @@ loop.store = loop.store || {};
}
this._endSession();
this.setStoreState({callState: CALL_STATES.FINISHED});
this.setStoreState({
callState: this._storeState.callState === CALL_STATES.ONGOING ?
CALL_STATES.FINISHED : CALL_STATES.CLOSE
});
},
/**

View File

@ -163,7 +163,7 @@ loop.shared.views = (function(_, mozL10n) {
React.createElement("div", null,
React.createElement("button", {className: screenShareClasses,
onClick: this.handleClick,
ref: "menu-button",
ref: "anchor",
title: this._getTitle()},
isActive ? null : React.createElement("span", {className: "chevron"})
),

View File

@ -163,7 +163,7 @@ loop.shared.views = (function(_, mozL10n) {
<div>
<button className={screenShareClasses}
onClick={this.handleClick}
ref="menu-button"
ref="anchor"
title={this._getTitle()}>
{isActive ? null : <span className="chevron"/>}
</button>

View File

@ -777,12 +777,22 @@ describe("loop.store.ConversationStore", function () {
sinon.assert.calledOnce(wsHangupSpy);
});
it("should set the callState to finished", function() {
it("should set the callState to finished for ongoing call state", function() {
store.hangupCall(new sharedActions.HangupCall());
expect(store.getStoreState("callState")).eql(CALL_STATES.FINISHED);
});
it("should set the callState to CLOSE for non-ongoing call state", function() {
store.setStoreState({
callState: CALL_STATES.CONNECTING
});
store.hangupCall(new sharedActions.HangupCall());
expect(store.getStoreState("callState")).eql(CALL_STATES.CLOSE);
});
it("should release mozLoop callsData", function() {
store.hangupCall(new sharedActions.HangupCall());

View File

@ -6,6 +6,10 @@ add_task(function* () {
/** Bug 607016 - If a tab is never restored, attributes (eg. hidden) aren't updated correctly **/
ignoreAllUncaughtExceptions();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
yield new Promise(resolve => TabView._initFrame(resolve));
// Set the pref to true so we know exactly how many tabs should be restoring at
// any given time. This guarantees that a finishing load won't start another.
Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true);

View File

@ -7,6 +7,12 @@
function test() {
waitForExplicitFinish();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
TabView._initFrame(runTest);
}
function runTest() {
// We speed up the interval between session saves to ensure that the test
// runs quickly.
Services.prefs.setIntPref("browser.sessionstore.interval", 2000);

View File

@ -229,6 +229,8 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY addons.commandkey "A">
<!ENTITY webapps.label "Apps">
<!ENTITY webapps.accesskey "p">
<!ENTITY loopMenuItem.label "Start a conversation…">
<!ENTITY loopMenuItem.accesskey "t">
<!ENTITY webDeveloperMenu.label "Web Developer">
<!ENTITY webDeveloperMenu.accesskey "W">

View File

@ -39,11 +39,18 @@ var RemotePrompt = {
let tabPrompt = window.gBrowser.getTabModalPromptBox(browser)
let callbackInvoked = false;
let newPrompt;
let needRemove = false;
let promptId = args._remoteId;
function onPromptClose(forceCleanup) {
// It's possible that we removed the prompt during the
// appendPrompt call below. In that case, newPrompt will be
// undefined. We set the needRemove flag to remember to remove
// it right after we've finished adding it.
if (newPrompt)
tabPrompt.removePrompt(newPrompt);
else
needRemove = true;
PromptUtils.fireDialogEvent(window, "DOMModalDialogClosed", browser);
browser.messageManager.sendAsyncMessage("Prompt:Close", args);
@ -69,6 +76,10 @@ var RemotePrompt = {
newPrompt = tabPrompt.appendPrompt(args, onPromptClose);
if (needRemove) {
tabPrompt.removePrompt(newPrompt);
}
// TODO since we don't actually open a window, need to check if
// there's other stuff in nsWindowWatcher::OpenWindowInternal
// that we might need to do here as well.

View File

@ -49,12 +49,6 @@ import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import com.mozilla.SUTAgentAndroid.R;
import com.mozilla.SUTAgentAndroid.SUTAgentAndroid;
@ -2964,53 +2958,6 @@ private void CancelNotification()
return(sRet);
}
public String GetInternetData(String sHost, String sPort, String sURL)
{
String sRet = "";
String sNewURL = "";
HttpClient httpClient = new DefaultHttpClient();
try
{
sNewURL = "http://" + sHost + ((sPort.length() > 0) ? (":" + sPort) : "") + sURL;
HttpGet request = new HttpGet(sNewURL);
HttpResponse response = httpClient.execute(request);
int status = response.getStatusLine().getStatusCode();
// we assume that the response body contains the error message
if (status != HttpStatus.SC_OK)
{
ByteArrayOutputStream ostream = new ByteArrayOutputStream();
response.getEntity().writeTo(ostream);
Log.e("HTTP CLIENT", ostream.toString());
}
else
{
InputStream content = response.getEntity().getContent();
byte [] data = new byte [2048];
int nRead = content.read(data);
sRet = new String(data, 0, nRead);
content.close(); // this will also close the connection
}
}
catch (IllegalArgumentException e)
{
sRet = e.getLocalizedMessage();
e.printStackTrace();
}
catch (ClientProtocolException e)
{
sRet = e.getLocalizedMessage();
e.printStackTrace();
}
catch (IOException e)
{
sRet = e.getLocalizedMessage();
e.printStackTrace();
}
return(sRet);
}
public String GetTimeZone()
{
String sRet = "";

View File

@ -9,7 +9,6 @@ import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import org.apache.http.conn.util.InetAddressUtils;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
@ -19,6 +18,7 @@ import java.util.Date;
import java.util.Enumeration;
import java.util.Formatter;
import java.util.List;
import java.util.regex.Pattern;
import java.util.Timer;
import com.mozilla.SUTAgentAndroid.service.ASMozStub;
@ -56,6 +56,8 @@ public class SUTAgentAndroid extends Activity
{
final Handler mHandler = new Handler();
private static final Pattern IPV4_PATTERN = Pattern.compile("^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
public static final int START_PRG = 1959;
MenuItem mExitMenuItem;
Timer timer = null;
@ -810,6 +812,10 @@ public class SUTAgentAndroid extends Activity
return sHWID;
}
public static boolean isIPv4Address(final String input) {
return IPV4_PATTERN.matcher(input).matches();
}
public static InetAddress getLocalInetAddress() throws SocketException
{
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();)
@ -818,7 +824,7 @@ public class SUTAgentAndroid extends Activity
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();)
{
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && InetAddressUtils.isIPv4Address(inetAddress.getHostAddress()))
if (!inetAddress.isLoopbackAddress() && isIPv4Address(inetAddress.getHostAddress()))
{
return inetAddress;
}

View File

@ -107,7 +107,8 @@ function removeTab(aTab, aWindow) {
let targetWindow = aWindow || window;
let targetBrowser = targetWindow.gBrowser;
targetBrowser.removeTab(aTab);
// browser_net_pane-toggle.js relies on synchronous removeTab behavior.
targetBrowser.removeTab(aTab, {skipPermitUnload: true});
}
function waitForNavigation(aTarget) {

View File

@ -28,8 +28,8 @@ function runCodeMirrorTest(browser) {
'function check() { ' +
' var doc = content.document; var out = doc.getElementById("status"); ' +
' if (!out || !out.classList.contains("done")) { return setTimeout(check, 100); }' +
' sendSyncMessage("done", { failed: content.wrappedJSObject.failed });' +
' sendAsyncMessage("done", { failed: content.wrappedJSObject.failed });' +
'}' +
'check();'
, true);
}
}

View File

@ -7764,7 +7764,7 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
mTiming->NotifyBeforeUnload();
bool okToUnload;
rv = mContentViewer->PermitUnload(false, &okToUnload);
rv = mContentViewer->PermitUnload(&okToUnload);
if (NS_SUCCEEDED(rv) && !okToUnload) {
// The user chose not to unload the page, interrupt the load.
@ -10097,7 +10097,7 @@ nsDocShell::InternalLoad(nsIURI* aURI,
// protocol handler deals with this for javascript: URLs.
if (!isJavaScript && aFileName.IsVoid() && mContentViewer) {
bool okToUnload;
rv = mContentViewer->PermitUnload(false, &okToUnload);
rv = mContentViewer->PermitUnload(&okToUnload);
if (NS_SUCCEEDED(rv) && !okToUnload) {
// The user chose not to unload the page, interrupt the

View File

@ -31,7 +31,7 @@ class nsDOMNavigationTiming;
[ptr] native nsDOMNavigationTimingPtr(nsDOMNavigationTiming);
[ref] native nsIContentViewerTArray(nsTArray<nsCOMPtr<nsIContentViewer> >);
[scriptable, builtinclass, uuid(702e0a92-7d63-490e-b5ee-d247e6bd4588)]
[scriptable, builtinclass, uuid(91b6c1f3-fc5f-43a9-88f4-9286bd19387f)]
interface nsIContentViewer : nsISupports
{
@ -46,12 +46,8 @@ interface nsIContentViewer : nsISupports
/**
* Checks if the document wants to prevent unloading by firing beforeunload on
* the document, and if it does, prompts the user. The result is returned.
*
* @param aCallerClosesWindow indicates that the current caller will close the
* window. If the method returns true, all subsequent calls will be
* ignored.
*/
boolean permitUnload([optional] in boolean aCallerClosesWindow);
boolean permitUnload();
/**
* Exposes whether we're blocked in a call to permitUnload.
@ -63,8 +59,7 @@ interface nsIContentViewer : nsISupports
* track of whether the user has responded to a prompt.
* Used internally by the scriptable version to ensure we only prompt once.
*/
[noscript,nostdcall] boolean permitUnloadInternal(in boolean aCallerClosesWindow,
inout boolean aShouldPrompt);
[noscript,nostdcall] boolean permitUnloadInternal(inout boolean aShouldPrompt);
/**
* Exposes whether we're in the process of firing the beforeunload event.
@ -72,16 +67,6 @@ interface nsIContentViewer : nsISupports
*/
readonly attribute boolean beforeUnloadFiring;
/**
* Works in tandem with permitUnload, if the caller decides not to close the
* window it indicated it will, it is the caller's responsibility to reset
* that with this method.
*
* @Note this method is only meant to be called on documents for which the
* caller has indicated that it will close the window. If that is not the case
* the behavior of this method is undefined.
*/
void resetCloseWindow();
void pageHide(in boolean isUnload);
/**

View File

@ -103,7 +103,6 @@ skip-if = e10s
skip-if = e10s # Bug ?????? - event handler checks event.target is the content document and test e10s-utils doesn't do that.
[browser_multiple_pushState.js]
[browser_onbeforeunload_navigation.js]
skip-if = e10s
[browser_search_notification.js]
[browser_timelineMarkers-01.js]
[browser_timelineMarkers-02.js]

View File

@ -10,6 +10,7 @@ SpecialPowers.pushPrefEnv({"set": [["dom.require_user_interaction_for_beforeunlo
var loadExpected = TEST_PAGE;
var testTab;
var testsLength;
var loadStarted = false;
var tabStateListener = {
@ -40,6 +41,10 @@ function onTabLoaded(event) {
return;
}
if (!testsLength) {
testsLength = testTab.linkedBrowser.contentWindow.wrappedJSObject.testFns.length;
}
is(loadedPage, loadExpected, "Loaded the expected page");
if (contentWindow) {
is(contentWindow.document, event.target, "Same doc");
@ -102,47 +107,9 @@ function onTabModalDialogLoaded(node) {
// Listen for the dialog being created
Services.obs.addObserver(onTabModalDialogLoaded, "tabmodal-dialog-loaded", false);
var testFns = [
function(e) {
e.target.location.href = 'otherpage-href-set.html';
return "stop";
},
function(e) {
e.target.location.reload();
return "stop";
},
function(e) {
e.target.location.replace('otherpage-location-replaced.html');
return "stop";
},
function(e) {
var link = e.target.createElement('a');
link.href = "otherpage.html";
e.target.body.appendChild(link);
link.click();
return "stop";
},
function(e) {
var link = e.target.createElement('a');
link.href = "otherpage.html";
link.setAttribute("target", "_blank");
e.target.body.appendChild(link);
link.click();
return "stop";
},
function(e) {
var link = e.target.createElement('a');
link.href = e.target.location.href;
e.target.body.appendChild(link);
link.setAttribute("target", "somearbitrarywindow");
link.click();
return "stop";
},
];
function runNextTest() {
currentTest++;
if (currentTest >= testFns.length) {
if (currentTest >= testsLength) {
if (!stayingOnPage) {
finish();
return;
@ -171,10 +138,10 @@ function runCurrentTest() {
contentWindow.dialogWasInvoked = false;
originalLocation = contentWindow.location.href;
// And run this test:
info("Running test with onbeforeunload " + testFns[currentTest].toSource());
contentWindow.onbeforeunload = testFns[currentTest];
info("Running test with onbeforeunload " + contentWindow.wrappedJSObject.testFns[currentTest].toSource());
contentWindow.onbeforeunload = contentWindow.wrappedJSObject.testFns[currentTest];
loadStarted = false;
contentWindow.location.href = TARGETED_PAGE;
testTab.linkedBrowser.loadURI(TARGETED_PAGE);
}
var onAfterPageLoad = runNextTest;

View File

@ -7,4 +7,44 @@
<body>
Waiting for onbeforeunload to hit...
</body>
<script>
var testFns = [
function(e) {
e.target.location.href = 'otherpage-href-set.html';
return "stop";
},
function(e) {
e.target.location.reload();
return "stop";
},
function(e) {
e.target.location.replace('otherpage-location-replaced.html');
return "stop";
},
function(e) {
var link = e.target.createElement('a');
link.href = "otherpage.html";
e.target.body.appendChild(link);
link.click();
return "stop";
},
function(e) {
var link = e.target.createElement('a');
link.href = "otherpage.html";
link.setAttribute("target", "_blank");
e.target.body.appendChild(link);
link.click();
return "stop";
},
function(e) {
var link = e.target.createElement('a');
link.href = e.target.location.href;
e.target.body.appendChild(link);
link.setAttribute("target", "somearbitrarywindow");
link.click();
return "stop";
},
];
</script>
</html>

View File

@ -31,8 +31,8 @@ function makeTimelineTest(frameScriptName, url) {
info(message.data.message);
});
mm.addMessageListener("browser:test:finish", function(ignore) {
finish();
gBrowser.removeCurrentTab();
finish();
});
});
}

View File

@ -14,6 +14,7 @@
#ifndef __nsContentPolicyUtils_h__
#define __nsContentPolicyUtils_h__
#include "nsContentUtils.h"
#include "nsIContentPolicy.h"
#include "nsIContent.h"
#include "nsIScriptSecurityManager.h"
@ -194,7 +195,9 @@ NS_CP_ContentTypeName(uint32_t contentType)
do_GetService( \
"@mozilla.org/data-document-content-policy;1"); \
if (dataPolicy) { \
dataPolicy-> action (contentType, contentLocation, \
nsContentPolicyType externalType = \
nsContentUtils::InternalContentPolicyTypeToExternal(contentType);\
dataPolicy-> action (externalType, contentLocation, \
requestOrigin, context, \
mimeType, extra, \
originPrincipal, decision); \

View File

@ -8754,6 +8754,17 @@ nsGlobalWindow::CanClose()
{
MOZ_ASSERT(IsOuterWindow());
if (mIsChrome) {
nsCOMPtr<nsIBrowserDOMWindow> bwin;
nsIDOMChromeWindow* chromeWin = static_cast<nsGlobalChromeWindow*>(this);
chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
bool canClose = true;
if (bwin && NS_SUCCEEDED(bwin->CanClose(&canClose))) {
return canClose;
}
}
if (!mDocShell) {
return true;
}
@ -8767,7 +8778,7 @@ nsGlobalWindow::CanClose()
mDocShell->GetContentViewer(getter_AddRefs(cv));
if (cv) {
bool canClose;
nsresult rv = cv->PermitUnload(false, &canClose);
nsresult rv = cv->PermitUnload(&canClose);
if (NS_SUCCEEDED(rv) && !canClose)
return false;

View File

@ -1472,7 +1472,6 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode)
return mode;
}
#ifdef DEBUG
int32_t
CanvasRenderingContext2D::GetWidth() const
{
@ -1484,7 +1483,6 @@ CanvasRenderingContext2D::GetHeight() const
{
return mHeight;
}
#endif
NS_IMETHODIMP
CanvasRenderingContext2D::SetDimensions(int32_t width, int32_t height)

View File

@ -418,10 +418,9 @@ public:
nsresult Redraw();
#ifdef DEBUG
virtual int32_t GetWidth() const override;
virtual int32_t GetHeight() const override;
#endif
virtual int32_t GetWidth() const override;
virtual int32_t GetHeight() const override;
// nsICanvasRenderingContextInternal
/**
* Gets the pres shell from either the canvas element or the doc shell

View File

@ -480,7 +480,6 @@ WebGLContext::SetContextOptions(JSContext* cx, JS::Handle<JS::Value> options)
return NS_OK;
}
#ifdef DEBUG
int32_t
WebGLContext::GetWidth() const
{
@ -492,7 +491,6 @@ WebGLContext::GetHeight() const
{
return mHeight;
}
#endif
/* So there are a number of points of failure here. We might fail based
* on EGL vs. WGL, or we might fail to alloc a too-large size, or we

View File

@ -215,10 +215,9 @@ public:
NS_DECL_NSIDOMWEBGLRENDERINGCONTEXT
// nsICanvasRenderingContextInternal
#ifdef DEBUG
virtual int32_t GetWidth() const override;
virtual int32_t GetHeight() const override;
#endif
NS_IMETHOD SetDimensions(int32_t width, int32_t height) override;
NS_IMETHOD InitializeWithSurface(nsIDocShell*, gfxASurface*, int32_t,
int32_t) override

View File

@ -80,11 +80,9 @@ public:
return mCanvasElement;
}
#ifdef DEBUG
// Useful for testing
virtual int32_t GetWidth() const = 0;
virtual int32_t GetHeight() const = 0;
#endif
// Dimensions of the canvas, in pixels.
virtual int32_t GetWidth() const = 0;
virtual int32_t GetHeight() const = 0;
// Sets the dimensions of the canvas, in pixels. Called
// whenever the size of the element changes.

View File

@ -669,18 +669,19 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
return;
}
#ifdef DEBUG
if (mCurrentContext) {
// We disallow canvases of width or height zero, and set them to 1, so
// we will have a discrepancy with the sizes of the canvas and the context.
// That discrepancy is OK, the rest are not.
nsIntSize elementSize = GetWidthHeight();
MOZ_ASSERT(elementSize.width == mCurrentContext->GetWidth() ||
(elementSize.width == 0 && mCurrentContext->GetWidth() == 1));
MOZ_ASSERT(elementSize.height == mCurrentContext->GetHeight() ||
(elementSize.height == 0 && mCurrentContext->GetHeight() == 1));
if ((elementSize.width != mCurrentContext->GetWidth() &&
(elementSize.width != 0 || mCurrentContext->GetWidth() != 1)) ||
(elementSize.height != mCurrentContext->GetHeight() &&
(elementSize.height != 0 || mCurrentContext->GetHeight() != 1))) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
}
#endif
uint8_t* imageBuffer = nullptr;
int32_t format = 0;

View File

@ -1519,7 +1519,7 @@ nsHTMLDocument::Open(JSContext* cx,
if (cv) {
bool okToUnload;
if (NS_SUCCEEDED(cv->PermitUnload(false, &okToUnload)) && !okToUnload) {
if (NS_SUCCEEDED(cv->PermitUnload(&okToUnload)) && !okToUnload) {
// We don't want to unload, so stop here, but don't throw an
// exception.
nsCOMPtr<nsIDocument> ret = this;

View File

@ -23,7 +23,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=448166
/** Test for Bug 448166 **/
isnot($("test").href, "http://www.mozilla.org/",
"Should notice unpaired surrogate");
is($("test").href, "http://www.moz\ufffdilla.org/",
is($("test").href, "http://www.xn--mozilla-2e14b.org/",
"Should replace unpaired surrogate with replacement char");
is($("control").href, "http://www.mozilla.org/",
"Just making sure .href works");

View File

@ -17,7 +17,7 @@ interface nsIOpenURIInFrameParams : nsISupports
attribute boolean isPrivate;
};
[scriptable, uuid(99f5a347-722c-4337-bd38-f14ec94801b3)]
[scriptable, uuid(31da1ce2-aec4-4c26-ac66-d622935c3bf4)]
/**
* The C++ source has access to the browser script source through
@ -99,6 +99,14 @@ interface nsIBrowserDOMWindow : nsISupports
* @return whether the window is the main content window for any
* currently open tab in this toplevel browser window.
*/
boolean isTabContentWindow(in nsIDOMWindow aWindow);
boolean isTabContentWindow(in nsIDOMWindow aWindow);
/**
* This function is responsible for calling
* nsIContentViewer::PermitUnload on each frame in the window. It
* returns true if closing the window is allowed. See canClose() in
* BrowserUtils.jsm for a simple implementation of this method.
*/
boolean canClose();
};

View File

@ -749,7 +749,7 @@ nsJSChannel::EvaluateScript()
if (cv) {
bool okToUnload;
if (NS_SUCCEEDED(cv->PermitUnload(false, &okToUnload)) &&
if (NS_SUCCEEDED(cv->PermitUnload(&okToUnload)) &&
!okToUnload) {
// The user didn't want to unload the current
// page, translate this into an undefined

View File

@ -200,10 +200,10 @@ DecoderTraits::IsWebMType(const nsACString& aType)
static bool
IsGStreamerSupportedType(const nsACString& aMimeType)
{
if (!MediaDecoder::IsGStreamerEnabled())
if (DecoderTraits::IsWebMType(aMimeType))
return false;
if (DecoderTraits::IsWebMType(aMimeType) && !Preferences::GetBool("media.prefer-gstreamer", false))
if (!MediaDecoder::IsGStreamerEnabled())
return false;
if (IsOggType(aMimeType) && !Preferences::GetBool("media.prefer-gstreamer", false))
@ -366,7 +366,7 @@ static bool
IsMP3SupportedType(const nsACString& aType,
const nsAString& aCodecs = EmptyString())
{
return aType.EqualsASCII("audio/mpeg") && MP3Decoder::IsEnabled();
return MP3Decoder::CanHandleMediaType(aType, aCodecs);
}
#ifdef MOZ_APPLEMEDIA

View File

@ -10,10 +10,7 @@
#include "MediaFormatReader.h"
#include "MP3Demuxer.h"
#include "mozilla/Preferences.h"
#ifdef MOZ_WIDGET_ANDROID
#include "AndroidBridge.h"
#endif
#include "PlatformDecoderModule.h"
namespace mozilla {
@ -32,14 +29,61 @@ MP3Decoder::CreateStateMachine() {
return new MediaDecoderStateMachine(this, reader);
}
static already_AddRefed<MediaDataDecoder>
CreateTestMP3Decoder(AudioInfo& aConfig)
{
PlatformDecoderModule::Init();
nsRefPtr<PlatformDecoderModule> platform = PlatformDecoderModule::Create();
if (!platform || !platform->SupportsMimeType(aConfig.mMimeType)) {
return nullptr;
}
nsRefPtr<MediaDataDecoder> decoder(
platform->CreateDecoder(aConfig, nullptr, nullptr));
if (!decoder) {
return nullptr;
}
return decoder.forget();
}
static bool
CanCreateMP3Decoder()
{
static bool haveCachedResult = false;
static bool result = false;
if (haveCachedResult) {
return result;
}
AudioInfo config;
config.mMimeType = "audio/mpeg";
config.mRate = 48000;
config.mChannels = 2;
config.mBitDepth = 16;
nsRefPtr<MediaDataDecoder> decoder(CreateTestMP3Decoder(config));
if (decoder) {
result = true;
}
haveCachedResult = true;
return result;
}
/* static */
bool
MP3Decoder::IsEnabled() {
#ifdef MOZ_WIDGET_ANDROID
// We need android.media.MediaCodec which exists in API level 16 and higher.
return AndroidBridge::Bridge()->GetAPIVersion() >= 16;
#else
return Preferences::GetBool("media.mp3.enabled");
#endif
return CanCreateMP3Decoder();
}
/* static */
bool MP3Decoder::CanHandleMediaType(const nsACString& aType,
const nsAString& aCodecs)
{
if (aType.EqualsASCII("audio/mp3") || aType.EqualsASCII("audio/mpeg")) {
return CanCreateMP3Decoder() &&
(aCodecs.IsEmpty() || aCodecs.EqualsASCII("mp3"));
}
return false;
}
} // namespace mozilla

View File

@ -19,6 +19,8 @@ public:
// Returns true if the MP3 backend is preffed on, and we're running on a
// platform that is likely to have decoders for the format.
static bool IsEnabled();
static bool CanHandleMediaType(const nsACString& aType,
const nsAString& aCodecs);
};
} // namespace mozilla

View File

@ -318,10 +318,13 @@ MP3TrackDemuxer::GetResourceOffset() const {
TimeIntervals
MP3TrackDemuxer::GetBuffered() {
// TODO: bug 1169485.
MP3DEMUXER_LOG("MP3TrackDemuxer::GetBuffered()");
NS_WARNING("Unimplemented function GetBuffered");
return TimeIntervals();
TimeUnit duration = Duration();
if (duration <= TimeUnit()) {
return TimeIntervals();
}
AutoPinned<MediaResource> stream(mSource.GetResource());
return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds());
}
int64_t
@ -458,6 +461,8 @@ MP3TrackDemuxer::GetNextFrame(const MediaByteRange& aRange) {
frame->mTime = Duration(mFrameIndex - 1).ToMicroseconds();
frame->mDuration = Duration(1).ToMicroseconds();
frame->mTimecode = frame->mTime;
frame->mKeyframe = true;
MOZ_ASSERT(frame->mTime >= 0);
MOZ_ASSERT(frame->mDuration > 0);

View File

@ -26,6 +26,11 @@ public:
bool IsSeekable() const override;
void NotifyDataArrived(uint32_t aLength, int64_t aOffset) override;
void NotifyDataRemoved() override;
// Do not shift the calculated buffered range by the start time of the first
// decoded frame. The mac MP3 decoder will buffer some samples and the first
// frame returned has typically a start time that is non-zero, causing our
// buffered range to have a negative start time.
bool ShouldComputeStartTime() const override { return false; }
private:
// Synchronous initialization.

View File

@ -387,8 +387,9 @@ RTCPeerConnection.prototype = {
"RTCPeerConnection constructor passed invalid RTCConfiguration");
}
// Save the appId
this._appId = Cu.getWebIDLCallerPrincipal().appId;
this._https = this._win.document.documentURIObject.schemeIs("https");
var principal = Cu.getWebIDLCallerPrincipal();
this._appId = principal.appId;
this._isChrome = Services.scriptSecurityManager.isSystemPrincipal(principal);
// Get the offline status for this appId
let appOffline = false;
@ -778,7 +779,8 @@ RTCPeerConnection.prototype = {
if (this._havePermission) {
return this._havePermission;
}
if (AppConstants.MOZ_B2G ||
if (this._isChrome ||
AppConstants.MOZ_B2G ||
Services.prefs.getBoolPref("media.navigator.permission.disabled")) {
return this._havePermission = Promise.resolve();
}

View File

@ -76,7 +76,7 @@ var gPlayedTests = [
{ name:"seek.ogv", type:"video/ogg", duration:3.966 },
{ name:"seek.webm", type:"video/webm", duration:3.966 },
{ name:"gizmo.mp4", type:"video/mp4", duration:5.56 },
{ name:"owl.mp3", type:"audio/mpeg", duration:3.29 },
{ name:"owl.mp3", type:"audio/mpeg", duration:3.343 },
// Disable vbr.mp3 to see if it reduces the error of AUDCLNT_E_CPUUSAGE_EXCEEDED.
// See bug 1110922 comment 26.
//{ name:"vbr.mp3", type:"audio/mpeg", duration:10.0 },
@ -237,13 +237,13 @@ var gPlayTests = [
{ name:"small-shot.m4a", type:"audio/mp4", duration:0.29 },
{ name:"small-shot.mp3", type:"audio/mpeg", duration:0.27 },
{ name:"owl.mp3", type:"audio/mpeg", duration:3.29 },
{ name:"owl.mp3", type:"audio/mpeg", duration:3.343 },
// owl.mp3 as above, but with something funny going on in the ID3v2 tag
// that causes DirectShow to fail.
{ name:"owl-funny-id3.mp3", type:"audio/mpeg", duration:3.29 },
{ name:"owl-funny-id3.mp3", type:"audio/mpeg", duration:3.343 },
// owl.mp3 as above, but with something even funnier going on in the ID3v2 tag
// that causes DirectShow to fail.
{ name:"owl-funnier-id3.mp3", type:"audio/mpeg", duration:3.29 },
{ name:"owl-funnier-id3.mp3", type:"audio/mpeg", duration:3.343 },
// One second of silence with ~140KB of ID3 tags. Usually when the first MP3
// frame is at such a high offset into the file, MP3FrameParser will give up
// and report that the stream is not MP3. However, it does not count ID3 tags
@ -469,7 +469,7 @@ var gSeekTests = [
{ name:"split.webm", type:"video/webm", duration:1.967 },
{ name:"detodos.opus", type:"audio/ogg; codecs=opus", duration:2.9135 },
{ name:"gizmo.mp4", type:"video/mp4", duration:5.56 },
{ name:"owl.mp3", type:"audio/mpeg", duration:3.29 },
{ name:"owl.mp3", type:"audio/mpeg", duration:3.343 },
{ name:"bogus.duh", type:"bogus/duh", duration:123 }
];
@ -523,7 +523,7 @@ if (getAndroidVersion() >= 18) {
var gAudioTests = [
{ name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
{ name:"sound.ogg", type:"audio/ogg" },
{ name:"owl.mp3", type:"audio/mpeg", duration:3.29 },
{ name:"owl.mp3", type:"audio/mpeg", duration:3.343 },
{ name:"small-shot.m4a", type:"audio/mp4", duration:0.29 },
{ name:"bogus.duh", type:"bogus/duh", duration:123 }
];

View File

@ -580,8 +580,8 @@ AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
, mLoopStart(0.0)
, mLoopEnd(0.0)
// mOffset and mDuration are initialized in Start().
, mPlaybackRate(new AudioParam(this, SendPlaybackRateToStream, 1.0f, "playbackRate"))
, mDetune(new AudioParam(this, SendDetuneToStream, 0.0f, "detune"))
, mPlaybackRate(new AudioParam(this, PLAYBACKRATE, 1.0f, "playbackRate"))
, mDetune(new AudioParam(this, DETUNE, 0.0f, "detune"))
, mLoop(false)
, mStartCalled(false)
{
@ -784,28 +784,6 @@ AudioBufferSourceNode::NotifyMainThreadStreamFinished()
MarkInactive();
}
void
AudioBufferSourceNode::SendPlaybackRateToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent)
{
AudioBufferSourceNode* This = static_cast<AudioBufferSourceNode*>(aNode);
if (!This->mStream) {
return;
}
SendTimelineEventToStream(This, PLAYBACKRATE, aEvent);
}
void
AudioBufferSourceNode::SendDetuneToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent)
{
AudioBufferSourceNode* This = static_cast<AudioBufferSourceNode*>(aNode);
if (!This->mStream) {
return;
}
SendTimelineEventToStream(This, DETUNE, aEvent);
}
void
AudioBufferSourceNode::SendDopplerShiftToStream(double aDopplerShift)
{

View File

@ -129,10 +129,6 @@ private:
void SendLoopParametersToStream();
void SendBufferParameterToStream(JSContext* aCx);
void SendOffsetAndDurationParametersToStream(AudioNodeStream* aStream);
static void SendPlaybackRateToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent);
static void SendDetuneToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent);
private:
double mLoopStart;

View File

@ -303,15 +303,6 @@ AudioNode::SendChannelMixingParametersToStream()
}
}
void
AudioNode::SendTimelineEventToStream(AudioNode* aNode, uint32_t aIndex,
const AudioTimelineEvent& aEvent)
{
AudioNodeStream* ns = aNode->mStream;
MOZ_ASSERT(ns, "How come we don't have a stream here?");
ns->SendTimelineEvent(aIndex, aEvent);
}
void
AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv)
{

View File

@ -28,7 +28,6 @@ class AudioBufferSourceNode;
class AudioParam;
class AudioParamTimeline;
struct ThreeDPoint;
struct AudioTimelineEvent;
/**
* The DOM object representing a Web Audio AudioNode.
@ -212,20 +211,15 @@ public:
virtual const char* NodeType() const = 0;
private:
friend class AudioBufferSourceNode;
// This could possibly delete 'this'.
void DisconnectFromGraph();
protected:
static void Callback(AudioNode* aNode) { /* not implemented */ }
// Helpers for sending different value types to streams
void SendDoubleParameterToStream(uint32_t aIndex, double aValue);
void SendInt32ParameterToStream(uint32_t aIndex, int32_t aValue);
void SendThreeDPointParameterToStream(uint32_t aIndex, const ThreeDPoint& aValue);
void SendChannelMixingParametersToStream();
static void SendTimelineEventToStream(AudioNode* aNode, uint32_t aIndex,
const dom::AudioTimelineEvent& aEvent);
private:
nsRefPtr<AudioContext> mContext;

View File

@ -493,20 +493,18 @@ AudioNodeStream::UpMixDownMixChunk(const AudioBlock* aChunk,
nsTArray<const float*>& aOutputChannels,
nsTArray<float>& aDownmixBuffer)
{
static const float silenceChannel[WEBAUDIO_BLOCK_SIZE] = {0.f};
for (uint32_t i = 0; i < aChunk->ChannelCount(); i++) {
aOutputChannels.AppendElement(static_cast<const float*>(aChunk->mChannelData[i]));
}
if (aOutputChannels.Length() < aOutputChannelCount) {
if (mChannelInterpretation == ChannelInterpretation::Speakers) {
AudioChannelsUpMix(&aOutputChannels, aOutputChannelCount, SilentChannel::ZeroChannel<float>());
AudioChannelsUpMix<float>(&aOutputChannels, aOutputChannelCount, nullptr);
NS_ASSERTION(aOutputChannelCount == aOutputChannels.Length(),
"We called GetAudioChannelsSuperset to avoid this");
} else {
// Fill up the remaining aOutputChannels by zeros
for (uint32_t j = aOutputChannels.Length(); j < aOutputChannelCount; ++j) {
aOutputChannels.AppendElement(silenceChannel);
aOutputChannels.AppendElement(nullptr);
}
}
} else if (aOutputChannels.Length() > aOutputChannelCount) {

View File

@ -44,14 +44,14 @@ NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AudioParam, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioParam, Release)
AudioParam::AudioParam(AudioNode* aNode,
AudioParam::CallbackType aCallback,
uint32_t aIndex,
float aDefaultValue,
const char* aName)
: AudioParamTimeline(aDefaultValue)
, mNode(aNode)
, mCallback(aCallback)
, mDefaultValue(aDefaultValue)
, mName(aName)
, mIndex(aIndex)
, mDefaultValue(aDefaultValue)
{
}
@ -120,12 +120,20 @@ AudioParam::Stream()
// Send the stream to the timeline on the MSG side.
AudioTimelineEvent event(mStream);
mCallback(mNode, event);
SendEventToEngine(event);
return mStream;
}
void
AudioParam::SendEventToEngine(const AudioTimelineEvent& aEvent)
{
AudioNodeStream* stream = mNode->GetStream();
if (stream) {
stream->SendTimelineEvent(mIndex, aEvent);
}
}
float
AudioParamTimeline::AudioNodeInputValue(size_t aCounter) const
{

View File

@ -26,10 +26,8 @@ class AudioParam final : public nsWrapperCache,
virtual ~AudioParam();
public:
typedef void (*CallbackType)(AudioNode* aNode, const AudioTimelineEvent&);
AudioParam(AudioNode* aNode,
CallbackType aCallback,
uint32_t aIndex,
float aDefaultValue,
const char* aName);
@ -72,7 +70,7 @@ public:
AudioParamTimeline::SetValue(aValue);
mCallback(mNode, event);
SendEventToEngine(event);
}
void SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv)
@ -129,7 +127,7 @@ public:
AudioTimelineEvent event(AudioTimelineEvent::Cancel, aStartTime, 0.0f);
mCallback(mNode, event);
SendEventToEngine(event);
}
uint32_t ParentNodeId()
@ -147,11 +145,6 @@ public:
return mDefaultValue;
}
AudioNode* Node() const
{
return mNode;
}
const nsTArray<AudioNode::InputNode>& InputNodes() const
{
return mInputNodes;
@ -193,10 +186,6 @@ public:
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
protected:
nsCycleCollectingAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
private:
void EventInsertionHelper(ErrorResult& aRv,
AudioTimelineEvent::Type aType,
@ -215,18 +204,22 @@ private:
AudioEventTimeline::InsertEvent<double>(event);
mCallback(mNode, event);
SendEventToEngine(event);
}
void SendEventToEngine(const AudioTimelineEvent& aEvent);
nsCycleCollectingAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
nsRefPtr<AudioNode> mNode;
// For every InputNode, there is a corresponding entry in mOutputParams of the
// InputNode's mInputNode.
nsTArray<AudioNode::InputNode> mInputNodes;
CallbackType mCallback;
const float mDefaultValue;
const char* mName;
// The input port used to connect the AudioParam's stream to its node's stream
nsRefPtr<MediaInputPort> mNodeStreamPort;
const uint32_t mIndex;
const float mDefaultValue;
};
} // namespace dom

View File

@ -242,10 +242,11 @@ BiquadFilterNode::BiquadFilterNode(AudioContext* aContext)
ChannelCountMode::Max,
ChannelInterpretation::Speakers)
, mType(BiquadFilterType::Lowpass)
, mFrequency(new AudioParam(this, SendFrequencyToStream, 350.f, "frequency"))
, mDetune(new AudioParam(this, SendDetuneToStream, 0.f, "detune"))
, mQ(new AudioParam(this, SendQToStream, 1.f, "Q"))
, mGain(new AudioParam(this, SendGainToStream, 0.f, "gain"))
, mFrequency(new AudioParam(this, BiquadFilterNodeEngine::FREQUENCY,
350.f, "frequency"))
, mDetune(new AudioParam(this, BiquadFilterNodeEngine::DETUNE, 0.f, "detune"))
, mQ(new AudioParam(this, BiquadFilterNodeEngine::Q, 1.f, "Q"))
, mGain(new AudioParam(this, BiquadFilterNodeEngine::GAIN, 0.f, "gain"))
{
BiquadFilterNodeEngine* engine = new BiquadFilterNodeEngine(this, aContext->Destination());
mStream = AudioNodeStream::Create(aContext, engine,
@ -336,33 +337,5 @@ BiquadFilterNode::GetFrequencyResponse(const Float32Array& aFrequencyHz,
biquad.getFrequencyResponse(int(length), frequencies, aMagResponse.Data(), aPhaseResponse.Data());
}
void
BiquadFilterNode::SendFrequencyToStream(AudioNode* aNode, const AudioTimelineEvent& aEvent)
{
BiquadFilterNode* This = static_cast<BiquadFilterNode*>(aNode);
SendTimelineEventToStream(This, BiquadFilterNodeEngine::FREQUENCY, aEvent);
}
void
BiquadFilterNode::SendDetuneToStream(AudioNode* aNode, const AudioTimelineEvent& aEvent)
{
BiquadFilterNode* This = static_cast<BiquadFilterNode*>(aNode);
SendTimelineEventToStream(This, BiquadFilterNodeEngine::DETUNE, aEvent);
}
void
BiquadFilterNode::SendQToStream(AudioNode* aNode, const AudioTimelineEvent& aEvent)
{
BiquadFilterNode* This = static_cast<BiquadFilterNode*>(aNode);
SendTimelineEventToStream(This, BiquadFilterNodeEngine::Q, aEvent);
}
void
BiquadFilterNode::SendGainToStream(AudioNode* aNode, const AudioTimelineEvent& aEvent)
{
BiquadFilterNode* This = static_cast<BiquadFilterNode*>(aNode);
SendTimelineEventToStream(This, BiquadFilterNodeEngine::GAIN, aEvent);
}
} // namespace dom
} // namespace mozilla

View File

@ -15,7 +15,6 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct AudioTimelineEvent;
class BiquadFilterNode final : public AudioNode
{
@ -68,16 +67,6 @@ public:
protected:
virtual ~BiquadFilterNode();
private:
static void SendFrequencyToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent);
static void SendDetuneToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvente);
static void SendQToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent);
static void SendGainToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent);
private:
BiquadFilterType mType;
nsRefPtr<AudioParam> mFrequency;

View File

@ -196,7 +196,7 @@ DelayNode::DelayNode(AudioContext* aContext, double aMaxDelay)
2,
ChannelCountMode::Max,
ChannelInterpretation::Speakers)
, mDelay(new AudioParam(this, SendDelayToStream, 0.0f, "delayTime"))
, mDelay(new AudioParam(this, DelayNodeEngine::DELAY, 0.0f, "delayTime"))
{
DelayNodeEngine* engine =
new DelayNodeEngine(this, aContext->Destination(),
@ -229,12 +229,5 @@ DelayNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return DelayNodeBinding::Wrap(aCx, this, aGivenProto);
}
void
DelayNode::SendDelayToStream(AudioNode* aNode, const AudioTimelineEvent& aEvent)
{
DelayNode* This = static_cast<DelayNode*>(aNode);
SendTimelineEventToStream(This, DelayNodeEngine::DELAY, aEvent);
}
} // namespace dom
} // namespace mozilla

View File

@ -42,8 +42,6 @@ protected:
virtual ~DelayNode();
private:
static void SendDelayToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent);
friend class DelayNodeEngine;
private:

View File

@ -186,12 +186,17 @@ DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
2,
ChannelCountMode::Explicit,
ChannelInterpretation::Speakers)
, mThreshold(new AudioParam(this, SendThresholdToStream, -24.f, "threshold"))
, mKnee(new AudioParam(this, SendKneeToStream, 30.f, "knee"))
, mRatio(new AudioParam(this, SendRatioToStream, 12.f, "ratio"))
, mThreshold(new AudioParam(this, DynamicsCompressorNodeEngine::THRESHOLD,
-24.f, "threshold"))
, mKnee(new AudioParam(this, DynamicsCompressorNodeEngine::KNEE,
30.f, "knee"))
, mRatio(new AudioParam(this, DynamicsCompressorNodeEngine::RATIO,
12.f, "ratio"))
, mReduction(0)
, mAttack(new AudioParam(this, SendAttackToStream, 0.003f, "attack"))
, mRelease(new AudioParam(this, SendReleaseToStream, 0.25f, "release"))
, mAttack(new AudioParam(this, DynamicsCompressorNodeEngine::ATTACK,
0.003f, "attack"))
, mRelease(new AudioParam(this, DynamicsCompressorNodeEngine::RELEASE,
0.25f, "release"))
{
DynamicsCompressorNodeEngine* engine = new DynamicsCompressorNodeEngine(this, aContext->Destination());
mStream = AudioNodeStream::Create(aContext, engine,
@ -226,45 +231,5 @@ DynamicsCompressorNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenP
return DynamicsCompressorNodeBinding::Wrap(aCx, this, aGivenProto);
}
void
DynamicsCompressorNode::SendThresholdToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent)
{
DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
SendTimelineEventToStream(This, DynamicsCompressorNodeEngine::THRESHOLD, aEvent);
}
void
DynamicsCompressorNode::SendKneeToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent)
{
DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
SendTimelineEventToStream(This, DynamicsCompressorNodeEngine::KNEE, aEvent);
}
void
DynamicsCompressorNode::SendRatioToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent)
{
DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
SendTimelineEventToStream(This, DynamicsCompressorNodeEngine::RATIO, aEvent);
}
void
DynamicsCompressorNode::SendAttackToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent)
{
DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
SendTimelineEventToStream(This, DynamicsCompressorNodeEngine::ATTACK, aEvent);
}
void
DynamicsCompressorNode::SendReleaseToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent)
{
DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
SendTimelineEventToStream(This, DynamicsCompressorNodeEngine::RELEASE, aEvent);
}
} // namespace dom
} // namespace mozilla

View File

@ -73,18 +73,6 @@ public:
protected:
virtual ~DynamicsCompressorNode();
private:
static void SendThresholdToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent);
static void SendKneeToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent);
static void SendRatioToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent);
static void SendAttackToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent);
static void SendReleaseToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent);
private:
nsRefPtr<AudioParam> mThreshold;
nsRefPtr<AudioParam> mKnee;

View File

@ -117,7 +117,7 @@ GainNode::GainNode(AudioContext* aContext)
2,
ChannelCountMode::Max,
ChannelInterpretation::Speakers)
, mGain(new AudioParam(this, SendGainToStream, 1.0f, "gain"))
, mGain(new AudioParam(this, GainNodeEngine::GAIN, 1.0f, "gain"))
{
GainNodeEngine* engine = new GainNodeEngine(this, aContext->Destination());
mStream = AudioNodeStream::Create(aContext, engine,
@ -148,12 +148,5 @@ GainNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return GainNodeBinding::Wrap(aCx, this, aGivenProto);
}
void
GainNode::SendGainToStream(AudioNode* aNode, const AudioTimelineEvent& aEvent)
{
GainNode* This = static_cast<GainNode*>(aNode);
SendTimelineEventToStream(This, GainNodeEngine::GAIN, aEvent);
}
} // namespace dom
} // namespace mozilla

View File

@ -41,9 +41,6 @@ public:
protected:
virtual ~GainNode();
private:
static void SendGainToStream(AudioNode* aNode, const AudioTimelineEvent& aEvent);
private:
nsRefPtr<AudioParam> mGain;
};

View File

@ -402,8 +402,9 @@ OscillatorNode::OscillatorNode(AudioContext* aContext)
ChannelCountMode::Max,
ChannelInterpretation::Speakers)
, mType(OscillatorType::Sine)
, mFrequency(new AudioParam(this, SendFrequencyToStream, 440.0f, "frequency"))
, mDetune(new AudioParam(this, SendDetuneToStream, 0.0f, "detune"))
, mFrequency(new AudioParam(this, OscillatorNodeEngine::FREQUENCY,
440.0f, "frequency"))
, mDetune(new AudioParam(this, OscillatorNodeEngine::DETUNE, 0.0f, "detune"))
, mStartCalled(false)
{
OscillatorNodeEngine* engine = new OscillatorNodeEngine(this, aContext->Destination());
@ -452,26 +453,6 @@ OscillatorNode::DestroyMediaStream()
AudioNode::DestroyMediaStream();
}
void
OscillatorNode::SendFrequencyToStream(AudioNode* aNode, const AudioTimelineEvent& aEvent)
{
OscillatorNode* This = static_cast<OscillatorNode*>(aNode);
if (!This->mStream) {
return;
}
SendTimelineEventToStream(This, OscillatorNodeEngine::FREQUENCY, aEvent);
}
void
OscillatorNode::SendDetuneToStream(AudioNode* aNode, const AudioTimelineEvent& aEvent)
{
OscillatorNode* This = static_cast<OscillatorNode*>(aNode);
if (!This->mStream) {
return;
}
SendTimelineEventToStream(This, OscillatorNodeEngine::DETUNE, aEvent);
}
void
OscillatorNode::SendTypeToStream()
{

View File

@ -87,8 +87,6 @@ protected:
virtual ~OscillatorNode();
private:
static void SendFrequencyToStream(AudioNode* aNode, const AudioTimelineEvent& aEvent);
static void SendDetuneToStream(AudioNode* aNode, const AudioTimelineEvent& aEvent);
void SendTypeToStream();
void SendPeriodicWaveToStream();

View File

@ -171,7 +171,7 @@ StereoPannerNode::StereoPannerNode(AudioContext* aContext)
2,
ChannelCountMode::Clamped_max,
ChannelInterpretation::Speakers)
, mPan(new AudioParam(this, SendPanToStream, 0.f, "pan"))
, mPan(new AudioParam(this, StereoPannerNodeEngine::PAN, 0.f, "pan"))
{
StereoPannerNodeEngine* engine = new StereoPannerNodeEngine(this, aContext->Destination());
mStream = AudioNodeStream::Create(aContext, engine,
@ -202,12 +202,5 @@ StereoPannerNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return StereoPannerNodeBinding::Wrap(aCx, this, aGivenProto);
}
void
StereoPannerNode::SendPanToStream(AudioNode* aNode, const AudioTimelineEvent& aEvent)
{
StereoPannerNode* This = static_cast<StereoPannerNode*>(aNode);
SendTimelineEventToStream(This, StereoPannerNodeEngine::PAN, aEvent);
}
} // namespace dom
} // namespace mozilla

View File

@ -60,8 +60,6 @@ protected:
virtual ~StereoPannerNode();
private:
static void SendPanToStream(AudioNode* aNode,
const AudioTimelineEvent& aEvent);
nsRefPtr<AudioParam> mPan;
};

View File

@ -81,7 +81,7 @@ nsSVGPathGeometryElement::GetOrBuildPath(const DrawTarget& aDrawTarget,
{
// We only cache the path if it matches the backend used for screen painting:
bool cacheable = aDrawTarget.GetBackendType() ==
gfxPlatform::GetPlatform()->GetContentBackend();
gfxPlatform::GetPlatform()->GetDefaultContentBackend();
// Checking for and returning mCachedPath before checking the pref means
// that the pref is only live on page reload (or app restart for SVG in

View File

@ -29,6 +29,11 @@ function test() {
function eventHandler(event) {
if (event.type === 'base-load') {
if (cachedLoad) {
removeEventListener('base-load', eventHandler, true);
removeEventListener('base-register', eventHandler, true);
removeEventListener('base-sw-ready', eventHandler, true);
removeEventListener('cached-load', eventHandler, true);
gBrowser.removeTab(tab);
executeSoon(finish);
}

View File

@ -74,7 +74,7 @@ BasicCompositor::BasicCompositor(nsIWidget *aWidget)
SetBackend(LayersBackend::LAYERS_BASIC);
mMaxTextureSize =
Factory::GetMaxSurfaceSize(gfxPlatform::GetPlatform()->GetContentBackend());
Factory::GetMaxSurfaceSize(gfxPlatform::GetPlatform()->GetContentBackendFor(LayersBackend::LAYERS_BASIC));
}
BasicCompositor::~BasicCompositor()

View File

@ -343,13 +343,13 @@ CreateBufferTextureClient(ISurfaceAllocator* aAllocator,
}
static inline gfx::BackendType
BackendTypeForBackendSelector(BackendSelector aSelector)
BackendTypeForBackendSelector(LayersBackend aLayersBackend, BackendSelector aSelector)
{
switch (aSelector) {
case BackendSelector::Canvas:
return gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
case BackendSelector::Content:
return gfxPlatform::GetPlatform()->GetContentBackend();
return gfxPlatform::GetPlatform()->GetContentBackendFor(aLayersBackend);
default:
MOZ_ASSERT_UNREACHABLE("Unknown backend selector");
return gfx::BackendType::NONE;
@ -365,7 +365,8 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
TextureFlags aTextureFlags,
TextureAllocationFlags aAllocFlags)
{
gfx::BackendType moz2DBackend = BackendTypeForBackendSelector(aSelector);
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
gfx::BackendType moz2DBackend = BackendTypeForBackendSelector(parentBackend, aSelector);
RefPtr<TextureClient> texture;
@ -374,7 +375,6 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
#endif
#ifdef XP_WIN
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
if (parentBackend == LayersBackend::LAYERS_D3D11 &&
(moz2DBackend == gfx::BackendType::DIRECT2D ||
moz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
@ -407,7 +407,6 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
#endif
#ifdef MOZ_X11
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
gfxSurfaceType type =
gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();

View File

@ -579,7 +579,8 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag
// When we're not on the main thread we're not going to be using Direct2D
// to access the contents of this texture client so we will always use D3D11.
bool haveD3d11Backend = windowsPlatform->GetContentBackend() == BackendType::DIRECT2D1_1 || !NS_IsMainThread();
BackendType backend = windowsPlatform->GetContentBackendFor(LayersBackend::LAYERS_D3D11);
bool haveD3d11Backend = (backend == BackendType::DIRECT2D1_1) || !NS_IsMainThread();
if (haveD3d11Backend) {
if (!AllocateD3D11Surface(d3d11device, aSize)) {

View File

@ -271,7 +271,16 @@ public:
}
void GetApzSupportInfo(mozilla::widget::InfoObject& aObj);
mozilla::gfx::BackendType GetContentBackend() {
// Get the default content backend that will be used with the default
// compositor. If the compositor is known when calling this function,
// GetContentBackendFor() should be called instead.
mozilla::gfx::BackendType GetDefaultContentBackend() {
return mContentBackend;
}
// Return the best content backend available that is compatible with the
// given layers backend.
virtual mozilla::gfx::BackendType GetContentBackendFor(mozilla::layers::LayersBackend aLayers) {
return mContentBackend;
}

View File

@ -99,8 +99,8 @@ public:
bool UseXRender() {
#if defined(MOZ_X11)
if (GetContentBackend() != mozilla::gfx::BackendType::NONE &&
GetContentBackend() != mozilla::gfx::BackendType::CAIRO)
if (GetDefaultContentBackend() != mozilla::gfx::BackendType::NONE &&
GetDefaultContentBackend() != mozilla::gfx::BackendType::CAIRO)
return false;
return sUseXRender;

View File

@ -512,12 +512,14 @@ gfxWindowsPlatform::HandleDeviceReset()
return true;
}
static const BackendType SOFTWARE_BACKEND = BackendType::CAIRO;
void
gfxWindowsPlatform::UpdateBackendPrefs()
{
uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
BackendType defaultBackend = BackendType::CAIRO;
uint32_t canvasMask = BackendTypeBit(SOFTWARE_BACKEND);
uint32_t contentMask = BackendTypeBit(SOFTWARE_BACKEND);
BackendType defaultBackend = SOFTWARE_BACKEND;
if (GetD2DStatus() == FeatureStatus::Available) {
mRenderMode = RENDER_DIRECT2D;
canvasMask |= BackendTypeBit(BackendType::DIRECT2D);
@ -550,6 +552,17 @@ gfxWindowsPlatform::UpdateRenderMode()
}
}
mozilla::gfx::BackendType
gfxWindowsPlatform::GetContentBackendFor(mozilla::layers::LayersBackend aLayers)
{
if (aLayers == LayersBackend::LAYERS_D3D11) {
return gfxPlatform::GetDefaultContentBackend();
}
// If we're not accelerated with D3D11, never use D2D.
return SOFTWARE_BACKEND;
}
#ifdef CAIRO_HAS_D2D_SURFACE
HRESULT
gfxWindowsPlatform::CreateDevice(nsRefPtr<IDXGIAdapter1> &adapter1,

View File

@ -214,6 +214,8 @@ public:
virtual bool DidRenderingDeviceReset(DeviceResetReason* aResetReason = nullptr);
mozilla::gfx::BackendType GetContentBackendFor(mozilla::layers::LayersBackend aLayers) override;
// ClearType is not always enabled even when available (e.g. Windows XP)
// if either of these prefs are enabled and apply, use ClearType rendering
bool UseClearTypeForDownloadableFonts();
@ -333,7 +335,7 @@ private:
mozilla::gfx::FeatureStatus AttemptD3D11ImageBridgeDeviceCreation();
mozilla::gfx::FeatureStatus AttemptD3D11ContentDeviceCreation();
bool gfxWindowsPlatform::AttemptD3D11ContentDeviceCreationHelper(
bool AttemptD3D11ContentDeviceCreationHelper(
IDXGIAdapter1* aAdapter, HRESULT& aResOut);
bool CanUseD3D11ImageBridge();

View File

@ -156,7 +156,7 @@ public:
const nsIntSize& TargetSize() const { return nsIntSize(); }
const gfxSize& Scale() const { return gfxSize(1.0, 1.0); }
nsresult BeginFrame(const nsIntSize&, uint8_t*, bool, bool = false)
nsresult BeginFrame(const nsIntSize&, const Maybe<nsIntRect>&, uint8_t*, bool, bool = false)
{
return NS_ERROR_FAILURE;
}

View File

@ -153,7 +153,8 @@ uint8_t* LazyLinkTopActivation(JSContext* cx);
static inline bool
IsIonEnabled(JSContext* cx)
{
#ifdef JS_CODEGEN_NONE
// The ARM64 Ion engine is not yet implemented.
#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64)
return false;
#else
return cx->runtime()->options().ion() &&

View File

@ -104,6 +104,34 @@ js::jit::AtomicOperations::fetchXorSeqCst(T* addr, T val)
return __atomic_fetch_xor(addr, val, __ATOMIC_SEQ_CST);
}
template <typename T>
inline T
js::jit::AtomicOperations::loadSafeWhenRacy(T* addr)
{
return *addr; // FIXME (1208663): not yet safe
}
template <typename T>
inline void
js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val)
{
*addr = val; // FIXME (1208663): not yet safe
}
inline void
js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest, const void* src,
size_t nbytes)
{
memcpy(dest, src, nbytes); // FIXME (1208663): not yet safe
}
inline void
js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest, const void* src,
size_t nbytes)
{
memmove(dest, src, nbytes); // FIXME (1208663): not yet safe
}
template<size_t nbytes>
inline void
js::jit::RegionLock::acquire(void* addr)

View File

@ -238,8 +238,13 @@ MacroAssemblerCompat::branchValueIsNurseryObject(Condition cond, ValueOperand va
MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
MOZ_ASSERT(temp != ScratchReg && temp != ScratchReg2); // Both may be used internally.
// 'Value' representing the start of the nursery tagged as a JSObject
const Nursery& nursery = GetJitContext()->runtime->gcNursery();
// Avoid creating a bogus ObjectValue below.
if (!nursery.exists())
return;
// 'Value' representing the start of the nursery tagged as a JSObject
Value start = ObjectValue(*reinterpret_cast<JSObject*>(nursery.start()));
movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), temp);

View File

@ -136,8 +136,8 @@ Instrument::Instrument(const char* datafile, uint64_t sample_period)
// Construct Counter objects from counter description array.
for (int i = 0; i < num_counters; i++) {
Counter* counter = js_new<Counter>(kCounterList[i].name, kCounterList[i].type);
counters_.append(counter);
if (Counter* counter = js_new<Counter>(kCounterList[i].name, kCounterList[i].type))
counters_.append(counter);
}
DumpCounterNames();

View File

@ -37,26 +37,19 @@ namespace vixl {
using mozilla::DebugOnly;
using js::jit::ABIFunctionType;
Simulator::Simulator() {
decoder_ = js_new<Decoder>();
if (!decoder_) {
MOZ_ReportAssertionFailure("[unhandlable oom] Decoder", __FILE__, __LINE__);
MOZ_CRASH();
}
// FIXME: This just leaks the Decoder object for now, which is probably OK.
// FIXME: We should free it at some point.
// FIXME: Note that it can't be stored in the SimulatorRuntime due to lifetime conflicts.
this->init(decoder_, stdout);
Simulator::Simulator(Decoder* decoder, FILE* stream)
: stream_(nullptr)
, print_disasm_(nullptr)
, instrumentation_(nullptr)
, stack_(nullptr)
, stack_limit_(nullptr)
, decoder_(nullptr)
, oom_(false)
, lock_(nullptr)
{
this->init(decoder, stream);
}
Simulator::Simulator(Decoder* decoder, FILE* stream) {
this->init(decoder, stream);
}
void Simulator::ResetState() {
// Reset the system registers.
nzcv_ = SimSystemRegister::DefaultValueFor(NZCV);
@ -92,6 +85,10 @@ void Simulator::init(Decoder* decoder, FILE* stream) {
stream_ = stream;
print_disasm_ = js_new<PrintDisassembler>(stream_);
if (!print_disasm_) {
oom_ = true;
return;
}
set_coloured_trace(false);
trace_parameters_ = LOG_NONE;
@ -99,6 +96,10 @@ void Simulator::init(Decoder* decoder, FILE* stream) {
// Allocate and set up the simulator stack.
stack_ = (byte*)js_malloc(stack_size_);
if (!stack_) {
oom_ = true;
return;
}
stack_limit_ = stack_ + stack_protection_size_;
// Configure the starting stack pointer.
// - Find the top of the stack.
@ -111,6 +112,10 @@ void Simulator::init(Decoder* decoder, FILE* stream) {
// Set the sample period to 10, as the VIXL examples and tests are short.
instrumentation_ = js_new<Instrument>("vixl_stats.csv", 10);
if (!instrumentation_) {
oom_ = true;
return;
}
// Print a warning about exclusive-access instructions, but only the first
// time they are encountered. This warning can be silenced using
@ -118,8 +123,10 @@ void Simulator::init(Decoder* decoder, FILE* stream) {
print_exclusive_access_warning_ = true;
lock_ = PR_NewLock();
if (!lock_)
MOZ_CRASH("Could not allocate simulator lock.");
if (!lock_) {
oom_ = true;
return;
}
#ifdef DEBUG
lockOwner_ = nullptr;
#endif
@ -133,30 +140,24 @@ Simulator* Simulator::Current() {
Simulator* Simulator::Create() {
Decoder* decoder = js_new<vixl::Decoder>();
if (!decoder) {
MOZ_ReportAssertionFailure("[unhandlable oom] Decoder", __FILE__, __LINE__);
MOZ_CRASH();
}
Decoder *decoder = js_new<vixl::Decoder>();
if (!decoder)
return nullptr;
// FIXME: This just leaks the Decoder object for now, which is probably OK.
// FIXME: We should free it at some point.
// FIXME: Note that it can't be stored in the SimulatorRuntime due to lifetime conflicts.
if (getenv("USE_DEBUGGER") != nullptr) {
Debugger* debugger = js_new<Debugger>(decoder, stdout);
if (!debugger) {
MOZ_ReportAssertionFailure("[unhandlable oom] Decoder", __FILE__, __LINE__);
MOZ_CRASH();
}
return debugger;
}
Simulator *sim;
if (getenv("USE_DEBUGGER") != nullptr)
sim = js_new<Debugger>(decoder, stdout);
else
sim = js_new<Simulator>(decoder, stdout);
Simulator* sim = js_new<Simulator>();
if (!sim) {
MOZ_CRASH("NEED SIMULATOR");
// Check if Simulator:init ran out of memory.
if (sim && sim->oom()) {
js_delete(sim);
return nullptr;
}
sim->init(decoder, stdout);
return sim;
}

Some files were not shown because too many files have changed in this diff Show More