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

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: Add tests. 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);
386 395
387 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { 396 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) {
388 return ui::AXNodeData::IsFlagSet(node_->GetData().state, 397 return ui::AXNodeData::IsFlagSet(node_->GetData().state,
389 ui::AX_STATE_FOCUSABLE); 398 ui::AX_STATE_FOCUSABLE);
390 } 399 }
391 400
392 // TODO(patricialor): Add callbacks for updating the above attributes except 401 // TODO(patricialor): Add callbacks for updating the above attributes except
393 // NSAccessibilityValueAttribute and return YES. 402 // NSAccessibilityValueAttribute and return YES.
394 return NO; 403 return NO;
395 } 404 }
396 405
397 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { 406 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
398 ui::AXActionData data; 407 ui::AXActionData data;
399 if ([value isKindOfClass:[NSString class]]) { 408 if ([value isKindOfClass:[NSString class]]) {
400 data.value = base::SysNSStringToUTF16(value); 409 data.value = base::SysNSStringToUTF16(value);
401 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { 410 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
402 data.action = ui::AX_ACTION_SET_VALUE; 411 data.action = node_->GetData().role == ui::AX_ROLE_TAB
412 ? ui::AX_ACTION_SET_SELECTION
413 : ui::AX_ACTION_SET_VALUE;
403 } else if ([attribute 414 } else if ([attribute
404 isEqualToString:NSAccessibilitySelectedTextAttribute]) { 415 isEqualToString:NSAccessibilitySelectedTextAttribute]) {
405 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; 416 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT;
406 } 417 }
407 } else if ([value isKindOfClass:[NSNumber class]]) { 418 } else if ([value isKindOfClass:[NSNumber class]]) {
408 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { 419 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
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 }
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 ui::AX_STATE_PROTECTED)) 472 ui::AX_STATE_PROTECTED))
462 return NSAccessibilitySecureTextFieldSubrole; 473 return NSAccessibilitySecureTextFieldSubrole;
463 break; 474 break;
464 default: 475 default:
465 break; 476 break;
466 } 477 }
467 return [AXPlatformNodeCocoa nativeSubroleFromAXRole:role]; 478 return [AXPlatformNodeCocoa nativeSubroleFromAXRole:role];
468 } 479 }
469 480
470 - (NSString*)AXRoleDescription { 481 - (NSString*)AXRoleDescription {
482 switch (node_->GetData().role) {
483 case ui::AX_ROLE_TAB:
484 // There is no NSAccessibilityTabRole or similar (AXRadioButton is used
485 // instead). Do the same as NSTabView and put "tab" in the description.
486 return [l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB) lowercaseString];
487 default:
488 break;
489 }
471 return NSAccessibilityRoleDescription([self AXRole], [self AXSubrole]); 490 return NSAccessibilityRoleDescription([self AXRole], [self AXSubrole]);
472 } 491 }
473 492
474 - (NSValue*)AXSize { 493 - (NSValue*)AXSize {
475 return [NSValue valueWithSize:self.boundsInScreen.size]; 494 return [NSValue valueWithSize:self.boundsInScreen.size];
476 } 495 }
477 496
478 - (NSString*)AXTitle { 497 - (NSString*)AXTitle {
479 return [self getStringAttribute:ui::AX_ATTR_NAME]; 498 return [self getStringAttribute:ui::AX_ATTR_NAME];
480 } 499 }
481 500
482 - (NSString*)AXValue { 501 - (NSString*)AXValue {
502 if (node_->GetData().role == ui::AX_ROLE_TAB)
503 return [[self AXSelected] stringValue];
483 return [self getStringAttribute:ui::AX_ATTR_VALUE]; 504 return [self getStringAttribute:ui::AX_ATTR_VALUE];
484 } 505 }
485 506
486 - (NSValue*)AXEnabled { 507 - (NSValue*)AXEnabled {
487 return [NSNumber 508 return [NSNumber
488 numberWithBool:!ui::AXNodeData::IsFlagSet(node_->GetData().state, 509 numberWithBool:!ui::AXNodeData::IsFlagSet(node_->GetData().state,
489 ui::AX_STATE_DISABLED)]; 510 ui::AX_STATE_DISABLED)];
490 } 511 }
491 512
492 - (NSValue*)AXFocused { 513 - (NSValue*)AXFocused {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
543 int beginSelectionIndex = (end > start && !isReversed) ? start : end; 564 int beginSelectionIndex = (end > start && !isReversed) ? start : end;
544 return [NSValue 565 return [NSValue
545 valueWithRange:NSMakeRange(beginSelectionIndex, abs(end - start))]; 566 valueWithRange:NSMakeRange(beginSelectionIndex, abs(end - start))];
546 } 567 }
547 568
548 - (NSValue*)AXVisibleCharacterRange { 569 - (NSValue*)AXVisibleCharacterRange {
549 return [NSValue 570 return [NSValue
550 valueWithRange:NSMakeRange(0, [[self AXNumberOfCharacters] intValue])]; 571 valueWithRange:NSMakeRange(0, [[self AXNumberOfCharacters] intValue])];
551 } 572 }
552 573
574 // Misc NSAccessibility attributes.
575
576 - (NSNumber*)AXSelected {
577 return [NSNumber
578 numberWithBool:node_->GetData().HasStateFlag(ui::AX_STATE_SELECTED)];
579 }
580
553 @end 581 @end
554 582
555 namespace ui { 583 namespace ui {
556 584
557 // static 585 // static
558 AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) { 586 AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) {
559 AXPlatformNodeBase* node = new AXPlatformNodeMac(); 587 AXPlatformNodeBase* node = new AXPlatformNodeMac();
560 node->Init(delegate); 588 node->Init(delegate);
561 return node; 589 return node;
562 } 590 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 } 624 }
597 NotifyMacEvent(native_node_, event_type); 625 NotifyMacEvent(native_node_, event_type);
598 } 626 }
599 627
600 int AXPlatformNodeMac::GetIndexInParent() { 628 int AXPlatformNodeMac::GetIndexInParent() {
601 // TODO(dmazzoni): implement this. http://crbug.com/396137 629 // TODO(dmazzoni): implement this. http://crbug.com/396137
602 return -1; 630 return -1;
603 } 631 }
604 632
605 } // namespace ui 633 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698