2011-05-23 Sheriff Bot <webkit.review.bot@gmail.com>
[WebKit-https.git] / Source / WebCore / dom / Position.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2009 Apple 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 "Position.h"
28
29 #include "CSSComputedStyleDeclaration.h"
30 #include "HTMLNames.h"
31 #include "InlineTextBox.h"
32 #include "Logging.h"
33 #include "PositionIterator.h"
34 #include "RenderBlock.h"
35 #include "RenderText.h"
36 #include "Text.h"
37 #include "TextIterator.h"
38 #include "VisiblePosition.h"
39 #include "htmlediting.h"
40 #include "visible_units.h"
41 #include <stdio.h>
42 #include <wtf/text/CString.h>
43 #include <wtf/unicode/CharacterNames.h>
44   
45 namespace WebCore {
46
47 using namespace HTMLNames;
48
49 static Node* nextRenderedEditable(Node* node)
50 {
51     while ((node = node->nextLeafNode())) {
52         if (!node->rendererIsEditable())
53             continue;
54         RenderObject* renderer = node->renderer();
55         if (!renderer)
56             continue;
57         if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
58             return node;
59     }
60     return 0;
61 }
62
63 static Node* previousRenderedEditable(Node* node)
64 {
65     while ((node = node->previousLeafNode())) {
66         if (!node->rendererIsEditable())
67             continue;
68         RenderObject* renderer = node->renderer();
69         if (!renderer)
70             continue;
71         if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
72             return node;
73     }
74     return 0;
75 }
76
77 Position::Position(PassRefPtr<Node> anchorNode, int offset)
78     : m_anchorNode(anchorNode)
79     , m_offset(offset)
80     , m_anchorType(anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset))
81     , m_isLegacyEditingPosition(true)
82 {
83 }
84
85 Position::Position(PassRefPtr<Node> anchorNode, AnchorType anchorType)
86     : m_anchorNode(anchorNode)
87     , m_offset(0)
88     , m_anchorType(anchorType)
89     , m_isLegacyEditingPosition(false)
90 {
91     ASSERT(anchorType != PositionIsOffsetInAnchor);
92 }
93
94 Position::Position(PassRefPtr<Node> anchorNode, int offset, AnchorType anchorType)
95     : m_anchorNode(anchorNode)
96     , m_offset(offset)
97     , m_anchorType(anchorType)
98     , m_isLegacyEditingPosition(false)
99 {
100     ASSERT(!m_anchorNode || !editingIgnoresContent(m_anchorNode.get()));
101     ASSERT(anchorType == PositionIsOffsetInAnchor);
102 }
103
104 void Position::moveToPosition(PassRefPtr<Node> node, int offset)
105 {
106     ASSERT(!editingIgnoresContent(node.get()));
107     ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
108     m_anchorNode = node;
109     m_offset = offset;
110     if (m_isLegacyEditingPosition)
111         m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
112 }
113 void Position::moveToOffset(int offset)
114 {
115     ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
116     m_offset = offset;
117     if (m_isLegacyEditingPosition)
118         m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
119 }
120
121 Node* Position::containerNode() const
122 {
123     if (!m_anchorNode)
124         return 0;
125
126     switch (anchorType()) {
127     case PositionIsOffsetInAnchor:
128         return m_anchorNode.get();
129     case PositionIsBeforeAnchor:
130     case PositionIsAfterAnchor:
131         return m_anchorNode->parentNode();
132     }
133     ASSERT_NOT_REACHED();
134     return 0;
135 }
136
137 int Position::computeOffsetInContainerNode() const
138 {
139     if (!m_anchorNode)
140         return 0;
141
142     switch (anchorType()) {
143     case PositionIsOffsetInAnchor:
144         return std::min(lastOffsetInNode(m_anchorNode.get()), m_offset);
145     case PositionIsBeforeAnchor:
146         return m_anchorNode->nodeIndex();
147     case PositionIsAfterAnchor:
148         return m_anchorNode->nodeIndex() + 1;
149     }
150     ASSERT_NOT_REACHED();
151     return 0;
152 }
153
154 int Position::offsetForPositionAfterAnchor() const
155 {
156     ASSERT(m_anchorType == PositionIsAfterAnchor);
157     ASSERT(!m_isLegacyEditingPosition);
158     return lastOffsetForEditing(m_anchorNode.get());
159 }
160
161 // Neighbor-anchored positions are invalid DOM positions, so they need to be
162 // fixed up before handing them off to the Range object.
163 Position Position::parentAnchoredEquivalent() const
164 {
165     if (!m_anchorNode)
166         return Position();
167     
168     // FIXME: This should only be necessary for legacy positions, but is also needed for positions before and after Tables
169     if (m_offset <= 0 && m_anchorType != PositionIsAfterAnchor) {
170         if (m_anchorNode->parentNode() && (editingIgnoresContent(m_anchorNode.get()) || isTableElement(m_anchorNode.get())))
171             return positionInParentBeforeNode(m_anchorNode.get());
172         return firstPositionInOrBeforeNode(m_anchorNode.get());
173     }
174     if (!m_anchorNode->offsetInCharacters() && (m_anchorType == PositionIsAfterAnchor || static_cast<unsigned>(m_offset) == m_anchorNode->childNodeCount())
175         && (editingIgnoresContent(m_anchorNode.get()) || isTableElement(m_anchorNode.get()))) {
176         return positionInParentAfterNode(m_anchorNode.get());
177     }
178
179     return Position(containerNode(), computeOffsetInContainerNode(), PositionIsOffsetInAnchor);
180 }
181
182 Node* Position::computeNodeBeforePosition() const
183 {
184     if (!m_anchorNode)
185         return 0;
186
187     switch (anchorType()) {
188     case PositionIsOffsetInAnchor:
189         return m_anchorNode->childNode(m_offset - 1); // -1 converts to childNode((unsigned)-1) and returns null.
190     case PositionIsBeforeAnchor:
191         return m_anchorNode->previousSibling();
192     case PositionIsAfterAnchor:
193         return m_anchorNode.get();
194     }
195     ASSERT_NOT_REACHED();
196     return 0;
197 }
198
199 Node* Position::computeNodeAfterPosition() const
200 {
201     if (!m_anchorNode)
202         return 0;
203
204     switch (anchorType()) {
205     case PositionIsOffsetInAnchor:
206         return m_anchorNode->childNode(m_offset);
207     case PositionIsBeforeAnchor:
208         return m_anchorNode.get();
209     case PositionIsAfterAnchor:
210         return m_anchorNode->nextSibling();
211     }
212     ASSERT_NOT_REACHED();
213     return 0;
214 }
215
216 Position::AnchorType Position::anchorTypeForLegacyEditingPosition(Node* anchorNode, int offset)
217 {
218     if (anchorNode && editingIgnoresContent(anchorNode)) {
219         if (offset == 0)
220             return Position::PositionIsBeforeAnchor;
221         return Position::PositionIsAfterAnchor;
222     }
223     return Position::PositionIsOffsetInAnchor;
224 }
225
226 // FIXME: This method is confusing (does it return anchorNode() or containerNode()?) and should be renamed or removed
227 Element* Position::element() const
228 {
229     Node* n = anchorNode();
230     while (n && !n->isElementNode())
231         n = n->parentNode();
232     return static_cast<Element*>(n);
233 }
234
235 PassRefPtr<CSSComputedStyleDeclaration> Position::computedStyle() const
236 {
237     Element* elem = element();
238     if (!elem)
239         return 0;
240     return WebCore::computedStyle(elem);
241 }
242
243 Position Position::previous(PositionMoveType moveType) const
244 {
245     Node* n = deprecatedNode();
246     if (!n)
247         return *this;
248
249     int o = deprecatedEditingOffset();
250     // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
251     ASSERT(o >= 0);
252
253     if (o > 0) {
254         Node* child = n->childNode(o - 1);
255         if (child)
256             return lastPositionInOrAfterNode(child);
257
258         // There are two reasons child might be 0:
259         //   1) The node is node like a text node that is not an element, and therefore has no children.
260         //      Going backward one character at a time is correct.
261         //   2) The old offset was a bogus offset like (<br>, 1), and there is no child.
262         //      Going from 1 to 0 is correct.
263         switch (moveType) {
264         case CodePoint:
265             return Position(n, o - 1);
266         case Character:
267             return Position(n, uncheckedPreviousOffset(n, o));
268         case BackwardDeletion:
269             return Position(n, uncheckedPreviousOffsetForBackwardDeletion(n, o));
270         }
271     }
272
273     ContainerNode* parent = n->parentNode();
274     if (!parent)
275         return *this;
276
277     return Position(parent, n->nodeIndex());
278 }
279
280 Position Position::next(PositionMoveType moveType) const
281 {
282     ASSERT(moveType != BackwardDeletion);
283
284     Node* n = deprecatedNode();
285     if (!n)
286         return *this;
287
288     int o = deprecatedEditingOffset();
289     // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
290     ASSERT(o >= 0);
291
292     Node* child = n->childNode(o);
293     if (child || (!n->hasChildNodes() && o < lastOffsetForEditing(n))) {
294         if (child)
295             return firstPositionInOrBeforeNode(child);
296
297         // There are two reasons child might be 0:
298         //   1) The node is node like a text node that is not an element, and therefore has no children.
299         //      Going forward one character at a time is correct.
300         //   2) The new offset is a bogus offset like (<br>, 1), and there is no child.
301         //      Going from 0 to 1 is correct.
302         return Position(n, (moveType == Character) ? uncheckedNextOffset(n, o) : o + 1);
303     }
304
305     ContainerNode* parent = n->parentNode();
306     if (!parent)
307         return *this;
308
309     return Position(parent, n->nodeIndex() + 1);
310 }
311
312 int Position::uncheckedPreviousOffset(const Node* n, int current)
313 {
314     return n->renderer() ? n->renderer()->previousOffset(current) : current - 1;
315 }
316
317 int Position::uncheckedPreviousOffsetForBackwardDeletion(const Node* n, int current)
318 {
319     return n->renderer() ? n->renderer()->previousOffsetForBackwardDeletion(current) : current - 1;
320 }
321
322 int Position::uncheckedNextOffset(const Node* n, int current)
323 {
324     return n->renderer() ? n->renderer()->nextOffset(current) : current + 1;
325 }
326
327 bool Position::atFirstEditingPositionForNode() const
328 {
329     if (isNull())
330         return true;
331     return m_anchorType == PositionIsBeforeAnchor || m_offset <= 0;
332 }
333
334 bool Position::atLastEditingPositionForNode() const
335 {
336     if (isNull())
337         return true;
338     return m_anchorType == PositionIsAfterAnchor || m_offset >= lastOffsetForEditing(deprecatedNode());
339 }
340
341 // A position is considered at editing boundary if one of the following is true:
342 // 1. It is the first position in the node and the next visually equivalent position
343 //    is non editable.
344 // 2. It is the last position in the node and the previous visually equivalent position
345 //    is non editable.
346 // 3. It is an editable position and both the next and previous visually equivalent
347 //    positions are both non editable.
348 bool Position::atEditingBoundary() const
349 {
350     Position nextPosition = downstream(CanCrossEditingBoundary);
351     if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosition.deprecatedNode()->rendererIsEditable())
352         return true;
353         
354     Position prevPosition = upstream(CanCrossEditingBoundary);
355     if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->rendererIsEditable())
356         return true;
357         
358     return nextPosition.isNotNull() && !nextPosition.deprecatedNode()->rendererIsEditable()
359         && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->rendererIsEditable();
360 }
361
362 Node* Position::parentEditingBoundary() const
363 {
364     if (!m_anchorNode || !m_anchorNode->document())
365         return 0;
366
367     Node* documentElement = m_anchorNode->document()->documentElement();
368     if (!documentElement)
369         return 0;
370
371     Node* boundary = m_anchorNode.get();
372     while (boundary != documentElement && boundary->parentNode() && m_anchorNode->rendererIsEditable() == boundary->parentNode()->rendererIsEditable())
373         boundary = boundary->parentNode();
374     
375     return boundary;
376 }
377
378
379 bool Position::atStartOfTree() const
380 {
381     if (isNull())
382         return true;
383     return !deprecatedNode()->parentNode() && m_offset <= 0;
384 }
385
386 bool Position::atEndOfTree() const
387 {
388     if (isNull())
389         return true;
390     return !deprecatedNode()->parentNode() && m_offset >= lastOffsetForEditing(deprecatedNode());
391 }
392
393 int Position::renderedOffset() const
394 {
395     if (!deprecatedNode()->isTextNode())
396         return m_offset;
397    
398     if (!deprecatedNode()->renderer())
399         return m_offset;
400                     
401     int result = 0;
402     RenderText* textRenderer = toRenderText(deprecatedNode()->renderer());
403     for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
404         int start = box->start();
405         int end = box->start() + box->len();
406         if (m_offset < start)
407             return result;
408         if (m_offset <= end) {
409             result += m_offset - start;
410             return result;
411         }
412         result += box->len();
413     }
414     return result;
415 }
416
417 // return first preceding DOM position rendered at a different location, or "this"
418 Position Position::previousCharacterPosition(EAffinity affinity) const
419 {
420     if (isNull())
421         return Position();
422
423     Node* fromRootEditableElement = deprecatedNode()->rootEditableElement();
424
425     bool atStartOfLine = isStartOfLine(VisiblePosition(*this, affinity));
426     bool rendered = isCandidate();
427     
428     Position currentPos = *this;
429     while (!currentPos.atStartOfTree()) {
430         currentPos = currentPos.previous();
431
432         if (currentPos.deprecatedNode()->rootEditableElement() != fromRootEditableElement)
433             return *this;
434
435         if (atStartOfLine || !rendered) {
436             if (currentPos.isCandidate())
437                 return currentPos;
438         } else if (rendersInDifferentPosition(currentPos))
439             return currentPos;
440     }
441     
442     return *this;
443 }
444
445 // return first following position rendered at a different location, or "this"
446 Position Position::nextCharacterPosition(EAffinity affinity) const
447 {
448     if (isNull())
449         return Position();
450
451     Node* fromRootEditableElement = deprecatedNode()->rootEditableElement();
452
453     bool atEndOfLine = isEndOfLine(VisiblePosition(*this, affinity));
454     bool rendered = isCandidate();
455     
456     Position currentPos = *this;
457     while (!currentPos.atEndOfTree()) {
458         currentPos = currentPos.next();
459
460         if (currentPos.deprecatedNode()->rootEditableElement() != fromRootEditableElement)
461             return *this;
462
463         if (atEndOfLine || !rendered) {
464             if (currentPos.isCandidate())
465                 return currentPos;
466         } else if (rendersInDifferentPosition(currentPos))
467             return currentPos;
468     }
469     
470     return *this;
471 }
472
473 // Whether or not [node, 0] and [node, lastOffsetForEditing(node)] are their own VisiblePositions.
474 // If true, adjacent candidates are visually distinct.
475 // FIXME: Disregard nodes with renderers that have no height, as we do in isCandidate.
476 // FIXME: Share code with isCandidate, if possible.
477 static bool endsOfNodeAreVisuallyDistinctPositions(Node* node)
478 {
479     if (!node || !node->renderer())
480         return false;
481         
482     if (!node->renderer()->isInline())
483         return true;
484         
485     // Don't include inline tables.
486     if (node->hasTagName(tableTag))
487         return false;
488     
489     // There is a VisiblePosition inside an empty inline-block container.
490     return node->renderer()->isReplaced() && canHaveChildrenForEditing(node) && toRenderBox(node->renderer())->height() != 0 && !node->firstChild();
491 }
492
493 static Node* enclosingVisualBoundary(Node* node)
494 {
495     while (node && !endsOfNodeAreVisuallyDistinctPositions(node))
496         node = node->parentNode();
497         
498     return node;
499 }
500
501 // upstream() and downstream() want to return positions that are either in a
502 // text node or at just before a non-text node.  This method checks for that.
503 static bool isStreamer(const PositionIterator& pos)
504 {
505     if (!pos.node())
506         return true;
507         
508     if (isAtomicNode(pos.node()))
509         return true;
510         
511     return pos.atStartOfNode();
512 }
513
514 // This function and downstream() are used for moving back and forth between visually equivalent candidates.
515 // For example, for the text node "foo     bar" where whitespace is collapsible, there are two candidates 
516 // that map to the VisiblePosition between 'b' and the space.  This function will return the left candidate 
517 // and downstream() will return the right one.
518 // Also, upstream() will return [boundary, 0] for any of the positions from [boundary, 0] to the first candidate
519 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true.
520 Position Position::upstream(EditingBoundaryCrossingRule rule) const
521 {
522     Node* startNode = deprecatedNode();
523     if (!startNode)
524         return Position();
525     
526     // iterate backward from there, looking for a qualified position
527     Node* boundary = enclosingVisualBoundary(startNode);
528     // FIXME: PositionIterator should respect Before and After positions.
529     PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? Position(m_anchorNode, caretMaxOffset(m_anchorNode.get())) : *this;
530     PositionIterator currentPos = lastVisible;
531     bool startEditable = startNode->rendererIsEditable();
532     Node* lastNode = startNode;
533     bool boundaryCrossed = false;
534     for (; !currentPos.atStart(); currentPos.decrement()) {
535         Node* currentNode = currentPos.node();
536         
537         // Don't check for an editability change if we haven't moved to a different node,
538         // to avoid the expense of computing rendererIsEditable().
539         if (currentNode != lastNode) {
540             // Don't change editability.
541             bool currentEditable = currentNode->rendererIsEditable();
542             if (startEditable != currentEditable) {
543                 if (rule == CannotCrossEditingBoundary)
544                     break;
545                 boundaryCrossed = true;
546             }
547             lastNode = currentNode;
548         }
549
550         // If we've moved to a position that is visually distinct, return the last saved position. There 
551         // is code below that terminates early if we're *about* to move to a visually distinct position.
552         if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
553             return lastVisible;
554
555         // skip position in unrendered or invisible node
556         RenderObject* renderer = currentNode->renderer();
557         if (!renderer || renderer->style()->visibility() != VISIBLE)
558             continue;
559                  
560         if (rule == CanCrossEditingBoundary && boundaryCrossed) {
561             lastVisible = currentPos;
562             break;
563         }
564         
565         // track last visible streamer position
566         if (isStreamer(currentPos))
567             lastVisible = currentPos;
568         
569         // Don't move past a position that is visually distinct.  We could rely on code above to terminate and 
570         // return lastVisible on the next iteration, but we terminate early to avoid doing a nodeIndex() call.
571         if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.atStartOfNode())
572             return lastVisible;
573
574         // Return position after tables and nodes which have content that can be ignored.
575         if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
576             if (currentPos.atEndOfNode())
577                 return positionAfterNode(currentNode);
578             continue;
579         }
580
581         // return current position if it is in rendered text
582         if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
583             if (currentNode != startNode) {
584                 // This assertion fires in layout tests in the case-transform.html test because
585                 // of a mix-up between offsets in the text in the DOM tree with text in the
586                 // render tree which can have a different length due to case transformation.
587                 // Until we resolve that, disable this so we can run the layout tests!
588                 //ASSERT(currentOffset >= renderer->caretMaxOffset());
589                 return Position(currentNode, renderer->caretMaxOffset());
590             }
591
592             unsigned textOffset = currentPos.offsetInLeafNode();
593             RenderText* textRenderer = toRenderText(renderer);
594             InlineTextBox* lastTextBox = textRenderer->lastTextBox();
595             for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
596                 if (textOffset <= box->start() + box->len()) {
597                     if (textOffset > box->start())
598                         return currentPos;
599                     continue;
600                 }
601
602                 if (box == lastTextBox || textOffset != box->start() + box->len() + 1)
603                     continue;
604
605                 // The text continues on the next line only if the last text box is not on this line and
606                 // none of the boxes on this line have a larger start offset.
607
608                 bool continuesOnNextLine = true;
609                 InlineBox* otherBox = box;
610                 while (continuesOnNextLine) {
611                     otherBox = otherBox->nextLeafChild();
612                     if (!otherBox)
613                         break;
614                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
615                         continuesOnNextLine = false;
616                 }
617
618                 otherBox = box;
619                 while (continuesOnNextLine) {
620                     otherBox = otherBox->prevLeafChild();
621                     if (!otherBox)
622                         break;
623                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
624                         continuesOnNextLine = false;
625                 }
626
627                 if (continuesOnNextLine)
628                     return currentPos;
629             }
630         }
631     }
632
633     return lastVisible;
634 }
635
636 // This function and upstream() are used for moving back and forth between visually equivalent candidates.
637 // For example, for the text node "foo     bar" where whitespace is collapsible, there are two candidates 
638 // that map to the VisiblePosition between 'b' and the space.  This function will return the right candidate 
639 // and upstream() will return the left one.
640 // Also, downstream() will return the last position in the last atomic node in boundary for all of the positions
641 // in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPositions(boundary).
642 Position Position::downstream(EditingBoundaryCrossingRule rule) const
643 {
644     Node* startNode = deprecatedNode();
645     if (!startNode)
646         return Position();
647
648     // iterate forward from there, looking for a qualified position
649     Node* boundary = enclosingVisualBoundary(startNode);
650     // FIXME: PositionIterator should respect Before and After positions.
651     PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? Position(m_anchorNode, caretMaxOffset(m_anchorNode.get())) : *this;
652     PositionIterator currentPos = lastVisible;
653     bool startEditable = startNode->rendererIsEditable();
654     Node* lastNode = startNode;
655     bool boundaryCrossed = false;
656     for (; !currentPos.atEnd(); currentPos.increment()) {   
657         Node* currentNode = currentPos.node();
658         
659         // Don't check for an editability change if we haven't moved to a different node,
660         // to avoid the expense of computing rendererIsEditable().
661         if (currentNode != lastNode) {
662             // Don't change editability.
663             bool currentEditable = currentNode->rendererIsEditable();
664             if (startEditable != currentEditable) {
665                 if (rule == CannotCrossEditingBoundary)
666                     break;
667                 boundaryCrossed = true;
668             }
669                 
670             lastNode = currentNode;
671         }
672
673         // stop before going above the body, up into the head
674         // return the last visible streamer position
675         if (currentNode->hasTagName(bodyTag) && currentPos.atEndOfNode())
676             break;
677             
678         // Do not move to a visually distinct position.
679         if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
680             return lastVisible;
681         // Do not move past a visually disinct position.
682         // Note: The first position after the last in a node whose ends are visually distinct
683         // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1].
684         if (boundary && boundary->parentNode() == currentNode)
685             return lastVisible;
686
687         // skip position in unrendered or invisible node
688         RenderObject* renderer = currentNode->renderer();
689         if (!renderer || renderer->style()->visibility() != VISIBLE)
690             continue;
691             
692         if (rule == CanCrossEditingBoundary && boundaryCrossed) {
693             lastVisible = currentPos;
694             break;
695         }
696         
697         // track last visible streamer position
698         if (isStreamer(currentPos))
699             lastVisible = currentPos;
700
701         // Return position before tables and nodes which have content that can be ignored.
702         if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
703             if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset())
704                 return Position(currentNode, renderer->caretMinOffset());
705             continue;
706         }
707
708         // return current position if it is in rendered text
709         if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
710             if (currentNode != startNode) {
711                 ASSERT(currentPos.atStartOfNode());
712                 return Position(currentNode, renderer->caretMinOffset());
713             }
714
715             unsigned textOffset = currentPos.offsetInLeafNode();
716             RenderText* textRenderer = toRenderText(renderer);
717             InlineTextBox* lastTextBox = textRenderer->lastTextBox();
718             for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
719                 if (textOffset <= box->end()) {
720                     if (textOffset >= box->start())
721                         return currentPos;
722                     continue;
723                 }
724
725                 if (box == lastTextBox || textOffset != box->start() + box->len())
726                     continue;
727
728                 // The text continues on the next line only if the last text box is not on this line and
729                 // none of the boxes on this line have a larger start offset.
730
731                 bool continuesOnNextLine = true;
732                 InlineBox* otherBox = box;
733                 while (continuesOnNextLine) {
734                     otherBox = otherBox->nextLeafChild();
735                     if (!otherBox)
736                         break;
737                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
738                         continuesOnNextLine = false;
739                 }
740
741                 otherBox = box;
742                 while (continuesOnNextLine) {
743                     otherBox = otherBox->prevLeafChild();
744                     if (!otherBox)
745                         break;
746                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
747                         continuesOnNextLine = false;
748                 }
749
750                 if (continuesOnNextLine)
751                     return currentPos;
752             }
753         }
754     }
755     
756     return lastVisible;
757 }
758
759 bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* renderer)
760 {
761     RenderObject* stop = renderer->nextInPreOrderAfterChildren();
762     for (RenderObject *o = renderer->firstChild(); o && o != stop; o = o->nextInPreOrder())
763         if (o->node()) {
764             if ((o->isText() && toRenderText(o)->linesBoundingBox().height()) ||
765                 (o->isBox() && toRenderBox(o)->borderBoundingBox().height()))
766                 return true;
767         }
768     return false;
769 }
770
771 bool Position::nodeIsUserSelectNone(Node* node)
772 {
773     return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_NONE;
774 }
775
776 bool Position::isCandidate() const
777 {
778     if (isNull())
779         return false;
780         
781     RenderObject* renderer = deprecatedNode()->renderer();
782     if (!renderer)
783         return false;
784     
785     if (renderer->style()->visibility() != VISIBLE)
786         return false;
787
788     if (renderer->isBR())
789         // FIXME: The condition should be m_anchorType == PositionIsBeforeAnchor, but for now we still need to support legacy positions.
790         return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
791
792     if (renderer->isText())
793         return !nodeIsUserSelectNone(deprecatedNode()) && inRenderedText();
794
795     if (isTableElement(deprecatedNode()) || editingIgnoresContent(deprecatedNode()))
796         return (atFirstEditingPositionForNode() || atLastEditingPositionForNode()) && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
797
798     if (m_anchorNode->hasTagName(htmlTag))
799         return false;
800         
801     if (renderer->isBlockFlow()) {
802         if (toRenderBlock(renderer)->height() || m_anchorNode->hasTagName(bodyTag)) {
803             if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
804                 return atFirstEditingPositionForNode() && !Position::nodeIsUserSelectNone(deprecatedNode());
805             return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
806         }
807     } else
808         return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
809
810     return false;
811 }
812
813 bool Position::inRenderedText() const
814 {
815     if (isNull() || !deprecatedNode()->isTextNode())
816         return false;
817         
818     RenderObject* renderer = deprecatedNode()->renderer();
819     if (!renderer)
820         return false;
821     
822     RenderText *textRenderer = toRenderText(renderer);
823     for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
824         if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
825             // The offset we're looking for is before this node
826             // this means the offset must be in content that is
827             // not rendered. Return false.
828             return false;
829         }
830         if (box->containsCaretOffset(m_offset))
831             // Return false for offsets inside composed characters.
832             return m_offset == 0 || m_offset == textRenderer->nextOffset(textRenderer->previousOffset(m_offset));
833     }
834     
835     return false;
836 }
837
838 static unsigned caretMaxRenderedOffset(const Node* n)
839 {
840     RenderObject* r = n->renderer();
841     if (r)
842         return r->caretMaxRenderedOffset();
843     
844     if (n->isCharacterDataNode())
845         return static_cast<const CharacterData*>(n)->length();
846     return 1;
847 }
848
849 bool Position::isRenderedCharacter() const
850 {
851     if (isNull() || !deprecatedNode()->isTextNode())
852         return false;
853         
854     RenderObject* renderer = deprecatedNode()->renderer();
855     if (!renderer)
856         return false;
857     
858     RenderText* textRenderer = toRenderText(renderer);
859     for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
860         if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
861             // The offset we're looking for is before this node
862             // this means the offset must be in content that is
863             // not rendered. Return false.
864             return false;
865         }
866         if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast<int>(box->start() + box->len()))
867             return true;
868     }
869     
870     return false;
871 }
872
873 bool Position::rendersInDifferentPosition(const Position &pos) const
874 {
875     if (isNull() || pos.isNull())
876         return false;
877
878     RenderObject* renderer = deprecatedNode()->renderer();
879     if (!renderer)
880         return false;
881     
882     RenderObject* posRenderer = pos.deprecatedNode()->renderer();
883     if (!posRenderer)
884         return false;
885
886     if (renderer->style()->visibility() != VISIBLE ||
887         posRenderer->style()->visibility() != VISIBLE)
888         return false;
889     
890     if (deprecatedNode() == pos.deprecatedNode()) {
891         if (deprecatedNode()->hasTagName(brTag))
892             return false;
893
894         if (m_offset == pos.deprecatedEditingOffset())
895             return false;
896             
897         if (!deprecatedNode()->isTextNode() && !pos.deprecatedNode()->isTextNode()) {
898             if (m_offset != pos.deprecatedEditingOffset())
899                 return true;
900         }
901     }
902     
903     if (deprecatedNode()->hasTagName(brTag) && pos.isCandidate())
904         return true;
905                 
906     if (pos.deprecatedNode()->hasTagName(brTag) && isCandidate())
907         return true;
908                 
909     if (deprecatedNode()->enclosingBlockFlowElement() != pos.deprecatedNode()->enclosingBlockFlowElement())
910         return true;
911
912     if (deprecatedNode()->isTextNode() && !inRenderedText())
913         return false;
914
915     if (pos.deprecatedNode()->isTextNode() && !pos.inRenderedText())
916         return false;
917
918     int thisRenderedOffset = renderedOffset();
919     int posRenderedOffset = pos.renderedOffset();
920
921     if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
922         return false;
923
924     int ignoredCaretOffset;
925     InlineBox* b1;
926     getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset);
927     InlineBox* b2;
928     pos.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset);
929
930     LOG(Editing, "renderer:               %p [%p]\n", renderer, b1);
931     LOG(Editing, "thisRenderedOffset:         %d\n", thisRenderedOffset);
932     LOG(Editing, "posRenderer:            %p [%p]\n", posRenderer, b2);
933     LOG(Editing, "posRenderedOffset:      %d\n", posRenderedOffset);
934     LOG(Editing, "node min/max:           %d:%d\n", caretMinOffset(deprecatedNode()), caretMaxRenderedOffset(deprecatedNode()));
935     LOG(Editing, "pos node min/max:       %d:%d\n", caretMinOffset(pos.deprecatedNode()), caretMaxRenderedOffset(pos.deprecatedNode()));
936     LOG(Editing, "----------------------------------------------------------------------\n");
937
938     if (!b1 || !b2) {
939         return false;
940     }
941
942     if (b1->root() != b2->root()) {
943         return true;
944     }
945
946     if (nextRenderedEditable(deprecatedNode()) == pos.deprecatedNode()
947         && thisRenderedOffset == (int)caretMaxRenderedOffset(deprecatedNode()) && !posRenderedOffset) {
948         return false;
949     }
950     
951     if (previousRenderedEditable(deprecatedNode()) == pos.deprecatedNode()
952         && !thisRenderedOffset && posRenderedOffset == (int)caretMaxRenderedOffset(pos.deprecatedNode())) {
953         return false;
954     }
955
956     return true;
957 }
958
959 // This assumes that it starts in editable content.
960 Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNonCollapsibleWhitespace) const
961 {
962     ASSERT(isEditablePosition(*this));
963     if (isNull())
964         return Position();
965     
966     if (upstream().deprecatedNode()->hasTagName(brTag))
967         return Position();
968
969     Position prev = previousCharacterPosition(affinity);
970     if (prev != *this && prev.deprecatedNode()->inSameContainingBlockFlowElement(deprecatedNode()) && prev.deprecatedNode()->isTextNode()) {
971         String string = static_cast<Text *>(prev.deprecatedNode())->data();
972         UChar c = string[prev.deprecatedEditingOffset()];
973         if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
974             if (isEditablePosition(prev))
975                 return prev;
976     }
977
978     return Position();
979 }
980
981 // This assumes that it starts in editable content.
982 Position Position::trailingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace) const
983 {
984     ASSERT(isEditablePosition(*this));
985     if (isNull())
986         return Position();
987     
988     VisiblePosition v(*this);
989     UChar c = v.characterAfter();
990     // The space must not be in another paragraph and it must be editable.
991     if (!isEndOfParagraph(v) && v.next(CannotCrossEditingBoundary).isNotNull())
992         if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
993             return *this;
994     
995     return Position();
996 }
997
998 void Position::getInlineBoxAndOffset(EAffinity affinity, InlineBox*& inlineBox, int& caretOffset) const
999 {
1000     getInlineBoxAndOffset(affinity, primaryDirection(), inlineBox, caretOffset);
1001 }
1002
1003 static bool isNonTextLeafChild(RenderObject* object)
1004 {
1005     if (object->firstChild())
1006         return false;
1007     if (object->isText())
1008         return false;
1009     return true;
1010 }
1011
1012 static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer)
1013 {
1014     RenderBlock* container = renderer->containingBlock();
1015     RenderObject* next = renderer;
1016     while ((next = next->nextInPreOrder(container))) {
1017         if (next->isRenderBlock())
1018             return 0;
1019         if (next->isBR())
1020             return 0;
1021         if (isNonTextLeafChild(next))
1022             return 0;
1023         if (next->isText()) {
1024             InlineTextBox* match = 0;
1025             int minOffset = INT_MAX;
1026             for (InlineTextBox* box = toRenderText(next)->firstTextBox(); box; box = box->nextTextBox()) {
1027                 int caretMinOffset = box->caretMinOffset();
1028                 if (caretMinOffset < minOffset) {
1029                     match = box;
1030                     minOffset = caretMinOffset;
1031                 }
1032             }
1033             if (match)
1034                 return match;
1035         }
1036     }
1037     return 0;
1038 }
1039
1040 static Position downstreamIgnoringEditingBoundaries(Position position)
1041 {
1042     Position lastPosition;
1043     while (position != lastPosition) {
1044         lastPosition = position;
1045         position = position.downstream(CanCrossEditingBoundary);
1046     }
1047     return position;
1048 }
1049
1050 static Position upstreamIgnoringEditingBoundaries(Position position)
1051 {
1052     Position lastPosition;
1053     while (position != lastPosition) {
1054         lastPosition = position;
1055         position = position.upstream(CanCrossEditingBoundary);
1056     }
1057     return position;
1058 }
1059
1060 void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
1061 {
1062     caretOffset = deprecatedEditingOffset();
1063     RenderObject* renderer = deprecatedNode()->renderer();
1064
1065     if (!renderer->isText()) {
1066         inlineBox = 0;
1067         if (canHaveChildrenForEditing(deprecatedNode()) && renderer->isBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) {
1068             // Try a visually equivalent position with possibly opposite editability. This helps in case |this| is in
1069             // an editable block but surrounded by non-editable positions. It acts to negate the logic at the beginning
1070             // of RenderObject::createVisiblePosition().
1071             Position equivalent = downstreamIgnoringEditingBoundaries(*this);
1072             if (equivalent == *this) {
1073                 equivalent = upstreamIgnoringEditingBoundaries(*this);
1074                 if (equivalent == *this || downstreamIgnoringEditingBoundaries(equivalent) == *this)
1075                     return;
1076             }
1077
1078             equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineBox, caretOffset);
1079             return;
1080         }
1081         if (renderer->isBox()) {
1082             inlineBox = toRenderBox(renderer)->inlineBoxWrapper();
1083             if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset()))
1084                 return;
1085         }
1086     } else {
1087         RenderText* textRenderer = toRenderText(renderer);
1088
1089         InlineTextBox* box;
1090         InlineTextBox* candidate = 0;
1091
1092         for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
1093             int caretMinOffset = box->caretMinOffset();
1094             int caretMaxOffset = box->caretMaxOffset();
1095
1096             if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak()))
1097                 continue;
1098
1099             if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) {
1100                 inlineBox = box;
1101                 return;
1102             }
1103
1104             if (((caretOffset == caretMaxOffset) ^ (affinity == DOWNSTREAM))
1105                 || ((caretOffset == caretMinOffset) ^ (affinity == UPSTREAM)))
1106                 break;
1107
1108             candidate = box;
1109         }
1110         if (candidate && candidate == textRenderer->lastTextBox() && affinity == DOWNSTREAM) {
1111             box = searchAheadForBetterMatch(textRenderer);
1112             if (box)
1113                 caretOffset = box->caretMinOffset();
1114         }
1115         inlineBox = box ? box : candidate;
1116     }
1117
1118     if (!inlineBox)
1119         return;
1120
1121     unsigned char level = inlineBox->bidiLevel();
1122
1123     if (inlineBox->direction() == primaryDirection) {
1124         if (caretOffset == inlineBox->caretRightmostOffset()) {
1125             InlineBox* nextBox = inlineBox->nextLeafChild();
1126             if (!nextBox || nextBox->bidiLevel() >= level)
1127                 return;
1128
1129             level = nextBox->bidiLevel();
1130             InlineBox* prevBox = inlineBox;
1131             do {
1132                 prevBox = prevBox->prevLeafChild();
1133             } while (prevBox && prevBox->bidiLevel() > level);
1134
1135             if (prevBox && prevBox->bidiLevel() == level)   // For example, abc FED 123 ^ CBA
1136                 return;
1137
1138             // For example, abc 123 ^ CBA
1139             while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1140                 if (nextBox->bidiLevel() < level)
1141                     break;
1142                 inlineBox = nextBox;
1143             }
1144             caretOffset = inlineBox->caretRightmostOffset();
1145         } else {
1146             InlineBox* prevBox = inlineBox->prevLeafChild();
1147             if (!prevBox || prevBox->bidiLevel() >= level)
1148                 return;
1149
1150             level = prevBox->bidiLevel();
1151             InlineBox* nextBox = inlineBox;
1152             do {
1153                 nextBox = nextBox->nextLeafChild();
1154             } while (nextBox && nextBox->bidiLevel() > level);
1155
1156             if (nextBox && nextBox->bidiLevel() == level)
1157                 return;
1158
1159             while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1160                 if (prevBox->bidiLevel() < level)
1161                     break;
1162                 inlineBox = prevBox;
1163             }
1164             caretOffset = inlineBox->caretLeftmostOffset();
1165         }
1166         return;
1167     }
1168
1169     if (caretOffset == inlineBox->caretLeftmostOffset()) {
1170         InlineBox* prevBox = inlineBox->prevLeafChild();
1171         if (!prevBox || prevBox->bidiLevel() < level) {
1172             // Left edge of a secondary run. Set to the right edge of the entire run.
1173             while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1174                 if (nextBox->bidiLevel() < level)
1175                     break;
1176                 inlineBox = nextBox;
1177             }
1178             caretOffset = inlineBox->caretRightmostOffset();
1179         } else if (prevBox->bidiLevel() > level) {
1180             // Right edge of a "tertiary" run. Set to the left edge of that run.
1181             while (InlineBox* tertiaryBox = inlineBox->prevLeafChild()) {
1182                 if (tertiaryBox->bidiLevel() <= level)
1183                     break;
1184                 inlineBox = tertiaryBox;
1185             }
1186             caretOffset = inlineBox->caretLeftmostOffset();
1187         }
1188     } else {
1189         InlineBox* nextBox = inlineBox->nextLeafChild();
1190         if (!nextBox || nextBox->bidiLevel() < level) {
1191             // Right edge of a secondary run. Set to the left edge of the entire run.
1192             while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1193                 if (prevBox->bidiLevel() < level)
1194                     break;
1195                 inlineBox = prevBox;
1196             }
1197             caretOffset = inlineBox->caretLeftmostOffset();
1198         } else if (nextBox->bidiLevel() > level) {
1199             // Left edge of a "tertiary" run. Set to the right edge of that run.
1200             while (InlineBox* tertiaryBox = inlineBox->nextLeafChild()) {
1201                 if (tertiaryBox->bidiLevel() <= level)
1202                     break;
1203                 inlineBox = tertiaryBox;
1204             }
1205             caretOffset = inlineBox->caretRightmostOffset();
1206         }
1207     }
1208 }
1209
1210 TextDirection Position::primaryDirection() const
1211 {
1212     TextDirection primaryDirection = LTR;
1213     for (const RenderObject* r = m_anchorNode->renderer(); r; r = r->parent()) {
1214         if (r->isBlockFlow()) {
1215             primaryDirection = r->style()->direction();
1216             break;
1217         }
1218     }
1219
1220     return primaryDirection;
1221 }
1222
1223
1224 void Position::debugPosition(const char* msg) const
1225 {
1226     if (isNull())
1227         fprintf(stderr, "Position [%s]: null\n", msg);
1228     else
1229         fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, deprecatedNode()->nodeName().utf8().data(), deprecatedNode(), m_offset);
1230 }
1231
1232 #ifndef NDEBUG
1233
1234 void Position::formatForDebugger(char* buffer, unsigned length) const
1235 {
1236     String result;
1237     
1238     if (isNull())
1239         result = "<null>";
1240     else {
1241         char s[1024];
1242         result += "offset ";
1243         result += String::number(m_offset);
1244         result += " of ";
1245         deprecatedNode()->formatForDebugger(s, sizeof(s));
1246         result += s;
1247     }
1248           
1249     strncpy(buffer, result.utf8().data(), length - 1);
1250 }
1251
1252 void Position::showAnchorTypeAndOffset() const
1253 {
1254     if (m_isLegacyEditingPosition)
1255         fputs("legacy, ", stderr);
1256     switch (anchorType()) {
1257     case PositionIsOffsetInAnchor:
1258         fputs("offset", stderr);
1259         break;
1260     case PositionIsAfterAnchor:
1261         fputs("after", stderr);
1262         break;
1263     case PositionIsBeforeAnchor:
1264         fputs("before", stderr);
1265         break;
1266     }
1267     fprintf(stderr, ", offset:%d\n", m_offset);
1268 }
1269
1270 void Position::showTreeForThis() const
1271 {
1272     if (anchorNode()) {
1273         anchorNode()->showTreeForThis();
1274         showAnchorTypeAndOffset();
1275     }
1276 }
1277
1278 #endif
1279
1280
1281
1282 } // namespace WebCore
1283
1284 #ifndef NDEBUG
1285
1286 void showTree(const WebCore::Position& pos)
1287 {
1288     pos.showTreeForThis();
1289 }
1290
1291 void showTree(const WebCore::Position* pos)
1292 {
1293     if (pos)
1294         pos->showTreeForThis();
1295 }
1296
1297 #endif