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
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/core/editing/state_machines/state_machine_test_util.h"
6
7 #include <algorithm>
8 #include "third_party/blink/renderer/core/editing/state_machines/backward_grapheme_boundary_state_machine.h"
9 #include "third_party/blink/renderer/core/editing/state_machines/forward_grapheme_boundary_state_machine.h"
10 #include "third_party/blink/renderer/core/editing/state_machines/text_segmentation_machine_state.h"
11 #include "third_party/blink/renderer/platform/wtf/assertions.h"
12 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
13
14 namespace blink {
15
16 namespace {
MachineStateToChar(TextSegmentationMachineState state)17 char MachineStateToChar(TextSegmentationMachineState state) {
18 static const char kIndicators[] = {
19 'I', // Invalid
20 'R', // NeedMoreCodeUnit (Repeat)
21 'S', // NeedFollowingCodeUnit (Switch)
22 'F', // Finished
23 };
24 auto* const it = std::begin(kIndicators) + static_cast<size_t>(state);
25 DCHECK_GE(it, std::begin(kIndicators)) << "Unknown backspace value";
26 DCHECK_LT(it, std::end(kIndicators)) << "Unknown backspace value";
27 return *it;
28 }
29
CodePointsToCodeUnits(const Vector<UChar32> & code_points)30 Vector<UChar> CodePointsToCodeUnits(const Vector<UChar32>& code_points) {
31 Vector<UChar> out;
32 for (const auto& code_point : code_points) {
33 if (U16_LENGTH(code_point) == 2) {
34 out.push_back(U16_LEAD(code_point));
35 out.push_back(U16_TRAIL(code_point));
36 } else {
37 out.push_back(static_cast<UChar>(code_point));
38 }
39 }
40 return out;
41 }
42
43 template <typename StateMachine>
ProcessSequence(StateMachine * machine,const Vector<UChar32> & preceding,const Vector<UChar32> & following)44 String ProcessSequence(StateMachine* machine,
45 const Vector<UChar32>& preceding,
46 const Vector<UChar32>& following) {
47 machine->Reset();
48 StringBuilder out;
49 TextSegmentationMachineState state = TextSegmentationMachineState::kInvalid;
50 Vector<UChar> preceding_code_units = CodePointsToCodeUnits(preceding);
51 std::reverse(preceding_code_units.begin(), preceding_code_units.end());
52 for (const auto& code_unit : preceding_code_units) {
53 state = machine->FeedPrecedingCodeUnit(code_unit);
54 out.Append(MachineStateToChar(state));
55 switch (state) {
56 case TextSegmentationMachineState::kInvalid:
57 case TextSegmentationMachineState::kFinished:
58 return out.ToString();
59 case TextSegmentationMachineState::kNeedMoreCodeUnit:
60 continue;
61 case TextSegmentationMachineState::kNeedFollowingCodeUnit:
62 break;
63 }
64 }
65 if (preceding.IsEmpty() ||
66 state == TextSegmentationMachineState::kNeedMoreCodeUnit) {
67 state = machine->TellEndOfPrecedingText();
68 out.Append(MachineStateToChar(state));
69 }
70 if (state == TextSegmentationMachineState::kFinished)
71 return out.ToString();
72
73 Vector<UChar> following_code_units = CodePointsToCodeUnits(following);
74 for (const auto& code_unit : following_code_units) {
75 state = machine->FeedFollowingCodeUnit(code_unit);
76 out.Append(MachineStateToChar(state));
77 switch (state) {
78 case TextSegmentationMachineState::kInvalid:
79 case TextSegmentationMachineState::kFinished:
80 return out.ToString();
81 case TextSegmentationMachineState::kNeedMoreCodeUnit:
82 continue;
83 case TextSegmentationMachineState::kNeedFollowingCodeUnit:
84 break;
85 }
86 }
87 return out.ToString();
88 }
89 } // namespace
90
ProcessSequenceBackward(BackwardGraphemeBoundaryStateMachine * machine,const Vector<UChar32> & preceding)91 String GraphemeStateMachineTestBase::ProcessSequenceBackward(
92 BackwardGraphemeBoundaryStateMachine* machine,
93 const Vector<UChar32>& preceding) {
94 const String& out = ProcessSequence(machine, preceding, Vector<UChar32>());
95 if (machine->FinalizeAndGetBoundaryOffset() !=
96 machine->FinalizeAndGetBoundaryOffset())
97 return "State machine changes final offset after finished.";
98 return out;
99 }
100
ProcessSequenceForward(ForwardGraphemeBoundaryStateMachine * machine,const Vector<UChar32> & preceding,const Vector<UChar32> & following)101 String GraphemeStateMachineTestBase::ProcessSequenceForward(
102 ForwardGraphemeBoundaryStateMachine* machine,
103 const Vector<UChar32>& preceding,
104 const Vector<UChar32>& following) {
105 const String& out = ProcessSequence(machine, preceding, following);
106 if (machine->FinalizeAndGetBoundaryOffset() !=
107 machine->FinalizeAndGetBoundaryOffset())
108 return "State machine changes final offset after finished.";
109 return out;
110 }
111
112 } // namespace blink
113