mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
c2494b5883
@ -43,6 +43,7 @@ _OPT\.OBJ/
|
||||
^js/src/autom4te.cache$
|
||||
# SpiderMonkey test result logs
|
||||
^js/src/tests/results-.*\.(html|txt)$
|
||||
^js/src/devtools/rootAnalysis/t/out
|
||||
|
||||
# Java HTML5 parser classes
|
||||
^parser/html/java/(html|java)parser/
|
||||
|
@ -92,6 +92,17 @@ HTMLLIAccessible::Bounds() const
|
||||
return rect;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLLIAccessible::InsertChildAt(uint32_t aIndex, Accessible* aChild)
|
||||
{
|
||||
// Adjust index if there's a bullet.
|
||||
if (mBullet && aIndex == 0 && aChild != mBullet) {
|
||||
return HyperTextAccessible::InsertChildAt(aIndex + 1, aChild);
|
||||
}
|
||||
|
||||
return HyperTextAccessible::InsertChildAt(aIndex, aChild);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// HTMLLIAccessible: public
|
||||
|
||||
|
@ -53,6 +53,8 @@ public:
|
||||
virtual a11y::role NativeRole() override;
|
||||
virtual uint64_t NativeState() override;
|
||||
|
||||
virtual bool InsertChildAt(uint32_t aIndex, Accessible* aChild) override;
|
||||
|
||||
// HTMLLIAccessible
|
||||
HTMLListBulletAccessible* Bullet() const { return mBullet; }
|
||||
void UpdateBullet(bool aHasBullet);
|
||||
|
@ -157,7 +157,7 @@ public:
|
||||
virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
|
||||
virtual Relation RelationByType(RelationType aRelationType) override;
|
||||
|
||||
bool InsertChildAt(uint32_t aIndex, Accessible* aChild) override;
|
||||
virtual bool InsertChildAt(uint32_t aIndex, Accessible* aChild) override;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLTableAccessible() {}
|
||||
|
@ -82,6 +82,28 @@
|
||||
this.onProcessed = function showProcessor_onProcessed()
|
||||
{
|
||||
testLiAccessibleTree();
|
||||
gSequence.processNext();
|
||||
}
|
||||
};
|
||||
|
||||
function textReplaceProcessor()
|
||||
{
|
||||
this.liNode = getNode("li");
|
||||
|
||||
this.process = function textReplaceProcessor_process()
|
||||
{
|
||||
this.liNode.textContent = "hey";
|
||||
}
|
||||
|
||||
this.onProcessed = function textReplaceProcessor_onProcessed()
|
||||
{
|
||||
var tree = {
|
||||
LISTITEM: [
|
||||
{ STATICTEXT: [] },
|
||||
{ TEXT_LEAF: [] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(this.liNode, tree);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
@ -89,8 +111,9 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Test
|
||||
|
||||
var gSequence = null;
|
||||
//gA11yEventDumpToConsole = true;
|
||||
|
||||
var gSequence = null;
|
||||
function doTest()
|
||||
{
|
||||
testLiAccessibleTree();
|
||||
@ -101,6 +124,8 @@
|
||||
"hide HTML li");
|
||||
gSequence.append(new showProcessor(), EVENT_SHOW, getNode("li"),
|
||||
"show HTML li");
|
||||
gSequence.append(new textReplaceProcessor(), EVENT_REORDER, getNode("li"),
|
||||
"change text of HTML li");
|
||||
|
||||
gSequence.processNext(); // SimpleTest.finish() will be called in the end
|
||||
}
|
||||
|
@ -1087,6 +1087,8 @@ pref("dom.performance.enable_notify_performance_timing", true);
|
||||
pref("b2g.multiscreen.chrome_remote_url", "chrome://b2g/content/shell_remote.html");
|
||||
pref("b2g.multiscreen.system_remote_url", "index_remote.html");
|
||||
|
||||
// Audio competing between tabs
|
||||
pref("dom.audiochannel.audioCompeting", false);
|
||||
|
||||
// Because we can't have nice things.
|
||||
#ifdef MOZ_GRAPHENE
|
||||
|
@ -1,27 +1,27 @@
|
||||
[
|
||||
{
|
||||
"version": "gcc 4.9.3",
|
||||
"size" : 102421980,
|
||||
"digest" : "f25292aa93dc449e0472eee511c0ac15b5f1a4272ab76cf53ce5d20dc57f29e83da49ae1a9d9e994192647f75e13ae60f75ba2ac3cb9d26d5f5d6cabf88de921",
|
||||
"algorithm": "sha512",
|
||||
"version" : "gcc 4.9.3",
|
||||
"unpack" : true,
|
||||
"filename" : "gcc.tar.xz",
|
||||
"unpack": true
|
||||
"algorithm" : "sha512"
|
||||
},
|
||||
{
|
||||
"hg_id" : "cd93f15a30ce",
|
||||
"unpack" : true,
|
||||
"algorithm" : "sha512",
|
||||
"digest" : "541eb3842ab6b91bd87223cad7a5e4387ef3e496e5b580c8047b8b586bc7eb69fecf3c9eb8c45a1e0deebb53554f0e8acedfe1b4ca64d93b6d008f3f2eb11389",
|
||||
"filename" : "sixgill.tar.xz",
|
||||
"size" : 2626640,
|
||||
"unpack" : true
|
||||
"hg_id" : "8cb9c3fb039a+ tip",
|
||||
"digest" : "36dc644e24c0aa824975ad8f5c15714445d5cb064d823000c3cb637e885199414d7df551e6b99233f0656dcf5760918192ef04113c486af37f3c489bb93ad029",
|
||||
"size" : 2631908
|
||||
},
|
||||
{
|
||||
"size": 12072532,
|
||||
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
|
||||
"algorithm" : "sha512",
|
||||
"filename" : "gtk3.tar.xz",
|
||||
"setup" : "setup.sh",
|
||||
"unpack": true
|
||||
"unpack" : true,
|
||||
"digest" : "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
|
||||
"size" : 12072532
|
||||
},
|
||||
{
|
||||
"size" : 89319524,
|
||||
@ -31,17 +31,17 @@
|
||||
"unpack" : true
|
||||
},
|
||||
{
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm" : "sha512",
|
||||
"filename" : "sccache.tar.bz2",
|
||||
"unpack": true
|
||||
"unpack" : true,
|
||||
"digest" : "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"size" : 167175
|
||||
},
|
||||
{
|
||||
"size": 31078810,
|
||||
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||
"algorithm": "sha512",
|
||||
"filename" : "moz-tt.tar.bz2",
|
||||
"unpack": true
|
||||
"algorithm" : "sha512",
|
||||
"unpack" : true,
|
||||
"digest" : "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||
"size" : 31078810
|
||||
}
|
||||
]
|
||||
|
@ -4069,11 +4069,11 @@ function updateUserContextUIVisibility()
|
||||
/**
|
||||
* Updates the User Context UI indicators if the browser is in a non-default context
|
||||
*/
|
||||
function updateUserContextUIIndicator(browser)
|
||||
function updateUserContextUIIndicator()
|
||||
{
|
||||
let hbox = document.getElementById("userContext-icons");
|
||||
|
||||
let userContextId = browser.getAttribute("usercontextid");
|
||||
let userContextId = gBrowser.selectedBrowser.getAttribute("usercontextid");
|
||||
if (!userContextId) {
|
||||
hbox.hidden = true;
|
||||
return;
|
||||
@ -6420,8 +6420,16 @@ function checkEmptyPageOrigin(browser = gBrowser.selectedBrowser,
|
||||
let contentPrincipal = browser.contentPrincipal;
|
||||
// Not all principals have URIs...
|
||||
if (contentPrincipal.URI) {
|
||||
// A manually entered about:blank URI is slightly magical:
|
||||
if (uri.spec == "about:blank" && contentPrincipal.isNullPrincipal) {
|
||||
// There are two specialcases involving about:blank. One is where
|
||||
// the user has manually loaded it and it got created with a null
|
||||
// principal. The other involves the case where we load
|
||||
// some other empty page in a browser and the current page is the
|
||||
// initial about:blank page (which has that as its principal, not
|
||||
// just URI in which case it could be web-based). Especially in
|
||||
// e10s, we need to tackle that case specifically to avoid race
|
||||
// conditions when updating the URL bar.
|
||||
if ((uri.spec == "about:blank" && contentPrincipal.isNullPrincipal) ||
|
||||
contentPrincipal.URI.spec == "about:blank") {
|
||||
return true;
|
||||
}
|
||||
return contentPrincipal.URI.equals(uri);
|
||||
|
@ -637,15 +637,22 @@
|
||||
// pointing to their resolved jar: or file: URIs.
|
||||
if (!(originalLocation && gInitialPages.includes(originalLocation.spec) &&
|
||||
originalLocation != "about:blank" &&
|
||||
this.mBrowser.initialPageLoadedFromURLBar != originalLocation.spec &&
|
||||
this.mBrowser.currentURI && this.mBrowser.currentURI.spec == "about:blank")) {
|
||||
// This will trigger clearing the location bar. Don't do it if
|
||||
// we loaded off a blank browser and this is an initial page load
|
||||
// (e.g. about:privatebrowsing, about:newtab, etc.) so we avoid
|
||||
// clearing the location bar in case the user is typing in it.
|
||||
// loading about:blank shouldn't trigger this, either, because its
|
||||
// loads are "special".
|
||||
// Indicating that we started a load will allow the location
|
||||
// bar to be cleared when the load finishes.
|
||||
// In order to not overwrite user-typed content, we avoid it
|
||||
// (see if condition above) in a very specific case:
|
||||
// If the load is of an 'initial' page (e.g. about:privatebrowsing,
|
||||
// about:newtab, etc.), was not explicitly typed in the location
|
||||
// bar by the user, is not about:blank (because about:blank can be
|
||||
// loaded by websites under their principal), and the current
|
||||
// page in the browser is about:blank (indicating it is a newly
|
||||
// created or re-created browser, e.g. because it just switched
|
||||
// remoteness or is a new tab/window).
|
||||
this.mBrowser.urlbarChangeTracker.startedLoad();
|
||||
}
|
||||
delete this.mBrowser.initialPageLoadedFromURLBar;
|
||||
// If the browser is loading it must not be crashed anymore
|
||||
this.mTab.removeAttribute("crashed");
|
||||
}
|
||||
@ -1217,7 +1224,7 @@
|
||||
this._adjustFocusAfterTabSwitch(this.mCurrentTab);
|
||||
}
|
||||
|
||||
updateUserContextUIIndicator(gBrowser.selectedBrowser);
|
||||
updateUserContextUIIndicator();
|
||||
|
||||
this.tabContainer._setPositionalAttributes();
|
||||
|
||||
@ -4328,7 +4335,12 @@
|
||||
tab.setUserContextId(data.userContextId);
|
||||
}
|
||||
|
||||
updateUserContextUIIndicator(browser);
|
||||
// We don't want to update the container icon and identifier if
|
||||
// this is not the selected browser.
|
||||
if (browser == gBrowser.selectedBrowser) {
|
||||
updateUserContextUIIndicator();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "Findbar:Keypress": {
|
||||
|
@ -4,7 +4,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Feeds",
|
||||
function test() {
|
||||
var exampleUri = makeURI("http://example.com/");
|
||||
var secman = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
|
||||
var principal = secman.getSimpleCodebasePrincipal(exampleUri);
|
||||
var principal = secman.createCodebasePrincipal(exampleUri, {});
|
||||
|
||||
function testIsFeed(aTitle, aHref, aType, aKnown) {
|
||||
var link = { title: aTitle, href: aHref, type: aType };
|
||||
|
@ -1,39 +1,36 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests that the identity-box shows the chromeUI styling
|
||||
* when viewing about:home in a new window.
|
||||
*/
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("browser.startup.homepage");
|
||||
Services.prefs.clearUserPref("browser.startup.page");
|
||||
win.close();
|
||||
add_task(function*(){
|
||||
let homepage = "about:home";
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["browser.startup.homepage", homepage],
|
||||
["browser.startup.page", 1],
|
||||
]
|
||||
});
|
||||
|
||||
let homepage = "about:home";
|
||||
Services.prefs.setCharPref("browser.startup.homepage", homepage);
|
||||
Services.prefs.setIntPref("browser.startup.page", 1);
|
||||
let win = OpenBrowserWindow();
|
||||
whenDelayedStartupFinished(win, function() {
|
||||
yield BrowserTestUtils.waitForEvent(win, "load");
|
||||
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
// If we've finished loading about:home already, we can check
|
||||
// right away - otherwise, we need to wait.
|
||||
if (browser.contentDocument.readyState == "complete" &&
|
||||
browser.currentURI.spec == homepage) {
|
||||
checkIdentityMode(win);
|
||||
return;
|
||||
} else {
|
||||
yield BrowserTestUtils.browserLoaded(browser, false, homepage);
|
||||
checkIdentityMode(win);
|
||||
}
|
||||
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
if (browser.currentURI.spec != homepage)
|
||||
return;
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
checkIdentityMode(win);
|
||||
}, true);
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
}
|
||||
|
||||
function checkIdentityMode(win) {
|
||||
let identityMode = win.document.getElementById("identity-box").className;
|
||||
is(identityMode, "chromeUI", "Identity state should be chromeUI for about:home in a new window");
|
||||
finish();
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ support-files =
|
||||
moz.png
|
||||
[browser_tabMatchesInAwesomebar_perwindowpb.js]
|
||||
skip-if = os == 'linux' # Bug 1104755
|
||||
[browser_urlbarAboutHomeLoading.js]
|
||||
[browser_urlbarAutoFillTrimURLs.js]
|
||||
[browser_urlbarCopying.js]
|
||||
subsuite = clipboard
|
||||
|
@ -0,0 +1,104 @@
|
||||
"use strict";
|
||||
|
||||
const {TabStateFlusher} = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
|
||||
|
||||
/**
|
||||
* Test what happens if loading a URL that should clear the
|
||||
* location bar after a parent process URL.
|
||||
*/
|
||||
add_task(function* clearURLBarAfterParentProcessURL() {
|
||||
let tab = yield new Promise(resolve => {
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:preferences");
|
||||
let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
|
||||
newTabBrowser.addEventListener("Initialized", function onInit() {
|
||||
newTabBrowser.removeEventListener("Initialized", onInit, true);
|
||||
resolve(gBrowser.selectedTab);
|
||||
}, true);
|
||||
});
|
||||
document.getElementById("home-button").click();
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
is(gURLBar.value, "", "URL bar should be empty");
|
||||
is(tab.linkedBrowser.userTypedValue, null, "The browser should have no recorded userTypedValue");
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Same as above, but open the tab without passing the URL immediately
|
||||
* which changes behaviour in tabbrowser.xml.
|
||||
*/
|
||||
add_task(function* clearURLBarAfterParentProcessURLInExistingTab() {
|
||||
let tab = yield new Promise(resolve => {
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
|
||||
newTabBrowser.addEventListener("Initialized", function onInit() {
|
||||
newTabBrowser.removeEventListener("Initialized", onInit, true);
|
||||
resolve(gBrowser.selectedTab);
|
||||
}, true);
|
||||
newTabBrowser.loadURI("about:preferences");
|
||||
});
|
||||
document.getElementById("home-button").click();
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
is(gURLBar.value, "", "URL bar should be empty");
|
||||
is(tab.linkedBrowser.userTypedValue, null, "The browser should have no recorded userTypedValue");
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Load about:home directly from an about:newtab page. Because it is an
|
||||
* 'initial' page, we need to treat this specially if the user actually
|
||||
* loads a page like this from the URL bar.
|
||||
*/
|
||||
add_task(function* clearURLBarAfterManuallyLoadingAboutHome() {
|
||||
let promiseTabOpenedAndSwitchedTo = BrowserTestUtils.switchTab(gBrowser, () => {});
|
||||
// This opens about:newtab:
|
||||
BrowserOpenTab();
|
||||
let tab = yield promiseTabOpenedAndSwitchedTo;
|
||||
is(gURLBar.value, "", "URL bar should be empty");
|
||||
is(tab.linkedBrowser.userTypedValue, null, "userTypedValue should be null");
|
||||
|
||||
gURLBar.value = "about:home";
|
||||
gURLBar.select();
|
||||
let aboutHomeLoaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, "about:home");
|
||||
EventUtils.sendKey("return");
|
||||
yield aboutHomeLoaded;
|
||||
|
||||
is(gURLBar.value, "", "URL bar should be empty");
|
||||
is(tab.linkedBrowser.userTypedValue, null, "userTypedValue should be null");
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Ensure we don't show 'about:home' in the URL bar temporarily in new tabs
|
||||
* while we're switching remoteness (when the URL we're loading and the
|
||||
* default content principal are different).
|
||||
*/
|
||||
add_task(function* dontTemporarilyShowAboutHome() {
|
||||
yield SpecialPowers.pushPrefEnv({set: [["browser.startup.page", 1]]});
|
||||
let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
|
||||
let win = OpenBrowserWindow();
|
||||
yield windowOpenedPromise;
|
||||
let promiseTabSwitch = BrowserTestUtils.switchTab(win.gBrowser, () => {});
|
||||
win.BrowserOpenTab();
|
||||
yield promiseTabSwitch;
|
||||
yield TabStateFlusher.flush(win.gBrowser.selectedBrowser);
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
ok(SessionStore.getClosedWindowCount(), "Should have a closed window");
|
||||
|
||||
windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
|
||||
win = SessionStore.undoCloseWindow(0);
|
||||
yield windowOpenedPromise;
|
||||
let wpl = {
|
||||
onLocationChange(wpl, request, location, flags) {
|
||||
is(win.gURLBar.value, "", "URL bar value should stay empty.");
|
||||
},
|
||||
};
|
||||
win.gBrowser.addProgressListener(wpl);
|
||||
let otherTab = win.gBrowser.selectedTab.previousSibling;
|
||||
let tabLoaded = BrowserTestUtils.browserLoaded(otherTab.linkedBrowser, false, "about:home");
|
||||
yield BrowserTestUtils.switchTab(win.gBrowser, otherTab);
|
||||
yield tabLoaded;
|
||||
win.gBrowser.removeProgressListener(wpl);
|
||||
is(win.gURLBar.value, "", "URL bar value should be empty.");
|
||||
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
});
|
@ -382,6 +382,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
{
|
||||
this.value = url;
|
||||
gBrowser.userTypedValue = url;
|
||||
if (gInitialPages.includes(url)) {
|
||||
gBrowser.selectedBrowser.initialPageLoadedFromURLBar = url;
|
||||
}
|
||||
try {
|
||||
addToUrlbarHistory(url);
|
||||
} catch (ex) {
|
||||
|
@ -924,7 +924,7 @@ FeedWriter.prototype = {
|
||||
|
||||
let secman = Cc["@mozilla.org/scriptsecuritymanager;1"].
|
||||
getService(Ci.nsIScriptSecurityManager);
|
||||
this._feedPrincipal = secman.getSimpleCodebasePrincipal(this._feedURI);
|
||||
this._feedPrincipal = secman.createCodebasePrincipal(this._feedURI, {});
|
||||
|
||||
LOG("Subscribe Preview: feed uri = " + this._window.location.href);
|
||||
|
||||
|
@ -784,7 +784,10 @@ var SessionStoreInternal = {
|
||||
// clear user input instead), so we shouldn't set them here either.
|
||||
// They also don't fall under the issues in bug 439675 where user input
|
||||
// needs to be preserved if the load doesn't succeed.
|
||||
if (!browser.userTypedValue && uri && !win.gInitialPages.includes(uri)) {
|
||||
// We also don't do this for remoteness updates, where it should not
|
||||
// be necessary.
|
||||
if (!browser.userTypedValue && uri && !data.isRemotenessUpdate &&
|
||||
!win.gInitialPages.includes(uri)) {
|
||||
browser.userTypedValue = uri;
|
||||
}
|
||||
|
||||
@ -3335,7 +3338,8 @@ var SessionStoreInternal = {
|
||||
browser.messageManager.sendAsyncMessage("SessionStore:restoreHistory", {
|
||||
tabData: tabData,
|
||||
epoch: epoch,
|
||||
loadArguments: aLoadArguments
|
||||
loadArguments: aLoadArguments,
|
||||
isRemotenessUpdate,
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ var MessageListener = {
|
||||
}
|
||||
},
|
||||
|
||||
restoreHistory({epoch, tabData, loadArguments}) {
|
||||
restoreHistory({epoch, tabData, loadArguments, isRemotenessUpdate}) {
|
||||
gContentRestore.restoreHistory(tabData, loadArguments, {
|
||||
// Note: The callbacks passed here will only be used when a load starts
|
||||
// that was not initiated by sessionstore itself. This can happen when
|
||||
@ -179,7 +179,7 @@ var MessageListener = {
|
||||
// sync about the state of the restore (particularly regarding
|
||||
// docShell.currentURI). Using a synchronous message is the easiest way
|
||||
// to temporarily synchronize them.
|
||||
sendSyncMessage("SessionStore:restoreHistoryComplete", {epoch});
|
||||
sendSyncMessage("SessionStore:restoreHistoryComplete", {epoch, isRemotenessUpdate});
|
||||
},
|
||||
|
||||
restoreTabContent({loadArguments, isRemotenessUpdate}) {
|
||||
|
@ -1,51 +1,47 @@
|
||||
/* 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/. */
|
||||
"use strict";
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 480893 **/
|
||||
/**
|
||||
* Tests that we get sent to the right page when the user clicks
|
||||
* the "Close" button in about:sessionrestore
|
||||
*/
|
||||
add_task(function*() {
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["browser.startup.page", 0],
|
||||
]
|
||||
});
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Test that starting a new session loads a blank page if Firefox is
|
||||
// configured to display a blank page at startup (browser.startup.page = 0)
|
||||
gPrefService.setIntPref("browser.startup.page", 0);
|
||||
let tab = gBrowser.addTab("about:sessionrestore");
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
promiseBrowserLoaded(browser).then(() => {
|
||||
yield BrowserTestUtils.browserLoaded(browser, false, "about:sessionrestore");
|
||||
|
||||
let doc = browser.contentDocument;
|
||||
|
||||
// click on the "Start New Session" button after about:sessionrestore is loaded
|
||||
// Click on the "Close" button after about:sessionrestore is loaded.
|
||||
doc.getElementById("errorCancel").click();
|
||||
promiseBrowserLoaded(browser).then(() => {
|
||||
let doc = browser.contentDocument;
|
||||
|
||||
is(doc.URL, "about:blank", "loaded page is about:blank");
|
||||
yield BrowserTestUtils.browserLoaded(browser, false, "about:blank");
|
||||
|
||||
// Test that starting a new session loads the homepage (set to http://mochi.test:8888)
|
||||
// if Firefox is configured to display a homepage at startup (browser.startup.page = 1)
|
||||
let homepage = "http://mochi.test:8888/";
|
||||
gPrefService.setCharPref("browser.startup.homepage", homepage);
|
||||
gPrefService.setIntPref("browser.startup.page", 1);
|
||||
gBrowser.loadURI("about:sessionrestore");
|
||||
promiseBrowserLoaded(browser).then(() => {
|
||||
let doc = browser.contentDocument;
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["browser.startup.homepage", homepage],
|
||||
["browser.startup.page", 1],
|
||||
]
|
||||
});
|
||||
|
||||
// click on the "Start New Session" button after about:sessionrestore is loaded
|
||||
browser.loadURI("about:sessionrestore");
|
||||
yield BrowserTestUtils.browserLoaded(browser, false, "about:sessionrestore");
|
||||
doc = browser.contentDocument;
|
||||
|
||||
// Click on the "Close" button after about:sessionrestore is loaded.
|
||||
doc.getElementById("errorCancel").click();
|
||||
promiseBrowserLoaded(browser).then(() => {
|
||||
let doc = browser.contentDocument;
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
is(doc.URL, homepage, "loaded page is the homepage");
|
||||
is(browser.currentURI.spec, homepage, "loaded page is the homepage");
|
||||
|
||||
// close tab, restore default values and finish the test
|
||||
gBrowser.removeTab(tab);
|
||||
gPrefService.clearUserPref("browser.startup.page");
|
||||
gPrefService.clearUserPref("browser.startup.homepage");
|
||||
finish();
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1,40 +1,40 @@
|
||||
[
|
||||
{
|
||||
"version": "gcc 4.9.3",
|
||||
"size" : 102421980,
|
||||
"digest": "f25292aa93dc449e0472eee511c0ac15b5f1a4272ab76cf53ce5d20dc57f29e83da49ae1a9d9e994192647f75e13ae60f75ba2ac3cb9d26d5f5d6cabf88de921",
|
||||
"algorithm": "sha512",
|
||||
"version" : "gcc 4.9.3",
|
||||
"filename" : "gcc.tar.xz",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"hg_id" : "cd93f15a30ce",
|
||||
"algorithm" : "sha512",
|
||||
"digest" : "541eb3842ab6b91bd87223cad7a5e4387ef3e496e5b580c8047b8b586bc7eb69fecf3c9eb8c45a1e0deebb53554f0e8acedfe1b4ca64d93b6d008f3f2eb11389",
|
||||
"filename" : "sixgill.tar.xz",
|
||||
"size" : 2626640,
|
||||
"digest" : "f25292aa93dc449e0472eee511c0ac15b5f1a4272ab76cf53ce5d20dc57f29e83da49ae1a9d9e994192647f75e13ae60f75ba2ac3cb9d26d5f5d6cabf88de921",
|
||||
"unpack" : true
|
||||
},
|
||||
{
|
||||
"size": 12072532,
|
||||
"digest" : "36dc644e24c0aa824975ad8f5c15714445d5cb064d823000c3cb637e885199414d7df551e6b99233f0656dcf5760918192ef04113c486af37f3c489bb93ad029",
|
||||
"unpack" : true,
|
||||
"algorithm" : "sha512",
|
||||
"filename" : "sixgill.tar.xz",
|
||||
"size" : 2631908,
|
||||
"hg_id" : "8cb9c3fb039a+ tip"
|
||||
},
|
||||
{
|
||||
"digest" : "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
|
||||
"unpack" : true,
|
||||
"setup" : "setup.sh",
|
||||
"algorithm" : "sha512",
|
||||
"filename" : "gtk3.tar.xz",
|
||||
"setup": "setup.sh",
|
||||
"unpack": true
|
||||
"size" : 12072532
|
||||
},
|
||||
{
|
||||
"size": 89319524,
|
||||
"unpack" : true,
|
||||
"digest" : "5383d843c9f28abf0a6d254e9d975d96972d2c86d627ca836fa8e272a5d53230603b387d7d1499c49df7f84b1bb946946e800a85c88d968bdbe81c755fcb02e1",
|
||||
"algorithm": "sha512",
|
||||
"filename" : "rustc.tar.xz",
|
||||
"unpack": true
|
||||
"algorithm" : "sha512",
|
||||
"size" : 89319524
|
||||
},
|
||||
{
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename" : "sccache.tar.bz2",
|
||||
"unpack": true
|
||||
"algorithm" : "sha512",
|
||||
"digest" : "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"unpack" : true,
|
||||
"size" : 167175
|
||||
}
|
||||
]
|
||||
|
@ -6,9 +6,9 @@
|
||||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.8.0 (db2939409 2016-04-11)",
|
||||
"size": 78733276,
|
||||
"digest": "96ab09cd667ed854efeeca41881a92c9fdc5f3cdeff9b02b12c514183c0b54a21dee8574367abe532429e04660681a1f6c37f6d22cc877d63fbcca7b986d3495",
|
||||
"version": "rustc 1.9.0 (e4e8b6668 2016-05-18)",
|
||||
"size": 82463178,
|
||||
"digest": "a3c54c6792e75d53ec79caf958db25b651fcf968a37b00949fb327c54a54cad6305a4af302f267082d86d70fcf837ed0f273f85b97706c20b957ff3690889b40",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.bz2",
|
||||
"unpack": true
|
||||
|
@ -6,9 +6,9 @@
|
||||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.8.0 (db2939409 2016-04-11)",
|
||||
"size": 85285866,
|
||||
"digest": "f3862036781df9f699a18a5449d51a4f8880e7d890500b314d1f16f394da77c2c496fa537a691d9d99f3248ec2067beaf20b4361babe0dd449d4f7b4f539acac",
|
||||
"version": "rustc 1.9.0 (e4e8b6668 2016-05-18)",
|
||||
"size": 88486080,
|
||||
"digest": "a4fb99cd637b236a9c30e111757ca560bc8df1b143324c1d9ab58c32470b9b9a0598e3e0d220278ee157959dcd88421496388e2ed856e6261d9c81f18e6310e9",
|
||||
"algorithm": "sha512",
|
||||
"visibility": "public",
|
||||
"filename": "rustc.tar.bz2",
|
||||
|
@ -18,6 +18,7 @@ support-files =
|
||||
[browser_panel_privateBrowsing.js]
|
||||
[browser_mozLoop_sharingListeners.js]
|
||||
[browser_mozLoop_telemetry.js]
|
||||
skip-if = os == win && !debug # Bug 1267562 zombiecheck | child process 1228 still alive after shutdown (on win7-vm specifically)
|
||||
[browser_sharingTitleListeners.js]
|
||||
[browser_throttler.js]
|
||||
[browser_toolbarbutton.js]
|
||||
|
@ -53,6 +53,8 @@ PluginContent.prototype = {
|
||||
global.addMessageListener("BrowserPlugins:NPAPIPluginProcessCrashed", this);
|
||||
global.addMessageListener("BrowserPlugins:CrashReportSubmitted", this);
|
||||
global.addMessageListener("BrowserPlugins:Test:ClearCrashData", this);
|
||||
|
||||
Services.obs.addObserver(this, "Plugin::HiddenPluginTouched", false);
|
||||
},
|
||||
|
||||
uninit: function() {
|
||||
@ -75,6 +77,8 @@ PluginContent.prototype = {
|
||||
global.removeMessageListener("BrowserPlugins:Test:ClearCrashData", this);
|
||||
delete this.global;
|
||||
delete this.content;
|
||||
|
||||
Services.obs.removeObserver(this, "Plugin::HiddenPluginTouched");
|
||||
},
|
||||
|
||||
receiveMessage: function (msg) {
|
||||
@ -116,6 +120,15 @@ PluginContent.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
let pluginTag = aSubject;
|
||||
if (aTopic == "Plugin::HiddenPluginTouched") {
|
||||
this._showClickToPlayNotification(pluginTag, false);
|
||||
} else {
|
||||
Cu.reportError("unknown topic observed: " + aTopic);
|
||||
}
|
||||
},
|
||||
|
||||
onPageShow: function (event) {
|
||||
// Ignore events that aren't from the main document.
|
||||
if (!this.content || event.target != this.content.document) {
|
||||
@ -194,6 +207,45 @@ PluginContent.prototype = {
|
||||
};
|
||||
},
|
||||
|
||||
_getPluginInfoForTag: function (pluginTag, tagMimetype, fallbackType) {
|
||||
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
|
||||
let pluginName = gNavigatorBundle.GetStringFromName("pluginInfo.unknownPlugin");
|
||||
let permissionString = null;
|
||||
let blocklistState = null;
|
||||
|
||||
if (pluginTag) {
|
||||
pluginName = BrowserUtils.makeNicePluginName(pluginTag.name);
|
||||
|
||||
permissionString = pluginHost.getPermissionStringForTag(pluginTag);
|
||||
blocklistState = pluginTag.blocklistState;
|
||||
|
||||
// Convert this from nsIPluginTag so it can be serialized.
|
||||
let properties = ["name", "description", "filename", "version", "enabledState", "niceName"];
|
||||
let pluginTagCopy = {};
|
||||
for (let prop of properties) {
|
||||
pluginTagCopy[prop] = pluginTag[prop];
|
||||
}
|
||||
pluginTag = pluginTagCopy;
|
||||
|
||||
// Make state-softblocked == state-notblocked for our purposes,
|
||||
// they have the same UI. STATE_OUTDATED should not exist for plugin
|
||||
// items, but let's alias it anyway, just in case.
|
||||
if (blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED ||
|
||||
blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED) {
|
||||
blocklistState = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
return { mimetype: tagMimetype,
|
||||
pluginName: pluginName,
|
||||
pluginTag: pluginTag,
|
||||
permissionString: permissionString,
|
||||
fallbackType: fallbackType,
|
||||
blocklistState: blocklistState,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the visibility of the plugin overlay.
|
||||
*/
|
||||
|
@ -207,12 +207,6 @@ AC_DEFUN([MOZ_ANDROID_AAR],[
|
||||
MOZ_ANDROID_AAR_COMPONENT(concat(local_aar_var, _ASSETS), concat(root, assets), $6)
|
||||
])
|
||||
|
||||
ANDROID_SUPPORT_LIBRARY_VERSION="23.0.1"
|
||||
AC_SUBST(ANDROID_SUPPORT_LIBRARY_VERSION)
|
||||
|
||||
ANDROID_GOOGLE_PLAY_SERVICES_VERSION="8.4.0"
|
||||
AC_SUBST(ANDROID_GOOGLE_PLAY_SERVICES_VERSION)
|
||||
|
||||
AC_DEFUN([MOZ_ANDROID_GOOGLE_PLAY_SERVICES],
|
||||
[
|
||||
|
||||
|
@ -55,7 +55,8 @@ if __name__ == '__main__':
|
||||
"name": "compiler_metrics",
|
||||
"subtests": [{
|
||||
"name": "num_constructors",
|
||||
"value": count_ctors(f)
|
||||
"value": count_ctors(f),
|
||||
"alertThreshold": 0.25
|
||||
}]}
|
||||
]
|
||||
}
|
||||
|
@ -133,13 +133,6 @@ interface nsIScriptSecurityManager : nsISupports
|
||||
*/
|
||||
nsIPrincipal getSystemPrincipal();
|
||||
|
||||
/**
|
||||
* Return a principal that has the same origin as aURI.
|
||||
* This principals should not be used for any data/permission check, it will
|
||||
* have appId = UNKNOWN_APP_ID.
|
||||
*/
|
||||
nsIPrincipal getSimpleCodebasePrincipal(in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* Returns a principal that has the given information.
|
||||
* @param appId is the app id of the principal. It can't be UNKNOWN_APP_ID.
|
||||
|
@ -1108,16 +1108,6 @@ nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::GetSimpleCodebasePrincipal(nsIURI* aURI,
|
||||
nsIPrincipal** aPrincipal)
|
||||
{
|
||||
PrincipalOriginAttributes attrs(UNKNOWN_APP_ID, false);
|
||||
nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
|
||||
prin.forget(aPrincipal);
|
||||
return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::GetNoAppCodebasePrincipal(nsIURI* aURI,
|
||||
nsIPrincipal** aPrincipal)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsHashPropertyBag.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "mozilla/dom/SettingChangeNotificationBinding.h"
|
||||
@ -41,6 +42,7 @@ namespace {
|
||||
|
||||
// If true, any new AudioChannelAgent will be muted when created.
|
||||
bool sAudioChannelMutedByDefault = false;
|
||||
bool sAudioChannelCompeting = false;
|
||||
bool sXPCOMShuttingDown = false;
|
||||
|
||||
class NotifyChannelActiveRunnable final : public Runnable
|
||||
@ -210,6 +212,13 @@ AudioChannelService::Shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
AudioChannelService::IsEnableAudioCompeting()
|
||||
{
|
||||
CreateServiceIfNeeded();
|
||||
return sAudioChannelCompeting;
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(AudioChannelService)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAudioChannelService)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAudioChannelService)
|
||||
@ -241,6 +250,8 @@ AudioChannelService::AudioChannelService()
|
||||
|
||||
Preferences::AddBoolVarCache(&sAudioChannelMutedByDefault,
|
||||
"dom.audiochannel.mutedByDefault");
|
||||
Preferences::AddBoolVarCache(&sAudioChannelCompeting,
|
||||
"dom.audiochannel.audioCompeting");
|
||||
}
|
||||
|
||||
AudioChannelService::~AudioChannelService()
|
||||
@ -336,14 +347,15 @@ AudioChannelService::GetMediaConfig(nsPIDOMWindowOuter* aWindow,
|
||||
if (winData) {
|
||||
config.mVolume *= winData->mChannels[aAudioChannel].mVolume;
|
||||
config.mMuted = config.mMuted || winData->mChannels[aAudioChannel].mMuted;
|
||||
config.mSuspend = winData->mOwningAudioFocus ?
|
||||
config.mSuspend : nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE;
|
||||
}
|
||||
|
||||
config.mVolume *= window->GetAudioVolume();
|
||||
config.mMuted = config.mMuted || window->GetAudioMuted();
|
||||
|
||||
// If the mSuspend is already suspended, we don't need to set it again.
|
||||
config.mSuspend = (config.mSuspend == nsISuspendedTypes::NONE_SUSPENDED) ?
|
||||
window->GetMediaSuspend() : config.mSuspend;
|
||||
if (window->GetMediaSuspend() != nsISuspendedTypes::NONE_SUSPENDED) {
|
||||
config.mSuspend = window->GetMediaSuspend();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> win = window->GetScriptableParentOrNull();
|
||||
if (!win) {
|
||||
@ -994,6 +1006,176 @@ AudioChannelService::ChildStatusReceived(uint64_t aChildID,
|
||||
data->mActiveContentOrNormalChannel = aContentOrNormalChannel;
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::RefreshAgentsAudioFocusChanged(AudioChannelAgent* aAgent,
|
||||
bool aActive)
|
||||
{
|
||||
MOZ_ASSERT(aAgent);
|
||||
|
||||
nsTObserverArray<nsAutoPtr<AudioChannelWindow>>::ForwardIterator
|
||||
iter(mWindows);
|
||||
while (iter.HasMore()) {
|
||||
AudioChannelWindow* winData = iter.GetNext();
|
||||
if (winData->mOwningAudioFocus) {
|
||||
winData->AudioFocusChanged(aAgent, aActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::AudioChannelWindow::RequestAudioFocus(AudioChannelAgent* aAgent)
|
||||
{
|
||||
MOZ_ASSERT(aAgent);
|
||||
|
||||
// We already have the audio focus. No operation is needed.
|
||||
if (mOwningAudioFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only foreground window can request audio focus, but it would still own the
|
||||
// audio focus even it goes to background. Audio focus would be abandoned
|
||||
// only when other foreground window starts audio competing.
|
||||
mOwningAudioFocus = !(aAgent->Window()->IsBackground());
|
||||
|
||||
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
||||
("AudioChannelWindow, RequestAudioFocus, this = %p, "
|
||||
"agent = %p, owning audio focus = %d\n",
|
||||
this, aAgent, mOwningAudioFocus));
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::AudioChannelWindow::NotifyAudioCompetingChanged(AudioChannelAgent* aAgent,
|
||||
bool aActive)
|
||||
{
|
||||
// This function may be called after RemoveAgentAndReduceAgentsNum(), so the
|
||||
// agent may be not contained in mAgent. In addition, the agent would still
|
||||
// be alive because we have kungFuDeathGrip in UnregisterAudioChannelAgent().
|
||||
MOZ_ASSERT(aAgent);
|
||||
|
||||
RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
|
||||
MOZ_ASSERT(service);
|
||||
|
||||
if (!service->IsEnableAudioCompeting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsAgentInvolvingInAudioCompeting(aAgent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
||||
("AudioChannelWindow, NotifyAudioCompetingChanged, this = %p, "
|
||||
"agent = %p, active = %d\n",
|
||||
this, aAgent, aActive));
|
||||
|
||||
service->RefreshAgentsAudioFocusChanged(aAgent, aActive);
|
||||
}
|
||||
|
||||
bool
|
||||
AudioChannelService::AudioChannelWindow::IsAgentInvolvingInAudioCompeting(AudioChannelAgent* aAgent) const
|
||||
{
|
||||
MOZ_ASSERT(aAgent);
|
||||
|
||||
if(!mOwningAudioFocus) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsAudioCompetingInSameTab()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO : add MediaSession::ambient kind, because it doens't interact with
|
||||
// other kinds.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
AudioChannelService::AudioChannelWindow::IsAudioCompetingInSameTab() const
|
||||
{
|
||||
return (mOwningAudioFocus && mAudibleAgents.Length() > 1);
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::AudioChannelWindow::AudioFocusChanged(AudioChannelAgent* aNewPlayingAgent,
|
||||
bool aActive)
|
||||
{
|
||||
// This agent isn't always known for the current window, because it can comes
|
||||
// from other window.
|
||||
MOZ_ASSERT(aNewPlayingAgent);
|
||||
|
||||
if (mAudibleAgents.IsEmpty()) {
|
||||
// These would happen in two situations,
|
||||
// (1) Audio in page A was ended, and another page B want to play audio.
|
||||
// Page A should abandon its focus.
|
||||
// (2) Audio was paused by remote-control, page should still own the focus.
|
||||
mOwningAudioFocus = IsContainingPlayingAgent(aNewPlayingAgent);
|
||||
} else {
|
||||
nsTObserverArray<AudioChannelAgent*>::ForwardIterator iter(mAudibleAgents);
|
||||
while (iter.HasMore()) {
|
||||
AudioChannelAgent* agent = iter.GetNext();
|
||||
MOZ_ASSERT(agent);
|
||||
|
||||
// Don't need to update the playing state of new playing agent.
|
||||
if (agent == aNewPlayingAgent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t type = GetCompetingBehavior(agent,
|
||||
aNewPlayingAgent->AudioChannelType(),
|
||||
aActive);
|
||||
|
||||
// If window will be suspended, it needs to abandon the audio focus
|
||||
// because only one window can own audio focus at a time. However, we
|
||||
// would support multiple audio focus at the same time in the future.
|
||||
mOwningAudioFocus = (type == nsISuspendedTypes::NONE_SUSPENDED);
|
||||
|
||||
// TODO : support other behaviors which are definded in MediaSession API.
|
||||
switch (type) {
|
||||
case nsISuspendedTypes::NONE_SUSPENDED:
|
||||
case nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE:
|
||||
agent->WindowSuspendChanged(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
||||
("AudioChannelWindow, AudioFocusChanged, this = %p, "
|
||||
"OwningAudioFocus = %d\n", this, mOwningAudioFocus));
|
||||
}
|
||||
|
||||
bool
|
||||
AudioChannelService::AudioChannelWindow::IsContainingPlayingAgent(AudioChannelAgent* aAgent) const
|
||||
{
|
||||
return (aAgent->WindowID() == mWindowID);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
AudioChannelService::AudioChannelWindow::GetCompetingBehavior(AudioChannelAgent* aAgent,
|
||||
int32_t aIncomingChannelType,
|
||||
bool aIncomingChannelActive) const
|
||||
{
|
||||
MOZ_ASSERT(aAgent);
|
||||
MOZ_ASSERT(mAudibleAgents.Contains(aAgent));
|
||||
|
||||
uint32_t competingBehavior = nsISuspendedTypes::NONE_SUSPENDED;
|
||||
int32_t presentChannelType = aAgent->AudioChannelType();
|
||||
|
||||
// TODO : add other competing cases for MediaSession API
|
||||
if (presentChannelType == int32_t(AudioChannel::Normal) &&
|
||||
aIncomingChannelType == int32_t(AudioChannel::Normal) &&
|
||||
aIncomingChannelActive) {
|
||||
competingBehavior = nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE;
|
||||
}
|
||||
|
||||
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
||||
("AudioChannelWindow, GetCompetingBehavior, this = %p, "
|
||||
"present type = %d, incoming channel = %d, behavior = %d\n",
|
||||
this, presentChannelType, aIncomingChannelType, competingBehavior));
|
||||
|
||||
return competingBehavior;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
AudioChannelService::IsAudioChannelMutedByDefault()
|
||||
{
|
||||
@ -1007,9 +1189,12 @@ AudioChannelService::AudioChannelWindow::AppendAgent(AudioChannelAgent* aAgent,
|
||||
{
|
||||
MOZ_ASSERT(aAgent);
|
||||
|
||||
RequestAudioFocus(aAgent);
|
||||
AppendAgentAndIncreaseAgentsNum(aAgent);
|
||||
AudioCapturedChanged(aAgent, AudioCaptureState::eCapturing);
|
||||
AudioAudibleChanged(aAgent, aAudible);
|
||||
if (aAudible) {
|
||||
AudioAudibleChanged(aAgent, AudibleState::eAudible);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -1082,6 +1267,8 @@ AudioChannelService::AudioChannelWindow::AudioAudibleChanged(AudioChannelAgent*
|
||||
} else {
|
||||
RemoveAudibleAgentIfContained(aAgent);
|
||||
}
|
||||
|
||||
NotifyAudioCompetingChanged(aAgent, aAudible);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -89,6 +89,8 @@ public:
|
||||
|
||||
static PRLogModuleInfo* GetAudioChannelLog();
|
||||
|
||||
static bool IsEnableAudioCompeting();
|
||||
|
||||
/**
|
||||
* Any audio channel agent that starts playing should register itself to
|
||||
* this service, sharing the AudioChannel.
|
||||
@ -220,6 +222,9 @@ private:
|
||||
void SetDefaultVolumeControlChannelInternal(int32_t aChannel,
|
||||
bool aVisible, uint64_t aChildID);
|
||||
|
||||
void RefreshAgentsAudioFocusChanged(AudioChannelAgent* aAgent,
|
||||
bool aActive);
|
||||
|
||||
class AudioChannelConfig final : public AudioPlaybackConfig
|
||||
{
|
||||
public:
|
||||
@ -236,13 +241,15 @@ private:
|
||||
{
|
||||
public:
|
||||
explicit AudioChannelWindow(uint64_t aWindowID)
|
||||
: mWindowID(aWindowID),
|
||||
mIsAudioCaptured(false)
|
||||
: mWindowID(aWindowID)
|
||||
, mIsAudioCaptured(false)
|
||||
, mOwningAudioFocus(!AudioChannelService::IsEnableAudioCompeting())
|
||||
{
|
||||
// Workaround for bug1183033, system channel type can always playback.
|
||||
mChannels[(int16_t)AudioChannel::System].mMuted = false;
|
||||
}
|
||||
|
||||
void AudioFocusChanged(AudioChannelAgent* aNewPlayingAgent, bool aActive);
|
||||
void AudioAudibleChanged(AudioChannelAgent* aAgent, AudibleState aAudible);
|
||||
|
||||
void AppendAgent(AudioChannelAgent* aAgent, AudibleState aAudible);
|
||||
@ -256,6 +263,10 @@ private:
|
||||
nsTObserverArray<AudioChannelAgent*> mAgents;
|
||||
nsTObserverArray<AudioChannelAgent*> mAudibleAgents;
|
||||
|
||||
// Owning audio focus when the window starts playing audible sound, and
|
||||
// lose audio focus when other windows starts playing.
|
||||
bool mOwningAudioFocus;
|
||||
|
||||
private:
|
||||
void AudioCapturedChanged(AudioChannelAgent* aAgent,
|
||||
AudioCaptureState aCapture);
|
||||
@ -273,6 +284,16 @@ private:
|
||||
AudibleState aAudible);
|
||||
void NotifyChannelActive(uint64_t aWindowID, AudioChannel aChannel,
|
||||
bool aActive);
|
||||
|
||||
void RequestAudioFocus(AudioChannelAgent* aAgent);
|
||||
void NotifyAudioCompetingChanged(AudioChannelAgent* aAgent, bool aActive);
|
||||
|
||||
uint32_t GetCompetingBehavior(AudioChannelAgent* aAgent,
|
||||
int32_t aIncomingChannelType,
|
||||
bool aIncomingChannelActive) const;
|
||||
bool IsAgentInvolvingInAudioCompeting(AudioChannelAgent* aAgent) const;
|
||||
bool IsAudioCompetingInSameTab() const;
|
||||
bool IsContainingPlayingAgent(AudioChannelAgent* aAgent) const;
|
||||
};
|
||||
|
||||
AudioChannelWindow*
|
||||
|
@ -21,6 +21,10 @@ UNIFIED_SOURCES += [
|
||||
'AudioChannelService.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/base/',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
@ -339,12 +339,9 @@ DOMParser::Init(nsIPrincipal* principal, nsIURI* documentURI,
|
||||
mPrincipal = principal;
|
||||
nsresult rv;
|
||||
if (!mPrincipal) {
|
||||
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
||||
NS_ENSURE_TRUE(secMan, NS_ERROR_NOT_AVAILABLE);
|
||||
rv =
|
||||
secMan->GetSimpleCodebasePrincipal(mDocumentURI,
|
||||
getter_AddRefs(mPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
PrincipalOriginAttributes attrs;
|
||||
mPrincipal = BasePrincipal::CreateCodebasePrincipal(mDocumentURI, attrs);
|
||||
NS_ENSURE_TRUE(mPrincipal, NS_ERROR_FAILURE);
|
||||
mOriginalPrincipal = mPrincipal;
|
||||
} else {
|
||||
mOriginalPrincipal = mPrincipal;
|
||||
|
@ -1181,17 +1181,11 @@ Element::SetAttribute(const nsAString& aName,
|
||||
if (aError.Failed()) {
|
||||
return;
|
||||
}
|
||||
const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
|
||||
|
||||
nsAutoString nameToUse;
|
||||
const nsAttrName* name = InternalGetAttrNameFromQName(aName, &nameToUse);
|
||||
if (!name) {
|
||||
nsCOMPtr<nsIAtom> nameAtom;
|
||||
if (IsHTMLElement() && IsInHTMLDocument()) {
|
||||
nsAutoString lower;
|
||||
nsContentUtils::ASCIIToLower(aName, lower);
|
||||
nameAtom = NS_Atomize(lower);
|
||||
}
|
||||
else {
|
||||
nameAtom = NS_Atomize(aName);
|
||||
}
|
||||
nsCOMPtr<nsIAtom> nameAtom = NS_Atomize(nameToUse);
|
||||
if (!nameAtom) {
|
||||
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
@ -1208,7 +1202,7 @@ Element::SetAttribute(const nsAString& aName,
|
||||
void
|
||||
Element::RemoveAttribute(const nsAString& aName, ErrorResult& aError)
|
||||
{
|
||||
const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
|
||||
const nsAttrName* name = InternalGetAttrNameFromQName(aName);
|
||||
|
||||
if (!name) {
|
||||
// If there is no canonical nsAttrName for this attribute name, then the
|
||||
@ -1991,7 +1985,7 @@ Element::FindAttributeDependence(const nsIAtom* aAttribute,
|
||||
already_AddRefed<mozilla::dom::NodeInfo>
|
||||
Element::GetExistingAttrNameFromQName(const nsAString& aStr) const
|
||||
{
|
||||
const nsAttrName* name = InternalGetExistingAttrNameFromQName(aStr);
|
||||
const nsAttrName* name = InternalGetAttrNameFromQName(aStr);
|
||||
if (!name) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -2167,9 +2161,27 @@ Element::SetEventHandler(nsIAtom* aEventName,
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
const nsAttrName*
|
||||
Element::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
|
||||
Element::InternalGetAttrNameFromQName(const nsAString& aStr,
|
||||
nsAutoString* aNameToUse) const
|
||||
{
|
||||
return mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
|
||||
MOZ_ASSERT(!aNameToUse || aNameToUse->IsEmpty());
|
||||
const nsAttrName* val = nullptr;
|
||||
if (IsHTMLElement() && IsInHTMLDocument()) {
|
||||
nsAutoString lower;
|
||||
nsAutoString& outStr = aNameToUse ? *aNameToUse : lower;
|
||||
nsContentUtils::ASCIIToLower(aStr, outStr);
|
||||
val = mAttrsAndChildren.GetExistingAttrNameFromQName(outStr);
|
||||
if (val) {
|
||||
outStr.Truncate();
|
||||
}
|
||||
} else {
|
||||
val = mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
|
||||
if (!val && aNameToUse) {
|
||||
*aNameToUse = aStr;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -660,7 +660,7 @@ public:
|
||||
ErrorResult& aError);
|
||||
bool HasAttribute(const nsAString& aName) const
|
||||
{
|
||||
return InternalGetExistingAttrNameFromQName(aName) != nullptr;
|
||||
return InternalGetAttrNameFromQName(aName) != nullptr;
|
||||
}
|
||||
bool HasAttributeNS(const nsAString& aNamespaceURI,
|
||||
const nsAString& aLocalName) const;
|
||||
@ -1273,9 +1273,13 @@ protected:
|
||||
GetEventListenerManagerForAttr(nsIAtom* aAttrName, bool* aDefer);
|
||||
|
||||
/**
|
||||
* Internal hook for converting an attribute name-string to an atomized name
|
||||
* Internal hook for converting an attribute name-string to nsAttrName in
|
||||
* case there is such existing attribute. aNameToUse can be passed to get
|
||||
* name which was used for looking for the attribute (lowercase in HTML).
|
||||
*/
|
||||
virtual const nsAttrName* InternalGetExistingAttrNameFromQName(const nsAString& aStr) const;
|
||||
const nsAttrName*
|
||||
InternalGetAttrNameFromQName(const nsAString& aStr,
|
||||
nsAutoString* aNameToUse = nullptr) const;
|
||||
|
||||
nsIFrame* GetStyledFrame();
|
||||
|
||||
|
@ -2719,10 +2719,10 @@ class WorkerRunnableDispatcher final : public WorkerRunnable
|
||||
|
||||
public:
|
||||
WorkerRunnableDispatcher(WebSocketImpl* aImpl, WorkerPrivate* aWorkerPrivate,
|
||||
already_AddRefed<nsIRunnable>&& aEvent)
|
||||
already_AddRefed<nsIRunnable> aEvent)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
||||
, mWebSocketImpl(aImpl)
|
||||
, mEvent(aEvent)
|
||||
, mEvent(Move(aEvent))
|
||||
{
|
||||
}
|
||||
|
||||
@ -2779,7 +2779,7 @@ WebSocketImpl::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocketImpl::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
|
||||
WebSocketImpl::Dispatch(already_AddRefed<nsIRunnable> aEvent, uint32_t aFlags)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> event_ref(aEvent);
|
||||
// If the target is the main-thread we can just dispatch the runnable.
|
||||
@ -2811,7 +2811,7 @@ WebSocketImpl::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocketImpl::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
WebSocketImpl::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -47,3 +47,4 @@ DEPRECATED_OPERATION(AppCache)
|
||||
DEPRECATED_OPERATION(PrefixedFullscreenAPI)
|
||||
DEPRECATED_OPERATION(LenientSetter)
|
||||
DEPRECATED_OPERATION(NavigatorBattery)
|
||||
DEPRECATED_OPERATION(FileLastModifiedDate)
|
||||
|
@ -856,6 +856,7 @@ GK_ATOM(onmapsendmessagereq, "onmapsendmessagereq")
|
||||
GK_ATOM(onmapmessageupdatereq, "onmapmessageupdatereq")
|
||||
GK_ATOM(onnewrdsgroup, "onnewrdsgroup")
|
||||
GK_ATOM(onnotificationclick, "onnotificationclick")
|
||||
GK_ATOM(onnotificationclose, "onnotificationclose")
|
||||
GK_ATOM(onnoupdate, "onnoupdate")
|
||||
GK_ATOM(onobexpasswordreq, "onobexpasswordreq")
|
||||
GK_ATOM(onobsolete, "onobsolete")
|
||||
|
@ -134,25 +134,6 @@ private:
|
||||
void **aOffThreadToken);
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoDontReportUncaught {
|
||||
JSContext* mContext;
|
||||
bool mWasSet;
|
||||
|
||||
public:
|
||||
explicit AutoDontReportUncaught(JSContext* aContext) : mContext(aContext) {
|
||||
MOZ_ASSERT(aContext);
|
||||
mWasSet = JS::ContextOptionsRef(mContext).dontReportUncaught();
|
||||
if (!mWasSet) {
|
||||
JS::ContextOptionsRef(mContext).setDontReportUncaught(true);
|
||||
}
|
||||
}
|
||||
~AutoDontReportUncaught() {
|
||||
if (!mWasSet) {
|
||||
JS::ContextOptionsRef(mContext).setDontReportUncaught(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
AssignJSString(JSContext *cx, T &dest, JSString *s)
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "nsIWeakReference.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -66,7 +68,8 @@ NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray,
|
||||
mWindow,
|
||||
mPlugins)
|
||||
mPlugins,
|
||||
mCTPPlugins)
|
||||
|
||||
static void
|
||||
GetPluginMimeTypes(const nsTArray<RefPtr<nsPluginElement> >& aPlugins,
|
||||
@ -146,6 +149,7 @@ nsPluginArray::Refresh(bool aReloadDocuments)
|
||||
}
|
||||
|
||||
mPlugins.Clear();
|
||||
mCTPPlugins.Clear();
|
||||
|
||||
nsCOMPtr<nsIDOMNavigator> navigator = mWindow->GetNavigator();
|
||||
|
||||
@ -221,6 +225,13 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
|
||||
|
||||
nsPluginElement* plugin = FindPlugin(mPlugins, aName);
|
||||
aFound = (plugin != nullptr);
|
||||
if (!aFound) {
|
||||
nsPluginElement* hiddenPlugin = FindPlugin(mCTPPlugins, aName);
|
||||
if (hiddenPlugin) {
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
obs->NotifyObservers(hiddenPlugin->PluginTag(), "Plugin::HiddenPluginTouched", nsString(aName).get());
|
||||
}
|
||||
}
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@ -282,7 +293,7 @@ operator<(const RefPtr<nsPluginElement>& lhs,
|
||||
void
|
||||
nsPluginArray::EnsurePlugins()
|
||||
{
|
||||
if (!mPlugins.IsEmpty()) {
|
||||
if (!mPlugins.IsEmpty() || !mCTPPlugins.IsEmpty()) {
|
||||
// We already have an array of plugin elements.
|
||||
return;
|
||||
}
|
||||
@ -299,7 +310,31 @@ nsPluginArray::EnsurePlugins()
|
||||
// need to wrap each of these with a nsPluginElement, which is
|
||||
// scriptable.
|
||||
for (uint32_t i = 0; i < pluginTags.Length(); ++i) {
|
||||
nsCOMPtr<nsPluginTag> pluginTag = do_QueryInterface(pluginTags[i]);
|
||||
if (!pluginTag) {
|
||||
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
} else if (pluginTag->IsActive()) {
|
||||
uint32_t permission = nsIPermissionManager::ALLOW_ACTION;
|
||||
if (pluginTag->IsClicktoplay()) {
|
||||
nsCString name;
|
||||
pluginTag->GetName(name);
|
||||
if (NS_LITERAL_CSTRING("Shockwave Flash").Equals(name)) {
|
||||
RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
|
||||
nsCString permString;
|
||||
nsresult rv = pluginHost->GetPermissionStringForTag(pluginTag, 0, permString);
|
||||
if (rv == NS_OK) {
|
||||
nsIPrincipal* principal = mWindow->GetExtantDoc()->NodePrincipal();
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
||||
permMgr->TestPermissionFromPrincipal(principal, permString.get(), &permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (permission == nsIPermissionManager::ALLOW_ACTION) {
|
||||
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
} else {
|
||||
mCTPPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Alphabetize the enumeration order of non-hidden plugins to reduce
|
||||
|
@ -60,6 +60,10 @@ private:
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
nsTArray<RefPtr<nsPluginElement> > mPlugins;
|
||||
/* A separate list of click-to-play plugins that we don't tell content
|
||||
* about but keep track of so we can still prompt the user to click to play.
|
||||
*/
|
||||
nsTArray<RefPtr<nsPluginElement> > mCTPPlugins;
|
||||
};
|
||||
|
||||
class nsPluginElement final : public nsISupports,
|
||||
|
@ -13656,7 +13656,9 @@ class CGNativeMember(ClassMethod):
|
||||
def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
|
||||
breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
|
||||
typedArraysAreStructs=True, variadicIsSequence=False,
|
||||
resultNotAddRefed=False):
|
||||
resultNotAddRefed=False,
|
||||
virtual=False,
|
||||
override=False):
|
||||
"""
|
||||
If typedArraysAreStructs is false, typed arrays will be passed as
|
||||
JS::Handle<JSObject*>. If it's true they will be passed as one of the
|
||||
@ -13684,7 +13686,9 @@ class CGNativeMember(ClassMethod):
|
||||
not signature[0].isVoid()),
|
||||
breakAfterReturnDecl=" ",
|
||||
breakAfterSelf=breakAfterSelf,
|
||||
visibility=visibility)
|
||||
visibility=visibility,
|
||||
virtual=virtual,
|
||||
override=override)
|
||||
|
||||
def getReturnType(self, type, isMember):
|
||||
return self.getRetvalInfo(type, isMember)[0]
|
||||
@ -14448,12 +14452,15 @@ class CGJSImplMember(CGNativeMember):
|
||||
"""
|
||||
def __init__(self, descriptorProvider, member, name, signature,
|
||||
extendedAttrs, breakAfter=True, passJSBitsAsNeeded=True,
|
||||
visibility="public", variadicIsSequence=False):
|
||||
visibility="public", variadicIsSequence=False,
|
||||
virtual=False, override=False):
|
||||
CGNativeMember.__init__(self, descriptorProvider, member, name,
|
||||
signature, extendedAttrs, breakAfter=breakAfter,
|
||||
passJSBitsAsNeeded=passJSBitsAsNeeded,
|
||||
visibility=visibility,
|
||||
variadicIsSequence=variadicIsSequence)
|
||||
variadicIsSequence=variadicIsSequence,
|
||||
virtual=virtual,
|
||||
override=override)
|
||||
self.body = self.getImpl()
|
||||
|
||||
def getArgs(self, returnType, argList):
|
||||
@ -14468,6 +14475,13 @@ class CGJSImplMethod(CGJSImplMember):
|
||||
interface.
|
||||
"""
|
||||
def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
|
||||
virtual = False
|
||||
override = False
|
||||
if (method.identifier.name == "eventListenerWasAdded" or
|
||||
method.identifier.name == "eventListenerWasRemoved"):
|
||||
virtual = True
|
||||
override = True
|
||||
|
||||
self.signature = signature
|
||||
self.descriptor = descriptor
|
||||
self.isConstructor = isConstructor
|
||||
@ -14478,7 +14492,9 @@ class CGJSImplMethod(CGJSImplMember):
|
||||
descriptor.getExtendedAttributes(method),
|
||||
breakAfter=breakAfter,
|
||||
variadicIsSequence=True,
|
||||
passJSBitsAsNeeded=False)
|
||||
passJSBitsAsNeeded=False,
|
||||
virtual=virtual,
|
||||
override=override)
|
||||
|
||||
def getArgs(self, returnType, argList):
|
||||
if self.isConstructor:
|
||||
|
@ -218,10 +218,11 @@ TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
|
||||
|
||||
// And go!:
|
||||
MOZ_ASSERT(srcOrigin != dstOrigin || srcPremultiplied != dstPremultiplied);
|
||||
bool unused_wasTrivial;
|
||||
if (!ConvertImage(mWidth, mHeight,
|
||||
mBytes, rowStride, srcOrigin, texelFormat, srcPremultiplied,
|
||||
tempBuffer.get(), rowStride, dstOrigin, texelFormat,
|
||||
dstPremultiplied))
|
||||
dstPremultiplied, &unused_wasTrivial))
|
||||
{
|
||||
MOZ_ASSERT(false, "ConvertImage failed unexpectedly.");
|
||||
*out_glError = LOCAL_GL_OUT_OF_MEMORY;
|
||||
@ -311,6 +312,10 @@ TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
|
||||
return; // Blitting was successful, so we're done!
|
||||
} while (false);
|
||||
|
||||
webgl->GenerateWarning("%s: Failed to hit GPU-copy fast-path. Falling back to CPU"
|
||||
" upload.",
|
||||
funcName);
|
||||
|
||||
RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
|
||||
if (!surface) {
|
||||
*out_glError = LOCAL_GL_OUT_OF_MEMORY;
|
||||
@ -662,7 +667,7 @@ TexUnpackSurface::ConvertSurface(WebGLContext* webgl, const webgl::DriverUnpackI
|
||||
gfx::DataSourceSurface* surf, bool isSurfAlphaPremult,
|
||||
UniqueBuffer* const out_convertedBuffer,
|
||||
uint8_t* const out_convertedAlignment,
|
||||
bool* const out_outOfMemory)
|
||||
bool* const out_wasTrivial, bool* const out_outOfMemory)
|
||||
{
|
||||
*out_outOfMemory = false;
|
||||
|
||||
@ -719,9 +724,11 @@ TexUnpackSurface::ConvertSurface(WebGLContext* webgl, const webgl::DriverUnpackI
|
||||
const bool dstPremultiplied = webgl->mPixelStore_PremultiplyAlpha;
|
||||
|
||||
// And go!:
|
||||
bool wasTrivial;
|
||||
if (!ConvertImage(width, height,
|
||||
srcBegin, srcStride, srcOrigin, srcFormat, srcPremultiplied,
|
||||
dstBegin, dstStride, dstOrigin, dstFormat, dstPremultiplied))
|
||||
dstBegin, dstStride, dstOrigin, dstFormat, dstPremultiplied,
|
||||
&wasTrivial))
|
||||
{
|
||||
MOZ_ASSERT(false, "ConvertImage failed unexpectedly.");
|
||||
NS_ERROR("ConvertImage failed unexpectedly.");
|
||||
@ -731,6 +738,7 @@ TexUnpackSurface::ConvertSurface(WebGLContext* webgl, const webgl::DriverUnpackI
|
||||
|
||||
*out_convertedBuffer = Move(dstBuffer);
|
||||
*out_convertedAlignment = dstAlignment;
|
||||
*out_wasTrivial = wasTrivial;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -785,9 +793,10 @@ TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* f
|
||||
|
||||
UniqueBuffer convertedBuffer;
|
||||
uint8_t convertedAlignment;
|
||||
bool wasTrivial;
|
||||
bool outOfMemory;
|
||||
if (!ConvertSurface(webgl, dui, dataSurf, mIsAlphaPremult, &convertedBuffer,
|
||||
&convertedAlignment, &outOfMemory))
|
||||
&convertedAlignment, &wasTrivial, &outOfMemory))
|
||||
{
|
||||
if (outOfMemory) {
|
||||
*out_glError = LOCAL_GL_OUT_OF_MEMORY;
|
||||
@ -798,6 +807,12 @@ TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* f
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wasTrivial) {
|
||||
webgl->GenerateWarning("%s: Chosen format/type incured an expensive reformat:"
|
||||
" 0x%04x/0x%04x",
|
||||
funcName, dui->unpackFormat, dui->unpackType);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE( webgl->gl->MakeCurrent() );
|
||||
ScopedUnpackReset scopedReset(webgl);
|
||||
webgl->gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, convertedAlignment);
|
||||
|
@ -147,7 +147,7 @@ protected:
|
||||
gfx::DataSourceSurface* surf, bool isSurfAlphaPremult,
|
||||
UniqueBuffer* const out_convertedBuffer,
|
||||
uint8_t* const out_convertedAlignment,
|
||||
bool* const out_outOfMemory);
|
||||
bool* const out_wasTrivial, bool* const out_outOfMemory);
|
||||
static bool UploadDataSurface(bool isSubImage, WebGLContext* webgl,
|
||||
TexImageTarget target, GLint level,
|
||||
const webgl::DriverUnpackInfo* dui, GLint xOffset,
|
||||
|
@ -43,11 +43,8 @@ WebGL2Context::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
|
||||
/* GLenum */
|
||||
case LOCAL_GL_READ_BUFFER: {
|
||||
if (mBoundReadFramebuffer) {
|
||||
GLint val = LOCAL_GL_NONE;
|
||||
gl->fGetIntegerv(pname, &val);
|
||||
return JS::Int32Value(val);
|
||||
}
|
||||
if (mBoundReadFramebuffer)
|
||||
return JS::Int32Value(mBoundReadFramebuffer->ReadBufferMode());
|
||||
|
||||
return JS::Int32Value(LOCAL_GL_BACK);
|
||||
}
|
||||
|
@ -984,6 +984,9 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
|
||||
|
||||
mOptions.antialias = gl->Caps().antialias;
|
||||
|
||||
//////
|
||||
// Initial setup.
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
gl->fViewport(0, 0, mWidth, mHeight);
|
||||
@ -991,20 +994,13 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
|
||||
mViewportHeight = mHeight;
|
||||
|
||||
gl->fScissor(0, 0, mWidth, mHeight);
|
||||
|
||||
// Make sure that we clear this out, otherwise
|
||||
// we'll end up displaying random memory
|
||||
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
|
||||
|
||||
//////
|
||||
// Check everything
|
||||
|
||||
AssertCachedBindings();
|
||||
AssertCachedState();
|
||||
|
||||
// Clear immediately, because we need to present the cleared initial
|
||||
// buffer.
|
||||
mBackbufferNeedsClear = true;
|
||||
ClearBackbufferIfNeeded();
|
||||
|
||||
mShouldPresent = true;
|
||||
AssertCachedGlobalState();
|
||||
|
||||
MOZ_ASSERT(gl->Caps().color);
|
||||
|
||||
@ -1020,8 +1016,14 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
|
||||
MOZ_ASSERT(gl->Caps().antialias == mOptions.antialias);
|
||||
MOZ_ASSERT(gl->Caps().preserve == mOptions.preserveDrawingBuffer);
|
||||
|
||||
AssertCachedBindings();
|
||||
AssertCachedState();
|
||||
//////
|
||||
// Clear immediately, because we need to present the cleared initial buffer
|
||||
mBackbufferNeedsClear = true;
|
||||
ClearBackbufferIfNeeded();
|
||||
|
||||
mShouldPresent = true;
|
||||
|
||||
//////
|
||||
|
||||
reporter.SetSuccessful();
|
||||
|
||||
@ -1416,8 +1418,7 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield clearBits,
|
||||
|
||||
// Fun GL fact: No need to worry about the viewport here, glViewport is just
|
||||
// setting up a coordinates transformation, it doesn't affect glClear at all.
|
||||
AssertCachedState(); // Can't check cached bindings, as we could
|
||||
// have a different FB bound temporarily.
|
||||
AssertCachedGlobalState();
|
||||
|
||||
// Prepare GL state for clearing.
|
||||
gl->fDisable(LOCAL_GL_SCISSOR_TEST);
|
||||
@ -1881,6 +1882,14 @@ WebGLContext::ValidateCurFBForRead(const char* funcName,
|
||||
GLenum* const out_mode)
|
||||
{
|
||||
if (!mBoundReadFramebuffer) {
|
||||
const GLenum readBufferMode = gl->Screen()->GetReadBufferMode();
|
||||
if (readBufferMode == LOCAL_GL_NONE) {
|
||||
ErrorInvalidOperation("%s: Can't read from backbuffer when readBuffer mode is"
|
||||
" NONE.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
ClearBackbufferIfNeeded();
|
||||
|
||||
// FIXME - here we're assuming that the default framebuffer is backed by
|
||||
|
@ -376,7 +376,7 @@ public:
|
||||
bool TryToRestoreContext();
|
||||
|
||||
void AssertCachedBindings();
|
||||
void AssertCachedState();
|
||||
void AssertCachedGlobalState();
|
||||
|
||||
dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; }
|
||||
|
||||
|
@ -72,7 +72,8 @@ WebGLContext::ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
const bool supportsFloatColorBuffers = (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) ||
|
||||
const bool supportsFloatColorBuffers = (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_float) ||
|
||||
IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) ||
|
||||
IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float));
|
||||
if (!supportsFloatColorBuffers) {
|
||||
r = GLClampFloat(r);
|
||||
|
@ -68,7 +68,7 @@ ContextLossWorkerEventTarget::DispatchFromScript(nsIRunnable* aEvent, uint32_t a
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContextLossWorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
ContextLossWorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable> aEvent,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> eventRef(aEvent);
|
||||
@ -78,7 +78,7 @@ ContextLossWorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContextLossWorkerEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>&&,
|
||||
ContextLossWorkerEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>,
|
||||
uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
@ -380,16 +380,11 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
return JS::NumberValue(uint32_t(i));
|
||||
}
|
||||
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
|
||||
if (mBoundReadFramebuffer) {
|
||||
nsCString fbStatusInfoIgnored;
|
||||
const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(&fbStatusInfoIgnored);
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
ErrorInvalidOperation("getParameter: Read framebuffer must be"
|
||||
" complete before querying"
|
||||
" IMPLEMENTATION_COLOR_READ_TYPE.");
|
||||
const webgl::FormatUsageInfo* usage;
|
||||
uint32_t width, height;
|
||||
GLenum mode;
|
||||
if (!ValidateCurFBForRead(funcName, &usage, &width, &height, &mode))
|
||||
return JS::NullValue();
|
||||
}
|
||||
}
|
||||
|
||||
GLint i = 0;
|
||||
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
|
||||
@ -401,16 +396,11 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
return JS::NumberValue(uint32_t(i));
|
||||
}
|
||||
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: {
|
||||
if (mBoundReadFramebuffer) {
|
||||
nsCString fbStatusInfoIgnored;
|
||||
const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(&fbStatusInfoIgnored);
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
ErrorInvalidOperation("getParameter: Read framebuffer must be"
|
||||
" complete before querying"
|
||||
" IMPLEMENTATION_COLOR_READ_FORMAT.");
|
||||
const webgl::FormatUsageInfo* usage;
|
||||
uint32_t width, height;
|
||||
GLenum mode;
|
||||
if (!ValidateCurFBForRead(funcName, &usage, &width, &height, &mode))
|
||||
return JS::NullValue();
|
||||
}
|
||||
}
|
||||
|
||||
GLint i = 0;
|
||||
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
|
||||
|
@ -684,7 +684,7 @@ WebGLContext::AssertCachedBindings()
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound);
|
||||
}
|
||||
|
||||
// Bound object state
|
||||
// Framebuffers
|
||||
if (IsWebGL2()) {
|
||||
GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName
|
||||
: 0;
|
||||
@ -699,6 +699,15 @@ WebGLContext::AssertCachedBindings()
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
|
||||
}
|
||||
|
||||
GLint stencilBits = 0;
|
||||
if (GetStencilBits(&stencilBits)) { // Depends on current draw framebuffer.
|
||||
const GLuint stencilRefMask = (1 << stencilBits) - 1;
|
||||
|
||||
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront);
|
||||
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
|
||||
}
|
||||
|
||||
// Program
|
||||
GLuint bound = mCurrentProgram ? mCurrentProgram->mGLName : 0;
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound);
|
||||
|
||||
@ -730,7 +739,7 @@ WebGLContext::AssertCachedBindings()
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::AssertCachedState()
|
||||
WebGLContext::AssertCachedGlobalState()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
MakeContextCurrent();
|
||||
@ -771,14 +780,6 @@ WebGLContext::AssertCachedState()
|
||||
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE, mStencilClearValue);
|
||||
|
||||
GLint stencilBits = 0;
|
||||
if (GetStencilBits(&stencilBits)) {
|
||||
const GLuint stencilRefMask = (1 << stencilBits) - 1;
|
||||
|
||||
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront);
|
||||
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
|
||||
}
|
||||
|
||||
// GLES 3.0.4, $4.1.4, p177:
|
||||
// [...] the front and back stencil mask are both set to the value `2^s - 1`, where
|
||||
// `s` is greater than or equal to the number of bits in the deepest stencil buffer
|
||||
|
@ -257,6 +257,8 @@ public:
|
||||
mReadBufferMode = readBufferMode;
|
||||
}
|
||||
|
||||
GLenum ReadBufferMode() const { return mReadBufferMode; }
|
||||
|
||||
protected:
|
||||
WebGLFBAttachPoint* GetAttachPoint(GLenum attachment); // Fallible
|
||||
|
||||
|
@ -349,8 +349,11 @@ ConvertImage(size_t width, size_t height,
|
||||
const void* srcBegin, size_t srcStride, gl::OriginPos srcOrigin,
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied,
|
||||
void* dstBegin, size_t dstStride, gl::OriginPos dstOrigin,
|
||||
WebGLTexelFormat dstFormat, bool dstPremultiplied)
|
||||
WebGLTexelFormat dstFormat, bool dstPremultiplied,
|
||||
bool* const out_wasTrivial)
|
||||
{
|
||||
*out_wasTrivial = true;
|
||||
|
||||
if (srcFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion ||
|
||||
dstFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion)
|
||||
{
|
||||
@ -410,6 +413,8 @@ ConvertImage(size_t width, size_t height,
|
||||
return true;
|
||||
}
|
||||
|
||||
*out_wasTrivial = false;
|
||||
|
||||
WebGLImageConverter converter(width, height, srcItr, dstItr, srcStride, dstItrStride);
|
||||
converter.run(srcFormat, dstFormat, premultOp);
|
||||
|
||||
|
@ -43,7 +43,8 @@ bool ConvertImage(size_t width, size_t height,
|
||||
const void* srcBegin, size_t srcStride, gl::OriginPos srcOrigin,
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied,
|
||||
void* dstBegin, size_t dstStride, gl::OriginPos dstOrigin,
|
||||
WebGLTexelFormat dstFormat, bool dstPremultiplied);
|
||||
WebGLTexelFormat dstFormat, bool dstPremultiplied,
|
||||
bool* out_wasTrivial);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -1338,6 +1338,19 @@ EventListenerManager::Disconnect()
|
||||
RemoveAllListeners();
|
||||
}
|
||||
|
||||
static EventListenerFlags
|
||||
GetEventListenerFlagsFromOptions(const EventListenerOptions& aOptions)
|
||||
{
|
||||
EventListenerFlags flags;
|
||||
flags.mCapture = aOptions.mCapture;
|
||||
if (aOptions.mMozSystemGroup) {
|
||||
JSContext* cx = nsContentUtils::GetCurrentJSContext();
|
||||
MOZ_ASSERT(cx, "Not being called from JS?");
|
||||
flags.mInSystemGroup = IsChromeOrXBL(cx, nullptr);
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
void
|
||||
EventListenerManager::AddEventListener(
|
||||
const nsAString& aType,
|
||||
@ -1362,8 +1375,9 @@ EventListenerManager::AddEventListener(
|
||||
if (aOptions.IsBoolean()) {
|
||||
flags.mCapture = aOptions.GetAsBoolean();
|
||||
} else {
|
||||
flags.mCapture = aOptions.GetAsAddEventListenerOptions().mCapture;
|
||||
flags.mPassive = aOptions.GetAsAddEventListenerOptions().mPassive;
|
||||
const auto& options = aOptions.GetAsAddEventListenerOptions();
|
||||
flags = GetEventListenerFlagsFromOptions(options);
|
||||
flags.mPassive = options.mPassive;
|
||||
}
|
||||
flags.mAllowUntrustedEvents = aWantsUntrusted;
|
||||
return AddEventListenerByType(aListenerHolder, aType, flags);
|
||||
@ -1387,9 +1401,12 @@ EventListenerManager::RemoveEventListener(
|
||||
const dom::EventListenerOptionsOrBoolean& aOptions)
|
||||
{
|
||||
EventListenerFlags flags;
|
||||
flags.mCapture =
|
||||
aOptions.IsBoolean() ? aOptions.GetAsBoolean()
|
||||
: aOptions.GetAsEventListenerOptions().mCapture;
|
||||
if (aOptions.IsBoolean()) {
|
||||
flags.mCapture = aOptions.GetAsBoolean();
|
||||
} else {
|
||||
const auto& options = aOptions.GetAsEventListenerOptions();
|
||||
flags = GetEventListenerFlagsFromOptions(options);
|
||||
}
|
||||
RemoveEventListenerByType(aListenerHolder, aType, flags);
|
||||
}
|
||||
|
||||
|
@ -77,6 +77,55 @@ function test_duplicateGetFilesAndDirectories() {
|
||||
script.sendAsyncMessage("dir.open", { path: 'test' });
|
||||
}
|
||||
|
||||
function test_inputGetFiles() {
|
||||
var url = SimpleTest.getTestFileURL("script_fileList.js");
|
||||
var script = SpecialPowers.loadChromeScript(url);
|
||||
|
||||
function onOpened(message) {
|
||||
var fileList = document.getElementById('fileList');
|
||||
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
|
||||
|
||||
fileList.getFilesAndDirectories()
|
||||
.then(function(result) {
|
||||
is(result.length, 1, "getFilesAndDirectories should return 1 element");
|
||||
ok(result[0] instanceof Directory, "getFilesAndDirectories should return 1 directory");
|
||||
|
||||
return fileList.getFiles(false);
|
||||
})
|
||||
.then(function(result) {
|
||||
is(result.length, 1, "getFiles should return 1 element");
|
||||
ok(result[0] instanceof File, "getFile should return 1 file");
|
||||
is(result[0].name, 'foo.txt', "getFiles()[0].name should be 'foo.txt'");
|
||||
is(result[0].webkitRelativePath, '/foo.txt', "getFiles()[0].webkitRelativePath should be '/foo.txt'");
|
||||
|
||||
return fileList.getFiles(true);
|
||||
})
|
||||
.then(function(result) {
|
||||
is(result.length, 2, "getFiles should return 2 elements");
|
||||
|
||||
function checkFile(file) {
|
||||
ok(file instanceof File, "getFile[x] should return a file");
|
||||
if (file.name == 'foo.txt') {
|
||||
is(file.webkitRelativePath, '/foo.txt', "getFiles()[x].webkitRelativePath should be '/foo.txt'");
|
||||
} else {
|
||||
is(file.name, 'bar.txt', "getFiles()[x].name should be 'bar.txt'");
|
||||
is(file.webkitRelativePath, '/subdir/bar.txt', "getFiles()[x].webkitRelativePath should be '/subdir/bar.txt'");
|
||||
}
|
||||
}
|
||||
|
||||
checkFile(result[0]);
|
||||
checkFile(result[1]);
|
||||
})
|
||||
.then(function() {
|
||||
script.destroy();
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
script.addMessageListener("dir.opened", onOpened);
|
||||
script.sendAsyncMessage("dir.open", { path: 'test' });
|
||||
}
|
||||
|
||||
var tests = [
|
||||
function() { setup_tests(next); },
|
||||
|
||||
@ -95,6 +144,7 @@ var tests = [
|
||||
function() { test_getFiles(directory, false, next); },
|
||||
|
||||
test_duplicateGetFilesAndDirectories,
|
||||
test_inputGetFiles,
|
||||
test_simpleFilePicker
|
||||
];
|
||||
|
||||
|
@ -218,6 +218,321 @@ const Decimal HTMLInputElement::kStepAny = Decimal(0);
|
||||
#define PROGRESS_STR "progress"
|
||||
static const uint32_t kProgressEventInterval = 50; // ms
|
||||
|
||||
// Retrieving the list of files can be very time/IO consuming. We use this
|
||||
// helper class to do it just once.
|
||||
class GetFilesHelper final : public Runnable
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<GetFilesHelper>
|
||||
Create(nsIGlobalObject* aGlobal,
|
||||
const nsTArray<OwningFileOrDirectory>& aFilesOrDirectory,
|
||||
bool aRecursiveFlag, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aGlobal);
|
||||
|
||||
RefPtr<GetFilesHelper> helper = new GetFilesHelper(aGlobal, aRecursiveFlag);
|
||||
|
||||
nsAutoString directoryPath;
|
||||
|
||||
for (uint32_t i = 0; i < aFilesOrDirectory.Length(); ++i) {
|
||||
const OwningFileOrDirectory& data = aFilesOrDirectory[i];
|
||||
if (data.IsFile()) {
|
||||
if (!helper->mFiles.AppendElement(data.GetAsFile(), fallible)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(data.IsDirectory());
|
||||
|
||||
// We support the upload of only 1 top-level directory from our
|
||||
// directory picker. This means that we cannot have more than 1
|
||||
// Directory object in aFilesOrDirectory array.
|
||||
MOZ_ASSERT(directoryPath.IsEmpty());
|
||||
|
||||
RefPtr<Directory> directory = data.GetAsDirectory();
|
||||
MOZ_ASSERT(directory);
|
||||
|
||||
aRv = directory->GetFullRealPath(directoryPath);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No directories to explore.
|
||||
if (directoryPath.IsEmpty()) {
|
||||
helper->mListingCompleted = true;
|
||||
return helper.forget();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(helper->mFiles.IsEmpty());
|
||||
helper->SetDirectoryPath(directoryPath);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target =
|
||||
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
MOZ_ASSERT(target);
|
||||
|
||||
aRv = target->Dispatch(helper, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return helper.forget();
|
||||
}
|
||||
|
||||
void
|
||||
AddPromise(Promise* aPromise)
|
||||
{
|
||||
MOZ_ASSERT(aPromise);
|
||||
|
||||
// Still working.
|
||||
if (!mListingCompleted) {
|
||||
mPromises.AppendElement(aPromise);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPromises.IsEmpty());
|
||||
ResolveOrRejectPromise(aPromise);
|
||||
}
|
||||
|
||||
// CC methods
|
||||
void Unlink()
|
||||
{
|
||||
mGlobal = nullptr;
|
||||
mFiles.Clear();
|
||||
mPromises.Clear();
|
||||
}
|
||||
|
||||
void Traverse(nsCycleCollectionTraversalCallback &cb)
|
||||
{
|
||||
GetFilesHelper* tmp = this;
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromises);
|
||||
}
|
||||
|
||||
private:
|
||||
GetFilesHelper(nsIGlobalObject* aGlobal, bool aRecursiveFlag)
|
||||
: mGlobal(aGlobal)
|
||||
, mRecursiveFlag(aRecursiveFlag)
|
||||
, mListingCompleted(false)
|
||||
, mErrorResult(NS_OK)
|
||||
{
|
||||
MOZ_ASSERT(aGlobal);
|
||||
}
|
||||
|
||||
void
|
||||
SetDirectoryPath(const nsAString& aDirectoryPath)
|
||||
{
|
||||
mDirectoryPath = aDirectoryPath;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
MOZ_ASSERT(!mDirectoryPath.IsEmpty());
|
||||
MOZ_ASSERT(!mListingCompleted);
|
||||
|
||||
// First step is to retrieve the list of file paths.
|
||||
// This happens in the I/O thread.
|
||||
if (!NS_IsMainThread()) {
|
||||
RunIO();
|
||||
return NS_DispatchToMainThread(this);
|
||||
}
|
||||
|
||||
RunMainThread();
|
||||
|
||||
// We mark the operation as completed here.
|
||||
mListingCompleted = true;
|
||||
|
||||
// Let's process the pending promises.
|
||||
nsTArray<RefPtr<Promise>> promises;
|
||||
promises.SwapElements(mPromises);
|
||||
|
||||
for (uint32_t i = 0; i < promises.Length(); ++i) {
|
||||
ResolveOrRejectPromise(promises[i]);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
RunIO()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(!mDirectoryPath.IsEmpty());
|
||||
MOZ_ASSERT(!mListingCompleted);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
mErrorResult = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(mDirectoryPath), true,
|
||||
getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(mErrorResult))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString path;
|
||||
path.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
|
||||
|
||||
mErrorResult = ExploreDirectory(path, file);
|
||||
}
|
||||
|
||||
void
|
||||
RunMainThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mDirectoryPath.IsEmpty());
|
||||
MOZ_ASSERT(!mListingCompleted);
|
||||
|
||||
// If there is an error, do nothing.
|
||||
if (NS_FAILED(mErrorResult)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the sequence of Files.
|
||||
for (uint32_t i = 0; i < mTargetPathArray.Length(); ++i) {
|
||||
nsCOMPtr<nsIFile> file;
|
||||
mErrorResult =
|
||||
NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(mTargetPathArray[i].mRealPath),
|
||||
true, getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(mErrorResult))) {
|
||||
mFiles.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<File> domFile =
|
||||
File::CreateFromFile(mGlobal, file);
|
||||
MOZ_ASSERT(domFile);
|
||||
|
||||
domFile->SetPath(mTargetPathArray[i].mDomPath);
|
||||
|
||||
if (!mFiles.AppendElement(domFile, fallible)) {
|
||||
mErrorResult = NS_ERROR_OUT_OF_MEMORY;
|
||||
mFiles.Clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExploreDirectory(const nsAString& aDOMPath, nsIFile* aFile)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||
nsresult rv = aFile->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
bool hasMore = false;
|
||||
if (NS_WARN_IF(NS_FAILED(entries->HasMoreElements(&hasMore))) || !hasMore) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
if (NS_WARN_IF(NS_FAILED(entries->GetNext(getter_AddRefs(supp))))) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> currFile = do_QueryInterface(supp);
|
||||
MOZ_ASSERT(currFile);
|
||||
|
||||
bool isLink, isSpecial, isFile, isDir;
|
||||
if (NS_WARN_IF(NS_FAILED(currFile->IsSymlink(&isLink)) ||
|
||||
NS_FAILED(currFile->IsSpecial(&isSpecial))) ||
|
||||
isLink || isSpecial) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(currFile->IsFile(&isFile)) ||
|
||||
NS_FAILED(currFile->IsDirectory(&isDir))) ||
|
||||
!(isFile || isDir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The new domPath
|
||||
nsAutoString domPath;
|
||||
domPath.Assign(aDOMPath);
|
||||
if (!aDOMPath.EqualsLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL)) {
|
||||
domPath.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
|
||||
}
|
||||
|
||||
nsAutoString leafName;
|
||||
if (NS_WARN_IF(NS_FAILED(currFile->GetLeafName(leafName)))) {
|
||||
continue;
|
||||
}
|
||||
domPath.Append(leafName);
|
||||
|
||||
if (isFile) {
|
||||
FileData* data = mTargetPathArray.AppendElement(fallible);
|
||||
if (!data) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(currFile->GetPath(data->mRealPath)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data->mDomPath = domPath;
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(isDir);
|
||||
if (!mRecursiveFlag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Recursive.
|
||||
rv = ExploreDirectory(domPath, currFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ResolveOrRejectPromise(Promise* aPromise)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mListingCompleted);
|
||||
MOZ_ASSERT(aPromise);
|
||||
|
||||
// Error propagation.
|
||||
if (NS_FAILED(mErrorResult)) {
|
||||
aPromise->MaybeReject(mErrorResult);
|
||||
return;
|
||||
}
|
||||
|
||||
aPromise->MaybeResolve(mFiles);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
|
||||
bool mRecursiveFlag;
|
||||
bool mListingCompleted;
|
||||
nsString mDirectoryPath;
|
||||
|
||||
// We populate this array in the I/O thread with the paths of the Files that
|
||||
// we want to send as result to the promise objects.
|
||||
struct FileData {
|
||||
nsString mDomPath;
|
||||
nsString mRealPath;
|
||||
};
|
||||
FallibleTArray<FileData> mTargetPathArray;
|
||||
|
||||
// This is the real File sequence that we expose via Promises.
|
||||
Sequence<RefPtr<File>> mFiles;
|
||||
|
||||
// Error code to propagate.
|
||||
nsresult mErrorResult;
|
||||
|
||||
nsTArray<RefPtr<Promise>> mPromises;
|
||||
};
|
||||
|
||||
class HTMLInputElementState final : public nsISupports
|
||||
{
|
||||
public:
|
||||
@ -1052,6 +1367,15 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLInputElement,
|
||||
tmp->mInputData.mState->Traverse(cb);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesOrDirectories)
|
||||
|
||||
if (tmp->mGetFilesRecursiveHelper) {
|
||||
tmp->mGetFilesRecursiveHelper->Traverse(cb);
|
||||
}
|
||||
|
||||
if (tmp->mGetFilesNonRecursiveHelper) {
|
||||
tmp->mGetFilesNonRecursiveHelper->Traverse(cb);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
@ -1064,6 +1388,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement,
|
||||
if (tmp->IsSingleLineTextControl(false)) {
|
||||
tmp->mInputData.mState->Unlink();
|
||||
}
|
||||
|
||||
tmp->ClearGetFilesHelpers();
|
||||
|
||||
//XXX should unlink more?
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
@ -1117,6 +1444,7 @@ HTMLInputElement::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) co
|
||||
// we can just grab the pretty string and use it as wallpaper
|
||||
GetDisplayFileName(it->mStaticDocFileList);
|
||||
} else {
|
||||
it->ClearGetFilesHelpers();
|
||||
it->mFilesOrDirectories.Clear();
|
||||
it->mFilesOrDirectories.AppendElements(mFilesOrDirectories);
|
||||
}
|
||||
@ -2562,6 +2890,8 @@ void
|
||||
HTMLInputElement::SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories,
|
||||
bool aSetValueChanged)
|
||||
{
|
||||
ClearGetFilesHelpers();
|
||||
|
||||
mFilesOrDirectories.Clear();
|
||||
mFilesOrDirectories.AppendElements(aFilesOrDirectories);
|
||||
|
||||
@ -2574,6 +2904,7 @@ HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
|
||||
{
|
||||
RefPtr<FileList> files = static_cast<FileList*>(aFiles);
|
||||
mFilesOrDirectories.Clear();
|
||||
ClearGetFilesHelpers();
|
||||
|
||||
if (aFiles) {
|
||||
uint32_t listLength;
|
||||
@ -5081,6 +5412,58 @@ HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv)
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
HTMLInputElement::GetFiles(bool aRecursiveFlag, ErrorResult& aRv)
|
||||
{
|
||||
if (mType != NS_FORM_INPUT_FILE) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
||||
MOZ_ASSERT(global);
|
||||
if (!global) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<GetFilesHelper> helper;
|
||||
if (aRecursiveFlag) {
|
||||
if (!mGetFilesRecursiveHelper) {
|
||||
mGetFilesRecursiveHelper =
|
||||
GetFilesHelper::Create(global,
|
||||
GetFilesOrDirectoriesInternal(),
|
||||
aRecursiveFlag, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
helper = mGetFilesRecursiveHelper;
|
||||
} else {
|
||||
if (!mGetFilesNonRecursiveHelper) {
|
||||
mGetFilesNonRecursiveHelper =
|
||||
GetFilesHelper::Create(global,
|
||||
GetFilesOrDirectoriesInternal(),
|
||||
aRecursiveFlag, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
helper = mGetFilesNonRecursiveHelper;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(helper);
|
||||
|
||||
RefPtr<Promise> p = Promise::Create(global, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
helper->AddPromise(p);
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
|
||||
// Controllers Methods
|
||||
|
||||
@ -7578,6 +7961,20 @@ HTMLInputElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
return HTMLInputElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::ClearGetFilesHelpers()
|
||||
{
|
||||
if (mGetFilesRecursiveHelper) {
|
||||
mGetFilesRecursiveHelper->Unlink();
|
||||
mGetFilesRecursiveHelper = nullptr;
|
||||
}
|
||||
|
||||
if (mGetFilesNonRecursiveHelper) {
|
||||
mGetFilesNonRecursiveHelper->Unlink();
|
||||
mGetFilesNonRecursiveHelper = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -40,6 +40,7 @@ namespace dom {
|
||||
class Date;
|
||||
class File;
|
||||
class FileList;
|
||||
class GetFilesHelper;
|
||||
|
||||
/**
|
||||
* A class we use to create a singleton object that is used to keep track of
|
||||
@ -703,6 +704,8 @@ public:
|
||||
|
||||
already_AddRefed<Promise> GetFilesAndDirectories(ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> GetFiles(bool aRecursiveFlag, ErrorResult& aRv);
|
||||
|
||||
void ChooseDirectory(ErrorResult& aRv);
|
||||
|
||||
// XPCOM GetAlign() is OK
|
||||
@ -1253,6 +1256,8 @@ protected:
|
||||
*/
|
||||
bool IsPopupBlocked() const;
|
||||
|
||||
void ClearGetFilesHelpers();
|
||||
|
||||
nsCOMPtr<nsIControllers> mControllers;
|
||||
|
||||
/*
|
||||
@ -1286,6 +1291,9 @@ protected:
|
||||
*/
|
||||
nsTArray<OwningFileOrDirectory> mFilesOrDirectories;
|
||||
|
||||
RefPtr<GetFilesHelper> mGetFilesRecursiveHelper;
|
||||
RefPtr<GetFilesHelper> mGetFilesNonRecursiveHelper;
|
||||
|
||||
#ifndef MOZ_CHILD_PERMISSIONS
|
||||
/**
|
||||
* Hack for bug 1086684: Stash the .value when we're a file picker.
|
||||
|
@ -2802,18 +2802,6 @@ nsGenericHTMLElement::DispatchSimulatedClick(nsGenericHTMLElement* aElement,
|
||||
return EventDispatcher::Dispatch(ToSupports(aElement), aPresContext, &event);
|
||||
}
|
||||
|
||||
const nsAttrName*
|
||||
nsGenericHTMLElement::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
|
||||
{
|
||||
if (IsInHTMLDocument()) {
|
||||
nsAutoString lower;
|
||||
nsContentUtils::ASCIIToLower(aStr, lower);
|
||||
return mAttrsAndChildren.GetExistingAttrNameFromQName(lower);
|
||||
}
|
||||
|
||||
return mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGenericHTMLElement::GetEditor(nsIEditor** aEditor)
|
||||
{
|
||||
|
@ -937,8 +937,6 @@ protected:
|
||||
GetEventListenerManagerForAttr(nsIAtom* aAttrName,
|
||||
bool* aDefer) override;
|
||||
|
||||
virtual const nsAttrName* InternalGetExistingAttrNameFromQName(const nsAString& aStr) const override;
|
||||
|
||||
/**
|
||||
* Dispatch a simulated mouse click by keyboard to the given element.
|
||||
*/
|
||||
|
@ -185,6 +185,19 @@ interface nsIServiceWorkerManager : nsISupports
|
||||
in AString aIcon,
|
||||
in AString aData,
|
||||
in AString aBehavior);
|
||||
|
||||
void sendNotificationCloseEvent(in ACString aOriginSuffix,
|
||||
in ACString scope,
|
||||
in AString aID,
|
||||
in AString aTitle,
|
||||
in AString aDir,
|
||||
in AString aLang,
|
||||
in AString aBody,
|
||||
in AString aTag,
|
||||
in AString aIcon,
|
||||
in AString aData,
|
||||
in AString aBehavior);
|
||||
|
||||
[optional_argc] void sendPushEvent(in ACString aOriginAttributes,
|
||||
in ACString aScope,
|
||||
[optional] in uint32_t aDataLength,
|
||||
|
@ -5539,10 +5539,13 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
||||
nsCOMPtr<mozIDOMWindowProxy> window;
|
||||
TabParent::AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
|
||||
|
||||
const char* name = aName.IsVoid() ? nullptr : NS_ConvertUTF16toUTF8(aName).get();
|
||||
const char* features = aFeatures.IsVoid() ? nullptr : aFeatures.get();
|
||||
|
||||
*aResult = pwwatch->OpenWindow2(parent, nullptr, name, features, aCalledFromJS,
|
||||
*aResult = pwwatch->OpenWindow2(parent, nullptr,
|
||||
aName.IsVoid() ?
|
||||
nullptr :
|
||||
NS_ConvertUTF16toUTF8(aName).get(),
|
||||
features, aCalledFromJS,
|
||||
false, false, thisTabParent, nullptr,
|
||||
aFullZoom, 1, getter_AddRefs(window));
|
||||
|
||||
|
@ -229,3 +229,4 @@ PushMessageDecryptionFailure=The ServiceWorker for scope ‘%1$S’ encountered
|
||||
# LOCALIZATION NOTE: %1$S is the type of a DOM event. 'passive' is a literal parameter from the DOM spec.
|
||||
PreventDefaultFromPassiveListenerWarning=Ignoring ‘preventDefault()’ call on event of type ‘%1$S’ from a listener registered as ‘passive’.
|
||||
NavigatorBatteryWarning=navigator.battery is deprecated. Use navigator.getBattery() instead.
|
||||
FileLastModifiedDateWarning=File.lastModifiedDate is deprecated. Use File.lastModified instead.
|
||||
|
@ -315,16 +315,19 @@ struct ToCubebFormat<AUDIO_FORMAT_S16> {
|
||||
static const cubeb_sample_format value = CUBEB_SAMPLE_S16NE;
|
||||
};
|
||||
|
||||
template <typename Function, typename... Args>
|
||||
int AudioStream::InvokeCubeb(Function aFunction, Args&&... aArgs)
|
||||
{
|
||||
MonitorAutoUnlock mon(mMonitor);
|
||||
return aFunction(mCubebStream.get(), Forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
nsresult
|
||||
AudioStream::Init(uint32_t aNumChannels, uint32_t aRate,
|
||||
const dom::AudioChannel aAudioChannel)
|
||||
{
|
||||
auto startTime = TimeStamp::Now();
|
||||
mIsFirst = CubebUtils::GetFirstStream();
|
||||
|
||||
if (!CubebUtils::GetCubebContext()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
auto isFirst = CubebUtils::GetFirstStream();
|
||||
|
||||
LOG("%s channels: %d, rate: %d", __FUNCTION__, aNumChannels, aRate);
|
||||
mInRate = mOutRate = aRate;
|
||||
@ -351,49 +354,34 @@ AudioStream::Init(uint32_t aNumChannels, uint32_t aRate,
|
||||
params.format = ToCubebFormat<AUDIO_OUTPUT_FORMAT>::value;
|
||||
mAudioClock.Init();
|
||||
|
||||
return OpenCubeb(params, startTime);
|
||||
return OpenCubeb(params, startTime, isFirst);
|
||||
}
|
||||
|
||||
// This code used to live inside AudioStream::Init(), but on Mac (others?)
|
||||
// it has been known to take 300-800 (or even 8500) ms to execute(!)
|
||||
nsresult
|
||||
AudioStream::OpenCubeb(cubeb_stream_params &aParams, TimeStamp aStartTime)
|
||||
AudioStream::OpenCubeb(cubeb_stream_params& aParams,
|
||||
TimeStamp aStartTime, bool aIsFirst)
|
||||
{
|
||||
cubeb* cubebContext = CubebUtils::GetCubebContext();
|
||||
if (!cubebContext) {
|
||||
NS_WARNING("Can't get cubeb context!");
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mState = AudioStream::ERRORED;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If the latency pref is set, use it. Otherwise, if this stream is intended
|
||||
// for low latency playback, try to get the lowest latency possible.
|
||||
// Otherwise, for normal streams, use 100ms.
|
||||
uint32_t latency = CubebUtils::GetCubebLatency();
|
||||
|
||||
{
|
||||
cubeb_stream* stream;
|
||||
cubeb_stream* stream = nullptr;
|
||||
if (cubeb_stream_init(cubebContext, &stream, "AudioStream",
|
||||
nullptr, nullptr, nullptr, &aParams,
|
||||
latency, DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
MOZ_ASSERT(mState != SHUTDOWN);
|
||||
CubebUtils::GetCubebLatency(),
|
||||
DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
|
||||
mCubebStream.reset(stream);
|
||||
} else {
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mState = ERRORED;
|
||||
NS_WARNING(nsPrintfCString("AudioStream::OpenCubeb() %p failed to init cubeb", this).get());
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
mState = INITIALIZED;
|
||||
|
||||
TimeDuration timeDelta = TimeStamp::Now() - aStartTime;
|
||||
LOG("creation time %sfirst: %u ms", mIsFirst ? "" : "not ",
|
||||
LOG("creation time %sfirst: %u ms", aIsFirst ? "" : "not ",
|
||||
(uint32_t) timeDelta.ToMilliseconds());
|
||||
Telemetry::Accumulate(mIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS :
|
||||
Telemetry::Accumulate(aIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS :
|
||||
Telemetry::AUDIOSTREAM_LATER_OPEN_MS, timeDelta.ToMilliseconds());
|
||||
|
||||
return NS_OK;
|
||||
@ -413,22 +401,11 @@ void
|
||||
AudioStream::Start()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (mState == INITIALIZED) {
|
||||
mState = STARTED;
|
||||
int r;
|
||||
{
|
||||
MonitorAutoUnlock mon(mMonitor);
|
||||
r = cubeb_stream_start(mCubebStream.get());
|
||||
// DataCallback might be called before we exit this scope
|
||||
// if cubeb_stream_start() succeeds. mState must be set to STARTED
|
||||
// beforehand.
|
||||
}
|
||||
if (r != CUBEB_OK) {
|
||||
mState = ERRORED;
|
||||
}
|
||||
MOZ_ASSERT(mState == INITIALIZED);
|
||||
auto r = InvokeCubeb(cubeb_stream_start);
|
||||
mState = r == CUBEB_OK ? STARTED : ERRORED;
|
||||
LOG("started, state %s", mState == STARTED ? "STARTED" : "ERRORED");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioStream::Pause()
|
||||
@ -439,16 +416,12 @@ AudioStream::Pause()
|
||||
return;
|
||||
}
|
||||
|
||||
if (mState != STARTED && mState != RUNNING) {
|
||||
if (mState != STARTED) {
|
||||
mState = STOPPED; // which also tells async OpenCubeb not to start, just init
|
||||
return;
|
||||
}
|
||||
|
||||
int r;
|
||||
{
|
||||
MonitorAutoUnlock mon(mMonitor);
|
||||
r = cubeb_stream_stop(mCubebStream.get());
|
||||
}
|
||||
int r = InvokeCubeb(cubeb_stream_stop);
|
||||
if (mState != ERRORED && r == CUBEB_OK) {
|
||||
mState = STOPPED;
|
||||
}
|
||||
@ -462,11 +435,7 @@ AudioStream::Resume()
|
||||
return;
|
||||
}
|
||||
|
||||
int r;
|
||||
{
|
||||
MonitorAutoUnlock mon(mMonitor);
|
||||
r = cubeb_stream_start(mCubebStream.get());
|
||||
}
|
||||
int r = InvokeCubeb(cubeb_stream_start);
|
||||
if (mState != ERRORED && r == CUBEB_OK) {
|
||||
mState = STARTED;
|
||||
}
|
||||
@ -514,13 +483,9 @@ AudioStream::GetPositionInFramesUnlocked()
|
||||
}
|
||||
|
||||
uint64_t position = 0;
|
||||
{
|
||||
MonitorAutoUnlock mon(mMonitor);
|
||||
if (cubeb_stream_get_position(mCubebStream.get(), &position) != CUBEB_OK) {
|
||||
if (InvokeCubeb(cubeb_stream_get_position, &position) != CUBEB_OK) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return std::min<uint64_t>(position, INT64_MAX);
|
||||
}
|
||||
|
||||
@ -636,11 +601,6 @@ AudioStream::DataCallback(void* aBuffer, long aFrames)
|
||||
// NOTE: wasapi (others?) can call us back *after* stop()/Shutdown() (mState == SHUTDOWN)
|
||||
// Bug 996162
|
||||
|
||||
// callback tells us cubeb succeeded initializing
|
||||
if (mState == STARTED) {
|
||||
mState = RUNNING;
|
||||
}
|
||||
|
||||
if (mInRate == mOutRate) {
|
||||
GetUnprocessed(writer);
|
||||
} else {
|
||||
|
@ -313,7 +313,8 @@ protected:
|
||||
int64_t GetPositionInFramesUnlocked();
|
||||
|
||||
private:
|
||||
nsresult OpenCubeb(cubeb_stream_params &aParams, TimeStamp aStartTime);
|
||||
nsresult OpenCubeb(cubeb_stream_params& aParams,
|
||||
TimeStamp aStartTime, bool aIsFirst);
|
||||
|
||||
static long DataCallback_S(cubeb_stream*, void* aThis,
|
||||
const void* /* aInputBuffer */, void* aOutputBuffer,
|
||||
@ -340,6 +341,9 @@ private:
|
||||
void GetUnprocessed(AudioBufferWriter& aWriter);
|
||||
void GetTimeStretched(AudioBufferWriter& aWriter);
|
||||
|
||||
template <typename Function, typename... Args>
|
||||
int InvokeCubeb(Function aFunction, Args&&... aArgs);
|
||||
|
||||
// The monitor is held to protect all access to member variables.
|
||||
Monitor mMonitor;
|
||||
|
||||
@ -360,8 +364,7 @@ private:
|
||||
|
||||
enum StreamState {
|
||||
INITIALIZED, // Initialized, playback has not begun.
|
||||
STARTED, // cubeb started, but callbacks haven't started
|
||||
RUNNING, // DataCallbacks have started after STARTED, or after Resume().
|
||||
STARTED, // cubeb started.
|
||||
STOPPED, // Stopped by a call to Pause().
|
||||
DRAINED, // StateCallback has indicated that the drain is complete.
|
||||
ERRORED, // Stream disabled due to an internal error.
|
||||
@ -369,7 +372,6 @@ private:
|
||||
};
|
||||
|
||||
StreamState mState;
|
||||
bool mIsFirst;
|
||||
|
||||
DataSource& mDataSource;
|
||||
};
|
||||
|
@ -153,46 +153,47 @@ WMFVideoMFTManager::GetMediaSubtypeGUID()
|
||||
};
|
||||
}
|
||||
|
||||
struct D3D11BlacklistingCache
|
||||
struct D3DDLLBlacklistingCache
|
||||
{
|
||||
// D3D11-blacklist pref last seen.
|
||||
// Blacklist pref value last seen.
|
||||
nsCString mBlacklistPref;
|
||||
// Non-empty if a D3D11-blacklisted DLL was found.
|
||||
// Non-empty if a blacklisted DLL was found.
|
||||
nsCString mBlacklistedDLL;
|
||||
};
|
||||
StaticAutoPtr<D3D11BlacklistingCache> sD3D11BlacklistingCache;
|
||||
StaticAutoPtr<D3DDLLBlacklistingCache> sD3D11BlacklistingCache;
|
||||
StaticAutoPtr<D3DDLLBlacklistingCache> sD3D9BlacklistingCache;
|
||||
|
||||
// If a blacklisted DLL is found, return its information, otherwise "".
|
||||
static const nsACString&
|
||||
FindD3D11BlacklistedDLL()
|
||||
FindDXVABlacklistedDLL(StaticAutoPtr<D3DDLLBlacklistingCache>& aDLLBlacklistingCache,
|
||||
const char* aDLLBlacklistPrefName)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
|
||||
|
||||
if (!sD3D11BlacklistingCache) {
|
||||
if (!aDLLBlacklistingCache) {
|
||||
// First time here, create persistent data that will be reused in all
|
||||
// D3D11-blacklisting checks.
|
||||
sD3D11BlacklistingCache = new D3D11BlacklistingCache();
|
||||
ClearOnShutdown(&sD3D11BlacklistingCache);
|
||||
aDLLBlacklistingCache = new D3DDLLBlacklistingCache();
|
||||
ClearOnShutdown(&aDLLBlacklistingCache);
|
||||
}
|
||||
|
||||
nsAdoptingCString blacklist =
|
||||
Preferences::GetCString("media.wmf.disable-d3d11-for-dlls");
|
||||
nsAdoptingCString blacklist = Preferences::GetCString(aDLLBlacklistPrefName);
|
||||
if (blacklist.IsEmpty()) {
|
||||
// Empty blacklist -> No blacklisting.
|
||||
sD3D11BlacklistingCache->mBlacklistPref.SetLength(0);
|
||||
sD3D11BlacklistingCache->mBlacklistedDLL.SetLength(0);
|
||||
return sD3D11BlacklistingCache->mBlacklistedDLL;
|
||||
aDLLBlacklistingCache->mBlacklistPref.SetLength(0);
|
||||
aDLLBlacklistingCache->mBlacklistedDLL.SetLength(0);
|
||||
return aDLLBlacklistingCache->mBlacklistedDLL;
|
||||
}
|
||||
|
||||
// Detect changes in pref.
|
||||
if (sD3D11BlacklistingCache->mBlacklistPref.Equals(blacklist)) {
|
||||
if (aDLLBlacklistingCache->mBlacklistPref.Equals(blacklist)) {
|
||||
// Same blacklist -> Return same result (i.e., don't check DLLs again).
|
||||
return sD3D11BlacklistingCache->mBlacklistedDLL;
|
||||
return aDLLBlacklistingCache->mBlacklistedDLL;
|
||||
}
|
||||
// Adopt new pref now, so we don't work on it again.
|
||||
sD3D11BlacklistingCache->mBlacklistPref = blacklist;
|
||||
aDLLBlacklistingCache->mBlacklistPref = blacklist;
|
||||
|
||||
// media.wmf.disable-d3d11-for-dlls format: (whitespace is trimmed)
|
||||
// media.wmf.disable-d3d*-for-dlls format: (whitespace is trimmed)
|
||||
// "dll1.dll: 1.2.3.4[, more versions...][; more dlls...]"
|
||||
nsTArray<nsCString> dlls;
|
||||
SplitAt(";", blacklist, dlls);
|
||||
@ -200,7 +201,8 @@ FindD3D11BlacklistedDLL()
|
||||
nsTArray<nsCString> nameAndVersions;
|
||||
SplitAt(":", dll, nameAndVersions);
|
||||
if (nameAndVersions.Length() != 2) {
|
||||
NS_WARNING("Skipping incorrect 'media.wmf.disable-d3d11-for-dlls' dll:versions format");
|
||||
NS_WARNING(nsPrintfCString("Skipping incorrect '%s' dll:versions format",
|
||||
aDLLBlacklistPrefName).get());
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -235,7 +237,8 @@ FindD3D11BlacklistedDLL()
|
||||
nsTArray<nsCString> numberStrings;
|
||||
SplitAt(".", version, numberStrings);
|
||||
if (numberStrings.Length() != 4) {
|
||||
NS_WARNING("Skipping incorrect 'media.wmf.disable-d3d11-for-dlls' a.b.c.d version format");
|
||||
NS_WARNING(nsPrintfCString("Skipping incorrect '%s' a.b.c.d version format",
|
||||
aDLLBlacklistPrefName).get());
|
||||
continue;
|
||||
}
|
||||
DWORD numbers[4];
|
||||
@ -253,25 +256,38 @@ FindD3D11BlacklistedDLL()
|
||||
}
|
||||
|
||||
if (NS_FAILED(errorCode)) {
|
||||
NS_WARNING("Skipping incorrect 'media.wmf.disable-d3d11-for-dlls' a.b.c.d version format");
|
||||
NS_WARNING(nsPrintfCString("Skipping incorrect '%s' a.b.c.d version format",
|
||||
aDLLBlacklistPrefName).get());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vInfo->dwFileVersionMS == ((numbers[0] << 16) | numbers[1])
|
||||
&& vInfo->dwFileVersionLS == ((numbers[2] << 16) | numbers[3])) {
|
||||
// Blacklisted! Record bad DLL.
|
||||
sD3D11BlacklistingCache->mBlacklistedDLL.SetLength(0);
|
||||
sD3D11BlacklistingCache->mBlacklistedDLL.AppendPrintf(
|
||||
aDLLBlacklistingCache->mBlacklistedDLL.SetLength(0);
|
||||
aDLLBlacklistingCache->mBlacklistedDLL.AppendPrintf(
|
||||
"%s (%lu.%lu.%lu.%lu)",
|
||||
nameAndVersions[0].get(), numbers[0], numbers[1], numbers[2], numbers[3]);
|
||||
return sD3D11BlacklistingCache->mBlacklistedDLL;
|
||||
return aDLLBlacklistingCache->mBlacklistedDLL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No blacklisted DLL.
|
||||
sD3D11BlacklistingCache->mBlacklistedDLL.SetLength(0);
|
||||
return sD3D11BlacklistingCache->mBlacklistedDLL;
|
||||
aDLLBlacklistingCache->mBlacklistedDLL.SetLength(0);
|
||||
return aDLLBlacklistingCache->mBlacklistedDLL;
|
||||
}
|
||||
|
||||
static const nsACString&
|
||||
FindD3D11BlacklistedDLL() {
|
||||
return FindDXVABlacklistedDLL(sD3D11BlacklistingCache,
|
||||
"media.wmf.disable-d3d11-for-dlls");
|
||||
}
|
||||
|
||||
static const nsACString&
|
||||
FindD3D9BlacklistedDLL() {
|
||||
return FindDXVABlacklistedDLL(sD3D9BlacklistingCache,
|
||||
"media.wmf.disable-d3d9-for-dlls");
|
||||
}
|
||||
|
||||
class CreateDXVAManagerEvent : public Runnable {
|
||||
@ -302,9 +318,16 @@ public:
|
||||
failureReason = &secondFailureReason;
|
||||
mFailureReason.Append(NS_LITERAL_CSTRING("; "));
|
||||
}
|
||||
|
||||
const nsACString& blacklistedDLL = FindD3D9BlacklistedDLL();
|
||||
if (!blacklistedDLL.IsEmpty()) {
|
||||
mFailureReason.AppendPrintf("D3D9 blacklisted with DLL %s",
|
||||
blacklistedDLL);
|
||||
} else {
|
||||
mDXVA2Manager = DXVA2Manager::CreateD3D9DXVA(*failureReason);
|
||||
// Make sure we include the messages from both attempts (if applicable).
|
||||
mFailureReason.Append(secondFailureReason);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
nsAutoPtr<DXVA2Manager> mDXVA2Manager;
|
||||
|
@ -1590,7 +1590,6 @@ ServiceWorkerNotificationObserver::Observe(nsISupports* aSubject,
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (!strcmp("alertclickcallback", aTopic)) {
|
||||
nsAutoCString originSuffix;
|
||||
nsresult rv = mPrincipal->GetOriginSuffix(originSuffix);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -1599,9 +1598,12 @@ ServiceWorkerNotificationObserver::Observe(nsISupports* aSubject,
|
||||
|
||||
nsCOMPtr<nsIServiceWorkerManager> swm =
|
||||
mozilla::services::GetServiceWorkerManager();
|
||||
if (NS_WARN_IF(!swm)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (swm) {
|
||||
swm->SendNotificationClickEvent(originSuffix,
|
||||
if (!strcmp("alertclickcallback", aTopic)) {
|
||||
rv = swm->SendNotificationClickEvent(originSuffix,
|
||||
NS_ConvertUTF16toUTF8(mScope),
|
||||
mID,
|
||||
mTitle,
|
||||
@ -1612,7 +1614,7 @@ ServiceWorkerNotificationObserver::Observe(nsISupports* aSubject,
|
||||
mIcon,
|
||||
mData,
|
||||
mBehavior);
|
||||
}
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1629,6 +1631,20 @@ ServiceWorkerNotificationObserver::Observe(nsISupports* aSubject,
|
||||
if (notificationStorage) {
|
||||
notificationStorage->Delete(origin, mID);
|
||||
}
|
||||
|
||||
rv = swm->SendNotificationCloseEvent(originSuffix,
|
||||
NS_ConvertUTF16toUTF8(mScope),
|
||||
mID,
|
||||
mTitle,
|
||||
mDir,
|
||||
mLang,
|
||||
mBody,
|
||||
mTag,
|
||||
mIcon,
|
||||
mData,
|
||||
mBehavior);
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -99,6 +99,18 @@ interface nsIPluginHost : nsISupports
|
||||
ACString getPermissionStringForType(in AUTF8String mimeType,
|
||||
[optional] in uint32_t excludeFlags);
|
||||
|
||||
/**
|
||||
* Get the "permission string" for the plugin. This is a string that can be
|
||||
* passed to the permission manager to see whether the plugin is allowed to
|
||||
* run, for example. This will typically be based on the plugin's "nice name"
|
||||
* and its blocklist state.
|
||||
*
|
||||
* @tag The tage we're interested in
|
||||
* @excludeFlags Set of the EXCLUDE_* flags above, defaulting to EXCLUDE_NONE.
|
||||
*/
|
||||
ACString getPermissionStringForTag(in nsIPluginTag tag,
|
||||
[optional] in uint32_t excludeFlags);
|
||||
|
||||
/**
|
||||
* Get the nsIPluginTag for this MIME type. This method works with both
|
||||
* enabled and disabled/blocklisted plugins, but an enabled plugin will
|
||||
|
@ -1110,11 +1110,19 @@ nsPluginHost::GetPermissionStringForType(const nsACString &aMimeType,
|
||||
nsresult rv = GetPluginTagForType(aMimeType, aExcludeFlags,
|
||||
getter_AddRefs(tag));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(tag, NS_ERROR_FAILURE);
|
||||
return GetPermissionStringForTag(tag, aExcludeFlags, aPermissionString);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPluginHost::GetPermissionStringForTag(nsIPluginTag* aTag,
|
||||
uint32_t aExcludeFlags,
|
||||
nsACString &aPermissionString)
|
||||
{
|
||||
NS_ENSURE_TRUE(aTag, NS_ERROR_FAILURE);
|
||||
|
||||
aPermissionString.Truncate();
|
||||
uint32_t blocklistState;
|
||||
rv = tag->GetBlocklistState(&blocklistState);
|
||||
nsresult rv = aTag->GetBlocklistState(&blocklistState);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (blocklistState == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE ||
|
||||
@ -1126,7 +1134,7 @@ nsPluginHost::GetPermissionStringForType(const nsACString &aMimeType,
|
||||
}
|
||||
|
||||
nsCString niceName;
|
||||
rv = tag->GetNiceName(niceName);
|
||||
rv = aTag->GetNiceName(niceName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(!niceName.IsEmpty(), NS_ERROR_FAILURE);
|
||||
|
||||
|
@ -323,7 +323,7 @@ nsPluginTag::~nsPluginTag()
|
||||
NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349");
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsPluginTag, nsIPluginTag, nsIInternalPluginTag)
|
||||
NS_IMPL_ISUPPORTS(nsPluginTag, nsPluginTag, nsIInternalPluginTag, nsIPluginTag)
|
||||
|
||||
void nsPluginTag::InitMime(const char* const* aMimeTypes,
|
||||
const char* const* aMimeDescriptions,
|
||||
|
@ -31,6 +31,9 @@ struct FakePluginTagInit;
|
||||
{ 0xe8fdd227, 0x27da, 0x46ee, \
|
||||
{ 0xbe, 0xf3, 0x1a, 0xef, 0x5a, 0x8f, 0xc5, 0xb4 } }
|
||||
|
||||
#define NS_PLUGINTAG_IID \
|
||||
{ 0xcce2e8b9, 0x9702, 0x4d4b, \
|
||||
{ 0xbe, 0xa4, 0x7c, 0x1e, 0x13, 0x1f, 0xaf, 0x78 } }
|
||||
class nsIInternalPluginTag : public nsIPluginTag
|
||||
{
|
||||
public:
|
||||
@ -91,6 +94,8 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIInternalPluginTag, NS_IINTERNALPLUGINTAG_IID)
|
||||
class nsPluginTag final : public nsIInternalPluginTag
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PLUGINTAG_IID)
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPLUGINTAG
|
||||
|
||||
@ -193,6 +198,7 @@ private:
|
||||
|
||||
static uint32_t sNextId;
|
||||
};
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsPluginTag, NS_PLUGINTAG_IID)
|
||||
|
||||
// A class representing "fake" plugin tags; that is plugin tags not
|
||||
// corresponding to actual NPAPI plugins. In practice these are all
|
||||
|
@ -145,7 +145,7 @@ MulticastDNSDeviceProvider::Init()
|
||||
Preferences::AddStrongObservers(this, kObservedPrefs);
|
||||
|
||||
mDiscoveryEnabled = Preferences::GetBool(PREF_PRESENTATION_DISCOVERY);
|
||||
mDiscveryTimeoutMs = Preferences::GetUint(PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS);
|
||||
mDiscoveryTimeoutMs = Preferences::GetUint(PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS);
|
||||
mDiscoverable = Preferences::GetBool(PREF_PRESENTATION_DISCOVERABLE);
|
||||
mServiceName = Preferences::GetCString(PREF_PRESENTATION_DEVICE_NAME);
|
||||
|
||||
@ -534,7 +534,7 @@ MulticastDNSDeviceProvider::ForceDiscovery()
|
||||
Unused << mDiscoveryTimer->Cancel();
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED( rv = mDiscoveryTimer->Init(this,
|
||||
mDiscveryTimeoutMs,
|
||||
mDiscoveryTimeoutMs,
|
||||
nsITimer::TYPE_ONE_SHOT)))) {
|
||||
return rv;
|
||||
}
|
||||
@ -565,7 +565,7 @@ MulticastDNSDeviceProvider::OnDiscoveryStarted(const nsACString& aServiceType)
|
||||
|
||||
nsresult rv;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = mDiscoveryTimer->Init(this,
|
||||
mDiscveryTimeoutMs,
|
||||
mDiscoveryTimeoutMs,
|
||||
nsITimer::TYPE_ONE_SHOT)))) {
|
||||
return rv;
|
||||
}
|
||||
@ -924,7 +924,7 @@ MulticastDNSDeviceProvider::OnDiscoveryTimeoutChanged(uint32_t aTimeoutMs)
|
||||
LOG_I("OnDiscoveryTimeoutChanged = %d\n", aTimeoutMs);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mDiscveryTimeoutMs = aTimeoutMs;
|
||||
mDiscoveryTimeoutMs = aTimeoutMs;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ private:
|
||||
|
||||
bool mDiscoveryEnabled = false;
|
||||
bool mIsDiscovering = false;
|
||||
uint32_t mDiscveryTimeoutMs;
|
||||
uint32_t mDiscoveryTimeoutMs;
|
||||
nsCOMPtr<nsITimer> mDiscoveryTimer;
|
||||
|
||||
bool mDiscoverable = false;
|
||||
|
@ -2623,7 +2623,7 @@ Promise::ResolveInternal(JSContext* aCx,
|
||||
mResolvePending = true;
|
||||
|
||||
if (aValue.isObject()) {
|
||||
AutoDontReportUncaught silenceReporting(aCx);
|
||||
MOZ_ASSERT(JS::ContextOptionsRef(aCx).autoJSAPIOwnsErrorReporting());
|
||||
JS::Rooted<JSObject*> valueObj(aCx, &aValue.toObject());
|
||||
|
||||
// Thenables.
|
||||
|
@ -208,9 +208,15 @@ this.PushServiceAndroidGCM = {
|
||||
register: function(record) {
|
||||
console.debug("register:", record);
|
||||
let ctime = Date.now();
|
||||
let appServerKey = record.appServerKey ?
|
||||
ChromeUtils.base64URLEncode(record.appServerKey, {
|
||||
// The Push server requires padding.
|
||||
pad: true,
|
||||
}) : null;
|
||||
// Caller handles errors.
|
||||
return Messaging.sendRequestForResult({
|
||||
type: "PushServiceAndroidGCM:SubscribeChannel",
|
||||
appServerKey: appServerKey,
|
||||
}).then(data => {
|
||||
console.debug("Got data:", data);
|
||||
return PushCrypto.generateKeys()
|
||||
@ -227,6 +233,7 @@ this.PushServiceAndroidGCM = {
|
||||
p256dhPublicKey: exportedKeys[0],
|
||||
p256dhPrivateKey: exportedKeys[1],
|
||||
authenticationSecret: PushCrypto.generateAuthenticationSecret(),
|
||||
appServerKey: record.appServerKey,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -477,8 +477,10 @@ this.PushServiceWebSocket = {
|
||||
console.warn("makeWebSocket: Network is offline.");
|
||||
return null;
|
||||
}
|
||||
let socket = Cc["@mozilla.org/network/protocol;1?name=wss"]
|
||||
.createInstance(Ci.nsIWebSocketChannel);
|
||||
let contractId = uri.scheme == "ws" ?
|
||||
"@mozilla.org/network/protocol;1?name=ws" :
|
||||
"@mozilla.org/network/protocol;1?name=wss";
|
||||
let socket = Cc[contractId].createInstance(Ci.nsIWebSocketChannel);
|
||||
|
||||
socket.initLoadInfo(null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
|
@ -101,7 +101,9 @@ nsresult runTest(uint32_t aExpectedPolicyCount, // this should be 0 for policies
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> selfURIPrincipal;
|
||||
rv = secman->GetSimpleCodebasePrincipal(selfURI, getter_AddRefs(selfURIPrincipal));
|
||||
// Can't use BasePrincipal::CreateCodebasePrincipal here
|
||||
// because the symbol is not visible here
|
||||
rv = secman->GetCodebasePrincipal(selfURI, getter_AddRefs(selfURIPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// create a CSP object
|
||||
|
@ -41,7 +41,7 @@
|
||||
var secMan = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(SpecialPowers.Ci.nsIScriptSecurityManager);
|
||||
var manifestURI = SpecialPowers.Services.io.newURI(gManifestURL, null, null);
|
||||
principal = secMan.getSimpleCodebasePrincipal(manifestURI);
|
||||
principal = secMan.createCodebasePrincipal(manifestURI, {});
|
||||
csp.setRequestContext(null, principal);
|
||||
ok(true, "setRequestContext hasn't thown");
|
||||
} catch(e) {
|
||||
|
@ -87,7 +87,7 @@ function makeTest(id, expectedJSON, useReportOnlyPolicy, callback) {
|
||||
|
||||
let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager);
|
||||
principal = ssm.getSimpleCodebasePrincipal(selfuri);
|
||||
principal = ssm.createCodebasePrincipal(selfuri, {});
|
||||
csp.setRequestContext(null, principal);
|
||||
|
||||
// Load up the policy
|
||||
|
@ -35,8 +35,6 @@ interface Blob {
|
||||
enum EndingTypes { "transparent", "native" };
|
||||
|
||||
dictionary BlobPropertyBag {
|
||||
|
||||
DOMString type = "";
|
||||
EndingTypes endings = "transparent";
|
||||
|
||||
};
|
||||
|
@ -13,6 +13,9 @@
|
||||
|
||||
dictionary EventListenerOptions {
|
||||
boolean capture = false;
|
||||
/* This is a Mozilla extension only available in Chrome and XBL.
|
||||
Setting to true make the listener be added to the system group. */
|
||||
boolean mozSystemGroup = false;
|
||||
};
|
||||
|
||||
dictionary AddEventListenerOptions : EventListenerOptions {
|
||||
|
@ -2,6 +2,9 @@
|
||||
/* 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://w3c.github.io/FileAPI/#file
|
||||
*/
|
||||
|
||||
interface nsIFile;
|
||||
@ -16,32 +19,25 @@ interface nsIFile;
|
||||
|
||||
Exposed=(Window,Worker)]
|
||||
interface File : Blob {
|
||||
|
||||
readonly attribute DOMString name;
|
||||
|
||||
[GetterThrows]
|
||||
readonly attribute long long lastModified;
|
||||
|
||||
};
|
||||
|
||||
|
||||
dictionary FilePropertyBag {
|
||||
|
||||
DOMString type = "";
|
||||
long long lastModified;
|
||||
|
||||
};
|
||||
|
||||
dictionary ChromeFilePropertyBag : FilePropertyBag {
|
||||
|
||||
DOMString name = "";
|
||||
boolean temporary = false;
|
||||
};
|
||||
|
||||
// Mozilla extensions
|
||||
partial interface File {
|
||||
|
||||
[GetterThrows]
|
||||
[GetterThrows, Deprecated="FileLastModifiedDate"]
|
||||
readonly attribute Date lastModifiedDate;
|
||||
|
||||
[BinaryName="path", Func="mozilla::dom::Directory::WebkitBlinkDirectoryPickerEnabled"]
|
||||
|
@ -204,6 +204,9 @@ partial interface HTMLInputElement {
|
||||
[Throws, Pref="dom.input.dirpicker"]
|
||||
Promise<sequence<(File or Directory)>> getFilesAndDirectories();
|
||||
|
||||
[Throws, Pref="dom.input.dirpicker"]
|
||||
Promise<sequence<File>> getFiles(optional boolean recursiveFlag = false);
|
||||
|
||||
[Throws, Pref="dom.input.dirpicker"]
|
||||
void chooseDirectory();
|
||||
};
|
||||
|
@ -23,4 +23,5 @@ dictionary NotificationEventInit : ExtendableEventInit {
|
||||
|
||||
partial interface ServiceWorkerGlobalScope {
|
||||
attribute EventHandler onnotificationclick;
|
||||
attribute EventHandler onnotificationclose;
|
||||
};
|
||||
|
@ -147,9 +147,6 @@ namespace {
|
||||
|
||||
const uint32_t kNoIndex = uint32_t(-1);
|
||||
|
||||
const JS::ContextOptions kRequiredContextOptions =
|
||||
JS::ContextOptions().setDontReportUncaught(true);
|
||||
|
||||
uint32_t gMaxWorkersPerDomain = MAX_WORKERS_PER_DOMAIN;
|
||||
|
||||
// Does not hold an owning reference.
|
||||
@ -807,8 +804,6 @@ CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate, JSRuntime* aRuntime)
|
||||
|
||||
js::SetCTypesActivityCallback(aRuntime, CTypesActivityCallback);
|
||||
|
||||
JS::ContextOptionsRef(workerCx) = kRequiredContextOptions;
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
JS_SetGCZeal(workerCx, settings.gcZeal, settings.gcZealFrequency);
|
||||
#endif
|
||||
|
@ -959,8 +959,9 @@ ServiceWorkerManager::SendPushSubscriptionChangeEvent(const nsACString& aOriginA
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix,
|
||||
nsresult
|
||||
ServiceWorkerManager::SendNotificationEvent(const nsAString& aEventName,
|
||||
const nsACString& aOriginSuffix,
|
||||
const nsACString& aScope,
|
||||
const nsAString& aID,
|
||||
const nsAString& aTitle,
|
||||
@ -983,12 +984,48 @@ ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix
|
||||
}
|
||||
|
||||
ServiceWorkerPrivate* workerPrivate = info->WorkerPrivate();
|
||||
return workerPrivate->SendNotificationClickEvent(aID, aTitle, aDir,
|
||||
return workerPrivate->SendNotificationEvent(aEventName, aID, aTitle, aDir,
|
||||
aLang, aBody, aTag,
|
||||
aIcon, aData, aBehavior,
|
||||
NS_ConvertUTF8toUTF16(aScope));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix,
|
||||
const nsACString& aScope,
|
||||
const nsAString& aID,
|
||||
const nsAString& aTitle,
|
||||
const nsAString& aDir,
|
||||
const nsAString& aLang,
|
||||
const nsAString& aBody,
|
||||
const nsAString& aTag,
|
||||
const nsAString& aIcon,
|
||||
const nsAString& aData,
|
||||
const nsAString& aBehavior)
|
||||
{
|
||||
return SendNotificationEvent(NS_LITERAL_STRING(NOTIFICATION_CLICK_EVENT_NAME),
|
||||
aOriginSuffix, aScope, aID, aTitle, aDir, aLang,
|
||||
aBody, aTag, aIcon, aData, aBehavior);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::SendNotificationCloseEvent(const nsACString& aOriginSuffix,
|
||||
const nsACString& aScope,
|
||||
const nsAString& aID,
|
||||
const nsAString& aTitle,
|
||||
const nsAString& aDir,
|
||||
const nsAString& aLang,
|
||||
const nsAString& aBody,
|
||||
const nsAString& aTag,
|
||||
const nsAString& aIcon,
|
||||
const nsAString& aData,
|
||||
const nsAString& aBehavior)
|
||||
{
|
||||
return SendNotificationEvent(NS_LITERAL_STRING(NOTIFICATION_CLOSE_EVENT_NAME),
|
||||
aOriginSuffix, aScope, aID, aTitle, aDir, aLang,
|
||||
aBody, aTag, aIcon, aData, aBehavior);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::GetReadyPromise(mozIDOMWindow* aWindow,
|
||||
nsISupports** aPromise)
|
||||
|
@ -431,6 +431,20 @@ private:
|
||||
|
||||
void
|
||||
MaybeSendUnregister(nsIPrincipal* aPrincipal, const nsACString& aScope);
|
||||
|
||||
nsresult
|
||||
SendNotificationEvent(const nsAString& aEventName,
|
||||
const nsACString& aOriginSuffix,
|
||||
const nsACString& aScope,
|
||||
const nsAString& aID,
|
||||
const nsAString& aTitle,
|
||||
const nsAString& aDir,
|
||||
const nsAString& aLang,
|
||||
const nsAString& aBody,
|
||||
const nsAString& aTag,
|
||||
const nsAString& aIcon,
|
||||
const nsAString& aData,
|
||||
const nsAString& aBehavior);
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
|
@ -1079,8 +1079,9 @@ ClearWindowAllowedRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPriv
|
||||
return true;
|
||||
}
|
||||
|
||||
class SendNotificationClickEventRunnable final : public ExtendableEventWorkerRunnable
|
||||
class SendNotificationEventRunnable final : public ExtendableEventWorkerRunnable
|
||||
{
|
||||
const nsString mEventName;
|
||||
const nsString mID;
|
||||
const nsString mTitle;
|
||||
const nsString mDir;
|
||||
@ -1093,8 +1094,9 @@ class SendNotificationClickEventRunnable final : public ExtendableEventWorkerRun
|
||||
const nsString mScope;
|
||||
|
||||
public:
|
||||
SendNotificationClickEventRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
SendNotificationEventRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
KeepAliveToken* aKeepAliveToken,
|
||||
const nsAString& aEventName,
|
||||
const nsAString& aID,
|
||||
const nsAString& aTitle,
|
||||
const nsAString& aDir,
|
||||
@ -1106,6 +1108,7 @@ public:
|
||||
const nsAString& aBehavior,
|
||||
const nsAString& aScope)
|
||||
: ExtendableEventWorkerRunnable(aWorkerPrivate, aKeepAliveToken)
|
||||
, mEventName(aEventName)
|
||||
, mID(aID)
|
||||
, mTitle(aTitle)
|
||||
, mDir(aDir)
|
||||
@ -1144,8 +1147,7 @@ public:
|
||||
nei.mCancelable = false;
|
||||
|
||||
RefPtr<NotificationEvent> event =
|
||||
NotificationEvent::Constructor(target,
|
||||
NS_LITERAL_STRING("notificationclick"),
|
||||
NotificationEvent::Constructor(target, mEventName,
|
||||
nei, result);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
return false;
|
||||
@ -1170,7 +1172,8 @@ public:
|
||||
} // namespace anonymous
|
||||
|
||||
nsresult
|
||||
ServiceWorkerPrivate::SendNotificationClickEvent(const nsAString& aID,
|
||||
ServiceWorkerPrivate::SendNotificationEvent(const nsAString& aEventName,
|
||||
const nsAString& aID,
|
||||
const nsAString& aTitle,
|
||||
const nsAString& aDir,
|
||||
const nsAString& aLang,
|
||||
@ -1181,16 +1184,25 @@ ServiceWorkerPrivate::SendNotificationClickEvent(const nsAString& aID,
|
||||
const nsAString& aBehavior,
|
||||
const nsAString& aScope)
|
||||
{
|
||||
nsresult rv = SpawnWorkerIfNeeded(NotificationClickEvent, nullptr);
|
||||
WakeUpReason why;
|
||||
if (aEventName.EqualsLiteral(NOTIFICATION_CLICK_EVENT_NAME)) {
|
||||
why = NotificationClickEvent;
|
||||
gDOMDisableOpenClickDelay = Preferences::GetInt("dom.disable_open_click_delay");
|
||||
} else if (aEventName.EqualsLiteral(NOTIFICATION_CLOSE_EVENT_NAME)) {
|
||||
why = NotificationCloseEvent;
|
||||
} else {
|
||||
MOZ_ASSERT_UNREACHABLE("Invalid notification event name");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = SpawnWorkerIfNeeded(why, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
gDOMDisableOpenClickDelay = Preferences::GetInt("dom.disable_open_click_delay");
|
||||
|
||||
RefPtr<WorkerRunnable> r =
|
||||
new SendNotificationClickEventRunnable(mWorkerPrivate, mKeepAliveToken,
|
||||
aID, aTitle, aDir, aLang,
|
||||
aBody, aTag, aIcon, aData,
|
||||
aBehavior, aScope);
|
||||
new SendNotificationEventRunnable(mWorkerPrivate, mKeepAliveToken,
|
||||
aEventName, aID, aTitle, aDir, aLang,
|
||||
aBody, aTag, aIcon, aData, aBehavior,
|
||||
aScope);
|
||||
if (NS_WARN_IF(!r->Dispatch())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -11,6 +11,9 @@
|
||||
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
#define NOTIFICATION_CLICK_EVENT_NAME "notificationclick"
|
||||
#define NOTIFICATION_CLOSE_EVENT_NAME "notificationclose"
|
||||
|
||||
class nsIInterceptedChannel;
|
||||
|
||||
namespace mozilla {
|
||||
@ -93,7 +96,8 @@ public:
|
||||
SendPushSubscriptionChangeEvent();
|
||||
|
||||
nsresult
|
||||
SendNotificationClickEvent(const nsAString& aID,
|
||||
SendNotificationEvent(const nsAString& aEventName,
|
||||
const nsAString& aID,
|
||||
const nsAString& aTitle,
|
||||
const nsAString& aDir,
|
||||
const nsAString& aLang,
|
||||
@ -149,6 +153,7 @@ private:
|
||||
PushSubscriptionChangeEvent,
|
||||
MessageEvent,
|
||||
NotificationClickEvent,
|
||||
NotificationCloseEvent,
|
||||
LifeCycleEvent,
|
||||
AttachEvent
|
||||
};
|
||||
|
@ -1828,7 +1828,7 @@ TimerThreadEventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFla
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TimerThreadEventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags)
|
||||
TimerThreadEventTarget::Dispatch(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags)
|
||||
{
|
||||
// This should only happen on the timer thread.
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
@ -1850,7 +1850,7 @@ TimerThreadEventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TimerThreadEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
TimerThreadEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
@ -2402,7 +2402,7 @@ WorkerPrivateParent<Derived>::WrapObject(JSContext* aCx, JS::Handle<JSObject*> a
|
||||
|
||||
template <class Derived>
|
||||
nsresult
|
||||
WorkerPrivateParent<Derived>::DispatchPrivate(already_AddRefed<WorkerRunnable>&& aRunnable,
|
||||
WorkerPrivateParent<Derived>::DispatchPrivate(already_AddRefed<WorkerRunnable> aRunnable,
|
||||
nsIEventTarget* aSyncLoopTarget)
|
||||
{
|
||||
// May be called on any thread!
|
||||
@ -2480,7 +2480,7 @@ WorkerPrivateParent<Derived>::DisableDebugger()
|
||||
template <class Derived>
|
||||
nsresult
|
||||
WorkerPrivateParent<Derived>::DispatchControlRunnable(
|
||||
already_AddRefed<WorkerControlRunnable>&& aWorkerControlRunnable)
|
||||
already_AddRefed<WorkerControlRunnable> aWorkerControlRunnable)
|
||||
{
|
||||
// May be called on any thread!
|
||||
RefPtr<WorkerControlRunnable> runnable(aWorkerControlRunnable);
|
||||
@ -2518,7 +2518,7 @@ WorkerPrivateParent<Derived>::DispatchControlRunnable(
|
||||
template <class Derived>
|
||||
nsresult
|
||||
WorkerPrivateParent<Derived>::DispatchDebuggerRunnable(
|
||||
already_AddRefed<WorkerRunnable>&& aDebuggerRunnable)
|
||||
already_AddRefed<WorkerRunnable> aDebuggerRunnable)
|
||||
{
|
||||
// May be called on any thread!
|
||||
|
||||
@ -2548,7 +2548,7 @@ WorkerPrivateParent<Derived>::DispatchDebuggerRunnable(
|
||||
|
||||
template <class Derived>
|
||||
already_AddRefed<WorkerRunnable>
|
||||
WorkerPrivateParent<Derived>::MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable>&& aRunnable)
|
||||
WorkerPrivateParent<Derived>::MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable> aRunnable)
|
||||
{
|
||||
// May be called on any thread!
|
||||
|
||||
@ -6738,7 +6738,7 @@ EventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
|
||||
template <class Derived>
|
||||
NS_IMETHODIMP
|
||||
WorkerPrivateParent<Derived>::
|
||||
EventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags)
|
||||
EventTarget::Dispatch(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags)
|
||||
{
|
||||
// May be called on any thread!
|
||||
nsCOMPtr<nsIRunnable> event(aRunnable);
|
||||
@ -6774,7 +6774,7 @@ EventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags
|
||||
template <class Derived>
|
||||
NS_IMETHODIMP
|
||||
WorkerPrivateParent<Derived>::
|
||||
EventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
EventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ private:
|
||||
ErrorResult& aRv);
|
||||
|
||||
nsresult
|
||||
DispatchPrivate(already_AddRefed<WorkerRunnable>&& aRunnable, nsIEventTarget* aSyncLoopTarget);
|
||||
DispatchPrivate(already_AddRefed<WorkerRunnable> aRunnable, nsIEventTarget* aSyncLoopTarget);
|
||||
|
||||
public:
|
||||
virtual JSObject*
|
||||
@ -263,19 +263,19 @@ public:
|
||||
}
|
||||
|
||||
nsresult
|
||||
Dispatch(already_AddRefed<WorkerRunnable>&& aRunnable)
|
||||
Dispatch(already_AddRefed<WorkerRunnable> aRunnable)
|
||||
{
|
||||
return DispatchPrivate(Move(aRunnable), nullptr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
DispatchControlRunnable(already_AddRefed<WorkerControlRunnable>&& aWorkerControlRunnable);
|
||||
DispatchControlRunnable(already_AddRefed<WorkerControlRunnable> aWorkerControlRunnable);
|
||||
|
||||
nsresult
|
||||
DispatchDebuggerRunnable(already_AddRefed<WorkerRunnable>&& aDebuggerRunnable);
|
||||
DispatchDebuggerRunnable(already_AddRefed<WorkerRunnable> aDebuggerRunnable);
|
||||
|
||||
already_AddRefed<WorkerRunnable>
|
||||
MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable>&& aRunnable);
|
||||
MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable> aRunnable);
|
||||
|
||||
already_AddRefed<nsIEventTarget>
|
||||
GetEventTarget();
|
||||
@ -1538,10 +1538,10 @@ protected:
|
||||
|
||||
|
||||
NS_IMETHOD
|
||||
Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags) override;
|
||||
Dispatch(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags) override;
|
||||
|
||||
NS_IMETHOD
|
||||
DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t) override;
|
||||
DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) override;
|
||||
|
||||
NS_IMETHOD
|
||||
IsOnCurrentThread(bool* aIsOnCurrentThread) override;
|
||||
|
@ -243,6 +243,7 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerGlobalScope,
|
||||
WorkerGlobalScope)
|
||||
IMPL_EVENT_HANDLER(notificationclick)
|
||||
IMPL_EVENT_HANDLER(notificationclose)
|
||||
|
||||
ServiceWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, const nsACString& aScope);
|
||||
|
||||
|
@ -145,7 +145,7 @@ WorkerThread::SetWorker(const WorkerThreadFriendKey& /* aKey */,
|
||||
|
||||
nsresult
|
||||
WorkerThread::DispatchPrimaryRunnable(const WorkerThreadFriendKey& /* aKey */,
|
||||
already_AddRefed<nsIRunnable>&& aRunnable)
|
||||
already_AddRefed<nsIRunnable> aRunnable)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable(aRunnable);
|
||||
|
||||
@ -170,7 +170,7 @@ WorkerThread::DispatchPrimaryRunnable(const WorkerThreadFriendKey& /* aKey */,
|
||||
|
||||
nsresult
|
||||
WorkerThread::DispatchAnyThread(const WorkerThreadFriendKey& /* aKey */,
|
||||
already_AddRefed<WorkerRunnable>&& aWorkerRunnable)
|
||||
already_AddRefed<WorkerRunnable> aWorkerRunnable)
|
||||
{
|
||||
// May be called on any thread!
|
||||
|
||||
@ -213,7 +213,7 @@ WorkerThread::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerThread::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags)
|
||||
WorkerThread::Dispatch(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags)
|
||||
{
|
||||
// May be called on any thread!
|
||||
nsCOMPtr<nsIRunnable> runnable(aRunnable); // in case we exit early
|
||||
@ -299,7 +299,7 @@ WorkerThread::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlag
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerThread::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
WorkerThread::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -68,11 +68,11 @@ public:
|
||||
|
||||
nsresult
|
||||
DispatchPrimaryRunnable(const WorkerThreadFriendKey& aKey,
|
||||
already_AddRefed<nsIRunnable>&& aRunnable);
|
||||
already_AddRefed<nsIRunnable> aRunnable);
|
||||
|
||||
nsresult
|
||||
DispatchAnyThread(const WorkerThreadFriendKey& aKey,
|
||||
already_AddRefed<WorkerRunnable>&& aWorkerRunnable);
|
||||
already_AddRefed<WorkerRunnable> aWorkerRunnable);
|
||||
|
||||
uint32_t
|
||||
RecursionDepth(const WorkerThreadFriendKey& aKey) const;
|
||||
@ -86,13 +86,13 @@ private:
|
||||
// This should only be called by consumers that have an
|
||||
// nsIEventTarget/nsIThread pointer.
|
||||
NS_IMETHOD
|
||||
Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags) override;
|
||||
Dispatch(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags) override;
|
||||
|
||||
NS_IMETHOD
|
||||
DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) override;
|
||||
|
||||
NS_IMETHOD
|
||||
DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t) override;
|
||||
DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) override;
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
|
@ -133,6 +133,8 @@ support-files =
|
||||
notificationclick.js
|
||||
notificationclick_focus.html
|
||||
notificationclick_focus.js
|
||||
notificationclose.html
|
||||
notificationclose.js
|
||||
worker_updatefoundevent.js
|
||||
worker_updatefoundevent2.js
|
||||
updatefoundevent.html
|
||||
@ -249,6 +251,7 @@ tags = mcb
|
||||
[test_notificationclick.html]
|
||||
[test_notificationclick_focus.html]
|
||||
[test_notificationclick-otherwindow.html]
|
||||
[test_notificationclose.html]
|
||||
[test_opaque_intercept.html]
|
||||
[test_openWindow.html]
|
||||
[test_origin_after_redirect.html]
|
||||
|
37
dom/workers/test/serviceworkers/notificationclose.html
Normal file
37
dom/workers/test/serviceworkers/notificationclose.html
Normal file
@ -0,0 +1,37 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1265841 - controlled page</title>
|
||||
<script class="testbody" type="text/javascript">
|
||||
var testWindow = parent;
|
||||
if (opener) {
|
||||
testWindow = opener;
|
||||
}
|
||||
|
||||
navigator.serviceWorker.ready.then(function(swr) {
|
||||
return swr.showNotification(
|
||||
"Hi there. The ServiceWorker should receive a close event for this.",
|
||||
{ data: { complex: ["jsval", 5] }}).then(function() {
|
||||
return swr;
|
||||
});
|
||||
}).then(function(swr) {
|
||||
return swr.getNotifications();
|
||||
}).then(function(notifications) {
|
||||
notifications.forEach(function(notification) {
|
||||
notification.close();
|
||||
});
|
||||
});
|
||||
|
||||
navigator.serviceWorker.onmessage = function(msg) {
|
||||
testWindow.callback(msg.data.result);
|
||||
};
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
19
dom/workers/test/serviceworkers/notificationclose.js
Normal file
19
dom/workers/test/serviceworkers/notificationclose.js
Normal file
@ -0,0 +1,19 @@
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
//
|
||||
onnotificationclose = function(e) {
|
||||
self.clients.matchAll().then(function(clients) {
|
||||
if (clients.length === 0) {
|
||||
dump("********************* CLIENTS LIST EMPTY! Test will timeout! ***********************\n");
|
||||
return;
|
||||
}
|
||||
|
||||
clients.forEach(function(client) {
|
||||
client.postMessage({ result: e.notification.data &&
|
||||
e.notification.data['complex'] &&
|
||||
e.notification.data['complex'][0] == "jsval" &&
|
||||
e.notification.data['complex'][1] == 5 });
|
||||
|
||||
});
|
||||
});
|
||||
}
|
62
dom/workers/test/serviceworkers/test_notificationclose.html
Normal file
62
dom/workers/test/serviceworkers/test_notificationclose.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1265841
|
||||
-->
|
||||
<head>
|
||||
<title>Bug 1265841 - Test ServiceWorkerGlobalScope.notificationclose event.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1265841">Bug 1265841</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
<script type="text/javascript">
|
||||
SimpleTest.requestFlakyTimeout("Mock alert service dispatches show, click, and close events.");
|
||||
|
||||
function testFrame(src) {
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.src = src;
|
||||
window.callback = function(result) {
|
||||
window.callback = null;
|
||||
document.body.removeChild(iframe);
|
||||
iframe = null;
|
||||
ok(result, "Got notificationclose event with correct data.");
|
||||
MockServices.unregister();
|
||||
registration.unregister().then(function() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
};
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
var registration;
|
||||
|
||||
function runTest() {
|
||||
MockServices.register();
|
||||
testFrame('notificationclose.html');
|
||||
navigator.serviceWorker.register("notificationclose.js", { scope: "notificationclose.html" }).then(function(reg) {
|
||||
registration = reg;
|
||||
}, function(e) {
|
||||
ok(false, "registration should have passed!");
|
||||
});
|
||||
};
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.webnotifications.workers.enabled", true],
|
||||
["dom.webnotifications.serviceworker.enabled", true],
|
||||
["notification.prompt.testing", true],
|
||||
]}, runTest);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -417,11 +417,10 @@ txCompileObserver::loadURI(const nsAString& aUri,
|
||||
rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> referrerPrincipal;
|
||||
rv = nsContentUtils::GetSecurityManager()->
|
||||
GetSimpleCodebasePrincipal(referrerUri,
|
||||
getter_AddRefs(referrerPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
PrincipalOriginAttributes attrs;
|
||||
nsCOMPtr<nsIPrincipal> referrerPrincipal =
|
||||
BasePrincipal::CreateCodebasePrincipal(referrerUri, attrs);
|
||||
NS_ENSURE_TRUE(referrerPrincipal, NS_ERROR_FAILURE);
|
||||
|
||||
return startLoad(uri, aCompiler, referrerPrincipal, aReferrerPolicy);
|
||||
}
|
||||
@ -622,11 +621,9 @@ txSyncCompileObserver::loadURI(const nsAString& aUri,
|
||||
rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> referrerPrincipal;
|
||||
rv = nsContentUtils::GetSecurityManager()->
|
||||
GetSimpleCodebasePrincipal(referrerUri,
|
||||
getter_AddRefs(referrerPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIPrincipal> referrerPrincipal =
|
||||
BasePrincipal::CreateCodebasePrincipal(referrerUri, PrincipalOriginAttributes());
|
||||
NS_ENSURE_TRUE(referrerPrincipal, NS_ERROR_FAILURE);
|
||||
|
||||
// This is probably called by js, a loadGroup for the channel doesn't
|
||||
// make sense.
|
||||
|
@ -259,7 +259,7 @@ FlattenBezierCurveSegment(const BezierControlPoints &aControlPoints,
|
||||
|
||||
double t = 0;
|
||||
while (t < 1.0) {
|
||||
PointD cp21 = currentCP.mCP2 - currentCP.mCP3;
|
||||
PointD cp21 = currentCP.mCP2 - currentCP.mCP1;
|
||||
PointD cp31 = currentCP.mCP3 - currentCP.mCP1;
|
||||
|
||||
/* To remove divisions and check for divide-by-zero, this is optimized from:
|
||||
|
@ -69,6 +69,9 @@ const std::string &Framebuffer::Data::getLabel()
|
||||
|
||||
const FramebufferAttachment *Framebuffer::Data::getReadAttachment() const
|
||||
{
|
||||
if (mReadBufferState == GL_NONE)
|
||||
return nullptr;
|
||||
|
||||
ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
|
||||
size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
|
||||
ASSERT(readIndex < mColorAttachments.size());
|
||||
|
@ -365,6 +365,12 @@ typedef GenericFlingAnimation FlingAnimation;
|
||||
* \li\b apz.zoom_animation_duration_ms
|
||||
* This controls how long the zoom-to-rect animation takes.\n
|
||||
* Units: ms
|
||||
*
|
||||
* \li\b apz.scale_repaint_delay_ms
|
||||
* How long to delay between repaint requests during a scale.
|
||||
* A negative number prevents repaint requests during a scale.\n
|
||||
* Units: ms
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -703,6 +709,7 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
|
||||
mState(NOTHING),
|
||||
mNotificationBlockers(0),
|
||||
mInputQueue(aInputQueue),
|
||||
mPinchPaintTimerSet(false),
|
||||
mAPZCId(sAsyncPanZoomControllerCount++),
|
||||
mSharedLock(nullptr),
|
||||
mAsyncTransformAppliedToContent(false),
|
||||
@ -1281,6 +1288,7 @@ nsEventStatus AsyncPanZoomController::OnTouchCancel(const MultiTouchInput& aEven
|
||||
nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
|
||||
APZC_LOG("%p got a scale-begin in state %d\n", this, mState);
|
||||
|
||||
mPinchPaintTimerSet = false;
|
||||
// Note that there may not be a touch block at this point, if we received the
|
||||
// PinchGestureEvent directly from widget code without any touch events.
|
||||
if (HasReadyTouchBlock() && !CurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
|
||||
@ -1375,8 +1383,21 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||
}
|
||||
|
||||
ScheduleComposite();
|
||||
// We don't want to redraw on every scale, so don't use
|
||||
// RequestContentRepaint()
|
||||
|
||||
// We don't want to redraw on every scale, so throttle it.
|
||||
if (!mPinchPaintTimerSet) {
|
||||
const int delay = gfxPrefs::APZScaleRepaintDelay();
|
||||
if (delay >= 0) {
|
||||
if (RefPtr<GeckoContentController> controller = GetGeckoContentController()) {
|
||||
mPinchPaintTimerSet = true;
|
||||
controller->PostDelayedTask(
|
||||
NewRunnableMethod(this,
|
||||
&AsyncPanZoomController::DoDelayedRequestContentRepaint),
|
||||
delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
}
|
||||
|
||||
@ -1389,6 +1410,8 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||
nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent) {
|
||||
APZC_LOG("%p got a scale-end in state %d\n", this, mState);
|
||||
|
||||
mPinchPaintTimerSet = false;
|
||||
|
||||
if (HasReadyTouchBlock() && !CurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
@ -1613,6 +1636,15 @@ AsyncPanZoomController::AllowScrollHandoffInCurrentBlock() const
|
||||
return result;
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::DoDelayedRequestContentRepaint()
|
||||
{
|
||||
if (!IsDestroyed() && mPinchPaintTimerSet) {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
RequestContentRepaint();
|
||||
}
|
||||
mPinchPaintTimerSet = false;
|
||||
}
|
||||
|
||||
static ScrollInputMethod
|
||||
ScrollInputMethodForWheelDeltaType(ScrollWheelInput::ScrollDeltaType aDeltaType)
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user