0

Convert /ui/accessibility to use ARC

See https://chromium.googlesource.com/chromium/src/+/main/docs/mac/arc.md
for information about this conversion.

Bug: 1280317
Change-Id: Ib21037a39e5309515205171372ce17df831dd545
Include-Ci-Only-Tests: true
Cq-Include-Trybots: luci.chrome.try:mac-chrome
Validate-Test-Flakiness: skip
AX-Relnotes: n/a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4577142
Reviewed-by: Leonard Grey <lgrey@chromium.org>
Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
Reviewed-by: David Tseng <dtseng@chromium.org>
Auto-Submit: Avi Drissman <avi@chromium.org>
Commit-Queue: Avi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1152257}
This commit is contained in:
Avi Drissman
2023-06-02 00:17:12 +00:00
committed by Chromium LUCI CQ
parent 4756d043c4
commit c41a68c1d0
28 changed files with 647 additions and 514 deletions

@@ -42,14 +42,6 @@ struct CONTENT_EXPORT AXTextEdit {
// Returns true if the given object is an NSRange instance.
bool IsNSRange(id value);
// Returns an AXTextMarker representing the given position in the tree.
id AXTextMarkerFrom(const BrowserAccessibilityCocoa* anchor,
int offset,
ax::mojom::TextAffinity affinity);
// Returns an AXTextMarkerRange that spans the given AXTextMarkers.
id AXTextMarkerRangeFrom(id anchor_text_marker, id focus_text_marker);
} // namespace content
// BrowserAccessibilityCocoa is a cocoa wrapper around the BrowserAccessibility

@@ -7,6 +7,7 @@
#import "content/browser/accessibility/browser_accessibility_mac.h"
#include "base/debug/stack_trace.h"
#include "base/memory/scoped_policy.h"
#import "base/task/single_thread_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
@@ -69,7 +70,7 @@ void BrowserAccessibilityMac::ReplaceNativeObject() {
// because we need to retrieve some information from the old wrapper in order
// to add it to the new one, e.g. its list of children.
base::scoped_nsobject<AXPlatformNodeCocoa> old_native_obj(
platform_node_->ReleaseNativeWrapper());
platform_node_->ReleaseNativeWrapper(), base::scoped_policy::RETAIN);
// We should have never called this method if a native wrapper has not been
// created, but keep a null check just in case.

@@ -611,6 +611,10 @@ source_set("browser_sources") {
sources += [ "context_factory.h" ]
}
if (is_apple) {
configs += [ "//build/config/compiler:enable_arc" ]
}
if (is_mac) {
sources += [
"ax_inspect_factory_mac.mm",

@@ -9,6 +9,10 @@
#include "ui/accessibility/platform/inspect/ax_event_recorder_mac.h"
#include "ui/accessibility/platform/inspect/ax_tree_formatter_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace content {
// static
@@ -22,8 +26,8 @@ std::unique_ptr<ui::AXEventRecorder> AXInspectFactory::CreatePlatformRecorder(
BrowserAccessibilityManager*,
base::ProcessId pid,
const ui::AXTreeSelector& selector) {
return AXInspectFactory::CreateRecorder(ui::AXApiType::kMac, nullptr, pid,
selector);
return AXInspectFactory::CreateRecorder(ui::AXApiType::kMac,
/*manager=*/nullptr, pid, selector);
}
// static

@@ -6,6 +6,10 @@
#include "base/observer_list.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace content {
ScopedNotifyNativeEventProcessorObserver::
@@ -15,13 +19,13 @@ ScopedNotifyNativeEventProcessorObserver::
NSEvent* event)
: observer_list_(observer_list), event_(event) {
for (auto& observer : *observer_list_)
observer.WillRunNativeEvent(event_);
observer.WillRunNativeEvent((__bridge const void*)event_);
}
ScopedNotifyNativeEventProcessorObserver::
~ScopedNotifyNativeEventProcessorObserver() {
for (auto& obs : *observer_list_) {
obs.DidRunNativeEvent(event_);
obs.DidRunNativeEvent((__bridge const void*)event_);
}
}

@@ -243,6 +243,8 @@ component("platform") {
"inspect/ax_tree_indexer_mac.h",
]
configs += [ "//build/config/compiler:enable_arc" ]
frameworks = [
"AppKit.framework",
"Foundation.framework",

@@ -135,7 +135,7 @@ struct COMPONENT_EXPORT(AX_PLATFORM) AXTextStateChangeIntent final {
AXTextSelection selection);
// Constructs an editing intent.
AXTextStateChangeIntent(AXTextEditType edit);
explicit AXTextStateChangeIntent(AXTextEditType edit);
AXTextStateChangeIntent(const AXTextStateChangeIntent& intent);

@@ -7,6 +7,10 @@
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_event_intent.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace ui {
// static
@@ -107,7 +111,7 @@ AXTextSelection AXTextSelection::FromDirectionAndGranularity(
break;
}
return AXTextSelection(direction, granularity, /* focus_change */ false);
return AXTextSelection(direction, granularity, /*focus_change=*/false);
}
AXTextSelection::AXTextSelection() = default;
@@ -133,7 +137,7 @@ AXTextStateChangeIntent::DefaultFocusTextStateChangeIntent() {
AXTextStateChangeType::kSelectionMove,
AXTextSelection(AXTextSelectionDirection::kDiscontiguous,
AXTextSelectionGranularity::kUnknown,
/* focus_change */ true));
/*focus_change=*/true));
}
// static
@@ -143,7 +147,7 @@ AXTextStateChangeIntent::DefaultSelectionChangeIntent() {
AXTextStateChangeType::kSelectionMove,
AXTextSelection(AXTextSelectionDirection::kDiscontiguous,
AXTextSelectionGranularity::kUnknown,
/* focus_change */ false));
/*focus_change=*/false));
}
AXTextStateChangeIntent::AXTextStateChangeIntent() = default;

@@ -5,31 +5,24 @@
#ifndef UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_COCOA_H_
#define UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_COCOA_H_
#include <memory>
#import <Accessibility/Accessibility.h>
#import <Cocoa/Cocoa.h>
#include "base/component_export.h"
#include "base/mac/scoped_nsobject.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
namespace ui {
class AXPlatformNodeBase;
class AXPlatformNodeDelegate;
struct AXAnnouncementSpec {
AXAnnouncementSpec();
~AXAnnouncementSpec();
base::scoped_nsobject<NSString> announcement;
base::scoped_nsobject<NSWindow> window;
bool is_polite;
};
} // namespace ui
COMPONENT_EXPORT(AX_PLATFORM)
@interface AXAnnouncementSpec : NSObject
@property(nonatomic, readonly) NSString* announcement;
@property(nonatomic, readonly) NSWindow* window;
@property(nonatomic, readonly) BOOL polite;
@end
COMPONENT_EXPORT(AX_PLATFORM)
@interface AXPlatformNodeCocoa
: NSAccessibilityElement <NSAccessibility, AXCustomContentProvider>
@@ -75,17 +68,15 @@ COMPONENT_EXPORT(AX_PLATFORM)
@property(nonatomic, readonly) ui::AXPlatformNodeDelegate* nodeDelegate;
// Returns the data necessary to queue an NSAccessibility announcement if
// |eventType| should be announced, or nullptr otherwise.
- (std::unique_ptr<ui::AXAnnouncementSpec>)announcementForEvent:
(ax::mojom::Event)eventType;
// |eventType| should be announced, or nil otherwise.
- (AXAnnouncementSpec*)announcementForEvent:(ax::mojom::Event)eventType;
// Ask the system to announce |announcementText|. This is debounced to happen
// at most every |kLiveRegionDebounceMillis| per node, with only the most
// recent announcement text read, to account for situations with multiple
// notifications happening one after another (for example, results for
// find-in-page updating rapidly as they come in from subframes).
- (void)scheduleLiveRegionAnnouncement:
(std::unique_ptr<ui::AXAnnouncementSpec>)announcement;
- (void)scheduleLiveRegionAnnouncement:(AXAnnouncementSpec*)announcement;
- (id)AXWindow;

@@ -5,6 +5,7 @@
#import "ui/accessibility/platform/ax_platform_node_cocoa.h"
#import <Cocoa/Cocoa.h>
#include <Foundation/Foundation.h>
#include "base/logging.h"
#include "base/mac/foundation_util.h"
@@ -27,19 +28,32 @@
#import "ui/gfx/mac/coordinate_conversion.h"
#include "ui/strings/grit/ax_strings.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using AXRange = ui::AXPlatformNodeDelegate::AXRange;
namespace ui {
@interface AXAnnouncementSpec ()
AXAnnouncementSpec::AXAnnouncementSpec() = default;
AXAnnouncementSpec::~AXAnnouncementSpec() = default;
@property(nonatomic, strong) NSString* announcement;
@property(nonatomic, strong) NSWindow* window;
@property(nonatomic, assign) BOOL polite;
} // namespace ui
@end
@implementation AXAnnouncementSpec
@synthesize announcement = _announcement;
@synthesize window = _window;
@synthesize polite = _polite;
@end
namespace {
// Same length as web content/WebKit.
static int kLiveRegionDebounceMillis = 20;
int kLiveRegionDebounceMillis = 20;
using RoleMap = std::map<ax::mojom::Role, NSString*>;
using EventMap = std::map<ax::mojom::Event, NSString*>;
@@ -236,7 +250,7 @@ void CollectAncestorRoles(
@implementation AXPlatformNodeCocoa {
// This field is not a raw_ptr<> because it requires @property rewrite.
RAW_PTR_EXCLUSION ui::AXPlatformNodeBase* _node; // Weak. Retains us.
std::unique_ptr<ui::AXAnnouncementSpec> _pendingAnnouncement;
AXAnnouncementSpec* __strong _pendingAnnouncement;
}
@synthesize node = _node;
@@ -329,9 +343,9 @@ void CollectAncestorRoles(
break;
}
// On Mac OS X, the accessible name of an object is exposed as its
// title if it comes from visible text, and as its description
// otherwise, but never both.
// On macOS, the accessible name of an object is exposed as its title if it
// comes from visible text, and as its description otherwise, but never both.
//
// Note: a placeholder is often visible text, but since it aids in data entry
// it is similar to accessibilityValue, and thus cannot be exposed either in
// accessibilityTitle or in accessibilityLabel.
@@ -785,7 +799,7 @@ void CollectAncestorRoles(
// Add annotation information
int leafTextLength = leafTextRange.GetText().length();
DCHECK_LE(static_cast<unsigned long>(anchorStartOffset + leafTextLength),
[attributedString length]);
attributedString.length);
NSRange leafRange = NSMakeRange(anchorStartOffset, leafTextLength);
CollectAncestorRoles(*anchor, ancestor_roles);
@@ -821,16 +835,15 @@ void CollectAncestorRoles(
// TODO(crbug.com/958811): Implement NSAccessibilityVisibleNameKey.
if (text_attrs.font_size != ui::AXTextAttributes::kUnsetValue) {
[fontAttributes setValue:@(text_attrs.font_size)
forKey:NSAccessibilityFontSizeKey];
fontAttributes[NSAccessibilityFontSizeKey] = @(text_attrs.font_size);
}
if (text_attrs.HasTextStyle(ax::mojom::TextStyle::kBold)) {
[fontAttributes setValue:@YES forKey:@"AXFontBold"];
fontAttributes[@"AXFontBold"] = @YES;
}
if (text_attrs.HasTextStyle(ax::mojom::TextStyle::kItalic)) {
[fontAttributes setValue:@YES forKey:@"AXFontItalic"];
fontAttributes[@"AXFontItalic"] = @YES;
}
[attributedString addAttribute:NSAccessibilityFontTextAttribute
@@ -913,24 +926,24 @@ void CollectAncestorRoles(
return base::SysUTF8ToNSString(_node->GetName());
}
- (std::unique_ptr<ui::AXAnnouncementSpec>)announcementForEvent:
(ax::mojom::Event)eventType {
- (AXAnnouncementSpec*)announcementForEvent:(ax::mojom::Event)eventType {
// Only alerts and live region changes should be announced.
DCHECK(eventType == ax::mojom::Event::kAlert ||
eventType == ax::mojom::Event::kLiveRegionChanged);
std::string liveStatus =
_node->GetStringAttribute(ax::mojom::StringAttribute::kLiveStatus);
// If live status is explicitly set to off, don't announce.
if (liveStatus == "off")
return nullptr;
if (liveStatus == "off") {
return nil;
}
NSString* name = [self getName];
NSString* announcementText =
[name length] > 0
? name
: base::SysUTF16ToNSString(_node->GetTextContentUTF16());
if ([announcementText length] == 0)
return nullptr;
name.length > 0 ? name
: base::SysUTF16ToNSString(_node->GetTextContentUTF16());
if (announcementText.length == 0) {
return nil;
}
const std::string& description =
_node->GetStringAttribute(ax::mojom::StringAttribute::kDescription);
@@ -942,34 +955,31 @@ void CollectAncestorRoles(
base::SysUTF8ToNSString(description)];
}
auto announcement = std::make_unique<ui::AXAnnouncementSpec>();
announcement->announcement =
base::scoped_nsobject<NSString>([announcementText retain]);
announcement->window =
base::scoped_nsobject<NSWindow>([[self AXWindow] retain]);
announcement->is_polite = liveStatus != "assertive";
return announcement;
AXAnnouncementSpec* spec = [[AXAnnouncementSpec alloc] init];
spec.announcement = announcementText;
spec.window = [self AXWindow];
spec.polite = liveStatus != "assertive";
return spec;
}
- (void)scheduleLiveRegionAnnouncement:
(std::unique_ptr<ui::AXAnnouncementSpec>)announcement {
- (void)scheduleLiveRegionAnnouncement:(AXAnnouncementSpec*)announcement {
if (_pendingAnnouncement) {
// An announcement is already in flight, so just reset the contents. This is
// threadsafe because the dispatch is on the main queue.
_pendingAnnouncement = std::move(announcement);
_pendingAnnouncement = announcement;
return;
}
_pendingAnnouncement = std::move(announcement);
_pendingAnnouncement = announcement;
dispatch_after(
kLiveRegionDebounceMillis * NSEC_PER_MSEC, dispatch_get_main_queue(), ^{
if (!_pendingAnnouncement) {
if (!self->_pendingAnnouncement) {
return;
}
PostAnnouncementNotification(_pendingAnnouncement->announcement,
_pendingAnnouncement->window,
_pendingAnnouncement->is_polite);
_pendingAnnouncement.reset();
PostAnnouncementNotification(self->_pendingAnnouncement.announcement,
self->_pendingAnnouncement.window,
self->_pendingAnnouncement.polite);
self->_pendingAnnouncement = nil;
});
}
@@ -983,8 +993,9 @@ void CollectAncestorRoles(
}
- (id)accessibilityHitTest:(NSPoint)point {
if (!NSPointInRect(point, [self boundsInScreen]))
if (!NSPointInRect(point, self.boundsInScreen)) {
return nil;
}
for (id child in [[self AXChildren] reverseObjectEnumerator]) {
if (!NSPointInRect(point, [child accessibilityFrame]))
@@ -1012,8 +1023,7 @@ void CollectAncestorRoles(
if (!_node)
return @[];
base::scoped_nsobject<NSMutableArray> axActions(
[[NSMutableArray alloc] init]);
NSMutableArray* axActions = [NSMutableArray array];
const ActionList& action_list = GetActionList();
// VoiceOver expects the "press" action to be first. Note that some roles
@@ -1027,7 +1037,7 @@ void CollectAncestorRoles(
if (AlsoUseShowMenuActionForDefaultAction(*_node))
[axActions addObject:NSAccessibilityShowMenuAction];
return axActions.autorelease();
return axActions;
}
- (void)accessibilityPerformAction:(NSString*)action {
@@ -1092,10 +1102,9 @@ void CollectAncestorRoles(
];
// Required for all text, including protected textfields.
NSString* const kTextAttributes = NSAccessibilityPlaceholderValueAttribute;
base::scoped_nsobject<NSMutableArray> axAttributes(
[[NSMutableArray alloc] init]);
[axAttributes addObjectsFromArray:kAllRoleAttributes];
NSMutableArray* axAttributes =
[NSMutableArray arrayWithArray:kAllRoleAttributes];
ax::mojom::Role role = _node->GetRole();
switch (role) {
case ax::mojom::Role::kTextField:
@@ -1292,7 +1301,7 @@ void CollectAncestorRoles(
if ([self titleUIElement])
[axAttributes addObject:NSAccessibilityTitleUIElementAttribute];
return axAttributes.autorelease();
return axAttributes;
}
- (NSArray*)accessibilityParameterizedAttributeNames {
@@ -1342,8 +1351,11 @@ void CollectAncestorRoles(
return nil; // Return nil when detached. Even for ax::mojom::Role.
SEL selector = NSSelectorFromString(attribute);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
if ([self respondsToSelector:selector])
return [self performSelector:selector];
#pragma clang diagnostic pop
return nil;
}
@@ -1353,8 +1365,11 @@ void CollectAncestorRoles(
return nil;
SEL selector = NSSelectorFromString([attribute stringByAppendingString:@":"]);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
if ([self respondsToSelector:selector])
return [self performSelector:selector withObject:parameter];
#pragma clang diagnostic pop
return nil;
}
@@ -1524,7 +1539,7 @@ void CollectAncestorRoles(
if (![self instanceActive])
return nil;
NSMutableArray* elements = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray* elements = [NSMutableArray array];
for (ui::AXNodeID id :
_node->GetIntListAttribute(ax::mojom::IntListAttribute::kDetailsIds)) {
AXPlatformNodeCocoa* node = [self fromNodeID:id];
@@ -1532,14 +1547,14 @@ void CollectAncestorRoles(
[elements addObject:node];
}
return [elements count] ? elements : nil;
return elements.count ? elements : nil;
}
- (NSArray*)AXDOMClassList {
if (![self instanceActive])
return nil;
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray* ret = [NSMutableArray array];
std::string classes;
if (_node->GetStringAttribute(ax::mojom::StringAttribute::kClassName,
@@ -1673,9 +1688,7 @@ void CollectAncestorRoles(
if (!container)
return nil;
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
[ret addObject:container->GetNativeViewAccessible()];
return ret;
return @[ container->GetNativeViewAccessible() ];
}
- (NSString*)AXPopupValue {
@@ -1877,7 +1890,7 @@ void CollectAncestorRoles(
const auto checkedState = static_cast<ax::mojom::CheckedState>(
_node->GetIntAttribute(ax::mojom::IntAttribute::kCheckedState));
if (checkedState == ax::mojom::CheckedState::kTrue) {
return @"\xE2\x9C\x93"; // UTF-8 for unicode 0x2713, "check mark"
return @"\u2713"; // "check mark"
}
return @"";
@@ -2009,8 +2022,8 @@ void CollectAncestorRoles(
// We potentially need to add text attributes to the whole text content
// because a spelling mistake might start or end outside the given range.
NSMutableAttributedString* attributedTextContent =
[[[NSMutableAttributedString alloc]
initWithString:base::SysUTF16ToNSString(textContent)] autorelease];
[[NSMutableAttributedString alloc]
initWithString:base::SysUTF16ToNSString(textContent)];
if (!_node->IsText()) {
AXRange axRange(_node->GetDelegate()->CreateTextPositionAt(0),
_node->GetDelegate()->CreateTextPositionAt(
@@ -2027,11 +2040,12 @@ void CollectAncestorRoles(
return nil;
NSString* text = base::SysUTF16ToNSString(axRange.GetText());
if ([text length] == 0)
if (text.length == 0) {
return nil;
}
NSMutableAttributedString* attributedText =
[[[NSMutableAttributedString alloc] initWithString:text] autorelease];
[[NSMutableAttributedString alloc] initWithString:text];
// Currently, we only decorate the attributed string with misspelling
// and annotation information.
[self addTextAnnotationsIn:&axRange to:attributedText];
@@ -2094,7 +2108,7 @@ void CollectAncestorRoles(
if (![self instanceActive])
return nil;
// Mac OS X wants static text exposed in AXValue.
// macOS wants static text exposed in AXValue.
if (ui::IsNameExposedInAXValueForRole([self internalRole]))
return @"";
@@ -2345,7 +2359,7 @@ void CollectAncestorRoles(
NSArray* rows = [self accessibilityRows];
// accessibilityRows returns an empty array unless instanceActive does,
// not exist, so we do not need to check if rows is nil at this time.
NSMutableArray* selectedRows = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray* selectedRows = [NSMutableArray array];
for (id row in rows) {
if ([[row accessibilitySelected] boolValue]) {
[selectedRows addObject:row];
@@ -2362,7 +2376,7 @@ void CollectAncestorRoles(
ui::AXPlatformNodeDelegate* delegate = _node->GetDelegate();
DCHECK(delegate);
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray* ret = [NSMutableArray array];
// If this is a table, return all column headers.
ax::mojom::Role role = _node->GetRole();
@@ -2522,30 +2536,28 @@ void CollectAncestorRoles(
if (!_node)
return 0;
return
[[self AXLineForIndex:[NSNumber numberWithInteger:index]] integerValue];
return [[self AXLineForIndex:@(index)] integerValue];
}
- (NSRange)accessibilityRangeForIndex:(NSInteger)index {
if (!_node)
return NSMakeRange(0, 0);
return [[self AXRangeForIndex:[NSNumber numberWithInteger:index]] rangeValue];
return [[self AXRangeForIndex:@(index)] rangeValue];
}
- (NSRange)accessibilityStyleRangeForIndex:(NSInteger)index {
if (!_node)
return NSMakeRange(0, 0);
return [[self AXStyleRangeForIndex:[NSNumber numberWithInteger:index]]
rangeValue];
return [[self AXStyleRangeForIndex:@(index)] rangeValue];
}
- (NSRange)accessibilityRangeForLine:(NSInteger)line {
if (!_node)
return NSMakeRange(0, 0);
return [[self AXRangeForLine:[NSNumber numberWithInteger:line]] rangeValue];
return [[self AXRangeForLine:@(line)] rangeValue];
}
- (NSRange)accessibilityRangeForPosition:(NSPoint)point {
@@ -2746,30 +2758,27 @@ void CollectAncestorRoles(
return nil;
}
static NSDictionary* createMathSubSupScriptsPair(
AXPlatformNodeCocoa* subscript,
AXPlatformNodeCocoa* superscript) {
AXPlatformNodeCocoa* nodes[2];
NSString* keys[2];
NSUInteger count = 0;
namespace {
NSDictionary* CreateMathSubSupScriptsPair(AXPlatformNodeCocoa* subscript,
AXPlatformNodeCocoa* superscript) {
NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
if (subscript) {
nodes[count] = subscript;
keys[count] = NSAccessibilityMathSubscriptAttribute;
count++;
dictionary[NSAccessibilityMathSubscriptAttribute] = subscript;
}
if (superscript) {
nodes[count] = superscript;
keys[count] = NSAccessibilityMathSuperscriptAttribute;
count++;
dictionary[NSAccessibilityMathSuperscriptAttribute] = superscript;
}
return [[NSDictionary alloc] initWithObjects:nodes forKeys:keys count:count];
return dictionary;
}
} // namespace
- (NSArray*)AXMathPostscripts {
if (![self instanceActive] ||
_node->GetRole() != ax::mojom::Role::kMathMLMultiscripts)
return nil;
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray* ret = [NSMutableArray array];
bool foundBaseElement = false;
AXPlatformNodeCocoa* subscript = nullptr;
for (AXPlatformNodeCocoa* child in [self AXChildren]) {
@@ -2784,7 +2793,7 @@ static NSDictionary* createMathSubSupScriptsPair(
continue;
}
AXPlatformNodeCocoa* superscript = child;
[ret addObject:createMathSubSupScriptsPair(subscript, superscript)];
[ret addObject:CreateMathSubSupScriptsPair(subscript, superscript)];
subscript = nullptr;
}
return [ret count] ? ret : nil;
@@ -2794,7 +2803,7 @@ static NSDictionary* createMathSubSupScriptsPair(
if (![self instanceActive] ||
_node->GetRole() != ax::mojom::Role::kMathMLMultiscripts)
return nil;
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray* ret = [NSMutableArray array];
bool foundPrescriptDelimiter = false;
AXPlatformNodeCocoa* subscript = nullptr;
for (AXPlatformNodeCocoa* child in [self AXChildren]) {
@@ -2808,7 +2817,7 @@ static NSDictionary* createMathSubSupScriptsPair(
continue;
}
AXPlatformNodeCocoa* superscript = child;
[ret addObject:createMathSubSupScriptsPair(subscript, superscript)];
[ret addObject:CreateMathSubSupScriptsPair(subscript, superscript)];
subscript = nullptr;
}
return [ret count] ? ret : nil;

@@ -7,15 +7,17 @@
#import <Cocoa/Cocoa.h>
#include <memory>
#include "base/component_export.h"
#include "base/mac/scoped_nsobject.h"
#include "ui/accessibility/platform/ax_platform_node_base.h"
@class AXPlatformNodeCocoa;
namespace ui {
class AXPlatformNodeMac : public AXPlatformNodeBase {
class COMPONENT_EXPORT(AX_PLATFORM) AXPlatformNodeMac
: public AXPlatformNodeBase {
public:
~AXPlatformNodeMac() override;
AXPlatformNodeMac(const AXPlatformNodeMac&) = delete;
@@ -30,15 +32,9 @@ class AXPlatformNodeMac : public AXPlatformNodeBase {
void Destroy() override;
bool IsPlatformCheckable() const override;
AXPlatformNodeCocoa* GetNativeWrapper() const { return native_node_.get(); }
base::scoped_nsobject<AXPlatformNodeCocoa> ReleaseNativeWrapper() {
return std::move(native_node_);
}
void SetNativeWrapper(AXPlatformNodeCocoa* native_node) {
return native_node_.reset(native_node);
}
AXPlatformNodeCocoa* GetNativeWrapper() const;
AXPlatformNodeCocoa* ReleaseNativeWrapper();
void SetNativeWrapper(AXPlatformNodeCocoa* native_node);
protected:
AXPlatformNodeMac();
@@ -48,10 +44,11 @@ class AXPlatformNodeMac : public AXPlatformNodeBase {
PlatformAttributeList* attributes) override;
private:
base::scoped_nsobject<AXPlatformNodeCocoa> native_node_;
friend AXPlatformNode* AXPlatformNode::Create(
AXPlatformNodeDelegate* delegate);
struct ObjCStorage;
std::unique_ptr<ObjCStorage> objc_storage_;
};
// Convenience function to determine whether an internal object role should

@@ -7,6 +7,10 @@
#include "base/strings/sys_string_conversions.h"
#include "ui/accessibility/platform/ax_platform_node_cocoa.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
using RoleMap = std::map<ax::mojom::Role, NSString*>;
@@ -59,15 +63,19 @@ AXPlatformNode* AXPlatformNode::FromNativeViewAccessible(
return nullptr;
}
AXPlatformNodeMac::AXPlatformNodeMac() = default;
struct AXPlatformNodeMac::ObjCStorage {
AXPlatformNodeCocoa* __strong native_node;
};
AXPlatformNodeMac::AXPlatformNodeMac()
: objc_storage_(std::make_unique<ObjCStorage>()) {}
AXPlatformNodeMac::~AXPlatformNodeMac() = default;
void AXPlatformNodeMac::Destroy() {
if (native_node_) {
[native_node_ detach];
// Also, nullify smart pointer to make accidental use-after-free impossible.
native_node_.reset();
if (objc_storage_->native_node) {
[objc_storage_->native_node detach];
// Also, clear the pointer to make accidental use-after-free impossible.
objc_storage_->native_node = nil;
}
AXPlatformNodeBase::Destroy();
}
@@ -83,10 +91,26 @@ bool AXPlatformNodeMac::IsPlatformCheckable() const {
return AXPlatformNodeBase::IsPlatformCheckable();
}
AXPlatformNodeCocoa* AXPlatformNodeMac::GetNativeWrapper() const {
return objc_storage_->native_node;
}
AXPlatformNodeCocoa* AXPlatformNodeMac::ReleaseNativeWrapper() {
AXPlatformNodeCocoa* native_node = objc_storage_->native_node;
objc_storage_->native_node = nil;
return native_node;
}
void AXPlatformNodeMac::SetNativeWrapper(AXPlatformNodeCocoa* native_node) {
objc_storage_->native_node = native_node;
}
gfx::NativeViewAccessible AXPlatformNodeMac::GetNativeViewAccessible() {
if (!native_node_)
native_node_.reset([[AXPlatformNodeCocoa alloc] initWithNode:this]);
return native_node_.get();
if (!objc_storage_->native_node) {
objc_storage_->native_node =
[[AXPlatformNodeCocoa alloc] initWithNode:this];
}
return objc_storage_->native_node;
}
void AXPlatformNodeMac::NotifyAccessibilityEvent(ax::mojom::Event event_type) {
@@ -98,8 +122,9 @@ void AXPlatformNodeMac::NotifyAccessibilityEvent(ax::mojom::Event event_type) {
// regular NSAccessibility notification system.
if (event_type == ax::mojom::Event::kAlert ||
event_type == ax::mojom::Event::kLiveRegionChanged) {
if (auto announcement = [native_node_ announcementForEvent:event_type]) {
[native_node_ scheduleLiveRegionAnnouncement:std::move(announcement)];
if (AXAnnouncementSpec* announcement =
[objc_storage_->native_node announcementForEvent:event_type]) {
[objc_storage_->native_node scheduleLiveRegionAnnouncement:announcement];
}
return;
}
@@ -107,14 +132,14 @@ void AXPlatformNodeMac::NotifyAccessibilityEvent(ax::mojom::Event event_type) {
ax::mojom::Role role = GetRole();
if (ui::IsMenuItem(role)) {
// On Mac, map menu item selection to a focus event.
NotifyMacEvent(native_node_, ax::mojom::Event::kFocus);
NotifyMacEvent(objc_storage_->native_node, ax::mojom::Event::kFocus);
return;
} else if (ui::IsListItem(role)) {
if (const AXPlatformNodeBase* container = GetSelectionContainer()) {
if (container->GetRole() == ax::mojom::Role::kListBox &&
!container->HasState(ax::mojom::State::kMultiselectable) &&
GetDelegate()->GetFocus() == GetNativeViewAccessible()) {
NotifyMacEvent(native_node_, ax::mojom::Event::kFocus);
NotifyMacEvent(objc_storage_->native_node, ax::mojom::Event::kFocus);
return;
}
}
@@ -123,12 +148,12 @@ void AXPlatformNodeMac::NotifyAccessibilityEvent(ax::mojom::Event event_type) {
// Otherwise, use mappings between ax::mojom::Event and NSAccessibility
// notifications from the EventMap above.
NotifyMacEvent(native_node_, event_type);
NotifyMacEvent(objc_storage_->native_node, event_type);
}
void AXPlatformNodeMac::AnnounceText(const std::u16string& text) {
PostAnnouncementNotification(base::SysUTF16ToNSString(text),
[native_node_ AXWindow], false);
[objc_storage_->native_node AXWindow], false);
}
bool IsNameExposedInAXValueForRole(ax::mojom::Role role) {

@@ -6,6 +6,7 @@
#define UI_ACCESSIBILITY_PLATFORM_AX_PRIVATE_WEBKIT_CONSTANTS_MAC_H_
#import <Cocoa/Cocoa.h>
#include "base/component_export.h"
namespace ui {

@@ -4,6 +4,10 @@
#include "ui/accessibility/platform/ax_private_webkit_constants_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace ui {
const char* ToString(AXTextStateChangeType type) {

@@ -10,9 +10,9 @@
#include "base/component_export.h"
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
namespace ui {
@class AXPlatformNodeCocoa;
class AXPlatformNodeCocoa;
namespace ui {
// An AXTextMarker is used by applications like Chrome to store a position in
// the accessibility tree's text representation. It is a data structure whose
@@ -48,7 +48,7 @@ id AXRangeToAXTextMarkerRange(AXPlatformNodeDelegate::AXRange);
// Returns the AXTextMarker representing the position within the given node.
COMPONENT_EXPORT(AX_PLATFORM)
id AXTextMarkerFrom(const AXPlatformNodeCocoa* anchor,
id AXTextMarkerFrom(AXPlatformNodeCocoa* anchor,
int offset,
ax::mojom::TextAffinity affinity);

@@ -4,45 +4,51 @@
#include "ui/accessibility/platform/ax_utils_mac.h"
#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/Foundation.h>
#include "base/mac/scoped_cftyperef.h"
#include "ui/accessibility/ax_range.h"
#include "ui/accessibility/platform/ax_platform_node_base.h"
#include "ui/accessibility/platform/ax_platform_node_cocoa.h"
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace ui {
bool IsAXTextMarker(id object) {
if (object == nil)
if (object == nil) {
return false;
AXTextMarkerRef cf_text_marker = static_cast<AXTextMarkerRef>(object);
DCHECK(cf_text_marker);
return CFGetTypeID(cf_text_marker) == AXTextMarkerGetTypeID();
}
return CFGetTypeID((__bridge CFTypeRef)object) == AXTextMarkerGetTypeID();
}
bool IsAXTextMarkerRange(id object) {
if (object == nil)
if (object == nil) {
return false;
AXTextMarkerRangeRef cf_marker_range =
static_cast<AXTextMarkerRangeRef>(object);
DCHECK(cf_marker_range);
return CFGetTypeID(cf_marker_range) == AXTextMarkerRangeGetTypeID();
}
return CFGetTypeID((__bridge CFTypeRef)object) ==
AXTextMarkerRangeGetTypeID();
}
AXPlatformNodeDelegate::AXPosition AXTextMarkerToAXPosition(id text_marker) {
if (!IsAXTextMarker(text_marker))
if (!IsAXTextMarker(text_marker)) {
return AXNodePosition::CreateNullPosition();
}
AXTextMarkerRef cf_text_marker = static_cast<AXTextMarkerRef>(text_marker);
AXTextMarkerRef cf_text_marker = (__bridge AXTextMarkerRef)text_marker;
if (AXTextMarkerGetLength(cf_text_marker) !=
sizeof(AXPlatformNodeDelegate::SerializedPosition))
sizeof(AXPlatformNodeDelegate::SerializedPosition)) {
return AXNodePosition::CreateNullPosition();
}
const UInt8* source_buffer = AXTextMarkerGetBytePtr(cf_text_marker);
if (!source_buffer)
if (!source_buffer) {
return AXNodePosition::CreateNullPosition();
}
return AXNodePosition::Unserialize(
*reinterpret_cast<const AXPlatformNodeDelegate::SerializedPosition*>(
@@ -56,20 +62,21 @@ AXPlatformNodeDelegate::AXRange AXTextMarkerRangeToAXRange(
}
AXTextMarkerRangeRef cf_marker_range =
static_cast<AXTextMarkerRangeRef>(text_marker_range);
(__bridge AXTextMarkerRangeRef)text_marker_range;
base::ScopedCFTypeRef<AXTextMarkerRef> start_marker(
AXTextMarkerRangeCopyStartMarker(cf_marker_range));
base::ScopedCFTypeRef<AXTextMarkerRef> end_marker(
AXTextMarkerRangeCopyEndMarker(cf_marker_range));
if (!start_marker.get() || !end_marker.get())
id start_marker =
CFBridgingRelease(AXTextMarkerRangeCopyStartMarker(cf_marker_range));
id end_marker =
CFBridgingRelease(AXTextMarkerRangeCopyEndMarker(cf_marker_range));
if (!start_marker || !end_marker) {
return AXPlatformNodeDelegate::AXRange();
}
// |AXPlatformNodeDelegate::AXRange| takes ownership of its anchor and focus.
AXPlatformNodeDelegate::AXPosition anchor =
AXTextMarkerToAXPosition(static_cast<id>(start_marker.get()));
AXTextMarkerToAXPosition(start_marker);
AXPlatformNodeDelegate::AXPosition focus =
AXTextMarkerToAXPosition(static_cast<id>(end_marker.get()));
AXTextMarkerToAXPosition(end_marker);
return AXPlatformNodeDelegate::AXRange(std::move(anchor), std::move(focus));
}
@@ -77,10 +84,9 @@ id AXPositionToAXTextMarker(AXPlatformNodeDelegate::AXPosition position) {
// AXTextMarkerCreate is a system function that makes a copy of the data
// buffer given to it.
AXPlatformNodeDelegate::SerializedPosition serialized = position->Serialize();
AXTextMarkerRef cf_text_marker = AXTextMarkerCreate(
return CFBridgingRelease(AXTextMarkerCreate(
kCFAllocatorDefault, reinterpret_cast<const UInt8*>(&serialized),
sizeof(AXPlatformNodeDelegate::SerializedPosition));
return [static_cast<id>(cf_text_marker) autorelease];
sizeof(AXPlatformNodeDelegate::SerializedPosition)));
}
id AXRangeToAXTextMarkerRange(AXPlatformNodeDelegate::AXRange range) {
@@ -96,15 +102,14 @@ id AXRangeToAXTextMarkerRange(AXPlatformNodeDelegate::AXRange range) {
kCFAllocatorDefault, reinterpret_cast<const UInt8*>(&serialized_focus),
sizeof(AXPlatformNodeDelegate::SerializedPosition)));
AXTextMarkerRangeRef cf_marker_range =
AXTextMarkerRangeCreate(kCFAllocatorDefault, start_marker, end_marker);
return [static_cast<id>(cf_marker_range) autorelease];
return CFBridgingRelease(
AXTextMarkerRangeCreate(kCFAllocatorDefault, start_marker, end_marker));
}
id AXTextMarkerFrom(const AXPlatformNodeCocoa* anchor,
id AXTextMarkerFrom(AXPlatformNodeCocoa* anchor,
int offset,
ax::mojom::TextAffinity affinity) {
AXPlatformNode* anchor_platform_node = [static_cast<id>(anchor) node];
AXPlatformNode* anchor_platform_node = anchor.node;
AXPlatformNodeDelegate* anchor_node = anchor_platform_node->GetDelegate();
AXPlatformNodeDelegate::AXPosition position =
anchor_node->CreateTextPositionAt(offset, affinity);
@@ -112,20 +117,19 @@ id AXTextMarkerFrom(const AXPlatformNodeCocoa* anchor,
}
id AXTextMarkerRangeFrom(id start_textmarker, id end_textmarker) {
AXTextMarkerRangeRef cf_marker_range = AXTextMarkerRangeCreate(
kCFAllocatorDefault, static_cast<AXTextMarkerRef>(start_textmarker),
static_cast<AXTextMarkerRef>(end_textmarker));
return [static_cast<id>(cf_marker_range) autorelease];
return CFBridgingRelease(AXTextMarkerRangeCreate(
kCFAllocatorDefault, (__bridge AXTextMarkerRef)start_textmarker,
(__bridge AXTextMarkerRef)end_textmarker));
}
id AXTextMarkerRangeStart(id text_marker_range) {
return static_cast<id>(AXTextMarkerRangeCopyStartMarker(
static_cast<AXTextMarkerRangeRef>(text_marker_range)));
return CFBridgingRelease(AXTextMarkerRangeCopyStartMarker(
(__bridge AXTextMarkerRangeRef)text_marker_range));
}
id AXTextMarkerRangeEnd(id text_marker_range) {
return static_cast<id>(AXTextMarkerRangeCopyEndMarker(
static_cast<AXTextMarkerRangeRef>(text_marker_range)));
return CFBridgingRelease(AXTextMarkerRangeCopyEndMarker(
(__bridge AXTextMarkerRangeRef)text_marker_range));
}
} // namespace ui

@@ -9,6 +9,10 @@
#include "base/memory/raw_ptr.h"
#include "ui/accessibility/platform/inspect/ax_tree_indexer_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace ui {
class AXElementWrapper;
@@ -107,7 +111,7 @@ class COMPONENT_EXPORT(AX_PLATFORM) AXCallStatementInvoker final {
gfx::NativeViewAccessible LineIndexToNode(
const std::u16string line_index) const;
const id node;
id __strong node;
// Map between AXUIElement objects and their DOMIds/accessible tree
// line numbers. Owned by the caller and outlives this object.

@@ -12,6 +12,10 @@
#include "ui/accessibility/platform/inspect/ax_inspect_utils_mac.h"
#include "ui/accessibility/platform/inspect/ax_property_node.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace ui {
// Template specialization of AXOptional<id>::ToString().
@@ -93,7 +97,7 @@ AXOptionalNSObject AXCallStatementInvoker::Invoke(
// Case 2: try to get target from the tree indexer. The target may refer to
// an accessible element by DOM id or by a line number (:LINE_NUM format) in
// a result accessible tree. The tree indexer keeps the mappings between
// accesible elements and their DOM ids and line numbers.
// accessible elements and their DOM ids and line numbers.
if (!target)
target = indexer_->NodeBy(property_node.name_or_value);
@@ -165,7 +169,7 @@ AXOptionalNSObject AXCallStatementInvoker::InvokeFor(
}
if (AXElementWrapper::IsValidElement(target))
return InvokeForAXElement({target}, property_node);
return InvokeForAXElement(AXElementWrapper{target}, property_node);
if (IsAXTextMarkerRange(target)) {
return InvokeForAXTextMarkerRange(target, property_node);
@@ -283,7 +287,7 @@ AXOptionalNSObject AXCallStatementInvoker::InvokeForAXElement(
optional_arg_selector
? ax_element.Invoke<BOOL, SEL>(selector, *optional_arg_selector)
: ax_element.Invoke<BOOL>(selector);
return AXOptionalNSObject([NSNumber numberWithBool:return_value]);
return AXOptionalNSObject(@(return_value));
}
if (property_node.name_or_value == "setAccessibilityFocused")

@@ -13,12 +13,16 @@
#include "ui/accessibility/platform/inspect/ax_inspect.h"
#include "ui/accessibility/platform/inspect/ax_optional.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace ui {
// Optional tri-state id object.
using AXOptionalNSObject = AXOptional<id>;
// A wrapper around AXUIElement or NSAccessibilityElement object.
// A wrapper around either AXUIElement or NSAccessibilityElement object.
class COMPONENT_EXPORT(AX_PLATFORM) AXElementWrapper final {
public:
// Returns true if the object is either NSAccessibilityElement or
@@ -39,7 +43,7 @@ class COMPONENT_EXPORT(AX_PLATFORM) AXElementWrapper final {
// BrowserAccessibilityCocoa).
static std::string DOMIdOf(const id node);
AXElementWrapper(const id node) : node_(node) {}
explicit AXElementWrapper(const id node) : node_(node) {}
// Returns true if the object is either an NSAccessibilityElement or
// AXUIElement.
@@ -150,7 +154,7 @@ class COMPONENT_EXPORT(AX_PLATFORM) AXElementWrapper final {
// Converts the given value and the error object into AXOptional object.
AXOptionalNSObject ToOptional(id, AXError, const std::string& message) const;
const id node_;
id __strong node_;
};
} // namespace ui

@@ -4,16 +4,25 @@
#include "ui/accessibility/platform/inspect/ax_element_wrapper_mac.h"
#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/Foundation.h>
#include <ostream>
#include "base/apple/bridging.h"
#include "base/containers/fixed_flat_set.h"
#include "base/debug/stack_trace.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/strings/pattern.h"
#include "base/strings/sys_string_conversions.h"
#include "ui/accessibility/platform/ax_private_attributes_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// error: 'accessibilityAttributeNames' is deprecated: first deprecated in
// macOS 10.10 - Use the NSAccessibility protocol methods instead (see
// NSAccessibilityProtocols.h
@@ -22,8 +31,6 @@
namespace ui {
using base::SysNSStringToUTF8;
constexpr char kUnsupportedObject[] =
"Only AXUIElementRef and BrowserAccessibilityCocoa are supported.";
@@ -32,20 +39,24 @@ bool AXElementWrapper::IsValidElement(const id node) {
return AXElementWrapper(node).IsValidElement();
}
// static
bool AXElementWrapper::IsNSAccessibilityElement(const id node) {
return AXElementWrapper(node).IsNSAccessibilityElement();
}
// static
bool AXElementWrapper::IsAXUIElement(const id node) {
return AXElementWrapper(node).IsAXUIElement();
}
// static
NSArray* AXElementWrapper::ChildrenOf(const id node) {
return AXElementWrapper(node).Children();
}
// Returns DOM id of a given node (either AXUIElement or
// BrowserAccessibilityCocoa).
// static
std::string AXElementWrapper::DOMIdOf(const id node) {
return AXElementWrapper(node).DOMId();
}
@@ -59,7 +70,7 @@ bool AXElementWrapper::IsNSAccessibilityElement() const {
}
bool AXElementWrapper::IsAXUIElement() const {
return CFGetTypeID(node_) == AXUIElementGetTypeID();
return CFGetTypeID((__bridge CFTypeRef)node_) == AXUIElementGetTypeID();
}
id AXElementWrapper::AsId() const {
@@ -76,11 +87,13 @@ NSArray* AXElementWrapper::Children() const {
return [node_ children];
if (IsAXUIElement()) {
CFTypeRef children_ref;
if ((AXUIElementCopyAttributeValue(static_cast<AXUIElementRef>(node_),
kAXChildrenAttribute, &children_ref)) ==
kAXErrorSuccess)
return static_cast<NSArray*>(children_ref);
base::ScopedCFTypeRef<CFTypeRef> children_ref;
if ((AXUIElementCopyAttributeValue(
(__bridge AXUIElementRef)node_, kAXChildrenAttribute,
children_ref.InitializeInto())) == kAXErrorSuccess) {
return base::apple::CFToNSOwnershipCast(
(CFArrayRef)children_ref.release());
}
return nil;
}
@@ -101,11 +114,11 @@ NSSize AXElementWrapper::Size() const {
}
id value = *GetAttributeValue(NSAccessibilitySizeAttribute);
if (value && CFGetTypeID(value) == AXValueGetTypeID()) {
AXValueType type = AXValueGetType(static_cast<AXValueRef>(value));
if (value && CFGetTypeID((__bridge CFTypeRef)value) == AXValueGetTypeID()) {
AXValueType type = AXValueGetType((__bridge AXValueRef)value);
if (type == kAXValueCGSizeType) {
NSSize size;
if (AXValueGetValue(static_cast<AXValueRef>(value), type, &size)) {
if (AXValueGetValue((__bridge AXValueRef)value, type, &size)) {
return size;
}
}
@@ -118,35 +131,36 @@ NSPoint AXElementWrapper::Position() const {
return [node_ accessibilityFrame].origin;
}
if (!IsAXUIElement()) {
NOTREACHED()
<< "Only AXUIElementRef and BrowserAccessibilityCocoa are supported.";
return NSMakePoint(0, 0);
}
id value = *GetAttributeValue(NSAccessibilityPositionAttribute);
if (value && CFGetTypeID(value) == AXValueGetTypeID()) {
AXValueType type = AXValueGetType(static_cast<AXValueRef>(value));
if (type == kAXValueCGPointType) {
NSPoint point;
if (AXValueGetValue(static_cast<AXValueRef>(value), type, &point)) {
return point;
if (IsAXUIElement()) {
id value = *GetAttributeValue(NSAccessibilityPositionAttribute);
if (value && CFGetTypeID((__bridge CFTypeRef)value) == AXValueGetTypeID()) {
AXValueType type = AXValueGetType((__bridge AXValueRef)value);
if (type == kAXValueCGPointType) {
NSPoint point;
if (AXValueGetValue((__bridge AXValueRef)value, type, &point)) {
return point;
}
}
}
}
NOTREACHED()
<< "Only AXUIElementRef and BrowserAccessibilityCocoa are supported.";
return NSMakePoint(0, 0);
}
NSArray* AXElementWrapper::AttributeNames() const {
if (IsNSAccessibilityElement())
if (IsNSAccessibilityElement()) {
return [node_ accessibilityAttributeNames];
}
if (IsAXUIElement()) {
CFArrayRef attributes_ref;
base::ScopedCFTypeRef<CFArrayRef> attributes_ref;
AXError result = AXUIElementCopyAttributeNames(
static_cast<AXUIElementRef>(node_), &attributes_ref);
if (AXSuccess(result, "AXAttributeNamesOf"))
return static_cast<NSArray*>(attributes_ref);
(__bridge AXUIElementRef)node_, attributes_ref.InitializeInto());
if (AXSuccess(result, "AXAttributeNamesOf")) {
return base::apple::CFToNSOwnershipCast(attributes_ref.release());
}
return nil;
}
@@ -156,15 +170,17 @@ NSArray* AXElementWrapper::AttributeNames() const {
}
NSArray* AXElementWrapper::ParameterizedAttributeNames() const {
if (IsNSAccessibilityElement())
if (IsNSAccessibilityElement()) {
return [node_ accessibilityParameterizedAttributeNames];
}
if (IsAXUIElement()) {
CFArrayRef attributes_ref;
base::ScopedCFTypeRef<CFArrayRef> attributes_ref;
AXError result = AXUIElementCopyParameterizedAttributeNames(
static_cast<AXUIElementRef>(node_), &attributes_ref);
if (AXSuccess(result, "AXParameterizedAttributeNamesOf"))
return static_cast<NSArray*>(attributes_ref);
(__bridge AXUIElementRef)node_, attributes_ref.InitializeInto());
if (AXSuccess(result, "AXParameterizedAttributeNamesOf")) {
return base::apple::CFToNSOwnershipCast(attributes_ref.release());
}
return nil;
}
@@ -175,16 +191,17 @@ NSArray* AXElementWrapper::ParameterizedAttributeNames() const {
AXOptionalNSObject AXElementWrapper::GetAttributeValue(
NSString* attribute) const {
if (IsNSAccessibilityElement())
if (IsNSAccessibilityElement()) {
return AXOptionalNSObject([node_ accessibilityAttributeValue:attribute]);
}
if (IsAXUIElement()) {
CFTypeRef value_ref;
base::ScopedCFTypeRef<CFTypeRef> value_ref;
AXError result = AXUIElementCopyAttributeValue(
static_cast<AXUIElementRef>(node_), static_cast<CFStringRef>(attribute),
&value_ref);
(__bridge AXUIElementRef)node_, (__bridge CFStringRef)attribute,
value_ref.InitializeInto());
return ToOptional(
static_cast<id>(value_ref), result,
(__bridge id)value_ref.get(), result,
"AXGetAttributeValue(" + base::SysNSStringToUTF8(attribute) + ")");
}
@@ -199,22 +216,20 @@ AXOptionalNSObject AXElementWrapper::GetParameterizedAttributeValue(
forParameter:parameter]);
if (IsAXUIElement()) {
// Convert NSValue parameter to CFTypeRef if needed.
CFTypeRef parameter_ref = static_cast<CFTypeRef>(parameter);
base::ScopedCFTypeRef<CFTypeRef> parameter_ref(CFBridgingRetain(parameter));
if ([parameter isKindOfClass:[NSValue class]] &&
!strcmp([static_cast<NSValue*>(parameter) objCType],
@encode(NSRange))) {
NSRange range = [static_cast<NSValue*>(parameter) rangeValue];
parameter_ref = AXValueCreate(kAXValueTypeCFRange, &range);
!strcmp([parameter objCType], @encode(NSRange))) {
NSRange range = [parameter rangeValue];
parameter_ref.reset(AXValueCreate(kAXValueTypeCFRange, &range));
}
// Get value.
CFTypeRef value_ref;
base::ScopedCFTypeRef<CFTypeRef> value_ref;
AXError result = AXUIElementCopyParameterizedAttributeValue(
static_cast<AXUIElementRef>(node_), static_cast<CFStringRef>(attribute),
parameter_ref, &value_ref);
(__bridge AXUIElementRef)node_, (__bridge CFStringRef)attribute,
parameter_ref, value_ref.InitializeInto());
return ToOptional(static_cast<id>(value_ref), result,
return ToOptional((__bridge id)value_ref.get(), result,
"GetParameterizedAttributeValue(" +
base::SysNSStringToUTF8(attribute) + ")");
}
@@ -245,8 +260,11 @@ absl::optional<id> AXElementWrapper::PerformSelector(
NSSelectorFromString(base::SysUTF8ToNSString(selector_string + ":"));
NSString* argument = base::SysUTF8ToNSString(argument_string);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
if ([node_ respondsToSelector:selector])
return [node_ performSelector:selector withObject:argument];
#pragma clang diagnostic pop
return absl::nullopt;
}
@@ -257,9 +275,9 @@ void AXElementWrapper::SetAttributeValue(NSString* attribute, id value) const {
}
if (IsAXUIElement()) {
AXUIElementSetAttributeValue(static_cast<AXUIElementRef>(node_),
static_cast<CFStringRef>(attribute),
static_cast<CFTypeRef>(value));
AXUIElementSetAttributeValue((__bridge AXUIElementRef)node_,
(__bridge CFStringRef)attribute,
(__bridge CFTypeRef)value);
return;
}
@@ -272,10 +290,12 @@ NSArray* AXElementWrapper::ActionNames() const {
return [node_ accessibilityActionNames];
if (IsAXUIElement()) {
CFArrayRef attributes_ref;
if ((AXUIElementCopyActionNames(static_cast<AXUIElementRef>(node_),
&attributes_ref)) == kAXErrorSuccess)
return static_cast<NSArray*>(attributes_ref);
base::ScopedCFTypeRef<CFArrayRef> attributes_ref;
if ((AXUIElementCopyActionNames((__bridge AXUIElementRef)node_,
attributes_ref.InitializeInto())) ==
kAXErrorSuccess) {
return base::apple::CFToNSOwnershipCast(attributes_ref.release());
}
return nil;
}
@@ -291,8 +311,8 @@ void AXElementWrapper::PerformAction(NSString* action) const {
}
if (IsAXUIElement()) {
AXUIElementPerformAction(static_cast<AXUIElementRef>(node_),
static_cast<CFStringRef>(action));
AXUIElementPerformAction((__bridge AXUIElementRef)node_,
(__bridge CFStringRef)action);
return;
}

@@ -9,6 +9,7 @@
#include <algorithm>
#include <string>
#include "base/apple/bridging.h"
#include "base/logging.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
@@ -19,6 +20,10 @@
#include "ui/accessibility/platform/inspect/ax_inspect_utils_mac.h"
#include "ui/accessibility/platform/inspect/ax_tree_formatter_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace ui {
// Callback function registered using AXObserverCreate.
@@ -34,9 +39,9 @@ static void EventReceivedThunk(AXObserverRef observer_ref,
AXEventRecorderMac::AXEventRecorderMac(base::ProcessId pid,
const AXTreeSelector& selector)
: observer_run_loop_source_(nullptr) {
AXUIElementRef node = nil;
base::ScopedCFTypeRef<AXUIElementRef> node;
if (pid) {
node = AXUIElementCreateApplication(pid);
node.reset(AXUIElementCreateApplication(pid));
if (!node) {
LOG(FATAL) << "Failed to get AXUIElement for pid " << pid;
}
@@ -54,12 +59,12 @@ AXEventRecorderMac::AXEventRecorderMac(base::ProcessId pid,
}
// Get an AXUIElement for the Chrome application.
application_.reset(node);
application_ = std::move(node);
if (!application_.get())
LOG(FATAL) << "Failed to create AXUIElement for application.";
// Add the notifications we care about to the observer.
static NSArray* notifications = [@[
static NSArray* notifications = @[
@"AXAutocorrectionOccurred",
@"AXElementBusyChanged",
@"AXExpandedChanged",
@@ -103,7 +108,7 @@ AXEventRecorderMac::AXEventRecorderMac(base::ProcessId pid,
NSAccessibilityWindowMiniaturizedNotification,
NSAccessibilityWindowMovedNotification,
NSAccessibilityWindowResizedNotification,
] retain];
];
for (NSString* notification : notifications) {
AddNotification(notification);
@@ -122,7 +127,7 @@ AXEventRecorderMac::~AXEventRecorderMac() {
void AXEventRecorderMac::AddNotification(NSString* notification) {
AXObserverAddNotification(observer_ref_, application_,
base::mac::NSToCFCast(notification), this);
base::apple::NSToCFPtrCast(notification), this);
}
void AXEventRecorderMac::EventReceived(AXUIElementRef element,
@@ -135,7 +140,7 @@ void AXEventRecorderMac::EventReceived(AXUIElementRef element,
AXTreeFormatter::kFiltersDefaultSet);
std::string element_str =
formatter.FormatTree(formatter.BuildNode(static_cast<id>(element)));
formatter.FormatTree(formatter.BuildNode((__bridge id)element));
// Element dumps contain a new line character at the end, remove it.
if (!element_str.empty() && element_str.back() == '\n') {
@@ -157,33 +162,27 @@ std::string AXEventRecorderMac::SerializeTextSelectionChangedProperties(
if (user_info == nil)
return {};
std::vector<std::string> serialized_info;
CFDictionaryApplyFunction(
user_info,
[](const void* raw_key, const void* raw_value, void* context) {
auto* key = static_cast<NSString*>(raw_key);
auto* value = static_cast<NSObject*>(raw_value);
auto* serialized_info = static_cast<std::vector<std::string>*>(context);
std::string value_string;
if ([key isEqual:NSAccessibilityTextStateChangeTypeKey]) {
value_string = ToString(static_cast<AXTextStateChangeType>(
[static_cast<NSNumber*>(value) intValue]));
} else if ([key isEqual:NSAccessibilityTextSelectionDirection]) {
value_string = ToString(static_cast<AXTextSelectionDirection>(
[static_cast<NSNumber*>(value) intValue]));
} else if ([key isEqual:NSAccessibilityTextSelectionGranularity]) {
value_string = ToString(static_cast<AXTextSelectionGranularity>(
[static_cast<NSNumber*>(value) intValue]));
} else if ([key isEqual:NSAccessibilityTextEditType]) {
value_string = ToString(static_cast<AXTextEditType>(
[static_cast<NSNumber*>(value) intValue]));
} else {
return;
}
serialized_info->push_back(base::SysNSStringToUTF8(key) + "=" +
value_string);
},
&serialized_info);
__block std::vector<std::string> serialized_info;
[base::apple::CFToNSPtrCast(user_info) enumerateKeysAndObjectsUsingBlock:^(
id key, id value, BOOL* stop) {
std::string value_string;
if ([key isEqual:NSAccessibilityTextStateChangeTypeKey]) {
value_string =
ToString(static_cast<AXTextStateChangeType>([value intValue]));
} else if ([key isEqual:NSAccessibilityTextSelectionDirection]) {
value_string =
ToString(static_cast<AXTextSelectionDirection>([value intValue]));
} else if ([key isEqual:NSAccessibilityTextSelectionGranularity]) {
value_string =
ToString(static_cast<AXTextSelectionGranularity>([value intValue]));
} else if ([key isEqual:NSAccessibilityTextEditType]) {
value_string = ToString(static_cast<AXTextEditType>([value intValue]));
} else {
return;
}
serialized_info.push_back(base::SysNSStringToUTF8(key) + "=" +
value_string);
}];
// Always sort the info so that we don't depend on CFDictionary for
// consistent output ordering.

@@ -5,10 +5,11 @@
#ifndef UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_INSPECT_UTILS_MAC_H_
#define UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_INSPECT_UTILS_MAC_H_
#import <Cocoa/Cocoa.h>
#include <ApplicationServices/ApplicationServices.h>
#include "base/component_export.h"
#include "base/functional/callback_forward.h"
#include "base/mac/scoped_cftyperef.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/accessibility/platform/inspect/ax_inspect.h"
@@ -24,17 +25,20 @@ bool IsValidAXAttribute(const std::string& attribute);
// Return AXElement in a tree by a given criteria.
using AXFindCriteria = base::RepeatingCallback<bool(const AXUIElementRef)>;
COMPONENT_EXPORT(AX_PLATFORM)
AXUIElementRef FindAXUIElement(const AXUIElementRef node,
const AXFindCriteria& criteria);
base::ScopedCFTypeRef<AXUIElementRef> FindAXUIElement(
const AXUIElementRef node,
const AXFindCriteria& criteria);
// Returns AXUIElement and its application process id by a given tree selector.
COMPONENT_EXPORT(AX_PLATFORM)
std::pair<AXUIElementRef, int> FindAXUIElement(const AXTreeSelector&);
std::pair<base::ScopedCFTypeRef<AXUIElementRef>, int> FindAXUIElement(
const AXTreeSelector&);
// Returns AXUIElement for a window having title matching the given pattern.
COMPONENT_EXPORT(AX_PLATFORM)
AXUIElementRef FindAXWindowChild(AXUIElementRef parent,
const std::string& pattern);
base::ScopedCFTypeRef<AXUIElementRef> FindAXWindowChild(
AXUIElementRef parent,
const std::string& pattern);
} // namespace ui

@@ -4,17 +4,26 @@
#include "ui/accessibility/platform/inspect/ax_inspect_utils_mac.h"
#include <CoreGraphics/CoreGraphics.h>
#include <ostream>
#include "base/apple/bridging.h"
#include "base/containers/fixed_flat_set.h"
#include "base/debug/stack_trace.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/mac/foundation_util.h"
#include "base/memory/scoped_policy.h"
#include "base/strings/pattern.h"
#include "base/strings/sys_string_conversions.h"
#include "ui/accessibility/platform/ax_private_attributes_mac.h"
#include "ui/accessibility/platform/inspect/ax_element_wrapper_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// error: 'accessibilityAttributeNames' is deprecated: first deprecated in
// macOS 10.10 - Use the NSAccessibility protocol methods instead (see
// NSAccessibilityProtocols.h
@@ -23,112 +32,106 @@
namespace ui {
using base::SysNSStringToUTF8;
namespace {
const char kChromeTitle[] = "Google Chrome";
const char kChromiumTitle[] = "Chromium";
const char kFirefoxTitle[] = "Firefox";
const char kSafariTitle[] = "Safari";
struct NSStringComparator {
bool operator()(NSString* lhs, NSString* rhs) const {
return [lhs compare:rhs] == NSOrderedAscending;
}
};
bool IsValidAXAttribute(const std::string& attribute) {
// static local to avoid a global static constructor.
static auto kValidAttributes = base::MakeFixedFlatSet<NSString*>(
{NSAccessibilityAccessKeyAttribute,
NSAccessibilityARIAAtomicAttribute,
NSAccessibilityARIABusyAttribute,
NSAccessibilityARIAColumnCountAttribute,
NSAccessibilityARIAColumnIndexAttribute,
NSAccessibilityARIACurrentAttribute,
NSAccessibilityARIALiveAttribute,
NSAccessibilityARIAPosInSetAttribute,
NSAccessibilityARIARelevantAttribute,
NSAccessibilityARIARowCountAttribute,
NSAccessibilityARIARowIndexAttribute,
NSAccessibilityARIASetSizeAttribute,
NSAccessibilityAutocompleteValueAttribute,
NSAccessibilityBlockQuoteLevelAttribute,
NSAccessibilityBrailleLabelAttribute,
NSAccessibilityBrailleRoleDescription,
NSAccessibilityChromeAXNodeIdAttribute,
NSAccessibilityColumnHeaderUIElementsAttribute,
NSAccessibilityDescriptionAttribute,
NSAccessibilityDetailsElementsAttribute,
NSAccessibilityDOMClassList,
NSAccessibilityDropEffectsAttribute,
NSAccessibilityElementBusyAttribute,
NSAccessibilityFocusableAncestorAttribute,
NSAccessibilityGrabbedAttribute,
NSAccessibilityHasPopupAttribute,
NSAccessibilityInvalidAttribute,
NSAccessibilityIsMultiSelectable,
NSAccessibilityKeyShortcutsValueAttribute,
NSAccessibilityLoadedAttribute,
NSAccessibilityLoadingProgressAttribute,
NSAccessibilityMathFractionNumeratorAttribute,
NSAccessibilityMathFractionDenominatorAttribute,
NSAccessibilityMathRootRadicandAttribute,
NSAccessibilityMathRootIndexAttribute,
NSAccessibilityMathBaseAttribute,
NSAccessibilityMathSubscriptAttribute,
NSAccessibilityMathSuperscriptAttribute,
NSAccessibilityMathUnderAttribute,
NSAccessibilityMathOverAttribute,
NSAccessibilityMathPostscriptsAttribute,
NSAccessibilityMathPrescriptsAttribute,
NSAccessibilityOwnsAttribute,
NSAccessibilityPopupValueAttribute,
NSAccessibilityRequiredAttribute,
NSAccessibilityRoleDescriptionAttribute,
NSAccessibilitySelectedAttribute,
NSAccessibilitySizeAttribute,
NSAccessibilityTitleAttribute,
NSAccessibilityTitleUIElementAttribute,
NSAccessibilityURLAttribute,
NSAccessibilityVisitedAttribute},
NSStringComparator());
return kValidAttributes.contains(base::SysUTF8ToNSString(attribute));
}
NSArray* AXChildrenOf(const id node) {
return AXElementWrapper(node).Children();
}
std::string GetDOMId(const id node) {
return AXElementWrapper(node).DOMId();
} // namespace
bool IsValidAXAttribute(const std::string& attribute) {
static NSSet<NSString*>* valid_attributes = [NSSet setWithArray:@[
NSAccessibilityAccessKeyAttribute,
NSAccessibilityARIAAtomicAttribute,
NSAccessibilityARIABusyAttribute,
NSAccessibilityARIAColumnCountAttribute,
NSAccessibilityARIAColumnIndexAttribute,
NSAccessibilityARIACurrentAttribute,
NSAccessibilityARIALiveAttribute,
NSAccessibilityARIAPosInSetAttribute,
NSAccessibilityARIARelevantAttribute,
NSAccessibilityARIARowCountAttribute,
NSAccessibilityARIARowIndexAttribute,
NSAccessibilityARIASetSizeAttribute,
NSAccessibilityAutocompleteValueAttribute,
NSAccessibilityBlockQuoteLevelAttribute,
NSAccessibilityBrailleLabelAttribute,
NSAccessibilityBrailleRoleDescription,
NSAccessibilityChromeAXNodeIdAttribute,
NSAccessibilityColumnHeaderUIElementsAttribute,
NSAccessibilityDescriptionAttribute,
NSAccessibilityDetailsElementsAttribute,
NSAccessibilityDOMClassList,
NSAccessibilityDropEffectsAttribute,
NSAccessibilityElementBusyAttribute,
NSAccessibilityFocusableAncestorAttribute,
NSAccessibilityGrabbedAttribute,
NSAccessibilityHasPopupAttribute,
NSAccessibilityInvalidAttribute,
NSAccessibilityIsMultiSelectable,
NSAccessibilityKeyShortcutsValueAttribute,
NSAccessibilityLoadedAttribute,
NSAccessibilityLoadingProgressAttribute,
NSAccessibilityMathFractionNumeratorAttribute,
NSAccessibilityMathFractionDenominatorAttribute,
NSAccessibilityMathRootRadicandAttribute,
NSAccessibilityMathRootIndexAttribute,
NSAccessibilityMathBaseAttribute,
NSAccessibilityMathSubscriptAttribute,
NSAccessibilityMathSuperscriptAttribute,
NSAccessibilityMathUnderAttribute,
NSAccessibilityMathOverAttribute,
NSAccessibilityMathPostscriptsAttribute,
NSAccessibilityMathPrescriptsAttribute,
NSAccessibilityOwnsAttribute,
NSAccessibilityPopupValueAttribute,
NSAccessibilityRequiredAttribute,
NSAccessibilityRoleDescriptionAttribute,
NSAccessibilitySelectedAttribute,
NSAccessibilitySizeAttribute,
NSAccessibilityTitleAttribute,
NSAccessibilityTitleUIElementAttribute,
NSAccessibilityURLAttribute,
NSAccessibilityVisitedAttribute,
]];
return [valid_attributes containsObject:base::SysUTF8ToNSString(attribute)];
}
AXUIElementRef FindAXUIElement(const AXUIElementRef node,
const AXFindCriteria& criteria) {
if (criteria.Run(node))
return node;
base::ScopedCFTypeRef<AXUIElementRef> FindAXUIElement(
const AXUIElementRef node,
const AXFindCriteria& criteria) {
if (criteria.Run(node)) {
return base::ScopedCFTypeRef<AXUIElementRef>(node,
base::scoped_policy::RETAIN);
}
NSArray* children = AXChildrenOf(static_cast<id>(node));
NSArray* children = AXChildrenOf((__bridge id)node);
for (id child in children) {
AXUIElementRef found =
FindAXUIElement(static_cast<AXUIElementRef>(child), criteria);
if (found != nil)
base::ScopedCFTypeRef<AXUIElementRef> found =
FindAXUIElement((__bridge AXUIElementRef)child, criteria);
if (found != nil) {
return found;
}
}
return nil;
return base::ScopedCFTypeRef<AXUIElementRef>();
}
std::pair<AXUIElementRef, int> FindAXUIElement(const AXTreeSelector& selector) {
std::pair<base::ScopedCFTypeRef<AXUIElementRef>, int> FindAXUIElement(
const AXTreeSelector& selector) {
if (selector.widget) {
return {AXUIElementCreateApplication(selector.widget), selector.widget};
return {base::ScopedCFTypeRef<AXUIElementRef>(
AXUIElementCreateApplication(selector.widget)),
selector.widget};
}
NSArray* windows = static_cast<NSArray*>(CGWindowListCopyWindowInfo(
kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
kCGNullWindowID));
std::string title;
if (selector.types & AXTreeSelector::Chrome)
title = kChromeTitle;
@@ -139,32 +142,40 @@ std::pair<AXUIElementRef, int> FindAXUIElement(const AXTreeSelector& selector) {
else if (selector.types & AXTreeSelector::Safari)
title = kSafariTitle;
else
return {nil, 0};
return {base::ScopedCFTypeRef<AXUIElementRef>(), 0};
NSArray* windows =
base::apple::CFToNSOwnershipCast(CGWindowListCopyWindowInfo(
kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
kCGNullWindowID));
for (NSDictionary* window_info in windows) {
int pid =
[static_cast<NSNumber*>([window_info objectForKey:@"kCGWindowOwnerPID"])
intValue];
std::string window_name = SysNSStringToUTF8(static_cast<NSString*>(
[window_info objectForKey:@"kCGWindowOwnerName"]));
int pid = base::mac::ObjCCast<NSNumber>(window_info[@"kCGWindowOwnerPID"])
.intValue;
std::string window_name = base::SysNSStringToUTF8(
base::mac::ObjCCast<NSString>(window_info[@"kCGWindowOwnerName"]));
AXUIElementRef node = nil;
base::ScopedCFTypeRef<AXUIElementRef> node;
// Application pre-defined selectors match or application title exact match.
bool appTitleMatch = window_name == selector.pattern;
if (window_name == title || appTitleMatch)
node = AXUIElementCreateApplication(pid);
bool app_title_match = window_name == selector.pattern;
if (window_name == title || app_title_match) {
node.reset(AXUIElementCreateApplication(pid));
}
// Window title match. Application contain an AXWindow accessible object as
// a first child, which accessible name contain a window title. For example:
// 'Inbox (2) - asurkov@igalia.com - Gmail'.
if (!selector.pattern.empty() && !appTitleMatch) {
if (!node)
node = AXUIElementCreateApplication(pid);
if (!selector.pattern.empty() && !app_title_match) {
if (!node) {
node.reset(AXUIElementCreateApplication(pid));
}
AXUIElementRef window = FindAXWindowChild(node, selector.pattern);
if (window)
base::ScopedCFTypeRef<AXUIElementRef> window =
FindAXWindowChild(node, selector.pattern);
if (window) {
node = window;
}
}
// ActiveTab selector.
@@ -173,10 +184,10 @@ std::pair<AXUIElementRef, int> FindAXUIElement(const AXTreeSelector& selector) {
node, base::BindRepeating([](const AXUIElementRef node) {
// Only active tab in exposed in browsers, thus find first
// AXWebArea role.
AXElementWrapper ax_node(static_cast<id>(node));
AXElementWrapper ax_node((__bridge id)node);
NSString* role =
*ax_node.GetAttributeValue(NSAccessibilityRoleAttribute);
return SysNSStringToUTF8(role) == "AXWebArea";
return base::SysNSStringToUTF8(role) == "AXWebArea";
}));
}
@@ -184,28 +195,33 @@ std::pair<AXUIElementRef, int> FindAXUIElement(const AXTreeSelector& selector) {
if (node)
return {node, pid};
}
return {nil, 0};
return {base::ScopedCFTypeRef<AXUIElementRef>(), 0};
}
AXUIElementRef FindAXWindowChild(AXUIElementRef parent,
const std::string& pattern) {
NSArray* children = AXChildrenOf(static_cast<id>(parent));
if ([children count] == 0)
return nil;
base::ScopedCFTypeRef<AXUIElementRef> FindAXWindowChild(
AXUIElementRef parent,
const std::string& pattern) {
NSArray* children = AXChildrenOf((__bridge id)parent);
if (children.count == 0) {
return base::ScopedCFTypeRef<AXUIElementRef>();
}
id window = [children objectAtIndex:0];
id window = children.firstObject;
AXElementWrapper ax_window(window);
NSString* role = *ax_window.GetAttributeValue(NSAccessibilityRoleAttribute);
if (SysNSStringToUTF8(role) != "AXWindow")
return nil;
if (base::SysNSStringToUTF8(role) != "AXWindow") {
return base::ScopedCFTypeRef<AXUIElementRef>();
}
NSString* window_title =
*ax_window.GetAttributeValue(NSAccessibilityTitleAttribute);
if (base::MatchPattern(SysNSStringToUTF8(window_title), pattern))
return static_cast<AXUIElementRef>(window);
if (base::MatchPattern(base::SysNSStringToUTF8(window_title), pattern)) {
return base::ScopedCFTypeRef<AXUIElementRef>(
(__bridge AXUIElementRef)window, base::scoped_policy::RETAIN);
}
return nil;
return base::ScopedCFTypeRef<AXUIElementRef>();
}
} // namespace ui

@@ -4,6 +4,7 @@
#include "ui/accessibility/platform/inspect/ax_transform_mac.h"
#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
#include "ui/accessibility/ax_range.h"
#include "ui/accessibility/platform/ax_platform_node.h"
@@ -14,6 +15,10 @@
#include "ui/accessibility/platform/inspect/ax_element_wrapper_mac.h"
#include "ui/accessibility/platform/inspect/ax_inspect_utils.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace ui {
constexpr char kHeightDictKey[] = "h";
@@ -30,73 +35,75 @@ base::Value AXNSObjectToBaseValue(id value, const AXTreeIndexerMac* indexer) {
}
// NSArray
if ([value isKindOfClass:[NSArray class]]) {
return base::Value(AXNSArrayToBaseValue((NSArray*)value, indexer));
if (NSArray* array = base::mac::ObjCCast<NSArray>(value)) {
return base::Value(AXNSArrayToBaseValue(value, indexer));
}
// AXCustomContent
if (@available(macOS 11.0, *)) {
if ([value isKindOfClass:[AXCustomContent class]]) {
return base::Value(AXCustomContentToBaseValue((AXCustomContent*)value));
if (AXCustomContent* custom_content =
base::mac::ObjCCast<AXCustomContent>(value)) {
return base::Value(AXCustomContentToBaseValue(custom_content));
}
}
// NSDictionary
if ([value isKindOfClass:[NSDictionary class]]) {
return base::Value(
AXNSDictionaryToBaseValue((NSDictionary*)value, indexer));
if (NSDictionary* dictionary = base::mac::ObjCCast<NSDictionary>(value)) {
return base::Value(AXNSDictionaryToBaseValue(dictionary, indexer));
}
// NSNumber
if ([value isKindOfClass:[NSNumber class]]) {
return base::Value([value intValue]);
if (NSNumber* number = base::mac::ObjCCast<NSNumber>(value)) {
return base::Value(number.intValue);
}
// NSRange, NSSize
if ([value isKindOfClass:[NSValue class]]) {
if (0 == strcmp([value objCType], @encode(NSRange))) {
return base::Value(AXNSRangeToBaseValue([value rangeValue]));
if (NSValue* ns_value = base::mac::ObjCCast<NSValue>(value)) {
if (0 == strcmp(ns_value.objCType, @encode(NSRange))) {
return base::Value(AXNSRangeToBaseValue(ns_value.rangeValue));
}
if (0 == strcmp([value objCType], @encode(NSSize))) {
return base::Value(AXNSSizeToBaseValue([value sizeValue]));
if (0 == strcmp(ns_value.objCType, @encode(NSSize))) {
return base::Value(AXNSSizeToBaseValue(ns_value.sizeValue));
}
}
// NSAttributedString
if ([value isKindOfClass:[NSAttributedString class]]) {
return NSAttributedStringToBaseValue((NSAttributedString*)value, indexer);
if (NSAttributedString* attr_string =
base::mac::ObjCCast<NSAttributedString>(value)) {
return NSAttributedStringToBaseValue(attr_string, indexer);
}
// CGColorRef
if (CFGetTypeID(value) == CGColorGetTypeID()) {
return base::Value(CGColorRefToBaseValue(static_cast<CGColorRef>(value)));
if (CFGetTypeID((__bridge CFTypeRef)value) == CGColorGetTypeID()) {
return base::Value(CGColorRefToBaseValue((__bridge CGColorRef)value));
}
// AXValue
if (CFGetTypeID(value) == AXValueGetTypeID()) {
AXValueType type = AXValueGetType(static_cast<AXValueRef>(value));
if (CFGetTypeID((__bridge CFTypeRef)value) == AXValueGetTypeID()) {
AXValueRef ax_value = (__bridge AXValueRef)value;
AXValueType type = AXValueGetType(ax_value);
switch (type) {
case kAXValueCGPointType: {
NSPoint point;
if (AXValueGetValue(static_cast<AXValueRef>(value), type, &point)) {
if (AXValueGetValue(ax_value, type, &point)) {
return base::Value(AXNSPointToBaseValue(point));
}
} break;
case kAXValueCGSizeType: {
NSSize size;
if (AXValueGetValue(static_cast<AXValueRef>(value), type, &size)) {
if (AXValueGetValue(ax_value, type, &size)) {
return base::Value(AXNSSizeToBaseValue(size));
}
} break;
case kAXValueCGRectType: {
NSRect rect;
if (AXValueGetValue(static_cast<AXValueRef>(value), type, &rect)) {
if (AXValueGetValue(ax_value, type, &rect)) {
return base::Value(AXNSRectToBaseValue(rect));
}
} break;
case kAXValueCFRangeType: {
NSRange range;
if (AXValueGetValue(static_cast<AXValueRef>(value), type, &range)) {
if (AXValueGetValue(ax_value, type, &range)) {
return base::Value(AXNSRangeToBaseValue(range));
}
} break;
@@ -111,8 +118,9 @@ base::Value AXNSObjectToBaseValue(id value, const AXTreeIndexerMac* indexer) {
}
// AXTextMarkerRange
if (IsAXTextMarkerRange(value))
if (IsAXTextMarkerRange(value)) {
return AXTextMarkerRangeToBaseValue(value, indexer);
}
// Accessible object
if (AXElementWrapper::IsValidElement(value)) {
@@ -131,23 +139,27 @@ base::Value AXElementToBaseValue(id node, const AXTreeIndexerMac* indexer) {
base::Value AXPositionToBaseValue(
const AXPlatformNodeDelegate::AXPosition& position,
const AXTreeIndexerMac* indexer) {
if (position->IsNullPosition())
if (position->IsNullPosition()) {
return AXNilToBaseValue();
}
const AXPlatformTreeManager* manager =
static_cast<AXPlatformTreeManager*>(position->GetManager());
if (!manager)
if (!manager) {
return AXNilToBaseValue();
}
AXPlatformNode* platform_node_anchor =
manager->GetPlatformNodeFromTree(position->anchor_id());
if (!platform_node_anchor)
if (!platform_node_anchor) {
return AXNilToBaseValue();
}
AXPlatformNodeCocoa* cocoa_anchor = static_cast<AXPlatformNodeCocoa*>(
platform_node_anchor->GetNativeViewAccessible());
if (!cocoa_anchor)
if (!cocoa_anchor) {
return AXNilToBaseValue();
}
std::string affinity;
switch (position->affinity()) {
@@ -162,13 +174,14 @@ base::Value AXPositionToBaseValue(
break;
}
base::Value::Dict value;
value.Set(AXMakeSetKey(AXMakeOrderedKey("anchor", 0)),
AXElementToBaseValue(static_cast<id>(cocoa_anchor), indexer));
value.Set(AXMakeSetKey(AXMakeOrderedKey("offset", 1)),
position->text_offset());
value.Set(AXMakeSetKey(AXMakeOrderedKey("affinity", 2)),
AXMakeConst(affinity));
base::Value::Dict value =
base::Value::Dict()
.Set(AXMakeSetKey(AXMakeOrderedKey("anchor", 0)),
AXElementToBaseValue(static_cast<id>(cocoa_anchor), indexer))
.Set(AXMakeSetKey(AXMakeOrderedKey("offset", 1)),
position->text_offset())
.Set(AXMakeSetKey(AXMakeOrderedKey("affinity", 2)),
AXMakeConst(affinity));
return base::Value(std::move(value));
}
@@ -181,13 +194,16 @@ base::Value AXTextMarkerRangeToBaseValue(id text_marker_range,
const AXTreeIndexerMac* indexer) {
AXPlatformNodeDelegate::AXRange ax_range =
AXTextMarkerRangeToAXRange(text_marker_range);
if (ax_range.IsNull())
if (ax_range.IsNull()) {
return AXNilToBaseValue();
}
base::Value::Dict value;
value.Set("anchor",
AXPositionToBaseValue(ax_range.anchor()->Clone(), indexer));
value.Set("focus", AXPositionToBaseValue(ax_range.focus()->Clone(), indexer));
base::Value::Dict value =
base::Value::Dict()
.Set("anchor",
AXPositionToBaseValue(ax_range.anchor()->Clone(), indexer))
.Set("focus",
AXPositionToBaseValue(ax_range.focus()->Clone(), indexer));
return base::Value(std::move(value));
}
@@ -196,7 +212,7 @@ base::Value NSAttributedStringToBaseValue(NSAttributedString* attr_string,
__block base::Value::Dict result;
[attr_string
enumerateAttributesInRange:NSMakeRange(0, [attr_string length])
enumerateAttributesInRange:NSMakeRange(0, attr_string.length)
options:
NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
usingBlock:^(NSDictionary* attrs, NSRange nsRange,
@@ -210,7 +226,7 @@ base::Value NSAttributedStringToBaseValue(NSAttributedString* attr_string,
}];
result.Set(std::string(base::SysNSStringToUTF8(
[[attr_string string]
[attr_string.string
substringWithRange:nsRange])),
std::move(base_attrs));
}];
@@ -232,15 +248,17 @@ base::Value AXNilToBaseValue() {
base::Value::List AXNSArrayToBaseValue(NSArray* node_array,
const AXTreeIndexerMac* indexer) {
base::Value::List list;
for (NSUInteger i = 0; i < [node_array count]; i++)
list.Append(AXNSObjectToBaseValue([node_array objectAtIndex:i], indexer));
for (id item in node_array) {
list.Append(AXNSObjectToBaseValue(item, indexer));
}
return list;
}
base::Value::Dict AXCustomContentToBaseValue(AXCustomContent* content) {
base::Value::Dict value;
value.Set("label", base::SysNSStringToUTF16(content.label));
value.Set("value", base::SysNSStringToUTF16(content.value));
base::Value::Dict value =
base::Value::Dict()
.Set("label", base::SysNSStringToUTF16(content.label))
.Set("value", base::SysNSStringToUTF16(content.value));
return value;
}
@@ -256,40 +274,41 @@ base::Value::Dict AXNSDictionaryToBaseValue(NSDictionary* dictionary_value,
}
base::Value::Dict AXNSPointToBaseValue(NSPoint point_value) {
base::Value::Dict point;
point.Set(kXCoordDictKey, static_cast<int>(point_value.x));
point.Set(kYCoordDictKey, static_cast<int>(point_value.y));
base::Value::Dict point =
base::Value::Dict()
.Set(kXCoordDictKey, static_cast<int>(point_value.x))
.Set(kYCoordDictKey, static_cast<int>(point_value.y));
return point;
}
base::Value::Dict AXNSSizeToBaseValue(NSSize size_value) {
base::Value::Dict size;
size.Set(AXMakeOrderedKey(kWidthDictKey, 0),
static_cast<int>(size_value.width));
size.Set(AXMakeOrderedKey(kHeightDictKey, 1),
static_cast<int>(size_value.height));
base::Value::Dict size = base::Value::Dict()
.Set(AXMakeOrderedKey(kWidthDictKey, 0),
static_cast<int>(size_value.width))
.Set(AXMakeOrderedKey(kHeightDictKey, 1),
static_cast<int>(size_value.height));
return size;
}
base::Value::Dict AXNSRectToBaseValue(NSRect rect_value) {
base::Value::Dict rect;
rect.Set(AXMakeOrderedKey(kXCoordDictKey, 0),
static_cast<int>(rect_value.origin.x));
rect.Set(AXMakeOrderedKey(kYCoordDictKey, 1),
static_cast<int>(rect_value.origin.y));
rect.Set(AXMakeOrderedKey(kWidthDictKey, 2),
static_cast<int>(rect_value.size.width));
rect.Set(AXMakeOrderedKey(kHeightDictKey, 3),
static_cast<int>(rect_value.size.height));
base::Value::Dict rect = base::Value::Dict()
.Set(AXMakeOrderedKey(kXCoordDictKey, 0),
static_cast<int>(rect_value.origin.x))
.Set(AXMakeOrderedKey(kYCoordDictKey, 1),
static_cast<int>(rect_value.origin.y))
.Set(AXMakeOrderedKey(kWidthDictKey, 2),
static_cast<int>(rect_value.size.width))
.Set(AXMakeOrderedKey(kHeightDictKey, 3),
static_cast<int>(rect_value.size.height));
return rect;
}
base::Value::Dict AXNSRangeToBaseValue(NSRange node_range) {
base::Value::Dict range;
range.Set(AXMakeOrderedKey(kRangeLocDictKey, 0),
static_cast<int>(node_range.location));
range.Set(AXMakeOrderedKey(kRangeLenDictKey, 1),
static_cast<int>(node_range.length));
base::Value::Dict range = base::Value::Dict()
.Set(AXMakeOrderedKey(kRangeLocDictKey, 0),
static_cast<int>(node_range.location))
.Set(AXMakeOrderedKey(kRangeLenDictKey, 1),
static_cast<int>(node_range.length));
return range;
}

@@ -4,6 +4,8 @@
#include "ui/accessibility/platform/inspect/ax_tree_formatter_mac.h"
#include <string>
#include "base/files/file_path.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
@@ -19,16 +21,15 @@
#include "ui/accessibility/platform/inspect/ax_script_instruction.h"
#include "ui/accessibility/platform/inspect/ax_transform_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// This file uses the deprecated NSObject accessibility interface.
// TODO(crbug.com/948844): Migrate to the new NSAccessibility interface.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
using base::StringPrintf;
using base::SysNSStringToUTF8;
using base::SysNSStringToUTF16;
using std::string;
namespace ui {
namespace {
@@ -47,13 +48,13 @@ AXTreeFormatterMac::~AXTreeFormatterMac() = default;
void AXTreeFormatterMac::AddDefaultFilters(
std::vector<AXPropertyFilter>* property_filters) {
static NSArray* default_attributes = [@[
static NSArray* default_attributes = @[
@"AXAutocompleteValue", @"AXDescription", @"AXRole", @"AXSubrole",
@"AXTitle", @"AXTitleUIElement", @"AXValue"
] retain];
];
for (NSString* attribute : default_attributes) {
AddPropertyFilter(property_filters, SysNSStringToUTF8(attribute));
AddPropertyFilter(property_filters, base::SysNSStringToUTF8(attribute));
}
if (show_ids()) {
@@ -69,7 +70,7 @@ base::Value::Dict AXTreeFormatterMac::BuildTree(
base::Value::Dict AXTreeFormatterMac::BuildTreeForSelector(
const AXTreeSelector& selector) const {
AXUIElementRef node = nil;
base::ScopedCFTypeRef<AXUIElementRef> node;
std::tie(node, std::ignore) = FindAXUIElement(selector);
if (node == nil) {
return base::Value::Dict();
@@ -79,7 +80,7 @@ base::Value::Dict AXTreeFormatterMac::BuildTreeForSelector(
base::Value::Dict AXTreeFormatterMac::BuildTreeForAXUIElement(
AXUIElementRef node) const {
return BuildTree(static_cast<id>(node));
return BuildTree((__bridge id)node);
}
base::Value::Dict AXTreeFormatterMac::BuildTree(const id root) const {
@@ -101,13 +102,13 @@ base::Value::Dict AXTreeFormatterMac::BuildTree(const id root) const {
std::string AXTreeFormatterMac::EvaluateScript(
const AXTreeSelector& selector,
const AXInspectScenario& scenario) const {
AXUIElementRef root = nil;
base::ScopedCFTypeRef<AXUIElementRef> root;
std::tie(root, std::ignore) = FindAXUIElement(selector);
if (!root)
return "";
std::string result =
EvaluateScript(static_cast<id>(root), scenario.script_instructions, 0,
EvaluateScript((__bridge id)root.get(), scenario.script_instructions, 0,
scenario.script_instructions.size());
return result;
@@ -207,7 +208,8 @@ void AXTreeFormatterMac::RecursiveBuildTree(const AXElementWrapper& ax_element,
base::Value::List child_dict_list;
for (id child in children) {
base::Value::Dict child_dict;
RecursiveBuildTree({child}, root_rect, indexer, &child_dict);
RecursiveBuildTree(AXElementWrapper{child}, root_rect, indexer,
&child_dict);
child_dict_list.Append(std::move(child_dict));
}
dict->Set(kChildrenDictAttr, std::move(child_dict_list));
@@ -226,7 +228,7 @@ void AXTreeFormatterMac::AddProperties(const AXElementWrapper& ax_element,
NSArray* attributes = ax_element.AttributeNames();
for (NSString* attribute : attributes) {
dict->SetByDottedPath(
SysNSStringToUTF8(attribute),
base::SysNSStringToUTF8(attribute),
AXNSObjectToBaseValue(*ax_element.GetAttributeValue(attribute),
indexer));
}
@@ -279,17 +281,19 @@ std::string AXTreeFormatterMac::ProcessTreeForOutput(
std::string line;
// AXRole and AXSubrole have own formatting and should be listed upfront.
std::string role_attr = SysNSStringToUTF8(NSAccessibilityRoleAttribute);
std::string role_attr = base::SysNSStringToUTF8(NSAccessibilityRoleAttribute);
const std::string* value = dict.FindString(role_attr);
if (value) {
WriteAttribute(true, *value, &line);
}
std::string subrole_attr = SysNSStringToUTF8(NSAccessibilitySubroleAttribute);
std::string subrole_attr =
base::SysNSStringToUTF8(NSAccessibilitySubroleAttribute);
value = dict.FindString(subrole_attr);
if (value) {
WriteAttribute(false,
StringPrintf("%s=%s", subrole_attr.c_str(), value->c_str()),
&line);
WriteAttribute(
false,
base::StringPrintf("%s=%s", subrole_attr.c_str(), value->c_str()),
&line);
}
// Expose all other attributes.
@@ -308,10 +312,10 @@ std::string AXTreeFormatterMac::ProcessTreeForOutput(
// Write formatted value.
std::string formatted_value = AXFormatValue(item.second);
WriteAttribute(
false,
StringPrintf("%s=%s", item.first.c_str(), formatted_value.c_str()),
&line);
WriteAttribute(false,
base::StringPrintf("%s=%s", item.first.c_str(),
formatted_value.c_str()),
&line);
}
return line;

@@ -10,14 +10,13 @@
namespace ui {
//
// NSAccessibilityElement or AXUIElement accessible node comparator.
struct AXNodeComparator {
constexpr bool operator()(const gfx::NativeViewAccessible& lhs,
const gfx::NativeViewAccessible& rhs) const {
if (AXElementWrapper::IsAXUIElement(lhs)) {
DCHECK(AXElementWrapper::IsAXUIElement(rhs));
return CFHash(lhs) < CFHash(rhs);
return CFHash((__bridge CFTypeRef)lhs) < CFHash((__bridge CFTypeRef)rhs);
}
DCHECK(AXElementWrapper::IsNSAccessibilityElement(lhs));
DCHECK(AXElementWrapper::IsNSAccessibilityElement(rhs));

@@ -1169,6 +1169,22 @@ source_set("test_support") {
}
}
if (is_mac) {
# TODO(https://crbug.com/1280317): Merge back into views_unittests once all
# .mm files are ARCed.
source_set("views_unittests_arc") {
testonly = true
sources = [ "widget/ax_native_widget_mac_unittest.mm" ]
configs += [ "//build/config/compiler:enable_arc" ]
deps = [
":views",
"//testing/gtest",
"//ui/accessibility",
"//ui/views:test_support",
]
}
}
test("views_unittests") {
use_xvfb = use_xvfb_in_this_config
@@ -1406,7 +1422,6 @@ test("views_unittests") {
"controls/native/native_view_host_mac_unittest.mm",
"controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm",
"view_unittest_mac.mm",
"widget/ax_native_widget_mac_unittest.mm",
"widget/native_widget_mac_unittest.mm",
"widget/sublevel_manager_mac_unittest.mm",
]
@@ -1415,6 +1430,7 @@ test("views_unittests") {
sources -= [ "controls/native/native_view_host_unittest.cc" ]
public_deps = [
":views_unittests_arc",
"//components/remote_cocoa/app_shim",
"//ui/accelerated_widget_mac",
]

@@ -24,6 +24,10 @@
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/widget.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace views {
namespace {
@@ -164,9 +168,8 @@ class AXNativeWidgetMacTest : public test::WidgetTest {
// on a retained accessibility object after the source view is deleted.
TEST_F(AXNativeWidgetMacTest, Lifetime) {
Textfield* view = AddChildTextfield(widget()->GetContentsView()->size());
base::scoped_nsobject<NSObject> ax_node(view->GetNativeViewAccessible(),
base::scoped_policy::RETAIN);
id<NSAccessibility> ax_obj = ToNSAccessibility(ax_node.get());
NSObject* ax_node = view->GetNativeViewAccessible();
id<NSAccessibility> ax_obj = ToNSAccessibility(ax_node);
EXPECT_TRUE(AXObjectHandlesSelector(ax_obj, @selector(accessibilityValue)));
EXPECT_NSEQ(kTestStringValue, ax_obj.accessibilityValue);
@@ -190,12 +193,11 @@ TEST_F(AXNativeWidgetMacTest, Lifetime) {
// The only usually available array attribute is AXChildren, so go up a level
// to the Widget to test that a bit. The default implementation just gets the
// attribute normally and returns its size (if it's an array).
base::scoped_nsprotocol<id<NSAccessibility>> ax_parent(
ax_obj.accessibilityParent, base::scoped_policy::RETAIN);
id<NSAccessibility> ax_parent = ax_obj.accessibilityParent;
// There are two children: a NativeFrameView and the TextField.
EXPECT_EQ(2u, ax_parent.get().accessibilityChildren.count);
EXPECT_EQ(ax_node.get(), ax_parent.get().accessibilityChildren[1]);
EXPECT_EQ(2u, ax_parent.accessibilityChildren.count);
EXPECT_EQ(ax_node, ax_parent.accessibilityChildren[1]);
// If it is not an array, the default implementation throws an exception, so
// it's impossible to test these methods further on |ax_node|, apart from the
@@ -230,7 +232,7 @@ TEST_F(AXNativeWidgetMacTest, Lifetime) {
// The Widget is currently still around, but the TextField should be gone,
// leaving just the NativeFrameView.
EXPECT_EQ(1u, ax_parent.get().accessibilityChildren.count);
EXPECT_EQ(1u, ax_parent.accessibilityChildren.count);
}
// Check that potentially keyboard-focusable elements are always leaf nodes.
@@ -687,8 +689,8 @@ TEST_F(AXNativeWidgetMacTest, ProtectedTextfields) {
EXPECT_TRUE(ax_node);
// Create a native Cocoa NSSecureTextField to compare against.
base::scoped_nsobject<NSSecureTextField> cocoa_secure_textfield(
[[NSSecureTextField alloc] initWithFrame:NSMakeRect(0, 0, 10, 10)]);
NSSecureTextField* cocoa_secure_textfield =
[[NSSecureTextField alloc] initWithFrame:NSMakeRect(0, 0, 10, 10)];
const SEL expected_supported_selectors[] = {
@selector(accessibilityValue),
@@ -702,7 +704,7 @@ TEST_F(AXNativeWidgetMacTest, ProtectedTextfields) {
for (auto* sel : expected_supported_selectors) {
EXPECT_TRUE(AXObjectHandlesSelector(ax_node, sel));
EXPECT_TRUE(AXObjectHandlesSelector(cocoa_secure_textfield.get(), sel));
EXPECT_TRUE(AXObjectHandlesSelector(cocoa_secure_textfield, sel));
}
// TODO(https://crbug.com/939965): This should assert the same behavior of