d5c8b92339b9fd5fce75b13d5f59e609a586475d
[WebKit-https.git] / WebCore / khtml / editing / visible_position.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 "visible_position.h"
27
28 #include "misc/htmltags.h"
29 #include "rendering/render_text.h"
30 #include "xml/dom2_rangeimpl.h"
31
32 #if APPLE_CHANGES
33 #include "KWQAssertions.h"
34 #include "KWQLogging.h"
35 #else
36 #define ASSERT(assertion) assert(assertion)
37 #define LOG(channel, formatAndArgs...) ((void)0)
38 #endif
39
40 using DOM::CharacterDataImpl;
41 using DOM::offsetInCharacters;
42 using DOM::Position;
43 using DOM::Range;
44 using DOM::RangeImpl;
45 using DOM::StayInBlock;
46
47 namespace khtml {
48
49 VisiblePosition::VisiblePosition(NodeImpl *node, long offset, EAffinity affinity)
50 {
51     Position pos = Position(node, offset);
52
53     // A first step toward eliminating the affinity parameter.
54     // For <br> 0, it's important not to move past the <br>.
55     if (node && node->id() == ID_BR && offset == 0)
56         affinity = UPSTREAM;
57
58     switch (affinity) {
59         case UPSTREAM:
60             initUpstream(pos);
61             break;
62         case DOWNSTREAM:
63             initDownstream(pos);
64             break;
65         default:
66             ASSERT_NOT_REACHED();
67             break;
68     }
69 }
70
71 VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
72 {
73     // A first step toward eliminating the affinity parameter.
74     // For <br> 0, it's important not to move past the <br>.
75     if (pos.node() && pos.node()->id() == ID_BR && pos.offset() == 0)
76         affinity = UPSTREAM;
77
78     switch (affinity) {
79         case UPSTREAM:
80             initUpstream(pos);
81             break;
82         case DOWNSTREAM:
83             initDownstream(pos);
84             break;
85         default:
86             ASSERT_NOT_REACHED();
87             break;
88     }
89 }
90
91 void VisiblePosition::initUpstream(const Position &pos)
92 {
93     Position deepPos = deepEquivalent(pos);
94
95     if (isCandidate(deepPos)) {
96         m_deepPosition = deepPos;
97         Position next = nextVisiblePosition(deepPos);
98         if (next.isNotNull()) {
99             Position previous = previousVisiblePosition(next);
100             if (previous.isNotNull())
101                 m_deepPosition = previous;
102         }
103     }
104     else {
105         Position previous = previousVisiblePosition(deepPos);
106         if (previous.isNotNull()) {
107             m_deepPosition = previous;
108         }
109         else {
110             Position next = nextVisiblePosition(deepPos);
111             if (next.isNotNull())
112                 m_deepPosition = next;
113         }
114     }
115 }
116
117 void VisiblePosition::initDownstream(const Position &pos)
118 {
119     Position deepPos = deepEquivalent(pos);
120
121     if (isCandidate(deepPos)) {
122         m_deepPosition = deepPos;
123         Position previous = previousVisiblePosition(deepPos);
124         if (previous.isNotNull()) {
125             Position next = nextVisiblePosition(previous);
126             if (next.isNotNull())
127                 m_deepPosition = next;
128         }
129     }
130     else {
131         Position next = nextVisiblePosition(deepPos);
132         if (next.isNotNull()) {
133             m_deepPosition = next;
134         }
135         else {
136             Position previous = previousVisiblePosition(deepPos);
137             if (previous.isNotNull())
138                 m_deepPosition = previous;
139         }
140     }
141 }
142
143 bool VisiblePosition::isLastInBlock() const
144 {
145     if (isNull())
146         return false;
147         
148     VisiblePosition n = next();
149     return n.isNull() || (n.deepEquivalent().node()->enclosingBlockFlowElement() != m_deepPosition.node()->enclosingBlockFlowElement());
150 }
151
152 VisiblePosition VisiblePosition::next() const
153 {
154     VisiblePosition result;
155     result.m_deepPosition = nextVisiblePosition(m_deepPosition);
156     return result;
157 }
158
159 VisiblePosition VisiblePosition::previous() const
160 {
161     VisiblePosition result;
162     result.m_deepPosition = previousVisiblePosition(m_deepPosition);
163     return result;
164 }
165
166 Position VisiblePosition::previousVisiblePosition(const Position &pos)
167 {
168     if (pos.isNull() || atStart(pos))
169         return Position();
170
171     Position test = deepEquivalent(pos);
172     bool acceptAnyVisiblePosition = !isCandidate(test) || pos.isFirstRenderedPositionOnLine();
173
174     Position current = test;
175     while (!atStart(current)) {
176         current = previousPosition(current);
177         if (isCandidate(current) && (acceptAnyVisiblePosition || current.rendersInDifferentPosition(test))) {
178             return current;
179         }
180     }
181     
182     return Position();
183 }
184
185 Position VisiblePosition::nextVisiblePosition(const Position &pos)
186 {
187     if (pos.isNull() || atEnd(pos))
188         return Position();
189
190     Position test = deepEquivalent(pos);
191     bool acceptAnyVisiblePosition = !isCandidate(test) || pos.isLastRenderedPositionOnLine();
192
193     Position current = test;
194     while (!atEnd(current)) {
195         current = nextPosition(current);
196         if (isCandidate(current) && (acceptAnyVisiblePosition || current.rendersInDifferentPosition(test))) {
197             return current;
198         }
199     }
200     
201     return Position();
202 }
203
204 Position VisiblePosition::previousPosition(const Position &pos)
205 {
206     if (pos.isNull())
207         return pos;
208     
209     Position result;
210
211     if (pos.offset() <= 0) {
212         NodeImpl *prevNode = pos.node()->traversePreviousNode();
213         if (prevNode)
214             result = Position(prevNode, prevNode->maxOffset());
215     }
216     else {
217         result = Position(pos.node(), pos.offset() - 1);
218     }
219     
220     return result;
221 }
222
223 Position VisiblePosition::nextPosition(const Position &pos)
224 {
225     if (pos.isNull())
226         return pos;
227     
228     Position result;
229
230     if (pos.offset() >= pos.node()->maxOffset()) {
231         NodeImpl *nextNode = pos.node()->traverseNextNode();
232         if (nextNode)
233             result = Position(nextNode, 0);
234     }
235     else {
236         result = Position(pos.node(), pos.offset() + 1);
237     }
238     
239     return result;
240 }
241
242 bool VisiblePosition::atStart(const Position &pos)
243 {
244     if (pos.isNull())
245         return true;
246
247     return pos.offset() <= 0 && pos.node()->previousLeafNode() == 0;
248 }
249
250 bool VisiblePosition::atEnd(const Position &pos)
251 {
252     if (pos.isNull())
253         return true;
254
255     return pos.offset() >= pos.node()->maxOffset() && pos.node()->nextLeafNode() == 0;
256 }
257
258 bool VisiblePosition::isCandidate(const Position &pos)
259 {
260     if (pos.isNull())
261         return false;
262         
263     RenderObject *renderer = pos.node()->renderer();
264     if (!renderer)
265         return false;
266     
267     if (renderer->style()->visibility() != VISIBLE)
268         return false;
269
270     if (renderer->isReplaced())
271         // return true for replaced elements
272         return pos.offset() == 0 || pos.offset() == 1;
273
274     if (renderer->isBR()) {
275         if (pos.offset() == 0) {
276             InlineBox* box = static_cast<RenderText*>(renderer)->firstTextBox();
277             if (box) {
278                 // return true for offset 0 into BR element on a line by itself
279                 RootInlineBox* root = box->root();
280                 if (root)
281                     return root->firstLeafChild() == box && root->lastLeafChild() == box;
282             }
283         }   
284         return false;
285     }
286     
287     if (renderer->isText()) {
288         RenderText *textRenderer = static_cast<RenderText *>(renderer);
289         for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
290             if (pos.offset() >= box->m_start && pos.offset() <= box->m_start + box->m_len) {
291                 // return true if in a text node
292                 return true;
293             }
294             else if (pos.offset() < box->m_start) {
295                 // The offset we're looking for is before this node
296                 // this means the offset must be in content that is
297                 // not rendered. Return false.
298                 return false;
299             }
300         }
301     }
302     
303     if (renderer->isBlockFlow() && !renderer->firstChild() && (renderer->height() || pos.node()->id() == ID_BODY))
304         // return true for offset 0 into rendered blocks that are empty of rendered kids, but have a height
305         return pos.offset() == 0;
306     
307     return false;
308 }
309
310 Position VisiblePosition::deepEquivalent(const Position &pos)
311 {
312     NodeImpl *node = pos.node();
313     long offset = pos.offset();
314
315     if (!node)
316         return Position();
317     
318     if (isAtomicNode(node)) {
319         // This is part of the strategy to wean the code off Positions with BRs and replaced elements
320         // as the nodes and offsets > 0.
321         if (offset > 0 && (node->id() == ID_BR || node->renderer() && node->renderer()->isReplaced())) {
322             NodeImpl *next = node->traverseNextNode();
323             if (next && node->enclosingBlockFlowElement() == next->enclosingBlockFlowElement())
324                 return deepEquivalent(Position(next, 0));
325         }
326         return pos;
327     }
328
329     if (offset >= (long)node->childNodeCount()) {
330         do {
331             NodeImpl *child = node->lastChild();
332             if (!child)
333                 break;
334             node = child;
335         } while (!isAtomicNode(node));
336         return Position(node, node->caretMaxOffset());
337     }
338     
339     node = node->childNode(offset);
340     ASSERT(node);
341     while (!isAtomicNode(node)) {
342         NodeImpl *child = node->firstChild();
343         if (!child)
344             break;
345         node = child;
346     }
347     return Position(node, 0);
348 }
349
350 Position VisiblePosition::upstreamDeepEquivalent() const
351 {
352     Position pos = m_deepPosition;
353     
354     if (pos.isNull() || atStart(pos))
355         return pos;
356
357     Position downstreamTest = pos.downstream(StayInBlock);
358
359     Position current = pos;
360     while (!atStart(current)) {
361         current = previousPosition(current);
362         if (isCandidate(current)) {
363             if (downstreamTest != current.downstream(StayInBlock))
364                 break;
365             pos = current;
366         }
367     }
368     
369     return pos;
370 }
371
372 Position VisiblePosition::rangeCompliantEquivalent(const Position &pos)
373 {
374     NodeImpl *node = pos.node();
375     if (!node)
376         return Position();
377     
378     // FIXME: This clamps out-of-range values.
379     // Instead we should probably assert, and not use such values.
380
381     long offset = pos.offset();
382     if (!offsetInCharacters(node->nodeType()) && isAtomicNode(node) && offset > 0)
383         return Position(node->parentNode(), node->nodeIndex() + 1);
384
385     return Position(node, kMax(0L, kMin(offset, maxOffset(node))));
386 }
387
388 long VisiblePosition::maxOffset(const NodeImpl *node)
389 {
390     return offsetInCharacters(node->nodeType()) ? (long)static_cast<const CharacterDataImpl *>(node)->length() : (long)node->childNodeCount();
391 }
392
393 bool VisiblePosition::isAtomicNode(const NodeImpl *node)
394 {
395     return node && (!node->hasChildNodes() || (node->id() == ID_OBJECT && node->renderer() && node->renderer()->isReplaced()));
396 }
397
398 void VisiblePosition::debugPosition(const char *msg) const
399 {
400     if (isNull())
401         fprintf(stderr, "Position [%s]: null\n", msg);
402     else
403         fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, getTagName(m_deepPosition.node()->id()).string().latin1(), m_deepPosition.node(), m_deepPosition.offset());
404 }
405
406 #ifndef NDEBUG
407 void VisiblePosition::formatForDebugger(char *buffer, unsigned length) const
408 {
409     m_deepPosition.formatForDebugger(buffer, length);
410 }
411 #endif
412
413 Range makeRange(const VisiblePosition &start, const VisiblePosition &end)
414 {
415     Position s = start.position();
416     Position e = end.position();
417     return Range(s.node(), s.offset(), e.node(), e.offset());
418 }
419
420 VisiblePosition startVisiblePosition(const Range &r)
421 {
422     return VisiblePosition(r.startContainer().handle(), r.startOffset());
423 }
424
425 VisiblePosition endVisiblePosition(const Range &r)
426 {
427     return VisiblePosition(r.endContainer().handle(), r.endOffset());
428 }
429
430 bool setStart(Range &r, const VisiblePosition &c)
431 {
432     RangeImpl *ri = r.handle();
433     if (!ri)
434         return false;
435     Position p = c.position();
436     int code = 0;
437     ri->setStart(p.node(), p.offset(), code);
438     return code == 0;
439 }
440
441 bool setEnd(Range &r, const VisiblePosition &c)
442 {
443     RangeImpl *ri = r.handle();
444     if (!ri)
445         return false;
446     Position p = c.position();
447     int code = 0;
448     ri->setEnd(p.node(), p.offset(), code);
449     return code == 0;
450 }
451
452 }  // namespace DOM