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

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

Issue 2944103005: Fix lifetime problems in AXPlatformNodeCocoa. (Closed)
Patch Set: -tFix modern SDK warnings Created 3 years, 5 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
« no previous file with comments | « no previous file | ui/views/widget/native_widget_mac_accessibility_unittest.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 } 304 }
305 305
306 - (NSString*)getAXValueAsString { 306 - (NSString*)getAXValueAsString {
307 id value = [self AXValue]; 307 id value = [self AXValue];
308 return [value isKindOfClass:[NSString class]] ? value : nil; 308 return [value isKindOfClass:[NSString class]] ? value : nil;
309 } 309 }
310 310
311 // NSAccessibility informal protocol implementation. 311 // NSAccessibility informal protocol implementation.
312 312
313 - (BOOL)accessibilityIsIgnored { 313 - (BOOL)accessibilityIsIgnored {
314 if (!node_)
315 return YES;
316
314 return [[self AXRole] isEqualToString:NSAccessibilityUnknownRole] || 317 return [[self AXRole] isEqualToString:NSAccessibilityUnknownRole] ||
315 node_->GetData().HasState(ui::AX_STATE_INVISIBLE); 318 node_->GetData().HasState(ui::AX_STATE_INVISIBLE);
316 } 319 }
317 320
318 - (id)accessibilityHitTest:(NSPoint)point { 321 - (id)accessibilityHitTest:(NSPoint)point {
319 for (AXPlatformNodeCocoa* child in [self AXChildren]) { 322 for (AXPlatformNodeCocoa* child in [self AXChildren]) {
320 if (![child accessibilityIsIgnored] && 323 if (![child accessibilityIsIgnored] &&
321 NSPointInRect(point, child.boundsInScreen)) { 324 NSPointInRect(point, child.boundsInScreen)) {
322 return [child accessibilityHitTest:point]; 325 return [child accessibilityHitTest:point];
323 } 326 }
324 } 327 }
325 return NSAccessibilityUnignoredAncestor(self); 328 return NSAccessibilityUnignoredAncestor(self);
326 } 329 }
327 330
328 - (BOOL)accessibilityNotifiesWhenDestroyed { 331 - (BOOL)accessibilityNotifiesWhenDestroyed {
329 return YES; 332 return YES;
330 } 333 }
331 334
332 - (id)accessibilityFocusedUIElement { 335 - (id)accessibilityFocusedUIElement {
333 return node_->GetDelegate()->GetFocus(); 336 return node_ ? node_->GetDelegate()->GetFocus() : nil;
334 } 337 }
335 338
336 - (NSArray*)accessibilityActionNames { 339 - (NSArray*)accessibilityActionNames {
340 if (!node_)
341 return @[];
342
337 base::scoped_nsobject<NSMutableArray> axActions( 343 base::scoped_nsobject<NSMutableArray> axActions(
338 [[NSMutableArray alloc] init]); 344 [[NSMutableArray alloc] init]);
339 345
340 const ui::AXNodeData& data = node_->GetData(); 346 const ui::AXNodeData& data = node_->GetData();
341 const ActionList& action_list = GetActionList(); 347 const ActionList& action_list = GetActionList();
342 348
343 // VoiceOver expects the "press" action to be first. Note that some roles 349 // VoiceOver expects the "press" action to be first. Note that some roles
344 // should be given a press action implicitly. 350 // should be given a press action implicitly.
345 DCHECK([action_list[0].second isEqualToString:NSAccessibilityPressAction]); 351 DCHECK([action_list[0].second isEqualToString:NSAccessibilityPressAction]);
346 for (const auto item : action_list) { 352 for (const auto item : action_list) {
347 if (data.HasAction(item.first) || HasImplicitAction(data, item.first)) 353 if (data.HasAction(item.first) || HasImplicitAction(data, item.first))
348 [axActions addObject:item.second]; 354 [axActions addObject:item.second];
349 } 355 }
350 356
351 if (AlsoUseShowMenuActionForDefaultAction(data)) 357 if (AlsoUseShowMenuActionForDefaultAction(data))
352 [axActions addObject:NSAccessibilityShowMenuAction]; 358 [axActions addObject:NSAccessibilityShowMenuAction];
353 359
354 return axActions.autorelease(); 360 return axActions.autorelease();
355 } 361 }
356 362
357 - (void)accessibilityPerformAction:(NSString*)action { 363 - (void)accessibilityPerformAction:(NSString*)action {
358 DCHECK([[self accessibilityActionNames] containsObject:action]); 364 // Actions are performed asynchronously, so it's always possible for an object
365 // to change its mind after previously reporting an action as available.
366 if (![[self accessibilityActionNames] containsObject:action])
367 return;
368
359 ui::AXActionData data; 369 ui::AXActionData data;
360 if ([action isEqualToString:NSAccessibilityShowMenuAction] && 370 if ([action isEqualToString:NSAccessibilityShowMenuAction] &&
361 AlsoUseShowMenuActionForDefaultAction(node_->GetData())) { 371 AlsoUseShowMenuActionForDefaultAction(node_->GetData())) {
362 data.action = ui::AX_ACTION_DO_DEFAULT; 372 data.action = ui::AX_ACTION_DO_DEFAULT;
363 } else { 373 } else {
364 for (const ActionList::value_type& entry : GetActionList()) { 374 for (const ActionList::value_type& entry : GetActionList()) {
365 if ([action isEqualToString:entry.second]) { 375 if ([action isEqualToString:entry.second]) {
366 data.action = entry.first; 376 data.action = entry.first;
367 break; 377 break;
368 } 378 }
369 } 379 }
370 } 380 }
371 381
372 // Note ui::AX_ACTIONs which are just overwriting an accessibility attribute 382 // Note ui::AX_ACTIONs which are just overwriting an accessibility attribute
373 // are already implemented in -accessibilitySetValue:forAttribute:, so ignore 383 // are already implemented in -accessibilitySetValue:forAttribute:, so ignore
374 // those here. 384 // those here.
375 385
376 if (data.action != ui::AX_ACTION_NONE) 386 if (data.action != ui::AX_ACTION_NONE)
377 node_->GetDelegate()->AccessibilityPerformAction(data); 387 node_->GetDelegate()->AccessibilityPerformAction(data);
378 } 388 }
379 389
380 - (NSArray*)accessibilityAttributeNames { 390 - (NSArray*)accessibilityAttributeNames {
391 if (!node_)
392 return @[];
393
381 // These attributes are required on all accessibility objects. 394 // These attributes are required on all accessibility objects.
382 NSArray* const kAllRoleAttributes = @[ 395 NSArray* const kAllRoleAttributes = @[
383 NSAccessibilityChildrenAttribute, 396 NSAccessibilityChildrenAttribute,
384 NSAccessibilityParentAttribute, 397 NSAccessibilityParentAttribute,
385 NSAccessibilityPositionAttribute, 398 NSAccessibilityPositionAttribute,
386 NSAccessibilityRoleAttribute, 399 NSAccessibilityRoleAttribute,
387 NSAccessibilitySizeAttribute, 400 NSAccessibilitySizeAttribute,
388 NSAccessibilitySubroleAttribute, 401 NSAccessibilitySubroleAttribute,
389 402
390 // Title is required for most elements. Cocoa asks for the value even if it 403 // Title is required for most elements. Cocoa asks for the value even if it
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 break; 453 break;
441 // TODO(tapted): Add additional attributes based on role. 454 // TODO(tapted): Add additional attributes based on role.
442 default: 455 default:
443 break; 456 break;
444 } 457 }
445 return axAttributes.autorelease(); 458 return axAttributes.autorelease();
446 } 459 }
447 460
448 - (NSArray*)accessibilityParameterizedAttributeNames { 461 - (NSArray*)accessibilityParameterizedAttributeNames {
449 if (!node_) 462 if (!node_)
450 return nil; 463 return @[];
451 464
452 static NSArray* const kSelectableTextAttributes = [@[ 465 static NSArray* const kSelectableTextAttributes = [@[
453 NSAccessibilityLineForIndexParameterizedAttribute, 466 NSAccessibilityLineForIndexParameterizedAttribute,
454 NSAccessibilityRangeForLineParameterizedAttribute, 467 NSAccessibilityRangeForLineParameterizedAttribute,
455 NSAccessibilityStringForRangeParameterizedAttribute, 468 NSAccessibilityStringForRangeParameterizedAttribute,
456 NSAccessibilityRangeForPositionParameterizedAttribute, 469 NSAccessibilityRangeForPositionParameterizedAttribute,
457 NSAccessibilityRangeForIndexParameterizedAttribute, 470 NSAccessibilityRangeForIndexParameterizedAttribute,
458 NSAccessibilityBoundsForRangeParameterizedAttribute, 471 NSAccessibilityBoundsForRangeParameterizedAttribute,
459 NSAccessibilityRTFForRangeParameterizedAttribute, 472 NSAccessibilityRTFForRangeParameterizedAttribute,
460 NSAccessibilityStyleRangeForIndexParameterizedAttribute, 473 NSAccessibilityStyleRangeForIndexParameterizedAttribute,
461 NSAccessibilityAttributedStringForRangeParameterizedAttribute, 474 NSAccessibilityAttributedStringForRangeParameterizedAttribute,
462 ] retain]; 475 ] retain];
463 476
464 switch (node_->GetData().role) { 477 switch (node_->GetData().role) {
465 case ui::AX_ROLE_TEXT_FIELD: 478 case ui::AX_ROLE_TEXT_FIELD:
466 case ui::AX_ROLE_STATIC_TEXT: 479 case ui::AX_ROLE_STATIC_TEXT:
467 return kSelectableTextAttributes; 480 return kSelectableTextAttributes;
468 default: 481 default:
469 break; 482 break;
470 } 483 }
471 return nil; 484 return nil;
472 } 485 }
473 486
474 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName { 487 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName {
488 if (!node_)
489 return NO;
490
475 if (node_->GetData().HasState(ui::AX_STATE_DISABLED)) 491 if (node_->GetData().HasState(ui::AX_STATE_DISABLED))
476 return NO; 492 return NO;
477 493
478 // Allow certain attributes to be written via an accessibility client. A 494 // Allow certain attributes to be written via an accessibility client. A
479 // writable attribute will only appear as such if the accessibility element 495 // writable attribute will only appear as such if the accessibility element
480 // has a value set for that attribute. 496 // has a value set for that attribute.
481 if ([attributeName 497 if ([attributeName
482 isEqualToString:NSAccessibilitySelectedChildrenAttribute] || 498 isEqualToString:NSAccessibilitySelectedChildrenAttribute] ||
483 [attributeName 499 [attributeName
484 isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) { 500 isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) {
(...skipping 17 matching lines...) Expand all
502 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { 518 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) {
503 return node_->GetData().HasState(ui::AX_STATE_FOCUSABLE); 519 return node_->GetData().HasState(ui::AX_STATE_FOCUSABLE);
504 } 520 }
505 521
506 // TODO(patricialor): Add callbacks for updating the above attributes except 522 // TODO(patricialor): Add callbacks for updating the above attributes except
507 // NSAccessibilityValueAttribute and return YES. 523 // NSAccessibilityValueAttribute and return YES.
508 return NO; 524 return NO;
509 } 525 }
510 526
511 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { 527 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
528 if (!node_)
529 return;
530
512 ui::AXActionData data; 531 ui::AXActionData data;
513 532
514 // Check for attributes first. Only the |data.action| should be set here - any 533 // Check for attributes first. Only the |data.action| should be set here - any
515 // type-specific information, if needed, should be set below. 534 // type-specific information, if needed, should be set below.
516 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { 535 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
517 data.action = node_->GetData().role == ui::AX_ROLE_TAB 536 data.action = node_->GetData().role == ui::AX_ROLE_TAB
518 ? ui::AX_ACTION_SET_SELECTION 537 ? ui::AX_ACTION_SET_SELECTION
519 : ui::AX_ACTION_SET_VALUE; 538 : ui::AX_ACTION_SET_VALUE;
520 } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) { 539 } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
521 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; 540 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT;
(...skipping 18 matching lines...) Expand all
540 } 559 }
541 560
542 if (data.action != ui::AX_ACTION_NONE) 561 if (data.action != ui::AX_ACTION_NONE)
543 node_->GetDelegate()->AccessibilityPerformAction(data); 562 node_->GetDelegate()->AccessibilityPerformAction(data);
544 563
545 // TODO(patricialor): Plumb through all the other writable attributes as 564 // TODO(patricialor): Plumb through all the other writable attributes as
546 // specified in accessibilityIsAttributeSettable. 565 // specified in accessibilityIsAttributeSettable.
547 } 566 }
548 567
549 - (id)accessibilityAttributeValue:(NSString*)attribute { 568 - (id)accessibilityAttributeValue:(NSString*)attribute {
569 if (!node_)
570 return nil; // Return nil when detached. Even for AXRole.
571
550 SEL selector = NSSelectorFromString(attribute); 572 SEL selector = NSSelectorFromString(attribute);
551 if ([self respondsToSelector:selector]) 573 if ([self respondsToSelector:selector])
552 return [self performSelector:selector]; 574 return [self performSelector:selector];
553 return nil; 575 return nil;
554 } 576 }
555 577
556 - (id)accessibilityAttributeValue:(NSString*)attribute 578 - (id)accessibilityAttributeValue:(NSString*)attribute
557 forParameter:(id)parameter { 579 forParameter:(id)parameter {
580 if (!node_)
581 return nil;
582
558 SEL selector = NSSelectorFromString([attribute stringByAppendingString:@":"]); 583 SEL selector = NSSelectorFromString([attribute stringByAppendingString:@":"]);
559 if ([self respondsToSelector:selector]) 584 if ([self respondsToSelector:selector])
560 return [self performSelector:selector withObject:parameter]; 585 return [self performSelector:selector withObject:parameter];
561 return nil; 586 return nil;
562 } 587 }
563 588
564 // NSAccessibility attributes. Order them according to 589 // NSAccessibility attributes. Order them according to
565 // NSAccessibilityConstants.h, or see https://crbug.com/678898. 590 // NSAccessibilityConstants.h, or see https://crbug.com/678898.
566 591
567 - (NSString*)AXRole { 592 - (NSString*)AXRole {
568 if (!node_) 593 if (!node_)
569 return nil; 594 return nil;
595
570 return [[self class] nativeRoleFromAXRole:node_->GetData().role]; 596 return [[self class] nativeRoleFromAXRole:node_->GetData().role];
571 } 597 }
572 598
573 - (NSString*)AXRoleDescription { 599 - (NSString*)AXRoleDescription {
574 switch (node_->GetData().role) { 600 switch (node_->GetData().role) {
575 case ui::AX_ROLE_TAB: 601 case ui::AX_ROLE_TAB:
576 // There is no NSAccessibilityTabRole or similar (AXRadioButton is used 602 // There is no NSAccessibilityTabRole or similar (AXRadioButton is used
577 // instead). Do the same as NSTabView and put "tab" in the description. 603 // instead). Do the same as NSTabView and put "tab" in the description.
578 return [l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB_ROLE_DESCRIPTION) 604 return [l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB_ROLE_DESCRIPTION)
579 lowercaseString]; 605 lowercaseString];
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 } 653 }
628 654
629 - (id)AXParent { 655 - (id)AXParent {
630 if (!node_) 656 if (!node_)
631 return nil; 657 return nil;
632 return NSAccessibilityUnignoredAncestor(node_->GetParent()); 658 return NSAccessibilityUnignoredAncestor(node_->GetParent());
633 } 659 }
634 660
635 - (NSArray*)AXChildren { 661 - (NSArray*)AXChildren {
636 if (!node_) 662 if (!node_)
637 return nil; 663 return @[];
664
638 int count = node_->GetChildCount(); 665 int count = node_->GetChildCount();
639 NSMutableArray* children = [NSMutableArray arrayWithCapacity:count]; 666 NSMutableArray* children = [NSMutableArray arrayWithCapacity:count];
640 for (int i = 0; i < count; ++i) 667 for (int i = 0; i < count; ++i)
641 [children addObject:node_->ChildAtIndex(i)]; 668 [children addObject:node_->ChildAtIndex(i)];
642 return NSAccessibilityUnignoredChildren(children); 669 return NSAccessibilityUnignoredChildren(children);
643 } 670 }
644 671
645 - (id)AXWindow { 672 - (id)AXWindow {
646 return node_->GetDelegate()->GetTopLevelWidget(); 673 return node_->GetDelegate()->GetTopLevelWidget();
647 } 674 }
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
820 } 847 }
821 NotifyMacEvent(native_node_, event_type); 848 NotifyMacEvent(native_node_, event_type);
822 } 849 }
823 850
824 int AXPlatformNodeMac::GetIndexInParent() { 851 int AXPlatformNodeMac::GetIndexInParent() {
825 // TODO(dmazzoni): implement this. http://crbug.com/396137 852 // TODO(dmazzoni): implement this. http://crbug.com/396137
826 return -1; 853 return -1;
827 } 854 }
828 855
829 } // namespace ui 856 } // namespace ui
OLDNEW
« no previous file with comments | « no previous file | ui/views/widget/native_widget_mac_accessibility_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698