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

Side by Side 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, 8 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 unified diff | Download patch
OLDNEW
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698