Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(225)

Unified Diff: third_party/WebKit/Source/core/editing/BackspaceStateMachine.cpp

Issue 1844663002: Implement backspace state machine for complex emoji sequence. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/editing/BackspaceStateMachine.cpp
diff --git a/third_party/WebKit/Source/core/editing/BackspaceStateMachine.cpp b/third_party/WebKit/Source/core/editing/BackspaceStateMachine.cpp
index fdc8b9292eef3b96b90b590dc134c256d2d95b58..02d3421b985bc062edb346ce97e2483fe9170540 100644
--- a/third_party/WebKit/Source/core/editing/BackspaceStateMachine.cpp
+++ b/third_party/WebKit/Source/core/editing/BackspaceStateMachine.cpp
@@ -4,12 +4,34 @@
#include "core/editing/BackspaceStateMachine.h"
+#include "platform/fonts/Character.h"
#include "wtf/text/Unicode.h"
namespace blink {
+namespace {
+
+const uint32_t kCarriageReturn = 0x000D;
+const uint32_t kLineFeed = 0x000A;
+const uint32_t kZWJ = 0x200D;
+const uint32_t kCombiningEnclosingKeycap = 0x20E3;
+
+// Returns true if the code point can be a part of ZWJ sequence.
+bool isZwjEmoji(uint32_t codePoint)
+{
+ return codePoint == 0x2764 // HEAVY BLACK HEART
+ || codePoint == 0x1F441 // EYE
+ || (codePoint >= 0x1F466 && codePoint <= 0x1F469) // BOY, GIRL, MAN, WOMAN
+ || codePoint == 0x1F48B // KISS MARK
+ || codePoint == 0x1F5E8; // LEFT SPEECH BUBBLE
+}
+
+} // namespace
+
BackspaceStateMachine::State BackspaceStateMachine::feedPrecedingCodeUnit(UChar codeUnit)
{
+ if (m_state == BackspaceState::Finished)
+ return State::Finished; // Already finished.
yosin_UTC9 2016/03/30 04:05:57 I think attempting update state for finished state
Seigo Nonaka 2016/03/30 08:50:15 Sure added DCHECK_NE and operator function.
uint32_t codePoint = codeUnit;
if (U16_IS_LEAD(codeUnit)) {
if (m_trailSurrogate == 0) {
@@ -35,9 +57,134 @@ BackspaceStateMachine::State BackspaceStateMachine::feedPrecedingCodeUnit(UChar
}
}
- // TODO(nona): Handle emoji sequences.
- m_codeUnitsToBeDeleted = U16_LENGTH(codePoint);
- return State::Finished;
+ switch (m_state) {
+ case BackspaceState::Start:
+ m_codeUnitsToBeDeleted = U16_LENGTH(codePoint);
+ if (codePoint == kLineFeed)
+ m_state = BackspaceState::BeforeLF;
yosin_UTC9 2016/03/30 04:05:57 I suggest to introduce member functions |State nee
Seigo Nonaka 2016/03/30 08:50:15 I applied your suggestions. Thank you.
+ else if (u_hasBinaryProperty(codePoint, UCHAR_VARIATION_SELECTOR))
+ m_state = BackspaceState::BeforeVS;
+ else if (isZwjEmoji(codePoint))
+ m_state = BackspaceState::BeforeZWJEmoji;
+ else if (Character::isRegionalIndicator(codePoint))
+ m_state = BackspaceState::OddNumberedRIS;
+ else if (Character::isModifier(codePoint))
+ m_state = BackspaceState::BeforeEmojiModifier;
+ else if (codePoint == kCombiningEnclosingKeycap)
+ m_state = BackspaceState::BeforeKeycap;
+ else
+ m_state = BackspaceState::Finished;
+ break;
+ case BackspaceState::BeforeLF:
+ if (codePoint == kCarriageReturn)
+ ++m_codeUnitsToBeDeleted;
+ m_state = BackspaceState::Finished;
+ break;
+ case BackspaceState::BeforeKeycap:
+ if (u_hasBinaryProperty(codePoint, UCHAR_VARIATION_SELECTOR)) {
+ DCHECK_EQ(m_lastSeenVSCodeUnits, 0);
+ m_lastSeenVSCodeUnits = U16_LENGTH(codePoint);
+ m_state = BackspaceState::BeforeVSAndKeycap;
+ break;
+ }
+ if (Character::isEmojiKeycapBase(codePoint))
+ m_codeUnitsToBeDeleted += U16_LENGTH(codePoint);
+ m_state = BackspaceState::Finished;
+ break;
+ case BackspaceState::BeforeVSAndKeycap:
+ if (Character::isEmojiKeycapBase(codePoint)) {
+ DCHECK_NE(m_lastSeenVSCodeUnits, 0);
+ DCHECK_LE(m_lastSeenVSCodeUnits, 2);
+ m_codeUnitsToBeDeleted += m_lastSeenVSCodeUnits + U16_LENGTH(codePoint);
+ }
+ m_lastSeenVSCodeUnits = 0;
+ m_state = BackspaceState::Finished;
+ break;
+ case BackspaceState::BeforeEmojiModifier:
+ if (u_hasBinaryProperty(codePoint, UCHAR_VARIATION_SELECTOR)) {
+ DCHECK_EQ(m_lastSeenVSCodeUnits, 0);
+ m_lastSeenVSCodeUnits = U16_LENGTH(codePoint);
+ m_state = BackspaceState::BeforeVSAndEmojiModifier;
+ break;
+ }
+ if (Character::isEmojiModifierBase(codePoint))
+ m_codeUnitsToBeDeleted += U16_LENGTH(codePoint);
+ m_state = BackspaceState::Finished;
+ break;
+ case BackspaceState::BeforeVSAndEmojiModifier:
+ if (Character::isEmojiModifierBase(codePoint)) {
+ DCHECK_NE(m_lastSeenVSCodeUnits, 0);
+ DCHECK_LE(m_lastSeenVSCodeUnits, 2);
+ m_codeUnitsToBeDeleted += m_lastSeenVSCodeUnits + U16_LENGTH(codePoint);
+ }
+ m_lastSeenVSCodeUnits = 0;
+ m_state = BackspaceState::Finished;
+ break;
+ case BackspaceState::BeforeVS:
+ if (isZwjEmoji(codePoint)) {
+ m_codeUnitsToBeDeleted += U16_LENGTH(codePoint);
+ m_state = BackspaceState::BeforeZWJEmoji;
+ break;
+ }
+
+ if (!u_hasBinaryProperty(codePoint, UCHAR_VARIATION_SELECTOR)
+ && u_getCombiningClass(codePoint) == 0) {
+ m_codeUnitsToBeDeleted += U16_LENGTH(codePoint);
+ }
+ m_state = BackspaceState::Finished;
+ break;
+ case BackspaceState::BeforeZWJEmoji:
+ if (codePoint == kZWJ)
+ m_state = BackspaceState::BeforeZWJ;
+ else
+ m_state = BackspaceState::Finished;
+ break;
+ case BackspaceState::BeforeZWJ:
+ if (isZwjEmoji(codePoint)) {
+ m_codeUnitsToBeDeleted += U16_LENGTH(codePoint) + 1; // +1 for ZWJ
+ m_state = BackspaceState::BeforeZWJEmoji;
+ } else if (u_hasBinaryProperty(codePoint, UCHAR_VARIATION_SELECTOR)) {
+ DCHECK_EQ(m_lastSeenVSCodeUnits, 0);
+ m_lastSeenVSCodeUnits = U16_LENGTH(codePoint);
+ m_state = BackspaceState::BeforeVSAndZWJ;
+ } else {
+ m_state = BackspaceState::Finished;
+ }
+ break;
+ case BackspaceState::BeforeVSAndZWJ:
+ if (isZwjEmoji(codePoint)) {
+ DCHECK_NE(m_lastSeenVSCodeUnits, 0);
+ DCHECK_LE(m_lastSeenVSCodeUnits, 2);
+ // +1 for ZWJ
+ m_codeUnitsToBeDeleted += U16_LENGTH(codePoint) + 1 + m_lastSeenVSCodeUnits;
+ m_lastSeenVSCodeUnits = 0;
+ m_state = BackspaceState::BeforeZWJEmoji;
+ } else {
+ m_state = BackspaceState::Finished;
+ }
+ break;
+ case BackspaceState::OddNumberedRIS:
+ if (Character::isRegionalIndicator(codePoint)) {
+ m_codeUnitsToBeDeleted += 2; // Code units of RIS
+ m_state = BackspaceState::EvenNumberedRIS;
+ } else {
+ m_state = BackspaceState::Finished;
+ }
+ break;
+ case BackspaceState::EvenNumberedRIS:
+ if (Character::isRegionalIndicator(codePoint)) {
+ m_codeUnitsToBeDeleted -= 2; // Code units of RIS
+ m_state = BackspaceState::OddNumberedRIS;
+ } else {
+ m_state = BackspaceState::Finished;
+ }
+ break;
+ case BackspaceState::Finished:
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return m_state == BackspaceState::Finished ? State::Finished : State::NeedMoreCodeUnit;
}
BackspaceStateMachine::State BackspaceStateMachine::feedFollowingCodeUnit(UChar codeUnit)
@@ -52,6 +199,10 @@ int BackspaceStateMachine::finalizeAndGetBoundaryOffset()
++m_codeUnitsToBeDeleted;
m_trailSurrogate = 0;
}
+ if (m_state != BackspaceState::Finished) {
+ m_lastSeenVSCodeUnits = 0;
+ m_state = BackspaceState::Finished;
+ }
return -m_codeUnitsToBeDeleted;
}
@@ -59,6 +210,8 @@ void BackspaceStateMachine::reset()
{
m_codeUnitsToBeDeleted = 0;
m_trailSurrogate = 0;
+ m_state = BackspaceState::Start;
+ m_lastSeenVSCodeUnits = 0;
}
} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698