Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 #import "ui/accessibility/platform/ax_platform_node_mac.h" | 5 #import "ui/accessibility/platform/ax_platform_node_mac.h" |
| 6 | 6 |
| 7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 273 node_ = nil; | 273 node_ = nil; |
| 274 } | 274 } |
| 275 | 275 |
| 276 - (NSRect)boundsInScreen { | 276 - (NSRect)boundsInScreen { |
| 277 if (!node_) | 277 if (!node_) |
| 278 return NSZeroRect; | 278 return NSZeroRect; |
| 279 return gfx::ScreenRectToNSRect(node_->GetBoundsInScreen()); | 279 return gfx::ScreenRectToNSRect(node_->GetBoundsInScreen()); |
| 280 } | 280 } |
| 281 | 281 |
| 282 - (NSString*)getStringAttribute:(ui::AXStringAttribute)attribute { | 282 - (NSString*)getStringAttribute:(ui::AXStringAttribute)attribute { |
| 283 if (!node_) | |
|
dmazzoni
2017/06/20 17:47:16
Isn't this an internal helper method? It seems lik
tapted
2017/06/20 23:30:52
Removed - I think this was just left over from ear
| |
| 284 return nil; | |
| 285 | |
| 283 std::string attributeValue; | 286 std::string attributeValue; |
| 284 if (node_->GetStringAttribute(attribute, &attributeValue)) | 287 if (node_->GetStringAttribute(attribute, &attributeValue)) |
| 285 return base::SysUTF8ToNSString(attributeValue); | 288 return base::SysUTF8ToNSString(attributeValue); |
| 286 return nil; | 289 return nil; |
| 287 } | 290 } |
| 288 | 291 |
| 289 - (NSString*)getAXValueAsString { | 292 - (NSString*)getAXValueAsString { |
| 290 id value = [self AXValue]; | 293 id value = [self AXValue]; |
| 291 return [value isKindOfClass:[NSString class]] ? value : nil; | 294 return [value isKindOfClass:[NSString class]] ? value : nil; |
| 292 } | 295 } |
| 293 | 296 |
| 294 // NSAccessibility informal protocol implementation. | 297 // NSAccessibility informal protocol implementation. |
| 295 | 298 |
| 296 - (BOOL)accessibilityIsIgnored { | 299 - (BOOL)accessibilityIsIgnored { |
| 300 if (!node_) | |
| 301 return YES; | |
| 302 | |
| 297 return [[self AXRole] isEqualToString:NSAccessibilityUnknownRole] || | 303 return [[self AXRole] isEqualToString:NSAccessibilityUnknownRole] || |
| 298 node_->GetData().HasState(ui::AX_STATE_INVISIBLE); | 304 node_->GetData().HasState(ui::AX_STATE_INVISIBLE); |
| 299 } | 305 } |
| 300 | 306 |
| 301 - (id)accessibilityHitTest:(NSPoint)point { | 307 - (id)accessibilityHitTest:(NSPoint)point { |
| 302 for (AXPlatformNodeCocoa* child in [self AXChildren]) { | 308 for (AXPlatformNodeCocoa* child in [self AXChildren]) { |
| 303 if (![child accessibilityIsIgnored] && | 309 if (![child accessibilityIsIgnored] && |
| 304 NSPointInRect(point, child.boundsInScreen)) { | 310 NSPointInRect(point, child.boundsInScreen)) { |
| 305 return [child accessibilityHitTest:point]; | 311 return [child accessibilityHitTest:point]; |
| 306 } | 312 } |
| 307 } | 313 } |
| 308 return NSAccessibilityUnignoredAncestor(self); | 314 return NSAccessibilityUnignoredAncestor(self); |
| 309 } | 315 } |
| 310 | 316 |
| 311 - (BOOL)accessibilityNotifiesWhenDestroyed { | 317 - (BOOL)accessibilityNotifiesWhenDestroyed { |
| 312 return YES; | 318 return YES; |
| 313 } | 319 } |
| 314 | 320 |
| 315 - (id)accessibilityFocusedUIElement { | 321 - (id)accessibilityFocusedUIElement { |
| 316 return node_->GetDelegate()->GetFocus(); | 322 return node_ ? node_->GetDelegate()->GetFocus() : nil; |
| 317 } | 323 } |
| 318 | 324 |
| 319 - (NSArray*)accessibilityActionNames { | 325 - (NSArray*)accessibilityActionNames { |
| 326 if (!node_) | |
| 327 return @[]; | |
| 328 | |
| 320 base::scoped_nsobject<NSMutableArray> axActions( | 329 base::scoped_nsobject<NSMutableArray> axActions( |
| 321 [[NSMutableArray alloc] init]); | 330 [[NSMutableArray alloc] init]); |
| 322 | 331 |
| 323 const ui::AXNodeData& data = node_->GetData(); | 332 const ui::AXNodeData& data = node_->GetData(); |
| 324 | 333 |
| 325 // VoiceOver expects the "press" action to be first. | 334 // VoiceOver expects the "press" action to be first. |
| 326 if (ui::IsRoleClickable(data.role) || data.HasAction(kActionForPress)) | 335 if (ui::IsRoleClickable(data.role) || data.HasAction(kActionForPress)) |
| 327 [axActions addObject:NSAccessibilityPressAction]; | 336 [axActions addObject:NSAccessibilityPressAction]; |
| 328 | 337 |
| 329 for (const ActionMap::value_type& entry : GetActionMap()) { | 338 for (const ActionMap::value_type& entry : GetActionMap()) { |
| 330 if (entry.first == kActionForPress) | 339 if (entry.first == kActionForPress) |
| 331 continue; | 340 continue; |
| 332 | 341 |
| 333 DCHECK(![entry.second isEqualToString:NSAccessibilityPressAction]); | 342 DCHECK(![entry.second isEqualToString:NSAccessibilityPressAction]); |
| 334 | 343 |
| 335 if (data.HasAction(entry.first)) | 344 if (data.HasAction(entry.first)) |
| 336 [axActions addObject:entry.second]; | 345 [axActions addObject:entry.second]; |
| 337 } | 346 } |
| 338 | 347 |
| 339 return axActions.autorelease(); | 348 return axActions.autorelease(); |
| 340 } | 349 } |
| 341 | 350 |
| 342 - (void)accessibilityPerformAction:(NSString*)action { | 351 - (void)accessibilityPerformAction:(NSString*)action { |
| 343 DCHECK([[self accessibilityActionNames] containsObject:action]); | 352 // Actions are performed asynchronously, so it's always possible for an object |
| 353 // to change its mind after previously reporting an action as available. | |
| 354 if (![[self accessibilityActionNames] containsObject:action]) | |
| 355 return; | |
| 356 | |
| 344 ui::AXActionData data; | 357 ui::AXActionData data; |
| 345 for (const ActionMap::value_type& entry : GetActionMap()) { | 358 for (const ActionMap::value_type& entry : GetActionMap()) { |
| 346 if ([action isEqualToString:entry.second]) { | 359 if ([action isEqualToString:entry.second]) { |
| 347 data.action = entry.first; | 360 data.action = entry.first; |
| 348 break; | 361 break; |
| 349 } | 362 } |
| 350 } | 363 } |
| 351 | 364 |
| 352 // Note ui::AX_ACTIONs which are just overwriting an accessibility attribute | 365 // Note ui::AX_ACTIONs which are just overwriting an accessibility attribute |
| 353 // are already implemented in -accessibilitySetValue:forAttribute:, so ignore | 366 // are already implemented in -accessibilitySetValue:forAttribute:, so ignore |
| 354 // those here. | 367 // those here. |
| 355 | 368 |
| 356 if (data.action != ui::AX_ACTION_NONE) | 369 if (data.action != ui::AX_ACTION_NONE) |
| 357 node_->GetDelegate()->AccessibilityPerformAction(data); | 370 node_->GetDelegate()->AccessibilityPerformAction(data); |
| 358 } | 371 } |
| 359 | 372 |
| 360 - (NSArray*)accessibilityAttributeNames { | 373 - (NSArray*)accessibilityAttributeNames { |
| 374 if (!node_) | |
| 375 return @[]; | |
| 376 | |
| 361 // These attributes are required on all accessibility objects. | 377 // These attributes are required on all accessibility objects. |
| 362 NSArray* const kAllRoleAttributes = @[ | 378 NSArray* const kAllRoleAttributes = @[ |
| 363 NSAccessibilityChildrenAttribute, | 379 NSAccessibilityChildrenAttribute, |
| 364 NSAccessibilityParentAttribute, | 380 NSAccessibilityParentAttribute, |
| 365 NSAccessibilityPositionAttribute, | 381 NSAccessibilityPositionAttribute, |
| 366 NSAccessibilityRoleAttribute, | 382 NSAccessibilityRoleAttribute, |
| 367 NSAccessibilitySizeAttribute, | 383 NSAccessibilitySizeAttribute, |
| 368 NSAccessibilitySubroleAttribute, | 384 NSAccessibilitySubroleAttribute, |
| 369 | 385 |
| 370 // Title is required for most elements. Cocoa asks for the value even if it | 386 // Title is required for most elements. Cocoa asks for the value even if it |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 419 [axAttributes addObjectsFromArray:kValueAttributes]; | 435 [axAttributes addObjectsFromArray:kValueAttributes]; |
| 420 break; | 436 break; |
| 421 // TODO(tapted): Add additional attributes based on role. | 437 // TODO(tapted): Add additional attributes based on role. |
| 422 default: | 438 default: |
| 423 break; | 439 break; |
| 424 } | 440 } |
| 425 return axAttributes.autorelease(); | 441 return axAttributes.autorelease(); |
| 426 } | 442 } |
| 427 | 443 |
| 428 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName { | 444 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName { |
| 445 if (!node_) | |
| 446 return NO; | |
| 447 | |
| 429 if (node_->GetData().HasState(ui::AX_STATE_DISABLED)) | 448 if (node_->GetData().HasState(ui::AX_STATE_DISABLED)) |
| 430 return NO; | 449 return NO; |
| 431 | 450 |
| 432 // Allow certain attributes to be written via an accessibility client. A | 451 // Allow certain attributes to be written via an accessibility client. A |
| 433 // writable attribute will only appear as such if the accessibility element | 452 // writable attribute will only appear as such if the accessibility element |
| 434 // has a value set for that attribute. | 453 // has a value set for that attribute. |
| 435 if ([attributeName | 454 if ([attributeName |
| 436 isEqualToString:NSAccessibilitySelectedChildrenAttribute] || | 455 isEqualToString:NSAccessibilitySelectedChildrenAttribute] || |
| 437 [attributeName | 456 [attributeName |
| 438 isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) { | 457 isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 456 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { | 475 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { |
| 457 return node_->GetData().HasState(ui::AX_STATE_FOCUSABLE); | 476 return node_->GetData().HasState(ui::AX_STATE_FOCUSABLE); |
| 458 } | 477 } |
| 459 | 478 |
| 460 // TODO(patricialor): Add callbacks for updating the above attributes except | 479 // TODO(patricialor): Add callbacks for updating the above attributes except |
| 461 // NSAccessibilityValueAttribute and return YES. | 480 // NSAccessibilityValueAttribute and return YES. |
| 462 return NO; | 481 return NO; |
| 463 } | 482 } |
| 464 | 483 |
| 465 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { | 484 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { |
| 485 if (!node_) | |
| 486 return; | |
| 487 | |
| 466 ui::AXActionData data; | 488 ui::AXActionData data; |
| 467 | 489 |
| 468 // Check for attributes first. Only the |data.action| should be set here - any | 490 // Check for attributes first. Only the |data.action| should be set here - any |
| 469 // type-specific information, if needed, should be set below. | 491 // type-specific information, if needed, should be set below. |
| 470 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { | 492 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { |
| 471 data.action = node_->GetData().role == ui::AX_ROLE_TAB | 493 data.action = node_->GetData().role == ui::AX_ROLE_TAB |
| 472 ? ui::AX_ACTION_SET_SELECTION | 494 ? ui::AX_ACTION_SET_SELECTION |
| 473 : ui::AX_ACTION_SET_VALUE; | 495 : ui::AX_ACTION_SET_VALUE; |
| 474 } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) { | 496 } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) { |
| 475 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; | 497 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 494 } | 516 } |
| 495 | 517 |
| 496 if (data.action != ui::AX_ACTION_NONE) | 518 if (data.action != ui::AX_ACTION_NONE) |
| 497 node_->GetDelegate()->AccessibilityPerformAction(data); | 519 node_->GetDelegate()->AccessibilityPerformAction(data); |
| 498 | 520 |
| 499 // TODO(patricialor): Plumb through all the other writable attributes as | 521 // TODO(patricialor): Plumb through all the other writable attributes as |
| 500 // specified in accessibilityIsAttributeSettable. | 522 // specified in accessibilityIsAttributeSettable. |
| 501 } | 523 } |
| 502 | 524 |
| 503 - (id)accessibilityAttributeValue:(NSString*)attribute { | 525 - (id)accessibilityAttributeValue:(NSString*)attribute { |
| 526 if (!node_) | |
| 527 return nil; // Return nil when detached. Even for AXRole. | |
| 528 | |
| 504 SEL selector = NSSelectorFromString(attribute); | 529 SEL selector = NSSelectorFromString(attribute); |
| 505 if ([self respondsToSelector:selector]) | 530 if ([self respondsToSelector:selector]) |
| 506 return [self performSelector:selector]; | 531 return [self performSelector:selector]; |
| 507 return nil; | 532 return nil; |
| 508 } | 533 } |
| 509 | 534 |
| 510 // NSAccessibility attributes. Order them according to | 535 // NSAccessibility attributes. Order them according to |
| 511 // NSAccessibilityConstants.h, or see https://crbug.com/678898. | 536 // NSAccessibilityConstants.h, or see https://crbug.com/678898. |
| 512 | 537 |
| 513 - (NSString*)AXRole { | 538 - (NSString*)AXRole { |
| 514 if (!node_) | 539 if (!node_) |
| 515 return nil; | 540 return nil; |
| 541 | |
| 516 return [[self class] nativeRoleFromAXRole:node_->GetData().role]; | 542 return [[self class] nativeRoleFromAXRole:node_->GetData().role]; |
| 517 } | 543 } |
| 518 | 544 |
| 519 - (NSString*)AXRoleDescription { | 545 - (NSString*)AXRoleDescription { |
| 520 switch (node_->GetData().role) { | 546 switch (node_->GetData().role) { |
| 521 case ui::AX_ROLE_TAB: | 547 case ui::AX_ROLE_TAB: |
| 522 // There is no NSAccessibilityTabRole or similar (AXRadioButton is used | 548 // There is no NSAccessibilityTabRole or similar (AXRadioButton is used |
| 523 // instead). Do the same as NSTabView and put "tab" in the description. | 549 // instead). Do the same as NSTabView and put "tab" in the description. |
| 524 return [l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB_ROLE_DESCRIPTION) | 550 return [l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB_ROLE_DESCRIPTION) |
| 525 lowercaseString]; | 551 lowercaseString]; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 570 } | 596 } |
| 571 | 597 |
| 572 - (id)AXParent { | 598 - (id)AXParent { |
| 573 if (!node_) | 599 if (!node_) |
| 574 return nil; | 600 return nil; |
| 575 return NSAccessibilityUnignoredAncestor(node_->GetParent()); | 601 return NSAccessibilityUnignoredAncestor(node_->GetParent()); |
| 576 } | 602 } |
| 577 | 603 |
| 578 - (NSArray*)AXChildren { | 604 - (NSArray*)AXChildren { |
| 579 if (!node_) | 605 if (!node_) |
| 580 return nil; | 606 return @[]; |
| 607 | |
| 581 int count = node_->GetChildCount(); | 608 int count = node_->GetChildCount(); |
| 582 NSMutableArray* children = [NSMutableArray arrayWithCapacity:count]; | 609 NSMutableArray* children = [NSMutableArray arrayWithCapacity:count]; |
| 583 for (int i = 0; i < count; ++i) | 610 for (int i = 0; i < count; ++i) |
| 584 [children addObject:node_->ChildAtIndex(i)]; | 611 [children addObject:node_->ChildAtIndex(i)]; |
| 585 return NSAccessibilityUnignoredChildren(children); | 612 return NSAccessibilityUnignoredChildren(children); |
| 586 } | 613 } |
| 587 | 614 |
| 588 - (id)AXWindow { | 615 - (id)AXWindow { |
| 589 return node_->GetDelegate()->GetTopLevelWidget(); | 616 return node_->GetDelegate()->GetTopLevelWidget(); |
| 590 } | 617 } |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 } | 727 } |
| 701 NotifyMacEvent(native_node_, event_type); | 728 NotifyMacEvent(native_node_, event_type); |
| 702 } | 729 } |
| 703 | 730 |
| 704 int AXPlatformNodeMac::GetIndexInParent() { | 731 int AXPlatformNodeMac::GetIndexInParent() { |
| 705 // TODO(dmazzoni): implement this. http://crbug.com/396137 | 732 // TODO(dmazzoni): implement this. http://crbug.com/396137 |
| 706 return -1; | 733 return -1; |
| 707 } | 734 } |
| 708 | 735 |
| 709 } // namespace ui | 736 } // namespace ui |
| OLD | NEW |