mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1297474 - shutdown accessibility service only if there are no references to accessibles in JS. r=surkov
MozReview-Commit-ID: BTOuBQXA1Ly
This commit is contained in:
parent
d66a45ac98
commit
b2b4d318c0
@ -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->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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user