iOS: Migrate accessibility_bridge to ARC (flutter/engine#55570)

Keeps fml::scoped_* wrappers used in C++ class declarations in headers, since those are injected into both ARC and non-ARC translation units and these classes are ARC-safe. Once we've migrated all users of those headers to ARC, we can use the underlying classes directly.

No semantic changes, therefore not changes to tests.

Issue: https://github.com/flutter/flutter/issues/137801

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
Chris Bracken 2024-10-02 08:51:54 -07:00 committed by GitHub
parent c2ab019879
commit 86626a85fb
3 changed files with 24 additions and 25 deletions

View File

@ -112,6 +112,8 @@ source_set("flutter_framework_source_arc") {
"framework/Source/TextInputSemanticsObject.mm", "framework/Source/TextInputSemanticsObject.mm",
"framework/Source/UIViewController+FlutterScreenAndSceneIfLoaded.h", "framework/Source/UIViewController+FlutterScreenAndSceneIfLoaded.h",
"framework/Source/UIViewController+FlutterScreenAndSceneIfLoaded.mm", "framework/Source/UIViewController+FlutterScreenAndSceneIfLoaded.mm",
"framework/Source/accessibility_bridge.h",
"framework/Source/accessibility_bridge.mm",
"framework/Source/connection_collection.h", "framework/Source/connection_collection.h",
"framework/Source/connection_collection.mm", "framework/Source/connection_collection.mm",
"framework/Source/overlay_layer_pool.h", "framework/Source/overlay_layer_pool.h",
@ -188,8 +190,6 @@ source_set("flutter_framework_source") {
"framework/Source/FlutterEngine_Internal.h", "framework/Source/FlutterEngine_Internal.h",
"framework/Source/FlutterViewController.mm", "framework/Source/FlutterViewController.mm",
"framework/Source/FlutterViewController_Internal.h", "framework/Source/FlutterViewController_Internal.h",
"framework/Source/accessibility_bridge.h",
"framework/Source/accessibility_bridge.mm",
"platform_view_ios.h", "platform_view_ios.h",
"platform_view_ios.mm", "platform_view_ios.mm",
] ]

View File

@ -97,6 +97,9 @@ class AccessibilityBridge final : public AccessibilityBridgeIos {
// been focused or the focus is currently outside of the flutter application // been focused or the focus is currently outside of the flutter application
// (i.e. the status bar or keyboard) // (i.e. the status bar or keyboard)
int32_t last_focused_semantics_object_id_; int32_t last_focused_semantics_object_id_;
// TODO(cbracken): https://github.com/flutter/flutter/issues/137801
// Eliminate use of fml::scoped_* wrappers here.
fml::scoped_nsobject<NSMutableDictionary<NSNumber*, SemanticsObject*>> objects_; fml::scoped_nsobject<NSMutableDictionary<NSNumber*, SemanticsObject*>> objects_;
fml::scoped_nsprotocol<FlutterBasicMessageChannel*> accessibility_channel_; fml::scoped_nsprotocol<FlutterBasicMessageChannel*> accessibility_channel_;
int32_t previous_route_id_ = 0; int32_t previous_route_id_ = 0;

View File

@ -14,7 +14,7 @@
#pragma GCC diagnostic error "-Wundeclared-selector" #pragma GCC diagnostic error "-Wundeclared-selector"
FLUTTER_ASSERT_NOT_ARC FLUTTER_ASSERT_ARC
namespace flutter { namespace flutter {
namespace { namespace {
@ -101,14 +101,13 @@ void AccessibilityBridge::UpdateSemantics(
needsAnnouncement = [object nodeShouldTriggerAnnouncement:&node]; needsAnnouncement = [object nodeShouldTriggerAnnouncement:&node];
[object setSemanticsNode:&node]; [object setSemanticsNode:&node];
NSUInteger newChildCount = node.childrenInTraversalOrder.size(); NSUInteger newChildCount = node.childrenInTraversalOrder.size();
NSMutableArray* newChildren = NSMutableArray* newChildren = [[NSMutableArray alloc] initWithCapacity:newChildCount];
[[[NSMutableArray alloc] initWithCapacity:newChildCount] autorelease];
for (NSUInteger i = 0; i < newChildCount; ++i) { for (NSUInteger i = 0; i < newChildCount; ++i) {
SemanticsObject* child = GetOrCreateObject(node.childrenInTraversalOrder[i], nodes); SemanticsObject* child = GetOrCreateObject(node.childrenInTraversalOrder[i], nodes);
[newChildren addObject:child]; [newChildren addObject:child];
} }
NSMutableArray* newChildrenInHitTestOrder = NSMutableArray* newChildrenInHitTestOrder =
[[[NSMutableArray alloc] initWithCapacity:newChildCount] autorelease]; [[NSMutableArray alloc] initWithCapacity:newChildCount];
for (NSUInteger i = 0; i < newChildCount; ++i) { for (NSUInteger i = 0; i < newChildCount; ++i) {
SemanticsObject* child = GetOrCreateObject(node.childrenInHitTestOrder[i], nodes); SemanticsObject* child = GetOrCreateObject(node.childrenInHitTestOrder[i], nodes);
[newChildrenInHitTestOrder addObject:child]; [newChildrenInHitTestOrder addObject:child];
@ -117,7 +116,7 @@ void AccessibilityBridge::UpdateSemantics(
object.childrenInHitTestOrder = newChildrenInHitTestOrder; object.childrenInHitTestOrder = newChildrenInHitTestOrder;
if (!node.customAccessibilityActions.empty()) { if (!node.customAccessibilityActions.empty()) {
NSMutableArray<FlutterCustomAccessibilityAction*>* accessibilityCustomActions = NSMutableArray<FlutterCustomAccessibilityAction*>* accessibilityCustomActions =
[[[NSMutableArray alloc] init] autorelease]; [[NSMutableArray alloc] init];
for (int32_t action_id : node.customAccessibilityActions) { for (int32_t action_id : node.customAccessibilityActions) {
flutter::CustomAccessibilityAction& action = actions_[action_id]; flutter::CustomAccessibilityAction& action = actions_[action_id];
if (action.overrideId != -1) { if (action.overrideId != -1) {
@ -128,9 +127,9 @@ void AccessibilityBridge::UpdateSemantics(
NSString* label = @(action.label.data()); NSString* label = @(action.label.data());
SEL selector = @selector(onCustomAccessibilityAction:); SEL selector = @selector(onCustomAccessibilityAction:);
FlutterCustomAccessibilityAction* customAction = FlutterCustomAccessibilityAction* customAction =
[[[FlutterCustomAccessibilityAction alloc] initWithName:label [[FlutterCustomAccessibilityAction alloc] initWithName:label
target:object target:object
selector:selector] autorelease]; selector:selector];
customAction.uid = action_id; customAction.uid = action_id;
[accessibilityCustomActions addObject:customAction]; [accessibilityCustomActions addObject:customAction];
} }
@ -143,14 +142,13 @@ void AccessibilityBridge::UpdateSemantics(
// interrupting system notifications or other elements. // interrupting system notifications or other elements.
// Expectation: roughly match the behavior of polite announcements on // Expectation: roughly match the behavior of polite announcements on
// Android. // Android.
NSString* announcement = NSString* announcement = [[NSString alloc] initWithUTF8String:object.node.label.c_str()];
[[[NSString alloc] initWithUTF8String:object.node.label.c_str()] autorelease];
UIAccessibilityPostNotification( UIAccessibilityPostNotification(
UIAccessibilityAnnouncementNotification, UIAccessibilityAnnouncementNotification,
[[[NSAttributedString alloc] initWithString:announcement [[NSAttributedString alloc] initWithString:announcement
attributes:@{ attributes:@{
UIAccessibilitySpeechAttributeQueueAnnouncement : @YES UIAccessibilitySpeechAttributeQueueAnnouncement : @YES
}] autorelease]); }]);
} }
} }
@ -164,7 +162,7 @@ void AccessibilityBridge::UpdateSemantics(
view_controller_.view.accessibilityElements = view_controller_.view.accessibilityElements =
@[ [root accessibilityContainer] ?: [NSNull null] ]; @[ [root accessibilityContainer] ?: [NSNull null] ];
} }
NSMutableArray<SemanticsObject*>* newRoutes = [[[NSMutableArray alloc] init] autorelease]; NSMutableArray<SemanticsObject*>* newRoutes = [[NSMutableArray alloc] init];
[root collectRoutes:newRoutes]; [root collectRoutes:newRoutes];
// Finds the last route that is not in the previous routes. // Finds the last route that is not in the previous routes.
for (SemanticsObject* route in newRoutes) { for (SemanticsObject* route in newRoutes) {
@ -255,7 +253,6 @@ static void ReplaceSemanticsObject(SemanticsObject* oldObject,
FML_DCHECK(oldObject.node.id == newObject.uid); FML_DCHECK(oldObject.node.id == newObject.uid);
NSNumber* nodeId = @(oldObject.node.id); NSNumber* nodeId = @(oldObject.node.id);
NSUInteger positionInChildlist = [oldObject.parent.children indexOfObject:oldObject]; NSUInteger positionInChildlist = [oldObject.parent.children indexOfObject:oldObject];
[[oldObject retain] autorelease];
oldObject.children = @[]; oldObject.children = @[];
[oldObject.parent replaceChildAtIndex:positionInChildlist withChild:newObject]; [oldObject.parent replaceChildAtIndex:positionInChildlist withChild:newObject];
[objects removeObjectForKey:nodeId]; [objects removeObjectForKey:nodeId];
@ -267,22 +264,21 @@ static SemanticsObject* CreateObject(const flutter::SemanticsNode& node,
if (node.HasFlag(flutter::SemanticsFlags::kIsTextField) && if (node.HasFlag(flutter::SemanticsFlags::kIsTextField) &&
!node.HasFlag(flutter::SemanticsFlags::kIsReadOnly)) { !node.HasFlag(flutter::SemanticsFlags::kIsReadOnly)) {
// Text fields are backed by objects that implement UITextInput. // Text fields are backed by objects that implement UITextInput.
return [[[TextInputSemanticsObject alloc] initWithBridge:weak_ptr uid:node.id] autorelease]; return [[TextInputSemanticsObject alloc] initWithBridge:weak_ptr uid:node.id];
} else if (!node.HasFlag(flutter::SemanticsFlags::kIsInMutuallyExclusiveGroup) && } else if (!node.HasFlag(flutter::SemanticsFlags::kIsInMutuallyExclusiveGroup) &&
(node.HasFlag(flutter::SemanticsFlags::kHasToggledState) || (node.HasFlag(flutter::SemanticsFlags::kHasToggledState) ||
node.HasFlag(flutter::SemanticsFlags::kHasCheckedState))) { node.HasFlag(flutter::SemanticsFlags::kHasCheckedState))) {
return [[[FlutterSwitchSemanticsObject alloc] initWithBridge:weak_ptr uid:node.id] autorelease]; return [[FlutterSwitchSemanticsObject alloc] initWithBridge:weak_ptr uid:node.id];
} else if (node.HasFlag(flutter::SemanticsFlags::kHasImplicitScrolling)) { } else if (node.HasFlag(flutter::SemanticsFlags::kHasImplicitScrolling)) {
return [[[FlutterScrollableSemanticsObject alloc] initWithBridge:weak_ptr return [[FlutterScrollableSemanticsObject alloc] initWithBridge:weak_ptr uid:node.id];
uid:node.id] autorelease];
} else if (node.IsPlatformViewNode()) { } else if (node.IsPlatformViewNode()) {
return [[[FlutterPlatformViewSemanticsContainer alloc] return [[FlutterPlatformViewSemanticsContainer alloc]
initWithBridge:weak_ptr initWithBridge:weak_ptr
uid:node.id uid:node.id
platformView:weak_ptr->GetPlatformViewsController()->GetFlutterTouchInterceptingViewByID( platformView:weak_ptr->GetPlatformViewsController()->GetFlutterTouchInterceptingViewByID(
node.platformViewId)] autorelease]; node.platformViewId)];
} else { } else {
return [[[FlutterSemanticsObject alloc] initWithBridge:weak_ptr uid:node.id] autorelease]; return [[FlutterSemanticsObject alloc] initWithBridge:weak_ptr uid:node.id];
} }
} }