-
Notifications
You must be signed in to change notification settings - Fork 6k
Fix an issue that deleting an emoji may crash the app #34508
Changes from all commits
6c1d6cc
6f604cb
e8c4a37
a28afd0
8e59927
1382921
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,8 @@ | |
#import <Foundation/Foundation.h> | ||
#import <UIKit/UIKit.h> | ||
|
||
#include "unicode/uchar.h" | ||
|
||
#include "flutter/fml/logging.h" | ||
#include "flutter/fml/platform/darwin/string_range_sanitization.h" | ||
|
||
|
@@ -1896,6 +1898,22 @@ - (void)deleteBackward { | |
NSRange oldRange = ((FlutterTextRange*)oldSelectedRange).range; | ||
if (oldRange.location > 0) { | ||
NSRange newRange = NSMakeRange(oldRange.location - 1, 1); | ||
|
||
// We should check if the last character is a part of emoji. | ||
// If so, we must delete the entire emoji to prevent the text from being malformed. | ||
NSRange charRange = fml::RangeForCharacterAtIndex(self.text, oldRange.location - 1); | ||
UChar32 codePoint; | ||
BOOL gotCodePoint = [self.text getBytes:&codePoint | ||
maxLength:sizeof(codePoint) | ||
usedLength:NULL | ||
encoding:NSUTF32StringEncoding | ||
options:kNilOptions | ||
range:charRange | ||
remainingRange:NULL]; | ||
if (gotCodePoint && u_hasBinaryProperty(codePoint, UCHAR_EMOJI)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this getting applied only to emoji? Aren't there other multi-byte characters that are not emoji that we'd want to apply this to? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From #34508 (comment), languages with diacritical marks will expect a backward deletion should only delete one part of the composed character, such as Thai and Hebrew. We have two ways to distinguish this behavior from emoji's:
I chose the second one to keep consistency with android (see FlutterTextUtils.getOffsetBefore) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahhh ok this makes sense. |
||
newRange = NSMakeRange(charRange.location, oldRange.location - charRange.location); | ||
} | ||
|
||
_selectedTextRange = [[FlutterTextRange rangeWithNSRange:newRange] copy]; | ||
[oldSelectedRange release]; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -78,6 +78,12 @@ | |
ReferencedContainer = "container:IosUnitTests.xcodeproj"> | ||
</BuildableReference> | ||
</BuildableProductRunnable> | ||
<CommandLineArguments> | ||
<CommandLineArgument | ||
argument = "--icu-data-file-path=Frameworks/Flutter.framework/icudtl.dat" | ||
isEnabled = "YES"> | ||
Comment on lines
+83
to
+84
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. Without this the test will fail due to failing to load the ICU data file. Maybe we should file another issue to get rid of this later. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Filed flutter/flutter#108221 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is fine - in other tests we use the command line argument to load the ICU data file (see run_tests.py). |
||
</CommandLineArgument> | ||
</CommandLineArguments> | ||
</LaunchAction> | ||
<ProfileAction | ||
buildConfiguration = "Release" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dnfield since you jumped in, how do you feel about including this library? I've been trying to think of another way to check if it's an emoji without importing this but also reinventing the wheel. I guess it's okay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems fine to me. This is what ICU is for and there's no getting around having ICU in a flutter app