gecko-dev/accessible/mac/mozSelectableElements.mm
Eitan Isaacson d0f0c96f5e Bug 1641655 - Remove NSAccessibility methods from mozSelectableElements. r=morgan
A casualty of this is the "switch" action description for pressing tabs. That code
goes way back to our first Mac a11y support. WebKit and Chromium don't have it.

I tried to figure out when other browsers or apps had that with no luck.
Anyway, removing that description gives us the same behavior in VO as
WebKit and Chromium where there are no custom action description strings.

Differential Revision: https://phabricator.services.mozilla.com/D77342
2020-05-28 22:41:23 +00:00

213 lines
5.7 KiB
Plaintext

/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=2:
*/
/* 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/. */
#import "mozSelectableElements.h"
@implementation mozSelectableAccessible
/**
* Return the mozAccessibles that are selectable.
*/
- (NSArray*)selectableChildren {
return [[self moxChildren]
filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(mozAccessible* child,
NSDictionary* bindings) {
return [child isKindOfClass:[mozSelectableChildAccessible class]];
}]];
}
- (void)moxSetSelectedChildren:(NSArray*)selectedChildren {
for (id child in [self selectableChildren]) {
BOOL selected = [selectedChildren indexOfObjectIdenticalTo:child] != NSNotFound;
[child moxSetSelected:@(selected)];
}
}
/**
* Return the mozAccessibles that are actually selected.
*/
- (NSArray*)moxSelectedChildren {
return [[self moxChildren]
filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(mozAccessible* child,
NSDictionary* bindings) {
// Return mozSelectableChildAccessibles that have are selected (truthy value).
return [child isKindOfClass:[mozSelectableChildAccessible class]] &&
[[(mozSelectableChildAccessible*)child moxSelected] boolValue];
}]];
}
@end
@implementation mozSelectableChildAccessible
- (NSNumber*)moxSelected {
return @([self stateWithMask:states::SELECTED] != 0);
}
- (void)moxSetSelected:(NSNumber*)selected {
// Get SELECTABLE and UNAVAILABLE state.
uint64_t state = [self stateWithMask:(states::SELECTABLE | states::UNAVAILABLE)];
if ((state & states::SELECTABLE) == 0 || (state & states::UNAVAILABLE) != 0) {
// The object is either not selectable or is unavailable. Don't do anything.
return;
}
if (Accessible* acc = mGeckoAccessible.AsAccessible()) {
acc->SetSelected([selected boolValue]);
} else {
mGeckoAccessible.AsProxy()->SetSelected([selected boolValue]);
}
// We need to invalidate the state because the accessibility service
// may check the selected attribute synchornously and not wait for
// selection events.
[self invalidateState];
}
@end
@implementation mozTabGroupAccessible
- (NSArray*)moxTabs {
return [self selectableChildren];
}
- (NSArray*)moxContents {
return [self moxChildren];
}
- (id)moxValue {
// The value of a tab group is its selected child. In the case
// of multiple selections this will return the first one.
return [[self moxSelectedChildren] firstObject];
}
@end
@implementation mozTabAccessible
- (NSString*)moxRoleDescription {
return utils::LocalizedString(NS_LITERAL_STRING("tab"));
}
- (id)moxValue {
// Retuens 1 if item is selected, 0 if not.
return [self moxSelected];
}
@end
@implementation mozListboxAccessible
- (BOOL)ignoreChild:(mozAccessible*)child {
if (!child || child->mRole == roles::GROUPING) {
return YES;
}
return [super ignoreChild:child];
}
- (BOOL)disableChild:(mozAccessible*)child {
return ![child isKindOfClass:[mozSelectableChildAccessible class]];
}
- (NSString*)moxOrientation {
return NSAccessibilityUnknownOrientationValue;
}
@end
@implementation mozOptionAccessible
- (NSString*)moxTitle {
return @"";
}
- (id)moxValue {
// Swap title and value of option so it behaves more like a AXStaticText.
return [super moxTitle];
}
@end
@implementation mozMenuAccessible
- (NSString*)moxTitle {
return @"";
}
- (NSString*)moxLabel {
return @"";
}
- (void)moxPostNotification:(NSString*)notification {
[super moxPostNotification:notification];
if ([notification isEqualToString:@"AXMenuOpened"]) {
mIsOpened = YES;
} else if ([notification isEqualToString:@"AXMenuClosed"]) {
mIsOpened = NO;
}
}
- (void)expire {
if (mIsOpened) {
// VO needs to receive a menu closed event when the menu goes away.
// If the menu is being destroyed, send a menu closed event first.
[self moxPostNotification:@"AXMenuClosed"];
}
[super expire];
}
@end
@implementation mozMenuItemAccessible
- (NSString*)moxLabel {
return @"";
}
- (NSString*)moxMenuItemMarkChar {
Accessible* acc = mGeckoAccessible.AsAccessible();
if (acc && acc->IsContent() && acc->GetContent()->IsXULElement(nsGkAtoms::menuitem)) {
// We need to provide a marker character. This is the visible "√" you see
// on dropdown menus. In our a11y tree this is a single child text node
// of the menu item.
// We do this only with XUL menuitems that conform to the native theme, and not
// with aria menu items that might have a pseudo element or something.
if (acc->ChildCount() == 1 && acc->FirstChild()->Role() == roles::STATICTEXT) {
nsAutoString marker;
acc->FirstChild()->Name(marker);
if (marker.Length() == 1) {
return nsCocoaUtils::ToNSString(marker);
}
}
}
return nil;
}
- (NSNumber*)moxSelected {
// Our focused state is equivelent to native selected states for menus.
return @([self stateWithMask:states::FOCUSED] != 0);
}
- (void)handleAccessibleEvent:(uint32_t)eventType {
switch (eventType) {
case nsIAccessibleEvent::EVENT_FOCUS:
// Our focused state is equivelent to native selected states for menus.
mozAccessible* parent = (mozAccessible*)[self moxParent];
[parent moxPostNotification:NSAccessibilitySelectedChildrenChangedNotification];
break;
}
[super handleAccessibleEvent:eventType];
}
@end