diff --git a/content/browser/accessibility/browser_accessibility_cocoa.h b/content/browser/accessibility/browser_accessibility_cocoa.h index acdffbaf3c0a8..7da79adb84053 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.h +++ b/content/browser/accessibility/browser_accessibility_cocoa.h @@ -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 diff --git a/content/browser/accessibility/browser_accessibility_mac.mm b/content/browser/accessibility/browser_accessibility_mac.mm index 17e743e73b279..b5b7dc8bbad6a 100644 --- a/content/browser/accessibility/browser_accessibility_mac.mm +++ b/content/browser/accessibility/browser_accessibility_mac.mm @@ -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. diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn index d15a912121466..09ecbb4fe62e6 100644 --- a/content/public/browser/BUILD.gn +++ b/content/public/browser/BUILD.gn @@ -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", diff --git a/content/public/browser/ax_inspect_factory_mac.mm b/content/public/browser/ax_inspect_factory_mac.mm index ae73990290c94..a8c5a452479f5 100644 --- a/content/public/browser/ax_inspect_factory_mac.mm +++ b/content/public/browser/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 diff --git a/content/public/browser/native_event_processor_observer_mac.mm b/content/public/browser/native_event_processor_observer_mac.mm index b378c054d899d..96f6843d6cd21 100644 --- a/content/public/browser/native_event_processor_observer_mac.mm +++ b/content/public/browser/native_event_processor_observer_mac.mm @@ -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_); } } diff --git a/ui/accessibility/platform/BUILD.gn b/ui/accessibility/platform/BUILD.gn index c9777e07fdd31..7b3d41de1be24 100644 --- a/ui/accessibility/platform/BUILD.gn +++ b/ui/accessibility/platform/BUILD.gn @@ -243,6 +243,8 @@ component("platform") { "inspect/ax_tree_indexer_mac.h", ] + configs += [ "//build/config/compiler:enable_arc" ] + frameworks = [ "AppKit.framework", "Foundation.framework", diff --git a/ui/accessibility/platform/ax_event_intent_mac.h b/ui/accessibility/platform/ax_event_intent_mac.h index 7e714be174118..bf128c887807e 100644 --- a/ui/accessibility/platform/ax_event_intent_mac.h +++ b/ui/accessibility/platform/ax_event_intent_mac.h @@ -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); diff --git a/ui/accessibility/platform/ax_event_intent_mac.mm b/ui/accessibility/platform/ax_event_intent_mac.mm index a6169800846be..de8d4ba95949f 100644 --- a/ui/accessibility/platform/ax_event_intent_mac.mm +++ b/ui/accessibility/platform/ax_event_intent_mac.mm @@ -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; diff --git a/ui/accessibility/platform/ax_platform_node_cocoa.h b/ui/accessibility/platform/ax_platform_node_cocoa.h index c28aea7e84b37..e2e62973571e6 100644 --- a/ui/accessibility/platform/ax_platform_node_cocoa.h +++ b/ui/accessibility/platform/ax_platform_node_cocoa.h @@ -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; diff --git a/ui/accessibility/platform/ax_platform_node_cocoa.mm b/ui/accessibility/platform/ax_platform_node_cocoa.mm index a04de4da7b806..16de7b843b122 100644 --- a/ui/accessibility/platform/ax_platform_node_cocoa.mm +++ b/ui/accessibility/platform/ax_platform_node_cocoa.mm @@ -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; diff --git a/ui/accessibility/platform/ax_platform_node_mac.h b/ui/accessibility/platform/ax_platform_node_mac.h index c6d2d132782bc..563bcc94b8896 100644 --- a/ui/accessibility/platform/ax_platform_node_mac.h +++ b/ui/accessibility/platform/ax_platform_node_mac.h @@ -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 diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm index c95135eb2fa2c..5747307d3353b 100644 --- a/ui/accessibility/platform/ax_platform_node_mac.mm +++ b/ui/accessibility/platform/ax_platform_node_mac.mm @@ -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) { diff --git a/ui/accessibility/platform/ax_private_webkit_constants_mac.h b/ui/accessibility/platform/ax_private_webkit_constants_mac.h index dd96ad704242a..295b09672270e 100644 --- a/ui/accessibility/platform/ax_private_webkit_constants_mac.h +++ b/ui/accessibility/platform/ax_private_webkit_constants_mac.h @@ -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 { diff --git a/ui/accessibility/platform/ax_private_webkit_constants_mac.mm b/ui/accessibility/platform/ax_private_webkit_constants_mac.mm index 0ca130e5758ba..2521cac258f30 100644 --- a/ui/accessibility/platform/ax_private_webkit_constants_mac.mm +++ b/ui/accessibility/platform/ax_private_webkit_constants_mac.mm @@ -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) { diff --git a/ui/accessibility/platform/ax_utils_mac.h b/ui/accessibility/platform/ax_utils_mac.h index e572c5433e44f..0b5c9df93f2b6 100644 --- a/ui/accessibility/platform/ax_utils_mac.h +++ b/ui/accessibility/platform/ax_utils_mac.h @@ -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); diff --git a/ui/accessibility/platform/ax_utils_mac.mm b/ui/accessibility/platform/ax_utils_mac.mm index 41acc0600c9ff..b9f9b8b799d8c 100644 --- a/ui/accessibility/platform/ax_utils_mac.mm +++ b/ui/accessibility/platform/ax_utils_mac.mm @@ -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 diff --git a/ui/accessibility/platform/inspect/ax_call_statement_invoker_mac.h b/ui/accessibility/platform/inspect/ax_call_statement_invoker_mac.h index 2f3ec4f536df1..2c3ec0447f42e 100644 --- a/ui/accessibility/platform/inspect/ax_call_statement_invoker_mac.h +++ b/ui/accessibility/platform/inspect/ax_call_statement_invoker_mac.h @@ -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. diff --git a/ui/accessibility/platform/inspect/ax_call_statement_invoker_mac.mm b/ui/accessibility/platform/inspect/ax_call_statement_invoker_mac.mm index c0b0a5a96fcff..db66358f4a242 100644 --- a/ui/accessibility/platform/inspect/ax_call_statement_invoker_mac.mm +++ b/ui/accessibility/platform/inspect/ax_call_statement_invoker_mac.mm @@ -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") diff --git a/ui/accessibility/platform/inspect/ax_element_wrapper_mac.h b/ui/accessibility/platform/inspect/ax_element_wrapper_mac.h index c803de011ab18..59060ebf887a9 100644 --- a/ui/accessibility/platform/inspect/ax_element_wrapper_mac.h +++ b/ui/accessibility/platform/inspect/ax_element_wrapper_mac.h @@ -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 diff --git a/ui/accessibility/platform/inspect/ax_element_wrapper_mac.mm b/ui/accessibility/platform/inspect/ax_element_wrapper_mac.mm index c95a42e0622e2..1e6dbe4af6b10 100644 --- a/ui/accessibility/platform/inspect/ax_element_wrapper_mac.mm +++ b/ui/accessibility/platform/inspect/ax_element_wrapper_mac.mm @@ -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; } diff --git a/ui/accessibility/platform/inspect/ax_event_recorder_mac.mm b/ui/accessibility/platform/inspect/ax_event_recorder_mac.mm index f20644c755ed5..95638f1dabace 100644 --- a/ui/accessibility/platform/inspect/ax_event_recorder_mac.mm +++ b/ui/accessibility/platform/inspect/ax_event_recorder_mac.mm @@ -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. diff --git a/ui/accessibility/platform/inspect/ax_inspect_utils_mac.h b/ui/accessibility/platform/inspect/ax_inspect_utils_mac.h index eaa46518b65cc..c5abbd3b2267c 100644 --- a/ui/accessibility/platform/inspect/ax_inspect_utils_mac.h +++ b/ui/accessibility/platform/inspect/ax_inspect_utils_mac.h @@ -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 diff --git a/ui/accessibility/platform/inspect/ax_inspect_utils_mac.mm b/ui/accessibility/platform/inspect/ax_inspect_utils_mac.mm index 127f0b02184c3..5b64e5ebb134a 100644 --- a/ui/accessibility/platform/inspect/ax_inspect_utils_mac.mm +++ b/ui/accessibility/platform/inspect/ax_inspect_utils_mac.mm @@ -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 diff --git a/ui/accessibility/platform/inspect/ax_transform_mac.mm b/ui/accessibility/platform/inspect/ax_transform_mac.mm index 7bcf2eaaffc7f..fa8915da42d7c 100644 --- a/ui/accessibility/platform/inspect/ax_transform_mac.mm +++ b/ui/accessibility/platform/inspect/ax_transform_mac.mm @@ -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; } diff --git a/ui/accessibility/platform/inspect/ax_tree_formatter_mac.mm b/ui/accessibility/platform/inspect/ax_tree_formatter_mac.mm index d721c0546712f..94fe665af164a 100644 --- a/ui/accessibility/platform/inspect/ax_tree_formatter_mac.mm +++ b/ui/accessibility/platform/inspect/ax_tree_formatter_mac.mm @@ -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; diff --git a/ui/accessibility/platform/inspect/ax_tree_indexer_mac.h b/ui/accessibility/platform/inspect/ax_tree_indexer_mac.h index ee04f566e0a5c..47933d170782d 100644 --- a/ui/accessibility/platform/inspect/ax_tree_indexer_mac.h +++ b/ui/accessibility/platform/inspect/ax_tree_indexer_mac.h @@ -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)); diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index be0ebe3e2da94..416497c77970e 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn @@ -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", ] diff --git a/ui/views/widget/ax_native_widget_mac_unittest.mm b/ui/views/widget/ax_native_widget_mac_unittest.mm index 1075c0fb6e1c6..40dac631d6dc6 100644 --- a/ui/views/widget/ax_native_widget_mac_unittest.mm +++ b/ui/views/widget/ax_native_widget_mac_unittest.mm @@ -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