2 * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #include "dom_position.h"
28 #include "misc/helper.h"
29 #include "misc/htmltags.h"
30 #include "rendering/render_block.h"
31 #include "rendering/render_line.h"
32 #include "rendering/render_object.h"
33 #include "rendering/render_style.h"
34 #include "rendering/render_text.h"
35 #include "xml/dom_positioniterator.h"
36 #include "xml/dom_elementimpl.h"
37 #include "xml/dom_docimpl.h"
38 #include "xml/dom_nodeimpl.h"
39 #include "html/html_documentimpl.h"
41 #include "khtml_part.h"
45 using khtml::InlineBox
;
46 using khtml::InlineFlowBox
;
47 using khtml::InlineTextBox
;
48 using khtml::RenderBlock
;
49 using khtml::RenderObject
;
50 using khtml::RenderText
;
51 using khtml::RootInlineBox
;
55 static bool renderersOnDifferentLine(RenderObject
*r1
, long o1
, RenderObject
*r2
, long o2
)
57 InlineBox
*b1
= r1
? r1
->inlineBox(o1
) : 0;
58 InlineBox
*b2
= r2
? r2
->inlineBox(o2
) : 0;
59 return (b1
&& b2
&& b1
->root() != b2
->root());
62 static NodeImpl
*nextRenderedEditable(NodeImpl
*node
)
65 node
= node
->nextEditable();
68 if (!node
->renderer())
70 if (node
->renderer()->inlineBox(0))
76 static NodeImpl
*previousRenderedEditable(NodeImpl
*node
)
79 node
= node
->previousEditable();
82 if (!node
->renderer())
84 if (node
->renderer()->inlineBox(0))
90 static NodeImpl
*rootNavigableElement(NodeImpl
*node
)
92 DocumentImpl
*doc
= node
->document();
93 if (doc
&& doc
->part()->isCaretMode()) {
94 if (doc
->isHTMLDocument())
95 return static_cast<HTMLDocumentImpl
*>(doc
)->body();
97 return doc
->documentElement();
100 return node
->rootEditableElement();
103 inline static bool inSameRootNavigableElement(NodeImpl
*n1
, NodeImpl
*n2
)
105 return n1
&& n2
&& rootNavigableElement(n1
) == rootNavigableElement(n2
);
108 Position::Position(NodeImpl
*node
, long offset
)
109 : m_node(0), m_offset(offset
)
117 Position::Position(const Position
&o
)
118 : m_node(0), m_offset(o
.offset())
126 Position::~Position() {
132 Position
&Position::operator=(const Position
&o
)
142 m_offset
= o
.offset();
147 ElementImpl
*Position::element() const
152 NodeImpl
*n
= node();
153 for (; n
&& !n
->isElementNode(); n
= n
->parentNode()); //loop
155 return static_cast<ElementImpl
*>(n
);
158 long Position::renderedOffset() const
160 if (!node()->isTextNode())
163 if (!node()->renderer())
167 RenderText
*textRenderer
= static_cast<RenderText
*>(node()->renderer());
168 for (InlineTextBox
*box
= textRenderer
->firstTextBox(); box
; box
= box
->nextTextBox()) {
169 int start
= box
->m_start
;
170 int end
= box
->m_start
+ box
->m_len
;
171 if (offset() < start
)
173 if (offset() <= end
) {
174 result
+= offset() - start
;
177 result
+= box
->m_len
;
182 Position
Position::equivalentLeafPosition() const
187 if (!node()->renderer() || !node()->renderer()->firstChild())
190 NodeImpl
*n
= node();
193 n
= n
->nextLeafNode();
194 if (!n
|| !n
->inSameContainingBlockFlowElement(node()))
196 if (count
+ n
->maxOffset() >= offset()) {
197 count
= offset() - count
;
200 count
+= n
->maxOffset();
202 return Position(n
, count
);
205 Position
Position::previousRenderedEditablePosition() const
210 if ((node()->document()->part()->isCaretMode() || node()->isContentEditable()) && node()->hasChildNodes() == false && inRenderedContent())
213 NodeImpl
*n
= node();
215 n
= n
->previousEditable();
218 if (n
->renderer() && n
->renderer()->style()->visibility() == khtml::VISIBLE
)
222 return Position(n
, 0);
225 Position
Position::nextRenderedEditablePosition() const
230 if ((node()->document()->part()->isCaretMode() || node()->isContentEditable()) && node()->hasChildNodes() == false && inRenderedContent())
233 NodeImpl
*n
= node();
235 n
= n
->nextEditable();
238 if (n
->renderer() && n
->renderer()->style()->visibility() == khtml::VISIBLE
)
242 return Position(n
, 0);
245 Position
Position::previousCharacterPosition() const
250 NodeImpl
*fromRootNavigableElement
= rootNavigableElement(node());
251 // kDebug(6200) << "prevCharPos: cur(" << node() << "," << offset() << ") fromRootNav " << fromRootNavigableElement << endl;
252 PositionIterator
it(*this);
254 bool atStartOfLine
= isFirstRenderedPositionOnLine();
256 while (!it
.atStart()) {
257 Position pos
= it
.previous();
259 if (rootNavigableElement(pos
.node()) != fromRootNavigableElement
)
263 if (pos
.inRenderedContent())
266 else if (rendersInDifferentPosition(pos
))
273 Position
Position::nextCharacterPosition() const
278 NodeImpl
*fromRootNavigableElement
= rootNavigableElement(node());
279 PositionIterator
it(*this);
281 bool atEndOfLine
= isLastRenderedPositionOnLine();
283 while (!it
.atEnd()) {
284 Position pos
= it
.next();
286 if (rootNavigableElement(pos
.node()) != fromRootNavigableElement
)
290 if (pos
.inRenderedContent())
293 else if (rendersInDifferentPosition(pos
))
300 Position
Position::previousWordPosition() const
305 Position pos
= *this;
306 for (PositionIterator
it(*this); !it
.atStart(); it
.previous()) {
307 if (it
.current().node()->nodeType() == Node::TEXT_NODE
|| it
.current().node()->nodeType() == Node::CDATA_SECTION_NODE
) {
308 DOMString t
= it
.current().node()->nodeValue();
309 QChar
*chars
= t
.unicode();
310 uint len
= t
.length();
312 khtml::findWordBoundary(chars
, len
, it
.current().offset(), &start
, &end
);
313 pos
= Position(it
.current().node(), start
);
316 pos
= Position(it
.current().node(), it
.current().node()->caretMinOffset());
326 Position
Position::nextWordPosition() const
331 Position pos
= *this;
332 for (PositionIterator
it(*this); !it
.atEnd(); it
.next()) {
333 if (it
.current().node()->nodeType() == Node::TEXT_NODE
|| it
.current().node()->nodeType() == Node::CDATA_SECTION_NODE
) {
334 DOMString t
= it
.current().node()->nodeValue();
335 QChar
*chars
= t
.unicode();
336 uint len
= t
.length();
338 khtml::findWordBoundary(chars
, len
, it
.current().offset(), &start
, &end
);
339 pos
= Position(it
.current().node(), end
);
342 pos
= Position(it
.current().node(), it
.current().node()->caretMaxOffset());
352 Position
Position::previousLinePosition(int x
) const
357 if (!node()->renderer())
360 InlineBox
*box
= node()->renderer()->inlineBox(offset());
364 RenderBlock
*containingBlock
= 0;
365 RootInlineBox
*root
= box
->root()->prevRootBox();
367 containingBlock
= node()->renderer()->containingBlock();
370 // This containing editable block does not have a previous line.
371 // Need to move back to previous containing editable block in this root editable
372 // block and find the last root line box in that block.
373 NodeImpl
*startBlock
= node()->enclosingBlockFlowElement();
374 NodeImpl
*n
= node()->previousEditable();
375 while (n
&& startBlock
== n
->enclosingBlockFlowElement())
376 n
= n
->previousEditable();
378 while (n
&& !Position(n
, n
->caretMaxOffset()).inRenderedContent())
379 n
= n
->previousEditable();
380 if (n
&& inSameRootNavigableElement(n
, node())) {
381 assert(n
->renderer());
382 box
= n
->renderer()->inlineBox(n
->caretMaxOffset());
384 // previous root line box found
386 containingBlock
= n
->renderer()->containingBlock();
393 containingBlock
->absolutePosition(absx
, absy
);
394 RenderObject
*renderer
= root
->closestLeafChildForXPos(x
, absx
)->object();
395 return renderer
->positionForCoordinates(x
, absy
+ root
->topOverflow());
401 Position
Position::nextLinePosition(int x
) const
406 if (!node()->renderer())
409 InlineBox
*box
= node()->renderer()->inlineBox(offset());
413 RenderBlock
*containingBlock
= 0;
414 RootInlineBox
*root
= box
->root()->nextRootBox();
416 containingBlock
= node()->renderer()->containingBlock();
419 // This containing editable block does not have a next line.
420 // Need to move forward to next containing editable block in this root editable
421 // block and find the first root line box in that block.
422 NodeImpl
*startBlock
= node()->enclosingBlockFlowElement();
423 NodeImpl
*n
= node()->nextEditable();
424 while (n
&& startBlock
== n
->enclosingBlockFlowElement())
425 n
= n
->nextEditable();
427 while (n
&& !Position(n
, n
->caretMinOffset()).inRenderedContent())
428 n
= n
->nextEditable();
429 if (n
&& inSameRootNavigableElement(n
, node())) {
430 assert(n
->renderer());
431 box
= n
->renderer()->inlineBox(n
->caretMinOffset());
432 kDebug(6200) << "n: " << n
->nodeName() << endl
;
434 // previous root line box found
436 containingBlock
= n
->renderer()->containingBlock();
443 containingBlock
->absolutePosition(absx
, absy
);
444 RenderObject
*renderer
= root
->closestLeafChildForXPos(x
, absx
)->object();
445 return renderer
->positionForCoordinates(x
, absy
+ root
->topOverflow());
451 Position
Position::equivalentUpstreamPosition() const
456 NodeImpl
*block
= node()->enclosingBlockFlowElement();
458 PositionIterator
it(*this);
459 for (; !it
.atStart(); it
.previous()) {
460 NodeImpl
*currentBlock
= it
.current().node()->enclosingBlockFlowElement();
461 if (block
!= currentBlock
)
464 RenderObject
*renderer
= it
.current().node()->renderer();
468 if (renderer
->style()->visibility() != khtml::VISIBLE
)
471 if (renderer
->isBlockFlow() || renderer
->isReplaced() || renderer
->isBR()) {
472 if (it
.current().offset() >= renderer
->caretMaxOffset())
473 return Position(it
.current().node(), renderer
->caretMaxOffset());
478 if (renderer
->isText() && static_cast<RenderText
*>(renderer
)->firstTextBox()) {
479 if (it
.current().node() != node())
480 return Position(it
.current().node(), renderer
->caretMaxOffset());
482 if (it
.current().offset() < 0)
484 uint textOffset
= it
.current().offset();
486 RenderText
*textRenderer
= static_cast<RenderText
*>(renderer
);
487 for (InlineTextBox
*box
= textRenderer
->firstTextBox(); box
; box
= box
->nextTextBox()) {
488 if (textOffset
> box
->start() && textOffset
<= box
->start() + box
->len())
497 Position
Position::equivalentDownstreamPosition() const
502 NodeImpl
*block
= node()->enclosingBlockFlowElement();
504 PositionIterator
it(*this);
505 for (; !it
.atEnd(); it
.next()) {
506 NodeImpl
*currentBlock
= it
.current().node()->enclosingBlockFlowElement();
507 if (block
!= currentBlock
)
508 return it
.previous();
510 RenderObject
*renderer
= it
.current().node()->renderer();
514 if (renderer
->style()->visibility() != khtml::VISIBLE
)
517 if (renderer
->isBlockFlow() || renderer
->isReplaced() || renderer
->isBR()) {
518 if (it
.current().offset() <= renderer
->caretMinOffset())
519 return Position(it
.current().node(), renderer
->caretMinOffset());
524 if (renderer
->isText() && static_cast<RenderText
*>(renderer
)->firstTextBox()) {
525 if (it
.current().node() != node())
526 return Position(it
.current().node(), renderer
->caretMinOffset());
528 if (it
.current().offset() < 0)
530 uint textOffset
= it
.current().offset();
532 RenderText
*textRenderer
= static_cast<RenderText
*>(renderer
);
533 for (InlineTextBox
*box
= textRenderer
->firstTextBox(); box
; box
= box
->nextTextBox()) {
534 if (textOffset
>= box
->start() && textOffset
<= box
->end())
543 Position
Position::equivalentRangeCompliantPosition() const
548 if (!node()->parentNode())
551 RenderObject
*renderer
= node()->renderer();
555 if (!renderer
->isReplaced() && !renderer
->isBR())
559 const NodeImpl
*n
= node();
560 while ((n
= n
->previousSibling()))
563 return Position(node()->parentNode(), o
+ offset());
566 Position
Position::equivalentShallowPosition() const
572 while (pos
.offset() == pos
.node()->caretMinOffset() && pos
.node()->parentNode() && pos
.node() == pos
.node()->parentNode()->firstChild())
573 pos
= Position(pos
.node()->parentNode(), 0);
577 bool Position::atStartOfContainingEditableBlock() const
579 return renderedOffset() == 0 && inFirstEditableInContainingEditableBlock();
582 bool Position::atStartOfRootEditableElement() const
584 return renderedOffset() == 0 && inFirstEditableInRootEditableElement();
587 bool Position::inRenderedContent() const
592 RenderObject
*renderer
= node()->renderer();
593 if (!renderer
|| !(node()->document()->part()->isCaretMode() || renderer
->isEditable()))
596 if (renderer
->style()->visibility() != khtml::VISIBLE
)
599 if (renderer
->isBR() && static_cast<RenderText
*>(renderer
)->firstTextBox()) {
600 return offset() == 0;
602 else if (renderer
->isText()) {
603 RenderText
*textRenderer
= static_cast<RenderText
*>(renderer
);
604 for (InlineTextBox
*box
= textRenderer
->firstTextBox(); box
; box
= box
->nextTextBox()) {
605 if (offset() >= box
->m_start
&& offset() <= box
->m_start
+ box
->m_len
) {
608 else if (offset() < box
->m_start
) {
609 // The offset we're looking for is before this node
610 // this means the offset must be in content that is
611 // not rendered. Return false.
616 else if (offset() >= renderer
->caretMinOffset() && offset() <= renderer
->caretMaxOffset()) {
617 // don't return containing editable blocks unless they are empty
618 if (node()->enclosingBlockFlowElement() == node() && node()->firstChild())
626 bool Position::inRenderedText() const
628 if (!node()->isTextNode())
631 RenderObject
*renderer
= node()->renderer();
635 RenderText
*textRenderer
= static_cast<RenderText
*>(renderer
);
636 for (InlineTextBox
*box
= textRenderer
->firstTextBox(); box
; box
= box
->nextTextBox()) {
637 if (offset() < box
->m_start
) {
638 // The offset we're looking for is before this node
639 // this means the offset must be in content that is
640 // not rendered. Return false.
643 if (offset() >= box
->m_start
&& offset() <= box
->m_start
+ box
->m_len
)
650 bool Position::rendersOnSameLine(const Position
&pos
) const
652 if (isEmpty() || pos
.isEmpty())
655 if (node() == pos
.node() && offset() == pos
.offset())
658 if (node()->enclosingBlockFlowElement() != pos
.node()->enclosingBlockFlowElement())
661 RenderObject
*renderer
= node()->renderer();
665 RenderObject
*posRenderer
= pos
.node()->renderer();
669 if (renderer
->style()->visibility() != khtml::VISIBLE
||
670 posRenderer
->style()->visibility() != khtml::VISIBLE
)
673 return renderersOnDifferentLine(renderer
, offset(), posRenderer
, pos
.offset());
676 bool Position::rendersInDifferentPosition(const Position
&pos
) const
678 if (isEmpty() || pos
.isEmpty())
681 RenderObject
*renderer
= node()->renderer();
685 RenderObject
*posRenderer
= pos
.node()->renderer();
689 if (renderer
->style()->visibility() != khtml::VISIBLE
||
690 posRenderer
->style()->visibility() != khtml::VISIBLE
)
693 if (node() == pos
.node()) {
694 if (node()->id() == ID_BR
)
697 if (offset() == pos
.offset())
700 if (!node()->isTextNode() && !pos
.node()->isTextNode()) {
701 if (offset() != pos
.offset())
706 if (node()->id() == ID_BR
&& pos
.inRenderedContent())
709 if (pos
.node()->id() == ID_BR
&& inRenderedContent())
712 if (node()->enclosingBlockFlowElement() != pos
.node()->enclosingBlockFlowElement())
715 if (node()->isTextNode() && !inRenderedText())
718 if (pos
.node()->isTextNode() && !pos
.inRenderedText())
721 long thisRenderedOffset
= renderedOffset();
722 long posRenderedOffset
= pos
.renderedOffset();
724 if (renderer
== posRenderer
&& thisRenderedOffset
== posRenderedOffset
)
727 kDebug(6200) << "onDifferentLine:" << (renderersOnDifferentLine(renderer
, offset(), posRenderer
, pos
.offset()) ? "YES" : "NO");
728 kDebug(6200) << "renderer:" << renderer
<< "[" << (renderer
? renderer
->inlineBox(offset()) : 0) << "]";
729 kDebug(6200) << "thisRenderedOffset:" << thisRenderedOffset
;
730 kDebug(6200) << "posRenderer:" << posRenderer
<< "[" << (posRenderer
? posRenderer
->inlineBox(offset()) : 0) << "]";
731 kDebug(6200) << "posRenderedOffset:"<< posRenderedOffset
;
732 kDebug(6200) << "node min/max:"<< node()->caretMinOffset() << "/" << node()->caretMaxRenderedOffset();
733 kDebug(6200) << "pos node min/max:"<< pos
.node()->caretMinOffset() << "/" << pos
.node()->caretMaxRenderedOffset();
734 kDebug(6200) << "----------------------------------------------------------------------";
736 InlineBox
*b1
= renderer
? renderer
->inlineBox(offset()) : 0;
737 InlineBox
*b2
= posRenderer
? posRenderer
->inlineBox(pos
.offset()) : 0;
743 if (b1
->root() != b2
->root()) {
747 if (nextRenderedEditable(node()) == pos
.node() &&
748 thisRenderedOffset
== (long)node()->caretMaxRenderedOffset() && posRenderedOffset
== 0) {
752 if (previousRenderedEditable(node()) == pos
.node() &&
753 thisRenderedOffset
== 0 && posRenderedOffset
== (long)pos
.node()->caretMaxRenderedOffset()) {
760 bool Position::isFirstRenderedPositionOnLine() const
765 RenderObject
*renderer
= node()->renderer();
769 if (renderer
->style()->visibility() != khtml::VISIBLE
)
772 Position
pos(node(), offset());
773 PositionIterator
it(pos
);
774 while (!it
.atStart()) {
776 if (it
.current().inRenderedContent())
777 return renderersOnDifferentLine(renderer
, offset(), it
.current().node()->renderer(), it
.current().offset());
783 bool Position::isLastRenderedPositionOnLine() const
788 RenderObject
*renderer
= node()->renderer();
792 if (renderer
->style()->visibility() != khtml::VISIBLE
)
795 if (node()->id() == ID_BR
)
798 Position
pos(node(), offset());
799 PositionIterator
it(pos
);
800 while (!it
.atEnd()) {
802 if (it
.current().inRenderedContent())
803 return renderersOnDifferentLine(renderer
, offset(), it
.current().node()->renderer(), it
.current().offset());
809 bool Position::isLastRenderedPositionInEditableBlock() const
814 RenderObject
*renderer
= node()->renderer();
818 if (renderer
->style()->visibility() != khtml::VISIBLE
)
821 if (renderedOffset() != (long)node()->caretMaxRenderedOffset())
824 Position
pos(node(), offset());
825 PositionIterator
it(pos
);
826 while (!it
.atEnd()) {
828 if (!it
.current().node()->inSameContainingBlockFlowElement(node()))
830 if (it
.current().inRenderedContent())
836 bool Position::inFirstEditableInRootEditableElement() const
838 if (isEmpty() || !inRenderedContent())
841 PositionIterator
it(*this);
842 while (!it
.atStart()) {
843 if (it
.previous().inRenderedContent())
850 bool Position::inLastEditableInRootEditableElement() const
852 if (isEmpty() || !inRenderedContent())
855 PositionIterator
it(*this);
856 while (!it
.atEnd()) {
857 if (it
.next().inRenderedContent())
864 bool Position::inFirstEditableInContainingEditableBlock() const
866 if (isEmpty() || !inRenderedContent())
869 NodeImpl
*block
= node()->enclosingBlockFlowElement();
871 PositionIterator
it(*this);
872 while (!it
.atStart()) {
874 if (!it
.current().inRenderedContent())
876 return block
!= it
.current().node()->enclosingBlockFlowElement();
882 bool Position::inLastEditableInContainingEditableBlock() const
884 if (isEmpty() || !inRenderedContent())
887 NodeImpl
*block
= node()->enclosingBlockFlowElement();
889 PositionIterator
it(*this);
890 while (!it
.atEnd()) {
892 if (!it
.current().inRenderedContent())
894 return block
!= it
.current().node()->enclosingBlockFlowElement();
900 void Position::debugPosition(const char *msg
) const
903 fprintf(stderr
, "Position [%s]: empty\n", msg
);
906 fprintf(stderr
, "Position [%s]: %s [%p] at %ld\n", msg
, getTagName(node()->id()).string().latin1(), node(), offset());
908 fprintf(stderr
, "Position [%s]: %s [%p] at %ld\n", msg
,
909 qPrintable(getPrintableName(node()->id())), (void*) node(), offset());