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"
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_viewsimpl.h"
39 #include "text_affinity.h"
40 #include "visible_position.h"
41 #include "rendering/render_block.h"
42 #include "rendering/render_flow.h"
43 #include "rendering/render_line.h"
44 #include "rendering/render_style.h"
45 #include "rendering/render_text.h"
48 #include "KWQAssertions.h"
49 #include "KWQLogging.h"
51 #define ASSERT(assertion) assert(assertion)
52 #define LOG(channel, formatAndArgs...) ((void)0)
55 using khtml::EAffinity;
56 using khtml::InlineBox;
57 using khtml::InlineTextBox;
58 using khtml::RenderBlock;
59 using khtml::RenderFlow;
60 using khtml::RenderObject;
61 using khtml::RenderText;
62 using khtml::RootInlineBox;
64 using khtml::VisiblePosition;
68 static NodeImpl *nextRenderedEditable(NodeImpl *node)
71 node = node->nextEditable();
74 if (!node->renderer())
76 if (node->renderer()->inlineBox(0))
82 static NodeImpl *previousRenderedEditable(NodeImpl *node)
85 node = node->previousEditable();
88 if (!node->renderer())
90 if (node->renderer()->inlineBox(0))
97 Position::Position(NodeImpl *node, long offset)
98 : m_node(node), m_offset(offset)
105 Position::Position(const Position &o)
106 : m_node(o.m_node), m_offset(o.m_offset)
113 Position::~Position()
120 Position &Position::operator=(const Position &o)
130 m_offset = o.m_offset;
135 void Position::clear()
144 ElementImpl *Position::element() const
147 for (n = node(); n && !n->isElementNode(); n = n->parentNode())
149 return static_cast<ElementImpl *>(n);
152 CSSComputedStyleDeclarationImpl *Position::computedStyle() const
154 ElementImpl *elem = element();
157 return new CSSComputedStyleDeclarationImpl(elem);
160 long Position::renderedOffset() const
162 if (!node()->isTextNode())
165 if (!node()->renderer())
169 RenderText *textRenderer = static_cast<RenderText *>(node()->renderer());
170 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
171 long start = box->m_start;
172 long end = box->m_start + box->m_len;
173 if (offset() < start)
175 if (offset() <= end) {
176 result += offset() - start;
179 result += box->m_len;
184 Position Position::previousCharacterPosition() const
189 NodeImpl *fromRootEditableElement = node()->rootEditableElement();
190 PositionIterator it(*this);
192 bool atStartOfLine = isFirstVisiblePositionOnLine(VisiblePosition(*this));
193 bool rendered = inRenderedContent();
195 while (!it.atStart()) {
196 Position pos = it.previous();
198 if (pos.node()->rootEditableElement() != fromRootEditableElement)
201 if (atStartOfLine || !rendered) {
202 if (pos.inRenderedContent())
205 else if (rendersInDifferentPosition(pos))
212 Position Position::nextCharacterPosition() const
217 NodeImpl *fromRootEditableElement = node()->rootEditableElement();
218 PositionIterator it(*this);
220 bool atEndOfLine = isLastVisiblePositionOnLine(VisiblePosition(*this));
221 bool rendered = inRenderedContent();
223 while (!it.atEnd()) {
224 Position pos = it.next();
226 if (pos.node()->rootEditableElement() != fromRootEditableElement)
229 if (atEndOfLine || !rendered) {
230 if (pos.inRenderedContent())
233 else if (rendersInDifferentPosition(pos))
240 Position Position::previousLinePosition(int x, EAffinity affinity) const
245 if (!node()->renderer())
248 RenderBlock *containingBlock = 0;
249 RootInlineBox *root = 0;
250 InlineBox *box = node()->renderer()->inlineBox(offset(), affinity);
252 root = box->root()->prevRootBox();
254 containingBlock = node()->renderer()->containingBlock();
258 // This containing editable block does not have a previous line.
259 // Need to move back to previous containing editable block in this root editable
260 // block and find the last root line box in that block.
261 NodeImpl *startBlock = node()->enclosingBlockFlowElement();
262 NodeImpl *n = node()->previousEditable();
263 while (n && startBlock == n->enclosingBlockFlowElement())
264 n = n->previousEditable();
266 if (!n->inSameRootEditableElement(node()))
268 Position pos(n, n->caretMinOffset());
269 if (pos.inRenderedContent()) {
270 ASSERT(n->renderer());
271 box = n->renderer()->inlineBox(n->caretMaxOffset());
273 // previous root line box found
275 containingBlock = n->renderer()->containingBlock();
282 n = n->previousEditable();
288 containingBlock->absolutePosition(absx, absy);
289 RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
290 return renderer->positionForCoordinates(x, absy + root->topOverflow());
293 // Could not find a previous line. This means we must already be on the first line.
294 // Move to the start of the content in this block, which effectively moves us
295 // to the start of the line we're on.
296 return Position(node()->rootEditableElement(), 0);
299 Position Position::nextLinePosition(int x, EAffinity affinity) const
304 if (!node()->renderer())
307 RenderBlock *containingBlock = 0;
308 RootInlineBox *root = 0;
309 InlineBox *box = node()->renderer()->inlineBox(offset(), affinity);
311 root = box->root()->nextRootBox();
313 containingBlock = node()->renderer()->containingBlock();
317 // This containing editable block does not have a next line.
318 // Need to move forward to next containing editable block in this root editable
319 // block and find the first root line box in that block.
320 NodeImpl *startBlock = node()->enclosingBlockFlowElement();
321 NodeImpl *n = node()->nextEditable();
322 while (n && startBlock == n->enclosingBlockFlowElement())
323 n = n->nextEditable();
325 if (!n->inSameRootEditableElement(node()))
327 Position pos(n, n->caretMinOffset());
328 if (pos.inRenderedContent()) {
329 ASSERT(n->renderer());
330 box = n->renderer()->inlineBox(n->caretMinOffset());
332 // next root line box found
334 containingBlock = n->renderer()->containingBlock();
341 n = n->nextEditable();
347 containingBlock->absolutePosition(absx, absy);
348 RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
349 return renderer->positionForCoordinates(x, absy + root->topOverflow());
352 // Could not find a next line. This means we must already be on the last line.
353 // Move to the end of the content in this block, which effectively moves us
354 // to the end of the line we're on.
355 ElementImpl *rootElement = node()->rootEditableElement();
356 return Position(rootElement, rootElement ? rootElement->childNodeCount() : 0);
359 Position Position::upstream(EStayInBlock stayInBlock) const
361 Position start = equivalentDeepPosition();
362 NodeImpl *startNode = start.node();
366 NodeImpl *block = startNode->enclosingBlockFlowElement();
368 PositionIterator it(start);
369 for (; !it.atStart(); it.previous()) {
370 NodeImpl *currentNode = it.current().node();
373 NodeImpl *currentBlock = currentNode->enclosingBlockFlowElement();
374 if (block != currentBlock)
378 RenderObject *renderer = currentNode->renderer();
382 if (renderer->style()->visibility() != VISIBLE)
385 if (renderer->isReplaced() || renderer->isBR()) {
386 if (it.current().offset() >= renderer->caretMaxOffset())
387 return Position(currentNode, renderer->caretMaxOffset());
392 if (renderer->isText() && static_cast<RenderText *>(renderer)->firstTextBox()) {
393 if (currentNode != startNode)
394 return Position(currentNode, renderer->caretMaxOffset());
396 if (it.current().offset() < 0)
398 uint textOffset = it.current().offset();
400 RenderText *textRenderer = static_cast<RenderText *>(renderer);
401 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
402 if (textOffset > box->start() && textOffset <= box->start() + box->len())
404 else if (box != textRenderer->lastTextBox() &&
405 !box->nextOnLine() &&
406 textOffset == box->start() + box->len() + 1)
415 Position Position::downstream(EStayInBlock stayInBlock) const
417 Position start = equivalentDeepPosition();
418 NodeImpl *startNode = start.node();
422 NodeImpl *block = startNode->enclosingBlockFlowElement();
424 PositionIterator it(start);
425 for (; !it.atEnd(); it.next()) {
426 NodeImpl *currentNode = it.current().node();
429 NodeImpl *currentBlock = currentNode->enclosingBlockFlowElement();
430 if (block != currentBlock)
431 return it.previous();
434 RenderObject *renderer = currentNode->renderer();
438 if (renderer->style()->visibility() != VISIBLE)
441 if (currentNode != startNode && renderer->isBlockFlow()) {
442 if (it.current().offset() == 0) {
443 // If no first child, or first visible child is a not a block, return; otherwise continue.
444 if (!currentNode->firstChild())
445 return Position(currentNode, 0);
446 for (NodeImpl *child = currentNode->firstChild(); child; child = child->nextSibling()) {
447 RenderObject *r = child->renderer();
448 if (r && r->style()->visibility() == VISIBLE) {
449 if (r->isBlockFlow())
450 break; // break causes continue code below to run.
452 return Position(child, 0);
459 if (renderer->isReplaced() || renderer->isBR()) {
460 if (it.current().offset() <= renderer->caretMinOffset())
461 return Position(currentNode, renderer->caretMinOffset());
466 if (renderer->isText() && static_cast<RenderText *>(renderer)->firstTextBox()) {
467 if (currentNode != node())
468 return Position(currentNode, renderer->caretMinOffset());
470 if (it.current().offset() < 0)
472 uint textOffset = it.current().offset();
474 RenderText *textRenderer = static_cast<RenderText *>(renderer);
475 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
476 if (textOffset >= box->start() && textOffset <= box->end())
478 else if (box != textRenderer->lastTextBox() &&
479 !box->nextOnLine() &&
480 textOffset == box->start() + box->len())
489 Position Position::equivalentRangeCompliantPosition() const
494 // Make sure that 0 <= constrainedOffset <= num kids, otherwise using this Position
495 // in DOM calls can result in exceptions.
496 long maxOffset = node()->isTextNode() ? static_cast<TextImpl *>(node())->length(): node()->childNodeCount();
497 long constrainedOffset = offset() <= 0 ? 0 : kMin(maxOffset, offset());
499 if (!node()->parentNode())
500 return Position(node(), constrainedOffset);
502 RenderObject *renderer = node()->renderer();
504 return Position(node(), constrainedOffset);
506 if (!renderer->isReplaced() && !renderer->isBR())
507 return Position(node(), constrainedOffset);
510 const NodeImpl *n = node();
511 while ((n = n->previousSibling()))
514 // Make sure that 0 <= constrainedOffset <= num kids, as above.
515 NodeImpl *parent = node()->parentNode();
516 maxOffset = parent->isTextNode() ? static_cast<TextImpl *>(parent)->length(): parent->childNodeCount();
517 constrainedOffset = o <= 0 ? 0 : kMin(maxOffset, o);
518 return Position(parent, constrainedOffset);
521 Position Position::equivalentDeepPosition() const
523 if (isNull() || node()->isAtomicNode())
528 if (offset() >= (int)node()->childNodeCount()) {
529 child = node()->lastChild();
530 pos = Position(child, child->caretMaxOffset());
532 while (!child->isAtomicNode() && pos.node()->hasChildNodes()) {
533 child = pos.node()->lastChild();
535 pos = Position(child, child->caretMaxOffset());
539 child = node()->childNode(offset());
541 pos = Position(child, 0);
542 while (!child->isAtomicNode() && pos.node()->hasChildNodes()) {
543 child = pos.node()->firstChild();
545 pos = Position(child, 0);
551 bool Position::inRenderedContent() const
556 RenderObject *renderer = node()->renderer();
560 if (renderer->style()->visibility() != VISIBLE)
563 // FIXME: This check returns false for a <br> at the end of a line!
564 if (renderer->isBR() && static_cast<RenderText *>(renderer)->firstTextBox()) {
565 return offset() == 0;
567 else if (renderer->isText()) {
568 RenderText *textRenderer = static_cast<RenderText *>(renderer);
569 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
570 if (offset() >= box->m_start && offset() <= box->m_start + box->m_len) {
573 else if (offset() < box->m_start) {
574 // The offset we're looking for is before this node
575 // this means the offset must be in content that is
576 // not rendered. Return false.
581 else if (offset() >= renderer->caretMinOffset() && offset() <= renderer->caretMaxOffset()) {
582 // return true for replaced elements, for inline flows if they have a line box
583 // and for blocks if they are empty
584 if (renderer->isReplaced() ||
585 (renderer->isInlineFlow() && static_cast<RenderFlow *>(renderer)->firstLineBox()) ||
586 (renderer->isBlockFlow() && !renderer->firstChild() && renderer->height()))
593 bool Position::inRenderedText() const
595 if (isNull() || !node()->isTextNode())
598 RenderObject *renderer = node()->renderer();
602 RenderText *textRenderer = static_cast<RenderText *>(renderer);
603 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
604 if (offset() < box->m_start) {
605 // The offset we're looking for is before this node
606 // this means the offset must be in content that is
607 // not rendered. Return false.
610 if (offset() >= box->m_start && offset() <= box->m_start + box->m_len)
617 bool Position::isRenderedCharacter() const
619 if (isNull() || !node()->isTextNode())
622 RenderObject *renderer = node()->renderer();
626 RenderText *textRenderer = static_cast<RenderText *>(renderer);
627 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
628 if (offset() < box->m_start) {
629 // The offset we're looking for is before this node
630 // this means the offset must be in content that is
631 // not rendered. Return false.
634 if (offset() >= box->m_start && offset() < box->m_start + box->m_len)
641 bool Position::rendersInDifferentPosition(const Position &pos) const
643 if (isNull() || pos.isNull())
646 RenderObject *renderer = node()->renderer();
650 RenderObject *posRenderer = pos.node()->renderer();
654 if (renderer->style()->visibility() != VISIBLE ||
655 posRenderer->style()->visibility() != VISIBLE)
658 if (node() == pos.node()) {
659 if (node()->id() == ID_BR)
662 if (offset() == pos.offset())
665 if (!node()->isTextNode() && !pos.node()->isTextNode()) {
666 if (offset() != pos.offset())
671 if (node()->id() == ID_BR && pos.inRenderedContent())
674 if (pos.node()->id() == ID_BR && inRenderedContent())
677 if (node()->enclosingBlockFlowElement() != pos.node()->enclosingBlockFlowElement())
680 if (node()->isTextNode() && !inRenderedText())
683 if (pos.node()->isTextNode() && !pos.inRenderedText())
686 long thisRenderedOffset = renderedOffset();
687 long posRenderedOffset = pos.renderedOffset();
689 if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
692 LOG(Editing, "renderer: %p [%p]\n", renderer, renderer ? renderer->inlineBox(offset()) : 0);
693 LOG(Editing, "thisRenderedOffset: %d\n", thisRenderedOffset);
694 LOG(Editing, "posRenderer: %p [%p]\n", posRenderer, posRenderer ? posRenderer->inlineBox(offset()) : 0);
695 LOG(Editing, "posRenderedOffset: %d\n", posRenderedOffset);
696 LOG(Editing, "node min/max: %d:%d\n", node()->caretMinOffset(), node()->caretMaxRenderedOffset());
697 LOG(Editing, "pos node min/max: %d:%d\n", pos.node()->caretMinOffset(), pos.node()->caretMaxRenderedOffset());
698 LOG(Editing, "----------------------------------------------------------------------\n");
700 InlineBox *b1 = renderer ? renderer->inlineBox(offset()) : 0;
701 InlineBox *b2 = posRenderer ? posRenderer->inlineBox(pos.offset()) : 0;
707 if (b1->root() != b2->root()) {
711 if (nextRenderedEditable(node()) == pos.node() &&
712 thisRenderedOffset == (long)node()->caretMaxRenderedOffset() && posRenderedOffset == 0) {
716 if (previousRenderedEditable(node()) == pos.node() &&
717 thisRenderedOffset == 0 && posRenderedOffset == (long)pos.node()->caretMaxRenderedOffset()) {
724 static inline bool isWS(const QChar &c)
726 const char nonBreakingSpace = 0xA0;
727 return c.isSpace() && c != nonBreakingSpace;
730 Position Position::leadingWhitespacePosition() const
735 if (upstream(StayInBlock).node()->id() == ID_BR)
738 Position prev = previousCharacterPosition();
739 if (prev != *this && prev.node()->inSameContainingBlockFlowElement(node()) && prev.node()->isTextNode()) {
740 DOMString string = static_cast<TextImpl *>(prev.node())->data();
741 if (isWS(string[prev.offset()]))
748 Position Position::trailingWhitespacePosition() const
753 if (node()->isTextNode()) {
754 TextImpl *textNode = static_cast<TextImpl *>(node());
755 if (offset() < (long)textNode->length()) {
756 DOMString string = static_cast<TextImpl *>(node())->data();
757 if (isWS(string[offset()]))
763 if (downstream(StayInBlock).node()->id() == ID_BR)
766 Position next = nextCharacterPosition();
767 if (next != *this && next.node()->inSameContainingBlockFlowElement(node()) && next.node()->isTextNode()) {
768 DOMString string = static_cast<TextImpl *>(next.node())->data();
776 void Position::debugPosition(const char *msg) const
779 fprintf(stderr, "Position [%s]: null\n", msg);
781 fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, getTagName(node()->id()).string().latin1(), node(), offset());
785 #define FormatBufferSize 1024
786 void Position::formatForDebugger(char *buffer, unsigned length) const
795 char s[FormatBufferSize];
797 result += QString::number(m_offset);
799 m_node->formatForDebugger(s, FormatBufferSize);
803 strncpy(buffer, result.string().latin1(), length - 1);
805 #undef FormatBufferSize
809 Position startPosition(const Range &r)
811 return Position(r.startContainer().handle(), r.startOffset());
814 Position endPosition(const Range &r)
816 return Position(r.endContainer().handle(), r.endOffset());