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/browser_accessibility_manager.h" | 16 #include "content/browser/accessibility/browser_accessibility_manager.h" |
17 #include "content/browser/accessibility/browser_accessibility_manager_mac.h" | 17 #include "content/browser/accessibility/browser_accessibility_manager_mac.h" |
| 18 #include "content/browser/accessibility/one_shot_accessibility_tree_search.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; |
27 using content::BrowserAccessibility; | 29 using content::BrowserAccessibility; |
28 using content::BrowserAccessibilityDelegate; | 30 using content::BrowserAccessibilityDelegate; |
29 using content::BrowserAccessibilityManager; | 31 using content::BrowserAccessibilityManager; |
30 using content::BrowserAccessibilityManagerMac; | 32 using content::BrowserAccessibilityManagerMac; |
31 using content::ContentClient; | 33 using content::ContentClient; |
| 34 using content::OneShotAccessibilityTreeSearch; |
32 typedef ui::AXStringAttribute StringAttribute; | 35 typedef ui::AXStringAttribute StringAttribute; |
33 | 36 |
34 namespace { | 37 namespace { |
35 | 38 |
| 39 // VoiceOver uses -1 to mean "no limit" for AXResultsLimit. |
| 40 const int kAXResultsLimitNoLimit = -1; |
| 41 |
36 // Returns an autoreleased copy of the AXNodeData's attribute. | 42 // Returns an autoreleased copy of the AXNodeData's attribute. |
37 NSString* NSStringForStringAttribute( | 43 NSString* NSStringForStringAttribute( |
38 BrowserAccessibility* browserAccessibility, | 44 BrowserAccessibility* browserAccessibility, |
39 StringAttribute attribute) { | 45 StringAttribute attribute) { |
40 return base::SysUTF8ToNSString( | 46 return base::SysUTF8ToNSString( |
41 browserAccessibility->GetStringAttribute(attribute)); | 47 browserAccessibility->GetStringAttribute(attribute)); |
42 } | 48 } |
43 | 49 |
44 // GetState checks the bitmask used in AXNodeData to check | 50 // GetState checks the bitmask used in AXNodeData to check |
45 // if the given state was set on the accessibility object. | 51 // if the given state was set on the accessibility object. |
46 bool GetState(BrowserAccessibility* accessibility, ui::AXState state) { | 52 bool GetState(BrowserAccessibility* accessibility, ui::AXState state) { |
47 return ((accessibility->GetState() >> state) & 1); | 53 return ((accessibility->GetState() >> state) & 1); |
48 } | 54 } |
49 | 55 |
50 // A mapping from an accessibility attribute to its method name. | 56 // A mapping from an accessibility attribute to its method name. |
51 NSDictionary* attributeToMethodNameMap = nil; | 57 NSDictionary* attributeToMethodNameMap = nil; |
52 | 58 |
| 59 // Given a search key provided to AXUIElementCountForSearchPredicate or |
| 60 // AXUIElementsForSearchPredicate, return a predicate that can be added |
| 61 // to OneShotAccessibilityTreeSearch. |
| 62 AccessibilityMatchPredicate PredicateForSearchKey(NSString* searchKey) { |
| 63 if ([searchKey isEqualToString:@"AXAnyTypeSearchKey"]) { |
| 64 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 65 return true; |
| 66 }; |
| 67 } else if ([searchKey isEqualToString:@"AXBlockquoteSameLevelSearchKey"] || |
| 68 [searchKey isEqualToString:@"AXBlockquoteSearchKey"]) { |
| 69 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 70 // TODO(dmazzoni): implement the "same level" part. |
| 71 return current->GetRole() == ui::AX_ROLE_BLOCKQUOTE; |
| 72 }; |
| 73 } else if ([searchKey isEqualToString:@"AXBoldFontSearchKey"]) { |
| 74 // TODO(dmazzoni): implement this. |
| 75 return nullptr; |
| 76 } else if ([searchKey isEqualToString:@"AXButtonSearchKey"]) { |
| 77 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 78 return (current->GetRole() == ui::AX_ROLE_BUTTON || |
| 79 current->GetRole() == ui::AX_ROLE_MENU_BUTTON || |
| 80 current->GetRole() == ui::AX_ROLE_POP_UP_BUTTON || |
| 81 current->GetRole() == ui::AX_ROLE_SWITCH || |
| 82 current->GetRole() == ui::AX_ROLE_TOGGLE_BUTTON); |
| 83 }; |
| 84 } else if ([searchKey isEqualToString:@"AXCheckBoxSearchKey"]) { |
| 85 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 86 return (current->GetRole() == ui::AX_ROLE_CHECK_BOX || |
| 87 current->GetRole() == ui::AX_ROLE_MENU_ITEM_CHECK_BOX); |
| 88 }; |
| 89 } else if ([searchKey isEqualToString:@"AXControlSearchKey"]) { |
| 90 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 91 if (current->IsControl()) |
| 92 return true; |
| 93 if (current->HasState(ui::AX_STATE_FOCUSABLE) && |
| 94 current->GetRole() != ui::AX_ROLE_IMAGE_MAP_LINK && |
| 95 current->GetRole() != ui::AX_ROLE_LINK) { |
| 96 return true; |
| 97 } |
| 98 return false; |
| 99 }; |
| 100 } else if ([searchKey isEqualToString:@"AXDifferentTypeSearchKey"]) { |
| 101 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 102 return current->GetRole() != start->GetRole(); |
| 103 }; |
| 104 } else if ([searchKey isEqualToString:@"AXFontChangeSearchKey"]) { |
| 105 // TODO(dmazzoni): implement this. |
| 106 return nullptr; |
| 107 } else if ([searchKey isEqualToString:@"AXFontColorChangeSearchKey"]) { |
| 108 // TODO(dmazzoni): implement this. |
| 109 return nullptr; |
| 110 } else if ([searchKey isEqualToString:@"AXFrameSearchKey"]) { |
| 111 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 112 if (current->IsWebAreaForPresentationalIframe()) |
| 113 return false; |
| 114 return (current->GetRole() == ui::AX_ROLE_WEB_AREA || |
| 115 current->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA); |
| 116 }; |
| 117 } else if ([searchKey isEqualToString:@"AXGraphicSearchKey"]) { |
| 118 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 119 return current->GetRole() == ui::AX_ROLE_IMAGE; |
| 120 }; |
| 121 } else if ([searchKey isEqualToString:@"AXHeadingLevel1SearchKey"]) { |
| 122 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 123 return (current->GetRole() == ui::AX_ROLE_HEADING && |
| 124 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 1); |
| 125 }; |
| 126 } else if ([searchKey isEqualToString:@"AXHeadingLevel2SearchKey"]) { |
| 127 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 128 return (current->GetRole() == ui::AX_ROLE_HEADING && |
| 129 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 2); |
| 130 }; |
| 131 } else if ([searchKey isEqualToString:@"AXHeadingLevel3SearchKey"]) { |
| 132 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 133 return (current->GetRole() == ui::AX_ROLE_HEADING && |
| 134 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 3); |
| 135 }; |
| 136 } else if ([searchKey isEqualToString:@"AXHeadingLevel4SearchKey"]) { |
| 137 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 138 return (current->GetRole() == ui::AX_ROLE_HEADING && |
| 139 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 4); |
| 140 }; |
| 141 } else if ([searchKey isEqualToString:@"AXHeadingLevel5SearchKey"]) { |
| 142 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 143 return (current->GetRole() == ui::AX_ROLE_HEADING && |
| 144 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 5); |
| 145 }; |
| 146 } else if ([searchKey isEqualToString:@"AXHeadingLevel6SearchKey"]) { |
| 147 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 148 return (current->GetRole() == ui::AX_ROLE_HEADING && |
| 149 current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 6); |
| 150 }; |
| 151 } else if ([searchKey isEqualToString:@"AXHeadingSameLevelSearchKey"]) { |
| 152 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 153 return (current->GetRole() == ui::AX_ROLE_HEADING && |
| 154 start->GetRole() == ui::AX_ROLE_HEADING && |
| 155 (current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == |
| 156 start->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL))); |
| 157 }; |
| 158 } else if ([searchKey isEqualToString:@"AXHeadingSearchKey"]) { |
| 159 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 160 return current->GetRole() == ui::AX_ROLE_HEADING; |
| 161 }; |
| 162 } else if ([searchKey isEqualToString:@"AXHighlightedSearchKey"]) { |
| 163 // TODO(dmazzoni): implement this. |
| 164 return nullptr; |
| 165 } else if ([searchKey isEqualToString:@"AXItalicFontSearchKey"]) { |
| 166 // TODO(dmazzoni): implement this. |
| 167 return nullptr; |
| 168 } else if ([searchKey isEqualToString:@"AXLandmarkSearchKey"]) { |
| 169 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 170 return (current->GetRole() == ui::AX_ROLE_APPLICATION || |
| 171 current->GetRole() == ui::AX_ROLE_BANNER || |
| 172 current->GetRole() == ui::AX_ROLE_COMPLEMENTARY || |
| 173 current->GetRole() == ui::AX_ROLE_CONTENT_INFO || |
| 174 current->GetRole() == ui::AX_ROLE_FORM || |
| 175 current->GetRole() == ui::AX_ROLE_MAIN || |
| 176 current->GetRole() == ui::AX_ROLE_NAVIGATION || |
| 177 current->GetRole() == ui::AX_ROLE_SEARCH); |
| 178 }; |
| 179 } else if ([searchKey isEqualToString:@"AXLinkSearchKey"]) { |
| 180 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 181 return current->GetRole() == ui::AX_ROLE_LINK; |
| 182 }; |
| 183 } else if ([searchKey isEqualToString:@"AXListSearchKey"]) { |
| 184 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 185 return current->GetRole() == ui::AX_ROLE_LIST; |
| 186 }; |
| 187 } else if ([searchKey isEqualToString:@"AXLiveRegionSearchKey"]) { |
| 188 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 189 return current->HasStringAttribute(ui::AX_ATTR_LIVE_STATUS); |
| 190 }; |
| 191 } else if ([searchKey isEqualToString:@"AXMisspelledWordSearchKey"]) { |
| 192 // TODO(dmazzoni): implement this. |
| 193 return nullptr; |
| 194 } else if ([searchKey isEqualToString:@"AXOutlineSearchKey"]) { |
| 195 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 196 return current->GetRole() == ui::AX_ROLE_TREE; |
| 197 }; |
| 198 } else if ([searchKey isEqualToString:@"AXPlainTextSearchKey"]) { |
| 199 // TODO(dmazzoni): implement this. |
| 200 return nullptr; |
| 201 } else if ([searchKey isEqualToString:@"AXRadioGroupSearchKey"]) { |
| 202 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 203 return current->GetRole() == ui::AX_ROLE_RADIO_GROUP; |
| 204 }; |
| 205 } else if ([searchKey isEqualToString:@"AXSameTypeSearchKey"]) { |
| 206 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 207 return current->GetRole() == start->GetRole(); |
| 208 }; |
| 209 } else if ([searchKey isEqualToString:@"AXStaticTextSearchKey"]) { |
| 210 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 211 return current->GetRole() == ui::AX_ROLE_STATIC_TEXT; |
| 212 }; |
| 213 } else if ([searchKey isEqualToString:@"AXStyleChangeSearchKey"]) { |
| 214 // TODO(dmazzoni): implement this. |
| 215 return nullptr; |
| 216 } else if ([searchKey isEqualToString:@"AXTableSameLevelSearchKey"]) { |
| 217 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 218 // TODO(dmazzoni): implement the "same level" part. |
| 219 return current->GetRole() == ui::AX_ROLE_GRID || |
| 220 current->GetRole() == ui::AX_ROLE_TABLE; |
| 221 }; |
| 222 } else if ([searchKey isEqualToString:@"AXTableSearchKey"]) { |
| 223 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 224 return current->GetRole() == ui::AX_ROLE_GRID || |
| 225 current->GetRole() == ui::AX_ROLE_TABLE; |
| 226 }; |
| 227 } else if ([searchKey isEqualToString:@"AXTextFieldSearchKey"]) { |
| 228 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 229 return current->GetRole() == ui::AX_ROLE_TEXT_FIELD; |
| 230 }; |
| 231 } else if ([searchKey isEqualToString:@"AXUnderlineSearchKey"]) { |
| 232 // TODO(dmazzoni): implement this. |
| 233 return nullptr; |
| 234 } else if ([searchKey isEqualToString:@"AXUnvisitedLinkSearchKey"]) { |
| 235 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 236 return (current->GetRole() == ui::AX_ROLE_LINK && |
| 237 !current->HasState(ui::AX_STATE_VISITED)); |
| 238 }; |
| 239 } else if ([searchKey isEqualToString:@"AXVisitedLinkSearchKey"]) { |
| 240 return [](BrowserAccessibility* start, BrowserAccessibility* current) { |
| 241 return (current->GetRole() == ui::AX_ROLE_LINK && |
| 242 current->HasState(ui::AX_STATE_VISITED)); |
| 243 }; |
| 244 } |
| 245 |
| 246 return nullptr; |
| 247 } |
| 248 |
| 249 // Initialize a OneShotAccessibilityTreeSearch object given the parameters |
| 250 // passed to AXUIElementCountForSearchPredicate or |
| 251 // AXUIElementsForSearchPredicate. Return true on success. |
| 252 bool InitializeAccessibilityTreeSearch( |
| 253 OneShotAccessibilityTreeSearch* search, |
| 254 id parameter) { |
| 255 if (![parameter isKindOfClass:[NSDictionary class]]) |
| 256 return false; |
| 257 NSDictionary* dictionary = parameter; |
| 258 |
| 259 id startElementParameter = [dictionary objectForKey:@"AXStartElement"]; |
| 260 BrowserAccessibility* startNode = nullptr; |
| 261 if ([startElementParameter isKindOfClass:[BrowserAccessibilityCocoa class]]) { |
| 262 BrowserAccessibilityCocoa* startNodeCocoa = |
| 263 (BrowserAccessibilityCocoa*)startElementParameter; |
| 264 startNode = [startNodeCocoa browserAccessibility]; |
| 265 } |
| 266 |
| 267 bool immediateDescendantsOnly = false; |
| 268 NSNumber *immediateDescendantsOnlyParameter = |
| 269 [dictionary objectForKey:@"AXImmediateDescendantsOnly"]; |
| 270 if ([immediateDescendantsOnlyParameter isKindOfClass:[NSNumber class]]) |
| 271 immediateDescendantsOnly = [immediateDescendantsOnlyParameter boolValue]; |
| 272 |
| 273 bool visibleOnly = false; |
| 274 NSNumber *visibleOnlyParameter = [dictionary objectForKey:@"AXVisibleOnly"]; |
| 275 if ([visibleOnlyParameter isKindOfClass:[NSNumber class]]) |
| 276 visibleOnly = [visibleOnlyParameter boolValue]; |
| 277 |
| 278 content::OneShotAccessibilityTreeSearch::Direction direction = |
| 279 content::OneShotAccessibilityTreeSearch::FORWARDS; |
| 280 NSString* directionParameter = [dictionary objectForKey:@"AXDirection"]; |
| 281 if ([directionParameter isKindOfClass:[NSString class]]) { |
| 282 if ([directionParameter isEqualToString:@"AXDirectionNext"]) |
| 283 direction = content::OneShotAccessibilityTreeSearch::FORWARDS; |
| 284 else if ([directionParameter isEqualToString:@"AXDirectionPrevious"]) |
| 285 direction = content::OneShotAccessibilityTreeSearch::BACKWARDS; |
| 286 } |
| 287 |
| 288 int resultsLimit = kAXResultsLimitNoLimit; |
| 289 NSNumber* resultsLimitParameter = [dictionary objectForKey:@"AXResultsLimit"]; |
| 290 if ([resultsLimitParameter isKindOfClass:[NSNumber class]]) |
| 291 resultsLimit = [resultsLimitParameter intValue]; |
| 292 |
| 293 std::string searchText; |
| 294 NSString* searchTextParameter = [dictionary objectForKey:@"AXSearchText"]; |
| 295 if ([searchTextParameter isKindOfClass:[NSString class]]) |
| 296 searchText = base::SysNSStringToUTF8(searchTextParameter); |
| 297 |
| 298 search->SetStartNode(startNode); |
| 299 search->SetDirection(direction); |
| 300 search->SetImmediateDescendantsOnly(immediateDescendantsOnly); |
| 301 search->SetVisibleOnly(visibleOnly); |
| 302 search->SetSearchText(searchText); |
| 303 |
| 304 // Mac uses resultsLimit == -1 for unlimited, that that's |
| 305 // the default for OneShotAccessibilityTreeSearch already. |
| 306 // Only set the results limit if it's nonnegative. |
| 307 if (resultsLimit >= 0) |
| 308 search->SetResultLimit(resultsLimit); |
| 309 |
| 310 id searchKey = [dictionary objectForKey:@"AXSearchKey"]; |
| 311 if ([searchKey isKindOfClass:[NSString class]]) { |
| 312 AccessibilityMatchPredicate predicate = |
| 313 PredicateForSearchKey((NSString*)searchKey); |
| 314 if (predicate) |
| 315 search->AddPredicate(predicate); |
| 316 } else if ([searchKey isKindOfClass:[NSArray class]]) { |
| 317 size_t searchKeyCount = static_cast<size_t>([searchKey count]); |
| 318 for (size_t i = 0; i < searchKeyCount; ++i) { |
| 319 id key = [searchKey objectAtIndex:i]; |
| 320 if ([key isKindOfClass:[NSString class]]) { |
| 321 AccessibilityMatchPredicate predicate = |
| 322 PredicateForSearchKey((NSString*)key); |
| 323 if (predicate) |
| 324 search->AddPredicate(predicate); |
| 325 } |
| 326 } |
| 327 } |
| 328 |
| 329 return true; |
| 330 } |
| 331 |
53 } // namespace | 332 } // namespace |
54 | 333 |
55 @implementation BrowserAccessibilityCocoa | 334 @implementation BrowserAccessibilityCocoa |
56 | 335 |
57 + (void)initialize { | 336 + (void)initialize { |
58 const struct { | 337 const struct { |
59 NSString* attribute; | 338 NSString* attribute; |
60 NSString* methodName; | 339 NSString* methodName; |
61 } attributeToMethodNameContainer[] = { | 340 } attributeToMethodNameContainer[] = { |
62 { NSAccessibilityChildrenAttribute, @"children" }, | 341 { NSAccessibilityChildrenAttribute, @"children" }, |
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
550 - (ui::AXRole)internalRole { | 829 - (ui::AXRole)internalRole { |
551 return static_cast<ui::AXRole>(browserAccessibility_->GetRole()); | 830 return static_cast<ui::AXRole>(browserAccessibility_->GetRole()); |
552 } | 831 } |
553 | 832 |
554 - (content::BrowserAccessibilityDelegate*)delegate { | 833 - (content::BrowserAccessibilityDelegate*)delegate { |
555 return browserAccessibility_->manager() ? | 834 return browserAccessibility_->manager() ? |
556 browserAccessibility_->manager()->delegate() : | 835 browserAccessibility_->manager()->delegate() : |
557 nil; | 836 nil; |
558 } | 837 } |
559 | 838 |
| 839 - (content::BrowserAccessibility*)browserAccessibility { |
| 840 return browserAccessibility_; |
| 841 } |
| 842 |
560 - (NSPoint)pointInScreen:(NSPoint)origin | 843 - (NSPoint)pointInScreen:(NSPoint)origin |
561 size:(NSSize)size { | 844 size:(NSSize)size { |
562 if (!browserAccessibility_) | 845 if (!browserAccessibility_) |
563 return NSZeroPoint; | 846 return NSZeroPoint; |
564 | 847 |
565 // Get the delegate for the topmost BrowserAccessibilityManager, because | 848 // Get the delegate for the topmost BrowserAccessibilityManager, because |
566 // that's the only one that can convert points to their origin in the screen. | 849 // that's the only one that can convert points to their origin in the screen. |
567 BrowserAccessibilityDelegate* delegate = | 850 BrowserAccessibilityDelegate* delegate = |
568 browserAccessibility_->manager()->GetDelegateFromRootManager(); | 851 browserAccessibility_->manager()->GetDelegateFromRootManager(); |
569 if (delegate) { | 852 if (delegate) { |
(...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1206 NSRange range = [(NSValue*)parameter rangeValue]; | 1489 NSRange range = [(NSValue*)parameter rangeValue]; |
1207 gfx::Rect rect = browserAccessibility_->GetGlobalBoundsForRange( | 1490 gfx::Rect rect = browserAccessibility_->GetGlobalBoundsForRange( |
1208 range.location, range.length); | 1491 range.location, range.length); |
1209 NSPoint origin = NSMakePoint(rect.x(), rect.y()); | 1492 NSPoint origin = NSMakePoint(rect.x(), rect.y()); |
1210 NSSize size = NSMakeSize(rect.width(), rect.height()); | 1493 NSSize size = NSMakeSize(rect.width(), rect.height()); |
1211 NSPoint pointInScreen = [self pointInScreen:origin size:size]; | 1494 NSPoint pointInScreen = [self pointInScreen:origin size:size]; |
1212 NSRect nsrect = NSMakeRect( | 1495 NSRect nsrect = NSMakeRect( |
1213 pointInScreen.x, pointInScreen.y, rect.width(), rect.height()); | 1496 pointInScreen.x, pointInScreen.y, rect.width(), rect.height()); |
1214 return [NSValue valueWithRect:nsrect]; | 1497 return [NSValue valueWithRect:nsrect]; |
1215 } | 1498 } |
| 1499 if ([attribute isEqualToString:@"AXUIElementCountForSearchPredicate"]) { |
| 1500 OneShotAccessibilityTreeSearch search(browserAccessibility_->manager()); |
| 1501 if (InitializeAccessibilityTreeSearch(&search, parameter)) |
| 1502 return [NSNumber numberWithInt:search.CountMatches()]; |
| 1503 return nil; |
| 1504 } |
| 1505 |
| 1506 if ([attribute isEqualToString:@"AXUIElementsForSearchPredicate"]) { |
| 1507 OneShotAccessibilityTreeSearch search(browserAccessibility_->manager()); |
| 1508 if (InitializeAccessibilityTreeSearch(&search, parameter)) { |
| 1509 size_t count = search.CountMatches(); |
| 1510 NSMutableArray* result = [NSMutableArray arrayWithCapacity:count]; |
| 1511 for (size_t i = 0; i < count; ++i) { |
| 1512 BrowserAccessibility* match = search.GetMatchAtIndex(i); |
| 1513 [result addObject:match->ToBrowserAccessibilityCocoa()]; |
| 1514 } |
| 1515 return result; |
| 1516 } |
| 1517 return nil; |
| 1518 } |
1216 | 1519 |
1217 // TODO(dtseng): support the following attributes. | 1520 // TODO(dtseng): support the following attributes. |
1218 if ([attribute isEqualTo: | 1521 if ([attribute isEqualTo: |
1219 NSAccessibilityRangeForPositionParameterizedAttribute] || | 1522 NSAccessibilityRangeForPositionParameterizedAttribute] || |
1220 [attribute isEqualTo: | 1523 [attribute isEqualTo: |
1221 NSAccessibilityRangeForIndexParameterizedAttribute] || | 1524 NSAccessibilityRangeForIndexParameterizedAttribute] || |
1222 [attribute isEqualTo:NSAccessibilityRTFForRangeParameterizedAttribute] || | 1525 [attribute isEqualTo:NSAccessibilityRTFForRangeParameterizedAttribute] || |
1223 [attribute isEqualTo: | 1526 [attribute isEqualTo: |
1224 NSAccessibilityStyleRangeForIndexParameterizedAttribute]) { | 1527 NSAccessibilityStyleRangeForIndexParameterizedAttribute]) { |
1225 return nil; | 1528 return nil; |
1226 } | 1529 } |
1227 return nil; | 1530 return nil; |
1228 } | 1531 } |
1229 | 1532 |
1230 // Returns an array of parameterized attributes names that this object will | 1533 // Returns an array of parameterized attributes names that this object will |
1231 // respond to. | 1534 // respond to. |
1232 - (NSArray*)accessibilityParameterizedAttributeNames { | 1535 - (NSArray*)accessibilityParameterizedAttributeNames { |
1233 if (!browserAccessibility_) | 1536 if (!browserAccessibility_) |
1234 return nil; | 1537 return nil; |
1235 | 1538 |
| 1539 // General attributes. |
| 1540 NSMutableArray* ret = [NSMutableArray arrayWithObjects: |
| 1541 @"AXUIElementCountForSearchPredicate", |
| 1542 @"AXUIElementsForSearchPredicate", |
| 1543 nil]; |
| 1544 |
1236 if ([[self role] isEqualToString:NSAccessibilityTableRole] || | 1545 if ([[self role] isEqualToString:NSAccessibilityTableRole] || |
1237 [[self role] isEqualToString:NSAccessibilityGridRole]) { | 1546 [[self role] isEqualToString:NSAccessibilityGridRole]) { |
1238 return [NSArray arrayWithObjects: | 1547 [ret addObjectsFromArray:[NSArray arrayWithObjects: |
1239 NSAccessibilityCellForColumnAndRowParameterizedAttribute, | 1548 NSAccessibilityCellForColumnAndRowParameterizedAttribute, |
1240 nil]; | 1549 nil]]; |
1241 } | 1550 } |
1242 if ([[self role] isEqualToString:NSAccessibilityTextFieldRole]) { | 1551 if ([[self role] isEqualToString:NSAccessibilityTextFieldRole]) { |
1243 return [NSArray arrayWithObjects: | 1552 [ret addObjectsFromArray:[NSArray arrayWithObjects: |
1244 NSAccessibilityLineForIndexParameterizedAttribute, | 1553 NSAccessibilityLineForIndexParameterizedAttribute, |
1245 NSAccessibilityRangeForLineParameterizedAttribute, | 1554 NSAccessibilityRangeForLineParameterizedAttribute, |
1246 NSAccessibilityStringForRangeParameterizedAttribute, | 1555 NSAccessibilityStringForRangeParameterizedAttribute, |
1247 NSAccessibilityRangeForPositionParameterizedAttribute, | 1556 NSAccessibilityRangeForPositionParameterizedAttribute, |
1248 NSAccessibilityRangeForIndexParameterizedAttribute, | 1557 NSAccessibilityRangeForIndexParameterizedAttribute, |
1249 NSAccessibilityBoundsForRangeParameterizedAttribute, | 1558 NSAccessibilityBoundsForRangeParameterizedAttribute, |
1250 NSAccessibilityRTFForRangeParameterizedAttribute, | 1559 NSAccessibilityRTFForRangeParameterizedAttribute, |
1251 NSAccessibilityAttributedStringForRangeParameterizedAttribute, | 1560 NSAccessibilityAttributedStringForRangeParameterizedAttribute, |
1252 NSAccessibilityStyleRangeForIndexParameterizedAttribute, | 1561 NSAccessibilityStyleRangeForIndexParameterizedAttribute, |
1253 nil]; | 1562 nil]]; |
1254 } | 1563 } |
1255 if ([self internalRole] == ui::AX_ROLE_STATIC_TEXT) { | 1564 if ([self internalRole] == ui::AX_ROLE_STATIC_TEXT) { |
1256 return [NSArray arrayWithObjects: | 1565 [ret addObjectsFromArray:[NSArray arrayWithObjects: |
1257 NSAccessibilityBoundsForRangeParameterizedAttribute, | 1566 NSAccessibilityBoundsForRangeParameterizedAttribute, |
1258 nil]; | 1567 nil]]; |
1259 } | 1568 } |
1260 return nil; | 1569 return ret; |
1261 } | 1570 } |
1262 | 1571 |
1263 // Returns an array of action names that this object will respond to. | 1572 // Returns an array of action names that this object will respond to. |
1264 - (NSArray*)accessibilityActionNames { | 1573 - (NSArray*)accessibilityActionNames { |
1265 if (!browserAccessibility_) | 1574 if (!browserAccessibility_) |
1266 return nil; | 1575 return nil; |
1267 | 1576 |
1268 NSMutableArray* ret = | 1577 NSMutableArray* ret = |
1269 [NSMutableArray arrayWithObject:NSAccessibilityShowMenuAction]; | 1578 [NSMutableArray arrayWithObject:NSAccessibilityShowMenuAction]; |
1270 NSString* role = [self role]; | 1579 NSString* role = [self role]; |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1662 if (!browserAccessibility_) | 1971 if (!browserAccessibility_) |
1663 return [super hash]; | 1972 return [super hash]; |
1664 return browserAccessibility_->GetId(); | 1973 return browserAccessibility_->GetId(); |
1665 } | 1974 } |
1666 | 1975 |
1667 - (BOOL)accessibilityShouldUseUniqueId { | 1976 - (BOOL)accessibilityShouldUseUniqueId { |
1668 return YES; | 1977 return YES; |
1669 } | 1978 } |
1670 | 1979 |
1671 @end | 1980 @end |
OLD | NEW |