Avoid iOS text selection crash by returning nil range (#161996)
[Previously approved](https://github.com/flutter/engine/pull/55909) in /engine before monorepo shift. Reverts an unnecessary assertion introduced by [#16496](https://github.com/flutter/engine/pull/16496) that crashes upon valid user text field interactions. Follow-on work can resolve the underlying discrepancy between iOS and Flutter range finding (see #160100). For crash reports, see issue [#138464](https://github.com/flutter/flutter/issues/138464). ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md Co-authored-by: Chris Bracken <chris@bracken.jp>
This commit is contained in:
parent
ca14403b06
commit
489b186904
@ -1293,7 +1293,14 @@ static BOOL IsSelectionRectBoundaryCloserToPoint(CGPoint point,
|
|||||||
NSAssert([range isKindOfClass:[FlutterTextRange class]],
|
NSAssert([range isKindOfClass:[FlutterTextRange class]],
|
||||||
@"Expected a FlutterTextRange for range (got %@).", [range class]);
|
@"Expected a FlutterTextRange for range (got %@).", [range class]);
|
||||||
NSRange textRange = ((FlutterTextRange*)range).range;
|
NSRange textRange = ((FlutterTextRange*)range).range;
|
||||||
NSAssert(textRange.location != NSNotFound, @"Expected a valid text range.");
|
if (textRange.location == NSNotFound) {
|
||||||
|
// Avoids [crashes](https://github.com/flutter/flutter/issues/138464) from an assertion
|
||||||
|
// against NSNotFound.
|
||||||
|
// TODO(hellohuanlin): This is a temp workaround, but we should look into why
|
||||||
|
// framework is providing NSNotFound to the engine.
|
||||||
|
// https://github.com/flutter/flutter/issues/160100
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
// Sanitize the range to prevent going out of bounds.
|
// Sanitize the range to prevent going out of bounds.
|
||||||
NSUInteger location = MIN(textRange.location, self.text.length);
|
NSUInteger location = MIN(textRange.location, self.text.length);
|
||||||
NSUInteger length = MIN(self.text.length - location, textRange.length);
|
NSUInteger length = MIN(self.text.length - location, textRange.length);
|
||||||
|
@ -530,6 +530,19 @@ FLUTTER_ASSERT_ARC
|
|||||||
XCTAssertEqual(substring.length, 0ul);
|
XCTAssertEqual(substring.length, 0ul);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)testTextInRangeAcceptsNSNotFoundLocationGracefully {
|
||||||
|
NSDictionary* config = self.mutableTemplateCopy;
|
||||||
|
[self setClientId:123 configuration:config];
|
||||||
|
NSArray<FlutterTextInputView*>* inputFields = self.installedInputViews;
|
||||||
|
FlutterTextInputView* inputView = inputFields[0];
|
||||||
|
|
||||||
|
[inputView insertText:@"text"];
|
||||||
|
UITextRange* range = [FlutterTextRange rangeWithNSRange:NSMakeRange(NSNotFound, 0)];
|
||||||
|
|
||||||
|
NSString* substring = [inputView textInRange:range];
|
||||||
|
XCTAssertNil(substring);
|
||||||
|
}
|
||||||
|
|
||||||
- (void)testStandardEditActions {
|
- (void)testStandardEditActions {
|
||||||
NSDictionary* config = self.mutableTemplateCopy;
|
NSDictionary* config = self.mutableTemplateCopy;
|
||||||
[self setClientId:123 configuration:config];
|
[self setClientId:123 configuration:config];
|
||||||
|
@ -42,7 +42,14 @@ static const UIAccessibilityTraits kUIAccessibilityTraitUndocumentedEmptyLine =
|
|||||||
NSAssert([range isKindOfClass:[FlutterTextRange class]],
|
NSAssert([range isKindOfClass:[FlutterTextRange class]],
|
||||||
@"Expected a FlutterTextRange for range (got %@).", [range class]);
|
@"Expected a FlutterTextRange for range (got %@).", [range class]);
|
||||||
NSRange textRange = ((FlutterTextRange*)range).range;
|
NSRange textRange = ((FlutterTextRange*)range).range;
|
||||||
NSAssert(textRange.location != NSNotFound, @"Expected a valid text range.");
|
if (textRange.location == NSNotFound) {
|
||||||
|
// Avoids [crashes](https://github.com/flutter/flutter/issues/138464) from an assertion
|
||||||
|
// against NSNotFound.
|
||||||
|
// TODO(hellohuanlin): This is a temp workaround, but we should look into why
|
||||||
|
// framework is providing NSNotFound to the engine.
|
||||||
|
// https://github.com/flutter/flutter/issues/160100
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
return [self.text substringWithRange:textRange];
|
return [self.text substringWithRange:textRange];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user