Bug 1682985 - Support aria-busy with AXElementBusy and AXElementBusyChanged. r=morgan

Differential Revision: https://phabricator.services.mozilla.com/D100838
This commit is contained in:
Eitan Isaacson 2021-01-06 17:23:45 +00:00
parent 093ed43459
commit c21730a605
7 changed files with 85 additions and 12 deletions

View File

@ -124,6 +124,9 @@
// AXRequired // AXRequired
- (NSNumber* _Nullable)moxRequired; - (NSNumber* _Nullable)moxRequired;
// AXElementBusy
- (NSNumber* _Nullable)moxElementBusy;
// AXDOMIdentifier // AXDOMIdentifier
- (NSString* _Nullable)moxDOMIdentifier; - (NSString* _Nullable)moxDOMIdentifier;

View File

@ -38,6 +38,9 @@ using namespace mozilla::a11y;
// override // override
- (BOOL)moxBlockSelector:(SEL)selector; - (BOOL)moxBlockSelector:(SEL)selector;
// override
- (void)moxPostNotification:(NSString*)notification;
// override // override
- (void)handleAccessibleEvent:(uint32_t)eventType; - (void)handleAccessibleEvent:(uint32_t)eventType;

View File

@ -223,9 +223,23 @@ using namespace mozilla::a11y;
return YES; return YES;
} }
if (selector == @selector(moxElementBusy)) {
// Don't confuse aria-busy with a document's busy state.
return YES;
}
return [super moxBlockSelector:selector]; return [super moxBlockSelector:selector];
} }
- (void)moxPostNotification:(NSString*)notification {
if (![notification isEqualToString:@"AXElementBusyChanged"]) {
// Suppress AXElementBusyChanged since it uses gecko's BUSY state
// to tell VoiceOver about aria-busy changes. We use that state
// differently in documents.
[super moxPostNotification:notification];
}
}
- (id)rootGroup { - (id)rootGroup {
NSArray* children = [super moxUnignoredChildren]; NSArray* children = [super moxUnignoredChildren];
if (mRole != roles::APPLICATION && [children count] == 1 && if (mRole != roles::APPLICATION && [children count] == 1 &&

View File

@ -208,6 +208,9 @@ inline mozAccessible* GetNativeFromGeckoAccessible(
// override // override
- (NSNumber*)moxRequired; - (NSNumber*)moxRequired;
// override
- (NSNumber*)moxElementBusy;
// override // override
- (id)moxEditableAncestor; - (id)moxEditableAncestor;

View File

@ -111,7 +111,7 @@ using namespace mozilla::a11y;
static const uint64_t kCachedStates = static const uint64_t kCachedStates =
states::CHECKED | states::PRESSED | states::MIXED | states::EXPANDED | states::CHECKED | states::PRESSED | states::MIXED | states::EXPANDED |
states::CURRENT | states::SELECTED | states::TRAVERSED | states::LINKED | states::CURRENT | states::SELECTED | states::TRAVERSED | states::LINKED |
states::HASPOPUP; states::HASPOPUP | states::BUSY;
static const uint64_t kCacheInitialized = ((uint64_t)0x1) << 63; static const uint64_t kCacheInitialized = ((uint64_t)0x1) << 63;
- (uint64_t)state { - (uint64_t)state {
@ -143,19 +143,20 @@ static const uint64_t kCacheInitialized = ((uint64_t)0x1) << 63;
} }
- (void)stateChanged:(uint64_t)state isEnabled:(BOOL)enabled { - (void)stateChanged:(uint64_t)state isEnabled:(BOOL)enabled {
if ((state & kCachedStates) == 0) { if ((state & kCachedStates) != 0) {
return; if (!(mCachedState & kCacheInitialized)) {
[self state];
} else {
if (enabled) {
mCachedState |= state;
} else {
mCachedState &= ~state;
}
}
} }
if (!(mCachedState & kCacheInitialized)) { if (state == states::BUSY) {
[self state]; [self moxPostNotification:@"AXElementBusyChanged"];
return;
}
if (enabled) {
mCachedState |= state;
} else {
mCachedState &= ~state;
} }
} }
@ -789,6 +790,10 @@ struct RoleDescrComparator {
return @([self stateWithMask:states::REQUIRED] != 0); return @([self stateWithMask:states::REQUIRED] != 0);
} }
- (NSNumber*)moxElementBusy {
return @([self stateWithMask:states::BUSY] != 0);
}
- (mozAccessible*)topWebArea { - (mozAccessible*)topWebArea {
AccessibleOrProxy doc = [self geckoDocument]; AccessibleOrProxy doc = [self geckoDocument];
while (!doc.IsNull()) { while (!doc.IsNull()) {

View File

@ -46,3 +46,4 @@ skip-if = os == 'mac' && debug # Bug 1664577
[browser_menulist.js] [browser_menulist.js]
[browser_rich_listbox.js] [browser_rich_listbox.js]
[browser_live_regions.js] [browser_live_regions.js]
[browser_aria_busy.js]

View File

@ -0,0 +1,44 @@
/* 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";
/* import-globals-from ../../mochitest/role.js */
/* import-globals-from ../../mochitest/states.js */
loadScripts(
{ name: "role.js", dir: MOCHITESTS_DIR },
{ name: "states.js", dir: MOCHITESTS_DIR }
);
/**
* Test aria-busy
*/
addAccessibleTask(
`<div id="section" role="group">Hello</div>`,
async (browser, accDoc) => {
let section = getNativeInterface(accDoc, "section");
ok(!section.getAttributeValue("AXElementBusy"), "section is not busy");
let busyChanged = waitForMacEvent("AXElementBusyChanged", "section");
await SpecialPowers.spawn(browser, [], () => {
content.document
.getElementById("section")
.setAttribute("aria-busy", "true");
});
await busyChanged;
ok(section.getAttributeValue("AXElementBusy"), "section is busy");
busyChanged = waitForMacEvent("AXElementBusyChanged", "section");
await SpecialPowers.spawn(browser, [], () => {
content.document
.getElementById("section")
.setAttribute("aria-busy", "false");
});
await busyChanged;
ok(!section.getAttributeValue("AXElementBusy"), "section is not busy");
}
);