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 |
new file mode 100644 |
index 0000000000000000000000000000000000000000..40bcaf3f2b0abd54b8e5cb28ef67be13c23d967b |
--- /dev/null |
+++ b/ui/accessibility/platform/ax_platform_node_mac.mm |
@@ -0,0 +1,311 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "ui/accessibility/platform/ax_platform_node_mac.h" |
+ |
+#import <Cocoa/Cocoa.h> |
+ |
+#include "base/strings/sys_string_conversions.h" |
+#import "ui/accessibility/platform/ax_platform_node_delegate.h" |
+#import "ui/gfx/mac/coordinate_conversion.h" |
+ |
+namespace { |
+ |
+struct MapEntry { |
+ ui::AXRole value; |
+ NSString* nativeValue; |
+}; |
+ |
+typedef std::map<ui::AXRole, NSString*> RoleMap; |
+ |
+RoleMap BuildRoleMap() { |
+ const MapEntry roles[] = { |
+ {ui::AX_ROLE_ALERT, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_ALERT_DIALOG, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_ANNOTATION, NSAccessibilityUnknownRole}, |
+ {ui::AX_ROLE_APPLICATION, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_ARTICLE, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_BANNER, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_BROWSER, NSAccessibilityBrowserRole}, |
+ {ui::AX_ROLE_BUSY_INDICATOR, NSAccessibilityBusyIndicatorRole}, |
+ {ui::AX_ROLE_BUTTON, NSAccessibilityButtonRole}, |
+ {ui::AX_ROLE_CANVAS, NSAccessibilityImageRole}, |
+ {ui::AX_ROLE_CELL, @"AXCell"}, |
+ {ui::AX_ROLE_CHECK_BOX, NSAccessibilityCheckBoxRole}, |
+ {ui::AX_ROLE_COLOR_WELL, NSAccessibilityColorWellRole}, |
+ {ui::AX_ROLE_COLUMN, NSAccessibilityColumnRole}, |
+ {ui::AX_ROLE_COLUMN_HEADER, @"AXCell"}, |
+ {ui::AX_ROLE_COMBO_BOX, NSAccessibilityComboBoxRole}, |
+ {ui::AX_ROLE_COMPLEMENTARY, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_CONTENT_INFO, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_DEFINITION, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_DESCRIPTION_LIST_DETAIL, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_DESCRIPTION_LIST_TERM, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_DIALOG, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_DIRECTORY, NSAccessibilityListRole}, |
+ {ui::AX_ROLE_DISCLOSURE_TRIANGLE, NSAccessibilityDisclosureTriangleRole}, |
+ {ui::AX_ROLE_DIV, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_DOCUMENT, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_DRAWER, NSAccessibilityDrawerRole}, |
+ {ui::AX_ROLE_EDITABLE_TEXT, NSAccessibilityTextFieldRole}, |
+ {ui::AX_ROLE_FOOTER, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_FORM, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_GRID, NSAccessibilityGridRole}, |
+ {ui::AX_ROLE_GROUP, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_GROW_AREA, NSAccessibilityGrowAreaRole}, |
+ {ui::AX_ROLE_HEADING, @"AXHeading"}, |
+ {ui::AX_ROLE_HELP_TAG, NSAccessibilityHelpTagRole}, |
+ {ui::AX_ROLE_HORIZONTAL_RULE, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_IFRAME, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_IGNORED, NSAccessibilityUnknownRole}, |
+ {ui::AX_ROLE_IMAGE, NSAccessibilityImageRole}, |
+ {ui::AX_ROLE_IMAGE_MAP, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_IMAGE_MAP_LINK, NSAccessibilityLinkRole}, |
+ {ui::AX_ROLE_INCREMENTOR, NSAccessibilityIncrementorRole}, |
+ {ui::AX_ROLE_LABEL_TEXT, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_LINK, NSAccessibilityLinkRole}, |
+ {ui::AX_ROLE_LIST, NSAccessibilityListRole}, |
+ {ui::AX_ROLE_LIST_BOX, NSAccessibilityListRole}, |
+ {ui::AX_ROLE_LIST_BOX_OPTION, NSAccessibilityStaticTextRole}, |
+ {ui::AX_ROLE_LIST_ITEM, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_LIST_MARKER, @"AXListMarker"}, |
+ {ui::AX_ROLE_LOG, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_MAIN, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_MARQUEE, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_MATH, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_MATTE, NSAccessibilityMatteRole}, |
+ {ui::AX_ROLE_MENU, NSAccessibilityMenuRole}, |
+ {ui::AX_ROLE_MENU_BAR, NSAccessibilityMenuBarRole}, |
+ {ui::AX_ROLE_MENU_BUTTON, NSAccessibilityButtonRole}, |
+ {ui::AX_ROLE_MENU_ITEM, NSAccessibilityMenuItemRole}, |
+ {ui::AX_ROLE_MENU_LIST_OPTION, NSAccessibilityMenuItemRole}, |
+ {ui::AX_ROLE_MENU_LIST_POPUP, NSAccessibilityUnknownRole}, |
+ {ui::AX_ROLE_NAVIGATION, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_NOTE, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_OUTLINE, NSAccessibilityOutlineRole}, |
+ {ui::AX_ROLE_PARAGRAPH, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_POP_UP_BUTTON, NSAccessibilityPopUpButtonRole}, |
+ {ui::AX_ROLE_PRESENTATIONAL, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_PROGRESS_INDICATOR, NSAccessibilityProgressIndicatorRole}, |
+ {ui::AX_ROLE_RADIO_BUTTON, NSAccessibilityRadioButtonRole}, |
+ {ui::AX_ROLE_RADIO_GROUP, NSAccessibilityRadioGroupRole}, |
+ {ui::AX_ROLE_REGION, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_ROOT_WEB_AREA, @"AXWebArea"}, |
+ {ui::AX_ROLE_ROW, NSAccessibilityRowRole}, |
+ {ui::AX_ROLE_ROW_HEADER, @"AXCell"}, |
+ {ui::AX_ROLE_RULER, NSAccessibilityRulerRole}, |
+ {ui::AX_ROLE_RULER_MARKER, NSAccessibilityRulerMarkerRole}, |
+ {ui::AX_ROLE_SCROLL_BAR, NSAccessibilityScrollBarRole}, |
+ {ui::AX_ROLE_SEARCH, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_SHEET, NSAccessibilitySheetRole}, |
+ {ui::AX_ROLE_SLIDER, NSAccessibilitySliderRole}, |
+ {ui::AX_ROLE_SLIDER_THUMB, NSAccessibilityValueIndicatorRole}, |
+ {ui::AX_ROLE_SPIN_BUTTON, NSAccessibilitySliderRole}, |
+ {ui::AX_ROLE_SPLITTER, NSAccessibilitySplitterRole}, |
+ {ui::AX_ROLE_SPLIT_GROUP, NSAccessibilitySplitGroupRole}, |
+ {ui::AX_ROLE_STATIC_TEXT, NSAccessibilityStaticTextRole}, |
+ {ui::AX_ROLE_STATUS, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_SVG_ROOT, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_SYSTEM_WIDE, NSAccessibilityUnknownRole}, |
+ {ui::AX_ROLE_TAB, NSAccessibilityRadioButtonRole}, |
+ {ui::AX_ROLE_TABLE, NSAccessibilityTableRole}, |
+ {ui::AX_ROLE_TABLE_HEADER_CONTAINER, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_TAB_LIST, NSAccessibilityTabGroupRole}, |
+ {ui::AX_ROLE_TAB_PANEL, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_TEXT_AREA, NSAccessibilityTextAreaRole}, |
+ {ui::AX_ROLE_TEXT_FIELD, NSAccessibilityTextFieldRole}, |
+ {ui::AX_ROLE_TIMER, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_TOGGLE_BUTTON, NSAccessibilityCheckBoxRole}, |
+ {ui::AX_ROLE_TOOLBAR, NSAccessibilityToolbarRole}, |
+ {ui::AX_ROLE_TOOLTIP, NSAccessibilityGroupRole}, |
+ {ui::AX_ROLE_TREE, NSAccessibilityOutlineRole}, |
+ {ui::AX_ROLE_TREE_GRID, NSAccessibilityTableRole}, |
+ {ui::AX_ROLE_TREE_ITEM, NSAccessibilityRowRole}, |
+ {ui::AX_ROLE_VALUE_INDICATOR, NSAccessibilityValueIndicatorRole}, |
+ {ui::AX_ROLE_WEB_AREA, @"AXWebArea"}, |
+ {ui::AX_ROLE_WINDOW, NSAccessibilityWindowRole}, |
+ |
+ // TODO(dtseng): we don't correctly support the attributes for these |
+ // roles. |
+ // { ui::AX_ROLE_SCROLL_AREA, NSAccessibilityScrollAreaRole }, |
+ }; |
+ |
+ RoleMap role_map; |
+ for (size_t i = 0; i < arraysize(roles); ++i) |
+ role_map[roles[i].value] = roles[i].nativeValue; |
+ return role_map; |
+} |
+ |
+RoleMap BuildSubroleMap() { |
+ const MapEntry subroles[] = { |
+ {ui::AX_ROLE_ALERT, @"AXApplicationAlert"}, |
+ {ui::AX_ROLE_ALERT_DIALOG, @"AXApplicationAlertDialog"}, |
+ {ui::AX_ROLE_ARTICLE, @"AXDocumentArticle"}, |
+ {ui::AX_ROLE_DEFINITION, @"AXDefinition"}, |
+ {ui::AX_ROLE_DESCRIPTION_LIST_DETAIL, @"AXDescription"}, |
+ {ui::AX_ROLE_DESCRIPTION_LIST_TERM, @"AXTerm"}, |
+ {ui::AX_ROLE_DIALOG, @"AXApplicationDialog"}, |
+ {ui::AX_ROLE_DOCUMENT, @"AXDocument"}, |
+ {ui::AX_ROLE_FOOTER, @"AXLandmarkContentInfo"}, |
+ {ui::AX_ROLE_APPLICATION, @"AXLandmarkApplication"}, |
+ {ui::AX_ROLE_BANNER, @"AXLandmarkBanner"}, |
+ {ui::AX_ROLE_COMPLEMENTARY, @"AXLandmarkComplementary"}, |
+ {ui::AX_ROLE_CONTENT_INFO, @"AXLandmarkContentInfo"}, |
+ {ui::AX_ROLE_MAIN, @"AXLandmarkMain"}, |
+ {ui::AX_ROLE_NAVIGATION, @"AXLandmarkNavigation"}, |
+ {ui::AX_ROLE_SEARCH, @"AXLandmarkSearch"}, |
+ {ui::AX_ROLE_LOG, @"AXApplicationLog"}, |
+ {ui::AX_ROLE_MARQUEE, @"AXApplicationMarquee"}, |
+ {ui::AX_ROLE_MATH, @"AXDocumentMath"}, |
+ {ui::AX_ROLE_NOTE, @"AXDocumentNote"}, |
+ {ui::AX_ROLE_REGION, @"AXDocumentRegion"}, |
+ {ui::AX_ROLE_STATUS, @"AXApplicationStatus"}, |
+ {ui::AX_ROLE_TAB_PANEL, @"AXTabPanel"}, |
+ {ui::AX_ROLE_TIMER, @"AXApplicationTimer"}, |
+ {ui::AX_ROLE_TOGGLE_BUTTON, @"AXToggleButton"}, |
+ {ui::AX_ROLE_TOOLTIP, @"AXUserInterfaceTooltip"}, |
+ {ui::AX_ROLE_TREE_ITEM, NSAccessibilityOutlineRowSubrole}, |
+ }; |
+ |
+ RoleMap subrole_map; |
+ for (size_t i = 0; i < arraysize(subroles); ++i) |
+ subrole_map[subroles[i].value] = subroles[i].nativeValue; |
+ return subrole_map; |
+} |
+ |
+} // namespace |
+ |
+@implementation AXPlatformNodeCocoa |
+ |
+// A mapping of AX roles to native roles. |
++ (NSString*)nativeRoleFromAXRole:(ui::AXRole)role { |
+ CR_DEFINE_STATIC_LOCAL(RoleMap, role_map, (BuildRoleMap())); |
+ RoleMap::iterator it = role_map.find(role); |
+ return it != role_map.end() ? it->second : NSAccessibilityUnknownRole; |
+} |
+ |
+// A mapping of AX roles to native subroles. |
++ (NSString*)nativeSubroleFromAXRole:(ui::AXRole)role { |
+ CR_DEFINE_STATIC_LOCAL(RoleMap, subrole_map, (BuildSubroleMap())); |
+ RoleMap::iterator it = subrole_map.find(role); |
+ return it != subrole_map.end() ? it->second : nil; |
+} |
+ |
+- (instancetype)initWithNode:(ui::AXPlatformNodeBase*)node { |
+ if ((self = [super init])) { |
+ node_ = node; |
+ } |
+ return self; |
+} |
+ |
+- (void)detach { |
+ node_ = nil; |
+} |
+ |
+- (NSRect)boundsInScreen { |
+ if (!node_) |
+ return NSZeroRect; |
+ return gfx::ScreenRectToNSRect(node_->GetBoundsInScreen()); |
+} |
+ |
+- (NSArray*)AXChildren { |
+ if (!node_) |
+ return nil; |
+ int count = node_->GetChildCount(); |
+ NSMutableArray* children = [NSMutableArray arrayWithCapacity:count]; |
+ for (int i = 0; i < count; ++i) |
+ [children addObject:node_->ChildAtIndex(i)]; |
+ return NSAccessibilityUnignoredChildren(children); |
+} |
+ |
+- (id)AXParent { |
+ if (!node_) |
+ return nil; |
+ return NSAccessibilityUnignoredAncestor(node_->GetParent()); |
+} |
+ |
+- (NSValue*)AXPosition { |
+ return [NSValue valueWithPoint:self.boundsInScreen.origin]; |
+} |
+ |
+- (NSString*)AXRole { |
+ if (!node_) |
+ return nil; |
+ return [[self class] nativeRoleFromAXRole:node_->GetRole()]; |
+} |
+ |
+- (NSValue*)AXSize { |
+ return [NSValue valueWithSize:self.boundsInScreen.size]; |
+} |
+ |
+// NSAccessibility informal protocol implementation. |
+ |
+- (BOOL)accessibilityIsIgnored { |
+ return [[self AXRole] isEqualToString:NSAccessibilityUnknownRole]; |
+} |
+ |
+- (id)accessibilityHitTest:(NSPoint)point { |
+ for (AXPlatformNodeCocoa* child in [self AXChildren]) { |
+ if (NSPointInRect(point, child.boundsInScreen)) |
+ return [child accessibilityHitTest:point]; |
+ } |
+ return NSAccessibilityUnignoredAncestor(self); |
+} |
+ |
+- (NSArray*)accessibilityActionNames { |
+ return nil; |
+} |
+ |
+- (NSArray*)accessibilityAttributeNames { |
+ return @[ |
+ NSAccessibilityChildrenAttribute, |
+ NSAccessibilityParentAttribute, |
+ NSAccessibilityPositionAttribute, |
+ NSAccessibilityRoleAttribute, |
+ NSAccessibilitySizeAttribute, |
+ ]; |
+} |
+ |
+- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute { |
+ return NO; |
+} |
+ |
+- (id)accessibilityAttributeValue:(NSString*)attribute { |
+ SEL selector = NSSelectorFromString(attribute); |
+ if ([self respondsToSelector:selector]) |
+ return [self performSelector:selector]; |
+ return nil; |
+} |
+ |
+@end |
+ |
+namespace ui { |
+ |
+// static |
+AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) { |
+ AXPlatformNodeBase* node = new AXPlatformNodeMac(); |
+ node->Init(delegate); |
+ return node; |
+} |
+ |
+AXPlatformNodeMac::AXPlatformNodeMac() { |
+} |
+ |
+AXPlatformNodeMac::~AXPlatformNodeMac() { |
+} |
+ |
+void AXPlatformNodeMac::Destroy() { |
+ if (native_node_) |
+ [native_node_ detach]; |
+ delegate_ = NULL; |
+ delete this; |
+} |
+ |
+gfx::NativeViewAccessible AXPlatformNodeMac::GetNativeViewAccessible() { |
+ if (!native_node_) |
+ native_node_.reset([[AXPlatformNodeCocoa alloc] initWithNode:this]); |
+ return native_node_.get(); |
+} |
+ |
+} // namespace ui |