From 52d4f25aaf25b76e2dfe79f3296c6baa2489bf2b Mon Sep 17 00:00:00 2001 From: Callum Moffat Date: Sat, 3 Jun 2023 13:37:12 -0400 Subject: [PATCH 1/4] Remove isRTLAtPosition It had a bug in the binary search causing a crash. But aside from that it isn't actually needed. --- .../Source/FlutterTextInputPlugin.mm | 27 ++++--------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm index 4f92e456e5fad..7ec05d6fe6323 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm @@ -1658,25 +1658,6 @@ - (CGRect)firstRectForRange:(UITextRange*)range { return CGRectZero; } -- (BOOL)isRTLAtPosition:(NSUInteger)position { - // _selectionRects is sorted by position already. - // We can use binary search. - NSInteger min = 0; - NSInteger max = [_selectionRects count]; - while (min <= max) { - const NSUInteger mid = min + (max - min) / 2; - FlutterTextSelectionRect* rect = _selectionRects[mid]; - if (rect.position > position) { - max = mid - 1; - } else if (rect.position == position) { - return rect.isRTL; - } else { - min = mid + 1; - } - } - return NO; -} - - (CGRect)caretRectForPosition:(UITextPosition*)position { NSInteger index = ((FlutterTextPosition*)position).index; UITextStorageDirection affinity = ((FlutterTextPosition*)position).affinity; @@ -1699,7 +1680,7 @@ - (CGRect)caretRectForPosition:(UITextPosition*)position { CGRect characterAfterCaret = rects[0].rect; // Return a zero-width rectangle along the upstream edge of the character after the caret // position. - if ([self isRTLAtPosition:index]) { + if ([rects[0] isKindOfClass:[FlutterTextSelectionRect class]] && ((FlutterTextSelectionRect*)rects[0]).isRTL) { return CGRectMake(characterAfterCaret.origin.x + characterAfterCaret.size.width, characterAfterCaret.origin.y, 0, characterAfterCaret.size.height); } else { @@ -1712,7 +1693,7 @@ - (CGRect)caretRectForPosition:(UITextPosition*)position { CGRect characterAfterCaret = rects[1].rect; // Return a zero-width rectangle along the upstream edge of the character after the caret // position. - if ([self isRTLAtPosition:index]) { + if ([rects[1] isKindOfClass:[FlutterTextSelectionRect class]] && ((FlutterTextSelectionRect*)rects[1]).isRTL) { return CGRectMake(characterAfterCaret.origin.x + characterAfterCaret.size.width, characterAfterCaret.origin.y, 0, characterAfterCaret.size.height); } else { @@ -1727,7 +1708,9 @@ - (CGRect)caretRectForPosition:(UITextPosition*)position { // For both cases, return a zero-width rectangle along the downstream edge of the character // before the caret position. CGRect characterBeforeCaret = rects[0].rect; - if ([self isRTLAtPosition:index - 1]) { + // Return a zero-width rectangle along the downstream edge of the character before the caret + // position. + if ([rects[0] isKindOfClass:[FlutterTextSelectionRect class]] && ((FlutterTextSelectionRect*)rects[0]).isRTL) { return CGRectMake(characterBeforeCaret.origin.x, characterBeforeCaret.origin.y, 0, characterBeforeCaret.size.height); } else { From 52d7edfbdd17531df9ea0bdf0d8efefd7b25f65f Mon Sep 17 00:00:00 2001 From: Callum Moffat Date: Sat, 3 Jun 2023 13:38:04 -0400 Subject: [PATCH 2/4] Add test for partial rects --- .../Source/FlutterTextInputPluginTest.mm | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm index 04452ed9c3246..b1ee7274f36fe 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm @@ -1535,6 +1535,29 @@ - (void)testClosestPositionToPointWithinRange { ((FlutterTextPosition*)[inputView closestPositionToPoint:point withinRange:range]).affinity); } +- (void)testClosestPositionToPointWithPartialSelectionRects { + FlutterTextInputView* inputView = [[FlutterTextInputView alloc] initWithOwner:textInputPlugin]; + [inputView setTextInputState:@{@"text" : @"COMPOSING"}]; + + [inputView setSelectionRects:@[ [FlutterTextSelectionRect + selectionRectWithRect:CGRectMake(0, 0, 100, 100) + position:0U] ]]; + // Asking with a position at the end of selection rects should give you the trailing edge of + // the last rect. + XCTAssertTrue(CGRectEqualToRect( + [inputView caretRectForPosition:[FlutterTextPosition + positionWithIndex:1 + affinity:UITextStorageDirectionForward]], + CGRectMake(100, 0, 0, 100))); + // Asking with a position beyond the end of selection rects should return CGRectZero without + // crashing. + XCTAssertTrue(CGRectEqualToRect( + [inputView caretRectForPosition:[FlutterTextPosition + positionWithIndex:2 + affinity:UITextStorageDirectionForward]], + CGRectZero)); +} + #pragma mark - Floating Cursor - Tests - (void)testFloatingCursorDoesNotThrow { From 17c1a8a406c149c54d353c262cf7dd8af037bf70 Mon Sep 17 00:00:00 2001 From: Callum Moffat Date: Sat, 3 Jun 2023 13:39:43 -0400 Subject: [PATCH 3/4] Fix comment merge --- .../darwin/ios/framework/Source/FlutterTextInputPlugin.mm | 2 -- 1 file changed, 2 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm index 7ec05d6fe6323..b51b4cc627c3a 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm @@ -1708,8 +1708,6 @@ - (CGRect)caretRectForPosition:(UITextPosition*)position { // For both cases, return a zero-width rectangle along the downstream edge of the character // before the caret position. CGRect characterBeforeCaret = rects[0].rect; - // Return a zero-width rectangle along the downstream edge of the character before the caret - // position. if ([rects[0] isKindOfClass:[FlutterTextSelectionRect class]] && ((FlutterTextSelectionRect*)rects[0]).isRTL) { return CGRectMake(characterBeforeCaret.origin.x, characterBeforeCaret.origin.y, 0, characterBeforeCaret.size.height); From d6df36a53a0b5745ef8db34ec477c8f91bbe488f Mon Sep 17 00:00:00 2001 From: Callum Moffat Date: Sat, 3 Jun 2023 18:36:01 -0400 Subject: [PATCH 4/4] Fix formatting --- .../ios/framework/Source/FlutterTextInputPlugin.mm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm index b51b4cc627c3a..4af9ac6ec835b 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm @@ -1680,7 +1680,8 @@ - (CGRect)caretRectForPosition:(UITextPosition*)position { CGRect characterAfterCaret = rects[0].rect; // Return a zero-width rectangle along the upstream edge of the character after the caret // position. - if ([rects[0] isKindOfClass:[FlutterTextSelectionRect class]] && ((FlutterTextSelectionRect*)rects[0]).isRTL) { + if ([rects[0] isKindOfClass:[FlutterTextSelectionRect class]] && + ((FlutterTextSelectionRect*)rects[0]).isRTL) { return CGRectMake(characterAfterCaret.origin.x + characterAfterCaret.size.width, characterAfterCaret.origin.y, 0, characterAfterCaret.size.height); } else { @@ -1693,7 +1694,8 @@ - (CGRect)caretRectForPosition:(UITextPosition*)position { CGRect characterAfterCaret = rects[1].rect; // Return a zero-width rectangle along the upstream edge of the character after the caret // position. - if ([rects[1] isKindOfClass:[FlutterTextSelectionRect class]] && ((FlutterTextSelectionRect*)rects[1]).isRTL) { + if ([rects[1] isKindOfClass:[FlutterTextSelectionRect class]] && + ((FlutterTextSelectionRect*)rects[1]).isRTL) { return CGRectMake(characterAfterCaret.origin.x + characterAfterCaret.size.width, characterAfterCaret.origin.y, 0, characterAfterCaret.size.height); } else { @@ -1708,7 +1710,8 @@ - (CGRect)caretRectForPosition:(UITextPosition*)position { // For both cases, return a zero-width rectangle along the downstream edge of the character // before the caret position. CGRect characterBeforeCaret = rects[0].rect; - if ([rects[0] isKindOfClass:[FlutterTextSelectionRect class]] && ((FlutterTextSelectionRect*)rects[0]).isRTL) { + if ([rects[0] isKindOfClass:[FlutterTextSelectionRect class]] && + ((FlutterTextSelectionRect*)rects[0]).isRTL) { return CGRectMake(characterBeforeCaret.origin.x, characterBeforeCaret.origin.y, 0, characterBeforeCaret.size.height); } else {