mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Merge m-i to m-c, a=merge
MozReview-Commit-ID: EDVoIcyWOhi --HG-- rename : storage/test/test_AsXXX_helpers.cpp => storage/test/gtest/test_AsXXX_helpers.cpp rename : storage/test/test_binding_params.cpp => storage/test/gtest/test_binding_params.cpp rename : storage/test/test_mutex.cpp => storage/test/gtest/test_mutex.cpp
This commit is contained in:
commit
feef954874
13
.clang-tidy
Normal file
13
.clang-tidy
Normal file
@ -0,0 +1,13 @@
|
||||
# Checks run by clang-tidy over Mozilla code.
|
||||
# NOTE: please request review from ehsan when changing this file.
|
||||
|
||||
# The following checks are currently enabled:
|
||||
# * misc-use-override
|
||||
# Adds missing override keywords, and removes override keywords if the final
|
||||
# keyword is present as well.
|
||||
Checks: '-*,misc-use-override'
|
||||
CheckOptions:
|
||||
# Don't touch the virtual keyword!
|
||||
- key: misc-use-override.KeepVirtual
|
||||
value: '1'
|
||||
|
@ -85,6 +85,20 @@ DocManager::FindAccessibleInCache(nsINode* aNode) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
DocManager::RemoveFromXPCDocumentCache(DocAccessible* aDocument)
|
||||
{
|
||||
xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
|
||||
if (xpcDoc) {
|
||||
xpcDoc->Shutdown();
|
||||
mXPCDocumentCache.Remove(aDocument);
|
||||
}
|
||||
|
||||
if (!HasXPCDocuments()) {
|
||||
MaybeShutdownAccService(nsAccessibilityService::eXPCOM);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
|
||||
nsIDocument* aDOMDocument)
|
||||
@ -99,23 +113,28 @@ DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
|
||||
return;
|
||||
}
|
||||
|
||||
xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
|
||||
if (xpcDoc) {
|
||||
xpcDoc->Shutdown();
|
||||
mXPCDocumentCache.Remove(aDocument);
|
||||
}
|
||||
|
||||
RemoveFromXPCDocumentCache(aDocument);
|
||||
mDocAccessibleCache.Remove(aDOMDocument);
|
||||
}
|
||||
|
||||
void
|
||||
DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
|
||||
DocManager::RemoveFromRemoteXPCDocumentCache(DocAccessibleParent* aDoc)
|
||||
{
|
||||
xpcAccessibleDocument* doc = GetCachedXPCDocument(aDoc);
|
||||
if (doc) {
|
||||
doc->Shutdown();
|
||||
sRemoteXPCDocumentCache->Remove(aDoc);
|
||||
}
|
||||
|
||||
if (sRemoteXPCDocumentCache && sRemoteXPCDocumentCache->Count() == 0) {
|
||||
MaybeShutdownAccService(nsAccessibilityService::eXPCOM);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
|
||||
{
|
||||
RemoveFromRemoteXPCDocumentCache(aDoc);
|
||||
}
|
||||
|
||||
xpcAccessibleDocument*
|
||||
|
@ -66,6 +66,8 @@ public:
|
||||
void NotifyOfDocumentShutdown(DocAccessible* aDocument,
|
||||
nsIDocument* aDOMDocument);
|
||||
|
||||
void RemoveFromXPCDocumentCache(DocAccessible* aDocument);
|
||||
|
||||
/**
|
||||
* Return XPCOM accessible document.
|
||||
*/
|
||||
@ -95,6 +97,8 @@ public:
|
||||
*/
|
||||
static void NotifyOfRemoteDocShutdown(DocAccessibleParent* adoc);
|
||||
|
||||
static void RemoveFromRemoteXPCDocumentCache(DocAccessibleParent* aDoc);
|
||||
|
||||
/**
|
||||
* Get a XPC document for a remote document.
|
||||
*/
|
||||
@ -123,6 +127,12 @@ protected:
|
||||
*/
|
||||
void Shutdown();
|
||||
|
||||
bool HasXPCDocuments()
|
||||
{
|
||||
return mXPCDocumentCache.Count() > 0 ||
|
||||
(sRemoteXPCDocumentCache && sRemoteXPCDocumentCache->Count() > 0);
|
||||
}
|
||||
|
||||
private:
|
||||
DocManager(const DocManager&);
|
||||
DocManager& operator =(const DocManager&);
|
||||
|
@ -1815,7 +1815,8 @@ MaybeShutdownAccService(uint32_t aFormerConsumer)
|
||||
}
|
||||
|
||||
if (nsCoreUtils::AccEventObserversExist() ||
|
||||
xpcAccessibilityService::IsInUse()) {
|
||||
xpcAccessibilityService::IsInUse() ||
|
||||
accService->HasXPCDocuments()) {
|
||||
// Still used by XPCOM
|
||||
nsAccessibilityService::gConsumers =
|
||||
(nsAccessibilityService::gConsumers & ~aFormerConsumer) |
|
||||
|
@ -4,9 +4,21 @@ support-files =
|
||||
head.js
|
||||
shared-head.js
|
||||
|
||||
[browser_shutdown_acc_reference.js]
|
||||
[browser_shutdown_doc_acc_reference.js]
|
||||
[browser_shutdown_multi_acc_reference_obj.js]
|
||||
[browser_shutdown_multi_acc_reference_doc.js]
|
||||
[browser_shutdown_multi_reference.js]
|
||||
[browser_shutdown_parent_own_reference.js]
|
||||
skip-if = !e10s # e10s specific test for a11y start/shutdown between parent and content.
|
||||
[browser_shutdown_proxy_acc_reference.js]
|
||||
skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
|
||||
[browser_shutdown_proxy_doc_acc_reference.js]
|
||||
skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
|
||||
[browser_shutdown_multi_proxy_acc_reference_doc.js]
|
||||
skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
|
||||
[browser_shutdown_multi_proxy_acc_reference_obj.js]
|
||||
skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
|
||||
[browser_shutdown_remote_no_reference.js]
|
||||
skip-if = !e10s # e10s specific test for a11y start/shutdown between parent and content.
|
||||
[browser_shutdown_remote_only.js]
|
||||
|
55
accessible/tests/browser/browser_shutdown_acc_reference.js
Normal file
55
accessible/tests/browser/browser_shutdown_acc_reference.js
Normal file
@ -0,0 +1,55 @@
|
||||
/* 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';
|
||||
|
||||
add_task(function* () {
|
||||
// Create a11y service.
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
|
||||
yield a11yInit;
|
||||
ok(accService, 'Service initialized');
|
||||
|
||||
// Accessible object reference will live longer than the scope of this
|
||||
// function.
|
||||
let acc = yield new Promise(resolve => {
|
||||
let intervalId = setInterval(() => {
|
||||
let tabAcc = accService.getAccessibleFor(gBrowser.mCurrentTab);
|
||||
if (tabAcc) {
|
||||
clearInterval(intervalId);
|
||||
resolve(tabAcc);
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
ok(acc, 'Accessible object is created');
|
||||
|
||||
let canShutdown = false;
|
||||
// This promise will resolve only if canShutdown flag is set to true. If
|
||||
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
|
||||
// down, the promise will reject.
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject('Accessible service was shut down incorrectly')));
|
||||
|
||||
accService = null;
|
||||
ok(!accService, 'Service is removed');
|
||||
|
||||
// Force garbage collection that should not trigger shutdown because there is
|
||||
// a reference to an accessible object.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a reference to an accessible object.
|
||||
acc = null;
|
||||
ok(!acc, 'Accessible object is removed');
|
||||
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
yield a11yShutdown;
|
||||
});
|
@ -0,0 +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';
|
||||
|
||||
add_task(function* () {
|
||||
// Create a11y service.
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
|
||||
yield a11yInit;
|
||||
ok(accService, 'Service initialized');
|
||||
|
||||
// Accessible document reference will live longer than the scope of this
|
||||
// function.
|
||||
let docAcc = accService.getAccessibleFor(document);
|
||||
ok(docAcc, 'Accessible document is created');
|
||||
|
||||
let canShutdown = false;
|
||||
// This promise will resolve only if canShutdown flag is set to true. If
|
||||
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
|
||||
// down, the promise will reject.
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject('Accessible service was shut down incorrectly')));
|
||||
|
||||
accService = null;
|
||||
ok(!accService, 'Service is removed');
|
||||
|
||||
// Force garbage collection that should not trigger shutdown because there is
|
||||
// a reference to an accessible document.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a reference to an accessible document.
|
||||
docAcc = null;
|
||||
ok(!docAcc, 'Accessible document is removed');
|
||||
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
yield a11yShutdown;
|
||||
});
|
@ -0,0 +1,67 @@
|
||||
/* 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';
|
||||
|
||||
add_task(function* () {
|
||||
// Create a11y service.
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
|
||||
yield a11yInit;
|
||||
ok(accService, 'Service initialized');
|
||||
|
||||
let docAcc = accService.getAccessibleFor(document);
|
||||
ok(docAcc, 'Accessible document is created');
|
||||
|
||||
// Accessible object reference will live longer than the scope of this
|
||||
// function.
|
||||
let acc = yield new Promise(resolve => {
|
||||
let intervalId = setInterval(() => {
|
||||
let tabAcc = accService.getAccessibleFor(gBrowser.mCurrentTab);
|
||||
if (tabAcc) {
|
||||
clearInterval(intervalId);
|
||||
resolve(tabAcc);
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
ok(acc, 'Accessible object is created');
|
||||
|
||||
let canShutdown = false;
|
||||
// This promise will resolve only if canShutdown flag is set to true. If
|
||||
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
|
||||
// down, the promise will reject.
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject('Accessible service was shut down incorrectly')));
|
||||
|
||||
accService = null;
|
||||
ok(!accService, 'Service is removed');
|
||||
|
||||
// Force garbage collection that should not trigger shutdown because there are
|
||||
// references to accessible objects.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Remove a reference to an accessible object.
|
||||
acc = null;
|
||||
ok(!acc, 'Accessible object is removed');
|
||||
// Force garbage collection that should not trigger shutdown because there is
|
||||
// a reference to an accessible document.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a reference to an accessible document.
|
||||
docAcc = null;
|
||||
ok(!docAcc, 'Accessible document is removed');
|
||||
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
yield a11yShutdown;
|
||||
});
|
@ -0,0 +1,67 @@
|
||||
/* 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';
|
||||
|
||||
add_task(function* () {
|
||||
// Create a11y service.
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
|
||||
yield a11yInit;
|
||||
ok(accService, 'Service initialized');
|
||||
|
||||
let docAcc = accService.getAccessibleFor(document);
|
||||
ok(docAcc, 'Accessible document is created');
|
||||
|
||||
// Accessible object reference will live longer than the scope of this
|
||||
// function.
|
||||
let acc = yield new Promise(resolve => {
|
||||
let intervalId = setInterval(() => {
|
||||
let tabAcc = accService.getAccessibleFor(gBrowser.mCurrentTab);
|
||||
if (tabAcc) {
|
||||
clearInterval(intervalId);
|
||||
resolve(tabAcc);
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
ok(acc, 'Accessible object is created');
|
||||
|
||||
let canShutdown = false;
|
||||
// This promise will resolve only if canShutdown flag is set to true. If
|
||||
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
|
||||
// down, the promise will reject.
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject('Accessible service was shut down incorrectly')));
|
||||
|
||||
accService = null;
|
||||
ok(!accService, 'Service is removed');
|
||||
|
||||
// Force garbage collection that should not trigger shutdown because there are
|
||||
// references to accessible objects.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Remove a reference to an accessible document.
|
||||
docAcc = null;
|
||||
ok(!docAcc, 'Accessible document is removed');
|
||||
// Force garbage collection that should not trigger shutdown because there is
|
||||
// a reference to an accessible object.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a reference to an accessible object.
|
||||
acc = null;
|
||||
ok(!acc, 'Accessible object is removed');
|
||||
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
yield a11yShutdown;
|
||||
});
|
@ -0,0 +1,76 @@
|
||||
/* 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';
|
||||
|
||||
add_task(function* () {
|
||||
// Making sure that the e10s is enabled on Windows for testing.
|
||||
yield setE10sPrefs();
|
||||
|
||||
let docLoaded = waitForEvent(
|
||||
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, 'body');
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
ok(accService, 'Service initialized');
|
||||
yield a11yInit;
|
||||
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body id="body"><div id="div"></div></body>
|
||||
</html>`
|
||||
}, function*(browser) {
|
||||
let docLoadedEvent = yield docLoaded;
|
||||
let docAcc = docLoadedEvent.accessibleDocument;
|
||||
ok(docAcc, 'Accessible document proxy is created');
|
||||
// Remove unnecessary dangling references
|
||||
docLoaded = null;
|
||||
docLoadedEvent = null;
|
||||
forceGC();
|
||||
|
||||
let acc = docAcc.getChildAt(0);
|
||||
ok(acc, 'Accessible proxy is created');
|
||||
|
||||
let canShutdown = false;
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject('Accessible service was shut down incorrectly')));
|
||||
|
||||
accService = null;
|
||||
ok(!accService, 'Service is removed');
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Remove a reference to an accessible proxy.
|
||||
acc = null;
|
||||
ok(!acc, 'Accessible proxy is removed');
|
||||
// Force garbage collection that should not trigger shutdown because there is
|
||||
// a reference to an accessible document proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a last reference to an accessible document proxy.
|
||||
docAcc = null;
|
||||
ok(!docAcc, 'Accessible document proxy is removed');
|
||||
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
yield a11yShutdown;
|
||||
});
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
yield unsetE10sPrefs();
|
||||
});
|
@ -0,0 +1,76 @@
|
||||
/* 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';
|
||||
|
||||
add_task(function* () {
|
||||
// Making sure that the e10s is enabled on Windows for testing.
|
||||
yield setE10sPrefs();
|
||||
|
||||
let docLoaded = waitForEvent(
|
||||
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, 'body');
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
ok(accService, 'Service initialized');
|
||||
yield a11yInit;
|
||||
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body id="body"><div id="div"></div></body>
|
||||
</html>`
|
||||
}, function*(browser) {
|
||||
let docLoadedEvent = yield docLoaded;
|
||||
let docAcc = docLoadedEvent.accessibleDocument;
|
||||
ok(docAcc, 'Accessible document proxy is created');
|
||||
// Remove unnecessary dangling references
|
||||
docLoaded = null;
|
||||
docLoadedEvent = null;
|
||||
forceGC();
|
||||
|
||||
let acc = docAcc.getChildAt(0);
|
||||
ok(acc, 'Accessible proxy is created');
|
||||
|
||||
let canShutdown = false;
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject('Accessible service was shut down incorrectly')));
|
||||
|
||||
accService = null;
|
||||
ok(!accService, 'Service is removed');
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Remove a reference to an accessible document proxy.
|
||||
docAcc = null;
|
||||
ok(!docAcc, 'Accessible document proxy is removed');
|
||||
// Force garbage collection that should not trigger shutdown because there is
|
||||
// a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a last reference to an accessible proxy.
|
||||
acc = null;
|
||||
ok(!acc, 'Accessible proxy is removed');
|
||||
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
yield a11yShutdown;
|
||||
});
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
yield unsetE10sPrefs();
|
||||
});
|
@ -21,7 +21,7 @@ add_task(function* () {
|
||||
|
||||
info('Removing all service references');
|
||||
let canShutdown = false;
|
||||
// This promise will resolve only if canShutdonw flag is set to true. If
|
||||
// This promise will resolve only if canShutdown flag is set to true. If
|
||||
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
|
||||
// down, the promise will reject.
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
|
@ -0,0 +1,64 @@
|
||||
/* 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';
|
||||
|
||||
add_task(function* () {
|
||||
// Making sure that the e10s is enabled on Windows for testing.
|
||||
yield setE10sPrefs();
|
||||
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
ok(accService, 'Service initialized');
|
||||
yield a11yInit;
|
||||
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body><div id="div" style="visibility: hidden;"></div></body>
|
||||
</html>`
|
||||
}, function*(browser) {
|
||||
let onShow = waitForEvent(Ci.nsIAccessibleEvent.EVENT_SHOW, 'div');
|
||||
yield invokeSetStyle(browser, 'div', 'visibility', 'visible');
|
||||
let showEvent = yield onShow;
|
||||
let divAcc = showEvent.accessible;
|
||||
ok(divAcc, 'Accessible proxy is created');
|
||||
// Remove unnecessary dangling references
|
||||
onShow = null;
|
||||
showEvent = null;
|
||||
forceGC();
|
||||
|
||||
let canShutdown = false;
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject('Accessible service was shut down incorrectly')));
|
||||
|
||||
accService = null;
|
||||
ok(!accService, 'Service is removed');
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a last reference to an accessible proxy.
|
||||
divAcc = null;
|
||||
ok(!divAcc, 'Accessible proxy is removed');
|
||||
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
yield a11yShutdown;
|
||||
});
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
yield unsetE10sPrefs();
|
||||
});
|
@ -0,0 +1,64 @@
|
||||
/* 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';
|
||||
|
||||
add_task(function* () {
|
||||
// Making sure that the e10s is enabled on Windows for testing.
|
||||
yield setE10sPrefs();
|
||||
|
||||
let docLoaded = waitForEvent(
|
||||
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, 'body');
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
ok(accService, 'Service initialized');
|
||||
yield a11yInit;
|
||||
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body id="body"></body>
|
||||
</html>`
|
||||
}, function*(browser) {
|
||||
let docLoadedEvent = yield docLoaded;
|
||||
let docAcc = docLoadedEvent.accessibleDocument;
|
||||
ok(docAcc, 'Accessible document proxy is created');
|
||||
// Remove unnecessary dangling references
|
||||
docLoaded = null;
|
||||
docLoadedEvent = null;
|
||||
forceGC();
|
||||
|
||||
let canShutdown = false;
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject('Accessible service was shut down incorrectly')));
|
||||
|
||||
accService = null;
|
||||
ok(!accService, 'Service is removed');
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
yield new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a last reference to an accessible document proxy.
|
||||
docAcc = null;
|
||||
ok(!docAcc, 'Accessible document proxy is removed');
|
||||
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
yield a11yShutdown;
|
||||
});
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
yield unsetE10sPrefs();
|
||||
});
|
@ -4,8 +4,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* exported initPromise, shutdownPromise,
|
||||
setE10sPrefs, unsetE10sPrefs, forceGC */
|
||||
/* exported initPromise, shutdownPromise, waitForEvent, setE10sPrefs,
|
||||
unsetE10sPrefs, forceGC */
|
||||
|
||||
/**
|
||||
* Set e10s related preferences in the test environment.
|
||||
@ -107,10 +107,34 @@ function shutdownPromise(contentBrowser) {
|
||||
() => ok(false, 'Service initialized incorrectly'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Simpler verions of waitForEvent defined in
|
||||
* accessible/tests/browser/e10s/events.js
|
||||
*/
|
||||
function waitForEvent(eventType, expectedId) {
|
||||
return new Promise(resolve => {
|
||||
let eventObserver = {
|
||||
observe(subject) {
|
||||
let event = subject.QueryInterface(Ci.nsIAccessibleEvent);
|
||||
if (event.eventType === eventType &&
|
||||
event.accessible.id === expectedId) {
|
||||
Services.obs.removeObserver(this, 'accessible-event');
|
||||
resolve(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
Services.obs.addObserver(eventObserver, 'accessible-event', false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Force garbage collection.
|
||||
*/
|
||||
function forceGC() {
|
||||
Cu.forceCC();
|
||||
Cu.forceGC();
|
||||
SpecialPowers.gc();
|
||||
SpecialPowers.forceGC();
|
||||
SpecialPowers.forceCC();
|
||||
SpecialPowers.gc();
|
||||
SpecialPowers.forceGC();
|
||||
SpecialPowers.forceCC();
|
||||
}
|
||||
|
@ -33,7 +33,10 @@ public:
|
||||
NS_IMETHOD GetPlatformVersion(nsAString& aVersion) final override;
|
||||
|
||||
protected:
|
||||
virtual ~xpcAccessibleApplication() {}
|
||||
virtual ~xpcAccessibleApplication()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
private:
|
||||
ApplicationAccessible* Intl() { return mIntl.AsAccessible()->AsApplication(); }
|
||||
|
@ -17,26 +17,28 @@ using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsISupports and cycle collection
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(xpcAccessibleDocument)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(xpcAccessibleDocument,
|
||||
xpcAccessibleGeneric)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCache)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(xpcAccessibleDocument,
|
||||
xpcAccessibleGeneric)
|
||||
tmp->mCache.Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(xpcAccessibleDocument)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAccessibleDocument)
|
||||
NS_INTERFACE_MAP_END_INHERITING(xpcAccessibleHyperText)
|
||||
// nsISupports
|
||||
|
||||
NS_IMPL_QUERY_INTERFACE_INHERITED(xpcAccessibleDocument, xpcAccessibleHyperText,
|
||||
nsIAccessibleDocument)
|
||||
NS_IMPL_ADDREF_INHERITED(xpcAccessibleDocument, xpcAccessibleHyperText)
|
||||
NS_IMPL_RELEASE_INHERITED(xpcAccessibleDocument, xpcAccessibleHyperText)
|
||||
NS_IMETHODIMP_(MozExternalRefCountType) xpcAccessibleDocument::Release(void)
|
||||
{
|
||||
nsrefcnt r = xpcAccessibleHyperText::Release();
|
||||
NS_LOG_RELEASE(this, r, "xpcAccessibleDocument");
|
||||
|
||||
// The only reference to the xpcAccessibleDocument is in DocManager's cache.
|
||||
if (r == 1 && !mIntl.IsNull() && mCache.Count() == 0) {
|
||||
if (mIntl.IsAccessible()) {
|
||||
GetAccService()->RemoveFromXPCDocumentCache(
|
||||
mIntl.AsAccessible()->AsDoc());
|
||||
} else {
|
||||
GetAccService()->RemoveFromRemoteXPCDocumentCache(
|
||||
mIntl.AsProxy()->AsDoc());
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIAccessibleDocument
|
||||
@ -179,7 +181,7 @@ xpcAccessibleDocument::GetAccessible(Accessible* aAccessible)
|
||||
if (aAccessible->IsDoc())
|
||||
return this;
|
||||
|
||||
xpcAccessibleGeneric* xpcAcc = mCache.GetWeak(aAccessible);
|
||||
xpcAccessibleGeneric* xpcAcc = mCache.Get(aAccessible);
|
||||
if (xpcAcc)
|
||||
return xpcAcc;
|
||||
|
||||
@ -207,7 +209,7 @@ xpcAccessibleDocument::GetXPCAccessible(ProxyAccessible* aProxy)
|
||||
return this;
|
||||
}
|
||||
|
||||
xpcAccessibleGeneric* acc = mCache.GetWeak(aProxy);
|
||||
xpcAccessibleGeneric* acc = mCache.Get(aProxy);
|
||||
if (acc) {
|
||||
return acc;
|
||||
}
|
||||
@ -217,7 +219,7 @@ xpcAccessibleDocument::GetXPCAccessible(ProxyAccessible* aProxy)
|
||||
if (aProxy->mHasValue) {
|
||||
interfaces |= eValue;
|
||||
}
|
||||
|
||||
|
||||
if (aProxy->mIsHyperLink) {
|
||||
interfaces |= eHyperLink;
|
||||
}
|
||||
|
@ -32,8 +32,6 @@ public:
|
||||
mRemote(true) {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(xpcAccessibleDocument,
|
||||
xpcAccessibleGeneric)
|
||||
|
||||
// nsIAccessibleDocument
|
||||
NS_IMETHOD GetURL(nsAString& aURL) final override;
|
||||
@ -75,33 +73,43 @@ private:
|
||||
void NotifyOfShutdown(Accessible* aAccessible)
|
||||
{
|
||||
MOZ_ASSERT(!mRemote);
|
||||
xpcAccessibleGeneric* xpcAcc = mCache.GetWeak(aAccessible);
|
||||
if (xpcAcc)
|
||||
xpcAccessibleGeneric* xpcAcc = mCache.Get(aAccessible);
|
||||
if (xpcAcc) {
|
||||
xpcAcc->Shutdown();
|
||||
}
|
||||
|
||||
mCache.Remove(aAccessible);
|
||||
if (mCache.Count() == 0 && mRefCnt == 1) {
|
||||
GetAccService()->RemoveFromXPCDocumentCache(
|
||||
mIntl.AsAccessible()->AsDoc());
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyOfShutdown(ProxyAccessible* aProxy)
|
||||
{
|
||||
MOZ_ASSERT(mRemote);
|
||||
xpcAccessibleGeneric* acc = mCache.GetWeak(aProxy);
|
||||
if (acc) {
|
||||
acc->Shutdown();
|
||||
xpcAccessibleGeneric* xpcAcc = mCache.Get(aProxy);
|
||||
if (xpcAcc) {
|
||||
xpcAcc->Shutdown();
|
||||
}
|
||||
|
||||
mCache.Remove(aProxy);
|
||||
if (mCache.Count() == 0 && mRefCnt == 1) {
|
||||
GetAccService()->RemoveFromRemoteXPCDocumentCache(
|
||||
mIntl.AsProxy()->AsDoc());
|
||||
}
|
||||
}
|
||||
|
||||
friend class DocManager;
|
||||
friend class DocAccessible;
|
||||
friend class ProxyAccessible;
|
||||
friend class ProxyAccessibleBase<ProxyAccessible>;
|
||||
friend class xpcAccessibleGeneric;
|
||||
|
||||
xpcAccessibleDocument(const xpcAccessibleDocument&) = delete;
|
||||
xpcAccessibleDocument& operator =(const xpcAccessibleDocument&) = delete;
|
||||
|
||||
nsRefPtrHashtable<nsPtrHashKey<const void>, xpcAccessibleGeneric> mCache;
|
||||
nsDataHashtable<nsPtrHashKey<const void>, xpcAccessibleGeneric*> mCache;
|
||||
bool mRemote;
|
||||
};
|
||||
|
||||
|
@ -9,11 +9,9 @@
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsISupports and cycle collection
|
||||
// nsISupports
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_0(xpcAccessibleGeneric)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(xpcAccessibleGeneric)
|
||||
NS_INTERFACE_MAP_BEGIN(xpcAccessibleGeneric)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAccessible)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAccessibleSelectable,
|
||||
mSupportedIfaces & eSelectable)
|
||||
@ -24,8 +22,30 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(xpcAccessibleGeneric)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessible)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(xpcAccessibleGeneric)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(xpcAccessibleGeneric)
|
||||
NS_IMPL_ADDREF(xpcAccessibleGeneric)
|
||||
NS_IMPL_RELEASE(xpcAccessibleGeneric)
|
||||
|
||||
xpcAccessibleGeneric::~xpcAccessibleGeneric()
|
||||
{
|
||||
if (mIntl.IsNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
xpcAccessibleDocument* xpcDoc = nullptr;
|
||||
if (mIntl.IsAccessible()) {
|
||||
Accessible* acc = mIntl.AsAccessible();
|
||||
if (!acc->IsDoc() && !acc->IsApplication()) {
|
||||
xpcDoc = GetAccService()->GetXPCDocument(acc->Document());
|
||||
xpcDoc->NotifyOfShutdown(acc);
|
||||
}
|
||||
} else {
|
||||
ProxyAccessible* proxy = mIntl.AsProxy();
|
||||
if (!proxy->IsDoc()) {
|
||||
xpcDoc = GetAccService()->GetXPCDocument(proxy->Document());
|
||||
xpcDoc->NotifyOfShutdown(proxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIAccessible
|
||||
|
@ -41,8 +41,7 @@ public:
|
||||
xpcAccessibleGeneric(ProxyAccessible* aProxy, uint8_t aInterfaces) :
|
||||
mIntl(aProxy), mSupportedIfaces(aInterfaces) {}
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(xpcAccessibleGeneric, nsIAccessible)
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIAccessible
|
||||
virtual Accessible* ToInternalAccessible() const final override;
|
||||
@ -51,7 +50,7 @@ public:
|
||||
virtual void Shutdown();
|
||||
|
||||
protected:
|
||||
virtual ~xpcAccessibleGeneric() {}
|
||||
virtual ~xpcAccessibleGeneric();
|
||||
|
||||
AccessibleOrProxy mIntl;
|
||||
|
||||
|
@ -13,14 +13,8 @@ const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
|
||||
const PROMPT_FOR_UNKNOWN = ["audio-capture",
|
||||
"desktop-notification",
|
||||
"geolocation",
|
||||
"video-capture"];
|
||||
// Due to privary issue, permission requests like GetUserMedia should prompt
|
||||
// every time instead of providing session persistence.
|
||||
const PERMISSION_NO_SESSION = ["audio-capture", "video-capture"];
|
||||
const ALLOW_MULTIPLE_REQUESTS = ["audio-capture", "video-capture"];
|
||||
const PROMPT_FOR_UNKNOWN = ["desktop-notification",
|
||||
"geolocation"];
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
@ -113,23 +107,6 @@ ContentPermissionPrompt.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
// multiple requests should be audio and video
|
||||
checkMultipleRequest: function checkMultipleRequest(typesInfo) {
|
||||
if (typesInfo.length == 1) {
|
||||
return true;
|
||||
} else if (typesInfo.length > 1) {
|
||||
let checkIfAllowMultiRequest = function(type) {
|
||||
return (ALLOW_MULTIPLE_REQUESTS.indexOf(type.access) !== -1);
|
||||
}
|
||||
if (typesInfo.every(checkIfAllowMultiRequest)) {
|
||||
debug("legal multiple requests");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
handledByPermissionType: function handledByPermissionType(request, typesInfo) {
|
||||
for (let i in typesInfo) {
|
||||
if (permissionSpecificChecker.hasOwnProperty(typesInfo[i].permission) &&
|
||||
@ -176,11 +153,6 @@ ContentPermissionPrompt.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.checkMultipleRequest(typesInfo)) {
|
||||
request.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.handledByPermissionType(request, typesInfo)) {
|
||||
return;
|
||||
}
|
||||
@ -258,11 +230,6 @@ ContentPermissionPrompt.prototype = {
|
||||
if (remember) {
|
||||
Services.perms.addFromPrincipal(request.principal, type.access,
|
||||
Ci.nsIPermissionManager.DENY_ACTION);
|
||||
} else if (PERMISSION_NO_SESSION.indexOf(type.access) < 0) {
|
||||
Services.perms.addFromPrincipal(request.principal, type.access,
|
||||
Ci.nsIPermissionManager.DENY_ACTION,
|
||||
Ci.nsIPermissionManager.EXPIRE_SESSION,
|
||||
0);
|
||||
}
|
||||
}
|
||||
try {
|
||||
@ -297,11 +264,7 @@ ContentPermissionPrompt.prototype = {
|
||||
}
|
||||
|
||||
let principal = request.principal;
|
||||
let isApp = principal.appStatus != Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED;
|
||||
let remember = (principal.appStatus == Ci.nsIPrincipal.APP_STATUS_PRIVILEGED ||
|
||||
principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED)
|
||||
? true
|
||||
: request.remember;
|
||||
let remember = request.remember;
|
||||
let isGranted = typesInfo.every(function(type) {
|
||||
return type.action == Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
});
|
||||
@ -319,15 +282,11 @@ ContentPermissionPrompt.prototype = {
|
||||
// compare against the mozApp.origin of app windows, so we
|
||||
// are not concerned with origin suffixes here (appId, etc).
|
||||
origin: principal.originNoSuffix,
|
||||
isApp: isApp,
|
||||
isApp: false,
|
||||
remember: remember,
|
||||
isGranted: isGranted,
|
||||
};
|
||||
|
||||
if (isApp) {
|
||||
details.manifestURL = DOMApplicationRegistry.getManifestURLByLocalId(principal.appId);
|
||||
}
|
||||
|
||||
// request.element is defined for OOP content, while request.window
|
||||
// is defined for In-Process content.
|
||||
// In both cases the message needs to be dispatched to the top-level
|
||||
@ -352,18 +311,5 @@ ContentPermissionPrompt.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt])
|
||||
};
|
||||
|
||||
(function() {
|
||||
// Do not allow GetUserMedia while in call.
|
||||
permissionSpecificChecker["audio-capture"] = function(request) {
|
||||
let forbid = false;
|
||||
|
||||
if (forbid) {
|
||||
request.cancel();
|
||||
}
|
||||
|
||||
return forbid;
|
||||
};
|
||||
})();
|
||||
|
||||
//module initialization
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]);
|
||||
|
@ -25,10 +25,6 @@ function fireOrientationEvent(window) {
|
||||
function hookScreen(window) {
|
||||
let nodePrincipal = window.document.nodePrincipal;
|
||||
let origin = nodePrincipal.origin;
|
||||
if (nodePrincipal.appStatus == nodePrincipal.APP_STATUS_NOT_INSTALLED) {
|
||||
// Only inject screen mock for apps
|
||||
return;
|
||||
}
|
||||
|
||||
let screen = window.wrappedJSObject.screen;
|
||||
|
||||
|
@ -3,27 +3,6 @@
|
||||
<script>
|
||||
|
||||
var actions = [
|
||||
{
|
||||
permissions: ["video-capture"],
|
||||
action: function() {
|
||||
// invoke video-capture permission prompt
|
||||
navigator.mozGetUserMedia({video: true}, function () {}, function () {});
|
||||
}
|
||||
},
|
||||
{
|
||||
permissions: ["audio-capture", "video-capture"],
|
||||
action: function() {
|
||||
// invoke audio-capture + video-capture permission prompt
|
||||
navigator.mozGetUserMedia({audio: true, video: true}, function () {}, function () {});
|
||||
}
|
||||
},
|
||||
{
|
||||
permissions: ["audio-capture"],
|
||||
action: function() {
|
||||
// invoke audio-capture permission prompt
|
||||
navigator.mozGetUserMedia({audio: true}, function () {}, function () {});
|
||||
}
|
||||
},
|
||||
{
|
||||
permissions: ["geolocation"],
|
||||
action: function() {
|
||||
|
@ -10,10 +10,6 @@ support-files =
|
||||
|
||||
[test_filepicker_path.html]
|
||||
skip-if = toolkit != "gonk"
|
||||
[test_permission_deny.html]
|
||||
skip-if = toolkit != "gonk"
|
||||
[test_permission_gum_remember.html]
|
||||
skip-if = true # Bug 1019572 - frequent timeouts
|
||||
[test_sandbox_permission.html]
|
||||
skip-if = toolkit != "gonk"
|
||||
[test_screenshot.html]
|
||||
|
@ -1,83 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=981113
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Permission Deny Test</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=981113">Test Permission Deny</a>
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
'use strict';
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const PROMPT_ACTION = SpecialPowers.Ci.nsIPermissionManager.PROMPT_ACTION;
|
||||
|
||||
var gUrl = SimpleTest.getTestFileURL('permission_handler_chrome.js');
|
||||
var gScript = SpecialPowers.loadChromeScript(gUrl);
|
||||
var gTests = [
|
||||
{
|
||||
'video': true,
|
||||
},
|
||||
{
|
||||
'audio': true,
|
||||
'video': true,
|
||||
},
|
||||
{
|
||||
'audio': true,
|
||||
},
|
||||
];
|
||||
|
||||
function runNext() {
|
||||
if (gTests.length > 0) {
|
||||
// Put the requested permission in query string
|
||||
let requestedType = gTests.shift();
|
||||
info('getUserMedia for ' + JSON.stringify(requestedType));
|
||||
navigator.mozGetUserMedia(requestedType, function success() {
|
||||
ok(false, 'unexpected success, permission request should be denied');
|
||||
runNext();
|
||||
}, function failure(err) {
|
||||
is(err.name, 'SecurityError', 'expected permission denied');
|
||||
runNext();
|
||||
});
|
||||
} else {
|
||||
info('test finished, teardown');
|
||||
gScript.sendAsyncMessage('teardown', '');
|
||||
gScript.destroy();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
gScript.addMessageListener('permission-request', function(detail) {
|
||||
let response = {
|
||||
id: detail.id,
|
||||
type: 'permission-deny',
|
||||
remember: false,
|
||||
};
|
||||
gScript.sendAsyncMessage('permission-response', response);
|
||||
});
|
||||
|
||||
// Need to change camera permission from ALLOW to PROMPT, otherwise
|
||||
// MediaManager will automatically allow video-only gUM request.
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'video-capture', allow: PROMPT_ACTION, context: document},
|
||||
{type: 'audio-capture', allow: PROMPT_ACTION, context: document},
|
||||
{type: 'camera', allow: PROMPT_ACTION, context: document},
|
||||
], function() {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
'set': [
|
||||
['media.navigator.permission.disabled', false],
|
||||
]
|
||||
}, runNext);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -1,170 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=978660
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>gUM Remember Permission Test</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=978660">Test remembering gUM Permission</a>
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
'use strict';
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const PROMPT_ACTION = SpecialPowers.Ci.nsIPermissionManager.PROMPT_ACTION;
|
||||
|
||||
var gUrl = SimpleTest.getTestFileURL('permission_handler_chrome.js');
|
||||
var gScript = SpecialPowers.loadChromeScript(gUrl);
|
||||
gScript.addMessageListener('permission-request', function(detail) {
|
||||
ok(false, 'unexpected mozChromeEvent for permission prompt');
|
||||
let response = {
|
||||
id: detail.id,
|
||||
type: 'permission-deny',
|
||||
remember: false,
|
||||
};
|
||||
gScript.sendAsyncMessage('permission-response', response);
|
||||
});
|
||||
|
||||
var gTests = [
|
||||
{
|
||||
'audio': true,
|
||||
'video': {facingMode: 'environment', required: ['facingMode']},
|
||||
},
|
||||
{
|
||||
'video': {facingMode: 'environment', required: ['facingMode']},
|
||||
},
|
||||
{
|
||||
'audio': true,
|
||||
},
|
||||
];
|
||||
|
||||
function testGranted() {
|
||||
info('test remember permission granted');
|
||||
return new Promise(function(resolve, reject) {
|
||||
let steps = [].concat(gTests);
|
||||
function nextStep() {
|
||||
if (steps.length > 0) {
|
||||
let requestedType = steps.shift();
|
||||
info('getUserMedia for ' + JSON.stringify(requestedType));
|
||||
navigator.mozGetUserMedia(requestedType, function success(stream) {
|
||||
ok(true, 'expected gUM success');
|
||||
stream.stop();
|
||||
nextStep();
|
||||
}, function failure(err) {
|
||||
ok(false, 'unexpected gUM fail: ' + err);
|
||||
nextStep();
|
||||
});
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'video-capture', allow: true, context: document},
|
||||
{type: 'audio-capture', allow: true, context: document},
|
||||
], nextStep);
|
||||
});
|
||||
}
|
||||
|
||||
function testDenied() {
|
||||
info('test remember permission denied');
|
||||
return new Promise(function(resolve, reject) {
|
||||
let steps = [].concat(gTests);
|
||||
function nextStep() {
|
||||
if (steps.length > 0) {
|
||||
let requestedType = steps.shift();
|
||||
info('getUserMedia for ' + JSON.stringify(requestedType));
|
||||
navigator.mozGetUserMedia(requestedType, function success(stream) {
|
||||
ok(false, 'unexpected gUM success');
|
||||
stream.stop();
|
||||
nextStep();
|
||||
}, function failure(err) {
|
||||
ok(true, 'expected gUM fail: ' + err);
|
||||
nextStep();
|
||||
});
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'video-capture', allow: false, context: document},
|
||||
{type: 'audio-capture', allow: false, context: document},
|
||||
], nextStep);
|
||||
});
|
||||
}
|
||||
|
||||
function testPartialDeniedAudio() {
|
||||
info('test remember permission partial denied: audio');
|
||||
return new Promise(function(resolve, reject) {
|
||||
info('getUserMedia for video and audio');
|
||||
function nextStep() {
|
||||
navigator.mozGetUserMedia({video: {facingMode: 'environment', required: ['facingMode']},
|
||||
audio: true}, function success(stream) {
|
||||
ok(false, 'unexpected gUM success');
|
||||
stream.stop();
|
||||
resolve();
|
||||
}, function failure(err) {
|
||||
ok(true, 'expected gUM fail: ' + err);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'video-capture', allow: true, context: document},
|
||||
{type: 'audio-capture', allow: false, context: document},
|
||||
], nextStep);
|
||||
});
|
||||
}
|
||||
|
||||
function testPartialDeniedVideo() {
|
||||
info('test remember permission partial denied: video');
|
||||
return new Promise(function(resolve, reject) {
|
||||
info('getUserMedia for video and audio');
|
||||
function nextStep() {
|
||||
navigator.mozGetUserMedia({video: {facingMode: 'environment', required: ['facingMode']},
|
||||
audio: true}, function success(stream) {
|
||||
ok(false, 'unexpected gUM success');
|
||||
stream.stop();
|
||||
resolve();
|
||||
}, function failure(err) {
|
||||
ok(true, 'expected gUM fail: ' + err);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'video-capture', allow: false, context: document},
|
||||
{type: 'audio-capture', allow: true, context: document},
|
||||
], nextStep);
|
||||
});
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
testGranted()
|
||||
.then(testDenied)
|
||||
.then(testPartialDeniedAudio)
|
||||
.then(testPartialDeniedVideo)
|
||||
.then(function() {
|
||||
info('test finished, teardown');
|
||||
gScript.sendAsyncMessage('teardown', '');
|
||||
gScript.destroy();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
'set': [
|
||||
['media.navigator.permission.disabled', false],
|
||||
]
|
||||
}, runTests);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -21,16 +21,6 @@ var iframe;
|
||||
var gUrl = SimpleTest.getTestFileURL("permission_handler_chrome.js");
|
||||
var gScript = SpecialPowers.loadChromeScript(gUrl);
|
||||
var gResult = [
|
||||
{
|
||||
"video-capture": ["back"],
|
||||
},
|
||||
{
|
||||
"audio-capture": [""],
|
||||
"video-capture": ["back"],
|
||||
},
|
||||
{
|
||||
"audio-capture": [""],
|
||||
},
|
||||
{
|
||||
"geolocation": [],
|
||||
},
|
||||
@ -86,10 +76,6 @@ gScript.addMessageListener("permission-request", function (detail) {
|
||||
// should prompt for permission, not allow it without prompt.
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.navigator.permission.disabled", false]]},
|
||||
function() {
|
||||
SpecialPowers.addPermission('video-capture',
|
||||
SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION, document);
|
||||
SpecialPowers.addPermission('audio-capture',
|
||||
SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION, document);
|
||||
SpecialPowers.addPermission('geolocation',
|
||||
SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION, document);
|
||||
SpecialPowers.addPermission('desktop-notification',
|
||||
|
@ -41,7 +41,6 @@ function setup_fs() {
|
||||
function setup_sdcard() {
|
||||
let volName = "sdcard";
|
||||
let mountPoint = "/data/local/tmp/sdcard";
|
||||
volumeService.createFakeVolume(volName, mountPoint);
|
||||
|
||||
let vol = volumeService.getVolumeByName(volName);
|
||||
ok(vol, "volume shouldn't be null");
|
||||
|
@ -57,6 +57,7 @@ nsContextMenu.prototype = {
|
||||
onAudio: this.onAudio,
|
||||
onCanvas: this.onCanvas,
|
||||
onEditableArea: this.onEditableArea,
|
||||
onPassword: this.onPassword,
|
||||
srcUrl: this.mediaURL,
|
||||
frameUrl: gContextMenuContentData ? gContextMenuContentData.docLocation : undefined,
|
||||
pageUrl: this.browser ? this.browser.currentURI.spec : undefined,
|
||||
|
@ -239,6 +239,10 @@ function getContexts(contextData) {
|
||||
contexts.add("editable");
|
||||
}
|
||||
|
||||
if (contextData.onPassword) {
|
||||
contexts.add("password");
|
||||
}
|
||||
|
||||
if (contextData.onImage) {
|
||||
contexts.add("image");
|
||||
}
|
||||
@ -412,7 +416,7 @@ MenuItem.prototype = {
|
||||
|
||||
let info = {
|
||||
menuItemId: this.id,
|
||||
editable: contextData.onEditableArea,
|
||||
editable: contextData.onEditableArea || contextData.onPassword,
|
||||
};
|
||||
|
||||
function setIfDefined(argName, value) {
|
||||
|
@ -31,7 +31,7 @@
|
||||
{
|
||||
"id": "ContextType",
|
||||
"type": "string",
|
||||
"enum": ["all", "page", "frame", "selection", "link", "editable", "image", "video", "audio", "launcher", "browser_action", "page_action"],
|
||||
"enum": ["all", "page", "frame", "selection", "link", "editable", "password", "image", "video", "audio", "launcher", "browser_action", "page_action"],
|
||||
"description": "The different contexts a menu can appear in. Specifying 'all' is equivalent to the combination of all other contexts except for 'launcher'. The 'launcher' context is only supported by apps and is used to add menu items to the context menu that appears when clicking on the app icon in the launcher/taskbar/dock/etc. Different platforms might put limitations on what is actually supported in a launcher context menu."
|
||||
},
|
||||
{
|
||||
|
@ -72,7 +72,7 @@ add_task(function* () {
|
||||
type: "separator",
|
||||
});
|
||||
|
||||
let contexts = ["page", "selection", "image", "editable"];
|
||||
let contexts = ["page", "selection", "image", "editable", "password"];
|
||||
for (let i = 0; i < contexts.length; i++) {
|
||||
let context = contexts[i];
|
||||
let title = context;
|
||||
@ -204,6 +204,21 @@ add_task(function* () {
|
||||
result = yield extension.awaitMessage("browser.contextMenus.onClicked");
|
||||
checkClickInfo(result);
|
||||
|
||||
extensionMenuRoot = yield openExtensionContextMenu("#password");
|
||||
items = extensionMenuRoot.getElementsByAttribute("label", "password");
|
||||
is(items.length, 1, "contextMenu item for password input element was found (context=password)");
|
||||
let password = items[0];
|
||||
yield closeExtensionContextMenu(password);
|
||||
expectedClickInfo = {
|
||||
menuItemId: "ext-password",
|
||||
pageUrl: PAGE,
|
||||
editable: true,
|
||||
};
|
||||
|
||||
result = yield extension.awaitMessage("onclick");
|
||||
checkClickInfo(result);
|
||||
result = yield extension.awaitMessage("browser.contextMenus.onClicked");
|
||||
checkClickInfo(result);
|
||||
|
||||
// Select some text
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* (arg) {
|
||||
|
@ -17,7 +17,8 @@
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<input type="text" id="edit-me">
|
||||
<input type="text" id="edit-me"><br>
|
||||
<input type="password" id="password">
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -119,12 +119,12 @@ this.CaptivePortalWatcher = {
|
||||
|
||||
// If the tab is gone or going, we need to open a new one.
|
||||
if (!tab || tab.closing || !tab.parentNode) {
|
||||
tab = win.gBrowser.addTab(this.canonicalURL);
|
||||
tab = win.gBrowser.addTab(this.canonicalURL,
|
||||
{ ownerTab: win.gBrowser.selectedTab });
|
||||
this._captivePortalTab = Cu.getWeakReference(tab);
|
||||
}
|
||||
|
||||
this._captivePortalTab = Cu.getWeakReference(tab);
|
||||
win.gBrowser.selectedTab = tab;
|
||||
return tab;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -102,14 +102,14 @@ nsPrincipal::GetScriptLocation(nsACString &aStr)
|
||||
return mCodebase->GetSpec(aStr);
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin)
|
||||
nsresult
|
||||
nsPrincipal::GetOriginInternal(nsACString& aOrigin)
|
||||
{
|
||||
if (!aURI) {
|
||||
if (!mCodebase) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> origin = NS_GetInnermostURI(aURI);
|
||||
nsCOMPtr<nsIURI> origin = NS_GetInnermostURI(mCodebase);
|
||||
if (!origin) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -178,12 +178,6 @@ nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPrincipal::GetOriginInternal(nsACString& aOrigin)
|
||||
{
|
||||
return GetOriginForURI(mCodebase, aOrigin);
|
||||
}
|
||||
|
||||
bool
|
||||
nsPrincipal::SubsumesInternal(nsIPrincipal* aOther,
|
||||
BasePrincipal::DocumentDomainConsideration aConsideration)
|
||||
|
@ -37,11 +37,6 @@ public:
|
||||
virtual nsresult GetScriptLocation(nsACString& aStr) override;
|
||||
void SetURI(nsIURI* aURI);
|
||||
|
||||
/**
|
||||
* Computes the puny-encoded origin of aURI.
|
||||
*/
|
||||
static nsresult GetOriginForURI(nsIURI* aURI, nsACString& aOrigin);
|
||||
|
||||
/**
|
||||
* Called at startup to setup static data, e.g. about:config pref-observers.
|
||||
*/
|
||||
|
@ -115,7 +115,7 @@ const TEST_DATA = [ // eslint-disable-line
|
||||
expected: [
|
||||
{
|
||||
type: "click",
|
||||
filename: TEST_URL + ":1",
|
||||
filename: TEST_URL + ":0",
|
||||
attributes: [
|
||||
"Bubbling",
|
||||
"DOM2"
|
||||
@ -129,7 +129,7 @@ const TEST_DATA = [ // eslint-disable-line
|
||||
expected: [
|
||||
{
|
||||
type: "click",
|
||||
filename: TEST_URL + ":1",
|
||||
filename: TEST_URL + ":0",
|
||||
attributes: [
|
||||
"Bubbling",
|
||||
"DOM2"
|
||||
|
@ -212,6 +212,10 @@ CssRuleView.prototype = {
|
||||
* @return {Promise} Resolves to the instance of the highlighter.
|
||||
*/
|
||||
getSelectorHighlighter: Task.async(function* () {
|
||||
if (!this.inspector) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let utils = this.inspector.toolbox.highlighterUtils;
|
||||
if (!utils.supportsCustomHighlighters()) {
|
||||
return null;
|
||||
@ -270,13 +274,13 @@ CssRuleView.prototype = {
|
||||
},
|
||||
|
||||
highlightSelector: Task.async(function* (selector) {
|
||||
let node = this.inspector.selection.nodeFront;
|
||||
|
||||
let highlighter = yield this.getSelectorHighlighter();
|
||||
if (!highlighter) {
|
||||
return;
|
||||
}
|
||||
|
||||
let node = this.inspector.selection.nodeFront;
|
||||
|
||||
yield highlighter.show(node, {
|
||||
hideInfoBar: true,
|
||||
hideGuides: true,
|
||||
|
@ -375,7 +375,7 @@ body {
|
||||
|
||||
.animation-timeline .animation .name {
|
||||
position: absolute;
|
||||
color: var(--theme-selection-color3);
|
||||
color: var(--theme-content-color3);
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
height: 100%;
|
||||
|
@ -175,7 +175,6 @@ function* testJSTerm(hud) {
|
||||
"JSMSG_BAD_RADIX": "(42).toString(0);",
|
||||
"JSMSG_BAD_ARRAY_LENGTH": "([]).length = -1",
|
||||
"JSMSG_NEGATIVE_REPETITION_COUNT": "'abc'.repeat(-1);",
|
||||
"JSMSG_BAD_FORMAL": "var f = Function('x y', 'return x + y;');",
|
||||
"JSMSG_PRECISION_RANGE": "77.1234.toExponential(-1);",
|
||||
};
|
||||
|
||||
|
@ -18,7 +18,6 @@ const ErrorDocs = {
|
||||
JSMSG_RESULTING_STRING_TOO_LARGE: "Resulting_string_too_large",
|
||||
JSMSG_BAD_RADIX: "Bad_radix",
|
||||
JSMSG_PRECISION_RANGE: "Precision_range",
|
||||
JSMSG_BAD_FORMAL: "Malformed_formal_parameter",
|
||||
JSMSG_STMT_AFTER_RETURN: "Stmt_after_return",
|
||||
JSMSG_NOT_A_CODEPOINT: "Not_a_codepoint",
|
||||
JSMSG_BAD_SORT_ARG: "Array_sort_argument",
|
||||
|
@ -102,16 +102,6 @@ function doPageErrors()
|
||||
warning: false,
|
||||
exception: true,
|
||||
},
|
||||
"var f = Function('x y', 'return x + y;');": {
|
||||
errorMessage: /malformed formal/,
|
||||
errorMessageName: "JSMSG_BAD_FORMAL",
|
||||
sourceName: /test_page_errors/,
|
||||
category: "chrome javascript",
|
||||
timeStamp: /^\d+$/,
|
||||
error: false,
|
||||
warning: false,
|
||||
exception: true,
|
||||
},
|
||||
"function a() { return; 1 + 1; }": {
|
||||
errorMessage: /unreachable code/,
|
||||
errorMessageName: "JSMSG_STMT_AFTER_RETURN",
|
||||
|
@ -59,7 +59,6 @@ support-files = bug530396-noref.sjs bug530396-subframe.html
|
||||
[test_bug540462.html]
|
||||
[test_bug551225.html]
|
||||
[test_bug570341.html]
|
||||
skip-if = toolkit == 'android' && debug # Bug 1040769
|
||||
[test_bug580069.html]
|
||||
[test_bug590573.html]
|
||||
[test_bug598895.html]
|
||||
|
@ -108,9 +108,10 @@ window.onload = function() {
|
||||
}, true);
|
||||
frames[0].location = 'bug570341_recordevents.html'
|
||||
var interval = setInterval(function () {
|
||||
// time constants here are arbitrary, chosen to allow the test to pass
|
||||
var stopPolling = (win.performance && win.performance.loadEventEnd) ||
|
||||
(seenLoad && Date.now() >= seenLoad + 200) ||
|
||||
Date.now() >= start + 5000;
|
||||
(seenLoad && Date.now() >= seenLoad + 3000) ||
|
||||
Date.now() >= start + 30000;
|
||||
if (stopPolling) {
|
||||
clearInterval(interval);
|
||||
checkValues();
|
||||
|
@ -996,14 +996,12 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
|
||||
}
|
||||
aListener = nullptr;
|
||||
|
||||
uint32_t lineNo = 0;
|
||||
nsAutoCString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
|
||||
MOZ_ASSERT(body);
|
||||
MOZ_ASSERT(aElement);
|
||||
nsIURI *uri = aElement->OwnerDoc()->GetDocumentURI();
|
||||
if (uri) {
|
||||
uri->GetSpec(url);
|
||||
lineNo = 1;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mTarget);
|
||||
@ -1073,8 +1071,9 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
JS::CompileOptions options(cx);
|
||||
// Use line 0 to make the function body starts from line 1.
|
||||
options.setIntroductionType("eventHandler")
|
||||
.setFileAndLine(url.get(), lineNo)
|
||||
.setFileAndLine(url.get(), 0)
|
||||
.setVersion(JSVERSION_DEFAULT)
|
||||
.setElement(&v.toObject())
|
||||
.setElementAttributeName(jsStr);
|
||||
|
@ -7,4 +7,6 @@ support-files =
|
||||
[test_anchor_ping.html]
|
||||
skip-if = os == 'android'
|
||||
[test_audio_wakelock.html]
|
||||
skip-if = os == 'android' && processor == 'x86' # bug 1315749
|
||||
[test_video_wakelock.html]
|
||||
skip-if = os == 'android' && processor == 'x86' # bug 1315749
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "mozilla/dom/PushNotifier.h"
|
||||
#include "mozilla/dom/workers/ServiceWorkerManager.h"
|
||||
#include "mozilla/dom/nsIContentChild.h"
|
||||
#include "mozilla/dom/URLClassifierChild.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/psm/PSMContentListener.h"
|
||||
#include "mozilla/hal_sandbox/PHalChild.h"
|
||||
@ -2409,18 +2410,6 @@ ContentChild::RecvLastPrivateDocShellDestroyed()
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvVolumes(nsTArray<VolumeInfo>&& aVolumes)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
|
||||
if (vs) {
|
||||
vs->RecvVolumesFromParent(aVolumes);
|
||||
}
|
||||
#endif
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvFilePathUpdate(const nsString& aStorageType,
|
||||
const nsString& aStorageName,
|
||||
@ -2443,61 +2432,6 @@ ContentChild::RecvFilePathUpdate(const nsString& aStorageType,
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvFileSystemUpdate(const nsString& aFsName,
|
||||
const nsString& aVolumeName,
|
||||
const int32_t& aState,
|
||||
const int32_t& aMountGeneration,
|
||||
const bool& aIsMediaPresent,
|
||||
const bool& aIsSharing,
|
||||
const bool& aIsFormatting,
|
||||
const bool& aIsFake,
|
||||
const bool& aIsUnmounting,
|
||||
const bool& aIsRemovable,
|
||||
const bool& aIsHotSwappable)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
RefPtr<nsVolume> volume = new nsVolume(aFsName, aVolumeName, aState,
|
||||
aMountGeneration, aIsMediaPresent,
|
||||
aIsSharing, aIsFormatting, aIsFake,
|
||||
aIsUnmounting, aIsRemovable, aIsHotSwappable);
|
||||
|
||||
RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
|
||||
if (vs) {
|
||||
vs->UpdateVolume(volume);
|
||||
}
|
||||
#else
|
||||
// Remove warnings about unused arguments
|
||||
Unused << aFsName;
|
||||
Unused << aVolumeName;
|
||||
Unused << aState;
|
||||
Unused << aMountGeneration;
|
||||
Unused << aIsMediaPresent;
|
||||
Unused << aIsSharing;
|
||||
Unused << aIsFormatting;
|
||||
Unused << aIsFake;
|
||||
Unused << aIsUnmounting;
|
||||
Unused << aIsRemovable;
|
||||
Unused << aIsHotSwappable;
|
||||
#endif
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvVolumeRemoved(const nsString& aFsName)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
|
||||
if (vs) {
|
||||
vs->RemoveVolumeByName(aFsName);
|
||||
}
|
||||
#else
|
||||
// Remove warnings about unused arguments
|
||||
Unused << aFsName;
|
||||
#endif
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvNotifyProcessPriorityChanged(
|
||||
const hal::ProcessPriority& aPriority)
|
||||
@ -2525,16 +2459,6 @@ ContentChild::RecvMinimizeMemoryUsage()
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvNotifyPhoneStateChange(const nsString& aState)
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os) {
|
||||
os->NotifyObservers(nullptr, "phone-state-changed", aState.get());
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void
|
||||
ContentChild::AddIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS)
|
||||
{
|
||||
@ -3232,5 +3156,22 @@ ContentChild::FatalErrorIfNotUsingGPUProcess(const char* const aProtocolName,
|
||||
}
|
||||
}
|
||||
|
||||
PURLClassifierChild*
|
||||
ContentChild::AllocPURLClassifierChild(const Principal& aPrincipal,
|
||||
const bool& aUseTrackingProtection,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = true;
|
||||
return new URLClassifierChild();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPURLClassifierChild(PURLClassifierChild* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -30,6 +30,7 @@ class nsIObserver;
|
||||
struct SubstitutionMapping;
|
||||
struct OverrideMapping;
|
||||
class nsIDomainPolicy;
|
||||
class nsIURIClassifierCallback;
|
||||
|
||||
namespace mozilla {
|
||||
class RemoteSpellcheckEngineChild;
|
||||
@ -431,27 +432,11 @@ public:
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvLastPrivateDocShellDestroyed() override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvVolumes(InfallibleTArray<VolumeInfo>&& aVolumes) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvFilePathUpdate(const nsString& aStorageType,
|
||||
const nsString& aStorageName,
|
||||
const nsString& aPath,
|
||||
const nsCString& aReason) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvFileSystemUpdate(const nsString& aFsName,
|
||||
const nsString& aVolumeName,
|
||||
const int32_t& aState,
|
||||
const int32_t& aMountGeneration,
|
||||
const bool& aIsMediaPresent,
|
||||
const bool& aIsSharing,
|
||||
const bool& aIsFormatting,
|
||||
const bool& aIsFake,
|
||||
const bool& aIsUnmounting,
|
||||
const bool& aIsRemovable,
|
||||
const bool& aIsHotSwappable) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvVolumeRemoved(const nsString& aFsName) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvNotifyProcessPriorityChanged(const hal::ProcessPriority& aPriority) override;
|
||||
|
||||
@ -463,8 +448,6 @@ public:
|
||||
virtual mozilla::ipc::IPCResult RecvUnregisterSheet(const URIParams& aURI,
|
||||
const uint32_t& aType) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvNotifyPhoneStateChange(const nsString& aState) override;
|
||||
|
||||
void AddIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS);
|
||||
|
||||
void RemoveIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS);
|
||||
@ -631,6 +614,13 @@ public:
|
||||
return mFontFamilies;
|
||||
}
|
||||
|
||||
virtual PURLClassifierChild*
|
||||
AllocPURLClassifierChild(const Principal& aPrincipal,
|
||||
const bool& aUseTrackingProtection,
|
||||
bool* aSuccess) override;
|
||||
virtual bool
|
||||
DeallocPURLClassifierChild(PURLClassifierChild* aActor) override;
|
||||
|
||||
/**
|
||||
* Helper function for protocols that use the GPU process when available.
|
||||
* Overrides FatalError to just be a warning when communicating with the
|
||||
|
@ -63,6 +63,7 @@
|
||||
#include "mozilla/dom/FlyWebPublishedServerIPC.h"
|
||||
#include "mozilla/dom/quota/QuotaManagerService.h"
|
||||
#include "mozilla/dom/time/DateCacheCleaner.h"
|
||||
#include "mozilla/dom/URLClassifierParent.h"
|
||||
#include "mozilla/embedding/printingui/PrintingParent.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/gfx/GPUProcessManager.h"
|
||||
@ -527,11 +528,6 @@ static const char* sObserverTopics[] = {
|
||||
"child-mmu-request",
|
||||
"last-pb-context-exited",
|
||||
"file-watcher-update",
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
NS_VOLUME_STATE_CHANGED,
|
||||
NS_VOLUME_REMOVED,
|
||||
"phone-state-changed",
|
||||
#endif
|
||||
#ifdef ACCESSIBILITY
|
||||
"a11y-init-or-shutdown",
|
||||
#endif
|
||||
@ -702,8 +698,6 @@ ContentParent::GetNewOrUsedBrowserProcess(bool aForBrowserElement,
|
||||
|
||||
p->mLargeAllocationProcess = aLargeAllocationProcess;
|
||||
|
||||
p->ForwardKnownInfo();
|
||||
|
||||
contentParents->AppendElement(p);
|
||||
return p.forget();
|
||||
}
|
||||
@ -1138,23 +1132,6 @@ ContentParent::Init()
|
||||
gmps->UpdateContentProcessGMPCapabilities();
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::ForwardKnownInfo()
|
||||
{
|
||||
MOZ_ASSERT(mMetamorphosed);
|
||||
if (!mMetamorphosed) {
|
||||
return;
|
||||
}
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
InfallibleTArray<VolumeInfo> volumeInfo;
|
||||
RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
|
||||
if (vs) {
|
||||
vs->GetVolumesForIPC(&volumeInfo);
|
||||
Unused << SendVolumes(volumeInfo);
|
||||
}
|
||||
#endif /* MOZ_WIDGET_GONK */
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class RemoteWindowContext final : public nsIRemoteWindowContext
|
||||
@ -1752,7 +1729,6 @@ ContentParent::InitializeMembers()
|
||||
mGeolocationWatchID = -1;
|
||||
mNumDestroyingTabs = 0;
|
||||
mIsAlive = true;
|
||||
mMetamorphosed = false;
|
||||
mSendPermissionUpdates = false;
|
||||
mCalledClose = false;
|
||||
mCalledKillHard = false;
|
||||
@ -1799,8 +1775,6 @@ ContentParent::ContentParent(ContentParent* aOpener,
|
||||
{
|
||||
InitializeMembers(); // Perform common initialization.
|
||||
|
||||
mMetamorphosed = true;
|
||||
|
||||
// Insert ourselves into the global linked list of ContentParent objects.
|
||||
if (!sContentParents) {
|
||||
sContentParents = new LinkedList<ContentParent>();
|
||||
@ -2420,50 +2394,6 @@ ContentParent::Observe(nsISupports* aSubject,
|
||||
DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject);
|
||||
Unused << SendFilePathUpdate(file->mStorageType, file->mStorageName, file->mPath, creason);
|
||||
}
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
else if(!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) {
|
||||
nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject);
|
||||
if (!vol) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsString volName;
|
||||
nsString mountPoint;
|
||||
int32_t state;
|
||||
int32_t mountGeneration;
|
||||
bool isMediaPresent;
|
||||
bool isSharing;
|
||||
bool isFormatting;
|
||||
bool isFake;
|
||||
bool isUnmounting;
|
||||
bool isRemovable;
|
||||
bool isHotSwappable;
|
||||
|
||||
vol->GetName(volName);
|
||||
vol->GetMountPoint(mountPoint);
|
||||
vol->GetState(&state);
|
||||
vol->GetMountGeneration(&mountGeneration);
|
||||
vol->GetIsMediaPresent(&isMediaPresent);
|
||||
vol->GetIsSharing(&isSharing);
|
||||
vol->GetIsFormatting(&isFormatting);
|
||||
vol->GetIsFake(&isFake);
|
||||
vol->GetIsUnmounting(&isUnmounting);
|
||||
vol->GetIsRemovable(&isRemovable);
|
||||
vol->GetIsHotSwappable(&isHotSwappable);
|
||||
|
||||
Unused << SendFileSystemUpdate(volName, mountPoint, state,
|
||||
mountGeneration, isMediaPresent,
|
||||
isSharing, isFormatting, isFake,
|
||||
isUnmounting, isRemovable, isHotSwappable);
|
||||
} else if (!strcmp(aTopic, "phone-state-changed")) {
|
||||
nsString state(aData);
|
||||
Unused << SendNotifyPhoneStateChange(state);
|
||||
}
|
||||
else if(!strcmp(aTopic, NS_VOLUME_REMOVED)) {
|
||||
nsString volName(aData);
|
||||
Unused << SendVolumeRemoved(volName);
|
||||
}
|
||||
#endif
|
||||
#ifdef ACCESSIBILITY
|
||||
else if (aData && !strcmp(aTopic, "a11y-init-or-shutdown")) {
|
||||
if (*aData == '1') {
|
||||
@ -3709,55 +3639,6 @@ ContentParent::SendPBrowserConstructor(PBrowserParent* aActor,
|
||||
aIsForBrowser);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvCreateFakeVolume(const nsString& fsName,
|
||||
const nsString& mountPoint)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
|
||||
if (vs) {
|
||||
vs->CreateFakeVolume(fsName, mountPoint);
|
||||
}
|
||||
return IPC_OK();
|
||||
#else
|
||||
NS_WARNING("ContentParent::RecvCreateFakeVolume shouldn't be called when MOZ_WIDGET_GONK is not defined");
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvSetFakeVolumeState(const nsString& fsName, const int32_t& fsState)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
|
||||
if (vs) {
|
||||
vs->SetFakeVolumeState(fsName, fsState);
|
||||
}
|
||||
return IPC_OK();
|
||||
#else
|
||||
NS_WARNING("ContentParent::RecvSetFakeVolumeState shouldn't be called when MOZ_WIDGET_GONK is not defined");
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvRemoveFakeVolume(const nsString& fsName)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
|
||||
if (vs) {
|
||||
vs->RemoveFakeVolume(fsName);
|
||||
}
|
||||
return IPC_OK();
|
||||
#else
|
||||
NS_WARNING("ContentParent::RecvRemoveFakeVolume shouldn't be called when MOZ_WIDGET_GONK is not defined");
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvKeywordToURI(const nsCString& aKeyword,
|
||||
nsString* aProviderName,
|
||||
@ -4818,3 +4699,64 @@ ContentParent::RecvAccumulateChildKeyedHistogram(
|
||||
Telemetry::AccumulateChildKeyed(GeckoProcessType_Content, aAccumulations);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
PURLClassifierParent*
|
||||
ContentParent::AllocPURLClassifierParent(const Principal& aPrincipal,
|
||||
const bool& aUseTrackingProtection,
|
||||
bool* aSuccess)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
*aSuccess = true;
|
||||
RefPtr<URLClassifierParent> actor = new URLClassifierParent();
|
||||
return actor.forget().take();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvPURLClassifierConstructor(PURLClassifierParent* aActor,
|
||||
const Principal& aPrincipal,
|
||||
const bool& aUseTrackingProtection,
|
||||
bool* aSuccess)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
auto* actor = static_cast<URLClassifierParent*>(aActor);
|
||||
nsCOMPtr<nsIPrincipal> principal(aPrincipal);
|
||||
if (!principal) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
return actor->StartClassify(principal, aUseTrackingProtection, aSuccess);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPURLClassifierParent(PURLClassifierParent* aActor)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
RefPtr<URLClassifierParent> actor =
|
||||
dont_AddRef(static_cast<URLClassifierParent*>(aActor));
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvClassifyLocal(const URIParams& aURI, const nsCString& aTables,
|
||||
nsCString* aResults)
|
||||
{
|
||||
MOZ_ASSERT(aResults);
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
|
||||
if (!uri) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
nsCOMPtr<nsIURIClassifier> uriClassifier =
|
||||
do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID);
|
||||
if (!uriClassifier) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
nsresult rv = uriClassifier->ClassifyLocalWithTables(uri, aTables, *aResults);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return IPC_FAIL(this, "ClassifyLocalWithTables error");
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
@ -522,6 +522,23 @@ public:
|
||||
|
||||
virtual int32_t Pid() const override;
|
||||
|
||||
virtual PURLClassifierParent*
|
||||
AllocPURLClassifierParent(const Principal& aPrincipal,
|
||||
const bool& aUseTrackingProtection,
|
||||
bool* aSuccess) override;
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvPURLClassifierConstructor(PURLClassifierParent* aActor,
|
||||
const Principal& aPrincipal,
|
||||
const bool& aUseTrackingProtection,
|
||||
bool* aSuccess) override;
|
||||
virtual bool
|
||||
DeallocPURLClassifierParent(PURLClassifierParent* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvClassifyLocal(const URIParams& aURI,
|
||||
const nsCString& aTables,
|
||||
nsCString* aResults) override;
|
||||
|
||||
// Use the PHangMonitor channel to ask the child to repaint a tab.
|
||||
void ForceTabPaint(TabParent* aTabParent, uint64_t aLayerObserverEpoch);
|
||||
|
||||
@ -913,14 +930,6 @@ private:
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvGetLookAndFeelCache(nsTArray<LookAndFeelInt>* aLookAndFeelIntCache) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvCreateFakeVolume(const nsString& aFsName,
|
||||
const nsString& aMountPoint) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvSetFakeVolumeState(const nsString& aFsName,
|
||||
const int32_t& aFsState) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvRemoveFakeVolume(const nsString& fsName) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvKeywordToURI(const nsCString& aKeyword,
|
||||
nsString* aProviderName,
|
||||
OptionalInputStreamParams* aPostData,
|
||||
@ -1065,10 +1074,6 @@ private:
|
||||
// through.
|
||||
bool mIsAlive;
|
||||
|
||||
// True only the if process is already a browser or has
|
||||
// been transformed into one.
|
||||
bool mMetamorphosed;
|
||||
|
||||
bool mSendPermissionUpdates;
|
||||
bool mIsForBrowser;
|
||||
|
||||
|
@ -46,6 +46,7 @@ include protocol PRemoteSpellcheckEngine;
|
||||
include protocol PWebBrowserPersistDocument;
|
||||
include protocol PWebrtcGlobal;
|
||||
include protocol PPresentation;
|
||||
include protocol PURLClassifier;
|
||||
include protocol PVRManager;
|
||||
include protocol PVideoDecoderManager;
|
||||
include protocol PFlyWebPublishedServer;
|
||||
@ -264,22 +265,6 @@ struct DataStorageItem {
|
||||
DataStorageType type;
|
||||
};
|
||||
|
||||
// Note: Any changes to this structure should also be changed in
|
||||
// FileSystemUpdate below.
|
||||
struct VolumeInfo {
|
||||
nsString name;
|
||||
nsString mountPoint;
|
||||
int32_t volState;
|
||||
int32_t mountGeneration;
|
||||
bool isMediaPresent;
|
||||
bool isSharing;
|
||||
bool isFormatting;
|
||||
bool isFake;
|
||||
bool isUnmounting;
|
||||
bool isRemovable;
|
||||
bool isHotSwappable;
|
||||
};
|
||||
|
||||
struct ClipboardCapabilities {
|
||||
bool supportsSelectionClipboard;
|
||||
bool supportsFindClipboard;
|
||||
@ -394,6 +379,7 @@ nested(upto inside_cpow) sync protocol PContent
|
||||
manages PWebrtcGlobal;
|
||||
manages PPresentation;
|
||||
manages PFlyWebPublishedServer;
|
||||
manages PURLClassifier;
|
||||
|
||||
both:
|
||||
// Depending on exactly how the new browser is being created, it might be
|
||||
@ -508,8 +494,6 @@ child:
|
||||
// nsIPermissionManager messages
|
||||
async AddPermission(Permission permission);
|
||||
|
||||
async Volumes(VolumeInfo[] volumes);
|
||||
|
||||
async FlushMemory(nsString reason);
|
||||
|
||||
async GarbageCollect();
|
||||
@ -547,16 +531,6 @@ child:
|
||||
async FilePathUpdate(nsString storageType, nsString storageName, nsString filepath,
|
||||
nsCString reasons);
|
||||
|
||||
// Note: Any changes to this structure should also be changed in
|
||||
// VolumeInfo above.
|
||||
async FileSystemUpdate(nsString fsName, nsString mountPoint, int32_t fsState,
|
||||
int32_t mountGeneration, bool isMediaPresent,
|
||||
bool isSharing, bool isFormatting, bool isFake,
|
||||
bool isUnmounting, bool isRemovable, bool isHotSwappable);
|
||||
|
||||
// Notify volume is removed.
|
||||
async VolumeRemoved(nsString fsName);
|
||||
|
||||
async NotifyProcessPriorityChanged(ProcessPriority priority);
|
||||
async MinimizeMemoryUsage();
|
||||
|
||||
@ -566,8 +540,6 @@ child:
|
||||
async LoadAndRegisterSheet(URIParams uri, uint32_t type);
|
||||
async UnregisterSheet(URIParams uri, uint32_t type);
|
||||
|
||||
async NotifyPhoneStateChange(nsString newState);
|
||||
|
||||
/**
|
||||
* Notify idle observers in the child
|
||||
*/
|
||||
@ -826,6 +798,11 @@ parent:
|
||||
|
||||
async PFlyWebPublishedServer(nsString name, FlyWebPublishOptions params);
|
||||
|
||||
sync PURLClassifier(Principal principal, bool useTrackingProtection)
|
||||
returns (bool success);
|
||||
sync ClassifyLocal(URIParams uri, nsCString tables)
|
||||
returns (nsCString results);
|
||||
|
||||
// Services remoting
|
||||
|
||||
async StartVisitedQuery(URIParams uri);
|
||||
@ -927,11 +904,6 @@ parent:
|
||||
nsString aFilepath,
|
||||
nsCString aReason);
|
||||
|
||||
// called by the child (test code only) to propagate volume changes to the parent
|
||||
async CreateFakeVolume(nsString fsName, nsString mountPoint);
|
||||
async SetFakeVolumeState(nsString fsName, int32_t fsState);
|
||||
async RemoveFakeVolume(nsString fsName);
|
||||
|
||||
sync KeywordToURI(nsCString keyword)
|
||||
returns (nsString providerName, OptionalInputStreamParams postData, OptionalURIParams uri);
|
||||
|
||||
|
29
dom/ipc/PURLClassifier.ipdl
Normal file
29
dom/ipc/PURLClassifier.ipdl
Normal file
@ -0,0 +1,29 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* 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/. */
|
||||
|
||||
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
|
||||
|
||||
include protocol PContent;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
union MaybeResult {
|
||||
nsresult;
|
||||
void_t;
|
||||
};
|
||||
|
||||
protocol PURLClassifier
|
||||
{
|
||||
manager PContent;
|
||||
|
||||
child:
|
||||
async __delete__(MaybeResult status);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
20
dom/ipc/URLClassifierChild.cpp
Normal file
20
dom/ipc/URLClassifierChild.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "URLClassifierChild.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
URLClassifierChild::Recv__delete__(const MaybeResult& aResult)
|
||||
{
|
||||
MOZ_ASSERT(mCallback);
|
||||
if (aResult.type() == MaybeResult::Tnsresult) {
|
||||
mCallback->OnClassifyComplete(aResult.get_nsresult());
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
36
dom/ipc/URLClassifierChild.h
Normal file
36
dom/ipc/URLClassifierChild.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_URLClassifierChild_h
|
||||
#define mozilla_dom_URLClassifierChild_h
|
||||
|
||||
#include "mozilla/dom/PURLClassifierChild.h"
|
||||
#include "nsIURIClassifier.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class URLClassifierChild : public PURLClassifierChild
|
||||
{
|
||||
public:
|
||||
URLClassifierChild() = default;
|
||||
|
||||
void SetCallback(nsIURIClassifierCallback* aCallback)
|
||||
{
|
||||
mCallback = aCallback;
|
||||
}
|
||||
mozilla::ipc::IPCResult Recv__delete__(const MaybeResult& aResult) override;
|
||||
|
||||
private:
|
||||
~URLClassifierChild() = default;
|
||||
|
||||
nsCOMPtr<nsIURIClassifierCallback> mCallback;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_URLClassifierChild_h
|
50
dom/ipc/URLClassifierParent.cpp
Normal file
50
dom/ipc/URLClassifierParent.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "URLClassifierParent.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
NS_IMPL_ISUPPORTS(URLClassifierParent, nsIURIClassifierCallback)
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
URLClassifierParent::StartClassify(nsIPrincipal* aPrincipal,
|
||||
bool aUseTrackingProtection,
|
||||
bool* aSuccess)
|
||||
{
|
||||
nsCOMPtr<nsIURIClassifier> uriClassifier =
|
||||
do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID);
|
||||
if (!uriClassifier) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
nsresult rv = uriClassifier->Classify(aPrincipal, aUseTrackingProtection,
|
||||
this, aSuccess);
|
||||
if (NS_FAILED(rv) || !*aSuccess) {
|
||||
// We treat the case where we fail to classify and the case where the
|
||||
// classifier returns successfully but doesn't perform a lookup as the
|
||||
// classification not yielding any results, so we just kill the child actor
|
||||
// without ever calling out callback in both cases.
|
||||
// This means that code using this in the child process will only get a hit
|
||||
// on its callback if some classification actually happens.
|
||||
Unused << Send__delete__(this, void_t());
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
nsresult
|
||||
URLClassifierParent::OnClassifyComplete(nsresult aRv)
|
||||
{
|
||||
Unused << Send__delete__(this, aRv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
URLClassifierParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
}
|
37
dom/ipc/URLClassifierParent.h
Normal file
37
dom/ipc/URLClassifierParent.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_URLClassifierParent_h
|
||||
#define mozilla_dom_URLClassifierParent_h
|
||||
|
||||
#include "mozilla/dom/PURLClassifierParent.h"
|
||||
#include "nsIURIClassifier.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class URLClassifierParent : public nsIURIClassifierCallback,
|
||||
public PURLClassifierParent
|
||||
{
|
||||
public:
|
||||
URLClassifierParent() = default;
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIURICLASSIFIERCALLBACK
|
||||
|
||||
mozilla::ipc::IPCResult StartClassify(nsIPrincipal* aPrincipal,
|
||||
bool aUseTrackingProtection,
|
||||
bool* aSuccess);
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
private:
|
||||
~URLClassifierParent() = default;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_URLClassifierParent_h
|
@ -36,6 +36,8 @@ EXPORTS.mozilla.dom += [
|
||||
'TabContext.h',
|
||||
'TabMessageUtils.h',
|
||||
'TabParent.h',
|
||||
'URLClassifierChild.h',
|
||||
'URLClassifierParent.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
@ -64,6 +66,8 @@ UNIFIED_SOURCES += [
|
||||
'TabContext.cpp',
|
||||
'TabMessageUtils.cpp',
|
||||
'TabParent.cpp',
|
||||
'URLClassifierChild.cpp',
|
||||
'URLClassifierParent.cpp',
|
||||
]
|
||||
|
||||
# Blob.cpp cannot be compiled in unified mode because it triggers a fatal gcc warning.
|
||||
@ -99,6 +103,7 @@ IPDL_SOURCES += [
|
||||
'PProcessHangMonitor.ipdl',
|
||||
'PScreenManager.ipdl',
|
||||
'PTabContext.ipdlh',
|
||||
'PURLClassifier.ipdl',
|
||||
'ServiceWorkerConfiguration.ipdlh',
|
||||
]
|
||||
|
||||
|
@ -63,18 +63,18 @@ public:
|
||||
using Promise = MozPromise<RefPtr<Token>, bool, true>;
|
||||
|
||||
// Acquire a token for decoder creation. Thread-safe.
|
||||
auto Alloc(TrackType aTrack) -> RefPtr<Promise>;
|
||||
auto Alloc() -> RefPtr<Promise>;
|
||||
|
||||
// Called by ClearOnShutdown() to delete the singleton.
|
||||
void operator=(decltype(nullptr));
|
||||
|
||||
// Get the singleton. Thread-safe.
|
||||
static DecoderAllocPolicy& Instance();
|
||||
// Get the singleton for the given track type. Thread-safe.
|
||||
static DecoderAllocPolicy& Instance(TrackType aTrack);
|
||||
|
||||
private:
|
||||
class AutoDeallocToken;
|
||||
using PromisePrivate = Promise::Private;
|
||||
DecoderAllocPolicy();
|
||||
explicit DecoderAllocPolicy(TrackType aTrack);
|
||||
~DecoderAllocPolicy();
|
||||
// Called by the destructor of TokenImpl to restore the decoder limit.
|
||||
void Dealloc();
|
||||
@ -87,6 +87,8 @@ private:
|
||||
ReentrantMonitor mMonitor;
|
||||
// The number of decoders available for creation.
|
||||
int mDecoderLimit;
|
||||
// Track type.
|
||||
const TrackType mTrack;
|
||||
// Requests to acquire tokens.
|
||||
std::queue<RefPtr<PromisePrivate>> mPromises;
|
||||
};
|
||||
@ -95,13 +97,24 @@ StaticMutex DecoderAllocPolicy::sMutex;
|
||||
|
||||
class DecoderAllocPolicy::AutoDeallocToken : public Token
|
||||
{
|
||||
public:
|
||||
explicit AutoDeallocToken(TrackType aTrack)
|
||||
: mTrack(aTrack)
|
||||
{}
|
||||
|
||||
private:
|
||||
~AutoDeallocToken() { DecoderAllocPolicy::Instance().Dealloc(); }
|
||||
~AutoDeallocToken()
|
||||
{
|
||||
DecoderAllocPolicy::Instance(mTrack).Dealloc();
|
||||
}
|
||||
|
||||
const TrackType mTrack;
|
||||
};
|
||||
|
||||
DecoderAllocPolicy::DecoderAllocPolicy()
|
||||
DecoderAllocPolicy::DecoderAllocPolicy(TrackType aTrack)
|
||||
: mMonitor("DecoderAllocPolicy::mMonitor")
|
||||
, mDecoderLimit(MediaPrefs::MediaDecoderLimit())
|
||||
, mTrack(aTrack)
|
||||
{
|
||||
AbstractThread::MainThread()->Dispatch(NS_NewRunnableFunction([this] () {
|
||||
ClearOnShutdown(this, ShutdownPhase::ShutdownThreads);
|
||||
@ -118,18 +131,23 @@ DecoderAllocPolicy::~DecoderAllocPolicy()
|
||||
}
|
||||
|
||||
DecoderAllocPolicy&
|
||||
DecoderAllocPolicy::Instance()
|
||||
DecoderAllocPolicy::Instance(TrackType aTrack)
|
||||
{
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
static auto sPolicy = new DecoderAllocPolicy();
|
||||
return *sPolicy;
|
||||
if (aTrack == TrackType::kAudioTrack) {
|
||||
static auto sAudioPolicy = new DecoderAllocPolicy(TrackType::kAudioTrack);
|
||||
return *sAudioPolicy;
|
||||
} else {
|
||||
static auto sVideoPolicy = new DecoderAllocPolicy(TrackType::kVideoTrack);
|
||||
return *sVideoPolicy;
|
||||
}
|
||||
}
|
||||
|
||||
auto
|
||||
DecoderAllocPolicy::Alloc(TrackType aTrack) -> RefPtr<Promise>
|
||||
DecoderAllocPolicy::Alloc() -> RefPtr<Promise>
|
||||
{
|
||||
// No limit for audio decoders or a negative number.
|
||||
if (aTrack == TrackInfo::kAudioTrack || mDecoderLimit < 0) {
|
||||
// No decoder limit set.
|
||||
if (mDecoderLimit < 0) {
|
||||
return Promise::CreateAndResolve(new Token(), __func__);
|
||||
}
|
||||
|
||||
@ -157,7 +175,7 @@ DecoderAllocPolicy::ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock)
|
||||
--mDecoderLimit;
|
||||
RefPtr<PromisePrivate> p = mPromises.front().forget();
|
||||
mPromises.pop();
|
||||
p->Resolve(new AutoDeallocToken(), __func__);
|
||||
p->Resolve(new AutoDeallocToken(mTrack), __func__);
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,7 +284,7 @@ MediaFormatReader::DecoderFactory::RunStage(TrackType aTrack)
|
||||
switch (data.mStage) {
|
||||
case Stage::None: {
|
||||
MOZ_ASSERT(!data.mToken);
|
||||
data.mTokenPromise.Begin(DecoderAllocPolicy::Instance().Alloc(aTrack)->Then(
|
||||
data.mTokenPromise.Begin(DecoderAllocPolicy::Instance(aTrack).Alloc()->Then(
|
||||
mOwner->OwnerThread(), __func__,
|
||||
[this, &data, aTrack] (Token* aToken) {
|
||||
data.mTokenPromise.Complete();
|
||||
|
@ -2079,8 +2079,14 @@ if (privileged) {
|
||||
(uint32_t) GetUserMediaSecurityState::Other);
|
||||
}
|
||||
|
||||
nsCString origin;
|
||||
rv = nsPrincipal::GetOriginForURI(docURI, origin);
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
nsGlobalWindow::Cast(aWindow)->GetPrincipal();
|
||||
if (NS_WARN_IF(!principal)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAutoCString origin;
|
||||
rv = principal->GetOrigin(origin);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -2236,7 +2242,6 @@ if (privileged) {
|
||||
StreamListeners* listeners = AddWindowID(windowID);
|
||||
|
||||
// Create a disabled listener to act as a placeholder
|
||||
nsIPrincipal* principal = aWindow->GetExtantDoc()->NodePrincipal();
|
||||
RefPtr<GetUserMediaCallbackMediaStreamListener> listener =
|
||||
new GetUserMediaCallbackMediaStreamListener(mMediaThread, windowID,
|
||||
MakePrincipalHandle(principal));
|
||||
@ -2492,8 +2497,12 @@ MediaManager::EnumerateDevicesImpl(uint64_t aWindowId,
|
||||
// 3. Anonymize the raw list with the origin-key.
|
||||
|
||||
bool privateBrowsing = IsPrivateBrowsing(window);
|
||||
nsCString origin;
|
||||
nsPrincipal::GetOriginForURI(window->GetDocumentURI(), origin);
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
nsGlobalWindow::Cast(window)->GetPrincipal();
|
||||
MOZ_ASSERT(principal);
|
||||
|
||||
nsAutoCString origin;
|
||||
principal->GetOrigin(origin);
|
||||
|
||||
bool persist = IsActivelyCapturingOrHasAPermission(aWindowId);
|
||||
|
||||
|
@ -1,522 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MediaManager.h"
|
||||
#include "MediaPermissionGonk.h"
|
||||
|
||||
#include "nsArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIContentPermissionPrompt.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMNavigatorUserMedia.h"
|
||||
#include "nsIStringEnumerator.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsTArray.h"
|
||||
#include "GetUserMediaRequest.h"
|
||||
#include "mozilla/dom/PBrowserChild.h"
|
||||
#include "mozilla/dom/MediaStreamTrackBinding.h"
|
||||
#include "mozilla/dom/MediaStreamError.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
|
||||
#define AUDIO_PERMISSION_NAME "audio-capture"
|
||||
#define VIDEO_PERMISSION_NAME "video-capture"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static MediaPermissionManager *gMediaPermMgr = nullptr;
|
||||
|
||||
static void
|
||||
CreateDeviceNameList(nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices,
|
||||
nsTArray<nsString> &aDeviceNameList)
|
||||
{
|
||||
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
|
||||
nsString name;
|
||||
nsresult rv = aDevices[i]->GetName(name);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
aDeviceNameList.AppendElement(name);
|
||||
}
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIMediaDevice>
|
||||
FindDeviceByName(nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices,
|
||||
const nsAString &aDeviceName)
|
||||
{
|
||||
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
|
||||
nsCOMPtr<nsIMediaDevice> device = aDevices[i];
|
||||
nsString deviceName;
|
||||
device->GetName(deviceName);
|
||||
if (deviceName.Equals(aDeviceName)) {
|
||||
return device.forget();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Helper function for notifying permission granted
|
||||
static nsresult
|
||||
NotifyPermissionAllow(const nsAString &aCallID, nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIMutableArray> array = nsArray::Create();
|
||||
|
||||
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
|
||||
rv = array->AppendElement(aDevices.ElementAt(i), /*weak =*/ false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
|
||||
|
||||
return obs->NotifyObservers(array, "getUserMedia:response:allow",
|
||||
aCallID.BeginReading());
|
||||
}
|
||||
|
||||
// Helper function for notifying permision denial or error
|
||||
static nsresult
|
||||
NotifyPermissionDeny(const nsAString &aCallID, const nsAString &aErrorMsg)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISupportsString> supportsString =
|
||||
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = supportsString->SetData(aErrorMsg);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
|
||||
|
||||
return obs->NotifyObservers(supportsString, "getUserMedia:response:deny",
|
||||
aCallID.BeginReading());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* MediaPermissionRequest will send a prompt ipdl request to b2g process according
|
||||
* to its owned type.
|
||||
*/
|
||||
class MediaPermissionRequest : public nsIContentPermissionRequest
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICONTENTPERMISSIONREQUEST
|
||||
|
||||
MediaPermissionRequest(RefPtr<dom::GetUserMediaRequest> &aRequest,
|
||||
nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices);
|
||||
|
||||
already_AddRefed<nsPIDOMWindowInner> GetOwner();
|
||||
|
||||
protected:
|
||||
virtual ~MediaPermissionRequest() {}
|
||||
|
||||
private:
|
||||
nsresult DoAllow(const nsString &audioDevice, const nsString &videoDevice);
|
||||
|
||||
bool mAudio; // Request for audio permission
|
||||
bool mVideo; // Request for video permission
|
||||
RefPtr<dom::GetUserMediaRequest> mRequest;
|
||||
nsTArray<nsCOMPtr<nsIMediaDevice> > mAudioDevices; // candidate audio devices
|
||||
nsTArray<nsCOMPtr<nsIMediaDevice> > mVideoDevices; // candidate video devices
|
||||
nsCOMPtr<nsIContentPermissionRequester> mRequester;
|
||||
};
|
||||
|
||||
// MediaPermissionRequest
|
||||
NS_IMPL_ISUPPORTS(MediaPermissionRequest, nsIContentPermissionRequest)
|
||||
|
||||
MediaPermissionRequest::MediaPermissionRequest(RefPtr<dom::GetUserMediaRequest> &aRequest,
|
||||
nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices)
|
||||
: mRequest(aRequest)
|
||||
{
|
||||
dom::MediaStreamConstraints constraints;
|
||||
mRequest->GetConstraints(constraints);
|
||||
|
||||
mAudio = !constraints.mAudio.IsBoolean() || constraints.mAudio.GetAsBoolean();
|
||||
mVideo = !constraints.mVideo.IsBoolean() || constraints.mVideo.GetAsBoolean();
|
||||
|
||||
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
|
||||
nsCOMPtr<nsIMediaDevice> device(aDevices[i]);
|
||||
nsAutoString deviceType;
|
||||
device->GetType(deviceType);
|
||||
if (mAudio && deviceType.EqualsLiteral("audio")) {
|
||||
mAudioDevices.AppendElement(device);
|
||||
}
|
||||
if (mVideo && deviceType.EqualsLiteral("video")) {
|
||||
mVideoDevices.AppendElement(device);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
|
||||
mRequester = new nsContentPermissionRequester(window);
|
||||
}
|
||||
|
||||
// nsIContentPermissionRequest methods
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionRequest::GetTypes(nsIArray** aTypes)
|
||||
{
|
||||
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||
//XXX append device list
|
||||
if (mAudio) {
|
||||
nsTArray<nsString> audioDeviceNames;
|
||||
CreateDeviceNameList(mAudioDevices, audioDeviceNames);
|
||||
nsCOMPtr<nsISupports> AudioType =
|
||||
new ContentPermissionType(NS_LITERAL_CSTRING(AUDIO_PERMISSION_NAME),
|
||||
NS_LITERAL_CSTRING("unused"),
|
||||
audioDeviceNames);
|
||||
types->AppendElement(AudioType, false);
|
||||
}
|
||||
if (mVideo) {
|
||||
nsTArray<nsString> videoDeviceNames;
|
||||
CreateDeviceNameList(mVideoDevices, videoDeviceNames);
|
||||
nsCOMPtr<nsISupports> VideoType =
|
||||
new ContentPermissionType(NS_LITERAL_CSTRING(VIDEO_PERMISSION_NAME),
|
||||
NS_LITERAL_CSTRING("unused"),
|
||||
videoDeviceNames);
|
||||
types->AppendElement(VideoType, false);
|
||||
}
|
||||
NS_IF_ADDREF(*aTypes = types);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRequestingPrincipal);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window =
|
||||
nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())->AsInner();
|
||||
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
|
||||
|
||||
NS_ADDREF(*aRequestingPrincipal = doc->NodePrincipal());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionRequest::GetWindow(mozIDOMWindow** aRequestingWindow)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRequestingWindow);
|
||||
nsCOMPtr<nsPIDOMWindowInner> window =
|
||||
nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())->AsInner();
|
||||
window.forget(aRequestingWindow);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionRequest::GetElement(nsIDOMElement** aRequestingElement)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRequestingElement);
|
||||
*aRequestingElement = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionRequest::Cancel()
|
||||
{
|
||||
nsString callID;
|
||||
mRequest->GetCallID(callID);
|
||||
NotifyPermissionDeny(callID, NS_LITERAL_STRING("SecurityError"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionRequest::Allow(JS::HandleValue aChoices)
|
||||
{
|
||||
// check if JS object
|
||||
if (!aChoices.isObject()) {
|
||||
MOZ_ASSERT(false, "Not a correct format of PermissionChoice");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
// iterate through audio-capture and video-capture
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(&aChoices.toObject())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> obj(cx, &aChoices.toObject());
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
|
||||
// get selected audio device name
|
||||
nsString audioDevice;
|
||||
if (mAudio) {
|
||||
if (!JS_GetProperty(cx, obj, AUDIO_PERMISSION_NAME, &v) || !v.isString()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsAutoJSString deviceName;
|
||||
if (!deviceName.init(cx, v)) {
|
||||
MOZ_ASSERT(false, "Couldn't initialize string from aChoices");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
audioDevice = deviceName;
|
||||
}
|
||||
|
||||
// get selected video device name
|
||||
nsString videoDevice;
|
||||
if (mVideo) {
|
||||
if (!JS_GetProperty(cx, obj, VIDEO_PERMISSION_NAME, &v) || !v.isString()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsAutoJSString deviceName;
|
||||
if (!deviceName.init(cx, v)) {
|
||||
MOZ_ASSERT(false, "Couldn't initialize string from aChoices");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
videoDevice = deviceName;
|
||||
}
|
||||
|
||||
return DoAllow(audioDevice, videoDevice);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionRequest::GetRequester(nsIContentPermissionRequester** aRequester)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRequester);
|
||||
|
||||
nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
|
||||
requester.forget(aRequester);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaPermissionRequest::DoAllow(const nsString &audioDevice,
|
||||
const nsString &videoDevice)
|
||||
{
|
||||
nsTArray<nsCOMPtr<nsIMediaDevice> > selectedDevices;
|
||||
if (mAudio) {
|
||||
nsCOMPtr<nsIMediaDevice> device =
|
||||
FindDeviceByName(mAudioDevices, audioDevice);
|
||||
if (device) {
|
||||
selectedDevices.AppendElement(device);
|
||||
}
|
||||
}
|
||||
|
||||
if (mVideo) {
|
||||
nsCOMPtr<nsIMediaDevice> device =
|
||||
FindDeviceByName(mVideoDevices, videoDevice);
|
||||
if (device) {
|
||||
selectedDevices.AppendElement(device);
|
||||
}
|
||||
}
|
||||
|
||||
nsString callID;
|
||||
mRequest->GetCallID(callID);
|
||||
return NotifyPermissionAllow(callID, selectedDevices);
|
||||
}
|
||||
|
||||
already_AddRefed<nsPIDOMWindowInner>
|
||||
MediaPermissionRequest::GetOwner()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowInner> window =
|
||||
nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())->AsInner();
|
||||
return window.forget();
|
||||
}
|
||||
|
||||
// Success callback for MediaManager::GetUserMediaDevices().
|
||||
class MediaDeviceSuccessCallback: public nsIGetUserMediaDevicesSuccessCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIGETUSERMEDIADEVICESSUCCESSCALLBACK
|
||||
|
||||
explicit MediaDeviceSuccessCallback(RefPtr<dom::GetUserMediaRequest> &aRequest)
|
||||
: mRequest(aRequest) {}
|
||||
|
||||
protected:
|
||||
virtual ~MediaDeviceSuccessCallback() {}
|
||||
|
||||
private:
|
||||
nsresult DoPrompt(RefPtr<MediaPermissionRequest> &req);
|
||||
RefPtr<dom::GetUserMediaRequest> mRequest;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(MediaDeviceSuccessCallback, nsIGetUserMediaDevicesSuccessCallback)
|
||||
|
||||
// nsIGetUserMediaDevicesSuccessCallback method
|
||||
NS_IMETHODIMP
|
||||
MediaDeviceSuccessCallback::OnSuccess(nsIVariant* aDevices)
|
||||
{
|
||||
nsIID elementIID;
|
||||
uint16_t elementType;
|
||||
void* rawArray;
|
||||
uint32_t arrayLen;
|
||||
|
||||
nsresult rv;
|
||||
rv = aDevices->GetAsArray(&elementType, &elementIID, &arrayLen, &rawArray);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (elementType != nsIDataType::VTYPE_INTERFACE) {
|
||||
free(rawArray);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Create array for nsIMediaDevice
|
||||
nsTArray<nsCOMPtr<nsIMediaDevice> > devices;
|
||||
|
||||
nsISupports **supportsArray = reinterpret_cast<nsISupports **>(rawArray);
|
||||
for (uint32_t i = 0; i < arrayLen; ++i) {
|
||||
nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supportsArray[i]));
|
||||
devices.AppendElement(device);
|
||||
NS_IF_RELEASE(supportsArray[i]); // explicitly decrease reference count for raw pointer
|
||||
}
|
||||
free(rawArray); // explicitly free for the memory from nsIVariant::GetAsArray
|
||||
|
||||
// Send MediaPermissionRequest
|
||||
RefPtr<MediaPermissionRequest> req = new MediaPermissionRequest(mRequest, devices);
|
||||
rv = DoPrompt(req);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Trigger permission prompt UI
|
||||
nsresult
|
||||
MediaDeviceSuccessCallback::DoPrompt(RefPtr<MediaPermissionRequest> &req)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowInner> window(req->GetOwner());
|
||||
return dom::nsContentPermissionUtils::AskPermission(req, window);
|
||||
}
|
||||
|
||||
// Error callback for MediaManager::GetUserMediaDevices()
|
||||
class MediaDeviceErrorCallback: public nsIDOMGetUserMediaErrorCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMGETUSERMEDIAERRORCALLBACK
|
||||
|
||||
explicit MediaDeviceErrorCallback(const nsAString &aCallID)
|
||||
: mCallID(aCallID) {}
|
||||
|
||||
protected:
|
||||
virtual ~MediaDeviceErrorCallback() {}
|
||||
|
||||
private:
|
||||
const nsString mCallID;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(MediaDeviceErrorCallback, nsIDOMGetUserMediaErrorCallback)
|
||||
|
||||
// nsIDOMGetUserMediaErrorCallback method
|
||||
NS_IMETHODIMP
|
||||
MediaDeviceErrorCallback::OnError(nsISupports* aError)
|
||||
{
|
||||
RefPtr<MediaStreamError> error = do_QueryObject(aError);
|
||||
if (!error) {
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
nsString name;
|
||||
error->GetName(name);
|
||||
return NotifyPermissionDeny(mCallID, name);
|
||||
}
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
// MediaPermissionManager
|
||||
NS_IMPL_ISUPPORTS(MediaPermissionManager, nsIObserver)
|
||||
|
||||
MediaPermissionManager*
|
||||
MediaPermissionManager::GetInstance()
|
||||
{
|
||||
if (!gMediaPermMgr) {
|
||||
gMediaPermMgr = new MediaPermissionManager();
|
||||
}
|
||||
|
||||
return gMediaPermMgr;
|
||||
}
|
||||
|
||||
MediaPermissionManager::MediaPermissionManager()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(this, "getUserMedia:request", false);
|
||||
obs->AddObserver(this, "xpcom-shutdown", false);
|
||||
}
|
||||
}
|
||||
|
||||
MediaPermissionManager::~MediaPermissionManager()
|
||||
{
|
||||
this->Deinit();
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaPermissionManager::Deinit()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->RemoveObserver(this, "getUserMedia:request");
|
||||
obs->RemoveObserver(this, "xpcom-shutdown");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIObserver method
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionManager::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
nsresult rv;
|
||||
if (!strcmp(aTopic, "getUserMedia:request")) {
|
||||
RefPtr<dom::GetUserMediaRequest> req =
|
||||
static_cast<dom::GetUserMediaRequest*>(aSubject);
|
||||
rv = HandleRequest(req);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
nsString callID;
|
||||
req->GetCallID(callID);
|
||||
NotifyPermissionDeny(callID, NS_LITERAL_STRING("unable to enumerate media device"));
|
||||
}
|
||||
} else if (!strcmp(aTopic, "xpcom-shutdown")) {
|
||||
rv = this->Deinit();
|
||||
} else {
|
||||
// not reachable
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Handle GetUserMediaRequest, query available media device first.
|
||||
nsresult
|
||||
MediaPermissionManager::HandleRequest(RefPtr<dom::GetUserMediaRequest> &req)
|
||||
{
|
||||
nsString callID;
|
||||
req->GetCallID(callID);
|
||||
uint64_t innerWindowID = req->InnerWindowID();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> innerWindow =
|
||||
nsGlobalWindow::GetInnerWindowWithId(innerWindowID)->AsInner();
|
||||
if (!innerWindow) {
|
||||
MOZ_ASSERT(false, "No inner window");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess =
|
||||
new MediaDeviceSuccessCallback(req);
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError =
|
||||
new MediaDeviceErrorCallback(callID);
|
||||
|
||||
dom::MediaStreamConstraints constraints;
|
||||
req->GetConstraints(constraints);
|
||||
|
||||
RefPtr<MediaManager> MediaMgr = MediaManager::GetInstance();
|
||||
nsresult rv = MediaMgr->GetUserMediaDevices(innerWindow, constraints,
|
||||
onSuccess, onError,
|
||||
innerWindowID, callID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -1,39 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef DOM_MEDIA_MEDIAPERMISSIONGONK_H
|
||||
#define DOM_MEDIA_MEDIAPERMISSIONGONK_H
|
||||
|
||||
#include "nsError.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "GetUserMediaRequest.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* The observer to create the MediaPermissionMgr. This is the entry point of
|
||||
* permission request on b2g.
|
||||
*/
|
||||
class MediaPermissionManager : public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static MediaPermissionManager* GetInstance();
|
||||
|
||||
protected:
|
||||
virtual ~MediaPermissionManager();
|
||||
|
||||
private:
|
||||
MediaPermissionManager();
|
||||
nsresult Deinit();
|
||||
nsresult HandleRequest(RefPtr<dom::GetUserMediaRequest> &req);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_MEDIA_MEDIAPERMISSIONGONK_H
|
||||
|
@ -714,35 +714,6 @@ private:
|
||||
return PrincipalSubsumes(principal);
|
||||
}
|
||||
|
||||
bool CheckPermission(const char* aType)
|
||||
{
|
||||
if (!mRecorder || !mRecorder->GetOwner()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
|
||||
if (!doc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Certified applications can always assign AUDIO_3GPP
|
||||
if (doc->NodePrincipal()->GetAppStatus() ==
|
||||
nsIPrincipal::APP_STATUS_CERTIFIED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> pm =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
|
||||
if (!pm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t perm = nsIPermissionManager::DENY_ACTION;
|
||||
pm->TestExactPermissionFromPrincipal(doc->NodePrincipal(), aType, &perm);
|
||||
return perm == nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
void InitEncoder(uint8_t aTrackTypes, TrackRate aTrackRate)
|
||||
{
|
||||
LOG(LogLevel::Debug, ("Session.InitEncoder %p", this));
|
||||
@ -755,26 +726,11 @@ private:
|
||||
// Allocate encoder and bind with union stream.
|
||||
// At this stage, the API doesn't allow UA to choose the output mimeType format.
|
||||
|
||||
// Make sure the application has permission to assign AUDIO_3GPP
|
||||
if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP) && CheckPermission("audio-capture:3gpp")) {
|
||||
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP),
|
||||
mRecorder->GetAudioBitrate(),
|
||||
mRecorder->GetVideoBitrate(),
|
||||
mRecorder->GetBitrate(),
|
||||
aTrackTypes, aTrackRate);
|
||||
} else if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP2) && CheckPermission("audio-capture:3gpp2")) {
|
||||
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP2),
|
||||
mRecorder->GetAudioBitrate(),
|
||||
mRecorder->GetVideoBitrate(),
|
||||
mRecorder->GetBitrate(),
|
||||
aTrackTypes, aTrackRate);
|
||||
} else {
|
||||
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""),
|
||||
mRecorder->GetAudioBitrate(),
|
||||
mRecorder->GetVideoBitrate(),
|
||||
mRecorder->GetBitrate(),
|
||||
aTrackTypes, aTrackRate);
|
||||
}
|
||||
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""),
|
||||
mRecorder->GetAudioBitrate(),
|
||||
mRecorder->GetVideoBitrate(),
|
||||
mRecorder->GetBitrate(),
|
||||
aTrackTypes, aTrackRate);
|
||||
|
||||
if (!mEncoder) {
|
||||
LOG(LogLevel::Debug, ("Session.InitEncoder !mEncoder %p", this));
|
||||
|
@ -94,7 +94,7 @@ mozilla::ipc::IPCResult
|
||||
VideoDecoderChild::RecvInitComplete(const bool& aHardware, const nsCString& aHardwareReason)
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
mInitPromise.Resolve(TrackInfo::kVideoTrack, __func__);
|
||||
mInitPromise.ResolveIfExists(TrackInfo::kVideoTrack, __func__);
|
||||
mInitialized = true;
|
||||
mIsHardwareAccelerated = aHardware;
|
||||
mHardwareAcceleratedReason = aHardwareReason;
|
||||
@ -105,7 +105,7 @@ mozilla::ipc::IPCResult
|
||||
VideoDecoderChild::RecvInitFailed(const nsresult& aReason)
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
mInitPromise.Reject(aReason, __func__);
|
||||
mInitPromise.RejectIfExists(aReason, __func__);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,7 @@ VideoDecoderParent::VideoDecoderParent(VideoDecoderManagerParent* aParent,
|
||||
, mDestroyed(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(VideoDecoderParent);
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
// We hold a reference to ourselves to keep us alive until IPDL
|
||||
// explictly destroys us. There may still be refs held by
|
||||
// tasks, but no new ones should be added after we're
|
||||
@ -91,6 +92,7 @@ VideoDecoderParent::~VideoDecoderParent()
|
||||
void
|
||||
VideoDecoderParent::Destroy()
|
||||
{
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
mDecodeTaskQueue->AwaitShutdownAndIdle();
|
||||
mDestroyed = true;
|
||||
mIPDLSelfRef = nullptr;
|
||||
@ -99,10 +101,11 @@ VideoDecoderParent::Destroy()
|
||||
mozilla::ipc::IPCResult
|
||||
VideoDecoderParent::RecvInit()
|
||||
{
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
RefPtr<VideoDecoderParent> self = this;
|
||||
mDecoder->Init()->Then(mManagerTaskQueue, __func__,
|
||||
[self] (TrackInfo::TrackType aTrack) {
|
||||
if (!self->mDestroyed) {
|
||||
if (self->mDecoder) {
|
||||
nsCString hardwareReason;
|
||||
bool hardwareAccelerated = self->mDecoder->IsHardwareAccelerated(hardwareReason);
|
||||
Unused << self->SendInitComplete(hardwareAccelerated, hardwareReason);
|
||||
@ -119,6 +122,7 @@ VideoDecoderParent::RecvInit()
|
||||
mozilla::ipc::IPCResult
|
||||
VideoDecoderParent::RecvInput(const MediaRawDataIPDL& aData)
|
||||
{
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
// XXX: This copies the data into a buffer owned by the MediaRawData. Ideally we'd just take ownership
|
||||
// of the shmem.
|
||||
RefPtr<MediaRawData> data = new MediaRawData(aData.buffer().get<uint8_t>(), aData.buffer().Size<uint8_t>());
|
||||
@ -138,6 +142,7 @@ mozilla::ipc::IPCResult
|
||||
VideoDecoderParent::RecvFlush()
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
if (mDecoder) {
|
||||
mDecoder->Flush();
|
||||
}
|
||||
@ -158,6 +163,7 @@ mozilla::ipc::IPCResult
|
||||
VideoDecoderParent::RecvDrain()
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
mDecoder->Drain();
|
||||
return IPC_OK();
|
||||
}
|
||||
@ -166,6 +172,7 @@ mozilla::ipc::IPCResult
|
||||
VideoDecoderParent::RecvShutdown()
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
if (mDecoder) {
|
||||
mDecoder->Shutdown();
|
||||
}
|
||||
@ -177,6 +184,7 @@ mozilla::ipc::IPCResult
|
||||
VideoDecoderParent::RecvSetSeekThreshold(const int64_t& aTime)
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
mDecoder->SetSeekThreshold(media::TimeUnit::FromMicroseconds(aTime));
|
||||
return IPC_OK();
|
||||
}
|
||||
@ -185,6 +193,7 @@ void
|
||||
VideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
if (mDecoder) {
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = nullptr;
|
||||
@ -278,6 +287,12 @@ VideoDecoderParent::OnReaderTaskQueue()
|
||||
// Most of our calls into mDecoder come directly from IPDL so are on
|
||||
// the right thread, but not actually on the task queue. We only ever
|
||||
// run a single thread, not a pool, so this should work fine.
|
||||
return OnManagerThread();
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderParent::OnManagerThread()
|
||||
{
|
||||
return mParent->OnManagerThread();
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,8 @@ public:
|
||||
bool OnReaderTaskQueue() override;
|
||||
|
||||
private:
|
||||
bool OnManagerThread();
|
||||
|
||||
~VideoDecoderParent();
|
||||
|
||||
RefPtr<VideoDecoderManagerParent> mParent;
|
||||
|
@ -166,11 +166,6 @@ IPDL_SOURCES += [
|
||||
'webrtc/PWebrtcGlobal.ipdl'
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_B2G']:
|
||||
EXPORTS.mozilla += [
|
||||
'MediaPermissionGonk.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'AudioStreamTrack.h',
|
||||
'AudioTrack.h',
|
||||
@ -267,11 +262,6 @@ UNIFIED_SOURCES += [
|
||||
if CONFIG['OS_TARGET'] == 'WINNT':
|
||||
SOURCES += [ 'ThreadPoolCOMListener.cpp' ]
|
||||
|
||||
if CONFIG['MOZ_B2G']:
|
||||
SOURCES += [
|
||||
'MediaPermissionGonk.cpp',
|
||||
]
|
||||
|
||||
# DecoderTraits.cpp needs to be built separately because of Mac OS X headers.
|
||||
SOURCES += [
|
||||
'DecoderTraits.cpp',
|
||||
|
@ -20,13 +20,6 @@ interface nsIVolumeService : nsISupports
|
||||
nsIArray getVolumeNames();
|
||||
|
||||
void Dump(in DOMString label);
|
||||
|
||||
/* for test case only to simulate sdcard insertion/removal */
|
||||
void createFakeVolume(in DOMString name, in DOMString path);
|
||||
void SetFakeVolumeState(in DOMString name, in long state);
|
||||
|
||||
/* for test case only to test removal of storage area */
|
||||
void removeFakeVolume(in DOMString name);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
@ -24,32 +24,8 @@ public:
|
||||
// This constructor is used by the UpdateVolumeRunnable constructor
|
||||
nsVolume(const Volume* aVolume);
|
||||
|
||||
// This constructor is used by nsVolumeService::SetFakeVolumeState
|
||||
nsVolume(const nsVolume* aVolume);
|
||||
|
||||
// This constructor is used by ContentChild::RecvFileSystemUpdate which is
|
||||
// used to update the volume cache maintained in the child process.
|
||||
nsVolume(const nsAString& aName, const nsAString& aMountPoint,
|
||||
const int32_t& aState, const int32_t& aMountGeneration,
|
||||
const bool& aIsMediaPresent, const bool& aIsSharing,
|
||||
const bool& aIsFormatting, const bool& aIsFake,
|
||||
const bool& aIsUnmounting, const bool& aIsRemovable,
|
||||
const bool& aIsHotSwappable)
|
||||
: mName(aName),
|
||||
mMountPoint(aMountPoint),
|
||||
mState(aState),
|
||||
mMountGeneration(aMountGeneration),
|
||||
mMountLocked(false),
|
||||
mIsFake(aIsFake),
|
||||
mIsMediaPresent(aIsMediaPresent),
|
||||
mIsSharing(aIsSharing),
|
||||
mIsFormatting(aIsFormatting),
|
||||
mIsUnmounting(aIsUnmounting),
|
||||
mIsRemovable(aIsRemovable),
|
||||
mIsHotSwappable(aIsHotSwappable)
|
||||
{
|
||||
}
|
||||
|
||||
bool Equals(nsIVolume* aVolume);
|
||||
void UpdateMountLock(nsVolume* aOldVolume);
|
||||
|
||||
|
@ -416,67 +416,6 @@ nsVolumeService::UpdateVolume(nsVolume* aVolume, bool aNotifyObservers)
|
||||
obs->NotifyObservers(aVolume, NS_VOLUME_STATE_CHANGED, stateStr.get());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsVolumeService::CreateFakeVolume(const nsAString& name, const nsAString& path)
|
||||
{
|
||||
if (XRE_IsParentProcess()) {
|
||||
RefPtr<nsVolume> vol = new nsVolume(name, path, nsIVolume::STATE_INIT,
|
||||
-1 /* mountGeneration */,
|
||||
true /* isMediaPresent */,
|
||||
false /* isSharing */,
|
||||
false /* isFormatting */,
|
||||
true /* isFake */,
|
||||
false /* isUnmounting */,
|
||||
false /* isRemovable */,
|
||||
false /* isHotSwappable */);
|
||||
vol->SetState(nsIVolume::STATE_MOUNTED);
|
||||
vol->LogState();
|
||||
UpdateVolume(vol.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ContentChild::GetSingleton()->SendCreateFakeVolume(nsString(name), nsString(path));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsVolumeService::SetFakeVolumeState(const nsAString& name, int32_t state)
|
||||
{
|
||||
if (XRE_IsParentProcess()) {
|
||||
RefPtr<nsVolume> vol;
|
||||
{
|
||||
MonitorAutoLock autoLock(mArrayMonitor);
|
||||
vol = FindVolumeByName(name);
|
||||
}
|
||||
if (!vol || !vol->IsFake()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Clone the existing volume so we can replace it
|
||||
RefPtr<nsVolume> volume = new nsVolume(vol);
|
||||
volume->SetState(state);
|
||||
volume->LogState();
|
||||
UpdateVolume(volume.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ContentChild::GetSingleton()->SendSetFakeVolumeState(nsString(name), state);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsVolumeService::RemoveFakeVolume(const nsAString& name)
|
||||
{
|
||||
if (XRE_IsParentProcess()) {
|
||||
SetFakeVolumeState(name, nsIVolume::STATE_NOMEDIA);
|
||||
RemoveVolumeByName(name);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ContentChild::GetSingleton()->SendRemoveFakeVolume(nsString(name));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsVolumeService::RemoveVolumeByName(const nsAString& aName)
|
||||
{
|
||||
|
@ -3,7 +3,6 @@ run-if = buildapp == 'b2g'
|
||||
|
||||
[test_geolocation.js]
|
||||
skip-if = true # Bug 808783
|
||||
[test_fakevolume.js]
|
||||
[test_ril_code_quality.py]
|
||||
[test_screen_state.js]
|
||||
[test_dsds_numRadioInterfaces.js]
|
||||
|
@ -1,25 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
|
||||
var Cc = SpecialPowers.Cc;
|
||||
var Ci = SpecialPowers.Ci;
|
||||
|
||||
var volumeService = Cc["@mozilla.org/telephony/volume-service;1"].getService(Ci.nsIVolumeService);
|
||||
ok(volumeService, "Should have volume service");
|
||||
|
||||
var volName = "fake";
|
||||
var mountPoint = "/data/fake/storage";
|
||||
volumeService.createFakeVolume(volName, mountPoint);
|
||||
|
||||
var vol = volumeService.getVolumeByName(volName);
|
||||
ok(vol, "volume shouldn't be null");
|
||||
|
||||
is(volName, vol.name, "name");
|
||||
is(mountPoint, vol.mountPoint, "moutnPoint");
|
||||
is(Ci.nsIVolume.STATE_MOUNTED, vol.state, "state");
|
||||
|
||||
ok(vol.mountGeneration > 0, "mount generation should not be zero");
|
||||
|
||||
finish();
|
@ -36,7 +36,8 @@ DrawEventRecorderPrivate::RecordEvent(const RecordedEvent &aEvent)
|
||||
}
|
||||
|
||||
DrawEventRecorderFile::DrawEventRecorderFile(const char *aFilename)
|
||||
: DrawEventRecorderPrivate(nullptr)
|
||||
: DrawEventRecorderPrivate(nullptr)
|
||||
, mOutputFilename(aFilename)
|
||||
, mOutputFile(aFilename, ofstream::binary)
|
||||
{
|
||||
mOutputStream = &mOutputFile;
|
||||
@ -55,6 +56,25 @@ DrawEventRecorderFile::Flush()
|
||||
mOutputFile.flush();
|
||||
}
|
||||
|
||||
void
|
||||
DrawEventRecorderFile::OpenAndTruncate()
|
||||
{
|
||||
if (mOutputFile.is_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mOutputFile.open(mOutputFilename.c_str(), ofstream::binary | ofstream::trunc);
|
||||
WriteHeader();
|
||||
}
|
||||
|
||||
void
|
||||
DrawEventRecorderFile::Close()
|
||||
{
|
||||
MOZ_ASSERT(mOutputFile.is_open());
|
||||
|
||||
mOutputFile.close();
|
||||
}
|
||||
|
||||
DrawEventRecorderMemory::DrawEventRecorderMemory()
|
||||
: DrawEventRecorderPrivate(nullptr)
|
||||
{
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "RecordedEvent.h"
|
||||
#include <ostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <unordered_set>
|
||||
@ -78,9 +79,24 @@ public:
|
||||
explicit DrawEventRecorderFile(const char *aFilename);
|
||||
~DrawEventRecorderFile();
|
||||
|
||||
/**
|
||||
* Re-opens and truncates the file. The recorder does NOT forget which objects
|
||||
* it has recorded. This can be used with Close, so that a recording can be
|
||||
* processed in chunks. If the file is already open this does nothing.
|
||||
*/
|
||||
void OpenAndTruncate();
|
||||
|
||||
/**
|
||||
* Closes the file so that it can be processed. The recorder does NOT forget
|
||||
* which objects it has recorded. This can be used with OpenAndTruncate, so
|
||||
* that a recording can be processed in chunks. The file must be open.
|
||||
*/
|
||||
void Close();
|
||||
|
||||
private:
|
||||
virtual void Flush();
|
||||
|
||||
std::string mOutputFilename;
|
||||
std::ofstream mOutputFile;
|
||||
};
|
||||
|
||||
|
@ -146,6 +146,9 @@ ClientLayerManager::Destroy()
|
||||
});
|
||||
NS_DispatchToMainThread(task.forget());
|
||||
}
|
||||
|
||||
// Forget the widget pointer in case we outlive our owning widget.
|
||||
mWidget = nullptr;
|
||||
}
|
||||
|
||||
int32_t
|
||||
|
@ -67,5 +67,54 @@ PrintTargetCG::CreateOrNull(CGContextRef aContext, const IntSize& aSize)
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
static size_t
|
||||
PutBytesNull(void* info, const void* buffer, size_t count)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
already_AddRefed<DrawTarget>
|
||||
PrintTargetCG::GetReferenceDrawTarget(DrawEventRecorder* aRecorder)
|
||||
{
|
||||
if (!mRefDT) {
|
||||
const IntSize size(1, 1);
|
||||
|
||||
CGDataConsumerCallbacks callbacks = {PutBytesNull, nullptr};
|
||||
CGDataConsumerRef consumer = CGDataConsumerCreate(nullptr, &callbacks);
|
||||
CGContextRef pdfContext = CGPDFContextCreate(consumer, nullptr, nullptr);
|
||||
CGDataConsumerRelease(consumer);
|
||||
|
||||
cairo_surface_t* similar =
|
||||
cairo_quartz_surface_create_for_cg_context(
|
||||
pdfContext, size.width, size.height);
|
||||
|
||||
CGContextRelease(pdfContext);
|
||||
|
||||
if (cairo_surface_status(similar)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> dt =
|
||||
Factory::CreateDrawTargetForCairoSurface(similar, size);
|
||||
|
||||
// The DT addrefs the surface, so we need drop our own reference to it:
|
||||
cairo_surface_destroy(similar);
|
||||
|
||||
if (!dt || !dt->IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aRecorder) {
|
||||
dt = CreateRecordingDrawTarget(aRecorder, dt);
|
||||
if (!dt || !dt->IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mRefDT = dt.forget();
|
||||
}
|
||||
return do_AddRef(mRefDT);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
@ -28,6 +28,9 @@ public:
|
||||
static already_AddRefed<PrintTargetCG>
|
||||
CreateOrNull(CGContextRef aContext, const IntSize& aSize);
|
||||
|
||||
virtual already_AddRefed<DrawTarget>
|
||||
GetReferenceDrawTarget(DrawEventRecorder* aRecorder) final;
|
||||
|
||||
private:
|
||||
PrintTargetCG(cairo_surface_t* aCairoSurface,
|
||||
const IntSize& aSize);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "frontend/BytecodeCompiler.h"
|
||||
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jsscript.h"
|
||||
@ -28,6 +29,7 @@
|
||||
using namespace js;
|
||||
using namespace js::frontend;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::Nothing;
|
||||
|
||||
class MOZ_STACK_CLASS AutoCompilationTraceLogger
|
||||
{
|
||||
@ -57,24 +59,24 @@ class MOZ_STACK_CLASS BytecodeCompiler
|
||||
|
||||
// Call setters for optional arguments.
|
||||
void maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor);
|
||||
void setSourceArgumentsNotIncluded();
|
||||
|
||||
JSScript* compileGlobalScript(ScopeKind scopeKind);
|
||||
JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
|
||||
ModuleObject* compileModule();
|
||||
bool compileFunctionBody(MutableHandleFunction fun, Handle<PropertyNameVector> formals,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
|
||||
bool compileStandaloneFunction(MutableHandleFunction fun, GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind,
|
||||
Maybe<uint32_t> parameterListEnd);
|
||||
|
||||
ScriptSourceObject* sourceObjectPtr() const;
|
||||
|
||||
private:
|
||||
JSScript* compileScript(HandleObject environment, SharedContext* sc);
|
||||
bool checkLength();
|
||||
bool createScriptSource();
|
||||
bool createScriptSource(Maybe<uint32_t> parameterListEnd);
|
||||
bool maybeCompressSource();
|
||||
bool canLazilyParse();
|
||||
bool createParser();
|
||||
bool createSourceAndParser();
|
||||
bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
|
||||
bool createScript();
|
||||
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
|
||||
bool handleParseFailure(const Directives& newDirectives);
|
||||
@ -90,7 +92,6 @@ class MOZ_STACK_CLASS BytecodeCompiler
|
||||
SourceBufferHolder& sourceBuffer;
|
||||
|
||||
RootedScope enclosingScope;
|
||||
bool sourceArgumentsNotIncluded;
|
||||
|
||||
RootedScriptSource sourceObject;
|
||||
ScriptSource* scriptSource;
|
||||
@ -130,7 +131,6 @@ BytecodeCompiler::BytecodeCompiler(ExclusiveContext* cx,
|
||||
options(options),
|
||||
sourceBuffer(sourceBuffer),
|
||||
enclosingScope(cx, enclosingScope),
|
||||
sourceArgumentsNotIncluded(false),
|
||||
sourceObject(cx),
|
||||
scriptSource(nullptr),
|
||||
sourceCompressor(nullptr),
|
||||
@ -147,12 +147,6 @@ BytecodeCompiler::maybeSetSourceCompressor(SourceCompressionTask* sourceCompress
|
||||
this->sourceCompressor = sourceCompressor;
|
||||
}
|
||||
|
||||
void
|
||||
BytecodeCompiler::setSourceArgumentsNotIncluded()
|
||||
{
|
||||
sourceArgumentsNotIncluded = true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeCompiler::checkLength()
|
||||
{
|
||||
@ -169,12 +163,12 @@ BytecodeCompiler::checkLength()
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeCompiler::createScriptSource()
|
||||
BytecodeCompiler::createScriptSource(Maybe<uint32_t> parameterListEnd)
|
||||
{
|
||||
if (!checkLength())
|
||||
return false;
|
||||
|
||||
sourceObject = CreateScriptSourceObject(cx, options);
|
||||
sourceObject = CreateScriptSourceObject(cx, options, parameterListEnd);
|
||||
if (!sourceObject)
|
||||
return false;
|
||||
|
||||
@ -193,9 +187,7 @@ BytecodeCompiler::maybeCompressSource()
|
||||
if (!cx->compartment()->behaviors().discardSource()) {
|
||||
if (options.sourceIsLazy) {
|
||||
scriptSource->setSourceRetrievable();
|
||||
} else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceArgumentsNotIncluded,
|
||||
sourceCompressor))
|
||||
{
|
||||
} else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceCompressor)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -242,9 +234,9 @@ BytecodeCompiler::createParser()
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeCompiler::createSourceAndParser()
|
||||
BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = Nothing() */)
|
||||
{
|
||||
return createScriptSource() &&
|
||||
return createScriptSource(parameterListEnd) &&
|
||||
maybeCompressSource() &&
|
||||
createParser();
|
||||
}
|
||||
@ -432,18 +424,19 @@ BytecodeCompiler::compileModule()
|
||||
return module;
|
||||
}
|
||||
|
||||
// Compile a standalone JS function, which might appear as the value of an
|
||||
// event handler attribute in an HTML <INPUT> tag, or in a Function()
|
||||
// constructor.
|
||||
bool
|
||||
BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
|
||||
Handle<PropertyNameVector> formals,
|
||||
GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind)
|
||||
BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
|
||||
GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind,
|
||||
Maybe<uint32_t> parameterListEnd)
|
||||
{
|
||||
MOZ_ASSERT(fun);
|
||||
MOZ_ASSERT(fun->isTenured());
|
||||
|
||||
fun->setArgCount(formals.length());
|
||||
|
||||
if (!createSourceAndParser())
|
||||
if (!createSourceAndParser(parameterListEnd))
|
||||
return false;
|
||||
|
||||
// Speculatively parse using the default directives implied by the context.
|
||||
@ -454,8 +447,8 @@ BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
|
||||
ParseNode* fn;
|
||||
do {
|
||||
Directives newDirectives = directives;
|
||||
fn = parser->standaloneFunctionBody(fun, enclosingScope, formals, generatorKind, asyncKind,
|
||||
directives, &newDirectives);
|
||||
fn = parser->standaloneFunction(fun, enclosingScope, parameterListEnd, generatorKind,
|
||||
asyncKind, directives, &newDirectives);
|
||||
if (!fn && !handleParseFailure(newDirectives))
|
||||
return false;
|
||||
} while (!fn);
|
||||
@ -492,14 +485,15 @@ BytecodeCompiler::sourceObjectPtr() const
|
||||
}
|
||||
|
||||
ScriptSourceObject*
|
||||
frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
|
||||
frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
|
||||
Maybe<uint32_t> parameterListEnd /* = Nothing() */)
|
||||
{
|
||||
ScriptSource* ss = cx->new_<ScriptSource>();
|
||||
if (!ss)
|
||||
return nullptr;
|
||||
ScriptSourceHolder ssHolder(ss);
|
||||
|
||||
if (!ss->initFromOptions(cx, options))
|
||||
if (!ss->initFromOptions(cx, options, parameterListEnd))
|
||||
return nullptr;
|
||||
|
||||
RootedScriptSource sso(cx, ScriptSourceObject::create(cx, ss));
|
||||
@ -676,63 +670,44 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
|
||||
return bce.emitFunctionScript(pn->pn_body);
|
||||
}
|
||||
|
||||
// Compile a JS function body, which might appear as the value of an event
|
||||
// handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
|
||||
static bool
|
||||
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options,
|
||||
Handle<PropertyNameVector> formals, SourceBufferHolder& srcBuf,
|
||||
HandleScope enclosingScope, GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind)
|
||||
bool
|
||||
frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
Maybe<uint32_t> parameterListEnd,
|
||||
HandleScope enclosingScope /* = nullptr */)
|
||||
{
|
||||
MOZ_ASSERT(!options.isRunOnce);
|
||||
RootedScope scope(cx, enclosingScope);
|
||||
if (!scope)
|
||||
scope = &cx->global()->emptyGlobalScope();
|
||||
|
||||
// FIXME: make Function pass in two strings and parse them as arguments and
|
||||
// ProgramElements respectively.
|
||||
|
||||
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, enclosingScope,
|
||||
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, scope,
|
||||
TraceLogger_ParserCompileFunction);
|
||||
compiler.setSourceArgumentsNotIncluded();
|
||||
return compiler.compileFunctionBody(fun, formals, generatorKind, asyncKind);
|
||||
return compiler.compileStandaloneFunction(fun, NotGenerator, SyncFunction, parameterListEnd);
|
||||
}
|
||||
|
||||
bool
|
||||
frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
|
||||
HandleScope enclosingScope)
|
||||
{
|
||||
return CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingScope, NotGenerator,
|
||||
SyncFunction);
|
||||
}
|
||||
|
||||
bool
|
||||
frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf)
|
||||
frontend::CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
Maybe<uint32_t> parameterListEnd)
|
||||
{
|
||||
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
|
||||
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
|
||||
NotGenerator, SyncFunction);
|
||||
|
||||
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
|
||||
TraceLogger_ParserCompileFunction);
|
||||
return compiler.compileStandaloneFunction(fun, StarGenerator, SyncFunction, parameterListEnd);
|
||||
}
|
||||
|
||||
bool
|
||||
frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
Handle<PropertyNameVector> formals,
|
||||
JS::SourceBufferHolder& srcBuf)
|
||||
frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
Maybe<uint32_t> parameterListEnd)
|
||||
{
|
||||
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
|
||||
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
|
||||
StarGenerator, SyncFunction);
|
||||
}
|
||||
|
||||
bool
|
||||
frontend::CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
Handle<PropertyNameVector> formals,
|
||||
JS::SourceBufferHolder& srcBuf)
|
||||
{
|
||||
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
|
||||
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
|
||||
StarGenerator, AsyncFunction);
|
||||
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
|
||||
TraceLogger_ParserCompileFunction);
|
||||
return compiler.compileStandaloneFunction(fun, StarGenerator, AsyncFunction, parameterListEnd);
|
||||
}
|
||||
|
@ -7,6 +7,8 @@
|
||||
#ifndef frontend_BytecodeCompiler_h
|
||||
#define frontend_BytecodeCompiler_h
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
#include "vm/Scope.h"
|
||||
@ -51,22 +53,36 @@ CompileModule(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
|
||||
MOZ_MUST_USE bool
|
||||
CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);
|
||||
|
||||
//
|
||||
// Compile a single function. The source in srcBuf must match the ECMA-262
|
||||
// FunctionExpression production.
|
||||
//
|
||||
// If nonzero, parameterListEnd is the offset within srcBuf where the parameter
|
||||
// list is expected to end. During parsing, if we find that it ends anywhere
|
||||
// else, it's a SyntaxError. This is used to implement the Function constructor;
|
||||
// it's how we detect that these weird cases are SyntaxErrors:
|
||||
//
|
||||
// Function("/*", "*/x) {")
|
||||
// Function("x){ if (3", "return x;}")
|
||||
//
|
||||
MOZ_MUST_USE bool
|
||||
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
|
||||
HandleScope enclosingScope);
|
||||
|
||||
// As above, but defaults to the global lexical scope as the enclosing scope.
|
||||
MOZ_MUST_USE bool
|
||||
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
|
||||
CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
mozilla::Maybe<uint32_t> parameterListEnd,
|
||||
HandleScope enclosingScope = nullptr);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
|
||||
CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
mozilla::Maybe<uint32_t> parameterListEnd);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
mozilla::Maybe<uint32_t> parameterListEnd);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
@ -74,7 +90,8 @@ CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
|
||||
|
||||
ScriptSourceObject*
|
||||
CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options);
|
||||
CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
|
||||
mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
|
||||
|
||||
/*
|
||||
* True if str consists of an IdentifierStart character, followed by one or
|
||||
|
@ -2279,13 +2279,13 @@ GetYieldHandling(GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
|
||||
|
||||
template <>
|
||||
ParseNode*
|
||||
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
|
||||
HandleScope enclosingScope,
|
||||
Handle<PropertyNameVector> formals,
|
||||
GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind,
|
||||
Directives inheritedDirectives,
|
||||
Directives* newDirectives)
|
||||
Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
|
||||
HandleScope enclosingScope,
|
||||
Maybe<uint32_t> parameterListEnd,
|
||||
GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind,
|
||||
Directives inheritedDirectives,
|
||||
Directives* newDirectives)
|
||||
{
|
||||
MOZ_ASSERT(checkOptionsCalled);
|
||||
|
||||
@ -2308,25 +2308,14 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
|
||||
if (!funpc.init())
|
||||
return null();
|
||||
funpc.setIsStandaloneFunctionBody();
|
||||
funpc.functionScope().useAsVarScope(&funpc);
|
||||
|
||||
if (formals.length() >= ARGNO_LIMIT) {
|
||||
error(JSMSG_TOO_MANY_FUN_ARGS);
|
||||
return null();
|
||||
}
|
||||
|
||||
bool duplicatedParam = false;
|
||||
for (uint32_t i = 0; i < formals.length(); i++) {
|
||||
if (!notePositionalFormalParameter(fn, formals[i], false, &duplicatedParam))
|
||||
return null();
|
||||
}
|
||||
funbox->hasDuplicateParameters = duplicatedParam;
|
||||
|
||||
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
|
||||
AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction);
|
||||
ParseNode* pn = functionBody(InAllowed, yieldHandling, Statement, StatementListBody);
|
||||
if (!pn)
|
||||
if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement,
|
||||
parameterListEnd))
|
||||
{
|
||||
return null();
|
||||
}
|
||||
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
@ -2336,15 +2325,7 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
|
||||
return null();
|
||||
}
|
||||
|
||||
if (!FoldConstants(context, &pn, this))
|
||||
return null();
|
||||
|
||||
fn->pn_pos.end = pos().end;
|
||||
|
||||
MOZ_ASSERT(fn->pn_body->isKind(PNK_PARAMSBODY));
|
||||
fn->pn_body->append(pn);
|
||||
|
||||
if (!finishFunction())
|
||||
if (!FoldConstants(context, &fn, this))
|
||||
return null();
|
||||
|
||||
return fn;
|
||||
@ -3396,7 +3377,8 @@ template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
|
||||
YieldHandling yieldHandling,
|
||||
Node pn, FunctionSyntaxKind kind)
|
||||
Node pn, FunctionSyntaxKind kind,
|
||||
Maybe<uint32_t> parameterListEnd /* = Nothing() */)
|
||||
{
|
||||
// Given a properly initialized parse context, try to parse an actual
|
||||
// function without concern for conversion to strict mode, use of lazy
|
||||
@ -3428,6 +3410,13 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
|
||||
}
|
||||
}
|
||||
|
||||
// When parsing something for new Function() we have to make sure to
|
||||
// only treat a certain part of the source as a parameter list.
|
||||
if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) {
|
||||
error(JSMSG_UNEXPECTED_PARAMLIST_END);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the function body.
|
||||
FunctionBodyType bodyType = StatementListBody;
|
||||
TokenKind tt;
|
||||
@ -3483,7 +3472,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
|
||||
error(JSMSG_CURLY_AFTER_BODY);
|
||||
return false;
|
||||
}
|
||||
funbox->bufEnd = pos().begin + 1;
|
||||
funbox->bufEnd = pos().end;
|
||||
} else {
|
||||
#if !JS_HAS_EXPR_CLOSURES
|
||||
MOZ_ASSERT(kind == Arrow);
|
||||
|
@ -1050,12 +1050,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||
// Parse a module.
|
||||
Node moduleBody(ModuleSharedContext* modulesc);
|
||||
|
||||
// Parse a function, given only its body. Used for the Function and
|
||||
// Generator constructors.
|
||||
Node standaloneFunctionBody(HandleFunction fun, HandleScope enclosingScope,
|
||||
Handle<PropertyNameVector> formals,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
Directives inheritedDirectives, Directives* newDirectives);
|
||||
// Parse a function, used for the Function, GeneratorFunction, and
|
||||
// AsyncFunction constructors.
|
||||
Node standaloneFunction(HandleFunction fun, HandleScope enclosingScope,
|
||||
mozilla::Maybe<uint32_t> parameterListEnd,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
Directives inheritedDirectives, Directives* newDirectives);
|
||||
|
||||
// Parse a function, given only its arguments and body. Used for lazily
|
||||
// parsed functions.
|
||||
@ -1071,7 +1071,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||
// Parse a function's formal parameters and its body assuming its function
|
||||
// ParseContext is already on the stack.
|
||||
bool functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling,
|
||||
Node pn, FunctionSyntaxKind kind);
|
||||
Node pn, FunctionSyntaxKind kind,
|
||||
mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
|
||||
|
||||
// Determine whether |yield| is a valid name in the current context, or
|
||||
// whether it's prohibited due to strictness, JS version, or occurrence
|
||||
|
@ -947,7 +947,8 @@ class GCRuntime
|
||||
|
||||
void requestMajorGC(JS::gcreason::Reason reason);
|
||||
SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis);
|
||||
void budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& lock);
|
||||
void budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget,
|
||||
AutoLockForExclusiveAccess& lock);
|
||||
void resetIncrementalGC(AbortReason reason, AutoLockForExclusiveAccess& lock);
|
||||
|
||||
// Assert if the system state is such that we should never
|
||||
@ -962,6 +963,7 @@ class GCRuntime
|
||||
void collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) JS_HAZ_GC_CALL;
|
||||
MOZ_MUST_USE bool gcCycle(bool nonincrementalByAPI, SliceBudget& budget,
|
||||
JS::gcreason::Reason reason);
|
||||
bool shouldRepeatForDeadZone(JS::gcreason::Reason reason);
|
||||
void incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason,
|
||||
AutoLockForExclusiveAccess& lock);
|
||||
|
||||
|
@ -84,10 +84,7 @@ function testArgumentFunction(pattern, input) {
|
||||
'return [a, b, c, d, e, f];'
|
||||
)(input);
|
||||
}
|
||||
// XXX: ES6 requires the `Function` constructor to accept arbitrary
|
||||
// `BindingElement`s as formal parameters. See Bug 1037939.
|
||||
// Once fixed, please update the assertions below.
|
||||
assertThrowsInstanceOf(() => testAll(testArgumentFunction), SyntaxError);
|
||||
testAll(testArgumentFunction);
|
||||
|
||||
function testThrow(pattern, input) {
|
||||
return new Function('input',
|
||||
|
@ -132,10 +132,9 @@ function testArgumentFunction(pattern, input, binding) {
|
||||
'return ' + binding
|
||||
)(input);
|
||||
}
|
||||
// XXX: ES6 requires the `Function` constructor to accept arbitrary
|
||||
// `BindingElement`s as formal parameters. See Bug 1037939.
|
||||
// Once fixed, please update the assertions below.
|
||||
assertThrowsInstanceOf(() => testDeclaration(testArgumentFunction), SyntaxError);
|
||||
// ES6 requires the `Function` constructor to accept arbitrary
|
||||
// `BindingElement`s as formal parameters.
|
||||
testDeclaration(testArgumentFunction);
|
||||
|
||||
function testThrow(pattern, input, binding) {
|
||||
binding = binding || 'rest';
|
||||
|
@ -4,6 +4,14 @@ const prototypes = [
|
||||
WeakMap.prototype,
|
||||
WeakSet.prototype,
|
||||
Date.prototype,
|
||||
Error.prototype,
|
||||
InternalError.prototype,
|
||||
EvalError.prototype,
|
||||
RangeError.prototype,
|
||||
ReferenceError.prototype,
|
||||
SyntaxError.prototype,
|
||||
TypeError.prototype,
|
||||
URIError.prototype,
|
||||
];
|
||||
|
||||
for (const prototype of prototypes) {
|
||||
|
@ -10,5 +10,5 @@ assertEq(arr.length, 10);
|
||||
gc();
|
||||
|
||||
for (var i = 0; i < arr.length; i++)
|
||||
assertEq(arr[i].lineCount, 1);
|
||||
assertEq(arr[i].lineCount, 3);
|
||||
|
||||
|
@ -10,6 +10,6 @@ assertEq(arr.length, 100);
|
||||
gc(g);
|
||||
|
||||
for (var i = 0; i < arr.length; i++)
|
||||
assertEq(arr[i].lineCount, 1);
|
||||
assertEq(arr[i].lineCount, 3);
|
||||
|
||||
gc();
|
||||
|
@ -20,6 +20,6 @@ function test(string, range) {
|
||||
}
|
||||
|
||||
test("eval('2 * 3')", [0, 5]);
|
||||
test("new Function('2 * 3')", [0, 5]);
|
||||
test("new Function('x', 'x * x')", [0, 5]);
|
||||
test("new Function('2 * 3')", [0, 12]);
|
||||
test("new Function('x', 'x * x')", [0, 13]);
|
||||
assertEq(count, 6);
|
||||
|
@ -92,9 +92,11 @@ var e = wasmEvalText('(module (func $i2v (param i32)) (export "i2v" $i2v) (func
|
||||
var i2vm = new Module(wasmTextToBinary('(module (import "a" "b" (param i32)))'));
|
||||
var f2vm = new Module(wasmTextToBinary('(module (import "a" "b" (param f32)))'));
|
||||
assertEq(new Instance(i2vm, {a:{b:e.i2v}}) instanceof Instance, true);
|
||||
assertErrorMessage(() => new Instance(i2vm, {a:{b:e.f2v}}), TypeError, /imported function signature mismatch/);
|
||||
assertErrorMessage(() => new Instance(f2vm, {a:{b:e.i2v}}), TypeError, /imported function signature mismatch/);
|
||||
assertErrorMessage(() => new Instance(i2vm, {a:{b:e.f2v}}), TypeError, /imported function 'a.b' signature mismatch/);
|
||||
assertErrorMessage(() => new Instance(f2vm, {a:{b:e.i2v}}), TypeError, /imported function 'a.b' signature mismatch/);
|
||||
assertEq(new Instance(f2vm, {a:{b:e.f2v}}) instanceof Instance, true);
|
||||
var l2vm = new Module(wasmTextToBinary('(module (import "x" "y" (memory 1)) (import "c" "d" (param i64)))'));
|
||||
assertErrorMessage(() => new Instance(l2vm, {x:{y:mem1Page}, c:{d:e.i2v}}), TypeError, /imported function 'c.d' signature mismatch/);
|
||||
|
||||
// Import order:
|
||||
|
||||
|
@ -3112,6 +3112,11 @@ MBinaryArithInstruction::constantDoubleResult(TempAllocator& alloc)
|
||||
MDefinition*
|
||||
MRsh::foldsTo(TempAllocator& alloc)
|
||||
{
|
||||
MDefinition* f = MBinaryBitwiseInstruction::foldsTo(alloc);
|
||||
|
||||
if (f != this)
|
||||
return f;
|
||||
|
||||
MDefinition* lhs = getOperand(0);
|
||||
MDefinition* rhs = getOperand(1);
|
||||
|
||||
|
@ -332,6 +332,7 @@ MSG_DEF(JSMSG_TOO_MANY_LOCALS, 0, JSEXN_SYNTAXERR, "too many local varia
|
||||
MSG_DEF(JSMSG_TOO_MANY_YIELDS, 0, JSEXN_SYNTAXERR, "too many yield expressions")
|
||||
MSG_DEF(JSMSG_TOUGH_BREAK, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch")
|
||||
MSG_DEF(JSMSG_UNEXPECTED_TOKEN, 2, JSEXN_SYNTAXERR, "expected {0}, got {1}")
|
||||
MSG_DEF(JSMSG_UNEXPECTED_PARAMLIST_END,0, JSEXN_SYNTAXERR, "unexpected end of function parameter list")
|
||||
MSG_DEF(JSMSG_UNNAMED_CLASS_STMT, 0, JSEXN_SYNTAXERR, "class statement requires a name")
|
||||
MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name")
|
||||
MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 0, JSEXN_SYNTAXERR, "unterminated comment")
|
||||
@ -377,7 +378,7 @@ MSG_DEF(JSMSG_WASM_BAD_IMP_MAX, 1, JSEXN_TYPEERR, "imported {0} with
|
||||
MSG_DEF(JSMSG_WASM_BAD_ELEMENT, 0, JSEXN_TYPEERR, "\"element\" property of table descriptor must be \"anyfunc\"")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument must be an object")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD, 2, JSEXN_TYPEERR, "import object field '{0}' is not {1}")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG, 0, JSEXN_TYPEERR, "imported function signature mismatch")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG, 2, JSEXN_TYPEERR, "imported function '{0}.{1}' signature mismatch")
|
||||
MSG_DEF(JSMSG_WASM_BAD_TABLE_VALUE, 0, JSEXN_TYPEERR, "can only assign WebAssembly exported functions to Table")
|
||||
MSG_DEF(JSMSG_WASM_BAD_I64, 0, JSEXN_TYPEERR, "cannot pass i64 to or from JS")
|
||||
MSG_DEF(JSMSG_WASM_NO_TRANSFER, 0, JSEXN_TYPEERR, "cannot transfer WebAssembly/asm.js ArrayBuffer")
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "jsapi.h"
|
||||
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
|
||||
@ -107,6 +108,7 @@ using namespace js::gc;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::PodCopy;
|
||||
using mozilla::PodZero;
|
||||
using mozilla::Some;
|
||||
|
||||
using JS::AutoGCRooter;
|
||||
using JS::ToInt32;
|
||||
@ -4205,15 +4207,15 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun)
|
||||
}
|
||||
|
||||
/*
|
||||
* enclosingScope is a static enclosing scope, if any (e.g. a WithScope). If
|
||||
* the enclosing scope is the global scope, this must be null.
|
||||
* enclosingScope is a scope, if any (e.g. a WithScope). If the scope is the
|
||||
* global scope, this must be null.
|
||||
*
|
||||
* enclosingDynamicScope is a dynamic scope to use, if it's not the global.
|
||||
* enclosingEnv is an environment to use, if it's not the global.
|
||||
*/
|
||||
static bool
|
||||
CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
||||
const char* name, unsigned nargs, const char* const* argnames,
|
||||
SourceBufferHolder& srcBuf,
|
||||
const char* name,
|
||||
SourceBufferHolder& srcBuf, uint32_t parameterListEnd,
|
||||
HandleObject enclosingEnv, HandleScope enclosingScope,
|
||||
MutableHandleFunction fun)
|
||||
{
|
||||
@ -4229,13 +4231,6 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
||||
return false;
|
||||
}
|
||||
|
||||
Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
|
||||
for (unsigned i = 0; i < nargs; i++) {
|
||||
RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i])));
|
||||
if (!argAtom || !formals.append(argAtom->asPropertyName()))
|
||||
return false;
|
||||
}
|
||||
|
||||
fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom,
|
||||
/* proto = */ nullptr,
|
||||
gc::AllocKind::FUNCTION, TenuredObject,
|
||||
@ -4248,7 +4243,45 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
||||
MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(enclosingEnv),
|
||||
enclosingScope->hasOnChain(ScopeKind::NonSyntactic));
|
||||
|
||||
if (!frontend::CompileFunctionBody(cx, fun, optionsArg, formals, srcBuf, enclosingScope))
|
||||
if (!frontend::CompileStandaloneFunction(cx, fun, optionsArg, srcBuf,
|
||||
Some(parameterListEnd), enclosingScope))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE bool
|
||||
BuildFunctionString(unsigned nargs, const char* const* argnames,
|
||||
const SourceBufferHolder& srcBuf, StringBuffer* out,
|
||||
uint32_t* parameterListEnd)
|
||||
{
|
||||
MOZ_ASSERT(out);
|
||||
MOZ_ASSERT(parameterListEnd);
|
||||
|
||||
if (!out->ensureTwoByteChars())
|
||||
return false;
|
||||
if (!out->append("("))
|
||||
return false;
|
||||
for (unsigned i = 0; i < nargs; i++) {
|
||||
if (i != 0) {
|
||||
if (!out->append(", "))
|
||||
return false;
|
||||
}
|
||||
if (!out->append(argnames[i], strlen(argnames[i])))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remember the position of ")".
|
||||
*parameterListEnd = out->length();
|
||||
MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
|
||||
|
||||
if (!out->append(FunctionConstructorMedialSigils))
|
||||
return false;
|
||||
if (!out->append(srcBuf.get(), srcBuf.length()))
|
||||
return false;
|
||||
if (!out->append(FunctionConstructorFinalBrace))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -4264,7 +4297,16 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
|
||||
RootedScope scope(cx);
|
||||
if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
|
||||
return false;
|
||||
return CompileFunction(cx, options, name, nargs, argnames, srcBuf, env, scope, fun);
|
||||
|
||||
uint32_t parameterListEnd;
|
||||
StringBuffer funStr(cx);
|
||||
if (!BuildFunctionString(nargs, argnames, srcBuf, &funStr, ¶meterListEnd))
|
||||
return false;
|
||||
|
||||
size_t newLen = funStr.length();
|
||||
SourceBufferHolder newSrcBuf(funStr.stealChars(), newLen, SourceBufferHolder::GiveOwnership);
|
||||
|
||||
return CompileFunction(cx, options, name, newSrcBuf, parameterListEnd, env, scope, fun);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
|
@ -650,7 +650,8 @@ typedef enum JSExnType {
|
||||
JSEXN_DEBUGGEEWOULDRUN,
|
||||
JSEXN_WASMCOMPILEERROR,
|
||||
JSEXN_WASMRUNTIMEERROR,
|
||||
JSEXN_WARN,
|
||||
JSEXN_ERROR_LIMIT,
|
||||
JSEXN_WARN = JSEXN_ERROR_LIMIT,
|
||||
JSEXN_LIMIT
|
||||
} JSExnType;
|
||||
|
||||
|
227
js/src/jsexn.cpp
227
js/src/jsexn.cpp
@ -48,18 +48,35 @@ using mozilla::PodArrayZero;
|
||||
static void
|
||||
exn_finalize(FreeOp* fop, JSObject* obj);
|
||||
|
||||
bool
|
||||
Error(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
static bool
|
||||
exn_toSource(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
static const JSPropertySpec exception_properties[] = {
|
||||
JS_PSGS("stack", ErrorObject::getStack, ErrorObject::setStack, 0),
|
||||
JS_PS_END
|
||||
#define IMPLEMENT_ERROR_PROTO_CLASS(name) \
|
||||
{ \
|
||||
js_Object_str, \
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_##name), \
|
||||
JS_NULL_CLASS_OPS, \
|
||||
&ErrorObject::classSpecs[JSProto_##name - JSProto_Error] \
|
||||
}
|
||||
|
||||
const Class
|
||||
ErrorObject::protoClasses[JSEXN_ERROR_LIMIT] = {
|
||||
IMPLEMENT_ERROR_PROTO_CLASS(Error),
|
||||
|
||||
IMPLEMENT_ERROR_PROTO_CLASS(InternalError),
|
||||
IMPLEMENT_ERROR_PROTO_CLASS(EvalError),
|
||||
IMPLEMENT_ERROR_PROTO_CLASS(RangeError),
|
||||
IMPLEMENT_ERROR_PROTO_CLASS(ReferenceError),
|
||||
IMPLEMENT_ERROR_PROTO_CLASS(SyntaxError),
|
||||
IMPLEMENT_ERROR_PROTO_CLASS(TypeError),
|
||||
IMPLEMENT_ERROR_PROTO_CLASS(URIError),
|
||||
|
||||
IMPLEMENT_ERROR_PROTO_CLASS(DebuggeeWouldRun),
|
||||
IMPLEMENT_ERROR_PROTO_CLASS(CompileError),
|
||||
IMPLEMENT_ERROR_PROTO_CLASS(RuntimeError)
|
||||
};
|
||||
|
||||
static const JSFunctionSpec exception_methods[] = {
|
||||
static const JSFunctionSpec error_methods[] = {
|
||||
#if JS_HAS_TOSOURCE
|
||||
JS_FN(js_toSource_str, exn_toSource, 0, 0),
|
||||
#endif
|
||||
@ -67,6 +84,92 @@ static const JSFunctionSpec exception_methods[] = {
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
static const JSPropertySpec error_properties[] = {
|
||||
JS_STRING_PS("message", "", 0),
|
||||
JS_STRING_PS("name", "Error", 0),
|
||||
// Only Error.prototype has .stack!
|
||||
JS_PSGS("stack", ErrorObject::getStack, ErrorObject::setStack, 0),
|
||||
JS_PS_END
|
||||
};
|
||||
|
||||
#define IMPLEMENT_ERROR_PROPERTIES(name) \
|
||||
{ \
|
||||
JS_STRING_PS("message", "", 0), \
|
||||
JS_STRING_PS("name", #name, 0), \
|
||||
JS_PS_END \
|
||||
}
|
||||
|
||||
static const JSPropertySpec other_error_properties[JSEXN_ERROR_LIMIT - 1][3] = {
|
||||
IMPLEMENT_ERROR_PROPERTIES(InternalError),
|
||||
IMPLEMENT_ERROR_PROPERTIES(EvalError),
|
||||
IMPLEMENT_ERROR_PROPERTIES(RangeError),
|
||||
IMPLEMENT_ERROR_PROPERTIES(ReferenceError),
|
||||
IMPLEMENT_ERROR_PROPERTIES(SyntaxError),
|
||||
IMPLEMENT_ERROR_PROPERTIES(TypeError),
|
||||
IMPLEMENT_ERROR_PROPERTIES(URIError),
|
||||
IMPLEMENT_ERROR_PROPERTIES(DebuggeeWouldRun),
|
||||
IMPLEMENT_ERROR_PROPERTIES(CompileError),
|
||||
IMPLEMENT_ERROR_PROPERTIES(RuntimeError)
|
||||
};
|
||||
|
||||
#define IMPLEMENT_NATIVE_ERROR_SPEC(name) \
|
||||
{ \
|
||||
ErrorObject::createConstructor, \
|
||||
ErrorObject::createProto, \
|
||||
nullptr, \
|
||||
nullptr, \
|
||||
nullptr, \
|
||||
other_error_properties[JSProto_##name - JSProto_Error - 1], \
|
||||
nullptr, \
|
||||
JSProto_Error \
|
||||
}
|
||||
|
||||
#define IMPLEMENT_NONGLOBAL_ERROR_SPEC(name) \
|
||||
{ \
|
||||
ErrorObject::createConstructor, \
|
||||
ErrorObject::createProto, \
|
||||
nullptr, \
|
||||
nullptr, \
|
||||
nullptr, \
|
||||
other_error_properties[JSProto_##name - JSProto_Error - 1], \
|
||||
nullptr, \
|
||||
JSProto_Error | ClassSpec::DontDefineConstructor \
|
||||
}
|
||||
|
||||
const ClassSpec
|
||||
ErrorObject::classSpecs[JSEXN_ERROR_LIMIT] = {
|
||||
{
|
||||
ErrorObject::createConstructor,
|
||||
ErrorObject::createProto,
|
||||
nullptr,
|
||||
nullptr,
|
||||
error_methods,
|
||||
error_properties
|
||||
},
|
||||
|
||||
IMPLEMENT_NATIVE_ERROR_SPEC(InternalError),
|
||||
IMPLEMENT_NATIVE_ERROR_SPEC(EvalError),
|
||||
IMPLEMENT_NATIVE_ERROR_SPEC(RangeError),
|
||||
IMPLEMENT_NATIVE_ERROR_SPEC(ReferenceError),
|
||||
IMPLEMENT_NATIVE_ERROR_SPEC(SyntaxError),
|
||||
IMPLEMENT_NATIVE_ERROR_SPEC(TypeError),
|
||||
IMPLEMENT_NATIVE_ERROR_SPEC(URIError),
|
||||
|
||||
IMPLEMENT_NONGLOBAL_ERROR_SPEC(DebuggeeWouldRun),
|
||||
IMPLEMENT_NONGLOBAL_ERROR_SPEC(CompileError),
|
||||
IMPLEMENT_NONGLOBAL_ERROR_SPEC(RuntimeError)
|
||||
};
|
||||
|
||||
#define IMPLEMENT_ERROR_CLASS(name) \
|
||||
{ \
|
||||
js_Error_str, /* yes, really */ \
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS) | \
|
||||
JSCLASS_BACKGROUND_FINALIZE, \
|
||||
&ErrorObjectClassOps, \
|
||||
&ErrorObject::classSpecs[JSProto_##name - JSProto_Error ] \
|
||||
}
|
||||
|
||||
static const ClassOps ErrorObjectClassOps = {
|
||||
nullptr, /* addProperty */
|
||||
nullptr, /* delProperty */
|
||||
@ -82,67 +185,20 @@ static const ClassOps ErrorObjectClassOps = {
|
||||
nullptr, /* trace */
|
||||
};
|
||||
|
||||
#define IMPLEMENT_ERROR_CLASS(name, classSpecPtr) \
|
||||
{ \
|
||||
js_Error_str, /* yes, really */ \
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS) | \
|
||||
JSCLASS_BACKGROUND_FINALIZE, \
|
||||
&ErrorObjectClassOps, \
|
||||
classSpecPtr \
|
||||
}
|
||||
|
||||
const ClassSpec
|
||||
ErrorObject::errorClassSpec_ = {
|
||||
ErrorObject::createConstructor,
|
||||
ErrorObject::createProto,
|
||||
nullptr,
|
||||
nullptr,
|
||||
exception_methods,
|
||||
exception_properties,
|
||||
nullptr,
|
||||
0
|
||||
};
|
||||
|
||||
const ClassSpec
|
||||
ErrorObject::subErrorClassSpec_ = {
|
||||
ErrorObject::createConstructor,
|
||||
ErrorObject::createProto,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
JSProto_Error
|
||||
};
|
||||
|
||||
const ClassSpec
|
||||
ErrorObject::nonGlobalErrorClassSpec_ = {
|
||||
ErrorObject::createConstructor,
|
||||
ErrorObject::createProto,
|
||||
nullptr,
|
||||
nullptr,
|
||||
exception_methods,
|
||||
exception_properties,
|
||||
nullptr,
|
||||
JSProto_Error | ClassSpec::DontDefineConstructor
|
||||
};
|
||||
|
||||
const Class
|
||||
ErrorObject::classes[JSEXN_LIMIT] = {
|
||||
IMPLEMENT_ERROR_CLASS(Error, &ErrorObject::errorClassSpec_),
|
||||
IMPLEMENT_ERROR_CLASS(InternalError, &ErrorObject::subErrorClassSpec_),
|
||||
IMPLEMENT_ERROR_CLASS(EvalError, &ErrorObject::subErrorClassSpec_),
|
||||
IMPLEMENT_ERROR_CLASS(RangeError, &ErrorObject::subErrorClassSpec_),
|
||||
IMPLEMENT_ERROR_CLASS(ReferenceError, &ErrorObject::subErrorClassSpec_),
|
||||
IMPLEMENT_ERROR_CLASS(SyntaxError, &ErrorObject::subErrorClassSpec_),
|
||||
IMPLEMENT_ERROR_CLASS(TypeError, &ErrorObject::subErrorClassSpec_),
|
||||
IMPLEMENT_ERROR_CLASS(URIError, &ErrorObject::subErrorClassSpec_),
|
||||
|
||||
ErrorObject::classes[JSEXN_ERROR_LIMIT] = {
|
||||
IMPLEMENT_ERROR_CLASS(Error),
|
||||
IMPLEMENT_ERROR_CLASS(InternalError),
|
||||
IMPLEMENT_ERROR_CLASS(EvalError),
|
||||
IMPLEMENT_ERROR_CLASS(RangeError),
|
||||
IMPLEMENT_ERROR_CLASS(ReferenceError),
|
||||
IMPLEMENT_ERROR_CLASS(SyntaxError),
|
||||
IMPLEMENT_ERROR_CLASS(TypeError),
|
||||
IMPLEMENT_ERROR_CLASS(URIError),
|
||||
// These Error subclasses are not accessible via the global object:
|
||||
IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun, &ErrorObject::nonGlobalErrorClassSpec_),
|
||||
IMPLEMENT_ERROR_CLASS(CompileError, &ErrorObject::nonGlobalErrorClassSpec_),
|
||||
IMPLEMENT_ERROR_CLASS(RuntimeError, &ErrorObject::nonGlobalErrorClassSpec_)
|
||||
IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun),
|
||||
IMPLEMENT_ERROR_CLASS(CompileError),
|
||||
IMPLEMENT_ERROR_CLASS(RuntimeError)
|
||||
};
|
||||
|
||||
JSErrorReport*
|
||||
@ -454,35 +510,40 @@ exn_toSource(JSContext* cx, unsigned argc, Value* vp)
|
||||
/* static */ JSObject*
|
||||
ErrorObject::createProto(JSContext* cx, JSProtoKey key)
|
||||
{
|
||||
RootedObject errorProto(cx, GenericCreatePrototype(cx, key));
|
||||
if (!errorProto)
|
||||
return nullptr;
|
||||
|
||||
Rooted<ErrorObject*> err(cx, &errorProto->as<ErrorObject>());
|
||||
RootedString emptyStr(cx, cx->names().empty);
|
||||
JSExnType type = ExnTypeFromProtoKey(key);
|
||||
if (!ErrorObject::init(cx, err, type, nullptr, emptyStr, nullptr, 0, 0, emptyStr))
|
||||
|
||||
if (type == JSEXN_ERR)
|
||||
return cx->global()->createBlankPrototype(cx, &ErrorObject::protoClasses[JSEXN_ERR]);
|
||||
|
||||
RootedObject protoProto(cx, GlobalObject::getOrCreateErrorPrototype(cx, cx->global()));
|
||||
if (!protoProto)
|
||||
return nullptr;
|
||||
|
||||
// The various prototypes also have .name in addition to the normal error
|
||||
// instance properties.
|
||||
RootedPropertyName name(cx, ClassName(key, cx));
|
||||
RootedValue nameValue(cx, StringValue(name));
|
||||
if (!DefineProperty(cx, err, cx->names().name, nameValue, nullptr, nullptr, 0))
|
||||
return nullptr;
|
||||
|
||||
return errorProto;
|
||||
return cx->global()->createBlankPrototypeInheriting(cx, &ErrorObject::protoClasses[type],
|
||||
protoProto);
|
||||
}
|
||||
|
||||
/* static */ JSObject*
|
||||
ErrorObject::createConstructor(JSContext* cx, JSProtoKey key)
|
||||
{
|
||||
JSExnType type = ExnTypeFromProtoKey(key);
|
||||
RootedObject ctor(cx);
|
||||
ctor = GenericCreateConstructor<Error, 1, gc::AllocKind::FUNCTION_EXTENDED>(cx, key);
|
||||
|
||||
if (type == JSEXN_ERR) {
|
||||
ctor = GenericCreateConstructor<Error, 1, gc::AllocKind::FUNCTION_EXTENDED>(cx, key);
|
||||
} else {
|
||||
RootedFunction proto(cx, GlobalObject::getOrCreateErrorConstructor(cx, cx->global()));
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
|
||||
ctor = NewFunctionWithProto(cx, Error, 1, JSFunction::NATIVE_CTOR, nullptr,
|
||||
ClassName(key, cx), proto, gc::AllocKind::FUNCTION_EXTENDED);
|
||||
}
|
||||
|
||||
if (!ctor)
|
||||
return nullptr;
|
||||
|
||||
ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(ExnTypeFromProtoKey(key)));
|
||||
ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(type));
|
||||
return ctor;
|
||||
}
|
||||
|
||||
|
@ -85,10 +85,17 @@ ExnTypeFromProtoKey(JSProtoKey key)
|
||||
{
|
||||
JSExnType type = static_cast<JSExnType>(key - JSProto_Error);
|
||||
MOZ_ASSERT(type >= JSEXN_ERR);
|
||||
MOZ_ASSERT(type < JSEXN_WARN);
|
||||
MOZ_ASSERT(type < JSEXN_ERROR_LIMIT);
|
||||
return type;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsErrorProtoKey(JSProtoKey key)
|
||||
{
|
||||
JSExnType type = static_cast<JSExnType>(key - JSProto_Error);
|
||||
return type >= JSEXN_ERR && type < JSEXN_ERROR_LIMIT;
|
||||
}
|
||||
|
||||
class AutoClearPendingException
|
||||
{
|
||||
JSContext* cx;
|
||||
|
276
js/src/jsfun.cpp
276
js/src/jsfun.cpp
@ -12,6 +12,7 @@
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/Range.h"
|
||||
|
||||
@ -60,8 +61,10 @@ using namespace js::gc;
|
||||
using namespace js::frontend;
|
||||
|
||||
using mozilla::ArrayLength;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::PodCopy;
|
||||
using mozilla::RangedPtr;
|
||||
using mozilla::Some;
|
||||
|
||||
static bool
|
||||
fun_enumerate(JSContext* cx, HandleObject obj)
|
||||
@ -933,19 +936,19 @@ const Class JSFunction::class_ = {
|
||||
const Class* const js::FunctionClassPtr = &JSFunction::class_;
|
||||
|
||||
JSString*
|
||||
js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
|
||||
js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
|
||||
{
|
||||
if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
|
||||
return nullptr;
|
||||
|
||||
if (IsAsmJSModule(fun))
|
||||
return AsmJSModuleToString(cx, fun, !lambdaParen);
|
||||
return AsmJSModuleToString(cx, fun, !prettyPrint);
|
||||
if (IsAsmJSFunction(fun))
|
||||
return AsmJSFunctionToString(cx, fun);
|
||||
|
||||
if (IsWrappedAsyncFunction(fun)) {
|
||||
RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
|
||||
return FunctionToString(cx, unwrapped, lambdaParen);
|
||||
return FunctionToString(cx, unwrapped, prettyPrint);
|
||||
}
|
||||
|
||||
StringBuffer out(cx);
|
||||
@ -971,11 +974,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
|
||||
|
||||
bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
|
||||
fun->isGetter() || fun->isSetter();
|
||||
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
|
||||
|
||||
// If we're not in pretty mode, put parentheses around lambda functions and methods.
|
||||
if (fun->isInterpreted() && !lambdaParen && funIsMethodOrNonArrowLambda &&
|
||||
!fun->isSelfHostedBuiltin())
|
||||
{
|
||||
if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) {
|
||||
if (!out.append("("))
|
||||
return nullptr;
|
||||
}
|
||||
@ -993,7 +995,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
|
||||
if (haveSource && !script->scriptSource()->hasSourceData() &&
|
||||
!JSScript::loadSource(cx, script->scriptSource(), &haveSource))
|
||||
{
|
||||
@ -1004,54 +1005,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
|
||||
if (!src)
|
||||
return nullptr;
|
||||
|
||||
// The source data for functions created by calling the Function
|
||||
// constructor is only the function's body. This depends on the fact,
|
||||
// asserted below, that in Function("function f() {}"), the inner
|
||||
// function's sourceStart points to the '(', not the 'f'.
|
||||
bool funCon = !fun->isArrow() &&
|
||||
script->sourceStart() == 0 &&
|
||||
script->sourceEnd() == script->scriptSource()->length() &&
|
||||
script->scriptSource()->argumentsNotIncluded();
|
||||
|
||||
// Functions created with the constructor can't be arrow functions or
|
||||
// expression closures.
|
||||
MOZ_ASSERT_IF(funCon, !fun->isArrow());
|
||||
MOZ_ASSERT_IF(funCon, !fun->isExprBody());
|
||||
MOZ_ASSERT_IF(!funCon && !fun->isArrow(),
|
||||
src->length() > 0 && src->latin1OrTwoByteChar(0) == '(');
|
||||
|
||||
bool buildBody = funCon;
|
||||
if (buildBody) {
|
||||
// This function was created with the Function constructor. We don't
|
||||
// have source for the arguments, so we have to generate that. Part
|
||||
// of bug 755821 should be cobbling the arguments passed into the
|
||||
// Function constructor into the source string.
|
||||
if (!out.append("("))
|
||||
return nullptr;
|
||||
|
||||
// Fish out the argument names.
|
||||
MOZ_ASSERT(script->numArgs() == fun->nargs());
|
||||
|
||||
BindingIter bi(script);
|
||||
for (unsigned i = 0; i < fun->nargs(); i++, bi++) {
|
||||
MOZ_ASSERT(bi.argumentSlot() == i);
|
||||
if (i && !out.append(", "))
|
||||
return nullptr;
|
||||
if (i == unsigned(fun->nargs() - 1) && fun->hasRest() && !out.append("..."))
|
||||
return nullptr;
|
||||
if (!out.append(bi.name()))
|
||||
return nullptr;
|
||||
}
|
||||
if (!out.append(") {\n"))
|
||||
return nullptr;
|
||||
}
|
||||
if (!out.append(src))
|
||||
return nullptr;
|
||||
if (buildBody) {
|
||||
if (!out.append("\n}"))
|
||||
return nullptr;
|
||||
}
|
||||
if (!lambdaParen && funIsMethodOrNonArrowLambda) {
|
||||
|
||||
if (!prettyPrint && funIsMethodOrNonArrowLambda) {
|
||||
if (!out.append(")"))
|
||||
return nullptr;
|
||||
}
|
||||
@ -1062,8 +1019,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (!lambdaParen && fun->isLambda() && !fun->isArrow() && !out.append(")"))
|
||||
return nullptr;
|
||||
} else {
|
||||
MOZ_ASSERT(!fun->isExprBody());
|
||||
|
||||
@ -1605,17 +1560,6 @@ fun_isGenerator(JSContext* cx, unsigned argc, Value* vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Report "malformed formal parameter" iff no illegal char or similar scanner
|
||||
* error was already reported.
|
||||
*/
|
||||
static bool
|
||||
OnBadFormal(JSContext* cx)
|
||||
{
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_FORMAL);
|
||||
return false;
|
||||
}
|
||||
|
||||
const JSFunctionSpec js::function_methods[] = {
|
||||
#if JS_HAS_TOSOURCE
|
||||
JS_FN(js_toSource_str, fun_toSource, 0,0),
|
||||
@ -1629,11 +1573,12 @@ const JSFunctionSpec js::function_methods[] = {
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
// ES 2017 draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077 19.2.1.1.1.
|
||||
static bool
|
||||
FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind)
|
||||
{
|
||||
/* Block this call if security callbacks forbid it. */
|
||||
// Block this call if security callbacks forbid it.
|
||||
Rooted<GlobalObject*> global(cx, &args.callee().global());
|
||||
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
|
||||
@ -1665,83 +1610,66 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
|
||||
introducerFilename = maybeScript->scriptSource()->introducerFilename();
|
||||
|
||||
CompileOptions options(cx);
|
||||
// Use line 0 to make the function body starts from line 1.
|
||||
options.setMutedErrors(mutedErrors)
|
||||
.setFileAndLine(filename, 1)
|
||||
.setFileAndLine(filename, 0)
|
||||
.setNoScriptRval(false)
|
||||
.setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset);
|
||||
|
||||
Vector<char16_t> paramStr(cx);
|
||||
RootedString bodyText(cx);
|
||||
StringBuffer sb(cx);
|
||||
|
||||
if (args.length() == 0) {
|
||||
bodyText = cx->names().empty;
|
||||
} else {
|
||||
// Collect the function-argument arguments into one string, separated
|
||||
// by commas, then make a tokenstream from that string, and scan it to
|
||||
// get the arguments. We need to throw the full scanner at the
|
||||
// problem because the argument string may contain comments, newlines,
|
||||
// destructuring arguments, and similar manner of insanities. ("I have
|
||||
// a feeling we're not in simple-comma-separated-parameters land any
|
||||
// more, Toto....")
|
||||
//
|
||||
// XXX It'd be better if the parser provided utility methods to parse
|
||||
// an argument list, and to parse a function body given a parameter
|
||||
// list. But our parser provides no such pleasant interface now.
|
||||
if (!sb.append('('))
|
||||
return false;
|
||||
|
||||
if (args.length() > 1) {
|
||||
RootedString str(cx);
|
||||
|
||||
// Steps 5-6, 9.
|
||||
unsigned n = args.length() - 1;
|
||||
|
||||
// Convert the parameters-related arguments to strings, and determine
|
||||
// the length of the string containing the overall parameter list.
|
||||
mozilla::CheckedInt<uint32_t> paramStrLen = 0;
|
||||
RootedString str(cx);
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
// Steps 9.a-b, 9.d.i-ii.
|
||||
str = ToString<CanGC>(cx, args[i]);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
args[i].setString(str);
|
||||
paramStrLen += str->length();
|
||||
// Steps 9.b, 9.d.iii.
|
||||
if (!sb.append(str))
|
||||
return false;
|
||||
|
||||
if (i < args.length() - 2) {
|
||||
// Step 9.d.iii.
|
||||
if (!sb.append(", "))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Tack in space for any combining commas.
|
||||
if (n > 0)
|
||||
paramStrLen += n - 1;
|
||||
|
||||
// Check for integer and string-size overflow.
|
||||
if (!paramStrLen.isValid() || paramStrLen.value() > JSString::MAX_LENGTH) {
|
||||
ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t paramsLen = paramStrLen.value();
|
||||
|
||||
// Fill a vector with the comma-joined arguments. Careful! This
|
||||
// string is *not* null-terminated!
|
||||
MOZ_ASSERT(paramStr.length() == 0);
|
||||
if (!paramStr.growBy(paramsLen)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
char16_t* cp = paramStr.begin();
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
JSLinearString* argLinear = args[i].toString()->ensureLinear(cx);
|
||||
if (!argLinear)
|
||||
return false;
|
||||
|
||||
CopyChars(cp, *argLinear);
|
||||
cp += argLinear->length();
|
||||
|
||||
if (i + 1 < n)
|
||||
*cp++ = ',';
|
||||
}
|
||||
|
||||
MOZ_ASSERT(cp == paramStr.end());
|
||||
|
||||
bodyText = ToString(cx, args[n]);
|
||||
if (!bodyText)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remember the position of ")".
|
||||
Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
|
||||
MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
|
||||
|
||||
if (!sb.append(FunctionConstructorMedialSigils))
|
||||
return false;
|
||||
|
||||
if (args.length() > 0) {
|
||||
// Steps 7-8, 10.
|
||||
RootedString body(cx, ToString<CanGC>(cx, args[args.length() - 1]));
|
||||
if (!body || !sb.append(body))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sb.append(FunctionConstructorFinalBrace))
|
||||
return false;
|
||||
|
||||
// The parser only accepts two byte strings.
|
||||
if (!sb.ensureTwoByteChars())
|
||||
return false;
|
||||
|
||||
RootedString functionText(cx, sb.finishString());
|
||||
if (!functionText)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* NB: (new Function) is not lexically closed by its caller, it's just an
|
||||
* anonymous function in the top-level scope that its constructor inhabits.
|
||||
@ -1750,24 +1678,22 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
|
||||
*/
|
||||
RootedAtom anonymousAtom(cx, cx->names().anonymous);
|
||||
|
||||
// ES2017, draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077
|
||||
// 19.2.1.1.1 Runtime Semantics: CreateDynamicFunction, step 24.
|
||||
// Step 24.
|
||||
RootedObject proto(cx);
|
||||
if (!isAsync) {
|
||||
if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
|
||||
return false;
|
||||
}
|
||||
|
||||
// 19.2.1.1.1, step 4.d, use %Generator% as the fallback prototype.
|
||||
// Step 4.d, use %Generator% as the fallback prototype.
|
||||
// Also use %Generator% for the unwrapped function of async functions.
|
||||
if (!proto && isStarGenerator) {
|
||||
// Unwrapped function of async function should use GeneratorFunction,
|
||||
// while wrapped function isn't generator.
|
||||
proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
|
||||
if (!proto)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 25-32 (reordered).
|
||||
RootedObject globalLexical(cx, &global->lexicalEnvironment());
|
||||
AllocKind allocKind = isAsync ? AllocKind::FUNCTION_EXTENDED : AllocKind::FUNCTION;
|
||||
RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
|
||||
@ -1780,81 +1706,11 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
|
||||
if (!JSFunction::setTypeForScriptedFunction(cx, fun))
|
||||
return false;
|
||||
|
||||
// Steps 2.a-b, 3.a-b, 4.a-b, 11-23.
|
||||
AutoStableStringChars stableChars(cx);
|
||||
if (!stableChars.initTwoByte(cx, bodyText))
|
||||
if (!stableChars.initTwoByte(cx, functionText))
|
||||
return false;
|
||||
|
||||
bool hasRest = false;
|
||||
|
||||
Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
|
||||
if (args.length() > 1) {
|
||||
// Initialize a tokenstream to parse the new function's arguments. No
|
||||
// StrictModeGetter is needed because this TokenStream won't report any
|
||||
// strict mode errors. Strict mode errors that might be reported here
|
||||
// (duplicate argument names, etc.) will be detected when we compile
|
||||
// the function body.
|
||||
//
|
||||
// XXX Bug! We have to parse the body first to determine strictness.
|
||||
// We have to know strictness to parse arguments correctly, in case
|
||||
// arguments contains a strict mode violation. And we should be
|
||||
// using full-fledged arguments parsing here, in order to handle
|
||||
// destructuring and other exotic syntaxes.
|
||||
AutoKeepAtoms keepAtoms(cx->perThreadData);
|
||||
TokenStream ts(cx, options, paramStr.begin(), paramStr.length(),
|
||||
/* strictModeGetter = */ nullptr);
|
||||
bool yieldIsValidName = ts.versionNumber() < JSVERSION_1_7 && !isStarGenerator;
|
||||
|
||||
// The argument string may be empty or contain no tokens.
|
||||
TokenKind tt;
|
||||
if (!ts.getToken(&tt))
|
||||
return false;
|
||||
if (tt != TOK_EOF) {
|
||||
while (true) {
|
||||
// Check that it's a name.
|
||||
if (hasRest) {
|
||||
ts.reportError(JSMSG_PARAMETER_AFTER_REST);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tt == TOK_YIELD && yieldIsValidName)
|
||||
tt = TOK_NAME;
|
||||
|
||||
if (tt != TOK_NAME) {
|
||||
if (tt == TOK_TRIPLEDOT) {
|
||||
hasRest = true;
|
||||
if (!ts.getToken(&tt))
|
||||
return false;
|
||||
if (tt == TOK_YIELD && yieldIsValidName)
|
||||
tt = TOK_NAME;
|
||||
if (tt != TOK_NAME) {
|
||||
ts.reportError(JSMSG_NO_REST_NAME);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return OnBadFormal(cx);
|
||||
}
|
||||
}
|
||||
|
||||
if (!formals.append(ts.currentName()))
|
||||
return false;
|
||||
|
||||
// Get the next token. Stop on end of stream. Otherwise
|
||||
// insist on a comma, get another name, and iterate.
|
||||
if (!ts.getToken(&tt))
|
||||
return false;
|
||||
if (tt == TOK_EOF)
|
||||
break;
|
||||
if (tt != TOK_COMMA)
|
||||
return OnBadFormal(cx);
|
||||
if (!ts.getToken(&tt))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasRest)
|
||||
fun->setHasRest();
|
||||
|
||||
mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
|
||||
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
|
||||
? SourceBufferHolder::GiveOwnership
|
||||
@ -1862,11 +1718,13 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
|
||||
bool ok;
|
||||
SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership);
|
||||
if (isAsync)
|
||||
ok = frontend::CompileAsyncFunctionBody(cx, &fun, options, formals, srcBuf);
|
||||
ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf, parameterListEnd);
|
||||
else if (isStarGenerator)
|
||||
ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf);
|
||||
ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd);
|
||||
else
|
||||
ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf);
|
||||
ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd);
|
||||
|
||||
// Step 33.
|
||||
args.rval().setObject(*fun);
|
||||
return ok;
|
||||
}
|
||||
|
@ -28,6 +28,9 @@ static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET = 2;
|
||||
static const uint32_t JSSLOT_BOUND_FUNCTION_THIS = 3;
|
||||
static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS = 4;
|
||||
|
||||
static const char FunctionConstructorMedialSigils[] = ") {\n";
|
||||
static const char FunctionConstructorFinalBrace[] = "\n}";
|
||||
|
||||
class JSFunction : public js::NativeObject
|
||||
{
|
||||
public:
|
||||
@ -812,7 +815,7 @@ JSFunction::getExtendedSlot(size_t which) const
|
||||
|
||||
namespace js {
|
||||
|
||||
JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen);
|
||||
JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPring);
|
||||
|
||||
template<XDRMode mode>
|
||||
bool
|
||||
|
111
js/src/jsgc.cpp
111
js/src/jsgc.cpp
@ -1689,20 +1689,11 @@ GCMarker::delayMarkingChildren(const void* thing)
|
||||
}
|
||||
|
||||
inline void
|
||||
ArenaLists::prepareForIncrementalGC(JSRuntime* rt)
|
||||
ArenaLists::prepareForIncrementalGC()
|
||||
{
|
||||
for (auto i : AllAllocKinds()) {
|
||||
FreeSpan* span = freeLists[i];
|
||||
if (span != &placeholder) {
|
||||
if (!span->isEmpty()) {
|
||||
Arena* arena = span->getArena();
|
||||
arena->allocatedDuringIncremental = true;
|
||||
rt->gc.marker.delayMarkingArena(arena);
|
||||
} else {
|
||||
freeLists[i] = &placeholder;
|
||||
}
|
||||
}
|
||||
}
|
||||
purge();
|
||||
for (auto i : AllAllocKinds())
|
||||
arenaLists[i].moveCursorToEnd();
|
||||
}
|
||||
|
||||
/* Compacting GC */
|
||||
@ -3760,6 +3751,23 @@ RelazifyFunctions(Zone* zone, AllocKind kind)
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason)
|
||||
{
|
||||
// Normally we collect all scheduled zones.
|
||||
if (reason != JS::gcreason::COMPARTMENT_REVIVED)
|
||||
return zone->isGCScheduled();
|
||||
|
||||
// If we are repeating a GC becuase we noticed dead compartments haven't
|
||||
// been collected, then only collect zones contianing those compartments.
|
||||
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
|
||||
if (comp->scheduledForDestruction)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock)
|
||||
{
|
||||
@ -3783,7 +3791,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
|
||||
#endif
|
||||
|
||||
/* Set up which zones will be collected. */
|
||||
if (zone->isGCScheduled()) {
|
||||
if (ShouldCollectZone(zone, reason)) {
|
||||
if (!zone->isAtomsZone()) {
|
||||
any = true;
|
||||
zone->setGCState(Zone::Mark);
|
||||
@ -3832,15 +3840,12 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
|
||||
return false;
|
||||
|
||||
/*
|
||||
* At the end of each incremental slice, we call prepareForIncrementalGC,
|
||||
* which marks objects in all arenas that we're currently allocating
|
||||
* into. This can cause leaks if unreachable objects are in these
|
||||
* arenas. This purge call ensures that we only mark arenas that have had
|
||||
* allocations after the incremental GC started.
|
||||
* Ensure that after the start of a collection we don't allocate into any
|
||||
* existing arenas, as this can cause unreachable things to be marked.
|
||||
*/
|
||||
if (isIncremental) {
|
||||
for (GCZonesIter zone(rt); !zone.done(); zone.next())
|
||||
zone->arenas.purge();
|
||||
zone->arenas.prepareForIncrementalGC();
|
||||
}
|
||||
|
||||
MemProfiler::MarkTenuredStart(rt);
|
||||
@ -5759,7 +5764,7 @@ AutoGCSlice::~AutoGCSlice()
|
||||
for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) {
|
||||
if (zone->isGCMarking()) {
|
||||
zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit);
|
||||
zone->arenas.prepareForIncrementalGC(runtime);
|
||||
zone->arenas.purge();
|
||||
} else {
|
||||
zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
|
||||
}
|
||||
@ -5999,9 +6004,17 @@ gc::IsIncrementalGCUnsafe(JSRuntime* rt)
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& lock)
|
||||
GCRuntime::budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget,
|
||||
AutoLockForExclusiveAccess& lock)
|
||||
{
|
||||
AbortReason unsafeReason = IsIncrementalGCUnsafe(rt);
|
||||
if (unsafeReason == AbortReason::None) {
|
||||
if (reason == JS::gcreason::COMPARTMENT_REVIVED)
|
||||
unsafeReason = gc::AbortReason::CompartmentRevived;
|
||||
else if (mode != JSGC_MODE_INCREMENTAL)
|
||||
unsafeReason = gc::AbortReason::ModeChange;
|
||||
}
|
||||
|
||||
if (unsafeReason != AbortReason::None) {
|
||||
resetIncrementalGC(unsafeReason, lock);
|
||||
budget.makeUnlimited();
|
||||
@ -6009,13 +6022,6 @@ GCRuntime::budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess&
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode != JSGC_MODE_INCREMENTAL) {
|
||||
resetIncrementalGC(AbortReason::ModeChange, lock);
|
||||
budget.makeUnlimited();
|
||||
stats.nonincremental(AbortReason::ModeChange);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTooMuchMalloc()) {
|
||||
budget.makeUnlimited();
|
||||
stats.nonincremental(AbortReason::MallocBytesTrigger);
|
||||
@ -6173,7 +6179,7 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::
|
||||
stats.nonincremental(gc::AbortReason::NonIncrementalRequested);
|
||||
budget.makeUnlimited();
|
||||
} else {
|
||||
budgetIncrementalGC(budget, session.lock);
|
||||
budgetIncrementalGC(reason, budget, session.lock);
|
||||
}
|
||||
|
||||
/* The GC was reset, so we need a do-over. */
|
||||
@ -6292,6 +6298,22 @@ GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason)
|
||||
{
|
||||
MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental);
|
||||
|
||||
if (!isIncremental || isIncrementalGCInProgress())
|
||||
return false;
|
||||
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
if (c->scheduledForDestruction)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason)
|
||||
{
|
||||
@ -6322,25 +6344,18 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
|
||||
poked = false;
|
||||
bool wasReset = gcCycle(nonincrementalByAPI, budget, reason);
|
||||
|
||||
/* Need to re-schedule all zones for GC. */
|
||||
if (poked && cleanUpEverything)
|
||||
JS::PrepareForFullGC(rt->contextFromMainThread());
|
||||
|
||||
/*
|
||||
* This code makes an extra effort to collect compartments that we
|
||||
* thought were dead at the start of the GC. See the large comment in
|
||||
* beginMarkPhase.
|
||||
*/
|
||||
bool repeatForDeadZone = false;
|
||||
if (!nonincrementalByAPI && !isIncrementalGCInProgress()) {
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
if (c->scheduledForDestruction) {
|
||||
nonincrementalByAPI = true;
|
||||
repeatForDeadZone = true;
|
||||
reason = JS::gcreason::COMPARTMENT_REVIVED;
|
||||
c->zone()->scheduleGC();
|
||||
}
|
||||
}
|
||||
if (poked && cleanUpEverything) {
|
||||
/* Need to re-schedule all zones for GC. */
|
||||
JS::PrepareForFullGC(rt->contextFromMainThread());
|
||||
} else if (shouldRepeatForDeadZone(reason) && !wasReset) {
|
||||
/*
|
||||
* This code makes an extra effort to collect compartments that we
|
||||
* thought were dead at the start of the GC. See the large comment
|
||||
* in beginMarkPhase.
|
||||
*/
|
||||
repeatForDeadZone = true;
|
||||
reason = JS::gcreason::COMPARTMENT_REVIVED;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -60,7 +60,8 @@ enum class State {
|
||||
D(ModeChange) \
|
||||
D(MallocBytesTrigger) \
|
||||
D(GCBytesTrigger) \
|
||||
D(ZoneChange)
|
||||
D(ZoneChange) \
|
||||
D(CompartmentRevived)
|
||||
enum class AbortReason {
|
||||
#define MAKE_REASON(name) name,
|
||||
GC_ABORT_REASONS(MAKE_REASON)
|
||||
@ -449,6 +450,11 @@ class ArenaList {
|
||||
return !*cursorp_;
|
||||
}
|
||||
|
||||
void moveCursorToEnd() {
|
||||
while (!isCursorAtEnd())
|
||||
cursorp_ = &(*cursorp_)->next;
|
||||
}
|
||||
|
||||
// This can return nullptr.
|
||||
Arena* arenaAfterCursor() const {
|
||||
check();
|
||||
@ -734,7 +740,7 @@ class ArenaLists
|
||||
freeLists[i] = &placeholder;
|
||||
}
|
||||
|
||||
inline void prepareForIncrementalGC(JSRuntime* rt);
|
||||
inline void prepareForIncrementalGC();
|
||||
|
||||
/* Check if this arena is in use. */
|
||||
bool arenaIsInUse(Arena* arena, AllocKind kind) const {
|
||||
|
@ -470,7 +470,7 @@ js::SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level)
|
||||
|
||||
// Steps 8-9, loosely interpreted.
|
||||
if (obj->isNative() && !obj->as<NativeObject>().inDictionaryMode() &&
|
||||
!obj->is<TypedArrayObject>())
|
||||
!obj->is<TypedArrayObject>() && !obj->is<MappedArgumentsObject>())
|
||||
{
|
||||
HandleNativeObject nobj = obj.as<NativeObject>();
|
||||
|
||||
|
@ -1675,6 +1675,16 @@ ScriptSource::substringDontDeflate(JSContext* cx, size_t start, size_t stop)
|
||||
return NewStringCopyNDontDeflate<CanGC>(cx, chars, len);
|
||||
}
|
||||
|
||||
JSFlatString*
|
||||
ScriptSource::functionBodyString(JSContext* cx)
|
||||
{
|
||||
MOZ_ASSERT(isFunctionBody());
|
||||
|
||||
size_t start = parameterListEnd_ + (sizeof(FunctionConstructorMedialSigils) - 1);
|
||||
size_t stop = length() - (sizeof(FunctionConstructorFinalBrace) - 1);
|
||||
return substring(cx, start, stop);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
ScriptSource::setSource(ExclusiveContext* cx,
|
||||
mozilla::UniquePtr<char16_t[], JS::FreePolicy>&& source,
|
||||
@ -1726,10 +1736,9 @@ ScriptSource::setCompressedSource(SharedImmutableString&& raw, size_t uncompress
|
||||
|
||||
bool
|
||||
ScriptSource::setSourceCopy(ExclusiveContext* cx, SourceBufferHolder& srcBuf,
|
||||
bool argumentsNotIncluded, SourceCompressionTask* task)
|
||||
SourceCompressionTask* task)
|
||||
{
|
||||
MOZ_ASSERT(!hasSourceData());
|
||||
argumentsNotIncluded_ = argumentsNotIncluded;
|
||||
|
||||
auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
|
||||
auto deduped = cache.getOrCreate(srcBuf.get(), srcBuf.length(), [&]() {
|
||||
@ -1926,16 +1935,6 @@ ScriptSource::performXDR(XDRState<mode>* xdr)
|
||||
if (!xdr->codeUint32(&compressedLength))
|
||||
return false;
|
||||
|
||||
{
|
||||
uint8_t argumentsNotIncluded;
|
||||
if (mode == XDR_ENCODE)
|
||||
argumentsNotIncluded = argumentsNotIncluded_;
|
||||
if (!xdr->codeUint8(&argumentsNotIncluded))
|
||||
return false;
|
||||
if (mode == XDR_DECODE)
|
||||
argumentsNotIncluded_ = argumentsNotIncluded;
|
||||
}
|
||||
|
||||
size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t));
|
||||
if (mode == XDR_DECODE) {
|
||||
uint8_t* p = xdr->cx()->template pod_malloc<uint8_t>(Max<size_t>(byteLen, 1));
|
||||
@ -2060,7 +2059,8 @@ FormatIntroducedFilename(ExclusiveContext* cx, const char* filename, unsigned li
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
|
||||
ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
|
||||
Maybe<uint32_t> parameterListEnd)
|
||||
{
|
||||
MOZ_ASSERT(!filename_);
|
||||
MOZ_ASSERT(!introducerFilename_);
|
||||
@ -2069,6 +2069,7 @@ ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions
|
||||
|
||||
introductionType_ = options.introductionType;
|
||||
setIntroductionOffset(options.introductionOffset);
|
||||
parameterListEnd_ = parameterListEnd.isSome() ? parameterListEnd.value() : 0;
|
||||
|
||||
if (options.hasIntroductionInfo) {
|
||||
MOZ_ASSERT(options.introductionType != nullptr);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user