a325bfb389d6c6450bdf6a1b5eeaa056cb0da287
[WebKit-https.git] / WebCore / editing / VisiblePosition.cpp
1 /*
2  * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "VisiblePosition.h"
28
29 #include "Document.h"
30 #include "Element.h"
31 #include "HTMLNames.h"
32 #include "InlineTextBox.h"
33 #include "Logging.h"
34 #include "Range.h"
35 #include "Text.h"
36 #include "htmlediting.h"
37 #include "visible_units.h"
38
39 namespace WebCore {
40
41 using namespace HTMLNames;
42
43 VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
44 {
45     init(pos, affinity);
46 }
47
48 VisiblePosition::VisiblePosition(Node *node, int offset, EAffinity affinity)
49 {
50     ASSERT(offset >= 0);
51     init(Position(node, offset), affinity);
52 }
53
54 void VisiblePosition::init(const Position& position, EAffinity affinity)
55 {
56     m_affinity = affinity;
57     
58     m_deepPosition = canonicalPosition(position);
59     
60     // When not at a line wrap, make sure to end up with DOWNSTREAM affinity.
61     if (m_affinity == UPSTREAM && (isNull() || inSameLine(VisiblePosition(position, DOWNSTREAM), *this)))
62         m_affinity = DOWNSTREAM;
63 }
64
65 VisiblePosition VisiblePosition::next(bool stayInEditableContent) const
66 {
67     VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
68     
69     if (!stayInEditableContent)
70         return next;
71     
72     return firstEditablePositionAtOrAfter(next);
73 }
74
75 VisiblePosition VisiblePosition::previous(bool stayInEditableContent) const
76 {
77     // find first previous DOM position that is visible
78     Position pos = previousVisuallyDistinctCandidate(m_deepPosition);
79     
80     // return null visible position if there is no previous visible position
81     if (pos.atStart())
82         return VisiblePosition();
83         
84     VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM);
85     ASSERT(prev != *this);
86     
87 #ifndef NDEBUG
88     // we should always be able to make the affinity DOWNSTREAM, because going previous from an
89     // UPSTREAM position can never yield another UPSTREAM position (unless line wrap length is 0!).
90     if (prev.isNotNull() && m_affinity == UPSTREAM) {
91         VisiblePosition temp = prev;
92         temp.setAffinity(UPSTREAM);
93         ASSERT(inSameLine(temp, prev));
94     }
95 #endif
96
97     if (!stayInEditableContent)
98         return prev;
99     
100     return lastEditablePositionAtOrBefore(prev);
101 }
102
103 VisiblePosition VisiblePosition::lastEditablePositionAtOrBefore(const VisiblePosition &pos) const
104 {
105     if (pos.isNull())
106         return pos;
107     
108     Node* highestRoot = highestEditableRoot(deepEquivalent());
109     
110     if (!pos.deepEquivalent().node()->isDescendantOf(highestRoot))
111         return VisiblePosition();
112         
113     if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
114         return pos;
115
116     return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
117 }
118
119 VisiblePosition VisiblePosition::firstEditablePositionAtOrAfter(const VisiblePosition &pos) const
120 {
121     if (pos.isNull())
122         return pos;
123     
124     Node* highestRoot = highestEditableRoot(deepEquivalent());
125     
126     if (!pos.deepEquivalent().node()->isDescendantOf(highestRoot))
127         return VisiblePosition();
128         
129     if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
130         return pos;
131
132     return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
133 }
134
135 Position canonicalizeCandidate(const Position& candidate)
136 {
137     if (candidate.isNull())
138         return Position();
139     ASSERT(candidate.isCandidate());
140     Position upstream = candidate.upstream();
141     if (upstream.isCandidate())
142         return upstream;
143     return candidate;
144 }
145
146 Position VisiblePosition::canonicalPosition(const Position& position)
147 {
148     // FIXME (9535):  Canonicalizing to the leftmost candidate means that if we're at a line wrap, we will 
149     // ask renderers to paint downstream carets for other renderers.
150     // To fix this, we need to either a) add code to all paintCarets to pass the responsibility off to
151     // the appropriate renderer for VisiblePosition's like these, or b) canonicalize to the rightmost candidate
152     // unless the affinity is upstream.
153     Node* node = position.node();
154     if (!node)
155         return Position();
156
157     node->document()->updateLayoutIgnorePendingStylesheets();
158
159     Position candidate = position.upstream();
160     if (candidate.isCandidate())
161         return candidate;
162     candidate = position.downstream();
163     if (candidate.isCandidate())
164         return candidate;
165
166     // When neither upstream or downstream gets us to a candidate (upstream/downstream won't leave 
167     // blocks or enter new ones), we search forward and backward until we find one.
168     Position next = canonicalizeCandidate(nextCandidate(position));
169     Position prev = canonicalizeCandidate(previousCandidate(position));
170     Node* nextNode = next.node();
171     Node* prevNode = prev.node();
172
173     // The new position must be in the same editable element. Enforce that first.
174     // Unless the descent is from a non-editable html element to an editable body.
175     if (node->hasTagName(htmlTag) && !node->isContentEditable())
176         return next.isNotNull() ? next : prev;
177
178     Node* editingRoot = editableRootForPosition(position);
179         
180     // If the html element is editable, descending into its body will look like a descent 
181     // from non-editable to editable content since rootEditableElement() always stops at the body.
182     if (editingRoot && editingRoot->hasTagName(htmlTag) || position.node()->isDocumentNode())
183         return next.isNotNull() ? next : prev;
184         
185     bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot;
186     bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot;
187     if (prevIsInSameEditableElement && !nextIsInSameEditableElement)
188         return prev;
189         
190     if (nextIsInSameEditableElement && !prevIsInSameEditableElement)
191         return next;
192         
193     if (!nextIsInSameEditableElement && !prevIsInSameEditableElement)
194         return Position();
195
196     // The new position should be in the same block flow element. Favor that.
197     Node *originalBlock = node->enclosingBlockFlowElement();
198     bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock;
199     bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock;
200     if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
201         return prev;
202         
203     return next;
204 }
205
206 UChar VisiblePosition::characterAfter() const
207 {
208     // We canonicalize to the first of two equivalent candidates, but the second of the two candidates
209     // is the one that will be inside the text node containing the character after this visible position.
210     Position pos = m_deepPosition.downstream();
211     Node* node = pos.node();
212     if (!node || !node->isTextNode())
213         return 0;
214     Text* textNode = static_cast<Text*>(pos.node());
215     int offset = pos.offset();
216     if ((unsigned)offset >= textNode->length())
217         return 0;
218     return textNode->data()[offset];
219 }
220
221 IntRect VisiblePosition::caretRect() const
222 {
223     if (!m_deepPosition.node() || !m_deepPosition.node()->renderer())
224         return IntRect();
225
226     return m_deepPosition.node()->renderer()->caretRect(m_deepPosition.offset(), m_affinity);
227 }
228
229 void VisiblePosition::debugPosition(const char *msg) const
230 {
231     if (isNull())
232         fprintf(stderr, "Position [%s]: null\n", msg);
233     else
234         fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, m_deepPosition.node()->nodeName().deprecatedString().latin1(), m_deepPosition.node(), m_deepPosition.offset());
235 }
236
237 #ifndef NDEBUG
238
239 void VisiblePosition::formatForDebugger(char* buffer, unsigned length) const
240 {
241     m_deepPosition.formatForDebugger(buffer, length);
242 }
243
244 void VisiblePosition::showTreeForThis() const
245 {
246     m_deepPosition.showTreeForThis();
247 }
248
249 #endif
250
251 PassRefPtr<Range> makeRange(const VisiblePosition &start, const VisiblePosition &end)
252 {
253     Position s = rangeCompliantEquivalent(start);
254     Position e = rangeCompliantEquivalent(end);
255     return new Range(s.node()->document(), s.node(), s.offset(), e.node(), e.offset());
256 }
257
258 VisiblePosition startVisiblePosition(const Range *r, EAffinity affinity)
259 {
260     int exception = 0;
261     return VisiblePosition(r->startContainer(exception), r->startOffset(exception), affinity);
262 }
263
264 VisiblePosition endVisiblePosition(const Range *r, EAffinity affinity)
265 {
266     int exception = 0;
267     return VisiblePosition(r->endContainer(exception), r->endOffset(exception), affinity);
268 }
269
270 bool setStart(Range *r, const VisiblePosition &visiblePosition)
271 {
272     if (!r)
273         return false;
274     Position p = rangeCompliantEquivalent(visiblePosition);
275     int code = 0;
276     r->setStart(p.node(), p.offset(), code);
277     return code == 0;
278 }
279
280 bool setEnd(Range *r, const VisiblePosition &visiblePosition)
281 {
282     if (!r)
283         return false;
284     Position p = rangeCompliantEquivalent(visiblePosition);
285     int code = 0;
286     r->setEnd(p.node(), p.offset(), code);
287     return code == 0;
288 }
289
290 Node *enclosingBlockFlowElement(const VisiblePosition &visiblePosition)
291 {
292     if (visiblePosition.isNull())
293         return NULL;
294
295     return visiblePosition.deepEquivalent().node()->enclosingBlockFlowElement();
296 }
297
298 bool isFirstVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
299 {
300     if (visiblePosition.isNull())
301         return false;
302     
303     if (!visiblePosition.deepEquivalent().node()->isDescendantOf(node))
304         return false;
305         
306     VisiblePosition previous = visiblePosition.previous();
307     return previous.isNull() || !previous.deepEquivalent().node()->isDescendantOf(node);
308 }
309
310 bool isLastVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
311 {
312     if (visiblePosition.isNull())
313         return false;
314     
315     if (!visiblePosition.deepEquivalent().node()->isDescendantOf(node))
316         return false;
317                 
318     VisiblePosition next = visiblePosition.next();
319     return next.isNull() || !next.deepEquivalent().node()->isDescendantOf(node);
320 }
321
322 }  // namespace WebCore
323
324 #ifndef NDEBUG
325
326 void showTree(const WebCore::VisiblePosition* vpos)
327 {
328     if (vpos)
329         vpos->showTreeForThis();
330 }
331
332 void showTree(const WebCore::VisiblePosition& vpos)
333 {
334     vpos.showTreeForThis();
335 }
336
337 #endif