WebCore:
[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 dontChangeEditability) const
66 {
67     VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
68     
69     if (!dontChangeEditability)
70         return next;
71     
72     return firstPositionWithSameEditabilityAtOrAfter(next);
73 }
74
75 VisiblePosition VisiblePosition::previous(bool dontChangeEditability) 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 (!dontChangeEditability)
98         return prev;
99     
100     return lastPositionWithSameEditabilityAtOrBefore(prev);
101 }
102
103 VisiblePosition VisiblePosition::lastPositionWithSameEditabilityAtOrBefore(const VisiblePosition &pos) const
104 {
105     if (pos.isNull())
106         return pos;
107     
108     Node* highestRoot = highestEditableRoot(deepEquivalent());
109     
110     if (highestRoot && !pos.deepEquivalent().node()->isDescendantOf(highestRoot))
111         return VisiblePosition();
112         
113     // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
114     // to it is allowed.  Selection::adjustForEditableContent has this problem too.
115     if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
116         return pos;
117     
118     // FIXME: Move to the previous non-editable region.
119     if (!highestRoot)
120         return VisiblePosition();
121
122     return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
123 }
124
125 VisiblePosition VisiblePosition::firstPositionWithSameEditabilityAtOrAfter(const VisiblePosition &pos) const
126 {
127     if (pos.isNull())
128         return pos;
129     
130     Node* highestRoot = highestEditableRoot(deepEquivalent());
131     
132     if (highestRoot && !pos.deepEquivalent().node()->isDescendantOf(highestRoot))
133         return VisiblePosition();
134         
135     // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
136     // to it is allowed.  Selection::adjustForEditableContent has this problem too.
137     if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
138         return pos;
139         
140     // FIXME: Move to the previous non-editable region.
141     if (!highestRoot)
142         return VisiblePosition();
143
144     return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
145 }
146
147 Position canonicalizeCandidate(const Position& candidate)
148 {
149     if (candidate.isNull())
150         return Position();
151     ASSERT(candidate.isCandidate());
152     Position upstream = candidate.upstream();
153     if (upstream.isCandidate())
154         return upstream;
155     return candidate;
156 }
157
158 Position VisiblePosition::canonicalPosition(const Position& position)
159 {
160     // FIXME (9535):  Canonicalizing to the leftmost candidate means that if we're at a line wrap, we will 
161     // ask renderers to paint downstream carets for other renderers.
162     // To fix this, we need to either a) add code to all paintCarets to pass the responsibility off to
163     // the appropriate renderer for VisiblePosition's like these, or b) canonicalize to the rightmost candidate
164     // unless the affinity is upstream.
165     Node* node = position.node();
166     if (!node)
167         return Position();
168
169     node->document()->updateLayoutIgnorePendingStylesheets();
170
171     Position candidate = position.upstream();
172     if (candidate.isCandidate())
173         return candidate;
174     candidate = position.downstream();
175     if (candidate.isCandidate())
176         return candidate;
177
178     // When neither upstream or downstream gets us to a candidate (upstream/downstream won't leave 
179     // blocks or enter new ones), we search forward and backward until we find one.
180     Position next = canonicalizeCandidate(nextCandidate(position));
181     Position prev = canonicalizeCandidate(previousCandidate(position));
182     Node* nextNode = next.node();
183     Node* prevNode = prev.node();
184
185     // The new position must be in the same editable element. Enforce that first.
186     // Unless the descent is from a non-editable html element to an editable body.
187     if (node->hasTagName(htmlTag) && !node->isContentEditable())
188         return next.isNotNull() ? next : prev;
189
190     Node* editingRoot = editableRootForPosition(position);
191         
192     // If the html element is editable, descending into its body will look like a descent 
193     // from non-editable to editable content since rootEditableElement() always stops at the body.
194     if (editingRoot && editingRoot->hasTagName(htmlTag) || position.node()->isDocumentNode())
195         return next.isNotNull() ? next : prev;
196         
197     bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot;
198     bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot;
199     if (prevIsInSameEditableElement && !nextIsInSameEditableElement)
200         return prev;
201         
202     if (nextIsInSameEditableElement && !prevIsInSameEditableElement)
203         return next;
204         
205     if (!nextIsInSameEditableElement && !prevIsInSameEditableElement)
206         return Position();
207
208     // The new position should be in the same block flow element. Favor that.
209     Node *originalBlock = node->enclosingBlockFlowElement();
210     bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock;
211     bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock;
212     if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
213         return prev;
214         
215     return next;
216 }
217
218 UChar VisiblePosition::characterAfter() const
219 {
220     // We canonicalize to the first of two equivalent candidates, but the second of the two candidates
221     // is the one that will be inside the text node containing the character after this visible position.
222     Position pos = m_deepPosition.downstream();
223     Node* node = pos.node();
224     if (!node || !node->isTextNode())
225         return 0;
226     Text* textNode = static_cast<Text*>(pos.node());
227     int offset = pos.offset();
228     if ((unsigned)offset >= textNode->length())
229         return 0;
230     return textNode->data()[offset];
231 }
232
233 IntRect VisiblePosition::caretRect() const
234 {
235     if (!m_deepPosition.node() || !m_deepPosition.node()->renderer())
236         return IntRect();
237
238     return m_deepPosition.node()->renderer()->caretRect(m_deepPosition.offset(), m_affinity);
239 }
240
241 void VisiblePosition::debugPosition(const char *msg) const
242 {
243     if (isNull())
244         fprintf(stderr, "Position [%s]: null\n", msg);
245     else
246         fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, m_deepPosition.node()->nodeName().deprecatedString().latin1(), m_deepPosition.node(), m_deepPosition.offset());
247 }
248
249 #ifndef NDEBUG
250
251 void VisiblePosition::formatForDebugger(char* buffer, unsigned length) const
252 {
253     m_deepPosition.formatForDebugger(buffer, length);
254 }
255
256 void VisiblePosition::showTreeForThis() const
257 {
258     m_deepPosition.showTreeForThis();
259 }
260
261 #endif
262
263 PassRefPtr<Range> makeRange(const VisiblePosition &start, const VisiblePosition &end)
264 {
265     Position s = rangeCompliantEquivalent(start);
266     Position e = rangeCompliantEquivalent(end);
267     return new Range(s.node()->document(), s.node(), s.offset(), e.node(), e.offset());
268 }
269
270 VisiblePosition startVisiblePosition(const Range *r, EAffinity affinity)
271 {
272     int exception = 0;
273     return VisiblePosition(r->startContainer(exception), r->startOffset(exception), affinity);
274 }
275
276 VisiblePosition endVisiblePosition(const Range *r, EAffinity affinity)
277 {
278     int exception = 0;
279     return VisiblePosition(r->endContainer(exception), r->endOffset(exception), affinity);
280 }
281
282 bool setStart(Range *r, const VisiblePosition &visiblePosition)
283 {
284     if (!r)
285         return false;
286     Position p = rangeCompliantEquivalent(visiblePosition);
287     int code = 0;
288     r->setStart(p.node(), p.offset(), code);
289     return code == 0;
290 }
291
292 bool setEnd(Range *r, const VisiblePosition &visiblePosition)
293 {
294     if (!r)
295         return false;
296     Position p = rangeCompliantEquivalent(visiblePosition);
297     int code = 0;
298     r->setEnd(p.node(), p.offset(), code);
299     return code == 0;
300 }
301
302 Node *enclosingBlockFlowElement(const VisiblePosition &visiblePosition)
303 {
304     if (visiblePosition.isNull())
305         return NULL;
306
307     return visiblePosition.deepEquivalent().node()->enclosingBlockFlowElement();
308 }
309
310 bool isFirstVisiblePositionInNode(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 previous = visiblePosition.previous();
319     return previous.isNull() || !previous.deepEquivalent().node()->isDescendantOf(node);
320 }
321
322 bool isLastVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
323 {
324     if (visiblePosition.isNull())
325         return false;
326     
327     if (!visiblePosition.deepEquivalent().node()->isDescendantOf(node))
328         return false;
329                 
330     VisiblePosition next = visiblePosition.next();
331     return next.isNull() || !next.deepEquivalent().node()->isDescendantOf(node);
332 }
333
334 }  // namespace WebCore
335
336 #ifndef NDEBUG
337
338 void showTree(const WebCore::VisiblePosition* vpos)
339 {
340     if (vpos)
341         vpos->showTreeForThis();
342 }
343
344 void showTree(const WebCore::VisiblePosition& vpos)
345 {
346     vpos.showTreeForThis();
347 }
348
349 #endif