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/app/strings/grit/content_strings.h" | 15 #include "content/app/strings/grit/content_strings.h" |
16 #include "content/browser/accessibility/accessibility_tree_search.h" | |
16 #include "content/browser/accessibility/browser_accessibility_manager.h" | 17 #include "content/browser/accessibility/browser_accessibility_manager.h" |
17 #include "content/browser/accessibility/browser_accessibility_manager_mac.h" | 18 #include "content/browser/accessibility/browser_accessibility_manager_mac.h" |
18 #include "content/public/common/content_client.h" | 19 #include "content/public/common/content_client.h" |
19 #import "ui/accessibility/platform/ax_platform_node_mac.h" | 20 #import "ui/accessibility/platform/ax_platform_node_mac.h" |
20 | 21 |
21 // See http://openradar.appspot.com/9896491. This SPI has been tested on 10.5, | 22 // See http://openradar.appspot.com/9896491. This SPI has been tested on 10.5, |
22 // 10.6, and 10.7. It allows accessibility clients to observe events posted on | 23 // 10.6, and 10.7. It allows accessibility clients to observe events posted on |
23 // this object. | 24 // this object. |
24 extern "C" void NSAccessibilityUnregisterUniqueIdForUIElement(id element); | 25 extern "C" void NSAccessibilityUnregisterUniqueIdForUIElement(id element); |
25 | 26 |
26 using ui::AXNodeData; | 27 using ui::AXNodeData; |
28 using content::AccessibilityMatchPredicate; | |
29 using content::AccessibilityTreeSearch; | |
27 using content::BrowserAccessibility; | 30 using content::BrowserAccessibility; |
28 using content::BrowserAccessibilityDelegate; | 31 using content::BrowserAccessibilityDelegate; |
29 using content::BrowserAccessibilityManager; | 32 using content::BrowserAccessibilityManager; |
30 using content::BrowserAccessibilityManagerMac; | 33 using content::BrowserAccessibilityManagerMac; |
31 using content::ContentClient; | 34 using content::ContentClient; |
32 typedef ui::AXStringAttribute StringAttribute; | 35 typedef ui::AXStringAttribute StringAttribute; |
33 | 36 |
34 namespace { | 37 namespace { |
35 | 38 |
36 // Returns an autoreleased copy of the AXNodeData's attribute. | 39 // Returns an autoreleased copy of the AXNodeData's attribute. |
37 NSString* NSStringForStringAttribute( | 40 NSString* NSStringForStringAttribute( |
38 BrowserAccessibility* browserAccessibility, | 41 BrowserAccessibility* browserAccessibility, |
39 StringAttribute attribute) { | 42 StringAttribute attribute) { |
40 return base::SysUTF8ToNSString( | 43 return base::SysUTF8ToNSString( |
41 browserAccessibility->GetStringAttribute(attribute)); | 44 browserAccessibility->GetStringAttribute(attribute)); |
42 } | 45 } |
43 | 46 |
44 // GetState checks the bitmask used in AXNodeData to check | 47 // GetState checks the bitmask used in AXNodeData to check |
45 // if the given state was set on the accessibility object. | 48 // if the given state was set on the accessibility object. |
46 bool GetState(BrowserAccessibility* accessibility, ui::AXState state) { | 49 bool GetState(BrowserAccessibility* accessibility, ui::AXState state) { |
47 return ((accessibility->GetState() >> state) & 1); | 50 return ((accessibility->GetState() >> state) & 1); |
48 } | 51 } |
49 | 52 |
50 // A mapping from an accessibility attribute to its method name. | 53 // A mapping from an accessibility attribute to its method name. |
51 NSDictionary* attributeToMethodNameMap = nil; | 54 NSDictionary* attributeToMethodNameMap = nil; |
52 | 55 |
56 // Given a search key provided to AXUIElementCountForSearchPredicate or | |
57 // AXUIElementsForSearchPredicate, return a predicate that can be added | |
58 // to AccessibilityTreeSearch. | |
59 AccessibilityMatchPredicate PredicateForSearchKey(NSString* searchKey) { | |
60 if ([searchKey isEqualToString:@"AXAnyTypeSearchKey"]) { | |
David Tseng
2015/05/08 21:58:25
Is this string defined in NS*? Is this API availab
dmazzoni
2015/05/13 04:22:21
It's not even in 10.10. As far as I can tell the s
| |
61 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
62 return true; | |
63 }; | |
64 } else if ([searchKey isEqualToString:@"AXBlockquoteSameLevelSearchKey"] || | |
65 [searchKey isEqualToString:@"AXBlockquoteSearchKey"]) { | |
66 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
67 return current->GetRole() == ui::AX_ROLE_BLOCKQUOTE; | |
68 }; | |
69 } else if ([searchKey isEqualToString:@"AXBoldFontSearchKey"]) { | |
70 return nullptr; // TODO(dmazzoni): implement this. | |
David Tseng
2015/05/08 21:58:25
Can you move the TODO into its own line above?
dmazzoni
2015/05/13 04:22:21
Done throughout.
| |
71 } else if ([searchKey isEqualToString:@"AXButtonSearchKey"]) { | |
72 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
73 return (current->GetRole() == ui::AX_ROLE_BUTTON || | |
David Tseng
2015/05/08 21:58:25
Not sure if they exist on Mac, but menuButton and
dmazzoni
2015/05/13 04:22:21
Done.
| |
74 current->GetRole() == ui::AX_ROLE_POP_UP_BUTTON || | |
75 current->GetRole() == ui::AX_ROLE_TOGGLE_BUTTON); | |
76 }; | |
77 } else if ([searchKey isEqualToString:@"AXCheckBoxSearchKey"]) { | |
78 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
79 return (current->GetRole() == ui::AX_ROLE_CHECK_BOX || | |
80 current->GetRole() == ui::AX_ROLE_MENU_ITEM_CHECK_BOX); | |
81 }; | |
82 } else if ([searchKey isEqualToString:@"AXControlSearchKey"]) { | |
83 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
84 return current->HasState(ui::AX_STATE_FOCUSABLE); | |
David Tseng
2015/05/08 21:58:25
If a button doesn't take focus (like if it were di
dmazzoni
2015/05/13 04:22:20
No, good point. I implemented IsControl but decide
| |
85 }; | |
86 } else if ([searchKey isEqualToString:@"AXDifferentTypeSearchKey"]) { | |
87 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
88 return current->GetRole() != start->GetRole(); | |
89 }; | |
90 } else if ([searchKey isEqualToString:@"AXFontChangeSearchKey"]) { | |
91 return nullptr; // TODO(dmazzoni): implement this. | |
David Tseng
2015/05/08 21:58:25
Ditto
| |
92 } else if ([searchKey isEqualToString:@"AXFontColorChangeSearchKey"]) { | |
93 return nullptr; // TODO(dmazzoni): implement this. | |
David Tseng
2015/05/08 21:58:25
Ditto
| |
94 } else if ([searchKey isEqualToString:@"AXFrameSearchKey"]) { | |
95 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
96 if (current->IsWebAreaForPresentationalIframe()) | |
97 return false; | |
98 return (current->GetRole() == ui::AX_ROLE_WEB_AREA || | |
99 current->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA); | |
100 }; | |
101 } else if ([searchKey isEqualToString:@"AXGraphicSearchKey"]) { | |
102 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
103 return current->GetRole() == ui::AX_ROLE_IMAGE; | |
104 }; | |
105 } else if ([searchKey isEqualToString:@"AXHeadingLevel1SearchKey"]) { | |
106 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
107 return (current->GetRole() == ui::AX_ROLE_HEADING && | |
108 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 1); | |
109 }; | |
110 } else if ([searchKey isEqualToString:@"AXHeadingLevel2SearchKey"]) { | |
111 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
112 return (current->GetRole() == ui::AX_ROLE_HEADING && | |
113 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 2); | |
114 }; | |
115 } else if ([searchKey isEqualToString:@"AXHeadingLevel3SearchKey"]) { | |
116 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
117 return (current->GetRole() == ui::AX_ROLE_HEADING && | |
118 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 3); | |
119 }; | |
120 } else if ([searchKey isEqualToString:@"AXHeadingLevel4SearchKey"]) { | |
121 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
122 return (current->GetRole() == ui::AX_ROLE_HEADING && | |
123 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 4); | |
124 }; | |
125 } else if ([searchKey isEqualToString:@"AXHeadingLevel5SearchKey"]) { | |
126 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
127 return (current->GetRole() == ui::AX_ROLE_HEADING && | |
128 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 5); | |
David Tseng
2015/05/08 21:58:25
Maybe worth writing a helper returning a predicate
dmazzoni
2015/05/13 04:22:21
It's only 6 heading levels and they're 2 lines eac
| |
129 }; | |
130 } else if ([searchKey isEqualToString:@"AXHeadingLevel6SearchKey"]) { | |
131 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
132 return (current->GetRole() == ui::AX_ROLE_HEADING && | |
133 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 6); | |
134 }; | |
135 } else if ([searchKey isEqualToString:@"AXHeadingSameLevelSearchKey"]) { | |
136 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
137 return (current->GetRole() == ui::AX_ROLE_HEADING && | |
138 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == | |
139 start->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL)); | |
David Tseng
2015/05/08 21:58:25
Need to check start is a heading too?
dmazzoni
2015/05/13 04:22:20
Done.
| |
140 }; | |
141 } else if ([searchKey isEqualToString:@"AXHeadingSearchKey"]) { | |
142 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
143 return current->GetRole() == ui::AX_ROLE_HEADING; | |
144 }; | |
145 } else if ([searchKey isEqualToString:@"AXHighlightedSearchKey"]) { | |
146 return nullptr; // TODO(dmazzoni): implement this. | |
147 } else if ([searchKey isEqualToString:@"AXItalicFontSearchKey"]) { | |
148 return nullptr; // TODO(dmazzoni): implement this. | |
149 } else if ([searchKey isEqualToString:@"AXLandmarkSearchKey"]) { | |
150 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
151 return (current->GetRole() == ui::AX_ROLE_APPLICATION || | |
152 current->GetRole() == ui::AX_ROLE_BANNER || | |
153 current->GetRole() == ui::AX_ROLE_COMPLEMENTARY || | |
154 current->GetRole() == ui::AX_ROLE_CONTENT_INFO || | |
155 current->GetRole() == ui::AX_ROLE_FORM || | |
156 current->GetRole() == ui::AX_ROLE_MAIN || | |
157 current->GetRole() == ui::AX_ROLE_NAVIGATION || | |
158 current->GetRole() == ui::AX_ROLE_SEARCH); | |
159 }; | |
160 } else if ([searchKey isEqualToString:@"AXLinkSearchKey"]) { | |
161 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
162 return current->GetRole() == ui::AX_ROLE_LINK; | |
163 }; | |
164 } else if ([searchKey isEqualToString:@"AXListSearchKey"]) { | |
165 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
166 return current->GetRole() == ui::AX_ROLE_LIST; | |
167 }; | |
168 } else if ([searchKey isEqualToString:@"AXLiveRegionSearchKey"]) { | |
169 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
170 return current->HasStringAttribute(ui::AX_ATTR_LIVE_STATUS); | |
171 }; | |
172 } else if ([searchKey isEqualToString:@"AXMisspelledWordSearchKey"]) { | |
173 return nullptr; // TODO(dmazzoni): implement this. | |
174 } else if ([searchKey isEqualToString:@"AXOutlineSearchKey"]) { | |
175 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
176 return current->GetRole() == ui::AX_ROLE_TREE; | |
177 }; | |
178 } else if ([searchKey isEqualToString:@"AXPlainTextSearchKey"]) { | |
179 return nullptr; // TODO(dmazzoni): implement this. | |
180 } else if ([searchKey isEqualToString:@"AXRadioGroupSearchKey"]) { | |
181 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
182 return current->GetRole() == ui::AX_ROLE_RADIO_GROUP; | |
183 }; | |
184 } else if ([searchKey isEqualToString:@"AXSameTypeSearchKey"]) { | |
185 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
186 return current->GetRole() == start->GetRole(); | |
187 }; | |
188 } else if ([searchKey isEqualToString:@"AXStaticTextSearchKey"]) { | |
189 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
190 return current->GetRole() == ui::AX_ROLE_STATIC_TEXT; | |
191 }; | |
192 } else if ([searchKey isEqualToString:@"AXStyleChangeSearchKey"]) { | |
193 return nullptr; // TODO(dmazzoni): implement this. | |
194 } else if ([searchKey isEqualToString:@"AXTableSameLevelSearchKey"]) { | |
195 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
196 return current->GetRole() == ui::AX_ROLE_TABLE; | |
David Tseng
2015/05/08 21:58:25
What about grid? I think this means you need to ch
dmazzoni
2015/05/13 04:22:21
Done.
Added TODO for nested, I wasn't planning on
| |
197 }; | |
198 } else if ([searchKey isEqualToString:@"AXTableSearchKey"]) { | |
199 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
200 return current->GetRole() == ui::AX_ROLE_TABLE; | |
201 }; | |
202 } else if ([searchKey isEqualToString:@"AXTextFieldSearchKey"]) { | |
203 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
204 return current->GetRole() == ui::AX_ROLE_TEXT_FIELD; | |
205 }; | |
206 } else if ([searchKey isEqualToString:@"AXUnderlineSearchKey"]) { | |
207 return nullptr; // TODO(dmazzoni): implement this. | |
208 } else if ([searchKey isEqualToString:@"AXUnvisitedLinkSearchKey"]) { | |
209 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
210 return (current->GetRole() == ui::AX_ROLE_LINK && | |
211 !current->HasState(ui::AX_STATE_VISITED)); | |
212 }; | |
213 } else if ([searchKey isEqualToString:@"AXVisitedLinkSearchKey"]) { | |
214 return [](BrowserAccessibility* start, BrowserAccessibility* current) { | |
215 return (current->GetRole() == ui::AX_ROLE_LINK && | |
216 current->HasState(ui::AX_STATE_VISITED)); | |
217 }; | |
218 } | |
219 | |
220 return nullptr; | |
221 } | |
222 | |
223 // Initialize an AccessibilityTreeSearch object given the parameters | |
224 // passed to AXUIElementCountForSearchPredicate or | |
225 // AXUIElementsForSearchPredicate. Return true on success. | |
226 bool InitializeAccessibilityTreeSearch( | |
227 AccessibilityTreeSearch* search, | |
228 id parameter) { | |
229 if (![parameter isKindOfClass:[NSDictionary class]]) | |
230 return false; | |
231 NSDictionary* dictionary = parameter; | |
232 | |
233 id startElementParameter = [dictionary objectForKey:@"AXStartElement"]; | |
234 BrowserAccessibility* startNode = nullptr; | |
235 if ([startElementParameter isKindOfClass:[BrowserAccessibilityCocoa class]]) { | |
236 BrowserAccessibilityCocoa* startNodeCocoa = | |
237 (BrowserAccessibilityCocoa*)startElementParameter; | |
238 startNode = [startNodeCocoa browserAccessibility]; | |
239 } | |
240 | |
241 bool immediateDescendantsOnly = false; | |
242 NSNumber *immediateDescendantsOnlyParameter = | |
243 [dictionary objectForKey:@"AXImmediateDescendantsOnly"]; | |
244 if ([immediateDescendantsOnlyParameter isKindOfClass:[NSNumber class]]) | |
245 immediateDescendantsOnly = [immediateDescendantsOnlyParameter boolValue]; | |
246 | |
247 bool visibleOnly = false; | |
248 NSNumber *visibleOnlyParameter = [dictionary objectForKey:@"AXVisibleOnly"]; | |
249 if ([visibleOnlyParameter isKindOfClass:[NSNumber class]]) | |
250 visibleOnly = [visibleOnlyParameter boolValue]; | |
251 | |
252 content::AccessibilityTreeSearch::Direction direction = | |
253 content::AccessibilityTreeSearch::FORWARDS; | |
254 NSString* directionParameter = [dictionary objectForKey:@"AXDirection"]; | |
255 if ([directionParameter isKindOfClass:[NSString class]]) { | |
256 if ([directionParameter isEqualToString:@"AXDirectionNext"]) | |
257 direction = content::AccessibilityTreeSearch::FORWARDS; | |
258 else if ([directionParameter isEqualToString:@"AXDirectionPrevious"]) | |
259 direction = content::AccessibilityTreeSearch::BACKWARDS; | |
260 } | |
261 | |
262 int resultsLimit = 0; | |
263 NSNumber* resultsLimitParameter = [dictionary objectForKey:@"AXResultsLimit"]; | |
264 if ([resultsLimitParameter isKindOfClass:[NSNumber class]]) | |
265 resultsLimit = [resultsLimitParameter intValue]; | |
266 | |
267 std::string searchText; | |
268 NSString* searchTextParameter = [dictionary objectForKey:@"AXSearchText"]; | |
269 if ([searchTextParameter isKindOfClass:[NSString class]]) | |
270 searchText = base::SysNSStringToUTF8(searchTextParameter); | |
271 | |
272 search->SetStartNode(startNode); | |
273 search->SetDirection(direction); | |
274 search->SetResultLimit(resultsLimit); | |
275 search->SetImmediateDescendantsOnly(immediateDescendantsOnly); | |
276 search->SetVisibleOnly(visibleOnly); | |
277 search->SetSearchText(searchText); | |
David Tseng
2015/05/08 21:58:25
Looks like you do have all args available here; co
dmazzoni
2015/05/13 04:22:20
Two reasons not to:
* I think this is more readabl
| |
278 | |
279 id searchKey = [dictionary objectForKey:@"AXSearchKey"]; | |
280 if ([searchKey isKindOfClass:[NSString class]]) { | |
281 AccessibilityMatchPredicate predicate = | |
282 PredicateForSearchKey((NSString*)searchKey); | |
283 if (predicate) | |
284 search->AddPredicate(predicate); | |
285 } else if ([searchKey isKindOfClass:[NSArray class]]) { | |
286 size_t searchKeyCount = static_cast<size_t>([searchKey count]); | |
287 for (size_t i = 0; i < searchKeyCount; ++i) { | |
288 id key = [searchKey objectAtIndex:i]; | |
289 if ([key isKindOfClass:[NSString class]]) { | |
290 AccessibilityMatchPredicate predicate = | |
291 PredicateForSearchKey((NSString*)key); | |
292 if (predicate) | |
293 search->AddPredicate(predicate); | |
294 } | |
295 } | |
296 } | |
297 | |
298 return true; | |
299 } | |
300 | |
53 } // namespace | 301 } // namespace |
54 | 302 |
55 @implementation BrowserAccessibilityCocoa | 303 @implementation BrowserAccessibilityCocoa |
56 | 304 |
57 + (void)initialize { | 305 + (void)initialize { |
58 const struct { | 306 const struct { |
59 NSString* attribute; | 307 NSString* attribute; |
60 NSString* methodName; | 308 NSString* methodName; |
61 } attributeToMethodNameContainer[] = { | 309 } attributeToMethodNameContainer[] = { |
62 { NSAccessibilityChildrenAttribute, @"children" }, | 310 { NSAccessibilityChildrenAttribute, @"children" }, |
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
550 - (ui::AXRole)internalRole { | 798 - (ui::AXRole)internalRole { |
551 return static_cast<ui::AXRole>(browserAccessibility_->GetRole()); | 799 return static_cast<ui::AXRole>(browserAccessibility_->GetRole()); |
552 } | 800 } |
553 | 801 |
554 - (content::BrowserAccessibilityDelegate*)delegate { | 802 - (content::BrowserAccessibilityDelegate*)delegate { |
555 return browserAccessibility_->manager() ? | 803 return browserAccessibility_->manager() ? |
556 browserAccessibility_->manager()->delegate() : | 804 browserAccessibility_->manager()->delegate() : |
557 nil; | 805 nil; |
558 } | 806 } |
559 | 807 |
808 - (content::BrowserAccessibility*)browserAccessibility { | |
809 return browserAccessibility_; | |
810 } | |
811 | |
560 - (NSPoint)pointInScreen:(NSPoint)origin | 812 - (NSPoint)pointInScreen:(NSPoint)origin |
561 size:(NSSize)size { | 813 size:(NSSize)size { |
562 if (!browserAccessibility_) | 814 if (!browserAccessibility_) |
563 return NSZeroPoint; | 815 return NSZeroPoint; |
564 | 816 |
565 // Get the delegate for the topmost BrowserAccessibilityManager, because | 817 // Get the delegate for the topmost BrowserAccessibilityManager, because |
566 // that's the only one that can convert points to their origin in the screen. | 818 // that's the only one that can convert points to their origin in the screen. |
567 BrowserAccessibilityDelegate* delegate = | 819 BrowserAccessibilityDelegate* delegate = |
568 browserAccessibility_->manager()->GetDelegateFromRootManager(); | 820 browserAccessibility_->manager()->GetDelegateFromRootManager(); |
569 if (delegate) { | 821 if (delegate) { |
(...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1206 NSRange range = [(NSValue*)parameter rangeValue]; | 1458 NSRange range = [(NSValue*)parameter rangeValue]; |
1207 gfx::Rect rect = browserAccessibility_->GetGlobalBoundsForRange( | 1459 gfx::Rect rect = browserAccessibility_->GetGlobalBoundsForRange( |
1208 range.location, range.length); | 1460 range.location, range.length); |
1209 NSPoint origin = NSMakePoint(rect.x(), rect.y()); | 1461 NSPoint origin = NSMakePoint(rect.x(), rect.y()); |
1210 NSSize size = NSMakeSize(rect.width(), rect.height()); | 1462 NSSize size = NSMakeSize(rect.width(), rect.height()); |
1211 NSPoint pointInScreen = [self pointInScreen:origin size:size]; | 1463 NSPoint pointInScreen = [self pointInScreen:origin size:size]; |
1212 NSRect nsrect = NSMakeRect( | 1464 NSRect nsrect = NSMakeRect( |
1213 pointInScreen.x, pointInScreen.y, rect.width(), rect.height()); | 1465 pointInScreen.x, pointInScreen.y, rect.width(), rect.height()); |
1214 return [NSValue valueWithRect:nsrect]; | 1466 return [NSValue valueWithRect:nsrect]; |
1215 } | 1467 } |
1468 if ([attribute isEqualToString:@"AXUIElementCountForSearchPredicate"]) { | |
1469 AccessibilityTreeSearch search(browserAccessibility_->manager()); | |
1470 if (InitializeAccessibilityTreeSearch(&search, parameter)) | |
1471 return [NSNumber numberWithInt:search.CountMatches()]; | |
1472 return nil; | |
1473 } | |
1474 | |
1475 if ([attribute isEqualToString:@"AXUIElementsForSearchPredicate"]) { | |
1476 AccessibilityTreeSearch search(browserAccessibility_->manager()); | |
1477 if (InitializeAccessibilityTreeSearch(&search, parameter)) { | |
1478 size_t count = search.CountMatches(); | |
1479 NSMutableArray* result = [NSMutableArray arrayWithCapacity:count]; | |
1480 for (size_t i = 0; i < count; i++) { | |
1481 BrowserAccessibility* match = search.GetMatchAtIndex(i); | |
1482 [result addObject:match->ToBrowserAccessibilityCocoa()]; | |
1483 } | |
1484 return result; | |
1485 } | |
1486 return nil; | |
1487 } | |
1216 | 1488 |
1217 // TODO(dtseng): support the following attributes. | 1489 // TODO(dtseng): support the following attributes. |
1218 if ([attribute isEqualTo: | 1490 if ([attribute isEqualTo: |
1219 NSAccessibilityRangeForPositionParameterizedAttribute] || | 1491 NSAccessibilityRangeForPositionParameterizedAttribute] || |
1220 [attribute isEqualTo: | 1492 [attribute isEqualTo: |
1221 NSAccessibilityRangeForIndexParameterizedAttribute] || | 1493 NSAccessibilityRangeForIndexParameterizedAttribute] || |
1222 [attribute isEqualTo:NSAccessibilityRTFForRangeParameterizedAttribute] || | 1494 [attribute isEqualTo:NSAccessibilityRTFForRangeParameterizedAttribute] || |
1223 [attribute isEqualTo: | 1495 [attribute isEqualTo: |
1224 NSAccessibilityStyleRangeForIndexParameterizedAttribute]) { | 1496 NSAccessibilityStyleRangeForIndexParameterizedAttribute]) { |
1225 return nil; | 1497 return nil; |
1226 } | 1498 } |
1227 return nil; | 1499 return nil; |
1228 } | 1500 } |
1229 | 1501 |
1230 // Returns an array of parameterized attributes names that this object will | 1502 // Returns an array of parameterized attributes names that this object will |
1231 // respond to. | 1503 // respond to. |
1232 - (NSArray*)accessibilityParameterizedAttributeNames { | 1504 - (NSArray*)accessibilityParameterizedAttributeNames { |
1233 if (!browserAccessibility_) | 1505 if (!browserAccessibility_) |
1234 return nil; | 1506 return nil; |
1235 | 1507 |
1508 // General attributes. | |
1509 NSMutableArray* ret = [NSMutableArray arrayWithObjects: | |
1510 @"AXUIElementCountForSearchPredicate", | |
1511 @"AXUIElementsForSearchPredicate", | |
1512 nil]; | |
1513 | |
1236 if ([[self role] isEqualToString:NSAccessibilityTableRole] || | 1514 if ([[self role] isEqualToString:NSAccessibilityTableRole] || |
1237 [[self role] isEqualToString:NSAccessibilityGridRole]) { | 1515 [[self role] isEqualToString:NSAccessibilityGridRole]) { |
1238 return [NSArray arrayWithObjects: | 1516 [ret addObjectsFromArray:[NSArray arrayWithObjects: |
1239 NSAccessibilityCellForColumnAndRowParameterizedAttribute, | 1517 NSAccessibilityCellForColumnAndRowParameterizedAttribute, |
1240 nil]; | 1518 nil]]; |
1241 } | 1519 } |
1242 if ([[self role] isEqualToString:NSAccessibilityTextFieldRole]) { | 1520 if ([[self role] isEqualToString:NSAccessibilityTextFieldRole]) { |
1243 return [NSArray arrayWithObjects: | 1521 [ret addObjectsFromArray:[NSArray arrayWithObjects: |
1244 NSAccessibilityLineForIndexParameterizedAttribute, | 1522 NSAccessibilityLineForIndexParameterizedAttribute, |
1245 NSAccessibilityRangeForLineParameterizedAttribute, | 1523 NSAccessibilityRangeForLineParameterizedAttribute, |
1246 NSAccessibilityStringForRangeParameterizedAttribute, | 1524 NSAccessibilityStringForRangeParameterizedAttribute, |
1247 NSAccessibilityRangeForPositionParameterizedAttribute, | 1525 NSAccessibilityRangeForPositionParameterizedAttribute, |
1248 NSAccessibilityRangeForIndexParameterizedAttribute, | 1526 NSAccessibilityRangeForIndexParameterizedAttribute, |
1249 NSAccessibilityBoundsForRangeParameterizedAttribute, | 1527 NSAccessibilityBoundsForRangeParameterizedAttribute, |
1250 NSAccessibilityRTFForRangeParameterizedAttribute, | 1528 NSAccessibilityRTFForRangeParameterizedAttribute, |
1251 NSAccessibilityAttributedStringForRangeParameterizedAttribute, | 1529 NSAccessibilityAttributedStringForRangeParameterizedAttribute, |
1252 NSAccessibilityStyleRangeForIndexParameterizedAttribute, | 1530 NSAccessibilityStyleRangeForIndexParameterizedAttribute, |
1253 nil]; | 1531 nil]]; |
1254 } | 1532 } |
1255 if ([self internalRole] == ui::AX_ROLE_STATIC_TEXT) { | 1533 if ([self internalRole] == ui::AX_ROLE_STATIC_TEXT) { |
1256 return [NSArray arrayWithObjects: | 1534 [ret addObjectsFromArray:[NSArray arrayWithObjects: |
1257 NSAccessibilityBoundsForRangeParameterizedAttribute, | 1535 NSAccessibilityBoundsForRangeParameterizedAttribute, |
1258 nil]; | 1536 nil]]; |
1259 } | 1537 } |
1260 return nil; | 1538 return ret; |
1261 } | 1539 } |
1262 | 1540 |
1263 // Returns an array of action names that this object will respond to. | 1541 // Returns an array of action names that this object will respond to. |
1264 - (NSArray*)accessibilityActionNames { | 1542 - (NSArray*)accessibilityActionNames { |
1265 if (!browserAccessibility_) | 1543 if (!browserAccessibility_) |
1266 return nil; | 1544 return nil; |
1267 | 1545 |
1268 NSMutableArray* ret = | 1546 NSMutableArray* ret = |
1269 [NSMutableArray arrayWithObject:NSAccessibilityShowMenuAction]; | 1547 [NSMutableArray arrayWithObject:NSAccessibilityShowMenuAction]; |
1270 NSString* role = [self role]; | 1548 NSString* role = [self role]; |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1662 if (!browserAccessibility_) | 1940 if (!browserAccessibility_) |
1663 return [super hash]; | 1941 return [super hash]; |
1664 return browserAccessibility_->GetId(); | 1942 return browserAccessibility_->GetId(); |
1665 } | 1943 } |
1666 | 1944 |
1667 - (BOOL)accessibilityShouldUseUniqueId { | 1945 - (BOOL)accessibilityShouldUseUniqueId { |
1668 return YES; | 1946 return YES; |
1669 } | 1947 } |
1670 | 1948 |
1671 @end | 1949 @end |
OLD | NEW |