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

Unified Diff: third_party/WebKit/Source/core/editing/state_machines/ForwardGraphemeBoundaryStateMachine.cpp

Issue 1857633002: Introduce ForwardGraphemeBoundaryStateMachine (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebasing 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/editing/state_machines/ForwardGraphemeBoundaryStateMachine.cpp
diff --git a/third_party/WebKit/Source/core/editing/state_machines/ForwardGraphemeBoundaryStateMachine.cpp b/third_party/WebKit/Source/core/editing/state_machines/ForwardGraphemeBoundaryStateMachine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d63161ef1323546602dd63182141920a960aa429
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/state_machines/ForwardGraphemeBoundaryStateMachine.cpp
@@ -0,0 +1,266 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/editing/state_machines/ForwardGraphemeBoundaryStateMachine.h"
+
+#include "core/editing/state_machines/StateMachineUtil.h"
+#include "core/editing/state_machines/TextSegmentationMachineState.h"
+#include "platform/fonts/Character.h"
+#include "wtf/text/Unicode.h"
+#include <ostream> // NOLINT
+
+namespace blink {
+
+#define FOR_EACH_FORWARD_GRAPHEME_BOUNDARY_STATE(V) \
+ /* Counting preceding regional indicators. This is initial state. */ \
+ V(CountRIS) \
+ /* Waiting lead surrogate during counting regional indicators. */ \
+ V(CountRISWaitLeadSurrogate) \
+ /* Waiting first following code unit. */ \
+ V(StartForward) \
+ /* Waiting trail surrogate for the first following code point. */ \
+ V(StartForwardWaitTrailSurrgate) \
+ /* Searching grapheme boundary. */ \
+ V(Search) \
+ /* Waiting trail surrogate during searching grapheme boundary. */ \
+ V(SearchWaitTrailSurrogate) \
+ /* The state machine has stopped. */ \
+ V(Finished)
+
+enum class ForwardGraphemeBoundaryStateMachine::InternalState {
+#define V(name) name,
+ FOR_EACH_FORWARD_GRAPHEME_BOUNDARY_STATE(V)
+#undef V
+};
+
+std::ostream& operator<<(std::ostream& os,
+ ForwardGraphemeBoundaryStateMachine::InternalState state)
+{
+ static const char* const texts[] = {
+#define V(name) #name,
+ FOR_EACH_FORWARD_GRAPHEME_BOUNDARY_STATE(V)
+#undef V
+ };
+ const auto& it = std::begin(texts) + static_cast<size_t>(state);
+ DCHECK_GE(it, std::begin(texts)) << "Unknown state value";
+ DCHECK_LT(it, std::end(texts)) << "Unknown state value";
+ return os << *it;
+}
+
+ForwardGraphemeBoundaryStateMachine::ForwardGraphemeBoundaryStateMachine()
+ : m_internalState(InternalState::CountRIS)
+{
+}
+
+TextSegmentationMachineState
+ForwardGraphemeBoundaryStateMachine::feedPrecedingCodeUnit(UChar codeUnit)
+{
+ DCHECK_EQ(m_prevCodePoint, 0);
+ DCHECK_EQ(m_boundaryOffset, 0);
+ switch (m_internalState) {
+ case InternalState::CountRIS:
+ DCHECK_EQ(m_pendingCodeUnit, 0);
+ if (U16_IS_TRAIL(codeUnit)) {
+ m_pendingCodeUnit = codeUnit;
+ return moveToNextState(InternalState::CountRISWaitLeadSurrogate);
+ }
+ return moveToNextState(InternalState::StartForward);
+ case InternalState::CountRISWaitLeadSurrogate:
+ DCHECK_NE(m_pendingCodeUnit, 0);
+ if (U16_IS_LEAD(codeUnit)) {
+ const UChar32 codePoint =
+ U16_GET_SUPPLEMENTARY(codeUnit, m_pendingCodeUnit);
+ m_pendingCodeUnit = 0;
+ if (Character::isRegionalIndicator(codePoint)) {
+ ++m_precedingRISCount;
+ return moveToNextState(InternalState::CountRIS);
+ }
+ }
+ m_pendingCodeUnit = 0;
+ return moveToNextState(InternalState::StartForward);
+ case InternalState::StartForward: // Fallthrough
+ case InternalState::StartForwardWaitTrailSurrgate: // Fallthrough
+ case InternalState::Search: // Fallthrough
+ case InternalState::SearchWaitTrailSurrogate: // Fallthrough
+ NOTREACHED() << "Do not call feedPrecedingCodeUnit() once "
+ << TextSegmentationMachineState::NeedFollowingCodeUnit
+ << " is returned. InternalState: " << m_internalState;
+ return finish();
+ case InternalState::Finished:
+ NOTREACHED() << "Do not call feedPrecedingCodeUnit() once it finishes.";
+ return finish();
+ }
+ NOTREACHED() << "Unhandled state: " << m_internalState;
+ return finish();
+}
+
+TextSegmentationMachineState
+ForwardGraphemeBoundaryStateMachine::feedFollowingCodeUnit(UChar codeUnit)
+{
+ switch (m_internalState) {
+ case InternalState::CountRIS: // Fallthrough
+ case InternalState::CountRISWaitLeadSurrogate:
+ NOTREACHED() << "Do not call feedFollowingCodeUnit() until "
+ << TextSegmentationMachineState::NeedFollowingCodeUnit
+ << " is returned. InternalState: " << m_internalState;
+ return finish();
+ case InternalState::StartForward:
+ DCHECK_EQ(m_prevCodePoint, 0);
+ DCHECK_EQ(m_boundaryOffset, 0);
+ DCHECK_EQ(m_pendingCodeUnit, 0);
+ if (U16_IS_TRAIL(codeUnit)) {
+ // Lonely trail surrogate.
+ m_boundaryOffset = 1;
+ return finish();
+ }
+ if (U16_IS_LEAD(codeUnit)) {
+ m_pendingCodeUnit = codeUnit;
+ return moveToNextState(
+ InternalState::StartForwardWaitTrailSurrgate);
+ }
+ m_prevCodePoint = codeUnit;
+ m_boundaryOffset = 1;
+ return moveToNextState(InternalState::Search);
+ case InternalState::StartForwardWaitTrailSurrgate:
+ DCHECK_EQ(m_prevCodePoint, 0);
+ DCHECK_EQ(m_boundaryOffset, 0);
+ DCHECK_NE(m_pendingCodeUnit, 0);
+ if (U16_IS_TRAIL(codeUnit)) {
+ m_prevCodePoint =
+ U16_GET_SUPPLEMENTARY(m_pendingCodeUnit, codeUnit);
+ m_boundaryOffset = 2;
+ m_pendingCodeUnit = 0;
+ return moveToNextState(InternalState::Search);
+ }
+ // Lonely lead surrogate.
+ m_boundaryOffset = 1;
+ return finish();
+ case InternalState::Search:
+ DCHECK_NE(m_prevCodePoint, 0);
+ DCHECK_NE(m_boundaryOffset, 0);
+ DCHECK_EQ(m_pendingCodeUnit, 0);
+ if (U16_IS_LEAD(codeUnit)) {
+ m_pendingCodeUnit = codeUnit;
+ return moveToNextState(InternalState::SearchWaitTrailSurrogate);
+ }
+ if (U16_IS_TRAIL(codeUnit))
+ return finish(); // Lonely trail surrogate.
+ if (isGraphemeBreak(m_prevCodePoint, codeUnit))
+ return finish();
+ m_prevCodePoint = codeUnit;
+ m_boundaryOffset += 1;
+ return staySameState();
+ case InternalState::SearchWaitTrailSurrogate:
+ DCHECK_NE(m_prevCodePoint, 0);
+ DCHECK_NE(m_boundaryOffset, 0);
+ DCHECK_NE(m_pendingCodeUnit, 0);
+ if (!U16_IS_TRAIL(codeUnit))
+ return finish(); // Lonely lead surrogate.
+
+ {
+ const UChar32 codePoint =
+ U16_GET_SUPPLEMENTARY(m_pendingCodeUnit, codeUnit);
+ m_pendingCodeUnit = 0;
+ if (Character::isRegionalIndicator(m_prevCodePoint)
+ && Character::isRegionalIndicator(codePoint)) {
+ if (m_precedingRISCount % 2 == 0) {
+ // Odd numbered RI case, note that m_prevCodePoint is also
+ // RI.
+ m_boundaryOffset += 2;
+ }
+ return finish();
+ }
+ if (isGraphemeBreak(m_prevCodePoint, codePoint))
+ return finish();
+ m_prevCodePoint = codePoint;
+ m_boundaryOffset += 2;
+ return moveToNextState(InternalState::Search);
+ }
+ case InternalState::Finished:
+ NOTREACHED() << "Do not call feedFollowingCodeUnit() once it finishes.";
+ return finish();
+ }
+ NOTREACHED() << "Unhandled staet: " << m_internalState;
+ return finish();
+}
+
+TextSegmentationMachineState
+ForwardGraphemeBoundaryStateMachine::tellEndOfPrecedingText()
+{
+ DCHECK(m_internalState == InternalState::CountRIS
+ || m_internalState == InternalState::CountRISWaitLeadSurrogate)
+ << "Do not call tellEndOfPrecedingText() once "
+ << TextSegmentationMachineState::NeedFollowingCodeUnit
+ << " is returned. InternalState: " << m_internalState;
+
+ // Clear pending code unit since preceding buffer may end with lonely trail
+ // surrogate. We can just ignore it since preceding buffer is only used for
+ // counting preceding regional indicators.
+ m_pendingCodeUnit = 0;
+ return moveToNextState(InternalState::StartForward);
+}
+
+int ForwardGraphemeBoundaryStateMachine::finalizeAndGetBoundaryOffset()
+{
+ if (m_internalState != InternalState::Finished)
+ finishWithEndOfText();
+ DCHECK_GE(m_boundaryOffset, 0);
+ return m_boundaryOffset;
+}
+
+void ForwardGraphemeBoundaryStateMachine::reset()
+{
+ m_pendingCodeUnit = 0;
+ m_boundaryOffset = 0;
+ m_precedingRISCount = 0;
+ m_prevCodePoint = 0;
+ m_internalState = InternalState::CountRIS;
+}
+
+TextSegmentationMachineState ForwardGraphemeBoundaryStateMachine::finish()
+{
+ DCHECK_NE(m_internalState, InternalState::Finished);
+ m_internalState = InternalState::Finished;
+ return TextSegmentationMachineState::Finished;
+}
+
+TextSegmentationMachineState
+ForwardGraphemeBoundaryStateMachine::moveToNextState(InternalState nextState)
+{
+ DCHECK_NE(nextState, InternalState::Finished) << "Use finish() instead";
+ DCHECK_NE(nextState, m_internalState) << "Use staySameSatate() instead";
+ m_internalState = nextState;
+ if (nextState == InternalState::StartForward)
+ return TextSegmentationMachineState::NeedFollowingCodeUnit;
+ return TextSegmentationMachineState::NeedMoreCodeUnit;
+}
+
+TextSegmentationMachineState
+ForwardGraphemeBoundaryStateMachine::staySameState()
+{
+ DCHECK_EQ(m_internalState, InternalState::Search)
+ << "Only Search can stay the same state.";
+ return TextSegmentationMachineState::NeedMoreCodeUnit;
+}
+
+void ForwardGraphemeBoundaryStateMachine::finishWithEndOfText()
+{
+ switch (m_internalState) {
+ case InternalState::CountRIS: // Fallthrough
+ case InternalState::CountRISWaitLeadSurrogate: // Fallthrough
+ case InternalState::StartForward: // Fallthrough
+ return; // Haven't search anything to forward. Just finish.
+ case InternalState::StartForwardWaitTrailSurrgate:
+ // Lonely lead surrogate.
+ m_boundaryOffset = 1;
+ return;
+ case InternalState::Search: // Fallthrough
+ case InternalState::SearchWaitTrailSurrogate: // Fallthrough
+ return;
+ case InternalState::Finished: // Fallthrough
+ NOTREACHED() << "Do not call finishWithEndOfText() once it finishes.";
+ }
+ NOTREACHED() << "Unhandled state: " << m_internalState;
+}
+} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698