Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/editing/BackspaceStateMachine.h" | 5 #include "core/editing/BackspaceStateMachine.h" |
| 6 | 6 |
| 7 #include "platform/fonts/Character.h" | |
| 7 #include "wtf/text/Unicode.h" | 8 #include "wtf/text/Unicode.h" |
| 8 | 9 |
| 9 namespace blink { | 10 namespace blink { |
| 10 | 11 |
| 12 namespace { | |
| 13 | |
| 14 const uint32_t kCarriageReturn = 0x000D; | |
| 15 const uint32_t kLineFeed = 0x000A; | |
| 16 const uint32_t kZWJ = 0x200D; | |
| 17 const uint32_t kCombiningEnclosingKeycap = 0x20E3; | |
| 18 | |
| 19 // Returns true if the code point can be a part of ZWJ sequence. | |
| 20 bool isZwjEmoji(uint32_t codePoint) | |
| 21 { | |
| 22 return codePoint == 0x2764 // HEAVY BLACK HEART | |
| 23 || codePoint == 0x1F441 // EYE | |
| 24 || (codePoint >= 0x1F466 && codePoint <= 0x1F469) // BOY, GIRL, MAN, WOM AN | |
| 25 || codePoint == 0x1F48B // KISS MARK | |
| 26 || codePoint == 0x1F5E8; // LEFT SPEECH BUBBLE | |
| 27 } | |
| 28 | |
| 29 } // namespace | |
| 30 | |
| 11 BackspaceStateMachine::State BackspaceStateMachine::feedPrecedingCodeUnit(UChar codeUnit) | 31 BackspaceStateMachine::State BackspaceStateMachine::feedPrecedingCodeUnit(UChar codeUnit) |
| 12 { | 32 { |
| 33 if (m_state == BackspaceState::Finished) | |
| 34 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.
| |
| 13 uint32_t codePoint = codeUnit; | 35 uint32_t codePoint = codeUnit; |
| 14 if (U16_IS_LEAD(codeUnit)) { | 36 if (U16_IS_LEAD(codeUnit)) { |
| 15 if (m_trailSurrogate == 0) { | 37 if (m_trailSurrogate == 0) { |
| 16 // Unpaired lead surrogate. Aborting with deleting broken surrogate. | 38 // Unpaired lead surrogate. Aborting with deleting broken surrogate. |
| 17 ++m_codeUnitsToBeDeleted; | 39 ++m_codeUnitsToBeDeleted; |
| 18 return State::Finished; | 40 return State::Finished; |
| 19 } | 41 } |
| 20 codePoint = U16_GET_SUPPLEMENTARY(codeUnit, m_trailSurrogate); | 42 codePoint = U16_GET_SUPPLEMENTARY(codeUnit, m_trailSurrogate); |
| 21 m_trailSurrogate = 0; | 43 m_trailSurrogate = 0; |
| 22 } else if (U16_IS_TRAIL(codeUnit)) { | 44 } else if (U16_IS_TRAIL(codeUnit)) { |
| 23 if (m_trailSurrogate != 0) { | 45 if (m_trailSurrogate != 0) { |
| 24 // Unpaired trail surrogate. Aborting with deleting broken | 46 // Unpaired trail surrogate. Aborting with deleting broken |
| 25 // surrogate. | 47 // surrogate. |
| 26 return State::Finished; | 48 return State::Finished; |
| 27 } | 49 } |
| 28 m_trailSurrogate = codeUnit; | 50 m_trailSurrogate = codeUnit; |
| 29 return State::NeedMoreCodeUnit; | 51 return State::NeedMoreCodeUnit; |
| 30 } else { | 52 } else { |
| 31 if (m_trailSurrogate != 0) { | 53 if (m_trailSurrogate != 0) { |
| 32 // Unpaired trail surrogate. Aborting with deleting broken | 54 // Unpaired trail surrogate. Aborting with deleting broken |
| 33 // surrogate. | 55 // surrogate. |
| 34 return State::Finished; | 56 return State::Finished; |
| 35 } | 57 } |
| 36 } | 58 } |
| 37 | 59 |
| 38 // TODO(nona): Handle emoji sequences. | 60 switch (m_state) { |
| 39 m_codeUnitsToBeDeleted = U16_LENGTH(codePoint); | 61 case BackspaceState::Start: |
| 40 return State::Finished; | 62 m_codeUnitsToBeDeleted = U16_LENGTH(codePoint); |
| 63 if (codePoint == kLineFeed) | |
| 64 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.
| |
| 65 else if (u_hasBinaryProperty(codePoint, UCHAR_VARIATION_SELECTOR)) | |
| 66 m_state = BackspaceState::BeforeVS; | |
| 67 else if (isZwjEmoji(codePoint)) | |
| 68 m_state = BackspaceState::BeforeZWJEmoji; | |
| 69 else if (Character::isRegionalIndicator(codePoint)) | |
| 70 m_state = BackspaceState::OddNumberedRIS; | |
| 71 else if (Character::isModifier(codePoint)) | |
| 72 m_state = BackspaceState::BeforeEmojiModifier; | |
| 73 else if (codePoint == kCombiningEnclosingKeycap) | |
| 74 m_state = BackspaceState::BeforeKeycap; | |
| 75 else | |
| 76 m_state = BackspaceState::Finished; | |
| 77 break; | |
| 78 case BackspaceState::BeforeLF: | |
| 79 if (codePoint == kCarriageReturn) | |
| 80 ++m_codeUnitsToBeDeleted; | |
| 81 m_state = BackspaceState::Finished; | |
| 82 break; | |
| 83 case BackspaceState::BeforeKeycap: | |
| 84 if (u_hasBinaryProperty(codePoint, UCHAR_VARIATION_SELECTOR)) { | |
| 85 DCHECK_EQ(m_lastSeenVSCodeUnits, 0); | |
| 86 m_lastSeenVSCodeUnits = U16_LENGTH(codePoint); | |
| 87 m_state = BackspaceState::BeforeVSAndKeycap; | |
| 88 break; | |
| 89 } | |
| 90 if (Character::isEmojiKeycapBase(codePoint)) | |
| 91 m_codeUnitsToBeDeleted += U16_LENGTH(codePoint); | |
| 92 m_state = BackspaceState::Finished; | |
| 93 break; | |
| 94 case BackspaceState::BeforeVSAndKeycap: | |
| 95 if (Character::isEmojiKeycapBase(codePoint)) { | |
| 96 DCHECK_NE(m_lastSeenVSCodeUnits, 0); | |
| 97 DCHECK_LE(m_lastSeenVSCodeUnits, 2); | |
| 98 m_codeUnitsToBeDeleted += m_lastSeenVSCodeUnits + U16_LENGTH(codePoi nt); | |
| 99 } | |
| 100 m_lastSeenVSCodeUnits = 0; | |
| 101 m_state = BackspaceState::Finished; | |
| 102 break; | |
| 103 case BackspaceState::BeforeEmojiModifier: | |
| 104 if (u_hasBinaryProperty(codePoint, UCHAR_VARIATION_SELECTOR)) { | |
| 105 DCHECK_EQ(m_lastSeenVSCodeUnits, 0); | |
| 106 m_lastSeenVSCodeUnits = U16_LENGTH(codePoint); | |
| 107 m_state = BackspaceState::BeforeVSAndEmojiModifier; | |
| 108 break; | |
| 109 } | |
| 110 if (Character::isEmojiModifierBase(codePoint)) | |
| 111 m_codeUnitsToBeDeleted += U16_LENGTH(codePoint); | |
| 112 m_state = BackspaceState::Finished; | |
| 113 break; | |
| 114 case BackspaceState::BeforeVSAndEmojiModifier: | |
| 115 if (Character::isEmojiModifierBase(codePoint)) { | |
| 116 DCHECK_NE(m_lastSeenVSCodeUnits, 0); | |
| 117 DCHECK_LE(m_lastSeenVSCodeUnits, 2); | |
| 118 m_codeUnitsToBeDeleted += m_lastSeenVSCodeUnits + U16_LENGTH(codePoi nt); | |
| 119 } | |
| 120 m_lastSeenVSCodeUnits = 0; | |
| 121 m_state = BackspaceState::Finished; | |
| 122 break; | |
| 123 case BackspaceState::BeforeVS: | |
| 124 if (isZwjEmoji(codePoint)) { | |
| 125 m_codeUnitsToBeDeleted += U16_LENGTH(codePoint); | |
| 126 m_state = BackspaceState::BeforeZWJEmoji; | |
| 127 break; | |
| 128 } | |
| 129 | |
| 130 if (!u_hasBinaryProperty(codePoint, UCHAR_VARIATION_SELECTOR) | |
| 131 && u_getCombiningClass(codePoint) == 0) { | |
| 132 m_codeUnitsToBeDeleted += U16_LENGTH(codePoint); | |
| 133 } | |
| 134 m_state = BackspaceState::Finished; | |
| 135 break; | |
| 136 case BackspaceState::BeforeZWJEmoji: | |
| 137 if (codePoint == kZWJ) | |
| 138 m_state = BackspaceState::BeforeZWJ; | |
| 139 else | |
| 140 m_state = BackspaceState::Finished; | |
| 141 break; | |
| 142 case BackspaceState::BeforeZWJ: | |
| 143 if (isZwjEmoji(codePoint)) { | |
| 144 m_codeUnitsToBeDeleted += U16_LENGTH(codePoint) + 1; // +1 for ZWJ | |
| 145 m_state = BackspaceState::BeforeZWJEmoji; | |
| 146 } else if (u_hasBinaryProperty(codePoint, UCHAR_VARIATION_SELECTOR)) { | |
| 147 DCHECK_EQ(m_lastSeenVSCodeUnits, 0); | |
| 148 m_lastSeenVSCodeUnits = U16_LENGTH(codePoint); | |
| 149 m_state = BackspaceState::BeforeVSAndZWJ; | |
| 150 } else { | |
| 151 m_state = BackspaceState::Finished; | |
| 152 } | |
| 153 break; | |
| 154 case BackspaceState::BeforeVSAndZWJ: | |
| 155 if (isZwjEmoji(codePoint)) { | |
| 156 DCHECK_NE(m_lastSeenVSCodeUnits, 0); | |
| 157 DCHECK_LE(m_lastSeenVSCodeUnits, 2); | |
| 158 // +1 for ZWJ | |
| 159 m_codeUnitsToBeDeleted += U16_LENGTH(codePoint) + 1 + m_lastSeenVSCo deUnits; | |
| 160 m_lastSeenVSCodeUnits = 0; | |
| 161 m_state = BackspaceState::BeforeZWJEmoji; | |
| 162 } else { | |
| 163 m_state = BackspaceState::Finished; | |
| 164 } | |
| 165 break; | |
| 166 case BackspaceState::OddNumberedRIS: | |
| 167 if (Character::isRegionalIndicator(codePoint)) { | |
| 168 m_codeUnitsToBeDeleted += 2; // Code units of RIS | |
| 169 m_state = BackspaceState::EvenNumberedRIS; | |
| 170 } else { | |
| 171 m_state = BackspaceState::Finished; | |
| 172 } | |
| 173 break; | |
| 174 case BackspaceState::EvenNumberedRIS: | |
| 175 if (Character::isRegionalIndicator(codePoint)) { | |
| 176 m_codeUnitsToBeDeleted -= 2; // Code units of RIS | |
| 177 m_state = BackspaceState::OddNumberedRIS; | |
| 178 } else { | |
| 179 m_state = BackspaceState::Finished; | |
| 180 } | |
| 181 break; | |
| 182 case BackspaceState::Finished: | |
| 183 default: | |
| 184 ASSERT_NOT_REACHED(); | |
| 185 } | |
| 186 | |
| 187 return m_state == BackspaceState::Finished ? State::Finished : State::NeedMo reCodeUnit; | |
| 41 } | 188 } |
| 42 | 189 |
| 43 BackspaceStateMachine::State BackspaceStateMachine::feedFollowingCodeUnit(UChar codeUnit) | 190 BackspaceStateMachine::State BackspaceStateMachine::feedFollowingCodeUnit(UChar codeUnit) |
| 44 { | 191 { |
| 45 return State::Unknown; | 192 return State::Unknown; |
| 46 } | 193 } |
| 47 | 194 |
| 48 int BackspaceStateMachine::finalizeAndGetBoundaryOffset() | 195 int BackspaceStateMachine::finalizeAndGetBoundaryOffset() |
| 49 { | 196 { |
| 50 if (m_trailSurrogate != 0) { | 197 if (m_trailSurrogate != 0) { |
| 51 // Unpaired trail surrogate. Removing broken surrogate. | 198 // Unpaired trail surrogate. Removing broken surrogate. |
| 52 ++m_codeUnitsToBeDeleted; | 199 ++m_codeUnitsToBeDeleted; |
| 53 m_trailSurrogate = 0; | 200 m_trailSurrogate = 0; |
| 54 } | 201 } |
| 202 if (m_state != BackspaceState::Finished) { | |
| 203 m_lastSeenVSCodeUnits = 0; | |
| 204 m_state = BackspaceState::Finished; | |
| 205 } | |
| 55 return -m_codeUnitsToBeDeleted; | 206 return -m_codeUnitsToBeDeleted; |
| 56 } | 207 } |
| 57 | 208 |
| 58 void BackspaceStateMachine::reset() | 209 void BackspaceStateMachine::reset() |
| 59 { | 210 { |
| 60 m_codeUnitsToBeDeleted = 0; | 211 m_codeUnitsToBeDeleted = 0; |
| 61 m_trailSurrogate = 0; | 212 m_trailSurrogate = 0; |
| 213 m_state = BackspaceState::Start; | |
| 214 m_lastSeenVSCodeUnits = 0; | |
| 62 } | 215 } |
| 63 | 216 |
| 64 } // namespace blink | 217 } // namespace blink |
| OLD | NEW |