Chromium Code Reviews| 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 |