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