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

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

Issue 2944103005: Fix lifetime problems in AXPlatformNodeCocoa. (Closed)
Patch Set: tolerable format Created 3 years, 6 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 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 node_ = nil; 273 node_ = nil;
274 } 274 }
275 275
276 - (NSRect)boundsInScreen { 276 - (NSRect)boundsInScreen {
277 if (!node_) 277 if (!node_)
278 return NSZeroRect; 278 return NSZeroRect;
279 return gfx::ScreenRectToNSRect(node_->GetBoundsInScreen()); 279 return gfx::ScreenRectToNSRect(node_->GetBoundsInScreen());
280 } 280 }
281 281
282 - (NSString*)getStringAttribute:(ui::AXStringAttribute)attribute { 282 - (NSString*)getStringAttribute:(ui::AXStringAttribute)attribute {
283 if (!node_)
dmazzoni 2017/06/20 17:47:16 Isn't this an internal helper method? It seems lik
tapted 2017/06/20 23:30:52 Removed - I think this was just left over from ear
284 return nil;
285
283 std::string attributeValue; 286 std::string attributeValue;
284 if (node_->GetStringAttribute(attribute, &attributeValue)) 287 if (node_->GetStringAttribute(attribute, &attributeValue))
285 return base::SysUTF8ToNSString(attributeValue); 288 return base::SysUTF8ToNSString(attributeValue);
286 return nil; 289 return nil;
287 } 290 }
288 291
289 - (NSString*)getAXValueAsString { 292 - (NSString*)getAXValueAsString {
290 id value = [self AXValue]; 293 id value = [self AXValue];
291 return [value isKindOfClass:[NSString class]] ? value : nil; 294 return [value isKindOfClass:[NSString class]] ? value : nil;
292 } 295 }
293 296
294 // NSAccessibility informal protocol implementation. 297 // NSAccessibility informal protocol implementation.
295 298
296 - (BOOL)accessibilityIsIgnored { 299 - (BOOL)accessibilityIsIgnored {
300 if (!node_)
301 return YES;
302
297 return [[self AXRole] isEqualToString:NSAccessibilityUnknownRole] || 303 return [[self AXRole] isEqualToString:NSAccessibilityUnknownRole] ||
298 node_->GetData().HasState(ui::AX_STATE_INVISIBLE); 304 node_->GetData().HasState(ui::AX_STATE_INVISIBLE);
299 } 305 }
300 306
301 - (id)accessibilityHitTest:(NSPoint)point { 307 - (id)accessibilityHitTest:(NSPoint)point {
302 for (AXPlatformNodeCocoa* child in [self AXChildren]) { 308 for (AXPlatformNodeCocoa* child in [self AXChildren]) {
303 if (![child accessibilityIsIgnored] && 309 if (![child accessibilityIsIgnored] &&
304 NSPointInRect(point, child.boundsInScreen)) { 310 NSPointInRect(point, child.boundsInScreen)) {
305 return [child accessibilityHitTest:point]; 311 return [child accessibilityHitTest:point];
306 } 312 }
307 } 313 }
308 return NSAccessibilityUnignoredAncestor(self); 314 return NSAccessibilityUnignoredAncestor(self);
309 } 315 }
310 316
311 - (BOOL)accessibilityNotifiesWhenDestroyed { 317 - (BOOL)accessibilityNotifiesWhenDestroyed {
312 return YES; 318 return YES;
313 } 319 }
314 320
315 - (id)accessibilityFocusedUIElement { 321 - (id)accessibilityFocusedUIElement {
316 return node_->GetDelegate()->GetFocus(); 322 return node_ ? node_->GetDelegate()->GetFocus() : nil;
317 } 323 }
318 324
319 - (NSArray*)accessibilityActionNames { 325 - (NSArray*)accessibilityActionNames {
326 if (!node_)
327 return @[];
328
320 base::scoped_nsobject<NSMutableArray> axActions( 329 base::scoped_nsobject<NSMutableArray> axActions(
321 [[NSMutableArray alloc] init]); 330 [[NSMutableArray alloc] init]);
322 331
323 const ui::AXNodeData& data = node_->GetData(); 332 const ui::AXNodeData& data = node_->GetData();
324 333
325 // VoiceOver expects the "press" action to be first. 334 // VoiceOver expects the "press" action to be first.
326 if (ui::IsRoleClickable(data.role) || data.HasAction(kActionForPress)) 335 if (ui::IsRoleClickable(data.role) || data.HasAction(kActionForPress))
327 [axActions addObject:NSAccessibilityPressAction]; 336 [axActions addObject:NSAccessibilityPressAction];
328 337
329 for (const ActionMap::value_type& entry : GetActionMap()) { 338 for (const ActionMap::value_type& entry : GetActionMap()) {
330 if (entry.first == kActionForPress) 339 if (entry.first == kActionForPress)
331 continue; 340 continue;
332 341
333 DCHECK(![entry.second isEqualToString:NSAccessibilityPressAction]); 342 DCHECK(![entry.second isEqualToString:NSAccessibilityPressAction]);
334 343
335 if (data.HasAction(entry.first)) 344 if (data.HasAction(entry.first))
336 [axActions addObject:entry.second]; 345 [axActions addObject:entry.second];
337 } 346 }
338 347
339 return axActions.autorelease(); 348 return axActions.autorelease();
340 } 349 }
341 350
342 - (void)accessibilityPerformAction:(NSString*)action { 351 - (void)accessibilityPerformAction:(NSString*)action {
343 DCHECK([[self accessibilityActionNames] containsObject:action]); 352 // Actions are performed asynchronously, so it's always possible for an object
353 // to change its mind after previously reporting an action as available.
354 if (![[self accessibilityActionNames] containsObject:action])
355 return;
356
344 ui::AXActionData data; 357 ui::AXActionData data;
345 for (const ActionMap::value_type& entry : GetActionMap()) { 358 for (const ActionMap::value_type& entry : GetActionMap()) {
346 if ([action isEqualToString:entry.second]) { 359 if ([action isEqualToString:entry.second]) {
347 data.action = entry.first; 360 data.action = entry.first;
348 break; 361 break;
349 } 362 }
350 } 363 }
351 364
352 // Note ui::AX_ACTIONs which are just overwriting an accessibility attribute 365 // Note ui::AX_ACTIONs which are just overwriting an accessibility attribute
353 // are already implemented in -accessibilitySetValue:forAttribute:, so ignore 366 // are already implemented in -accessibilitySetValue:forAttribute:, so ignore
354 // those here. 367 // those here.
355 368
356 if (data.action != ui::AX_ACTION_NONE) 369 if (data.action != ui::AX_ACTION_NONE)
357 node_->GetDelegate()->AccessibilityPerformAction(data); 370 node_->GetDelegate()->AccessibilityPerformAction(data);
358 } 371 }
359 372
360 - (NSArray*)accessibilityAttributeNames { 373 - (NSArray*)accessibilityAttributeNames {
374 if (!node_)
375 return @[];
376
361 // These attributes are required on all accessibility objects. 377 // These attributes are required on all accessibility objects.
362 NSArray* const kAllRoleAttributes = @[ 378 NSArray* const kAllRoleAttributes = @[
363 NSAccessibilityChildrenAttribute, 379 NSAccessibilityChildrenAttribute,
364 NSAccessibilityParentAttribute, 380 NSAccessibilityParentAttribute,
365 NSAccessibilityPositionAttribute, 381 NSAccessibilityPositionAttribute,
366 NSAccessibilityRoleAttribute, 382 NSAccessibilityRoleAttribute,
367 NSAccessibilitySizeAttribute, 383 NSAccessibilitySizeAttribute,
368 NSAccessibilitySubroleAttribute, 384 NSAccessibilitySubroleAttribute,
369 385
370 // Title is required for most elements. Cocoa asks for the value even if it 386 // Title is required for most elements. Cocoa asks for the value even if it
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 [axAttributes addObjectsFromArray:kValueAttributes]; 435 [axAttributes addObjectsFromArray:kValueAttributes];
420 break; 436 break;
421 // TODO(tapted): Add additional attributes based on role. 437 // TODO(tapted): Add additional attributes based on role.
422 default: 438 default:
423 break; 439 break;
424 } 440 }
425 return axAttributes.autorelease(); 441 return axAttributes.autorelease();
426 } 442 }
427 443
428 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName { 444 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName {
445 if (!node_)
446 return NO;
447
429 if (node_->GetData().HasState(ui::AX_STATE_DISABLED)) 448 if (node_->GetData().HasState(ui::AX_STATE_DISABLED))
430 return NO; 449 return NO;
431 450
432 // Allow certain attributes to be written via an accessibility client. A 451 // Allow certain attributes to be written via an accessibility client. A
433 // writable attribute will only appear as such if the accessibility element 452 // writable attribute will only appear as such if the accessibility element
434 // has a value set for that attribute. 453 // has a value set for that attribute.
435 if ([attributeName 454 if ([attributeName
436 isEqualToString:NSAccessibilitySelectedChildrenAttribute] || 455 isEqualToString:NSAccessibilitySelectedChildrenAttribute] ||
437 [attributeName 456 [attributeName
438 isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) { 457 isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) {
(...skipping 17 matching lines...) Expand all
456 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { 475 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) {
457 return node_->GetData().HasState(ui::AX_STATE_FOCUSABLE); 476 return node_->GetData().HasState(ui::AX_STATE_FOCUSABLE);
458 } 477 }
459 478
460 // TODO(patricialor): Add callbacks for updating the above attributes except 479 // TODO(patricialor): Add callbacks for updating the above attributes except
461 // NSAccessibilityValueAttribute and return YES. 480 // NSAccessibilityValueAttribute and return YES.
462 return NO; 481 return NO;
463 } 482 }
464 483
465 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { 484 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
485 if (!node_)
486 return;
487
466 ui::AXActionData data; 488 ui::AXActionData data;
467 489
468 // Check for attributes first. Only the |data.action| should be set here - any 490 // Check for attributes first. Only the |data.action| should be set here - any
469 // type-specific information, if needed, should be set below. 491 // type-specific information, if needed, should be set below.
470 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { 492 if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
471 data.action = node_->GetData().role == ui::AX_ROLE_TAB 493 data.action = node_->GetData().role == ui::AX_ROLE_TAB
472 ? ui::AX_ACTION_SET_SELECTION 494 ? ui::AX_ACTION_SET_SELECTION
473 : ui::AX_ACTION_SET_VALUE; 495 : ui::AX_ACTION_SET_VALUE;
474 } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) { 496 } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
475 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; 497 data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT;
(...skipping 18 matching lines...) Expand all
494 } 516 }
495 517
496 if (data.action != ui::AX_ACTION_NONE) 518 if (data.action != ui::AX_ACTION_NONE)
497 node_->GetDelegate()->AccessibilityPerformAction(data); 519 node_->GetDelegate()->AccessibilityPerformAction(data);
498 520
499 // TODO(patricialor): Plumb through all the other writable attributes as 521 // TODO(patricialor): Plumb through all the other writable attributes as
500 // specified in accessibilityIsAttributeSettable. 522 // specified in accessibilityIsAttributeSettable.
501 } 523 }
502 524
503 - (id)accessibilityAttributeValue:(NSString*)attribute { 525 - (id)accessibilityAttributeValue:(NSString*)attribute {
526 if (!node_)
527 return nil; // Return nil when detached. Even for AXRole.
528
504 SEL selector = NSSelectorFromString(attribute); 529 SEL selector = NSSelectorFromString(attribute);
505 if ([self respondsToSelector:selector]) 530 if ([self respondsToSelector:selector])
506 return [self performSelector:selector]; 531 return [self performSelector:selector];
507 return nil; 532 return nil;
508 } 533 }
509 534
510 // NSAccessibility attributes. Order them according to 535 // NSAccessibility attributes. Order them according to
511 // NSAccessibilityConstants.h, or see https://crbug.com/678898. 536 // NSAccessibilityConstants.h, or see https://crbug.com/678898.
512 537
513 - (NSString*)AXRole { 538 - (NSString*)AXRole {
514 if (!node_) 539 if (!node_)
515 return nil; 540 return nil;
541
516 return [[self class] nativeRoleFromAXRole:node_->GetData().role]; 542 return [[self class] nativeRoleFromAXRole:node_->GetData().role];
517 } 543 }
518 544
519 - (NSString*)AXRoleDescription { 545 - (NSString*)AXRoleDescription {
520 switch (node_->GetData().role) { 546 switch (node_->GetData().role) {
521 case ui::AX_ROLE_TAB: 547 case ui::AX_ROLE_TAB:
522 // There is no NSAccessibilityTabRole or similar (AXRadioButton is used 548 // There is no NSAccessibilityTabRole or similar (AXRadioButton is used
523 // instead). Do the same as NSTabView and put "tab" in the description. 549 // instead). Do the same as NSTabView and put "tab" in the description.
524 return [l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB_ROLE_DESCRIPTION) 550 return [l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB_ROLE_DESCRIPTION)
525 lowercaseString]; 551 lowercaseString];
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
570 } 596 }
571 597
572 - (id)AXParent { 598 - (id)AXParent {
573 if (!node_) 599 if (!node_)
574 return nil; 600 return nil;
575 return NSAccessibilityUnignoredAncestor(node_->GetParent()); 601 return NSAccessibilityUnignoredAncestor(node_->GetParent());
576 } 602 }
577 603
578 - (NSArray*)AXChildren { 604 - (NSArray*)AXChildren {
579 if (!node_) 605 if (!node_)
580 return nil; 606 return @[];
607
581 int count = node_->GetChildCount(); 608 int count = node_->GetChildCount();
582 NSMutableArray* children = [NSMutableArray arrayWithCapacity:count]; 609 NSMutableArray* children = [NSMutableArray arrayWithCapacity:count];
583 for (int i = 0; i < count; ++i) 610 for (int i = 0; i < count; ++i)
584 [children addObject:node_->ChildAtIndex(i)]; 611 [children addObject:node_->ChildAtIndex(i)];
585 return NSAccessibilityUnignoredChildren(children); 612 return NSAccessibilityUnignoredChildren(children);
586 } 613 }
587 614
588 - (id)AXWindow { 615 - (id)AXWindow {
589 return node_->GetDelegate()->GetTopLevelWidget(); 616 return node_->GetDelegate()->GetTopLevelWidget();
590 } 617 }
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
700 } 727 }
701 NotifyMacEvent(native_node_, event_type); 728 NotifyMacEvent(native_node_, event_type);
702 } 729 }
703 730
704 int AXPlatformNodeMac::GetIndexInParent() { 731 int AXPlatformNodeMac::GetIndexInParent() {
705 // TODO(dmazzoni): implement this. http://crbug.com/396137 732 // TODO(dmazzoni): implement this. http://crbug.com/396137
706 return -1; 733 return -1;
707 } 734 }
708 735
709 } // namespace ui 736 } // 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