Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 3d6da02

Browse files
author
auto-submit[bot]
committed
Revert "[iOS] Full keyboard access scrolling (#56606)"
This reverts commit 7a8c1e8.
1 parent 0d4d2cc commit 3d6da02

File tree

15 files changed

+25
-295
lines changed

15 files changed

+25
-295
lines changed

lib/ui/semantics.dart

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ class SemanticsAction {
4545
static const int _kMoveCursorBackwardByWordIndex = 1 << 20;
4646
static const int _kSetTextIndex = 1 << 21;
4747
static const int _kFocusIndex = 1 << 22;
48-
static const int _kScrollToOffsetIndex = 1 << 23;
4948
// READ THIS: if you add an action here, you MUST update the
5049
// numSemanticsActions value in testing/dart/semantics_test.dart and
5150
// lib/web_ui/test/engine/semantics/semantics_api_test.dart, or tests
@@ -87,17 +86,6 @@ class SemanticsAction {
8786
/// scrollable.
8887
static const SemanticsAction scrollDown = SemanticsAction._(_kScrollDownIndex, 'scrollDown');
8988

90-
/// A request to scroll the scrollable container to a given scroll offset.
91-
///
92-
/// The payload of this [SemanticsAction] is a flutter-standard-encoded
93-
/// [Float64List] of length 2 containing the target horizontal and vertical
94-
/// offsets (in logical pixels) the receiving scrollable container should
95-
/// scroll to.
96-
///
97-
/// This action is used by iOS Full Keyboard Access to reveal contents that
98-
/// are currently not visible in the viewport.
99-
static const SemanticsAction scrollToOffset = SemanticsAction._(_kScrollToOffsetIndex, 'scrollToOffset');
100-
10189
/// A request to increase the value represented by the semantics node.
10290
///
10391
/// For example, this action might be recognized by a slider control.
@@ -277,7 +265,6 @@ class SemanticsAction {
277265
_kScrollRightIndex: scrollRight,
278266
_kScrollUpIndex: scrollUp,
279267
_kScrollDownIndex: scrollDown,
280-
_kScrollToOffsetIndex: scrollToOffset,
281268
_kIncreaseIndex: increase,
282269
_kDecreaseIndex: decrease,
283270
_kShowOnScreenIndex: showOnScreen,
@@ -777,7 +764,7 @@ base class LocaleStringAttribute extends StringAttribute {
777764
_initLocaleStringAttribute(this, range.start, range.end, locale.toLanguageTag());
778765
}
779766

780-
/// The language of this attribute.
767+
/// The lanuage of this attribute.
781768
final Locale locale;
782769

783770
@Native<Void Function(Handle, Int32, Int32, Handle)>(symbol: 'NativeStringAttribute::initLocaleStringAttribute')

lib/ui/semantics/semantics_node.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ enum class SemanticsAction : int32_t {
4343
kMoveCursorBackwardByWord = 1 << 20,
4444
kSetText = 1 << 21,
4545
kFocus = 1 << 22,
46-
kScrollToOffset = 1 << 23,
4746
};
4847

4948
const int kVerticalScrollSemanticsActions =

lib/web_ui/lib/semantics.dart

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,13 @@ class SemanticsAction {
3333
static const int _kMoveCursorBackwardByWordIndex = 1 << 20;
3434
static const int _kSetTextIndex = 1 << 21;
3535
static const int _kFocusIndex = 1 << 22;
36-
static const int _kScrollToOffsetIndex = 1 << 23;
3736

3837
static const SemanticsAction tap = SemanticsAction._(_kTapIndex, 'tap');
3938
static const SemanticsAction longPress = SemanticsAction._(_kLongPressIndex, 'longPress');
4039
static const SemanticsAction scrollLeft = SemanticsAction._(_kScrollLeftIndex, 'scrollLeft');
4140
static const SemanticsAction scrollRight = SemanticsAction._(_kScrollRightIndex, 'scrollRight');
4241
static const SemanticsAction scrollUp = SemanticsAction._(_kScrollUpIndex, 'scrollUp');
4342
static const SemanticsAction scrollDown = SemanticsAction._(_kScrollDownIndex, 'scrollDown');
44-
static const SemanticsAction scrollToOffset = SemanticsAction._(_kScrollToOffsetIndex, 'scrollToOffset');
4543
static const SemanticsAction increase = SemanticsAction._(_kIncreaseIndex, 'increase');
4644
static const SemanticsAction decrease = SemanticsAction._(_kDecreaseIndex, 'decrease');
4745
static const SemanticsAction showOnScreen = SemanticsAction._(_kShowOnScreenIndex, 'showOnScreen');
@@ -67,7 +65,6 @@ class SemanticsAction {
6765
_kScrollRightIndex: scrollRight,
6866
_kScrollUpIndex: scrollUp,
6967
_kScrollDownIndex: scrollDown,
70-
_kScrollToOffsetIndex: scrollToOffset,
7168
_kIncreaseIndex: increase,
7269
_kDecreaseIndex: decrease,
7370
_kShowOnScreenIndex: showOnScreen,

lib/web_ui/test/engine/semantics/semantics_api_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ void testMain() {
2929
});
3030

3131
// This must match the number of actions in lib/ui/semantics.dart
32-
const int numSemanticsActions = 24;
32+
const int numSemanticsActions = 23;
3333
test('SemanticsAction.values refers to all actions.', () async {
3434
expect(SemanticsAction.values.length, equals(numSemanticsActions));
3535
for (int index = 0; index < numSemanticsActions; ++index) {

shell/platform/android/io/flutter/view/AccessibilityBridge.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2120,8 +2120,7 @@ public enum Action {
21202120
MOVE_CURSOR_FORWARD_BY_WORD(1 << 19),
21212121
MOVE_CURSOR_BACKWARD_BY_WORD(1 << 20),
21222122
SET_TEXT(1 << 21),
2123-
FOCUS(1 << 22),
2124-
SCROLL_TO_OFFSET(1 << 23);
2123+
FOCUS(1 << 22);
21252124

21262125
public final int value;
21272126

shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,10 @@ NS_ASSUME_NONNULL_BEGIN
1818
* sends all of selector calls from accessibility services to the
1919
* owner SemanticsObject.
2020
*/
21-
@interface FlutterSemanticsScrollView : UIScrollView <UIScrollViewDelegate>
21+
@interface FlutterSemanticsScrollView : UIScrollView
2222

2323
@property(nonatomic, weak, nullable) SemanticsObject* semanticsObject;
2424

25-
/// Whether this scroll view's content offset is actively being updated by UIKit
26-
/// or other the system services.
27-
///
28-
/// This flag is set by the `FlutterSemanticsScrollView` itself, typically in
29-
/// one of the `UIScrollViewDelegate` methods.
30-
///
31-
/// When this flag is true, the `SemanticsObject` implementation ignores all
32-
/// content offset updates coming from the Flutter framework, to prevent
33-
/// potential feedback loops (especially when the framework is only echoing
34-
/// the new content offset back to this scroll view).
35-
///
36-
/// For example, to scroll a scrollable container with iOS full keyboard access,
37-
/// the iOS focus system uses a display link to scroll the container to the
38-
/// desired offset animatedly. If the user changes the scroll offset during the
39-
/// animation, the display link will be invalidated and the scrolling animation
40-
/// will be interrupted. For simplicity, content offset updates coming from the
41-
/// framework will be ignored in the relatively short animation duration (~1s),
42-
/// allowing the scrolling animation to finish.
43-
@property(nonatomic, readonly) BOOL isDoingSystemScrolling;
44-
4525
- (instancetype)init NS_UNAVAILABLE;
4626
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
4727
- (instancetype)initWithCoder:(NSCoder*)coder NS_UNAVAILABLE;

shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ - (instancetype)initWithSemanticsObject:(SemanticsObject*)semanticsObject {
1515
self = [super initWithFrame:CGRectZero];
1616
if (self) {
1717
_semanticsObject = semanticsObject;
18-
_isDoingSystemScrolling = NO;
19-
self.delegate = self;
2018
}
2119
return self;
2220
}
@@ -107,14 +105,4 @@ - (NSInteger)accessibilityElementCount {
107105
return self.semanticsObject.children.count;
108106
}
109107

110-
- (void)scrollViewWillEndDragging:(UIScrollView*)scrollView
111-
withVelocity:(CGPoint)velocity
112-
targetContentOffset:(inout CGPoint*)targetContentOffset {
113-
_isDoingSystemScrolling = YES;
114-
}
115-
116-
- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView {
117-
_isDoingSystemScrolling = NO;
118-
}
119-
120108
@end

shell/platform/darwin/ios/framework/Source/SemanticsObject+UIFocusSystem.mm

Lines changed: 6 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33
// found in the LICENSE file.
44

55
#import "SemanticsObject.h"
6-
#include "flutter/lib/ui/semantics/semantics_node.h"
7-
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterCodecs.h"
86
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
9-
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h"
107

118
FLUTTER_ASSERT_ARC
129

@@ -30,19 +27,10 @@
3027
// translated to calls such as -[NSObject accessibilityActivate]), while most
3128
// other key events are dispatched to the framework.
3229
@interface SemanticsObject (UIFocusSystem) <UIFocusItem, UIFocusItemContainer>
33-
/// The `UIFocusItem` that represents this SemanticsObject.
34-
///
35-
/// For regular `SemanticsObject`s, this method returns `self`,
36-
/// for `FlutterScrollableSemanticsObject`s, this method returns its scroll view.
37-
- (id<UIFocusItem>)focusItem;
3830
@end
3931

4032
@implementation SemanticsObject (UIFocusSystem)
4133

42-
- (id<UIFocusItem>)focusItem {
43-
return self;
44-
}
45-
4634
#pragma mark - UIFocusEnvironment Conformance
4735

4836
- (void)setNeedsFocusUpdate {
@@ -61,7 +49,7 @@ - (void)didUpdateFocusInContext:(UIFocusUpdateContext*)context
6149

6250
- (id<UIFocusEnvironment>)parentFocusEnvironment {
6351
// The root SemanticsObject node's parent is the FlutterView.
64-
return self.parent.focusItem ?: self.bridge->view();
52+
return self.parent ?: self.bridge->view();
6553
}
6654

6755
- (NSArray<id<UIFocusEnvironment>>*)preferredFocusEnvironments {
@@ -83,57 +71,8 @@ - (BOOL)canBecomeFocused {
8371
return self.node.HasAction(flutter::SemanticsAction::kTap);
8472
}
8573

86-
// The frame is described in the `coordinateSpace` of the
87-
// `parentFocusEnvironment` (all `parentFocusEnvironment`s are `UIFocusItem`s).
88-
//
89-
// See also the `coordinateSpace` implementation.
90-
// TODO(LongCatIsLooong): use CoreGraphics types.
9174
- (CGRect)frame {
92-
SkPoint quad[4] = {SkPoint::Make(self.node.rect.left(), self.node.rect.top()),
93-
SkPoint::Make(self.node.rect.left(), self.node.rect.bottom()),
94-
SkPoint::Make(self.node.rect.right(), self.node.rect.top()),
95-
SkPoint::Make(self.node.rect.right(), self.node.rect.bottom())};
96-
97-
SkM44 transform = self.node.transform;
98-
FlutterSemanticsScrollView* scrollView;
99-
for (SemanticsObject* ancestor = self.parent; ancestor; ancestor = ancestor.parent) {
100-
if ([ancestor isKindOfClass:[FlutterScrollableSemanticsObject class]]) {
101-
scrollView = ((FlutterScrollableSemanticsObject*)ancestor).scrollView;
102-
break;
103-
}
104-
transform = ancestor.node.transform * transform;
105-
}
106-
107-
for (auto& vertex : quad) {
108-
SkV4 vector = transform.map(vertex.x(), vertex.y(), 0, 1);
109-
vertex = SkPoint::Make(vector.x / vector.w, vector.y / vector.w);
110-
}
111-
112-
SkRect rect;
113-
rect.setBounds(quad, 4);
114-
// If this UIFocusItemContainer's coordinateSpace is a UIScrollView, offset
115-
// the rect by `contentOffset` because the contentOffset translation is
116-
// incorporated into the paint transform at different node depth in UIKit
117-
// and Flutter. In Flutter, the translation is added to the cells
118-
// while in UIKit the viewport's bounds is manipulated (IOW, each cell's frame
119-
// in the UIScrollView coordinateSpace does not change when the UIScrollView
120-
// scrolls).
121-
CGRect unscaledRect =
122-
CGRectMake(rect.x() + scrollView.bounds.origin.x, rect.y() + scrollView.bounds.origin.y,
123-
rect.width(), rect.height());
124-
if (scrollView) {
125-
return unscaledRect;
126-
}
127-
// `rect` could be in physical pixels since the root RenderObject ("RenderView")
128-
// applies a transform that turns logical pixels to physical pixels. Undo the
129-
// transform by dividing the coordinates by the screen's scale factor, if this
130-
// UIFocusItem's reported `coordinateSpace` is the root view (which means this
131-
// UIFocusItem is not inside of a scroll view).
132-
//
133-
// Screen can be nil if the FlutterView is covered by another native view.
134-
CGFloat scale = (self.bridge->view().window.screen ?: UIScreen.mainScreen).scale;
135-
return CGRectMake(unscaledRect.origin.x / scale, unscaledRect.origin.y / scale,
136-
unscaledRect.size.width / scale, unscaledRect.size.height / scale);
75+
return self.accessibilityFrame;
13776
}
13877

13978
#pragma mark - UIFocusItemContainer Conformance
@@ -148,94 +87,16 @@ - (CGRect)frame {
14887
//
14988
// This method is only supposed to return items within the given
15089
// rect but returning everything in the subtree seems to work fine.
151-
NSMutableArray<id<UIFocusItem>>* reversedItems =
90+
NSMutableArray<SemanticsObject*>* reversedItems =
15291
[[NSMutableArray alloc] initWithCapacity:self.childrenInHitTestOrder.count];
15392
for (NSUInteger i = 0; i < self.childrenInHitTestOrder.count; ++i) {
154-
SemanticsObject* child = self.childrenInHitTestOrder[self.childrenInHitTestOrder.count - 1 - i];
155-
[reversedItems addObject:child.focusItem];
93+
[reversedItems
94+
addObject:self.childrenInHitTestOrder[self.childrenInHitTestOrder.count - 1 - i]];
15695
}
15796
return reversedItems;
15897
}
15998

16099
- (id<UICoordinateSpace>)coordinateSpace {
161-
// A regular SemanticsObject uses the same coordinate space as its parent.
162-
return self.parent.coordinateSpace ?: self.bridge->view();
163-
}
164-
165-
@end
166-
167-
/// Scrollable containers interact with the iOS focus engine using the
168-
/// `UIFocusItemScrollableContainer` protocol. The said protocol (and other focus-related protocols)
169-
/// does not provide means to inform the focus system of layout changes. In order for the focus
170-
/// highlight to update properly as the scroll view scrolls, this implementation incorporates a
171-
/// UIScrollView into the focus hierarchy to workaround the highlight update problem.
172-
///
173-
/// As a result, in the current implementation only scrollable containers and the root node
174-
/// establish their own `coordinateSpace`s. All other `UIFocusItemContainter`s use the same
175-
/// `coordinateSpace` as the containing UIScrollView, or the root `FlutterView`, whichever is
176-
/// closer.
177-
///
178-
/// See also the `frame` method implementation.
179-
#pragma mark - Scrolling
180-
181-
@interface FlutterScrollableSemanticsObject (CoordinateSpace)
182-
@end
183-
184-
@implementation FlutterScrollableSemanticsObject (CoordinateSpace)
185-
- (id<UICoordinateSpace>)coordinateSpace {
186-
// A scrollable SemanticsObject uses the same coordinate space as the scroll view.
187-
// This may not work very well in nested scroll views.
188-
return self.scrollView;
189-
}
190-
191-
- (id<UIFocusItem>)focusItem {
192-
return self.scrollView;
193-
}
194-
195-
@end
196-
197-
@interface FlutterSemanticsScrollView (UIFocusItemScrollableContainer) <
198-
UIFocusItemScrollableContainer>
199-
@end
200-
201-
@implementation FlutterSemanticsScrollView (UIFocusItemScrollableContainer)
202-
203-
#pragma mark - FlutterSemanticsScrollView UIFocusItemScrollableContainer Conformance
204-
205-
- (CGSize)visibleSize {
206-
return self.frame.size;
207-
}
208-
209-
- (void)setContentOffset:(CGPoint)contentOffset {
210-
[super setContentOffset:contentOffset];
211-
// Do no send flutter::SemanticsAction::kScrollToOffset if it's triggered
212-
// by a framework update.
213-
if (![self.semanticsObject isAccessibilityBridgeAlive] || !self.isDoingSystemScrolling) {
214-
return;
215-
}
216-
217-
double offset[2] = {contentOffset.x, contentOffset.y};
218-
FlutterStandardTypedData* offsetData = [FlutterStandardTypedData
219-
typedDataWithFloat64:[NSData dataWithBytes:&offset length:sizeof(offset)]];
220-
NSData* encoded = [[FlutterStandardMessageCodec sharedInstance] encode:offsetData];
221-
self.semanticsObject.bridge->DispatchSemanticsAction(
222-
self.semanticsObject.uid, flutter::SemanticsAction::kScrollToOffset,
223-
fml::MallocMapping::Copy(encoded.bytes, encoded.length));
224-
}
225-
226-
- (BOOL)canBecomeFocused {
227-
return NO;
228-
}
229-
230-
- (id<UIFocusEnvironment>)parentFocusEnvironment {
231-
return self.semanticsObject.parentFocusEnvironment;
232-
}
233-
234-
- (NSArray<id<UIFocusEnvironment>>*)preferredFocusEnvironments {
235-
return nil;
236-
}
237-
238-
- (NSArray<id<UIFocusItem>>*)focusItemsInRect:(CGRect)rect {
239-
return [self.semanticsObject focusItemsInRect:rect];
100+
return self.bridge->view();
240101
}
241102
@end

shell/platform/darwin/ios/framework/Source/SemanticsObject.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include "flutter/fml/macros.h"
1111
#include "flutter/fml/memory/weak_ptr.h"
1212
#include "flutter/lib/ui/semantics/semantics_node.h"
13-
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h"
1413
#import "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge_ios.h"
1514

1615
constexpr int32_t kRootNodeId = 0;
@@ -187,7 +186,7 @@ constexpr float kScrollExtentMaxForInf = 1000;
187186
/// The semantics object for scrollable. This class creates an UIScrollView to interact with the
188187
/// iOS.
189188
@interface FlutterScrollableSemanticsObject : SemanticsObject
190-
@property(nonatomic, readonly) FlutterSemanticsScrollView* scrollView;
189+
191190
@end
192191

193192
/**

shell/platform/darwin/ios/framework/Source/SemanticsObject.mm

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,6 @@ - (instancetype)initWithBridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)br
154154
_scrollView = [[FlutterSemanticsScrollView alloc] initWithSemanticsObject:self];
155155
[_scrollView setShowsHorizontalScrollIndicator:NO];
156156
[_scrollView setShowsVerticalScrollIndicator:NO];
157-
[_scrollView setContentInset:UIEdgeInsetsZero];
158-
[_scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
159157
[self.bridge->view() addSubview:_scrollView];
160158
}
161159
return self;
@@ -176,10 +174,7 @@ - (void)accessibilityBridgeDidFinishUpdate {
176174
// contentOffset is 0.0, only the scroll down action is available.
177175
self.scrollView.frame = self.accessibilityFrame;
178176
self.scrollView.contentSize = [self contentSizeInternal];
179-
// See the documentation on `isDoingSystemScrolling`.
180-
if (!self.scrollView.isDoingSystemScrolling) {
181-
[self.scrollView setContentOffset:self.contentOffsetInternal animated:NO];
182-
}
177+
[self.scrollView setContentOffset:[self contentOffsetInternal] animated:NO];
183178
}
184179

185180
- (id)nativeAccessibility {

0 commit comments

Comments
 (0)