OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <execinfo.h> | 5 #include <execinfo.h> |
6 | 6 |
7 #import "content/browser/accessibility/browser_accessibility_cocoa.h" | 7 #import "content/browser/accessibility/browser_accessibility_cocoa.h" |
8 | 8 |
9 #include <map> | 9 #include <map> |
10 | 10 |
11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
12 #include "base/strings/string16.h" | 12 #include "base/strings/string16.h" |
13 #include "base/strings/sys_string_conversions.h" | 13 #include "base/strings/sys_string_conversions.h" |
14 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
15 #include "content/browser/accessibility/browser_accessibility_manager.h" | 15 #include "content/browser/accessibility/browser_accessibility_manager.h" |
16 #include "content/browser/accessibility/browser_accessibility_manager_mac.h" | 16 #include "content/browser/accessibility/browser_accessibility_manager_mac.h" |
17 #include "content/public/common/content_client.h" | 17 #include "content/public/common/content_client.h" |
18 #include "grit/webkit_strings.h" | 18 #include "grit/webkit_strings.h" |
| 19 #import "ui/accessibility/platform/ax_platform_node_mac.h" |
19 | 20 |
20 // See http://openradar.appspot.com/9896491. This SPI has been tested on 10.5, | 21 // See http://openradar.appspot.com/9896491. This SPI has been tested on 10.5, |
21 // 10.6, and 10.7. It allows accessibility clients to observe events posted on | 22 // 10.6, and 10.7. It allows accessibility clients to observe events posted on |
22 // this object. | 23 // this object. |
23 extern "C" void NSAccessibilityUnregisterUniqueIdForUIElement(id element); | 24 extern "C" void NSAccessibilityUnregisterUniqueIdForUIElement(id element); |
24 | 25 |
25 using ui::AXNodeData; | 26 using ui::AXNodeData; |
26 using content::BrowserAccessibility; | 27 using content::BrowserAccessibility; |
27 using content::BrowserAccessibilityManager; | 28 using content::BrowserAccessibilityManager; |
28 using content::BrowserAccessibilityManagerMac; | 29 using content::BrowserAccessibilityManagerMac; |
29 using content::ContentClient; | 30 using content::ContentClient; |
30 typedef ui::AXStringAttribute StringAttribute; | 31 typedef ui::AXStringAttribute StringAttribute; |
31 | 32 |
32 namespace { | 33 namespace { |
33 | 34 |
34 // Returns an autoreleased copy of the AXNodeData's attribute. | 35 // Returns an autoreleased copy of the AXNodeData's attribute. |
35 NSString* NSStringForStringAttribute( | 36 NSString* NSStringForStringAttribute( |
36 BrowserAccessibility* browserAccessibility, | 37 BrowserAccessibility* browserAccessibility, |
37 StringAttribute attribute) { | 38 StringAttribute attribute) { |
38 return base::SysUTF8ToNSString( | 39 return base::SysUTF8ToNSString( |
39 browserAccessibility->GetStringAttribute(attribute)); | 40 browserAccessibility->GetStringAttribute(attribute)); |
40 } | 41 } |
41 | 42 |
42 struct MapEntry { | |
43 ui::AXRole webKitValue; | |
44 NSString* nativeValue; | |
45 }; | |
46 | |
47 typedef std::map<ui::AXRole, NSString*> RoleMap; | |
48 | |
49 // GetState checks the bitmask used in AXNodeData to check | 43 // GetState checks the bitmask used in AXNodeData to check |
50 // if the given state was set on the accessibility object. | 44 // if the given state was set on the accessibility object. |
51 bool GetState(BrowserAccessibility* accessibility, ui::AXState state) { | 45 bool GetState(BrowserAccessibility* accessibility, ui::AXState state) { |
52 return ((accessibility->GetState() >> state) & 1); | 46 return ((accessibility->GetState() >> state) & 1); |
53 } | 47 } |
54 | 48 |
55 RoleMap BuildRoleMap() { | |
56 const MapEntry roles[] = { | |
57 { ui::AX_ROLE_ALERT, NSAccessibilityGroupRole }, | |
58 { ui::AX_ROLE_ALERT_DIALOG, NSAccessibilityGroupRole }, | |
59 { ui::AX_ROLE_ANNOTATION, NSAccessibilityUnknownRole }, | |
60 { ui::AX_ROLE_APPLICATION, NSAccessibilityGroupRole }, | |
61 { ui::AX_ROLE_ARTICLE, NSAccessibilityGroupRole }, | |
62 { ui::AX_ROLE_BANNER, NSAccessibilityGroupRole }, | |
63 { ui::AX_ROLE_BROWSER, NSAccessibilityBrowserRole }, | |
64 { ui::AX_ROLE_BUSY_INDICATOR, NSAccessibilityBusyIndicatorRole }, | |
65 { ui::AX_ROLE_BUTTON, NSAccessibilityButtonRole }, | |
66 { ui::AX_ROLE_CANVAS, NSAccessibilityImageRole }, | |
67 { ui::AX_ROLE_CELL, @"AXCell" }, | |
68 { ui::AX_ROLE_CHECK_BOX, NSAccessibilityCheckBoxRole }, | |
69 { ui::AX_ROLE_COLOR_WELL, NSAccessibilityColorWellRole }, | |
70 { ui::AX_ROLE_COLUMN, NSAccessibilityColumnRole }, | |
71 { ui::AX_ROLE_COLUMN_HEADER, @"AXCell" }, | |
72 { ui::AX_ROLE_COMBO_BOX, NSAccessibilityComboBoxRole }, | |
73 { ui::AX_ROLE_COMPLEMENTARY, NSAccessibilityGroupRole }, | |
74 { ui::AX_ROLE_CONTENT_INFO, NSAccessibilityGroupRole }, | |
75 { ui::AX_ROLE_DEFINITION, NSAccessibilityGroupRole }, | |
76 { ui::AX_ROLE_DESCRIPTION_LIST_DETAIL, NSAccessibilityGroupRole }, | |
77 { ui::AX_ROLE_DESCRIPTION_LIST_TERM, NSAccessibilityGroupRole }, | |
78 { ui::AX_ROLE_DIALOG, NSAccessibilityGroupRole }, | |
79 { ui::AX_ROLE_DIRECTORY, NSAccessibilityListRole }, | |
80 { ui::AX_ROLE_DISCLOSURE_TRIANGLE, NSAccessibilityDisclosureTriangleRole }, | |
81 { ui::AX_ROLE_DIV, NSAccessibilityGroupRole }, | |
82 { ui::AX_ROLE_DOCUMENT, NSAccessibilityGroupRole }, | |
83 { ui::AX_ROLE_DRAWER, NSAccessibilityDrawerRole }, | |
84 { ui::AX_ROLE_EDITABLE_TEXT, NSAccessibilityTextFieldRole }, | |
85 { ui::AX_ROLE_FOOTER, NSAccessibilityGroupRole }, | |
86 { ui::AX_ROLE_FORM, NSAccessibilityGroupRole }, | |
87 { ui::AX_ROLE_GRID, NSAccessibilityGridRole }, | |
88 { ui::AX_ROLE_GROUP, NSAccessibilityGroupRole }, | |
89 { ui::AX_ROLE_GROW_AREA, NSAccessibilityGrowAreaRole }, | |
90 { ui::AX_ROLE_HEADING, @"AXHeading" }, | |
91 { ui::AX_ROLE_HELP_TAG, NSAccessibilityHelpTagRole }, | |
92 { ui::AX_ROLE_HORIZONTAL_RULE, NSAccessibilityGroupRole }, | |
93 { ui::AX_ROLE_IFRAME, NSAccessibilityGroupRole }, | |
94 { ui::AX_ROLE_IGNORED, NSAccessibilityUnknownRole }, | |
95 { ui::AX_ROLE_IMAGE, NSAccessibilityImageRole }, | |
96 { ui::AX_ROLE_IMAGE_MAP, NSAccessibilityGroupRole }, | |
97 { ui::AX_ROLE_IMAGE_MAP_LINK, NSAccessibilityLinkRole }, | |
98 { ui::AX_ROLE_INCREMENTOR, NSAccessibilityIncrementorRole }, | |
99 { ui::AX_ROLE_LABEL_TEXT, NSAccessibilityGroupRole }, | |
100 { ui::AX_ROLE_LINK, NSAccessibilityLinkRole }, | |
101 { ui::AX_ROLE_LIST, NSAccessibilityListRole }, | |
102 { ui::AX_ROLE_LIST_BOX, NSAccessibilityListRole }, | |
103 { ui::AX_ROLE_LIST_BOX_OPTION, NSAccessibilityStaticTextRole }, | |
104 { ui::AX_ROLE_LIST_ITEM, NSAccessibilityGroupRole }, | |
105 { ui::AX_ROLE_LIST_MARKER, @"AXListMarker" }, | |
106 { ui::AX_ROLE_LOG, NSAccessibilityGroupRole }, | |
107 { ui::AX_ROLE_MAIN, NSAccessibilityGroupRole }, | |
108 { ui::AX_ROLE_MARQUEE, NSAccessibilityGroupRole }, | |
109 { ui::AX_ROLE_MATH, NSAccessibilityGroupRole }, | |
110 { ui::AX_ROLE_MATTE, NSAccessibilityMatteRole }, | |
111 { ui::AX_ROLE_MENU, NSAccessibilityMenuRole }, | |
112 { ui::AX_ROLE_MENU_BAR, NSAccessibilityMenuBarRole }, | |
113 { ui::AX_ROLE_MENU_BUTTON, NSAccessibilityButtonRole }, | |
114 { ui::AX_ROLE_MENU_ITEM, NSAccessibilityMenuItemRole }, | |
115 { ui::AX_ROLE_MENU_LIST_OPTION, NSAccessibilityMenuItemRole }, | |
116 { ui::AX_ROLE_MENU_LIST_POPUP, NSAccessibilityUnknownRole }, | |
117 { ui::AX_ROLE_NAVIGATION, NSAccessibilityGroupRole }, | |
118 { ui::AX_ROLE_NOTE, NSAccessibilityGroupRole }, | |
119 { ui::AX_ROLE_OUTLINE, NSAccessibilityOutlineRole }, | |
120 { ui::AX_ROLE_PARAGRAPH, NSAccessibilityGroupRole }, | |
121 { ui::AX_ROLE_POP_UP_BUTTON, NSAccessibilityPopUpButtonRole }, | |
122 { ui::AX_ROLE_PRESENTATIONAL, NSAccessibilityGroupRole }, | |
123 { ui::AX_ROLE_PROGRESS_INDICATOR, NSAccessibilityProgressIndicatorRole }, | |
124 { ui::AX_ROLE_RADIO_BUTTON, NSAccessibilityRadioButtonRole }, | |
125 { ui::AX_ROLE_RADIO_GROUP, NSAccessibilityRadioGroupRole }, | |
126 { ui::AX_ROLE_REGION, NSAccessibilityGroupRole }, | |
127 { ui::AX_ROLE_ROOT_WEB_AREA, @"AXWebArea" }, | |
128 { ui::AX_ROLE_ROW, NSAccessibilityRowRole }, | |
129 { ui::AX_ROLE_ROW_HEADER, @"AXCell" }, | |
130 { ui::AX_ROLE_RULER, NSAccessibilityRulerRole }, | |
131 { ui::AX_ROLE_RULER_MARKER, NSAccessibilityRulerMarkerRole }, | |
132 { ui::AX_ROLE_SCROLL_BAR, NSAccessibilityScrollBarRole }, | |
133 { ui::AX_ROLE_SEARCH, NSAccessibilityGroupRole }, | |
134 { ui::AX_ROLE_SHEET, NSAccessibilitySheetRole }, | |
135 { ui::AX_ROLE_SLIDER, NSAccessibilitySliderRole }, | |
136 { ui::AX_ROLE_SLIDER_THUMB, NSAccessibilityValueIndicatorRole }, | |
137 { ui::AX_ROLE_SPIN_BUTTON, NSAccessibilitySliderRole }, | |
138 { ui::AX_ROLE_SPLITTER, NSAccessibilitySplitterRole }, | |
139 { ui::AX_ROLE_SPLIT_GROUP, NSAccessibilitySplitGroupRole }, | |
140 { ui::AX_ROLE_STATIC_TEXT, NSAccessibilityStaticTextRole }, | |
141 { ui::AX_ROLE_STATUS, NSAccessibilityGroupRole }, | |
142 { ui::AX_ROLE_SVG_ROOT, NSAccessibilityGroupRole }, | |
143 { ui::AX_ROLE_SYSTEM_WIDE, NSAccessibilityUnknownRole }, | |
144 { ui::AX_ROLE_TAB, NSAccessibilityRadioButtonRole }, | |
145 { ui::AX_ROLE_TABLE, NSAccessibilityTableRole }, | |
146 { ui::AX_ROLE_TABLE_HEADER_CONTAINER, NSAccessibilityGroupRole }, | |
147 { ui::AX_ROLE_TAB_LIST, NSAccessibilityTabGroupRole }, | |
148 { ui::AX_ROLE_TAB_PANEL, NSAccessibilityGroupRole }, | |
149 { ui::AX_ROLE_TEXT_AREA, NSAccessibilityTextAreaRole }, | |
150 { ui::AX_ROLE_TEXT_FIELD, NSAccessibilityTextFieldRole }, | |
151 { ui::AX_ROLE_TIMER, NSAccessibilityGroupRole }, | |
152 { ui::AX_ROLE_TOGGLE_BUTTON, NSAccessibilityCheckBoxRole }, | |
153 { ui::AX_ROLE_TOOLBAR, NSAccessibilityToolbarRole }, | |
154 { ui::AX_ROLE_TOOLTIP, NSAccessibilityGroupRole }, | |
155 { ui::AX_ROLE_TREE, NSAccessibilityOutlineRole }, | |
156 { ui::AX_ROLE_TREE_GRID, NSAccessibilityTableRole }, | |
157 { ui::AX_ROLE_TREE_ITEM, NSAccessibilityRowRole }, | |
158 { ui::AX_ROLE_VALUE_INDICATOR, NSAccessibilityValueIndicatorRole }, | |
159 { ui::AX_ROLE_WEB_AREA, @"AXWebArea" }, | |
160 { ui::AX_ROLE_WINDOW, NSAccessibilityWindowRole }, | |
161 | |
162 // TODO(dtseng): we don't correctly support the attributes for these roles. | |
163 // { ui::AX_ROLE_SCROLL_AREA, NSAccessibilityScrollAreaRole }, | |
164 }; | |
165 | |
166 RoleMap role_map; | |
167 for (size_t i = 0; i < arraysize(roles); ++i) | |
168 role_map[roles[i].webKitValue] = roles[i].nativeValue; | |
169 return role_map; | |
170 } | |
171 | |
172 // A mapping of webkit roles to native roles. | |
173 NSString* NativeRoleFromAXRole( | |
174 const ui::AXRole& role) { | |
175 CR_DEFINE_STATIC_LOCAL(RoleMap, web_accessibility_to_native_role, | |
176 (BuildRoleMap())); | |
177 RoleMap::iterator it = web_accessibility_to_native_role.find(role); | |
178 if (it != web_accessibility_to_native_role.end()) | |
179 return it->second; | |
180 else | |
181 return NSAccessibilityUnknownRole; | |
182 } | |
183 | |
184 RoleMap BuildSubroleMap() { | |
185 const MapEntry subroles[] = { | |
186 { ui::AX_ROLE_ALERT, @"AXApplicationAlert" }, | |
187 { ui::AX_ROLE_ALERT_DIALOG, @"AXApplicationAlertDialog" }, | |
188 { ui::AX_ROLE_ARTICLE, @"AXDocumentArticle" }, | |
189 { ui::AX_ROLE_DEFINITION, @"AXDefinition" }, | |
190 { ui::AX_ROLE_DESCRIPTION_LIST_DETAIL, @"AXDescription" }, | |
191 { ui::AX_ROLE_DESCRIPTION_LIST_TERM, @"AXTerm" }, | |
192 { ui::AX_ROLE_DIALOG, @"AXApplicationDialog" }, | |
193 { ui::AX_ROLE_DOCUMENT, @"AXDocument" }, | |
194 { ui::AX_ROLE_FOOTER, @"AXLandmarkContentInfo" }, | |
195 { ui::AX_ROLE_APPLICATION, @"AXLandmarkApplication" }, | |
196 { ui::AX_ROLE_BANNER, @"AXLandmarkBanner" }, | |
197 { ui::AX_ROLE_COMPLEMENTARY, @"AXLandmarkComplementary" }, | |
198 { ui::AX_ROLE_CONTENT_INFO, @"AXLandmarkContentInfo" }, | |
199 { ui::AX_ROLE_MAIN, @"AXLandmarkMain" }, | |
200 { ui::AX_ROLE_NAVIGATION, @"AXLandmarkNavigation" }, | |
201 { ui::AX_ROLE_SEARCH, @"AXLandmarkSearch" }, | |
202 { ui::AX_ROLE_LOG, @"AXApplicationLog" }, | |
203 { ui::AX_ROLE_MARQUEE, @"AXApplicationMarquee" }, | |
204 { ui::AX_ROLE_MATH, @"AXDocumentMath" }, | |
205 { ui::AX_ROLE_NOTE, @"AXDocumentNote" }, | |
206 { ui::AX_ROLE_REGION, @"AXDocumentRegion" }, | |
207 { ui::AX_ROLE_STATUS, @"AXApplicationStatus" }, | |
208 { ui::AX_ROLE_TAB_PANEL, @"AXTabPanel" }, | |
209 { ui::AX_ROLE_TIMER, @"AXApplicationTimer" }, | |
210 { ui::AX_ROLE_TOGGLE_BUTTON, @"AXToggleButton" }, | |
211 { ui::AX_ROLE_TOOLTIP, @"AXUserInterfaceTooltip" }, | |
212 { ui::AX_ROLE_TREE_ITEM, NSAccessibilityOutlineRowSubrole }, | |
213 }; | |
214 | |
215 RoleMap subrole_map; | |
216 for (size_t i = 0; i < arraysize(subroles); ++i) | |
217 subrole_map[subroles[i].webKitValue] = subroles[i].nativeValue; | |
218 return subrole_map; | |
219 } | |
220 | |
221 // A mapping of webkit roles to native subroles. | |
222 NSString* NativeSubroleFromAXRole( | |
223 const ui::AXRole& role) { | |
224 CR_DEFINE_STATIC_LOCAL(RoleMap, web_accessibility_to_native_subrole, | |
225 (BuildSubroleMap())); | |
226 RoleMap::iterator it = web_accessibility_to_native_subrole.find(role); | |
227 if (it != web_accessibility_to_native_subrole.end()) | |
228 return it->second; | |
229 else | |
230 return nil; | |
231 } | |
232 | |
233 // A mapping from an accessibility attribute to its method name. | 49 // A mapping from an accessibility attribute to its method name. |
234 NSDictionary* attributeToMethodNameMap = nil; | 50 NSDictionary* attributeToMethodNameMap = nil; |
235 | 51 |
236 } // namespace | 52 } // namespace |
237 | 53 |
238 @implementation BrowserAccessibilityCocoa | 54 @implementation BrowserAccessibilityCocoa |
239 | 55 |
240 + (void)initialize { | 56 + (void)initialize { |
241 const struct { | 57 const struct { |
242 NSString* attribute; | 58 NSString* attribute; |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
712 bool isAriaPressedDefined; | 528 bool isAriaPressedDefined; |
713 bool isMixed; | 529 bool isMixed; |
714 browserAccessibility_->GetAriaTristate("aria-pressed", | 530 browserAccessibility_->GetAriaTristate("aria-pressed", |
715 &isAriaPressedDefined, | 531 &isAriaPressedDefined, |
716 &isMixed); | 532 &isMixed); |
717 if (isAriaPressedDefined) | 533 if (isAriaPressedDefined) |
718 return NSAccessibilityCheckBoxRole; | 534 return NSAccessibilityCheckBoxRole; |
719 else | 535 else |
720 return NSAccessibilityButtonRole; | 536 return NSAccessibilityButtonRole; |
721 } | 537 } |
722 return NativeRoleFromAXRole(role); | 538 return [AXPlatformNodeCocoa nativeRoleFromAXRole:role]; |
723 } | 539 } |
724 | 540 |
725 // Returns a string indicating the role description of this object. | 541 // Returns a string indicating the role description of this object. |
726 - (NSString*)roleDescription { | 542 - (NSString*)roleDescription { |
727 NSString* role = [self role]; | 543 NSString* role = [self role]; |
728 | 544 |
729 ContentClient* content_client = content::GetContentClient(); | 545 ContentClient* content_client = content::GetContentClient(); |
730 | 546 |
731 // The following descriptions are specific to webkit. | 547 // The following descriptions are specific to webkit. |
732 if ([role isEqualToString:@"AXWebArea"]) { | 548 if ([role isEqualToString:@"AXWebArea"]) { |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
888 browserAccessibility_, ui::AX_ATTR_HTML_TAG); | 704 browserAccessibility_, ui::AX_ATTR_HTML_TAG); |
889 | 705 |
890 if (browserAccessibilityRole == ui::AX_ROLE_LIST) { | 706 if (browserAccessibilityRole == ui::AX_ROLE_LIST) { |
891 if ([htmlTag isEqualToString:@"dl"]) { | 707 if ([htmlTag isEqualToString:@"dl"]) { |
892 return @"AXDescriptionList"; | 708 return @"AXDescriptionList"; |
893 } else { | 709 } else { |
894 return @"AXContentList"; | 710 return @"AXContentList"; |
895 } | 711 } |
896 } | 712 } |
897 | 713 |
898 return NativeSubroleFromAXRole(browserAccessibilityRole); | 714 return [AXPlatformNodeCocoa nativeSubroleFromAXRole:browserAccessibilityRole]; |
899 } | 715 } |
900 | 716 |
901 // Returns all tabs in this subtree. | 717 // Returns all tabs in this subtree. |
902 - (NSArray*)tabs { | 718 - (NSArray*)tabs { |
903 NSMutableArray* tabSubtree = [[[NSMutableArray alloc] init] autorelease]; | 719 NSMutableArray* tabSubtree = [[[NSMutableArray alloc] init] autorelease]; |
904 | 720 |
905 if ([self internalRole] == ui::AX_ROLE_TAB) | 721 if ([self internalRole] == ui::AX_ROLE_TAB) |
906 [tabSubtree addObject:self]; | 722 [tabSubtree addObject:self]; |
907 | 723 |
908 for (uint i=0; i < [[self children] count]; ++i) { | 724 for (uint i=0; i < [[self children] count]; ++i) { |
(...skipping 720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1629 return [super hash]; | 1445 return [super hash]; |
1630 return browserAccessibility_->GetId(); | 1446 return browserAccessibility_->GetId(); |
1631 } | 1447 } |
1632 | 1448 |
1633 - (BOOL)accessibilityShouldUseUniqueId { | 1449 - (BOOL)accessibilityShouldUseUniqueId { |
1634 return YES; | 1450 return YES; |
1635 } | 1451 } |
1636 | 1452 |
1637 @end | 1453 @end |
1638 | 1454 |
OLD | NEW |