1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All
3 * rights reserved.
4 * Copyright (C) 2005 Alexey Proskuryakov.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "third_party/blink/renderer/core/editing/iterators/character_iterator.h"
29
30 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
31
32 namespace blink {
33
34 template <typename Strategy>
CharacterIteratorAlgorithm(const PositionTemplate<Strategy> & start,const PositionTemplate<Strategy> & end,const TextIteratorBehavior & behavior)35 CharacterIteratorAlgorithm<Strategy>::CharacterIteratorAlgorithm(
36 const PositionTemplate<Strategy>& start,
37 const PositionTemplate<Strategy>& end,
38 const TextIteratorBehavior& behavior)
39 : offset_(0),
40 run_offset_(0),
41 at_break_(true),
42 text_iterator_(start, end, behavior) {
43 Initialize();
44 }
45
46 template <typename Strategy>
CharacterIteratorAlgorithm(const EphemeralRangeTemplate<Strategy> & range,const TextIteratorBehavior & behavior)47 CharacterIteratorAlgorithm<Strategy>::CharacterIteratorAlgorithm(
48 const EphemeralRangeTemplate<Strategy>& range,
49 const TextIteratorBehavior& behavior)
50 : CharacterIteratorAlgorithm(range.StartPosition(),
51 range.EndPosition(),
52 behavior) {}
53
54 template <typename Strategy>
Initialize()55 void CharacterIteratorAlgorithm<Strategy>::Initialize() {
56 while (!AtEnd() && !text_iterator_.length())
57 text_iterator_.Advance();
58 }
59
60 template <typename Strategy>
OwnerDocument() const61 const Document& CharacterIteratorAlgorithm<Strategy>::OwnerDocument() const {
62 return text_iterator_.OwnerDocument();
63 }
64
65 template <typename Strategy>
CurrentContainer() const66 const Node& CharacterIteratorAlgorithm<Strategy>::CurrentContainer() const {
67 return text_iterator_.CurrentContainer();
68 }
69
70 template <typename Strategy>
StartOffset() const71 int CharacterIteratorAlgorithm<Strategy>::StartOffset() const {
72 if (!text_iterator_.AtEnd()) {
73 if (text_iterator_.length() > 1)
74 return text_iterator_.StartOffsetInCurrentContainer() + run_offset_;
75 DCHECK(!run_offset_);
76 }
77 return text_iterator_.StartOffsetInCurrentContainer();
78 }
79
80 template <typename Strategy>
EndOffset() const81 int CharacterIteratorAlgorithm<Strategy>::EndOffset() const {
82 if (!text_iterator_.AtEnd()) {
83 if (text_iterator_.length() > 1)
84 return text_iterator_.StartOffsetInCurrentContainer() + run_offset_ + 1;
85 DCHECK(!run_offset_);
86 }
87 return text_iterator_.EndOffsetInCurrentContainer();
88 }
89
90 template <typename Strategy>
91 PositionTemplate<Strategy>
GetPositionBefore() const92 CharacterIteratorAlgorithm<Strategy>::GetPositionBefore() const {
93 return text_iterator_.GetPositionBefore(run_offset_);
94 }
95
96 template <typename Strategy>
97 PositionTemplate<Strategy>
GetPositionAfter() const98 CharacterIteratorAlgorithm<Strategy>::GetPositionAfter() const {
99 return text_iterator_.GetPositionAfter(run_offset_);
100 }
101
102 template <typename Strategy>
StartPosition() const103 PositionTemplate<Strategy> CharacterIteratorAlgorithm<Strategy>::StartPosition()
104 const {
105 if (!text_iterator_.AtEnd()) {
106 if (text_iterator_.length() > 1) {
107 const Node& node = text_iterator_.CurrentContainer();
108 int offset = text_iterator_.StartOffsetInCurrentContainer() + run_offset_;
109 return PositionTemplate<Strategy>::EditingPositionOf(&node, offset);
110 }
111 DCHECK(!run_offset_);
112 }
113 return text_iterator_.StartPositionInCurrentContainer();
114 }
115
116 template <typename Strategy>
EndPosition() const117 PositionTemplate<Strategy> CharacterIteratorAlgorithm<Strategy>::EndPosition()
118 const {
119 if (!text_iterator_.AtEnd()) {
120 if (text_iterator_.length() > 1) {
121 const Node& node = text_iterator_.CurrentContainer();
122 int offset = text_iterator_.StartOffsetInCurrentContainer() + run_offset_;
123 return PositionTemplate<Strategy>::EditingPositionOf(&node, offset + 1);
124 }
125 DCHECK(!run_offset_);
126 }
127 return text_iterator_.EndPositionInCurrentContainer();
128 }
129
130 template <typename Strategy>
Advance(int count)131 void CharacterIteratorAlgorithm<Strategy>::Advance(int count) {
132 if (count <= 0) {
133 DCHECK(!count);
134 return;
135 }
136
137 DCHECK(!AtEnd());
138
139 at_break_ = false;
140
141 // easy if there is enough left in the current text_iterator_ run
142 int remaining = text_iterator_.length() - run_offset_;
143 if (count < remaining) {
144 run_offset_ += count;
145 offset_ += count;
146 return;
147 }
148
149 // exhaust the current text_iterator_ run
150 count -= remaining;
151 offset_ += remaining;
152
153 // move to a subsequent text_iterator_ run
154 for (text_iterator_.Advance(); !AtEnd(); text_iterator_.Advance()) {
155 int run_length = text_iterator_.length();
156 if (!run_length) {
157 at_break_ = text_iterator_.BreaksAtReplacedElement();
158 } else {
159 // see whether this is text_iterator_ to use
160 if (count < run_length) {
161 run_offset_ = count;
162 offset_ += count;
163 return;
164 }
165
166 // exhaust this text_iterator_ run
167 count -= run_length;
168 offset_ += run_length;
169 }
170 }
171
172 // ran to the end of the text_iterator_... no more runs left
173 at_break_ = true;
174 run_offset_ = 0;
175 }
176
177 template <typename Strategy>
178 EphemeralRangeTemplate<Strategy>
CalculateCharacterSubrange(int offset,int length)179 CharacterIteratorAlgorithm<Strategy>::CalculateCharacterSubrange(int offset,
180 int length) {
181 Advance(offset);
182 const PositionTemplate<Strategy> start_pos = StartPosition();
183
184 if (!length)
185 return EphemeralRangeTemplate<Strategy>(start_pos, start_pos);
186 if (length > 1)
187 Advance(length - 1);
188 return EphemeralRangeTemplate<Strategy>(start_pos, EndPosition());
189 }
190
CalculateCharacterSubrange(const EphemeralRange & range,int character_offset,int character_count)191 EphemeralRange CalculateCharacterSubrange(const EphemeralRange& range,
192 int character_offset,
193 int character_count) {
194 CharacterIterator entire_range_iterator(
195 range, TextIteratorBehavior::Builder()
196 .SetEmitsObjectReplacementCharacter(true)
197 .Build());
198 return entire_range_iterator.CalculateCharacterSubrange(character_offset,
199 character_count);
200 }
201
202 template class CORE_TEMPLATE_EXPORT CharacterIteratorAlgorithm<EditingStrategy>;
203 template class CORE_TEMPLATE_EXPORT
204 CharacterIteratorAlgorithm<EditingInFlatTreeStrategy>;
205
206 } // namespace blink
207