| 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" |
| 11 #include "base/strings/sys_string_conversions.h" | 11 #include "base/strings/sys_string_conversions.h" |
| 12 #include "ui/accessibility/ax_action_data.h" | 12 #include "ui/accessibility/ax_action_data.h" |
| 13 #include "ui/accessibility/ax_node_data.h" | 13 #include "ui/accessibility/ax_node_data.h" |
| 14 #include "ui/accessibility/platform/ax_platform_node_delegate.h" | 14 #include "ui/accessibility/platform/ax_platform_node_delegate.h" |
| 15 #include "ui/base/l10n/l10n_util.h" |
| 15 #import "ui/gfx/mac/coordinate_conversion.h" | 16 #import "ui/gfx/mac/coordinate_conversion.h" |
| 17 #include "ui/strings/grit/ui_strings.h" |
| 16 | 18 |
| 17 namespace { | 19 namespace { |
| 18 | 20 |
| 19 struct RoleMapEntry { | 21 struct RoleMapEntry { |
| 20 ui::AXRole value; | 22 ui::AXRole value; |
| 21 NSString* nativeValue; | 23 NSString* nativeValue; |
| 22 }; | 24 }; |
| 23 | 25 |
| 24 struct EventMapEntry { | 26 struct EventMapEntry { |
| 25 ui::AXEvent value; | 27 ui::AXEvent value; |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 default: | 366 default: |
| 365 break; | 367 break; |
| 366 } | 368 } |
| 367 return axAttributes.autorelease(); | 369 return axAttributes.autorelease(); |
| 368 } | 370 } |
| 369 | 371 |
| 370 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName { | 372 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName { |
| 371 // Allow certain attributes to be written via an accessibility client. A | 373 // Allow certain attributes to be written via an accessibility client. A |
| 372 // writable attribute will only appear as such if the accessibility element | 374 // writable attribute will only appear as such if the accessibility element |
| 373 // has a value set for that attribute. | 375 // has a value set for that attribute. |
| 374 if ([attributeName isEqualToString:NSAccessibilitySelectedAttribute] || | 376 if ([attributeName |
| 375 [attributeName | |
| 376 isEqualToString:NSAccessibilitySelectedChildrenAttribute] || | 377 isEqualToString:NSAccessibilitySelectedChildrenAttribute] || |
| 377 [attributeName | 378 [attributeName |
| 378 isEqualToString:NSAccessibilitySelectedTextRangeAttribute] || | 379 isEqualToString:NSAccessibilitySelectedTextRangeAttribute] || |
| 379 [attributeName | 380 [attributeName |
| 380 isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) { | 381 isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) { |
| 381 return NO; | 382 return NO; |
| 382 } | 383 } |
| 383 | 384 |
| 385 // Since tabs use the Radio Button role on Mac, the standard way to set them |
| 386 // is via the value attribute rather than the selected attribute. |
| 387 if ([attributeName isEqualToString:NSAccessibilityValueAttribute] && |
| 388 node_->GetData().role == ui::AX_ROLE_TAB) { |
| 389 return !node_->GetData().HasStateFlag(ui::AX_STATE_SELECTED); |
| 390 } |
| 391 |
| 384 if ([attributeName isEqualToString:NSAccessibilityValueAttribute] || | 392 if ([attributeName isEqualToString:NSAccessibilityValueAttribute] || |
| 385 [attributeName isEqualToString:NSAccessibilitySelectedTextAttribute]) | 393 [attributeName isEqualToString:NSAccessibilitySelectedTextAttribute]) { |
| 386 return !ui::AXNodeData::IsFlagSet(node_->GetData().state, | 394 return !ui::AXNodeData::IsFlagSet(node_->GetData().state, |
| 387 ui::AX_STATE_READ_ONLY); | 395 ui::AX_STATE_READ_ONLY); |
| 396 } |
| 388 | 397 |
| 389 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { | 398 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { |
| 390 return ui::AXNodeData::IsFlagSet(node_->GetData().state, | 399 return ui::AXNodeData::IsFlagSet(node_->GetData().state, |
| 391 ui::AX_STATE_FOCUSABLE); | 400 ui::AX_STATE_FOCUSABLE); |
| 392 } | 401 } |
| 393 | 402 |
| 394 // TODO(patricialor): Add callbacks for updating the above attributes except | 403 // TODO(patricialor): Add callbacks for updating the above attributes except |
| 395 // NSAccessibilityValueAttribute and return YES. | 404 // NSAccessibilityValueAttribute and return YES. |
| 396 return NO; | 405 return NO; |
| 397 } | 406 } |
| 398 | 407 |
| 399 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { | 408 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { |
| 400 ui::AXActionData data; | 409 ui::AXActionData data; |
| 401 if ([value isKindOfClass:[NSString class]]) { | 410 |
| 402 data.value = base::SysNSStringToUTF16(value); | 411 // Check for attributes first. Only the |data.action| should be set here - any |
| 403 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { | 412 // type-specific information, if needed, should be set below. |
| 404 data.action = ui::AX_ACTION_SET_VALUE; | 413 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { |
| 405 } else if ([attribute | 414 data.action = node_->GetData().role == ui::AX_ROLE_TAB |
| 406 isEqualToString:NSAccessibilitySelectedTextAttribute]) { | 415 ? ui::AX_ACTION_SET_SELECTION |
| 407 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; | 416 : ui::AX_ACTION_SET_VALUE; |
| 408 } | 417 } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) { |
| 409 } else if ([value isKindOfClass:[NSNumber class]]) { | 418 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; |
| 410 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { | 419 } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { |
| 420 if ([value isKindOfClass:[NSNumber class]]) { |
| 411 data.action = | 421 data.action = |
| 412 [value boolValue] ? ui::AX_ACTION_FOCUS : ui::AX_ACTION_BLUR; | 422 [value boolValue] ? ui::AX_ACTION_FOCUS : ui::AX_ACTION_BLUR; |
| 413 } | 423 } |
| 414 } | 424 } |
| 415 | 425 |
| 426 // Set type-specific information as necessary for actions set above. |
| 427 if ([value isKindOfClass:[NSString class]]) |
| 428 data.value = base::SysNSStringToUTF16(value); |
| 429 |
| 416 if (data.action != ui::AX_ACTION_NONE) | 430 if (data.action != ui::AX_ACTION_NONE) |
| 417 node_->GetDelegate()->AccessibilityPerformAction(data); | 431 node_->GetDelegate()->AccessibilityPerformAction(data); |
| 418 | 432 |
| 419 // TODO(patricialor): Plumb through all the other writable attributes as | 433 // TODO(patricialor): Plumb through all the other writable attributes as |
| 420 // specified in accessibilityIsAttributeSettable. | 434 // specified in accessibilityIsAttributeSettable. |
| 421 } | 435 } |
| 422 | 436 |
| 423 - (id)accessibilityAttributeValue:(NSString*)attribute { | 437 - (id)accessibilityAttributeValue:(NSString*)attribute { |
| 424 SEL selector = NSSelectorFromString(attribute); | 438 SEL selector = NSSelectorFromString(attribute); |
| 425 if ([self respondsToSelector:selector]) | 439 if ([self respondsToSelector:selector]) |
| 426 return [self performSelector:selector]; | 440 return [self performSelector:selector]; |
| 427 return nil; | 441 return nil; |
| 428 } | 442 } |
| 429 | 443 |
| 430 // NSAccessibility attributes. Order them according to | 444 // NSAccessibility attributes. Order them according to |
| 431 // NSAccessibilityConstants.h, or see https://crbug.com/678898. | 445 // NSAccessibilityConstants.h, or see https://crbug.com/678898. |
| 432 | 446 |
| 433 - (NSString*)AXRole { | 447 - (NSString*)AXRole { |
| 434 if (!node_) | 448 if (!node_) |
| 435 return nil; | 449 return nil; |
| 436 return [[self class] nativeRoleFromAXRole:node_->GetData().role]; | 450 return [[self class] nativeRoleFromAXRole:node_->GetData().role]; |
| 437 } | 451 } |
| 438 | 452 |
| 439 - (NSString*)AXRoleDescription { | 453 - (NSString*)AXRoleDescription { |
| 454 switch (node_->GetData().role) { |
| 455 case ui::AX_ROLE_TAB: |
| 456 // There is no NSAccessibilityTabRole or similar (AXRadioButton is used |
| 457 // instead). Do the same as NSTabView and put "tab" in the description. |
| 458 return [l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB_ROLE_DESCRIPTION) |
| 459 lowercaseString]; |
| 460 default: |
| 461 break; |
| 462 } |
| 440 return NSAccessibilityRoleDescription([self AXRole], [self AXSubrole]); | 463 return NSAccessibilityRoleDescription([self AXRole], [self AXSubrole]); |
| 441 } | 464 } |
| 442 | 465 |
| 443 - (NSString*)AXSubrole { | 466 - (NSString*)AXSubrole { |
| 444 ui::AXRole role = node_->GetData().role; | 467 ui::AXRole role = node_->GetData().role; |
| 445 switch (role) { | 468 switch (role) { |
| 446 case ui::AX_ROLE_TEXT_FIELD: | 469 case ui::AX_ROLE_TEXT_FIELD: |
| 447 if (ui::AXNodeData::IsFlagSet(node_->GetData().state, | 470 if (ui::AXNodeData::IsFlagSet(node_->GetData().state, |
| 448 ui::AX_STATE_PROTECTED)) | 471 ui::AX_STATE_PROTECTED)) |
| 449 return NSAccessibilitySecureTextFieldSubrole; | 472 return NSAccessibilitySecureTextFieldSubrole; |
| 450 break; | 473 break; |
| 451 default: | 474 default: |
| 452 break; | 475 break; |
| 453 } | 476 } |
| 454 return [AXPlatformNodeCocoa nativeSubroleFromAXRole:role]; | 477 return [AXPlatformNodeCocoa nativeSubroleFromAXRole:role]; |
| 455 } | 478 } |
| 456 | 479 |
| 457 - (NSString*)AXHelp { | 480 - (NSString*)AXHelp { |
| 458 return [self getStringAttribute:ui::AX_ATTR_DESCRIPTION]; | 481 return [self getStringAttribute:ui::AX_ATTR_DESCRIPTION]; |
| 459 } | 482 } |
| 460 | 483 |
| 461 - (NSString*)AXValue { | 484 - (id)AXValue { |
| 485 if (node_->GetData().role == ui::AX_ROLE_TAB) |
| 486 return [self AXSelected]; |
| 462 return [self getStringAttribute:ui::AX_ATTR_VALUE]; | 487 return [self getStringAttribute:ui::AX_ATTR_VALUE]; |
| 463 } | 488 } |
| 464 | 489 |
| 465 - (NSNumber*)AXEnabled { | 490 - (NSNumber*)AXEnabled { |
| 466 return [NSNumber | 491 return [NSNumber |
| 467 numberWithBool:!ui::AXNodeData::IsFlagSet(node_->GetData().state, | 492 numberWithBool:!ui::AXNodeData::IsFlagSet(node_->GetData().state, |
| 468 ui::AX_STATE_DISABLED)]; | 493 ui::AX_STATE_DISABLED)]; |
| 469 } | 494 } |
| 470 | 495 |
| 471 - (NSNumber*)AXFocused { | 496 - (NSNumber*)AXFocused { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 507 - (NSValue*)AXSize { | 532 - (NSValue*)AXSize { |
| 508 return [NSValue valueWithSize:self.boundsInScreen.size]; | 533 return [NSValue valueWithSize:self.boundsInScreen.size]; |
| 509 } | 534 } |
| 510 | 535 |
| 511 - (NSString*)AXTitle { | 536 - (NSString*)AXTitle { |
| 512 return [self getStringAttribute:ui::AX_ATTR_NAME]; | 537 return [self getStringAttribute:ui::AX_ATTR_NAME]; |
| 513 } | 538 } |
| 514 | 539 |
| 515 // Misc attributes. | 540 // Misc attributes. |
| 516 | 541 |
| 542 - (NSNumber*)AXSelected { |
| 543 return [NSNumber |
| 544 numberWithBool:node_->GetData().HasStateFlag(ui::AX_STATE_SELECTED)]; |
| 545 } |
| 546 |
| 517 - (NSString*)AXPlaceholderValue { | 547 - (NSString*)AXPlaceholderValue { |
| 518 return [self getStringAttribute:ui::AX_ATTR_PLACEHOLDER]; | 548 return [self getStringAttribute:ui::AX_ATTR_PLACEHOLDER]; |
| 519 } | 549 } |
| 520 | 550 |
| 521 // Text-specific attributes. | 551 // Text-specific attributes. |
| 522 | 552 |
| 523 - (NSString*)AXSelectedText { | 553 - (NSString*)AXSelectedText { |
| 524 NSRange selectedTextRange; | 554 NSRange selectedTextRange; |
| 525 [[self AXSelectedTextRange] getValue:&selectedTextRange]; | 555 [[self AXSelectedTextRange] getValue:&selectedTextRange]; |
| 526 return [[self AXValue] substringWithRange:selectedTextRange]; | 556 return [[self AXValue] substringWithRange:selectedTextRange]; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 } | 631 } |
| 602 NotifyMacEvent(native_node_, event_type); | 632 NotifyMacEvent(native_node_, event_type); |
| 603 } | 633 } |
| 604 | 634 |
| 605 int AXPlatformNodeMac::GetIndexInParent() { | 635 int AXPlatformNodeMac::GetIndexInParent() { |
| 606 // TODO(dmazzoni): implement this. http://crbug.com/396137 | 636 // TODO(dmazzoni): implement this. http://crbug.com/396137 |
| 607 return -1; | 637 return -1; |
| 608 } | 638 } |
| 609 | 639 |
| 610 } // namespace ui | 640 } // namespace ui |
| OLD | NEW |