Skip to content

Commit 7050725

Browse files
authored
Fix an issue that deleting an emoji may crash the app (flutter#34508)
1 parent c6ab2ba commit 7050725

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#import <Foundation/Foundation.h>
88
#import <UIKit/UIKit.h>
99

10+
#include "unicode/uchar.h"
11+
1012
#include "flutter/fml/logging.h"
1113
#include "flutter/fml/platform/darwin/string_range_sanitization.h"
1214

@@ -1896,6 +1898,22 @@ - (void)deleteBackward {
18961898
NSRange oldRange = ((FlutterTextRange*)oldSelectedRange).range;
18971899
if (oldRange.location > 0) {
18981900
NSRange newRange = NSMakeRange(oldRange.location - 1, 1);
1901+
1902+
// We should check if the last character is a part of emoji.
1903+
// If so, we must delete the entire emoji to prevent the text from being malformed.
1904+
NSRange charRange = fml::RangeForCharacterAtIndex(self.text, oldRange.location - 1);
1905+
UChar32 codePoint;
1906+
BOOL gotCodePoint = [self.text getBytes:&codePoint
1907+
maxLength:sizeof(codePoint)
1908+
usedLength:NULL
1909+
encoding:NSUTF32StringEncoding
1910+
options:kNilOptions
1911+
range:charRange
1912+
remainingRange:NULL];
1913+
if (gotCodePoint && u_hasBinaryProperty(codePoint, UCHAR_EMOJI)) {
1914+
newRange = NSMakeRange(charRange.location, oldRange.location - charRange.location);
1915+
}
1916+
18991917
_selectedTextRange = [[FlutterTextRange rangeWithNSRange:newRange] copy];
19001918
[oldSelectedRange release];
19011919
}

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,41 @@ - (void)testStandardEditActions {
406406
XCTAssertEqualObjects(substring, @"bbbbaaaabbbbaaaa");
407407
}
408408

409+
- (void)testDeletingBackward {
410+
NSDictionary* config = self.mutableTemplateCopy;
411+
[self setClientId:123 configuration:config];
412+
NSArray<FlutterTextInputView*>* inputFields = self.installedInputViews;
413+
FlutterTextInputView* inputView = inputFields[0];
414+
415+
[inputView insertText:@"ឹ😀 text 🥰👨‍👩‍👧‍👦🇺🇳ดี "];
416+
[inputView deleteBackward];
417+
[inputView deleteBackward];
418+
419+
// Thai vowel is removed.
420+
XCTAssertEqualObjects(inputView.text, @"ឹ😀 text 🥰👨‍👩‍👧‍👦🇺🇳ด");
421+
[inputView deleteBackward];
422+
XCTAssertEqualObjects(inputView.text, @"ឹ😀 text 🥰👨‍👩‍👧‍👦🇺🇳");
423+
[inputView deleteBackward];
424+
XCTAssertEqualObjects(inputView.text, @"ឹ😀 text 🥰👨‍👩‍👧‍👦");
425+
[inputView deleteBackward];
426+
XCTAssertEqualObjects(inputView.text, @"ឹ😀 text 🥰");
427+
[inputView deleteBackward];
428+
429+
XCTAssertEqualObjects(inputView.text, @"ឹ😀 text ");
430+
[inputView deleteBackward];
431+
[inputView deleteBackward];
432+
[inputView deleteBackward];
433+
[inputView deleteBackward];
434+
[inputView deleteBackward];
435+
[inputView deleteBackward];
436+
437+
XCTAssertEqualObjects(inputView.text, @"ឹ😀");
438+
[inputView deleteBackward];
439+
XCTAssertEqualObjects(inputView.text, @"");
440+
[inputView deleteBackward];
441+
XCTAssertEqualObjects(inputView.text, @"");
442+
}
443+
409444
- (void)testPastingNonTextDisallowed {
410445
NSDictionary* config = self.mutableTemplateCopy;
411446
[self setClientId:123 configuration:config];

testing/ios/IosUnitTests/IosUnitTests.xcodeproj/xcshareddata/xcschemes/IosUnitTests.xcscheme

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@
7878
ReferencedContainer = "container:IosUnitTests.xcodeproj">
7979
</BuildableReference>
8080
</BuildableProductRunnable>
81+
<CommandLineArguments>
82+
<CommandLineArgument
83+
argument = "--icu-data-file-path=Frameworks/Flutter.framework/icudtl.dat"
84+
isEnabled = "YES">
85+
</CommandLineArgument>
86+
</CommandLineArguments>
8187
</LaunchAction>
8288
<ProfileAction
8389
buildConfiguration = "Release"

0 commit comments

Comments
 (0)