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:
Yura Zenevich 2016-11-18 23:29:10 -05:00
Родитель d66a45ac98
Коммит b2b4d318c0
18 изменённых файлов: 662 добавлений и 51 удалений

Просмотреть файл

@ -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]

Просмотреть файл

@ -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;