Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(216)

Side by Side Diff: ui/accessibility/platform/ax_platform_node_mac.mm

Issue 2578303003: a11y: Add a11y information to views::Tab and manually ignore its a11y children. (Closed)
Patch Set: Review comments. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 {ui::AX_ROLE_MAIN, @"AXLandmarkMain"}, 179 {ui::AX_ROLE_MAIN, @"AXLandmarkMain"},
178 {ui::AX_ROLE_MARQUEE, @"AXApplicationMarquee"}, 180 {ui::AX_ROLE_MARQUEE, @"AXApplicationMarquee"},
179 {ui::AX_ROLE_MATH, @"AXDocumentMath"}, 181 {ui::AX_ROLE_MATH, @"AXDocumentMath"},
180 {ui::AX_ROLE_NAVIGATION, @"AXLandmarkNavigation"}, 182 {ui::AX_ROLE_NAVIGATION, @"AXLandmarkNavigation"},
181 {ui::AX_ROLE_NOTE, @"AXDocumentNote"}, 183 {ui::AX_ROLE_NOTE, @"AXDocumentNote"},
182 {ui::AX_ROLE_REGION, @"AXDocumentRegion"}, 184 {ui::AX_ROLE_REGION, @"AXDocumentRegion"},
183 {ui::AX_ROLE_SEARCH, @"AXLandmarkSearch"}, 185 {ui::AX_ROLE_SEARCH, @"AXLandmarkSearch"},
184 {ui::AX_ROLE_SEARCH_BOX, @"AXSearchField"}, 186 {ui::AX_ROLE_SEARCH_BOX, @"AXSearchField"},
185 {ui::AX_ROLE_STATUS, @"AXApplicationStatus"}, 187 {ui::AX_ROLE_STATUS, @"AXApplicationStatus"},
186 {ui::AX_ROLE_SWITCH, @"AXSwitch"}, 188 {ui::AX_ROLE_SWITCH, @"AXSwitch"},
189 {ui::AX_ROLE_TAB, @"AXTab"},
187 {ui::AX_ROLE_TAB_PANEL, @"AXTabPanel"}, 190 {ui::AX_ROLE_TAB_PANEL, @"AXTabPanel"},
188 {ui::AX_ROLE_TIMER, @"AXApplicationTimer"}, 191 {ui::AX_ROLE_TIMER, @"AXApplicationTimer"},
189 {ui::AX_ROLE_TOGGLE_BUTTON, @"AXToggleButton"}, 192 {ui::AX_ROLE_TOGGLE_BUTTON, @"AXToggleButton"},
190 {ui::AX_ROLE_TOOLTIP, @"AXUserInterfaceTooltip"}, 193 {ui::AX_ROLE_TOOLTIP, @"AXUserInterfaceTooltip"},
191 {ui::AX_ROLE_TREE_ITEM, NSAccessibilityOutlineRowSubrole}, 194 {ui::AX_ROLE_TREE_ITEM, NSAccessibilityOutlineRowSubrole},
192 }; 195 };
193 196
194 RoleMap subrole_map; 197 RoleMap subrole_map;
195 for (size_t i = 0; i < arraysize(subroles); ++i) 198 for (size_t i = 0; i < arraysize(subroles); ++i)
196 subrole_map[subroles[i].value] = subroles[i].nativeValue; 199 subrole_map[subroles[i].value] = subroles[i].nativeValue;
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 default: 365 default:
363 break; 366 break;
364 } 367 }
365 return axAttributes.autorelease(); 368 return axAttributes.autorelease();
366 } 369 }
367 370
368 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName { 371 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName {
369 // Allow certain attributes to be written via an accessibility client. A 372 // Allow certain attributes to be written via an accessibility client. A
370 // writable attribute will only appear as such if the accessibility element 373 // writable attribute will only appear as such if the accessibility element
371 // has a value set for that attribute. 374 // has a value set for that attribute.
372 if ([attributeName isEqualToString:NSAccessibilitySelectedAttribute] || 375 if ([attributeName
373 [attributeName
374 isEqualToString:NSAccessibilitySelectedChildrenAttribute] || 376 isEqualToString:NSAccessibilitySelectedChildrenAttribute] ||
375 [attributeName 377 [attributeName
376 isEqualToString:NSAccessibilitySelectedTextRangeAttribute] || 378 isEqualToString:NSAccessibilitySelectedTextRangeAttribute] ||
377 [attributeName 379 [attributeName
378 isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) { 380 isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) {
379 return NO; 381 return NO;
380 } 382 }
381 383
384 // Since tabs use the Radio Button role on Mac, the standard way to set them
385 // is via the value attribute rather than the selected attribute.
386 if ([attributeName isEqualToString:NSAccessibilityValueAttribute] &&
387 node_->GetData().role == ui::AX_ROLE_TAB) {
388 return !node_->GetData().HasStateFlag(ui::AX_STATE_SELECTED);
389 }
390
382 if ([attributeName isEqualToString:NSAccessibilityValueAttribute] || 391 if ([attributeName isEqualToString:NSAccessibilityValueAttribute] ||
383 [attributeName isEqualToString:NSAccessibilitySelectedTextAttribute]) 392 [attributeName isEqualToString:NSAccessibilitySelectedTextAttribute]) {
384 return !ui::AXNodeData::IsFlagSet(node_->GetData().state, 393 return !ui::AXNodeData::IsFlagSet(node_->GetData().state,
385 ui::AX_STATE_READ_ONLY); 394 ui::AX_STATE_READ_ONLY);
395 }
386 396
387 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { 397 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) {
388 return ui::AXNodeData::IsFlagSet(node_->GetData().state, 398 return ui::AXNodeData::IsFlagSet(node_->GetData().state,
389 ui::AX_STATE_FOCUSABLE); 399 ui::AX_STATE_FOCUSABLE);
390 } 400 }
391 401
392 // TODO(patricialor): Add callbacks for updating the above attributes except 402 // TODO(patricialor): Add callbacks for updating the above attributes except
393 // NSAccessibilityValueAttribute and return YES. 403 // NSAccessibilityValueAttribute and return YES.
394 return NO; 404 return NO;
395 } 405 }
396 406
397 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { 407 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
398 ui::AXActionData data; 408 ui::AXActionData data;
399 if ([value isKindOfClass:[NSString class]]) { 409
400 data.value = base::SysNSStringToUTF16(value); 410 // Check for attributes first. Only the |data.action| should be set here - any
401 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { 411 // type-specific information, if needed, should be set below.
402 data.action = ui::AX_ACTION_SET_VALUE; 412 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
403 } else if ([attribute 413 data.action = node_->GetData().role == ui::AX_ROLE_TAB
404 isEqualToString:NSAccessibilitySelectedTextAttribute]) { 414 ? ui::AX_ACTION_SET_SELECTION
405 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; 415 : ui::AX_ACTION_SET_VALUE;
406 } 416 } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
407 } else if ([value isKindOfClass:[NSNumber class]]) { 417 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT;
408 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { 418 } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
419 if ([value isKindOfClass:[NSNumber class]]) {
409 data.action = 420 data.action =
410 [value boolValue] ? ui::AX_ACTION_FOCUS : ui::AX_ACTION_BLUR; 421 [value boolValue] ? ui::AX_ACTION_FOCUS : ui::AX_ACTION_BLUR;
411 } 422 }
412 } 423 }
413 424
425 // Set type-specific information as necessary for actions set above.
426 if ([value isKindOfClass:[NSString class]]) {
tapted 2017/01/12 16:33:55 nit: no curlies needed
Patti Lor 2017/01/13 05:48:38 Done.
427 data.value = base::SysNSStringToUTF16(value);
428 }
429
414 if (data.action != ui::AX_ACTION_NONE) 430 if (data.action != ui::AX_ACTION_NONE)
415 node_->GetDelegate()->AccessibilityPerformAction(data); 431 node_->GetDelegate()->AccessibilityPerformAction(data);
416 432
417 // TODO(patricialor): Plumb through all the other writable attributes as 433 // TODO(patricialor): Plumb through all the other writable attributes as
418 // specified in accessibilityIsAttributeSettable. 434 // specified in accessibilityIsAttributeSettable.
419 } 435 }
420 436
421 - (id)accessibilityAttributeValue:(NSString*)attribute { 437 - (id)accessibilityAttributeValue:(NSString*)attribute {
422 SEL selector = NSSelectorFromString(attribute); 438 SEL selector = NSSelectorFromString(attribute);
423 if ([self respondsToSelector:selector]) 439 if ([self respondsToSelector:selector])
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 ui::AX_STATE_PROTECTED)) 477 ui::AX_STATE_PROTECTED))
462 return NSAccessibilitySecureTextFieldSubrole; 478 return NSAccessibilitySecureTextFieldSubrole;
463 break; 479 break;
464 default: 480 default:
465 break; 481 break;
466 } 482 }
467 return [AXPlatformNodeCocoa nativeSubroleFromAXRole:role]; 483 return [AXPlatformNodeCocoa nativeSubroleFromAXRole:role];
468 } 484 }
469 485
470 - (NSString*)AXRoleDescription { 486 - (NSString*)AXRoleDescription {
487 switch (node_->GetData().role) {
488 case ui::AX_ROLE_TAB:
489 // There is no NSAccessibilityTabRole or similar (AXRadioButton is used
490 // instead). Do the same as NSTabView and put "tab" in the description.
491 return [l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB_ROLE_DESCRIPTION)
492 lowercaseString];
493 default:
494 break;
495 }
471 return NSAccessibilityRoleDescription([self AXRole], [self AXSubrole]); 496 return NSAccessibilityRoleDescription([self AXRole], [self AXSubrole]);
472 } 497 }
473 498
474 - (NSValue*)AXSize { 499 - (NSValue*)AXSize {
475 return [NSValue valueWithSize:self.boundsInScreen.size]; 500 return [NSValue valueWithSize:self.boundsInScreen.size];
476 } 501 }
477 502
478 - (NSString*)AXTitle { 503 - (NSString*)AXTitle {
479 return [self getStringAttribute:ui::AX_ATTR_NAME]; 504 return [self getStringAttribute:ui::AX_ATTR_NAME];
480 } 505 }
481 506
482 - (NSString*)AXValue { 507 - (id)AXValue {
508 if (node_->GetData().role == ui::AX_ROLE_TAB)
509 return [self AXSelected];
483 return [self getStringAttribute:ui::AX_ATTR_VALUE]; 510 return [self getStringAttribute:ui::AX_ATTR_VALUE];
484 } 511 }
485 512
486 - (NSValue*)AXEnabled { 513 - (NSValue*)AXEnabled {
487 return [NSNumber 514 return [NSNumber
488 numberWithBool:!ui::AXNodeData::IsFlagSet(node_->GetData().state, 515 numberWithBool:!ui::AXNodeData::IsFlagSet(node_->GetData().state,
489 ui::AX_STATE_DISABLED)]; 516 ui::AX_STATE_DISABLED)];
490 } 517 }
491 518
492 - (NSValue*)AXFocused { 519 - (NSValue*)AXFocused {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
543 int beginSelectionIndex = (end > start && !isReversed) ? start : end; 570 int beginSelectionIndex = (end > start && !isReversed) ? start : end;
544 return [NSValue 571 return [NSValue
545 valueWithRange:NSMakeRange(beginSelectionIndex, abs(end - start))]; 572 valueWithRange:NSMakeRange(beginSelectionIndex, abs(end - start))];
546 } 573 }
547 574
548 - (NSValue*)AXVisibleCharacterRange { 575 - (NSValue*)AXVisibleCharacterRange {
549 return [NSValue 576 return [NSValue
550 valueWithRange:NSMakeRange(0, [[self AXNumberOfCharacters] intValue])]; 577 valueWithRange:NSMakeRange(0, [[self AXNumberOfCharacters] intValue])];
551 } 578 }
552 579
580 // Misc NSAccessibility attributes.
581
582 - (NSNumber*)AXSelected {
583 return [NSNumber
584 numberWithBool:node_->GetData().HasStateFlag(ui::AX_STATE_SELECTED)];
585 }
586
553 @end 587 @end
554 588
555 namespace ui { 589 namespace ui {
556 590
557 // static 591 // static
558 AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) { 592 AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) {
559 AXPlatformNodeBase* node = new AXPlatformNodeMac(); 593 AXPlatformNodeBase* node = new AXPlatformNodeMac();
560 node->Init(delegate); 594 node->Init(delegate);
561 return node; 595 return node;
562 } 596 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 } 630 }
597 NotifyMacEvent(native_node_, event_type); 631 NotifyMacEvent(native_node_, event_type);
598 } 632 }
599 633
600 int AXPlatformNodeMac::GetIndexInParent() { 634 int AXPlatformNodeMac::GetIndexInParent() {
601 // TODO(dmazzoni): implement this. http://crbug.com/396137 635 // TODO(dmazzoni): implement this. http://crbug.com/396137
602 return -1; 636 return -1;
603 } 637 }
604 638
605 } // namespace ui 639 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698