Diff
Modified: branches/safari-600.1.4.15-branch/LayoutTests/ChangeLog (179734 => 179735)
--- branches/safari-600.1.4.15-branch/LayoutTests/ChangeLog 2015-02-06 01:40:21 UTC (rev 179734)
+++ branches/safari-600.1.4.15-branch/LayoutTests/ChangeLog 2015-02-06 02:04:19 UTC (rev 179735)
@@ -1,3 +1,18 @@
+2015-02-05 Lucas Forschler <[email protected]>
+
+ Merge r179567
+
+ 2015-02-02 Enrica Casucci <[email protected]>
+
+ Additional emoji support.
+ https://bugs.webkit.org/show_bug.cgi?id=141047
+ rdar://problem/19045135
+
+ Reviewed by Darin Adler.
+
+ * editing/deleting/delete-emoji.html: Added.
+ * editing/deleting/delete-emoji-expected.txt: Added.
+
2015-02-05 David Kilzer <[email protected]>
Merge r176473.
Copied: branches/safari-600.1.4.15-branch/LayoutTests/editing/deleting/delete-emoji-expected.txt (from rev 179567, trunk/LayoutTests/editing/deleting/delete-emoji-expected.txt) (0 => 179735)
--- branches/safari-600.1.4.15-branch/LayoutTests/editing/deleting/delete-emoji-expected.txt (rev 0)
+++ branches/safari-600.1.4.15-branch/LayoutTests/editing/deleting/delete-emoji-expected.txt 2015-02-06 02:04:19 UTC (rev 179735)
@@ -0,0 +1,17 @@
+This test verifies that emoji groups and emoji with variations are deleted correctly
+
+Dump of markup 1:
+| "π¦π»π¦πΎπ»π¦πΎπ¦π©βπ©βπ¦<#selection-caret>
+"
+
+Dump of markup 2:
+| "π¦π»π¦πΎπ»π¦πΎπ¦<#selection-caret>"
+
+Dump of markup 3:
+| "π¦π»π¦πΎπ»π¦πΎ<#selection-caret>"
+
+Dump of markup 4:
+| "π¦π»π¦πΎπ»<#selection-caret>"
+
+Dump of markup 5:
+| "π¦π»π¦πΎ<#selection-caret>"
Copied: branches/safari-600.1.4.15-branch/LayoutTests/editing/deleting/delete-emoji.html (from rev 179567, trunk/LayoutTests/editing/deleting/delete-emoji.html) (0 => 179735)
--- branches/safari-600.1.4.15-branch/LayoutTests/editing/deleting/delete-emoji.html (rev 0)
+++ branches/safari-600.1.4.15-branch/LayoutTests/editing/deleting/delete-emoji.html 2015-02-06 02:04:19 UTC (rev 179735)
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div id="test" contenteditable="true">👦🏻👦🏾🏻👦🏾👦👩‍👩‍👦
+</div>
+<script src=""
+<script>
+Markup.description("This test verifies that emoji groups and emoji with variations are deleted correctly");
+
+var selection = window.getSelection();
+var testElement = document.getElementById('test');
+selection.setBaseAndExtent(testElement.firstChild, 20, testElement.firstChild, 20);
+Markup.dump("test");
+document.execCommand("Delete");
+Markup.dump("test");
+document.execCommand("Delete");
+Markup.dump("test");
+document.execCommand("Delete");
+Markup.dump("test");
+document.execCommand("Delete");
+Markup.dump("test");
+</script>
+</body>
+</html>
Modified: branches/safari-600.1.4.15-branch/Source/WebCore/ChangeLog (179734 => 179735)
--- branches/safari-600.1.4.15-branch/Source/WebCore/ChangeLog 2015-02-06 01:40:21 UTC (rev 179734)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/ChangeLog 2015-02-06 02:04:19 UTC (rev 179735)
@@ -1,3 +1,28 @@
+2015-02-05 Lucas Forschler <[email protected]>
+
+ Merge r179567
+
+ 2015-02-02 Enrica Casucci <[email protected]>
+
+ Additional emoji support.
+ https://bugs.webkit.org/show_bug.cgi?id=141047
+ rdar://problem/19045135
+
+ Reviewed by Darin Adler.
+
+ Adds support for emoji modifiers and group emoji.
+
+ Test: editing/deleting/delete-emoji.html
+
+ * platform/graphics/FontCascade.cpp:
+ (WebCore::FontCascade::characterRangeCodePath):
+ * platform/text/TextBreakIterator.cpp:
+ (WebCore::cursorMovementIterator):
+ * rendering/RenderText.cpp:
+ (WebCore::isEmojiGroupCandidate):
+ (WebCore::isEmojiModifier):
+ (WebCore::RenderText::previousOffsetForBackwardDeletion):
+
2015-02-05 David Kilzer <[email protected]>
Merge r176473.
Modified: branches/safari-600.1.4.15-branch/Source/WebCore/platform/graphics/Font.cpp (179734 => 179735)
--- branches/safari-600.1.4.15-branch/Source/WebCore/platform/graphics/Font.cpp 2015-02-06 01:40:21 UTC (rev 179734)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/platform/graphics/Font.cpp 2015-02-06 02:04:19 UTC (rev 179735)
@@ -620,8 +620,13 @@
// Alternatively, we may as well consider binary search over a sorted
// list of ranges.
CodePath result = Simple;
+ bool previousCharacterIsEmojiGroupCandidate = false;
for (unsigned i = 0; i < len; i++) {
const UChar c = characters[i];
+ if (c == zeroWidthJoiner && previousCharacterIsEmojiGroupCandidate)
+ return Complex;
+
+ previousCharacterIsEmojiGroupCandidate = false;
if (c < 0x2E5) // U+02E5 through U+02E9 (Modifier Letters : Tone letters)
continue;
if (c <= 0x2E9)
@@ -742,6 +747,10 @@
if (supplementaryCharacter <= 0x1F1FF)
return Complex;
+ if (supplementaryCharacter >= 0x1F466 && supplementaryCharacter <= 0x1F469) {
+ previousCharacterIsEmojiGroupCandidate = true;
+ continue;
+ }
if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors.
continue;
if (supplementaryCharacter <= 0xE01EF)
Modified: branches/safari-600.1.4.15-branch/Source/WebCore/platform/text/TextBreakIterator.cpp (179734 => 179735)
--- branches/safari-600.1.4.15-branch/Source/WebCore/platform/text/TextBreakIterator.cpp 2015-02-06 01:40:21 UTC (rev 179734)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/platform/text/TextBreakIterator.cpp 2015-02-06 02:04:19 UTC (rev 179735)
@@ -207,6 +207,10 @@
"$MalV = \\u0D4D;" // Malayalam Sign Virama
"$Mal1 = [\\u0D15-\\u0D39];" // Malayalam Letter A,...,Ha
"$RI = [\\U0001F1E6-\\U0001F1FF];" // Emoji regional indicators
+ "$ZWJ = \\u200D;" // Zero width joiner
+ "$EmojiForModsAndSeqs = [\\U0001F466-\\U0001F469];" // Emoji that take Fitzpatrick modifiers AND participate in ZWJ sequences
+ "$EmojiForModsOnly = [\\u261D \\u270A-\\u270C \\U0001F385 \\U0001F3C3-\\U0001F3C4 \\U0001F3C7 \\U0001F3CA \\U0001F442-\\U0001F443 \\U0001F446-\\U0001F450 \\U0001F46E-\\U0001F478 \\U0001F47C \\U0001F481-\\U0001F483 \\U0001F485-\\U0001F487 \\U0001F4AA \\U0001F645-\\U0001F647 \\U0001F64B-\\U0001F64F \\U0001F6B4-\\U0001F6B6 \\U0001F6C0];" // Emoji that take Fitzpatrick modifiers
+ "$EmojiMods = [\\U0001F3FB-\\U0001F3FF];" // Fitzpatrick modifiers
"!!chain;"
"!!forward;"
"$CR $LF;"
@@ -225,6 +229,8 @@
"$Tel0 $TelV $Tel1;" // Telugu Virama (forward)
"$Kan0 $KanV $Kan1;" // Kannada Virama (forward)
"$Mal0 $MalV $Mal1;" // Malayalam Virama (forward)
+ "$ZWJ $EmojiForModsAndSeqs;" // Don't break in emoji ZWJ sequences
+ "[$EmojiForModsAndSeqs $EmojiForModsOnly] $EmojiMods;" // Don't break between relevant emoji and Fitzpatrick modifier
"!!reverse;"
"$LF $CR;"
"($L | $V | $LV | $LVT) $L;"
@@ -242,6 +248,8 @@
"$Tel1 $TelV $Tel0;" // Telugu Virama (backward)
"$Kan1 $KanV $Kan0;" // Kannada Virama (backward)
"$Mal1 $MalV $Mal0;" // Malayalam Virama (backward)
+ "$EmojiForModsAndSeqs $ZWJ;" // Don't break in emoji ZWJ sequences
+ "$EmojiMods [$EmojiForModsAndSeqs $EmojiForModsOnly];" // Don't break between relevant emoji and Fitzpatrick modifier
"!!safe_reverse;"
"!!safe_forward;";
static TextBreakIterator* staticCursorMovementIterator = initializeIteratorWithRules(kRules);
@@ -397,6 +405,10 @@
"$WJ = [:LineBreak = Word_Joiner:];"
"$XX = [:LineBreak = Unknown:];"
"$ZW = [:LineBreak = ZWSpace:];"
+ "$ZWJ = \\u200D;"
+ "$EmojiForModsAndSeqs = [\\U0001F466-\\U0001F469];"
+ "$EmojiForModsOnly = [\\u261D \\u270A-\\u270C \\U0001F385 \\U0001F3C3-\\U0001F3C4 \\U0001F3C7 \\U0001F3CA \\U0001F442-\\U0001F443 \\U0001F446-\\U0001F450 \\U0001F46E-\\U0001F478 \\U0001F47C \\U0001F481-\\U0001F483 \\U0001F485-\\U0001F487 \\U0001F4AA \\U0001F645-\\U0001F647 \\U0001F64B-\\U0001F64F \\U0001F6B4-\\U0001F6B6 \\U0001F6C0];"
+ "$EmojiMods = [\\U0001F3FB-\\U0001F3FF];"
"$dictionary = [:LineBreak = Complex_Context:];"
"$ALPlus = [$AL $AI $SA $SG $XX];"
"$ALcm = $ALPlus $CM*;"
@@ -473,6 +485,7 @@
"$LB4NonBreaks [$SP $ZW];"
"$CAN_CM $CM* [$SP $ZW];"
"$CM+ [$SP $ZW];"
+ "[$EmojiForModsAndSeqs $EmojiMods] $ZWJ $EmojiForModsAndSeqs;"
"$CAN_CM $CM+;"
"$CM+;"
"$CAN_CM $CM* $WJcm;"
@@ -539,7 +552,8 @@
"$IScm ($ALcm | $HLcm);"
"($ALcm | $HLcm | $NUcm) $OPcm;"
"$CM+ $OPcm;"
- "$CPcm ($ALcm | $HLcm | $NUcm);";
+ "$CPcm ($ALcm | $HLcm | $NUcm);"
+ "[$EmojiForModsAndSeqs $EmojiForModsOnly] $EmojiMods;";
static const char* uax14Reverse =
"!!reverse;"
@@ -577,6 +591,7 @@
"$LF $CR;"
"[$SP $ZW] [$LB4NonBreaks-$CM];"
"[$SP $ZW] $CM+ $CAN_CM;"
+ "$EmojiForModsAndSeqs $ZWJ [$EmojiForModsAndSeqs $EmojiMods];"
"$CM+ $CAN_CM;"
"$CM* $WJ $CM* $CAN_CM;"
"$CM* $WJ [$LB8NonBreaks-$CM];"
@@ -633,7 +648,8 @@
"$CM* ($ALPlus | $HL) $CM* ($ALPlus | $HL);"
"$CM* ($ALPlus | $HL) $CM* $IS;"
"$CM* $OP $CM* ($ALPlus | $HL | $NU);"
- "$CM* ($ALPlus | $HL | $NU) $CM* $CP;";
+ "$CM* ($ALPlus | $HL | $NU) $CM* $CP;"
+ "$EmojiMods [$EmojiForModsAndSeqs $EmojiForModsOnly];";
static const char* uax14SafeForward =
"!!safe_forward;"
Modified: branches/safari-600.1.4.15-branch/Source/WebCore/rendering/RenderText.cpp (179734 => 179735)
--- branches/safari-600.1.4.15-branch/Source/WebCore/rendering/RenderText.cpp 2015-02-06 01:40:21 UTC (rev 179734)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/rendering/RenderText.cpp 2015-02-06 02:04:19 UTC (rev 179735)
@@ -1397,23 +1397,33 @@
HangulStateBreak
};
-inline bool isHangulLVT(UChar32 character)
+static inline bool isHangulLVT(UChar32 character)
{
return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;
}
-inline bool isMark(UChar32 c)
+static inline bool isMark(UChar32 character)
{
- int8_t charType = u_charType(c);
+ int8_t charType = u_charType(character);
return charType == U_NON_SPACING_MARK || charType == U_ENCLOSING_MARK || charType == U_COMBINING_SPACING_MARK;
}
-inline bool isRegionalIndicator(UChar32 c)
+static inline bool isRegionalIndicator(UChar32 character)
{
// National flag emoji each consists of a pair of regional indicator symbols.
- return 0x1F1E6 <= c && c <= 0x1F1FF;
+ return 0x1F1E6 <= character && character <= 0x1F1FF;
}
+static inline bool isEmojiGroupCandidate(UChar32 character)
+{
+ return character >= 0x1F466 && character <= 0x1F469;
+}
+
+static inline bool isEmojiModifier(UChar32 character)
+{
+ return character >= 0x1F3FB && character <= 0x1F3FF;
+}
+
#endif
int RenderText::previousOffsetForBackwardDeletion(int current) const
@@ -1423,6 +1433,9 @@
StringImpl& text = *m_text.impl();
UChar32 character;
bool sawRegionalIndicator = false;
+ bool sawEmojiGroupCandidate = false;
+ bool sawEmojiModifier = false;
+
while (current > 0) {
if (U16_IS_TRAIL(text[--current]))
--current;
@@ -1431,6 +1444,22 @@
UChar32 character = text.characterStartingAt(current);
+ if (sawEmojiGroupCandidate) {
+ sawEmojiGroupCandidate = false;
+ if (character == zeroWidthJoiner)
+ continue;
+ // We could have two emoji group candidates without a joiner in between.
+ // Those should not be treated as a group.
+ U16_FWD_1_UNSAFE(text, current);
+ break;
+ }
+
+ if (sawEmojiModifier) {
+ if (isEmojiModifier(character))
+ U16_FWD_1_UNSAFE(text, current);
+ break;
+ }
+
if (sawRegionalIndicator) {
// We don't check if the pair of regional indicator symbols before current position can actually be combined
// into a flag, and just delete it. This may not agree with how the pair is rendered in edge cases,
@@ -1449,7 +1478,17 @@
sawRegionalIndicator = true;
continue;
}
+
+ if (isEmojiModifier(character)) {
+ sawEmojiModifier = true;
+ continue;
+ }
+ if (isEmojiGroupCandidate(character)) {
+ sawEmojiGroupCandidate = true;
+ continue;
+ }
+
if (!isMark(character) && (character != 0xFF9E) && (character != 0xFF9F))
break;
}