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