зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1415408
- send 'a11y-consumers-changed' notifcation whenever accessibility services consumers change. r=surkov
MozReview-Commit-ID: 2V4X4AO3JAT
This commit is contained in:
Родитель
446a07beed
Коммит
aa6a1a9b17
|
@ -25,6 +25,7 @@
|
|||
#include "nsAttrName.h"
|
||||
#include "nsEventShell.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "OuterDocAccessible.h"
|
||||
#include "Role.h"
|
||||
#ifdef MOZ_ACCESSIBILITY_ATK
|
||||
|
@ -1397,8 +1398,7 @@ nsAccessibilityService::Shutdown()
|
|||
// if someone will try to operate with it.
|
||||
|
||||
MOZ_ASSERT(gConsumers, "Accessibility was shutdown already");
|
||||
|
||||
gConsumers = 0;
|
||||
UnsetConsumers(eXPCOM | eMainProcess | ePlatformAPI);
|
||||
|
||||
// Remove observers.
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
|
@ -1856,6 +1856,47 @@ nsAccessibilityService::CreateAccessibleForXULTree(nsIContent* aContent,
|
|||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
nsAccessibilityService::SetConsumers(uint32_t aConsumers) {
|
||||
if (gConsumers & aConsumers) {
|
||||
return;
|
||||
}
|
||||
|
||||
gConsumers |= aConsumers;
|
||||
NotifyOfConsumersChange();
|
||||
}
|
||||
|
||||
void
|
||||
nsAccessibilityService::UnsetConsumers(uint32_t aConsumers) {
|
||||
if (!(gConsumers & aConsumers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
gConsumers &= ~aConsumers;
|
||||
NotifyOfConsumersChange();
|
||||
}
|
||||
|
||||
void
|
||||
nsAccessibilityService::NotifyOfConsumersChange()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
if (!observerService) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char16_t* kJSONFmt =
|
||||
u"{ \"XPCOM\": %s, \"MainProcess\": %s, \"PlatformAPI\": %s }";
|
||||
nsString json;
|
||||
nsTextFormatter::ssprintf(json, kJSONFmt,
|
||||
gConsumers & eXPCOM ? "true" : "false",
|
||||
gConsumers & eMainProcess ? "true" : "false",
|
||||
gConsumers & ePlatformAPI ? "true" : "false");
|
||||
observerService->NotifyObservers(
|
||||
nullptr, "a11y-consumers-changed", json.get());
|
||||
}
|
||||
|
||||
nsAccessibilityService*
|
||||
GetOrCreateAccService(uint32_t aNewConsumer)
|
||||
{
|
||||
|
@ -1869,7 +1910,7 @@ GetOrCreateAccService(uint32_t aNewConsumer)
|
|||
|
||||
MOZ_ASSERT(nsAccessibilityService::gAccessibilityService,
|
||||
"Accessible service is not initialized.");
|
||||
nsAccessibilityService::gConsumers |= aNewConsumer;
|
||||
nsAccessibilityService::gAccessibilityService->SetConsumers(aNewConsumer);
|
||||
return nsAccessibilityService::gAccessibilityService;
|
||||
}
|
||||
|
||||
|
@ -1887,14 +1928,15 @@ MaybeShutdownAccService(uint32_t aFormerConsumer)
|
|||
xpcAccessibilityService::IsInUse() ||
|
||||
accService->HasXPCDocuments()) {
|
||||
// Still used by XPCOM
|
||||
nsAccessibilityService::gConsumers =
|
||||
(nsAccessibilityService::gConsumers & ~aFormerConsumer) |
|
||||
nsAccessibilityService::eXPCOM;
|
||||
if (aFormerConsumer != nsAccessibilityService::eXPCOM) {
|
||||
// Only unset non-XPCOM consumers.
|
||||
accService->UnsetConsumers(aFormerConsumer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (nsAccessibilityService::gConsumers & ~aFormerConsumer) {
|
||||
nsAccessibilityService::gConsumers &= ~aFormerConsumer;
|
||||
accService->UnsetConsumers(aFormerConsumer);
|
||||
} else {
|
||||
accService->Shutdown(); // Will unset all nsAccessibilityService::gConsumers
|
||||
}
|
||||
|
|
|
@ -304,6 +304,21 @@ private:
|
|||
CreateAccessibleByFrameType(nsIFrame* aFrame, nsIContent* aContent,
|
||||
Accessible* aContext);
|
||||
|
||||
/**
|
||||
* Notify observers about change of the accessibility service's consumers.
|
||||
*/
|
||||
void NotifyOfConsumersChange();
|
||||
|
||||
/**
|
||||
* Set accessibility service consumers.
|
||||
*/
|
||||
void SetConsumers(uint32_t aConsumers);
|
||||
|
||||
/**
|
||||
* Unset accessibility service consumers.
|
||||
*/
|
||||
void UnsetConsumers(uint32_t aConsumers);
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
/**
|
||||
* Create accessible for XUL tree element.
|
||||
|
|
|
@ -25,22 +25,40 @@ add_task(async function() {
|
|||
// the a11y service in parent as well.
|
||||
let parentA11yInit = initPromise();
|
||||
let contentA11yInit = initPromise(browser);
|
||||
let parentConsumersChanged = a11yConsumersChangedPromise();
|
||||
let contentConsumersChanged =
|
||||
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
ok(accService, "Service initialized in parent");
|
||||
await Promise.all([parentA11yInit, contentA11yInit]);
|
||||
await parentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: true, MainProcess: false, PlatformAPI: false
|
||||
}, "Accessibility service consumers in parent are correct."));
|
||||
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: false, MainProcess: true, PlatformAPI: false
|
||||
}, "Accessibility service consumers in content are correct."));
|
||||
|
||||
info("Removing a service in parent and waiting for service to be shut " +
|
||||
"down in content");
|
||||
// Remove a11y service reference in the main process.
|
||||
let parentA11yShutdown = shutdownPromise();
|
||||
let contentA11yShutdown = shutdownPromise(browser);
|
||||
parentConsumersChanged = a11yConsumersChangedPromise();
|
||||
contentConsumersChanged =
|
||||
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed in parent");
|
||||
// Force garbage collection that should trigger shutdown in both main and
|
||||
// content process.
|
||||
forceGC();
|
||||
await Promise.all([parentA11yShutdown, contentA11yShutdown]);
|
||||
await parentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: false, MainProcess: false, PlatformAPI: false
|
||||
}, "Accessibility service consumers are correct."));
|
||||
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: false, MainProcess: false, PlatformAPI: false
|
||||
}, "Accessibility service consumers are correct."));
|
||||
});
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
|
|
|
@ -25,22 +25,34 @@ add_task(async function() {
|
|||
// the a11y service in parent as well.
|
||||
let parentA11yInit = initPromise();
|
||||
let contentA11yInit = initPromise(browser);
|
||||
let contentConsumersChanged =
|
||||
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
ok(accService, "Service initialized in parent");
|
||||
await Promise.all([parentA11yInit, contentA11yInit]);
|
||||
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: false, MainProcess: true, PlatformAPI: false
|
||||
}, "Accessibility service consumers in content are correct."));
|
||||
|
||||
info("Adding additional reference to accessibility service in content " +
|
||||
"process");
|
||||
contentConsumersChanged =
|
||||
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
|
||||
// Add a new reference to the a11y service inside the content process.
|
||||
loadFrameScripts(browser, `let accService = Components.classes[
|
||||
'@mozilla.org/accessibilityService;1'].getService(
|
||||
Components.interfaces.nsIAccessibilityService);`);
|
||||
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: true, MainProcess: true, PlatformAPI: false
|
||||
}, "Accessibility service consumers in content are correct."));
|
||||
|
||||
info("Shutting down a service in parent and making sure the one in " +
|
||||
"content stays alive");
|
||||
let contentCanShutdown = false;
|
||||
let parentA11yShutdown = shutdownPromise();
|
||||
contentConsumersChanged =
|
||||
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
|
||||
// This promise will resolve only if contentCanShutdown flag is set to true.
|
||||
// If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before
|
||||
// it can be shut down, the promise will reject.
|
||||
|
@ -57,6 +69,9 @@ add_task(async function() {
|
|||
forceGC();
|
||||
loadFrameScripts(browser, `Components.utils.forceGC();`);
|
||||
await parentA11yShutdown;
|
||||
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: true, MainProcess: false, PlatformAPI: false
|
||||
}, "Accessibility service consumers in content are correct."));
|
||||
|
||||
// Have some breathing room between a11y service shutdowns.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
|
@ -64,10 +79,15 @@ add_task(async function() {
|
|||
info("Removing a service in content");
|
||||
// Now allow a11y service to shutdown in content.
|
||||
contentCanShutdown = true;
|
||||
contentConsumersChanged =
|
||||
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
|
||||
// Remove last reference to a11y service in content and force garbage
|
||||
// collection that should trigger shutdown.
|
||||
loadFrameScripts(browser, `accService = null; Components.utils.forceGC();`);
|
||||
await contentA11yShutdown;
|
||||
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: false, MainProcess: false, PlatformAPI: false
|
||||
}, "Accessibility service consumers in content are correct."));
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
await unsetE10sPrefs();
|
||||
|
|
|
@ -37,6 +37,20 @@ Services.scriptloader.loadSubScript(
|
|||
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
|
||||
this);
|
||||
|
||||
/**
|
||||
* Returns a promise that resolves when 'a11y-consumers-changed' event is fired.
|
||||
* @return {Promise} event promise evaluating to event's data
|
||||
*/
|
||||
function a11yConsumersChangedPromise() {
|
||||
return new Promise(resolve => {
|
||||
let observe = (subject, topic, data) => {
|
||||
Services.obs.removeObserver(observe, "a11y-consumers-changed");
|
||||
resolve(JSON.parse(data));
|
||||
};
|
||||
Services.obs.addObserver(observe, "a11y-consumers-changed");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise that resolves when 'a11y-init-or-shutdown' event is fired.
|
||||
* @return {Promise} event promise evaluating to event's data
|
||||
|
|
Загрузка…
Ссылка в новой задаче