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 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 348 NSAccessibilityEnabledAttribute, | 348 NSAccessibilityEnabledAttribute, |
| 349 NSAccessibilityFocusedAttribute, | 349 NSAccessibilityFocusedAttribute, |
| 350 NSAccessibilityHelpAttribute, | 350 NSAccessibilityHelpAttribute, |
| 351 NSAccessibilityTopLevelUIElementAttribute, | 351 NSAccessibilityTopLevelUIElementAttribute, |
| 352 NSAccessibilityWindowAttribute, | 352 NSAccessibilityWindowAttribute, |
| 353 ]; | 353 ]; |
| 354 | 354 |
| 355 // Attributes required for user-editable controls. | 355 // Attributes required for user-editable controls. |
| 356 NSArray* const kValueAttributes = @[ NSAccessibilityValueAttribute ]; | 356 NSArray* const kValueAttributes = @[ NSAccessibilityValueAttribute ]; |
| 357 | 357 |
| 358 // Attributes required for textfields. | 358 // Attributes required for unprotected textfields. |
| 359 NSArray* const kTextfieldAttributes = @[ | 359 NSArray* const kUnprotectedTextfieldAttributes = @[ |
| 360 NSAccessibilityInsertionPointLineNumberAttribute, | 360 NSAccessibilityInsertionPointLineNumberAttribute, |
| 361 NSAccessibilityNumberOfCharactersAttribute, | 361 NSAccessibilityNumberOfCharactersAttribute, |
| 362 NSAccessibilityPlaceholderValueAttribute, | |
| 363 NSAccessibilitySelectedTextAttribute, | 362 NSAccessibilitySelectedTextAttribute, |
| 364 NSAccessibilitySelectedTextRangeAttribute, | 363 NSAccessibilitySelectedTextRangeAttribute, |
| 365 NSAccessibilityVisibleCharacterRangeAttribute, | 364 NSAccessibilityVisibleCharacterRangeAttribute, |
| 366 ]; | 365 ]; |
| 367 | 366 |
| 367 // Required for all textfields, including protected ones. | |
| 368 NSString* const kTextfieldAttributes = | |
| 369 NSAccessibilityPlaceholderValueAttribute; | |
| 370 | |
| 368 base::scoped_nsobject<NSMutableArray> axAttributes( | 371 base::scoped_nsobject<NSMutableArray> axAttributes( |
| 369 [[NSMutableArray alloc] init]); | 372 [[NSMutableArray alloc] init]); |
| 370 | 373 |
| 371 [axAttributes addObjectsFromArray:kAllRoleAttributes]; | 374 [axAttributes addObjectsFromArray:kAllRoleAttributes]; |
| 372 switch (node_->GetData().role) { | 375 switch (node_->GetData().role) { |
| 373 case ui::AX_ROLE_TEXT_FIELD: | 376 case ui::AX_ROLE_TEXT_FIELD: |
| 374 [axAttributes addObjectsFromArray:kTextfieldAttributes]; | 377 [axAttributes addObject:kTextfieldAttributes]; |
| 378 if (!ui::AXNodeData::IsFlagSet(node_->GetData().state, | |
| 379 ui::AX_STATE_PROTECTED)) { | |
| 380 [axAttributes addObjectsFromArray:kUnprotectedTextfieldAttributes]; | |
| 381 } | |
| 375 // Fallthrough. | 382 // Fallthrough. |
| 376 case ui::AX_ROLE_CHECK_BOX: | 383 case ui::AX_ROLE_CHECK_BOX: |
| 377 case ui::AX_ROLE_COMBO_BOX: | 384 case ui::AX_ROLE_COMBO_BOX: |
| 378 case ui::AX_ROLE_MENU_ITEM_CHECK_BOX: | 385 case ui::AX_ROLE_MENU_ITEM_CHECK_BOX: |
| 379 case ui::AX_ROLE_MENU_ITEM_RADIO: | 386 case ui::AX_ROLE_MENU_ITEM_RADIO: |
| 380 case ui::AX_ROLE_RADIO_BUTTON: | 387 case ui::AX_ROLE_RADIO_BUTTON: |
| 381 case ui::AX_ROLE_SEARCH_BOX: | 388 case ui::AX_ROLE_SEARCH_BOX: |
| 382 case ui::AX_ROLE_SLIDER: | 389 case ui::AX_ROLE_SLIDER: |
| 383 case ui::AX_ROLE_SLIDER_THUMB: | 390 case ui::AX_ROLE_SLIDER_THUMB: |
| 384 case ui::AX_ROLE_TOGGLE_BUTTON: | 391 case ui::AX_ROLE_TOGGLE_BUTTON: |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 398 // Allow certain attributes to be written via an accessibility client. A | 405 // Allow certain attributes to be written via an accessibility client. A |
| 399 // writable attribute will only appear as such if the accessibility element | 406 // writable attribute will only appear as such if the accessibility element |
| 400 // has a value set for that attribute. | 407 // has a value set for that attribute. |
| 401 if ([attributeName | 408 if ([attributeName |
| 402 isEqualToString:NSAccessibilitySelectedChildrenAttribute] || | 409 isEqualToString:NSAccessibilitySelectedChildrenAttribute] || |
| 403 [attributeName | 410 [attributeName |
| 404 isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) { | 411 isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) { |
| 405 return NO; | 412 return NO; |
| 406 } | 413 } |
| 407 | 414 |
| 408 // Since tabs use the Radio Button role on Mac, the standard way to set them | 415 if ([attributeName isEqualToString:NSAccessibilityValueAttribute]) { |
| 409 // is via the value attribute rather than the selected attribute. | 416 if (node_->GetData().HasStateFlag(ui::AX_STATE_PROTECTED)) { |
| 410 if ([attributeName isEqualToString:NSAccessibilityValueAttribute] && | 417 // NSSecureTextField doesn't allow values to be edited (despite showing up |
| 411 node_->GetData().role == ui::AX_ROLE_TAB) { | 418 // as editable), match its behavior. |
| 412 return !node_->GetData().HasStateFlag(ui::AX_STATE_SELECTED); | 419 return NO; |
| 420 } | |
| 421 // Since tabs use the Radio Button role on Mac, the standard way to set | |
| 422 // them is via the value attribute rather than the selected attribute. | |
| 423 else if (node_->GetData().role == ui::AX_ROLE_TAB) { | |
|
tapted
2017/02/24 05:23:42
nit: remove "else" (since the prior `if` always re
Patti Lor
2017/02/26 23:16:37
Done.
| |
| 424 return !node_->GetData().HasStateFlag(ui::AX_STATE_SELECTED); | |
| 425 } | |
| 413 } | 426 } |
| 414 | 427 |
| 415 if ([attributeName isEqualToString:NSAccessibilityValueAttribute] || | 428 if ([attributeName isEqualToString:NSAccessibilityValueAttribute] || |
| 416 [attributeName isEqualToString:NSAccessibilitySelectedTextAttribute] || | 429 [attributeName isEqualToString:NSAccessibilitySelectedTextAttribute] || |
| 417 [attributeName | 430 [attributeName |
| 418 isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { | 431 isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { |
| 419 return !ui::AXNodeData::IsFlagSet(node_->GetData().state, | 432 return !ui::AXNodeData::IsFlagSet(node_->GetData().state, |
| 420 ui::AX_STATE_READ_ONLY); | 433 ui::AX_STATE_READ_ONLY); |
| 421 } | 434 } |
| 422 | 435 |
| 423 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { | 436 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { |
| 424 return ui::AXNodeData::IsFlagSet(node_->GetData().state, | 437 return ui::AXNodeData::IsFlagSet(node_->GetData().state, |
| 425 ui::AX_STATE_FOCUSABLE); | 438 ui::AX_STATE_FOCUSABLE); |
| 426 } | 439 } |
| 427 | 440 |
| 428 // TODO(patricialor): Add callbacks for updating the above attributes except | 441 // TODO(patricialor): Add callbacks for updating the above attributes except |
| 429 // NSAccessibilityValueAttribute and return YES. | 442 // NSAccessibilityValueAttribute and return YES. |
| 430 return NO; | 443 return NO; |
| 431 } | 444 } |
| 432 | 445 |
| 433 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { | 446 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { |
| 434 ui::AXActionData data; | 447 ui::AXActionData data; |
| 435 | 448 |
| 436 // Check for attributes first. Only the |data.action| should be set here - any | 449 // Check for attributes first. Only the |data.action| should be set here - any |
| 437 // type-specific information, if needed, should be set below. | 450 // type-specific information, if needed, should be set below. |
| 438 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { | 451 if ([attribute isEqualToString:NSAccessibilityValueAttribute] && |
| 452 !node_->GetData().HasStateFlag(ui::AX_STATE_PROTECTED)) { | |
| 439 data.action = node_->GetData().role == ui::AX_ROLE_TAB | 453 data.action = node_->GetData().role == ui::AX_ROLE_TAB |
| 440 ? ui::AX_ACTION_SET_SELECTION | 454 ? ui::AX_ACTION_SET_SELECTION |
| 441 : ui::AX_ACTION_SET_VALUE; | 455 : ui::AX_ACTION_SET_VALUE; |
| 442 } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) { | 456 } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) { |
| 443 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; | 457 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; |
| 444 } else if ([attribute | 458 } else if ([attribute |
| 445 isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { | 459 isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { |
| 446 data.action = ui::AX_ACTION_SET_SELECTION; | 460 data.action = ui::AX_ACTION_SET_SELECTION; |
| 447 } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { | 461 } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { |
| 448 if ([value isKindOfClass:[NSNumber class]]) { | 462 if ([value isKindOfClass:[NSNumber class]]) { |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 576 return @(node_->GetData().HasStateFlag(ui::AX_STATE_SELECTED)); | 590 return @(node_->GetData().HasStateFlag(ui::AX_STATE_SELECTED)); |
| 577 } | 591 } |
| 578 | 592 |
| 579 - (NSString*)AXPlaceholderValue { | 593 - (NSString*)AXPlaceholderValue { |
| 580 return [self getStringAttribute:ui::AX_ATTR_PLACEHOLDER]; | 594 return [self getStringAttribute:ui::AX_ATTR_PLACEHOLDER]; |
| 581 } | 595 } |
| 582 | 596 |
| 583 // Text-specific attributes. | 597 // Text-specific attributes. |
| 584 | 598 |
| 585 - (NSString*)AXSelectedText { | 599 - (NSString*)AXSelectedText { |
| 600 if (ui::AXNodeData::IsFlagSet(node_->GetData().state, ui::AX_STATE_PROTECTED)) | |
| 601 return nil; | |
| 602 | |
| 586 NSRange selectedTextRange; | 603 NSRange selectedTextRange; |
| 587 [[self AXSelectedTextRange] getValue:&selectedTextRange]; | 604 [[self AXSelectedTextRange] getValue:&selectedTextRange]; |
| 588 return [[self AXValue] substringWithRange:selectedTextRange]; | 605 return [[self AXValue] substringWithRange:selectedTextRange]; |
| 589 } | 606 } |
| 590 | 607 |
| 591 - (NSValue*)AXSelectedTextRange { | 608 - (NSValue*)AXSelectedTextRange { |
| 609 if (ui::AXNodeData::IsFlagSet(node_->GetData().state, ui::AX_STATE_PROTECTED)) | |
| 610 return nil; | |
| 611 | |
| 592 int textDir, start, end; | 612 int textDir, start, end; |
| 593 node_->GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION, &textDir); | 613 node_->GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION, &textDir); |
| 594 node_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START, &start); | 614 node_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START, &start); |
| 595 node_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, &end); | 615 node_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, &end); |
| 596 // NSRange cannot represent the direction the text was selected in, so make | 616 // NSRange cannot represent the direction the text was selected in, so make |
| 597 // sure the correct selection index is used when creating a new range, taking | 617 // sure the correct selection index is used when creating a new range, taking |
| 598 // into account the textfield text direction as well. | 618 // into account the textfield text direction as well. |
| 599 bool isReversed = (textDir == ui::AX_TEXT_DIRECTION_RTL) || | 619 bool isReversed = (textDir == ui::AX_TEXT_DIRECTION_RTL) || |
| 600 (textDir == ui::AX_TEXT_DIRECTION_BTT); | 620 (textDir == ui::AX_TEXT_DIRECTION_BTT); |
| 601 int beginSelectionIndex = (end > start && !isReversed) ? start : end; | 621 int beginSelectionIndex = (end > start && !isReversed) ? start : end; |
| 602 return [NSValue valueWithRange:{beginSelectionIndex, abs(end - start)}]; | 622 return [NSValue valueWithRange:{beginSelectionIndex, abs(end - start)}]; |
| 603 } | 623 } |
| 604 | 624 |
| 605 - (NSNumber*)AXNumberOfCharacters { | 625 - (NSNumber*)AXNumberOfCharacters { |
| 626 if (ui::AXNodeData::IsFlagSet(node_->GetData().state, ui::AX_STATE_PROTECTED)) | |
| 627 return nil; | |
| 606 return @([[self AXValue] length]); | 628 return @([[self AXValue] length]); |
| 607 } | 629 } |
| 608 | 630 |
| 609 - (NSValue*)AXVisibleCharacterRange { | 631 - (NSValue*)AXVisibleCharacterRange { |
| 632 if (ui::AXNodeData::IsFlagSet(node_->GetData().state, ui::AX_STATE_PROTECTED)) | |
| 633 return nil; | |
| 610 return [NSValue valueWithRange:{0, [[self AXNumberOfCharacters] intValue]}]; | 634 return [NSValue valueWithRange:{0, [[self AXNumberOfCharacters] intValue]}]; |
| 611 } | 635 } |
| 612 | 636 |
| 613 - (NSNumber*)AXInsertionPointLineNumber { | 637 - (NSNumber*)AXInsertionPointLineNumber { |
| 638 if (ui::AXNodeData::IsFlagSet(node_->GetData().state, ui::AX_STATE_PROTECTED)) | |
| 639 return nil; | |
| 614 // Multiline is not supported on views. | 640 // Multiline is not supported on views. |
| 615 return @0; | 641 return @0; |
| 616 } | 642 } |
| 617 | 643 |
| 618 @end | 644 @end |
| 619 | 645 |
| 620 namespace ui { | 646 namespace ui { |
| 621 | 647 |
| 622 // static | 648 // static |
| 623 AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) { | 649 AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 661 } | 687 } |
| 662 NotifyMacEvent(native_node_, event_type); | 688 NotifyMacEvent(native_node_, event_type); |
| 663 } | 689 } |
| 664 | 690 |
| 665 int AXPlatformNodeMac::GetIndexInParent() { | 691 int AXPlatformNodeMac::GetIndexInParent() { |
| 666 // TODO(dmazzoni): implement this. http://crbug.com/396137 | 692 // TODO(dmazzoni): implement this. http://crbug.com/396137 |
| 667 return -1; | 693 return -1; |
| 668 } | 694 } |
| 669 | 695 |
| 670 } // namespace ui | 696 } // namespace ui |
| OLD | NEW |