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 |