Chromium Code Reviews| 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 @[ | |
|
dmazzoni
2014/07/29 06:35:14
Cool, no wonder I didn't know about this, I just l
| |
| 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::Detach() { | |
| 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 |