Chromium Code Reviews| Index: ui/accessibility/platform/ax_platform_node_mac.mm |
| diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm |
| index 2845950d812966d7d3131546b8777f1cdf400ecd..af0782e20ab84cebccc790e0d3618106b8f609fe 100644 |
| --- a/ui/accessibility/platform/ax_platform_node_mac.mm |
| +++ b/ui/accessibility/platform/ax_platform_node_mac.mm |
| @@ -16,15 +16,21 @@ |
| namespace { |
| -struct MapEntry { |
| +struct RoleMapEntry { |
| ui::AXRole value; |
| NSString* nativeValue; |
| }; |
| +struct EventMapEntry { |
| + ui::AXEvent value; |
| + NSString* nativeValue; |
| +}; |
| + |
| typedef std::map<ui::AXRole, NSString*> RoleMap; |
| +typedef std::map<ui::AXEvent, NSString*> EventMap; |
| RoleMap BuildRoleMap() { |
| - const MapEntry roles[] = { |
| + const RoleMapEntry roles[] = { |
| {ui::AX_ROLE_ABBR, NSAccessibilityGroupRole}, |
| {ui::AX_ROLE_ALERT, NSAccessibilityGroupRole}, |
| {ui::AX_ROLE_ALERT_DIALOG, NSAccessibilityGroupRole}, |
| @@ -150,7 +156,7 @@ RoleMap BuildRoleMap() { |
| } |
| RoleMap BuildSubroleMap() { |
| - const MapEntry subroles[] = { |
| + const RoleMapEntry subroles[] = { |
| {ui::AX_ROLE_ALERT, @"AXApplicationAlert"}, |
| {ui::AX_ROLE_ALERT_DIALOG, @"AXApplicationAlertDialog"}, |
| {ui::AX_ROLE_APPLICATION, @"AXLandmarkApplication"}, |
| @@ -189,6 +195,27 @@ RoleMap BuildSubroleMap() { |
| return subrole_map; |
| } |
| +EventMap BuildEventMap() { |
| + const EventMapEntry events[] = { |
| + {ui::AX_EVENT_TEXT_CHANGED, NSAccessibilityTitleChangedNotification}, |
| + {ui::AX_EVENT_VALUE_CHANGED, NSAccessibilityValueChangedNotification}, |
| + {ui::AX_EVENT_TEXT_SELECTION_CHANGED, |
| + NSAccessibilitySelectedTextChangedNotification}, |
| + // TODO(patricialor): Add more events. |
| + }; |
| + |
| + EventMap event_map; |
| + for (size_t i = 0; i < arraysize(events); ++i) { |
| + event_map[events[i].value] = events[i].nativeValue; |
| + } |
| + return event_map; |
| +} |
| + |
| +void NotifyMacEvent(ui::AXEvent event_type, gfx::AcceleratedWidget target) { |
| + NSAccessibilityPostNotification( |
| + target, [AXPlatformNodeCocoa nativeNotificationFromAXEvent:event_type]); |
| +} |
| + |
| } // namespace |
| @interface AXPlatformNodeCocoa () |
| @@ -212,6 +239,13 @@ RoleMap BuildSubroleMap() { |
| return it != subrole_map.end() ? it->second : nil; |
| } |
| +// A mapping of AX events to native notifications. |
| ++ (NSString*)nativeNotificationFromAXEvent:(ui::AXEvent)event { |
| + CR_DEFINE_STATIC_LOCAL(EventMap, event_map, (BuildEventMap())); |
| + EventMap::iterator it = event_map.find(event); |
| + return it != event_map.end() ? it->second : nil; |
| +} |
| + |
| - (instancetype)initWithNode:(ui::AXPlatformNodeBase*)node { |
| if ((self = [super init])) { |
| node_ = node; |
| @@ -270,16 +304,30 @@ RoleMap BuildSubroleMap() { |
| // Attributes which are not required, but are general to all roles. |
| NSAccessibilityRoleDescriptionAttribute, |
| + NSAccessibilityEnabledAttribute, |
| + NSAccessibilityFocusedAttribute, |
| ]; |
| // Attributes required for user-editable controls. |
| NSArray* const kValueAttributes = @[ NSAccessibilityValueAttribute ]; |
| + // Attributes required for textfields. |
| + NSArray* const kTextfieldAttributes = @[ |
| + NSAccessibilityInsertionPointLineNumberAttribute, |
| + NSAccessibilityNumberOfCharactersAttribute, |
| + NSAccessibilityPlaceholderValueAttribute, |
| + NSAccessibilitySelectedTextAttribute, |
| + NSAccessibilitySelectedTextRangeAttribute, |
| + NSAccessibilityVisibleCharacterRangeAttribute, |
| + ]; |
| + |
| base::scoped_nsobject<NSMutableArray> axAttributes( |
| [[NSMutableArray alloc] init]); |
| [axAttributes addObjectsFromArray:kAllRoleAttributes]; |
| switch (node_->GetData().role) { |
| + case ui::AX_ROLE_TEXT_FIELD: |
| + [axAttributes addObjectsFromArray:kTextfieldAttributes]; |
|
dmazzoni
2016/06/29 16:24:11
Please add a comment like "fallthrough" so that it
Patti Lor
2016/06/30 05:29:54
Done.
|
| case ui::AX_ROLE_CHECK_BOX: |
| case ui::AX_ROLE_COMBO_BOX: |
| case ui::AX_ROLE_MENU_ITEM_CHECK_BOX: |
| @@ -289,7 +337,6 @@ RoleMap BuildSubroleMap() { |
| case ui::AX_ROLE_SLIDER: |
| case ui::AX_ROLE_SLIDER_THUMB: |
| case ui::AX_ROLE_TOGGLE_BUTTON: |
| - case ui::AX_ROLE_TEXT_FIELD: |
| [axAttributes addObjectsFromArray:kValueAttributes]; |
| break; |
| // TODO(tapted): Add additional attributes based on role. |
| @@ -371,6 +418,63 @@ RoleMap BuildSubroleMap() { |
| return [self getStringAttribute:ui::AX_ATTR_VALUE]; |
| } |
| +- (NSValue*)AXEnabled { |
| + // TODO(patricialor): Check with dmazzoni@ to see if AX_STATE_ENABLED is still |
|
dmazzoni
2016/06/29 16:24:11
This is correct for now, no TODO needed. My plan i
Patti Lor
2016/06/30 05:29:54
Removed, thanks for clarifying!
|
| + // relevant. |
| + return [NSNumber |
| + numberWithBool:!ui::AXViewState::IsFlagSet(node_->GetData().state, |
| + ui::AX_STATE_DISABLED)]; |
| +} |
| + |
| +- (NSValue*)AXFocused { |
| + if (ui::AXViewState::IsFlagSet(node_->GetData().state, |
| + ui::AX_STATE_FOCUSABLE) && |
| + ui::AXViewState::IsFlagSet(node_->GetData().state, ui::AX_STATE_FOCUSED)) |
| + return [NSNumber numberWithBool:YES]; |
| + return [NSNumber numberWithBool:NO]; |
| +} |
| + |
| +// Textfield-specific NSAccessibility attributes. |
| + |
| +- (NSNumber*)AXInsertionPointLineNumber { |
| + // Multiline is not supported on views. |
| + return [NSNumber numberWithInteger:0]; |
| +} |
| + |
| +- (NSNumber*)AXNumberOfCharacters { |
| + return [NSNumber numberWithInteger:[[self AXValue] length]]; |
| +} |
| + |
| +- (NSString*)AXPlaceholderValue { |
| + return [self getStringAttribute:ui::AX_ATTR_PLACEHOLDER]; |
| +} |
| + |
| +- (NSString*)AXSelectedText { |
| + NSRange selectedTextRange; |
| + [[self AXSelectedTextRange] getValue:&selectedTextRange]; |
| + return [[self AXValue] substringWithRange:selectedTextRange]; |
| +} |
| + |
| +- (NSValue*)AXSelectedTextRange { |
| + int textDir, start, end; |
| + node_->GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION, &textDir); |
| + node_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START, &start); |
| + node_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, &end); |
| + // NSRange cannot represent the direction the text was selected in, so make |
| + // sure the correct selection index is used when creating a new range, taking |
| + // into account the textfield text direction as well. |
| + bool isReversed = (textDir == ui::AX_TEXT_DIRECTION_RTL) || |
| + (textDir == ui::AX_TEXT_DIRECTION_BTT); |
| + int beginSelectionIndex = (end > start && !isReversed) ? start : end; |
| + return [NSValue |
| + valueWithRange:NSMakeRange(beginSelectionIndex, abs(end - start))]; |
| +} |
| + |
| +- (NSValue*)AXVisibleCharacterRange { |
| + return [NSValue |
| + valueWithRange:NSMakeRange(0, [[self AXNumberOfCharacters] intValue])]; |
| +} |
| + |
| @end |
| namespace ui { |
| @@ -401,7 +505,24 @@ gfx::NativeViewAccessible AXPlatformNodeMac::GetNativeViewAccessible() { |
| } |
| void AXPlatformNodeMac::NotifyAccessibilityEvent(ui::AXEvent event_type) { |
| - // TODO(dmazzoni): implement this. http://crbug.com/396137 |
| + gfx::AcceleratedWidget target = |
| + GetDelegate()->GetTargetForNativeAccessibilityEvent(); |
| + |
| + // Add mappings between ui::AXEvent and NSAccessibility notifications using |
| + // the EventMap above. This switch contains exceptions to those mappings. |
| + switch (event_type) { |
| + case ui::AX_EVENT_TEXT_CHANGED: |
| + // If the view is a user-editable textfield, this should change the value. |
| + if (GetData().role == ui::AX_ROLE_TEXT_FIELD) { |
| + NSAccessibilityPostNotification( |
| + target, NSAccessibilityValueChangedNotification); |
| + return; |
| + } |
| + break; |
| + default: |
| + break; |
| + } |
| + NotifyMacEvent(event_type, target); |
| } |
| int AXPlatformNodeMac::GetIndexInParent() { |