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

Commit c8d40c2

Browse files
committed
addressing comments
1 parent 0193851 commit c8d40c2

15 files changed

+310
-187
lines changed

shell/platform/common/accessibility_bridge.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ AccessibilityBridge::AccessibilityBridge(
2929
AccessibilityBridge::~AccessibilityBridge() {
3030
event_generator_.ReleaseTree();
3131
tree_.RemoveObserver(static_cast<ui::AXTreeObserver*>(this));
32-
id_wrapper_map_.clear();
3332
}
3433

3534
void AccessibilityBridge::AddFlutterSemanticsNodeUpdate(

shell/platform/common/flutter_platform_node_delegate.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class FlutterPlatformNodeDelegate : public ui::AXPlatformNodeDelegateBase {
137137
/// @brief Gets the owner of this platform node delegate. This is useful
138138
/// when you want to get the information surround this platform
139139
/// node delegate, e.g. the global rect of this platform node
140-
/// delegate.
140+
/// delegate. This pointer is only safe in the platform thread.
141141
std::weak_ptr<OwnerBridge> GetOwnerBridge() const;
142142

143143
private:

shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacDelegate.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@
208208
.target = native_node,
209209
.user_info = nil,
210210
});
211-
// Voiceover requires a live region changed notification to actually
211+
// VoiceOver requires a live region changed notification to actually
212212
// announce the live region.
213213
auto live_region_events =
214214
MacOSEventsFromAXEvent(ui::AXEventGenerator::Event::LIVE_REGION_CHANGED, ax_node);

shell/platform/darwin/macos/framework/Source/FlutterEngine.mm

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ - (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine
9696
}
9797

9898
- (NSView*)view {
99+
if (!_flutterEngine.viewController.viewLoaded) {
100+
return nil;
101+
}
99102
return _flutterEngine.viewController.flutterView;
100103
}
101104

@@ -417,7 +420,7 @@ - (void)updateDisplayConfig {
417420
}
418421

419422
- (void)updateWindowMetrics {
420-
if (!_engine) {
423+
if (!_engine || !_viewController.viewLoaded) {
421424
return;
422425
}
423426
NSView* view = _viewController.flutterView;
@@ -453,7 +456,7 @@ - (void)setSemanticsEnabled:(BOOL)enabled {
453456
_semanticsEnabled = enabled;
454457
// We need to remove the accessibility children from flutter view
455458
// before we reset the bridge.
456-
if (!_semanticsEnabled) {
459+
if (!_semanticsEnabled && self.viewController.viewLoaded) {
457460
self.viewController.flutterView.accessibilityChildren = nil;
458461
}
459462
if (!_semanticsEnabled && _bridge) {
@@ -669,6 +672,10 @@ - (void)updateSemanticsCustomActions:(const FlutterSemanticsCustomAction*)action
669672
// Custom action with id = kFlutterSemanticsNodeIdBatchEnd indicates this is
670673
// the end of the update batch.
671674
_bridge->CommitUpdates();
675+
// Accessibility tree can only be used when the view is loaded.
676+
if (!self.viewController.viewLoaded) {
677+
return;
678+
}
672679
// Attaches the accessibility root to the flutter view.
673680
auto root = _bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
674681
if (root) {

shell/platform/darwin/macos/framework/Source/FlutterPlatformNodeDelegateMac.mm

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
gfx::NativeViewAccessible parent = FlutterPlatformNodeDelegate::GetParent();
4848
if (!parent) {
4949
NSCAssert(engine_, @"Flutter engine should not be deallocated");
50+
NSCAssert(engine_.viewController.viewLoaded, @"Flutter view must be loaded");
5051
return engine_.viewController.flutterView;
5152
}
5253
return parent;
@@ -101,22 +102,23 @@
101102
// increasing to bottom-right. Therefore, We need to flip the y coordinate when
102103
// we convert from flutter coordinates to macOS coordinates.
103104
ns_local_bounds.origin.y = -ns_local_bounds.origin.y - ns_local_bounds.size.height;
104-
__strong FlutterEngine* strong_engine = engine_;
105-
NSCAssert(strong_engine, @"Flutter engine should not be deallocated");
105+
106+
NSCAssert(engine_, @"Flutter engine should not be deallocated");
107+
NSCAssert(engine_.viewController.viewLoaded, @"Flutter view must be loaded.");
106108
NSRect ns_view_bounds =
107-
[strong_engine.viewController.flutterView convertRectFromBacking:ns_local_bounds];
108-
NSRect ns_window_bounds = [strong_engine.viewController.flutterView convertRect:ns_view_bounds
109-
toView:nil];
109+
[engine_.viewController.flutterView convertRectFromBacking:ns_local_bounds];
110+
NSRect ns_window_bounds = [engine_.viewController.flutterView convertRect:ns_view_bounds
111+
toView:nil];
110112
NSRect ns_screen_bounds =
111-
[[strong_engine.viewController.flutterView window] convertRectToScreen:ns_window_bounds];
113+
[[engine_.viewController.flutterView window] convertRectToScreen:ns_window_bounds];
112114
gfx::RectF screen_bounds(ns_screen_bounds.origin.x, ns_screen_bounds.origin.y,
113115
ns_screen_bounds.size.width, ns_screen_bounds.size.height);
114116
return screen_bounds;
115117
}
116118

117119
gfx::RectF FlutterPlatformNodeDelegateMac::ConvertBoundsFromScreenToGlobal(
118120
const gfx::RectF& screen_bounds) const {
119-
// The voiceover seems to only accept bounds that are relative to primary screen.
121+
// The VoiceOver seems to only accept bounds that are relative to primary screen.
120122
// Thus, we use [[NSScreen screens] firstObject] instead of [NSScreen mainScreen].
121123
NSScreen* screen = [[NSScreen screens] firstObject];
122124
NSRect primary_screen_bounds = [screen frame];

shell/platform/darwin/macos/framework/Source/FlutterPlatformNodeDelegateMacTest.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
99
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
1010
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformNodeDelegateMac.h"
11+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObject.h"
1112
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h"
1213
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
13-
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObject.h"
1414

1515
#include "flutter/shell/platform/common/accessibility_bridge.h"
1616
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"

shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* editing classes, via system channels.
1818
*
1919
* This is not an FlutterPlugin since it needs access to FlutterViewController internals, so needs
20-
* to be managed differently. The FlutterViewController has the ownership of this plugin.
20+
* to be managed differently.
2121
*
2222
* When accessibility is on, accessibility bridge creates a native text field, i.e.
2323
* FlutterTextField, for every text field in the Flutter. This plugin acts as a field editor for
@@ -26,7 +26,7 @@
2626
@interface FlutterTextInputPlugin : NSTextView <FlutterKeySecondaryResponder>
2727

2828
/**
29-
* The native text field this backed by this plugin as its field editor.
29+
* The native text field that currently has this plugin as its field editor.
3030
*
3131
* Must be nil if accessibility is off.
3232
*/
@@ -38,10 +38,10 @@
3838
- (instancetype)initWithViewController:(FlutterViewController*)viewController;
3939

4040
/**
41-
* Where this plugin is the first responder of this NSWindow.
41+
* Whether this plugin is the first responder of this NSWindow.
4242
*
4343
* When accessibility is on, this plugin is set as the first responder to act as the field
44-
* editor for FlutterTextField client.
44+
* editor for FlutterTextFields.
4545
*
4646
* Returns false if accessibility is off.
4747
*/

shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm

Lines changed: 51 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,20 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;
135135
*/
136136
- (void)setEditingState:(NSDictionary*)state;
137137

138+
/**
139+
* Informs the Flutter framework of changes to the text input model's state.
140+
*/
141+
- (void)updateEditState;
142+
143+
/**
144+
* Updates the stringValue and selectedRange that stored in the NSTextView interface
145+
* that this plugin inherits from.
146+
*
147+
* If there is a FlutterTextField uses this plugin as its field editor, this method
148+
* will update the stringValue and selectedRange through the API of the FlutterTextField.
149+
*/
150+
- (void)updateTextAndSelection;
151+
138152
@end
139153

140154
@implementation FlutterTextInputPlugin {
@@ -163,6 +177,11 @@ - (instancetype)initWithViewController:(FlutterViewController*)viewController {
163177
binaryMessenger:viewController.engine.binaryMessenger
164178
codec:[FlutterJSONMethodCodec sharedInstance]];
165179
_shown = FALSE;
180+
// NSTextView does not support _weak reference, so we have to
181+
// use __unsafe_unretained and manage the reference ourselves.
182+
//
183+
// Since we will nil the handler in dealloc. the weakSelf should
184+
// be valid if the handler is ever called.
166185
__unsafe_unretained FlutterTextInputPlugin* weakSelf = self;
167186
[_channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
168187
[weakSelf handleMethodCall:call result:result];
@@ -181,8 +200,10 @@ - (instancetype)initWithViewController:(FlutterViewController*)viewController {
181200
}
182201

183202
- (BOOL)isFirstResponder {
184-
FlutterAppDelegate* appDelegate = (FlutterAppDelegate*)[NSApp delegate];
185-
return [appDelegate.mainFlutterWindow firstResponder] == self;
203+
if (!self.flutterViewController.viewLoaded || !self.flutterViewController.view.window) {
204+
return false;
205+
}
206+
return [self.flutterViewController.view.window firstResponder] == self;
186207
}
187208

188209
- (void)dealloc {
@@ -298,15 +319,10 @@ - (void)setEditingState:(NSDictionary*)state {
298319
state[kComposingBaseKey], state[kComposingExtentKey], _activeModel->composing_range());
299320
size_t cursor_offset = selected_range.base() - composing_range.start();
300321
_activeModel->SetComposingRange(composing_range, cursor_offset);
301-
if (_client) {
302-
[_client becomeFirstResponder];
303-
}
322+
[_client becomeFirstResponder];
304323
[self updateTextAndSelection];
305324
}
306325

307-
/**
308-
* Informs the Flutter framework of changes to the text input model's state.
309-
*/
310326
- (void)updateEditState {
311327
if (_activeModel == nullptr) {
312328
return;
@@ -328,10 +344,29 @@ - (void)updateEditState {
328344
kComposingExtentKey : @(composingExtent),
329345
kTextKey : [NSString stringWithUTF8String:_activeModel->GetText().c_str()]
330346
};
347+
331348
[_channel invokeMethod:kUpdateEditStateResponseMethod arguments:@[ self.clientID, state ]];
332349
[self updateTextAndSelection];
333350
}
334351

352+
- (void)updateTextAndSelection {
353+
NSAssert(_activeModel != nullptr, @"Flutter text model must not be null.");
354+
NSString* text = @(_activeModel->GetText().data());
355+
int start = _activeModel->selection().base();
356+
int extend = _activeModel->selection().extent();
357+
NSRange selection = NSMakeRange(MIN(start, extend), ABS(start - extend));
358+
// There may be a native text field client if VoiceOver is on.
359+
// In this case, we have to update text and selection through
360+
// the client in order for VoiceOver to announce the text editing
361+
// properly.
362+
if (_client) {
363+
[_client updateString:text withSelection:selection];
364+
} else {
365+
self.string = text;
366+
[self setSelectedRange:selection];
367+
}
368+
}
369+
335370
#pragma mark -
336371
#pragma mark FlutterKeySecondaryResponder
337372

@@ -357,117 +392,74 @@ - (BOOL)handleKeyEvent:(NSEvent*)event {
357392
return [_textInputContext handleEvent:event];
358393
}
359394

395+
#pragma mark -
360396
#pragma mark NSResponder
361397

362398
- (void)keyDown:(NSEvent*)event {
363-
if (!self.flutterViewController) {
364-
return;
365-
}
366399
[self.flutterViewController keyDown:event];
367400
}
368401

369402
- (void)keyUp:(NSEvent*)event {
370-
if (!self.flutterViewController) {
371-
return;
372-
}
373403
[self.flutterViewController keyUp:event];
374404
}
375405

406+
- (BOOL)performKeyEquivalent:(NSEvent*)event {
407+
return [self.flutterViewController performKeyEquivalent:event];
408+
}
409+
376410
- (void)flagsChanged:(NSEvent*)event {
377-
if (!self.flutterViewController) {
378-
return;
379-
}
380411
[self.flutterViewController flagsChanged:event];
381412
}
382413

383414
- (void)mouseEntered:(NSEvent*)event {
384-
if (!self.flutterViewController) {
385-
return;
386-
}
387415
[self.flutterViewController mouseEntered:event];
388416
}
389417

390418
- (void)mouseExited:(NSEvent*)event {
391-
if (!self.flutterViewController) {
392-
return;
393-
}
394419
[self.flutterViewController mouseExited:event];
395420
}
396421

397422
- (void)mouseDown:(NSEvent*)event {
398-
if (!self.flutterViewController) {
399-
return;
400-
}
401423
[self.flutterViewController mouseDown:event];
402424
}
403425

404426
- (void)mouseUp:(NSEvent*)event {
405-
if (!self.flutterViewController) {
406-
return;
407-
}
408427
[self.flutterViewController mouseUp:event];
409428
}
410429

411430
- (void)mouseDragged:(NSEvent*)event {
412-
if (!self.flutterViewController) {
413-
return;
414-
}
415431
[self.flutterViewController mouseDragged:event];
416432
}
417433

418434
- (void)rightMouseDown:(NSEvent*)event {
419-
if (!self.flutterViewController) {
420-
return;
421-
}
422435
[self.flutterViewController rightMouseDown:event];
423436
}
424437

425438
- (void)rightMouseUp:(NSEvent*)event {
426-
if (!self.flutterViewController) {
427-
return;
428-
}
429439
[self.flutterViewController rightMouseUp:event];
430440
}
431441

432442
- (void)rightMouseDragged:(NSEvent*)event {
433-
if (!self.flutterViewController) {
434-
return;
435-
}
436443
[self.flutterViewController rightMouseDragged:event];
437444
}
438445

439446
- (void)otherMouseDown:(NSEvent*)event {
440-
if (!self.flutterViewController) {
441-
return;
442-
}
443447
[self.flutterViewController otherMouseDown:event];
444448
}
445449

446450
- (void)otherMouseUp:(NSEvent*)event {
447-
if (!self.flutterViewController) {
448-
return;
449-
}
450451
[self.flutterViewController otherMouseUp:event];
451452
}
452453

453454
- (void)otherMouseDragged:(NSEvent*)event {
454-
if (!self.flutterViewController) {
455-
return;
456-
}
457455
[self.flutterViewController otherMouseDragged:event];
458456
}
459457

460458
- (void)mouseMoved:(NSEvent*)event {
461-
if (!self.flutterViewController) {
462-
return;
463-
}
464459
[self.flutterViewController mouseMoved:event];
465460
}
466461

467462
- (void)scrollWheel:(NSEvent*)event {
468-
if (!self.flutterViewController) {
469-
return;
470-
}
471463
[self.flutterViewController scrollWheel:event];
472464
}
473465

@@ -553,24 +545,6 @@ - (void)unmarkText {
553545
[self updateEditState];
554546
}
555547

556-
- (void)updateTextAndSelection {
557-
NSAssert(_activeModel != nullptr, @"Flutter text model must not be null.");
558-
NSString* text = @(_activeModel->GetText().data());
559-
int start = _activeModel->selection().base();
560-
int extend = _activeModel->selection().extent();
561-
NSRange selection = NSMakeRange(MIN(start, extend), ABS(start - extend));
562-
// There may be a native text field client if voiceover is on.
563-
// In this case, we have to update text and selection through
564-
// the client in order for voiceover to announce the text editing
565-
// properly.
566-
if (_client) {
567-
[_client updateString:text withSelection:selection];
568-
} else {
569-
self.string = text;
570-
[self setSelectedRange:selection];
571-
}
572-
}
573-
574548
- (NSRange)markedRange {
575549
if (_activeModel == nullptr) {
576550
return NSMakeRange(NSNotFound, 0);
@@ -602,6 +576,9 @@ - (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range
602576
}
603577

604578
- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange {
579+
if (!self.flutterViewController.viewLoaded) {
580+
return CGRectZero;
581+
}
605582
// This only determines position of caret instead of any arbitrary range, but it's enough
606583
// to properly position accent selection popup
607584
if (CATransform3DIsAffine(_editableTransform) && !CGRectEqualToRect(_caretRect, CGRectNull)) {

0 commit comments

Comments
 (0)