Commit ffc34741 authored by Dominic Mazzoni's avatar Dominic Mazzoni Committed by Commit Bot

Support aria-activedescendant in comboboxes on Mac with VoiceOver.

Mac's accessibility API doesn't have a way for us to expose the
active descendant of a control. For something like a list box or grid,
we just pretend that the active descendant is actually focused and that
basically works.

For a combobox, we need VoiceOver to announce the selected option
while keeping focus on the text box. Fix this by exposing the
AXOwns relationship, which VoiceOver uses to find a list box owned
by a combo box.

Rather than plumbing through aria-owns, instead we just expose the
parent of the activeDescendant target. That way things just work if
the author uses aria-activedescendant correctly even if they forget
aria-owns.

Also implements AXHasPopup to match Safari.

Bug: 829945
Change-Id: I7f670ecb8af1056e14e889d31aa52a9917719964
Reviewed-on: https://chromium-review.googlesource.com/999958
Commit-Queue: Dominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarNektarios Paisios <nektar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#549286}
parent 21b59335
......@@ -69,12 +69,14 @@ NSString* const NSAccessibilityDropEffectsAttribute = @"AXDropEffects";
NSString* const NSAccessibilityEditableAncestorAttribute =
@"AXEditableAncestor";
NSString* const NSAccessibilityGrabbedAttribute = @"AXGrabbed";
NSString* const NSAccessibilityHasPopupAttribute = @"AXHasPopup";
NSString* const NSAccessibilityHighestEditableAncestorAttribute =
@"AXHighestEditableAncestor";
NSString* const NSAccessibilityInvalidAttribute = @"AXInvalid";
NSString* const NSAccessibilityIsMultiSelectableAttribute =
@"AXIsMultiSelectable";
NSString* const NSAccessibilityLoadingProgressAttribute = @"AXLoadingProgress";
NSString* const NSAccessibilityOwnsAttribute = @"AXOwns";
NSString* const
NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute =
@"AXUIElementCountForSearchPredicate";
......@@ -583,6 +585,7 @@ NSString* const NSAccessibilityRequiredAttributeChrome = @"AXRequired";
{NSAccessibilityFocusedAttribute, @"focused"},
{NSAccessibilityGrabbedAttribute, @"grabbed"},
{NSAccessibilityHeaderAttribute, @"header"},
{NSAccessibilityHasPopupAttribute, @"hasPopup"},
{NSAccessibilityHelpAttribute, @"help"},
{NSAccessibilityHighestEditableAncestorAttribute,
@"highestEditableAncestor"},
......@@ -598,6 +601,7 @@ NSString* const NSAccessibilityRequiredAttributeChrome = @"AXRequired";
{NSAccessibilityMinValueAttribute, @"minValue"},
{NSAccessibilityNumberOfCharactersAttribute, @"numberOfCharacters"},
{NSAccessibilityOrientationAttribute, @"orientation"},
{NSAccessibilityOwnsAttribute, @"owns"},
{NSAccessibilityParentAttribute, @"parent"},
{NSAccessibilityPlaceholderValueAttribute, @"placeholderValue"},
{NSAccessibilityPositionAttribute, @"position"},
......@@ -1108,6 +1112,13 @@ NSString* const NSAccessibilityRequiredAttributeChrome = @"AXRequired";
return [NSNumber numberWithBool:NO];
}
- (NSNumber*)hasPopup {
if (![self instanceActive])
return nil;
return browserAccessibility_->HasState(ax::mojom::State::kHaspopup) ? @YES
: @NO;
}
- (id)header {
if (![self instanceActive])
return nil;
......@@ -1360,6 +1371,40 @@ NSString* const NSAccessibilityRequiredAttributeChrome = @"AXRequired";
return @"";
}
- (id)owns {
if (![self instanceActive])
return nil;
//
// If the active descendant points to an element in a container with
// selectable children, add the "owns" relationship to point to that
// container. That's the only way activeDescendant is actually
// supported with VoiceOver.
//
int activeDescendantId;
if (!browserAccessibility_->GetIntAttribute(
ax::mojom::IntAttribute::kActivedescendantId, &activeDescendantId))
return nil;
BrowserAccessibilityManager* manager = browserAccessibility_->manager();
BrowserAccessibility* activeDescendant =
manager->GetFromID(activeDescendantId);
if (!activeDescendant)
return nil;
BrowserAccessibility* container = activeDescendant->PlatformGetParent();
while (container &&
!ui::IsContainerWithSelectableChildrenRole(container->GetRole()))
container = container->PlatformGetParent();
if (!container)
return nil;
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
[ret addObject:ToBrowserAccessibilityCocoa(container)];
return ret;
}
- (NSNumber*)numberOfCharacters {
if (![self instanceActive])
return nil;
......@@ -2984,6 +3029,10 @@ NSString* const NSAccessibilityRequiredAttributeChrome = @"AXRequired";
[ret addObjectsFromArray:@[ NSAccessibilityGrabbedAttribute ]];
}
if (browserAccessibility_->HasState(ax::mojom::State::kHaspopup)) {
[ret addObjectsFromArray:@[ NSAccessibilityHasPopupAttribute ]];
}
// Add expanded attribute only if it has expanded or collapsed state.
if (GetState(browserAccessibility_, ax::mojom::State::kExpanded) ||
GetState(browserAccessibility_, ax::mojom::State::kCollapsed)) {
......@@ -3009,6 +3058,12 @@ NSString* const NSAccessibilityRequiredAttributeChrome = @"AXRequired";
[ret addObjectsFromArray:@[ NSAccessibilityLanguageAttribute ]];
}
if ([self internalRole] == ax::mojom::Role::kTextFieldWithComboBox) {
[ret addObjectsFromArray:@[
NSAccessibilityOwnsAttribute,
]];
}
// Title UI Element.
if (browserAccessibility_->HasIntListAttribute(
ax::mojom::IntListAttribute::kLabelledbyIds) &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment