mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Fix crash when cursor ends up at invalid position (#8747)
This commit is contained in:
parent
e0bda0685e
commit
57bf1c0968
@ -190,6 +190,9 @@ FILE: ../../../flutter/fml/platform/darwin/scoped_block.h
|
||||
FILE: ../../../flutter/fml/platform/darwin/scoped_block.mm
|
||||
FILE: ../../../flutter/fml/platform/darwin/scoped_nsobject.h
|
||||
FILE: ../../../flutter/fml/platform/darwin/scoped_nsobject.mm
|
||||
FILE: ../../../flutter/fml/platform/darwin/string_range_sanitization.h
|
||||
FILE: ../../../flutter/fml/platform/darwin/string_range_sanitization.mm
|
||||
FILE: ../../../flutter/fml/platform/darwin/string_range_sanitization_unittests.mm
|
||||
FILE: ../../../flutter/fml/platform/fuchsia/paths_fuchsia.cc
|
||||
FILE: ../../../flutter/fml/platform/linux/message_loop_linux.cc
|
||||
FILE: ../../../flutter/fml/platform/linux/message_loop_linux.h
|
||||
|
||||
@ -106,6 +106,8 @@ source_set("fml") {
|
||||
"platform/darwin/scoped_block.mm",
|
||||
"platform/darwin/scoped_nsobject.h",
|
||||
"platform/darwin/scoped_nsobject.mm",
|
||||
"platform/darwin/string_range_sanitization.h",
|
||||
"platform/darwin/string_range_sanitization.mm",
|
||||
]
|
||||
|
||||
libs += [ "Foundation.framework" ]
|
||||
@ -188,6 +190,7 @@ executable("fml_unittests") {
|
||||
"message_loop_unittests.cc",
|
||||
"message_unittests.cc",
|
||||
"paths_unittests.cc",
|
||||
"platform/darwin/string_range_sanitization_unittests.mm",
|
||||
"string_view_unittest.cc",
|
||||
"synchronization/count_down_latch_unittests.cc",
|
||||
"synchronization/semaphore_unittest.cc",
|
||||
|
||||
29
fml/platform/darwin/string_range_sanitization.h
Normal file
29
fml/platform/darwin/string_range_sanitization.h
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_FML_STRING_RANGE_SANITIZATION_H_
|
||||
#define FLUTTER_FML_STRING_RANGE_SANITIZATION_H_
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
namespace fml {
|
||||
|
||||
// Returns a range encompassing the grapheme cluster in which |index| is located.
|
||||
//
|
||||
// A nil |text| or an index greater than or equal to text.length will result in
|
||||
// `NSRange(NSNotFound, 0)`.
|
||||
NSRange RangeForCharacterAtIndex(NSString* text, NSUInteger index);
|
||||
|
||||
// Returns a range encompassing the grapheme clusters falling in |range|.
|
||||
//
|
||||
// This method will not alter the length of the input range, but will ensure
|
||||
// that the range's location is not in the middle of a multi-byte unicode
|
||||
// sequence.
|
||||
//
|
||||
// An invalid range will result in `NSRange(NSNotFound, 0)`.
|
||||
NSRange RangeForCharactersInRange(NSString* text, NSRange range);
|
||||
|
||||
} // namespace fml
|
||||
|
||||
#endif // FLUTTER_FML_STRING_RANGE_SANITIZATION_H_
|
||||
29
fml/platform/darwin/string_range_sanitization.mm
Normal file
29
fml/platform/darwin/string_range_sanitization.mm
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/fml/platform/darwin/string_range_sanitization.h"
|
||||
|
||||
namespace fml {
|
||||
|
||||
NSRange RangeForCharacterAtIndex(NSString* text, NSUInteger index) {
|
||||
if (text == nil || index >= text.length) {
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
if (index < text.length)
|
||||
return [text rangeOfComposedCharacterSequenceAtIndex:index];
|
||||
return NSMakeRange(index, 0);
|
||||
}
|
||||
|
||||
NSRange RangeForCharactersInRange(NSString* text, NSRange range) {
|
||||
if (text == nil || range.location + range.length > text.length) {
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
NSRange sanitizedRange = [text rangeOfComposedCharacterSequencesForRange:range];
|
||||
// We don't want to override the length, we just want to make sure we don't
|
||||
// select into the middle of a multi-byte character. Taking the
|
||||
// `sanitizedRange`'s length will end up altering the actual selection.
|
||||
return NSMakeRange(sanitizedRange.location, range.length);
|
||||
}
|
||||
|
||||
} // namespace fml
|
||||
30
fml/platform/darwin/string_range_sanitization_unittests.mm
Normal file
30
fml/platform/darwin/string_range_sanitization_unittests.mm
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
#include "flutter/fml/platform/darwin/string_range_sanitization.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(StringRangeSanitizationTest, CanHandleUnicode) {
|
||||
auto result = fml::RangeForCharacterAtIndex(@"😠", 1);
|
||||
EXPECT_EQ(result.location, 0UL);
|
||||
EXPECT_EQ(result.length, 2UL);
|
||||
}
|
||||
|
||||
TEST(StringRangeSanitizationTest, HandlesInvalidRanges) {
|
||||
auto ns_not_found = static_cast<unsigned long>(NSNotFound);
|
||||
EXPECT_EQ(fml::RangeForCharacterAtIndex(@"😠", 3).location, ns_not_found);
|
||||
EXPECT_EQ(fml::RangeForCharacterAtIndex(@"😠", -1).location, ns_not_found);
|
||||
EXPECT_EQ(fml::RangeForCharacterAtIndex(nil, 0).location, ns_not_found);
|
||||
EXPECT_EQ(fml::RangeForCharactersInRange(@"😠", NSMakeRange(1, 2)).location, ns_not_found);
|
||||
EXPECT_EQ(fml::RangeForCharactersInRange(@"😠", NSMakeRange(3, 0)).location, ns_not_found);
|
||||
EXPECT_EQ(fml::RangeForCharactersInRange(nil, NSMakeRange(0, 0)).location, ns_not_found);
|
||||
}
|
||||
|
||||
TEST(StringRangeSanitizationTest, CanHandleUnicodeRange) {
|
||||
auto result = fml::RangeForCharactersInRange(@"😠", NSMakeRange(1, 0));
|
||||
EXPECT_EQ(result.location, 0UL);
|
||||
EXPECT_EQ(result.length, 0UL);
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h"
|
||||
#include "flutter/fml/platform/darwin/string_range_sanitization.h"
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <UIKit/UIKit.h>
|
||||
@ -283,7 +284,13 @@ static UIReturnKeyType ToUIReturnKeyType(NSString* inputType) {
|
||||
- (void)setSelectedTextRange:(UITextRange*)selectedTextRange updateEditingState:(BOOL)update {
|
||||
if (_selectedTextRange != selectedTextRange) {
|
||||
UITextRange* oldSelectedRange = _selectedTextRange;
|
||||
_selectedTextRange = [selectedTextRange copy];
|
||||
if (self.hasText) {
|
||||
FlutterTextRange* flutterTextRange = (FlutterTextRange*)selectedTextRange;
|
||||
_selectedTextRange = [[FlutterTextRange
|
||||
rangeWithNSRange:fml::RangeForCharactersInRange(self.text, flutterTextRange.range)] copy];
|
||||
} else {
|
||||
_selectedTextRange = [selectedTextRange copy];
|
||||
}
|
||||
[oldSelectedRange release];
|
||||
|
||||
if (update)
|
||||
@ -415,20 +422,12 @@ static UIReturnKeyType ToUIReturnKeyType(NSString* inputType) {
|
||||
return [FlutterTextRange rangeWithNSRange:NSMakeRange(fromIndex, toIndex - fromIndex)];
|
||||
}
|
||||
|
||||
/** Returns the range of the character sequence at the specified index in the
|
||||
* text. */
|
||||
- (NSRange)rangeForCharacterAtIndex:(NSUInteger)index {
|
||||
if (index < self.text.length)
|
||||
return [self.text rangeOfComposedCharacterSequenceAtIndex:index];
|
||||
return NSMakeRange(index, 0);
|
||||
}
|
||||
|
||||
- (NSUInteger)decrementOffsetPosition:(NSUInteger)position {
|
||||
return [self rangeForCharacterAtIndex:MAX(0, position - 1)].location;
|
||||
return fml::RangeForCharacterAtIndex(self.text, MAX(0, position - 1)).location;
|
||||
}
|
||||
|
||||
- (NSUInteger)incrementOffsetPosition:(NSUInteger)position {
|
||||
NSRange charRange = [self rangeForCharacterAtIndex:position];
|
||||
NSRange charRange = fml::RangeForCharacterAtIndex(self.text, position);
|
||||
return MIN(position + charRange.length, self.text.length);
|
||||
}
|
||||
|
||||
@ -565,7 +564,7 @@ static UIReturnKeyType ToUIReturnKeyType(NSString* inputType) {
|
||||
- (UITextRange*)characterRangeAtPoint:(CGPoint)point {
|
||||
// TODO(cbracken) Implement.
|
||||
NSUInteger currentIndex = ((FlutterTextPosition*)_selectedTextRange.start).index;
|
||||
return [FlutterTextRange rangeWithNSRange:[self rangeForCharacterAtIndex:currentIndex]];
|
||||
return [FlutterTextRange rangeWithNSRange:fml::RangeForCharacterAtIndex(self.text, currentIndex)];
|
||||
}
|
||||
|
||||
- (void)beginFloatingCursorAtPoint:(CGPoint)point {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user