OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "ui/accessibility/platform/ax_platform_node_mac.h" |
| 6 |
| 7 #import <Cocoa/Cocoa.h> |
| 8 |
| 9 #include "base/strings/sys_string_conversions.h" |
| 10 #import "ui/accessibility/platform/ax_platform_node_delegate.h" |
| 11 #import "ui/gfx/mac/coordinate_conversion.h" |
| 12 |
| 13 namespace { |
| 14 |
| 15 struct MapEntry { |
| 16 ui::AXRole value; |
| 17 NSString* nativeValue; |
| 18 }; |
| 19 |
| 20 typedef std::map<ui::AXRole, NSString*> RoleMap; |
| 21 |
| 22 RoleMap BuildRoleMap() { |
| 23 const MapEntry roles[] = { |
| 24 {ui::AX_ROLE_ALERT, NSAccessibilityGroupRole}, |
| 25 {ui::AX_ROLE_ALERT_DIALOG, NSAccessibilityGroupRole}, |
| 26 {ui::AX_ROLE_ANNOTATION, NSAccessibilityUnknownRole}, |
| 27 {ui::AX_ROLE_APPLICATION, NSAccessibilityGroupRole}, |
| 28 {ui::AX_ROLE_ARTICLE, NSAccessibilityGroupRole}, |
| 29 {ui::AX_ROLE_BANNER, NSAccessibilityGroupRole}, |
| 30 {ui::AX_ROLE_BROWSER, NSAccessibilityBrowserRole}, |
| 31 {ui::AX_ROLE_BUSY_INDICATOR, NSAccessibilityBusyIndicatorRole}, |
| 32 {ui::AX_ROLE_BUTTON, NSAccessibilityButtonRole}, |
| 33 {ui::AX_ROLE_CANVAS, NSAccessibilityImageRole}, |
| 34 {ui::AX_ROLE_CELL, @"AXCell"}, |
| 35 {ui::AX_ROLE_CHECK_BOX, NSAccessibilityCheckBoxRole}, |
| 36 {ui::AX_ROLE_COLOR_WELL, NSAccessibilityColorWellRole}, |
| 37 {ui::AX_ROLE_COLUMN, NSAccessibilityColumnRole}, |
| 38 {ui::AX_ROLE_COLUMN_HEADER, @"AXCell"}, |
| 39 {ui::AX_ROLE_COMBO_BOX, NSAccessibilityComboBoxRole}, |
| 40 {ui::AX_ROLE_COMPLEMENTARY, NSAccessibilityGroupRole}, |
| 41 {ui::AX_ROLE_CONTENT_INFO, NSAccessibilityGroupRole}, |
| 42 {ui::AX_ROLE_DEFINITION, NSAccessibilityGroupRole}, |
| 43 {ui::AX_ROLE_DESCRIPTION_LIST_DETAIL, NSAccessibilityGroupRole}, |
| 44 {ui::AX_ROLE_DESCRIPTION_LIST_TERM, NSAccessibilityGroupRole}, |
| 45 {ui::AX_ROLE_DIALOG, NSAccessibilityGroupRole}, |
| 46 {ui::AX_ROLE_DIRECTORY, NSAccessibilityListRole}, |
| 47 {ui::AX_ROLE_DISCLOSURE_TRIANGLE, NSAccessibilityDisclosureTriangleRole}, |
| 48 {ui::AX_ROLE_DIV, NSAccessibilityGroupRole}, |
| 49 {ui::AX_ROLE_DOCUMENT, NSAccessibilityGroupRole}, |
| 50 {ui::AX_ROLE_DRAWER, NSAccessibilityDrawerRole}, |
| 51 {ui::AX_ROLE_EDITABLE_TEXT, NSAccessibilityTextFieldRole}, |
| 52 {ui::AX_ROLE_FOOTER, NSAccessibilityGroupRole}, |
| 53 {ui::AX_ROLE_FORM, NSAccessibilityGroupRole}, |
| 54 {ui::AX_ROLE_GRID, NSAccessibilityGridRole}, |
| 55 {ui::AX_ROLE_GROUP, NSAccessibilityGroupRole}, |
| 56 {ui::AX_ROLE_GROW_AREA, NSAccessibilityGrowAreaRole}, |
| 57 {ui::AX_ROLE_HEADING, @"AXHeading"}, |
| 58 {ui::AX_ROLE_HELP_TAG, NSAccessibilityHelpTagRole}, |
| 59 {ui::AX_ROLE_HORIZONTAL_RULE, NSAccessibilityGroupRole}, |
| 60 {ui::AX_ROLE_IFRAME, NSAccessibilityGroupRole}, |
| 61 {ui::AX_ROLE_IGNORED, NSAccessibilityUnknownRole}, |
| 62 {ui::AX_ROLE_IMAGE, NSAccessibilityImageRole}, |
| 63 {ui::AX_ROLE_IMAGE_MAP, NSAccessibilityGroupRole}, |
| 64 {ui::AX_ROLE_IMAGE_MAP_LINK, NSAccessibilityLinkRole}, |
| 65 {ui::AX_ROLE_INCREMENTOR, NSAccessibilityIncrementorRole}, |
| 66 {ui::AX_ROLE_LABEL_TEXT, NSAccessibilityGroupRole}, |
| 67 {ui::AX_ROLE_LINK, NSAccessibilityLinkRole}, |
| 68 {ui::AX_ROLE_LIST, NSAccessibilityListRole}, |
| 69 {ui::AX_ROLE_LIST_BOX, NSAccessibilityListRole}, |
| 70 {ui::AX_ROLE_LIST_BOX_OPTION, NSAccessibilityStaticTextRole}, |
| 71 {ui::AX_ROLE_LIST_ITEM, NSAccessibilityGroupRole}, |
| 72 {ui::AX_ROLE_LIST_MARKER, @"AXListMarker"}, |
| 73 {ui::AX_ROLE_LOG, NSAccessibilityGroupRole}, |
| 74 {ui::AX_ROLE_MAIN, NSAccessibilityGroupRole}, |
| 75 {ui::AX_ROLE_MARQUEE, NSAccessibilityGroupRole}, |
| 76 {ui::AX_ROLE_MATH, NSAccessibilityGroupRole}, |
| 77 {ui::AX_ROLE_MATTE, NSAccessibilityMatteRole}, |
| 78 {ui::AX_ROLE_MENU, NSAccessibilityMenuRole}, |
| 79 {ui::AX_ROLE_MENU_BAR, NSAccessibilityMenuBarRole}, |
| 80 {ui::AX_ROLE_MENU_BUTTON, NSAccessibilityButtonRole}, |
| 81 {ui::AX_ROLE_MENU_ITEM, NSAccessibilityMenuItemRole}, |
| 82 {ui::AX_ROLE_MENU_LIST_OPTION, NSAccessibilityMenuItemRole}, |
| 83 {ui::AX_ROLE_MENU_LIST_POPUP, NSAccessibilityUnknownRole}, |
| 84 {ui::AX_ROLE_NAVIGATION, NSAccessibilityGroupRole}, |
| 85 {ui::AX_ROLE_NOTE, NSAccessibilityGroupRole}, |
| 86 {ui::AX_ROLE_OUTLINE, NSAccessibilityOutlineRole}, |
| 87 {ui::AX_ROLE_PARAGRAPH, NSAccessibilityGroupRole}, |
| 88 {ui::AX_ROLE_POP_UP_BUTTON, NSAccessibilityPopUpButtonRole}, |
| 89 {ui::AX_ROLE_PRESENTATIONAL, NSAccessibilityGroupRole}, |
| 90 {ui::AX_ROLE_PROGRESS_INDICATOR, NSAccessibilityProgressIndicatorRole}, |
| 91 {ui::AX_ROLE_RADIO_BUTTON, NSAccessibilityRadioButtonRole}, |
| 92 {ui::AX_ROLE_RADIO_GROUP, NSAccessibilityRadioGroupRole}, |
| 93 {ui::AX_ROLE_REGION, NSAccessibilityGroupRole}, |
| 94 {ui::AX_ROLE_ROOT_WEB_AREA, @"AXWebArea"}, |
| 95 {ui::AX_ROLE_ROW, NSAccessibilityRowRole}, |
| 96 {ui::AX_ROLE_ROW_HEADER, @"AXCell"}, |
| 97 {ui::AX_ROLE_RULER, NSAccessibilityRulerRole}, |
| 98 {ui::AX_ROLE_RULER_MARKER, NSAccessibilityRulerMarkerRole}, |
| 99 {ui::AX_ROLE_SCROLL_BAR, NSAccessibilityScrollBarRole}, |
| 100 {ui::AX_ROLE_SEARCH, NSAccessibilityGroupRole}, |
| 101 {ui::AX_ROLE_SHEET, NSAccessibilitySheetRole}, |
| 102 {ui::AX_ROLE_SLIDER, NSAccessibilitySliderRole}, |
| 103 {ui::AX_ROLE_SLIDER_THUMB, NSAccessibilityValueIndicatorRole}, |
| 104 {ui::AX_ROLE_SPIN_BUTTON, NSAccessibilitySliderRole}, |
| 105 {ui::AX_ROLE_SPLITTER, NSAccessibilitySplitterRole}, |
| 106 {ui::AX_ROLE_SPLIT_GROUP, NSAccessibilitySplitGroupRole}, |
| 107 {ui::AX_ROLE_STATIC_TEXT, NSAccessibilityStaticTextRole}, |
| 108 {ui::AX_ROLE_STATUS, NSAccessibilityGroupRole}, |
| 109 {ui::AX_ROLE_SVG_ROOT, NSAccessibilityGroupRole}, |
| 110 {ui::AX_ROLE_SYSTEM_WIDE, NSAccessibilityUnknownRole}, |
| 111 {ui::AX_ROLE_TAB, NSAccessibilityRadioButtonRole}, |
| 112 {ui::AX_ROLE_TABLE, NSAccessibilityTableRole}, |
| 113 {ui::AX_ROLE_TABLE_HEADER_CONTAINER, NSAccessibilityGroupRole}, |
| 114 {ui::AX_ROLE_TAB_LIST, NSAccessibilityTabGroupRole}, |
| 115 {ui::AX_ROLE_TAB_PANEL, NSAccessibilityGroupRole}, |
| 116 {ui::AX_ROLE_TEXT_AREA, NSAccessibilityTextAreaRole}, |
| 117 {ui::AX_ROLE_TEXT_FIELD, NSAccessibilityTextFieldRole}, |
| 118 {ui::AX_ROLE_TIMER, NSAccessibilityGroupRole}, |
| 119 {ui::AX_ROLE_TOGGLE_BUTTON, NSAccessibilityCheckBoxRole}, |
| 120 {ui::AX_ROLE_TOOLBAR, NSAccessibilityToolbarRole}, |
| 121 {ui::AX_ROLE_TOOLTIP, NSAccessibilityGroupRole}, |
| 122 {ui::AX_ROLE_TREE, NSAccessibilityOutlineRole}, |
| 123 {ui::AX_ROLE_TREE_GRID, NSAccessibilityTableRole}, |
| 124 {ui::AX_ROLE_TREE_ITEM, NSAccessibilityRowRole}, |
| 125 {ui::AX_ROLE_VALUE_INDICATOR, NSAccessibilityValueIndicatorRole}, |
| 126 {ui::AX_ROLE_WEB_AREA, @"AXWebArea"}, |
| 127 {ui::AX_ROLE_WINDOW, NSAccessibilityWindowRole}, |
| 128 |
| 129 // TODO(dtseng): we don't correctly support the attributes for these |
| 130 // roles. |
| 131 // { ui::AX_ROLE_SCROLL_AREA, NSAccessibilityScrollAreaRole }, |
| 132 }; |
| 133 |
| 134 RoleMap role_map; |
| 135 for (size_t i = 0; i < arraysize(roles); ++i) |
| 136 role_map[roles[i].value] = roles[i].nativeValue; |
| 137 return role_map; |
| 138 } |
| 139 |
| 140 RoleMap BuildSubroleMap() { |
| 141 const MapEntry subroles[] = { |
| 142 {ui::AX_ROLE_ALERT, @"AXApplicationAlert"}, |
| 143 {ui::AX_ROLE_ALERT_DIALOG, @"AXApplicationAlertDialog"}, |
| 144 {ui::AX_ROLE_ARTICLE, @"AXDocumentArticle"}, |
| 145 {ui::AX_ROLE_DEFINITION, @"AXDefinition"}, |
| 146 {ui::AX_ROLE_DESCRIPTION_LIST_DETAIL, @"AXDescription"}, |
| 147 {ui::AX_ROLE_DESCRIPTION_LIST_TERM, @"AXTerm"}, |
| 148 {ui::AX_ROLE_DIALOG, @"AXApplicationDialog"}, |
| 149 {ui::AX_ROLE_DOCUMENT, @"AXDocument"}, |
| 150 {ui::AX_ROLE_FOOTER, @"AXLandmarkContentInfo"}, |
| 151 {ui::AX_ROLE_APPLICATION, @"AXLandmarkApplication"}, |
| 152 {ui::AX_ROLE_BANNER, @"AXLandmarkBanner"}, |
| 153 {ui::AX_ROLE_COMPLEMENTARY, @"AXLandmarkComplementary"}, |
| 154 {ui::AX_ROLE_CONTENT_INFO, @"AXLandmarkContentInfo"}, |
| 155 {ui::AX_ROLE_MAIN, @"AXLandmarkMain"}, |
| 156 {ui::AX_ROLE_NAVIGATION, @"AXLandmarkNavigation"}, |
| 157 {ui::AX_ROLE_SEARCH, @"AXLandmarkSearch"}, |
| 158 {ui::AX_ROLE_LOG, @"AXApplicationLog"}, |
| 159 {ui::AX_ROLE_MARQUEE, @"AXApplicationMarquee"}, |
| 160 {ui::AX_ROLE_MATH, @"AXDocumentMath"}, |
| 161 {ui::AX_ROLE_NOTE, @"AXDocumentNote"}, |
| 162 {ui::AX_ROLE_REGION, @"AXDocumentRegion"}, |
| 163 {ui::AX_ROLE_STATUS, @"AXApplicationStatus"}, |
| 164 {ui::AX_ROLE_TAB_PANEL, @"AXTabPanel"}, |
| 165 {ui::AX_ROLE_TIMER, @"AXApplicationTimer"}, |
| 166 {ui::AX_ROLE_TOGGLE_BUTTON, @"AXToggleButton"}, |
| 167 {ui::AX_ROLE_TOOLTIP, @"AXUserInterfaceTooltip"}, |
| 168 {ui::AX_ROLE_TREE_ITEM, NSAccessibilityOutlineRowSubrole}, |
| 169 }; |
| 170 |
| 171 RoleMap subrole_map; |
| 172 for (size_t i = 0; i < arraysize(subroles); ++i) |
| 173 subrole_map[subroles[i].value] = subroles[i].nativeValue; |
| 174 return subrole_map; |
| 175 } |
| 176 |
| 177 } // namespace |
| 178 |
| 179 @implementation AXPlatformNodeCocoa |
| 180 |
| 181 // A mapping of AX roles to native roles. |
| 182 + (NSString*)nativeRoleFromAXRole:(ui::AXRole)role { |
| 183 CR_DEFINE_STATIC_LOCAL(RoleMap, role_map, (BuildRoleMap())); |
| 184 RoleMap::iterator it = role_map.find(role); |
| 185 return it != role_map.end() ? it->second : NSAccessibilityUnknownRole; |
| 186 } |
| 187 |
| 188 // A mapping of AX roles to native subroles. |
| 189 + (NSString*)nativeSubroleFromAXRole:(ui::AXRole)role { |
| 190 CR_DEFINE_STATIC_LOCAL(RoleMap, subrole_map, (BuildSubroleMap())); |
| 191 RoleMap::iterator it = subrole_map.find(role); |
| 192 return it != subrole_map.end() ? it->second : nil; |
| 193 } |
| 194 |
| 195 - (instancetype)initWithNode:(ui::AXPlatformNode*)node { |
| 196 if ((self = [super init])) { |
| 197 node_ = node; |
| 198 } |
| 199 return self; |
| 200 } |
| 201 |
| 202 - (void)detach { |
| 203 node_ = nil; |
| 204 } |
| 205 |
| 206 - (NSRect)boundsInScreen { |
| 207 if (!node_) |
| 208 return NSZeroRect; |
| 209 return gfx::ScreenRectToNSRect(node_->GetBoundsInScreen()); |
| 210 } |
| 211 |
| 212 - (BOOL)accessibilityIsIgnored { |
| 213 return [[self AXRole] isEqualToString:NSAccessibilityUnknownRole]; |
| 214 } |
| 215 |
| 216 - (id)accessibilityHitTest:(NSPoint)point { |
| 217 for (AXPlatformNodeCocoa* child in [self AXChildren]) { |
| 218 if (NSPointInRect(point, child.boundsInScreen)) |
| 219 return [child accessibilityHitTest:point]; |
| 220 } |
| 221 return NSAccessibilityUnignoredAncestor(self); |
| 222 } |
| 223 |
| 224 - (NSArray*)accessibilityActionNames { |
| 225 return nil; |
| 226 } |
| 227 |
| 228 - (NSArray*)accessibilityAttributeNames { |
| 229 return @[ |
| 230 NSAccessibilityChildrenAttribute, |
| 231 NSAccessibilityParentAttribute, |
| 232 NSAccessibilityPositionAttribute, |
| 233 NSAccessibilityRoleAttribute, |
| 234 NSAccessibilitySizeAttribute, |
| 235 NSAccessibilityTitleAttribute, |
| 236 ]; |
| 237 } |
| 238 |
| 239 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute { |
| 240 return NO; |
| 241 } |
| 242 |
| 243 - (id)accessibilityAttributeValue:(NSString*)attribute { |
| 244 SEL selector = NSSelectorFromString(attribute); |
| 245 if ([self respondsToSelector:selector]) |
| 246 return [self performSelector:selector]; |
| 247 return nil; |
| 248 } |
| 249 |
| 250 - (NSArray*)AXChildren { |
| 251 if (!node_) |
| 252 return nil; |
| 253 int count = node_->GetChildCount(); |
| 254 NSMutableArray* children = [NSMutableArray arrayWithCapacity:count]; |
| 255 for (int i = 0; i < count; ++i) |
| 256 [children addObject:node_->ChildAtIndex(i)]; |
| 257 return NSAccessibilityUnignoredChildren(children); |
| 258 } |
| 259 |
| 260 - (id)AXParent { |
| 261 if (!node_) |
| 262 return nil; |
| 263 return NSAccessibilityUnignoredAncestor(node_->GetParent()); |
| 264 } |
| 265 |
| 266 - (NSValue*)AXPosition { |
| 267 return [NSValue valueWithPoint:self.boundsInScreen.origin]; |
| 268 } |
| 269 |
| 270 - (NSString*)AXRole { |
| 271 if (!node_) |
| 272 return nil; |
| 273 return [[self class] nativeRoleFromAXRole:node_->GetRole()]; |
| 274 } |
| 275 |
| 276 - (NSValue*)AXSize { |
| 277 return [NSValue valueWithSize:self.boundsInScreen.size]; |
| 278 } |
| 279 |
| 280 @end |
| 281 |
| 282 namespace ui { |
| 283 |
| 284 // static |
| 285 AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) { |
| 286 AXPlatformNode* node = new AXPlatformNodeMac(); |
| 287 node->Init(delegate); |
| 288 return node; |
| 289 } |
| 290 |
| 291 AXPlatformNodeMac::AXPlatformNodeMac() { |
| 292 } |
| 293 |
| 294 AXPlatformNodeMac::~AXPlatformNodeMac() { |
| 295 } |
| 296 |
| 297 void AXPlatformNodeMac::Destroy() { |
| 298 if (native_node_) |
| 299 [native_node_ detach]; |
| 300 delegate_ = NULL; |
| 301 delete this; |
| 302 } |
| 303 |
| 304 gfx::NativeViewAccessible AXPlatformNodeMac::GetNativeViewAccessible() { |
| 305 if (!native_node_) |
| 306 native_node_.reset([[AXPlatformNodeCocoa alloc] initWithNode:this]); |
| 307 return native_node_.get(); |
| 308 } |
| 309 |
| 310 } // namespace ui |
OLD | NEW |