Reviewed by John
[WebKit-https.git] / WebCore / khtml / xml / dom_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 "dom_position.h"
27
28 #include <qstring.h>
29
30 #include "css_computedstyle.h"
31 #include "css_valueimpl.h"
32 #include "dom_elementimpl.h"
33 #include "dom_nodeimpl.h"
34 #include "dom_positioniterator.h"
35 #include "dom2_range.h"
36 #include "dom2_rangeimpl.h"
37 #include "dom2_viewsimpl.h"
38 #include "helper.h"
39 #include "htmltags.h"
40 #include "text_affinity.h"
41 #include "visible_position.h"
42 #include "rendering/render_block.h"
43 #include "rendering/render_flow.h"
44 #include "rendering/render_line.h"
45 #include "rendering/render_style.h"
46 #include "rendering/render_text.h"
47
48 #if APPLE_CHANGES
49 #include "KWQAssertions.h"
50 #include "KWQLogging.h"
51 #else
52 #define ASSERT(assertion) assert(assertion)
53 #define LOG(channel, formatAndArgs...) ((void)0)
54 #endif
55
56 using khtml::EAffinity;
57 using khtml::InlineBox;
58 using khtml::InlineTextBox;
59 using khtml::RenderBlock;
60 using khtml::RenderFlow;
61 using khtml::RenderObject;
62 using khtml::RenderText;
63 using khtml::RootInlineBox;
64 using khtml::VISIBLE;
65 using khtml::VisiblePosition;
66
67 namespace DOM {
68
69 static NodeImpl *nextRenderedEditable(NodeImpl *node)
70 {
71     while (1) {
72         node = node->nextEditable();
73         if (!node)
74             return 0;
75         if (!node->renderer())
76             continue;
77         if (node->renderer()->inlineBox(0))
78             return node;
79     }
80     return 0;
81 }
82
83 static NodeImpl *previousRenderedEditable(NodeImpl *node)
84 {
85     while (1) {
86         node = node->previousEditable();
87         if (!node)
88             return 0;
89         if (!node->renderer())
90             continue;
91         if (node->renderer()->inlineBox(0))
92             return node;
93     }
94     return 0;
95 }
96
97
98 Position::Position(NodeImpl *node, long offset) 
99     : m_node(node), m_offset(offset) 
100
101     if (node) {
102         node->ref();
103     }
104 }
105
106 Position::Position(const Position &o)
107     : m_node(o.m_node), m_offset(o.m_offset) 
108 {
109     if (m_node) {
110         m_node->ref();
111     }
112 }
113
114 Position::~Position()
115 {
116     if (m_node) {
117         m_node->deref();
118     }
119 }
120
121 Position &Position::operator=(const Position &o)
122 {
123     if (m_node) {
124         m_node->deref();
125     }
126     m_node = o.m_node;
127     if (m_node) {
128         m_node->ref();
129     }
130
131     m_offset = o.m_offset;
132     
133     return *this;
134 }
135
136 void Position::clear()
137 {
138     if (m_node) {
139         m_node->deref();
140         m_node = 0;
141     }
142     m_offset = 0;
143 }
144
145 ElementImpl *Position::element() const
146 {
147     NodeImpl *n;
148     for (n = node(); n && !n->isElementNode(); n = n->parentNode())
149         ; // empty loop body
150     return static_cast<ElementImpl *>(n);
151 }
152
153 CSSComputedStyleDeclarationImpl *Position::computedStyle() const
154 {
155     ElementImpl *elem = element();
156     if (!elem)
157         return 0;
158     return new CSSComputedStyleDeclarationImpl(elem);
159 }
160
161 long Position::renderedOffset() const
162 {
163     if (!node()->isTextNode())
164         return offset();
165    
166     if (!node()->renderer())
167         return offset();
168                     
169     long result = 0;
170     RenderText *textRenderer = static_cast<RenderText *>(node()->renderer());
171     for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
172         long start = box->m_start;
173         long end = box->m_start + box->m_len;
174         if (offset() < start)
175             return result;
176         if (offset() <= end) {
177             result += offset() - start;
178             return result;
179         }
180         result += box->m_len;
181     }
182     return result;
183 }
184
185 Position Position::previousCharacterPosition() const
186 {
187     if (isNull())
188         return Position();
189
190     NodeImpl *fromRootEditableElement = node()->rootEditableElement();
191     PositionIterator it(*this);
192
193     bool atStartOfLine = isFirstVisiblePositionOnLine(VisiblePosition(*this));
194     bool rendered = inRenderedContent();
195     
196     while (!it.atStart()) {
197         Position pos = it.previous();
198
199         if (pos.node()->rootEditableElement() != fromRootEditableElement)
200             return *this;
201
202         if (atStartOfLine || !rendered) {
203             if (pos.inRenderedContent())
204                 return pos;
205         }
206         else if (rendersInDifferentPosition(pos))
207             return pos;
208     }
209     
210     return *this;
211 }
212
213 Position Position::nextCharacterPosition() const
214 {
215     if (isNull())
216         return Position();
217
218     NodeImpl *fromRootEditableElement = node()->rootEditableElement();
219     PositionIterator it(*this);
220
221     bool atEndOfLine = isLastVisiblePositionOnLine(VisiblePosition(*this));
222     bool rendered = inRenderedContent();
223     
224     while (!it.atEnd()) {
225         Position pos = it.next();
226
227         if (pos.node()->rootEditableElement() != fromRootEditableElement)
228             return *this;
229
230         if (atEndOfLine || !rendered) {
231             if (pos.inRenderedContent())
232                 return pos;
233         }
234         else if (rendersInDifferentPosition(pos))
235             return pos;
236     }
237     
238     return *this;
239 }
240
241 Position Position::previousLinePosition(int x, EAffinity affinity) const
242 {
243     if (!node())
244         return Position();
245
246     if (!node()->renderer())
247         return *this;
248
249     RenderBlock *containingBlock = 0;
250     RootInlineBox *root = 0;
251     InlineBox *box = node()->renderer()->inlineBox(offset(), affinity);
252     if (box) {
253         root = box->root()->prevRootBox();
254         if (root)
255             containingBlock = node()->renderer()->containingBlock();
256     }
257
258     if (!root) {
259         // This containing editable block does not have a previous line.
260         // Need to move back to previous containing editable block in this root editable
261         // block and find the last root line box in that block.
262         NodeImpl *startBlock = node()->enclosingBlockFlowElement();
263         NodeImpl *n = node()->previousEditable();
264         while (n && startBlock == n->enclosingBlockFlowElement())
265             n = n->previousEditable();
266         while (n) {
267             if (!n->inSameRootEditableElement(node()))
268                 break;
269             Position pos(n, n->caretMinOffset());
270             if (pos.inRenderedContent()) {
271                 ASSERT(n->renderer());
272                 box = n->renderer()->inlineBox(n->caretMaxOffset());
273                 if (box) {
274                     // previous root line box found
275                     root = box->root();
276                     containingBlock = n->renderer()->containingBlock();
277                     break;
278                 }
279                 else {
280                     return pos;
281                 }
282             }
283             n = n->previousEditable();
284         }
285     }
286     
287     if (root) {
288         int absx, absy;
289         containingBlock->absolutePosition(absx, absy);
290         RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
291         return renderer->positionForCoordinates(x, absy + root->topOverflow());
292     }
293     
294     // Could not find a previous line. This means we must already be on the first line.
295     // Move to the start of the content in this block, which effectively moves us
296     // to the start of the line we're on.
297     return Position(node()->rootEditableElement(), 0);
298 }
299
300 Position Position::nextLinePosition(int x, EAffinity affinity) const
301 {
302     if (!node())
303         return Position();
304
305     if (!node()->renderer())
306         return *this;
307
308     RenderBlock *containingBlock = 0;
309     RootInlineBox *root = 0;
310     InlineBox *box = node()->renderer()->inlineBox(offset(), affinity);
311     if (box) {
312         root = box->root()->nextRootBox();
313         if (root)
314             containingBlock = node()->renderer()->containingBlock();
315     }
316
317     if (!root) {
318         // This containing editable block does not have a next line.
319         // Need to move forward to next containing editable block in this root editable
320         // block and find the first root line box in that block.
321         NodeImpl *startBlock = node()->enclosingBlockFlowElement();
322         NodeImpl *n = node()->nextEditable();
323         while (n && startBlock == n->enclosingBlockFlowElement())
324             n = n->nextEditable();
325         while (n) {
326             if (!n->inSameRootEditableElement(node()))
327                 break;
328             Position pos(n, n->caretMinOffset());
329             if (pos.inRenderedContent()) {
330                 ASSERT(n->renderer());
331                 box = n->renderer()->inlineBox(n->caretMinOffset());
332                 if (box) {
333                     // next root line box found
334                     root = box->root();
335                     containingBlock = n->renderer()->containingBlock();
336                     break;
337                 }
338                 else {
339                     return pos;
340                 }
341             }
342             n = n->nextEditable();
343         }
344     }
345     
346     if (root) {
347         int absx, absy;
348         containingBlock->absolutePosition(absx, absy);
349         RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
350         return renderer->positionForCoordinates(x, absy + root->topOverflow());
351     }    
352
353     // Could not find a next line. This means we must already be on the last line.
354     // Move to the end of the content in this block, which effectively moves us
355     // to the end of the line we're on.
356     ElementImpl *rootElement = node()->rootEditableElement();
357     return Position(rootElement, rootElement ? rootElement->childNodeCount() : 0);
358 }
359
360 Position Position::upstream(EStayInBlock stayInBlock) const
361 {
362     Position start = equivalentDeepPosition();
363     NodeImpl *startNode = start.node();
364     if (!startNode)
365         return Position();
366
367     NodeImpl *block = startNode->enclosingBlockFlowElement();
368     Position lastVisible;
369     
370     PositionIterator it(start);
371     for (; !it.atStart(); it.previous()) {
372         NodeImpl *currentNode = it.current().node();
373
374         if (stayInBlock) {
375             NodeImpl *currentBlock = currentNode->enclosingBlockFlowElement();
376             if (block != currentBlock)
377                 return it.next();
378         }
379
380         RenderObject *renderer = currentNode->renderer();
381         if (!renderer)
382             continue;
383
384         if (renderer->style()->visibility() != VISIBLE)
385             continue;
386
387         lastVisible = it.current();
388
389         if (renderer->isReplaced() || renderer->isBR()) {
390             if (it.current().offset() >= renderer->caretMaxOffset())
391                 return Position(currentNode, renderer->caretMaxOffset());
392             else
393                 continue;
394         }
395
396         if (renderer->isText() && static_cast<RenderText *>(renderer)->firstTextBox()) {
397             if (currentNode != startNode)
398                 return Position(currentNode, renderer->caretMaxOffset());
399
400             if (it.current().offset() < 0)
401                 continue;
402             uint textOffset = it.current().offset();
403
404             RenderText *textRenderer = static_cast<RenderText *>(renderer);
405             for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
406                 if (textOffset > box->start() && textOffset <= box->start() + box->len())
407                     return it.current();
408                 else if (box != textRenderer->lastTextBox() && 
409                          !box->nextOnLine() && 
410                          textOffset == box->start() + box->len() + 1)
411                     return it.current();
412             }
413         }
414     }
415     
416     return lastVisible.isNotNull() ? lastVisible : *this;
417 }
418
419 Position Position::downstream(EStayInBlock stayInBlock) const
420 {
421     Position start = equivalentDeepPosition();
422     NodeImpl *startNode = start.node();
423     if (!startNode)
424         return Position();
425
426     NodeImpl *block = startNode->enclosingBlockFlowElement();
427     Position lastVisible;
428     
429     PositionIterator it(start);            
430     for (; !it.atEnd(); it.next()) {   
431         NodeImpl *currentNode = it.current().node();
432
433         if (stayInBlock) {
434             NodeImpl *currentBlock = currentNode->enclosingBlockFlowElement();
435             if (block != currentBlock)
436                 return it.previous();
437         }
438
439         RenderObject *renderer = currentNode->renderer();
440         if (!renderer)
441             continue;
442
443         if (renderer->style()->visibility() != VISIBLE)
444             continue;
445
446         lastVisible = it.current();
447
448         if (currentNode != startNode && renderer->isBlockFlow()) {
449             if (it.current().offset() == 0) {
450                 // If no first child, or first visible child is a not a block, return; otherwise continue.
451                 if (!currentNode->firstChild())
452                     return Position(currentNode, 0);
453                 for (NodeImpl *child = currentNode->firstChild(); child; child = child->nextSibling()) {
454                     RenderObject *r = child->renderer();
455                     if (r && r->style()->visibility() == VISIBLE) {
456                          if (r->isBlockFlow())
457                             break; // break causes continue code below to run.
458                          else
459                             return Position(child, 0);
460                     }
461                 }
462                 continue;
463             }
464         }
465
466         if (renderer->isReplaced() || renderer->isBR()) {
467             if (it.current().offset() <= renderer->caretMinOffset())
468                 return Position(currentNode, renderer->caretMinOffset());
469             else
470                 continue;
471         }
472
473         if (renderer->isText() && static_cast<RenderText *>(renderer)->firstTextBox()) {
474             if (currentNode != node())
475                 return Position(currentNode, renderer->caretMinOffset());
476
477             if (it.current().offset() < 0)
478                 continue;
479             uint textOffset = it.current().offset();
480
481             RenderText *textRenderer = static_cast<RenderText *>(renderer);
482             for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
483                 if (textOffset >= box->start() && textOffset <= box->end())
484                     return it.current();
485                 else if (box != textRenderer->lastTextBox() && 
486                          !box->nextOnLine() && 
487                          textOffset == box->start() + box->len())
488                     return it.current();
489             }
490         }
491     }
492     
493     return lastVisible.isNotNull() ? lastVisible : *this;
494 }
495
496 Position Position::equivalentRangeCompliantPosition() const
497 {
498     if (isNull())
499         return Position();
500
501     // Make sure that 0 <= constrainedOffset <= num kids, otherwise using this Position
502     // in DOM calls can result in exceptions.
503     long maxOffset = node()->isTextNode() ? static_cast<TextImpl *>(node())->length(): node()->childNodeCount();
504     long constrainedOffset = offset() <= 0 ? 0 : kMin(maxOffset, offset());
505
506     if (!node()->parentNode())
507         return Position(node(), constrainedOffset);
508
509     RenderObject *renderer = node()->renderer();
510     if (!renderer)
511         return Position(node(), constrainedOffset);
512         
513     if (!renderer->isReplaced() && !renderer->isBR())
514         return Position(node(), constrainedOffset);
515     
516     long o = offset();
517     const NodeImpl *n = node();
518     while ((n = n->previousSibling()))
519         o++;
520     
521     // Make sure that 0 <= constrainedOffset <= num kids, as above.
522     NodeImpl *parent = node()->parentNode();
523     maxOffset = parent->isTextNode() ? static_cast<TextImpl *>(parent)->length(): parent->childNodeCount();
524     constrainedOffset = o <= 0 ? 0 : kMin(maxOffset, o);
525     return Position(parent, constrainedOffset);
526 }
527
528 Position Position::equivalentDeepPosition() const
529 {
530     if (isNull() || node()->isAtomicNode())
531         return *this;
532
533     NodeImpl *child = 0;
534     Position pos(*this);
535     if (offset() >= (int)node()->childNodeCount()) {
536         child = node()->lastChild();
537         pos = Position(child, child->caretMaxOffset());
538         ASSERT(child);
539         while (!child->isAtomicNode() && pos.node()->hasChildNodes()) {
540             child = pos.node()->lastChild();
541             ASSERT(child);
542             pos = Position(child, child->caretMaxOffset());
543         }
544     }
545     else {
546         child = node()->childNode(offset());
547         ASSERT(child);
548         pos = Position(child, 0);
549         while (!child->isAtomicNode() && pos.node()->hasChildNodes()) {
550             child = pos.node()->firstChild();
551             ASSERT(child);
552             pos = Position(child, 0);
553         }
554     }
555     return pos;
556 }
557
558 bool Position::inRenderedContent() const
559 {
560     if (isNull())
561         return false;
562         
563     RenderObject *renderer = node()->renderer();
564     if (!renderer)
565         return false;
566     
567     if (renderer->style()->visibility() != VISIBLE)
568         return false;
569
570     // FIXME: This check returns false for a <br> at the end of a line!
571     if (renderer->isBR() && static_cast<RenderText *>(renderer)->firstTextBox()) {
572         return offset() == 0;
573     }
574     else if (renderer->isText()) {
575         RenderText *textRenderer = static_cast<RenderText *>(renderer);
576         for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
577             if (offset() >= box->m_start && offset() <= box->m_start + box->m_len) {
578                 return true;
579             }
580             else if (offset() < box->m_start) {
581                 // The offset we're looking for is before this node
582                 // this means the offset must be in content that is
583                 // not rendered. Return false.
584                 return false;
585             }
586         }
587     }
588     else if (offset() >= renderer->caretMinOffset() && offset() <= renderer->caretMaxOffset()) {
589         // return true for replaced elements, for inline flows if they have a line box
590         // and for blocks if they are empty
591         if (renderer->isReplaced() ||
592             (renderer->isInlineFlow() && static_cast<RenderFlow *>(renderer)->firstLineBox()) ||
593             (renderer->isBlockFlow() && !renderer->firstChild() && renderer->height()))
594             return true;
595     }
596     
597     return false;
598 }
599
600 bool Position::inRenderedText() const
601 {
602     if (isNull() || !node()->isTextNode())
603         return false;
604         
605     RenderObject *renderer = node()->renderer();
606     if (!renderer)
607         return false;
608     
609     RenderText *textRenderer = static_cast<RenderText *>(renderer);
610     for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
611         if (offset() < box->m_start) {
612             // The offset we're looking for is before this node
613             // this means the offset must be in content that is
614             // not rendered. Return false.
615             return false;
616         }
617         if (offset() >= box->m_start && offset() <= box->m_start + box->m_len)
618             return true;
619     }
620     
621     return false;
622 }
623
624 bool Position::isRenderedCharacter() const
625 {
626     if (isNull() || !node()->isTextNode())
627         return false;
628         
629     RenderObject *renderer = node()->renderer();
630     if (!renderer)
631         return false;
632     
633     RenderText *textRenderer = static_cast<RenderText *>(renderer);
634     for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
635         if (offset() < box->m_start) {
636             // The offset we're looking for is before this node
637             // this means the offset must be in content that is
638             // not rendered. Return false.
639             return false;
640         }
641         if (offset() >= box->m_start && offset() < box->m_start + box->m_len)
642             return true;
643     }
644     
645     return false;
646 }
647
648 bool Position::rendersInDifferentPosition(const Position &pos) const
649 {
650     if (isNull() || pos.isNull())
651         return false;
652
653     RenderObject *renderer = node()->renderer();
654     if (!renderer)
655         return false;
656     
657     RenderObject *posRenderer = pos.node()->renderer();
658     if (!posRenderer)
659         return false;
660
661     if (renderer->style()->visibility() != VISIBLE ||
662         posRenderer->style()->visibility() != VISIBLE)
663         return false;
664     
665     if (node() == pos.node()) {
666         if (node()->id() == ID_BR)
667             return false;
668
669         if (offset() == pos.offset())
670             return false;
671             
672         if (!node()->isTextNode() && !pos.node()->isTextNode()) {
673             if (offset() != pos.offset())
674                 return true;
675         }
676     }
677     
678     if (node()->id() == ID_BR && pos.inRenderedContent())
679         return true;
680                 
681     if (pos.node()->id() == ID_BR && inRenderedContent())
682         return true;
683                 
684     if (node()->enclosingBlockFlowElement() != pos.node()->enclosingBlockFlowElement())
685         return true;
686
687     if (node()->isTextNode() && !inRenderedText())
688         return false;
689
690     if (pos.node()->isTextNode() && !pos.inRenderedText())
691         return false;
692
693     long thisRenderedOffset = renderedOffset();
694     long posRenderedOffset = pos.renderedOffset();
695
696     if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
697         return false;
698
699     LOG(Editing, "renderer:               %p [%p]\n", renderer, renderer ? renderer->inlineBox(offset()) : 0);
700     LOG(Editing, "thisRenderedOffset:         %d\n", thisRenderedOffset);
701     LOG(Editing, "posRenderer:            %p [%p]\n", posRenderer, posRenderer ? posRenderer->inlineBox(offset()) : 0);
702     LOG(Editing, "posRenderedOffset:      %d\n", posRenderedOffset);
703     LOG(Editing, "node min/max:           %d:%d\n", node()->caretMinOffset(), node()->caretMaxRenderedOffset());
704     LOG(Editing, "pos node min/max:       %d:%d\n", pos.node()->caretMinOffset(), pos.node()->caretMaxRenderedOffset());
705     LOG(Editing, "----------------------------------------------------------------------\n");
706
707     InlineBox *b1 = renderer ? renderer->inlineBox(offset()) : 0;
708     InlineBox *b2 = posRenderer ? posRenderer->inlineBox(pos.offset()) : 0;
709
710     if (!b1 || !b2) {
711         return false;
712     }
713
714     if (b1->root() != b2->root()) {
715         return true;
716     }
717
718     if (nextRenderedEditable(node()) == pos.node() && 
719         thisRenderedOffset == (long)node()->caretMaxRenderedOffset() && posRenderedOffset == 0) {
720         return false;
721     }
722     
723     if (previousRenderedEditable(node()) == pos.node() && 
724         thisRenderedOffset == 0 && posRenderedOffset == (long)pos.node()->caretMaxRenderedOffset()) {
725         return false;
726     }
727
728     return true;
729 }
730
731 static inline bool isWS(const QChar &c)
732 {
733     const char nonBreakingSpace = 0xA0;
734     return c.isSpace() && c != nonBreakingSpace;
735 }
736
737 Position Position::leadingWhitespacePosition() const
738 {
739     if (isNull())
740         return Position();
741     
742     if (upstream(StayInBlock).node()->id() == ID_BR)
743         return Position();
744     
745     Position prev = previousCharacterPosition();
746     if (prev != *this && prev.node()->inSameContainingBlockFlowElement(node()) && prev.node()->isTextNode()) {
747         DOMString string = static_cast<TextImpl *>(prev.node())->data();
748         if (isWS(string[prev.offset()]))
749             return prev;
750     }
751
752     return Position();
753 }
754
755 Position Position::trailingWhitespacePosition() const
756 {
757     if (isNull())
758         return Position();
759
760     if (node()->isTextNode()) {
761         TextImpl *textNode = static_cast<TextImpl *>(node());
762         if (offset() < (long)textNode->length()) {
763             DOMString string = static_cast<TextImpl *>(node())->data();
764             if (isWS(string[offset()]))
765                 return *this;
766             return Position();
767         }
768     }
769
770     if (downstream(StayInBlock).node()->id() == ID_BR)
771         return Position();
772
773     Position next = nextCharacterPosition();
774     if (next != *this && next.node()->inSameContainingBlockFlowElement(node()) && next.node()->isTextNode()) {
775         DOMString string = static_cast<TextImpl *>(next.node())->data();
776         if (isWS(string[0]))
777             return next;
778     }
779
780     return Position();
781 }
782
783 void Position::debugPosition(const char *msg) const
784 {
785     if (isNull())
786         fprintf(stderr, "Position [%s]: null\n", msg);
787     else
788         fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, node()->nodeName().string().latin1(), node(), offset());
789 }
790
791 #ifndef NDEBUG
792 #define FormatBufferSize 1024
793 void Position::formatForDebugger(char *buffer, unsigned length) const
794 {
795     DOMString result;
796     DOMString s;
797     
798     if (isNull()) {
799         result = "<null>";
800     }
801     else {
802         char s[FormatBufferSize];
803         result += "offset ";
804         result += QString::number(m_offset);
805         result += " of ";
806         m_node->formatForDebugger(s, FormatBufferSize);
807         result += s;
808     }
809           
810     strncpy(buffer, result.string().latin1(), length - 1);
811 }
812 #undef FormatBufferSize
813 #endif
814
815
816 Position startPosition(const Range &r)
817 {
818     if (r.isNull() || r.isDetached())
819         return Position();
820     return Position(r.startContainer().handle(), r.startOffset());
821 }
822
823 Position startPosition(const RangeImpl *r)
824 {
825     if (!r || r->isDetached())
826         return Position();
827     int exceptionCode;
828     return Position(r->startContainer(exceptionCode), r->startOffset(exceptionCode));
829 }
830
831 Position endPosition(const Range &r)
832 {
833     if (r.isNull() || r.isDetached())
834         return Position();
835     return Position(r.endContainer().handle(), r.endOffset());
836 }
837
838 Position endPosition(const RangeImpl *r)
839 {
840     if (!r || r->isDetached())
841         return Position();
842     int exceptionCode;
843     return Position(r->endContainer(exceptionCode), r->endOffset(exceptionCode));
844 }
845
846 } // namespace DOM