fix logic
[personal-kdelibs.git] / khtml / xml / dom_position.cpp
blob24b7fdcdd859eab2b24de0a85587e820127c3ca1
1 /*
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
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.
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"
43 #include <qstring.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;
53 namespace DOM {
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)
64 while (1) {
65 node = node->nextEditable();
66 if (!node)
67 return 0;
68 if (!node->renderer())
69 continue;
70 if (node->renderer()->inlineBox(0))
71 return node;
73 return 0;
76 static NodeImpl *previousRenderedEditable(NodeImpl *node)
78 while (1) {
79 node = node->previousEditable();
80 if (!node)
81 return 0;
82 if (!node->renderer())
83 continue;
84 if (node->renderer()->inlineBox(0))
85 return node;
87 return 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();
96 else
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)
111 if (node) {
112 m_node = node;
113 m_node->ref();
117 Position::Position(const Position &o)
118 : m_node(0), m_offset(o.offset())
120 if (o.node()) {
121 m_node = o.node();
122 m_node->ref();
126 Position::~Position() {
127 if (m_node) {
128 m_node->deref();
132 Position &Position::operator=(const Position &o)
134 if (m_node) {
135 m_node->deref();
137 m_node = o.node();
138 if (m_node) {
139 m_node->ref();
142 m_offset = o.offset();
144 return *this;
147 ElementImpl *Position::element() const
149 if (isEmpty())
150 return 0;
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())
161 return offset();
163 if (!node()->renderer())
164 return offset();
166 int result = 0;
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)
172 return result;
173 if (offset() <= end) {
174 result += offset() - start;
175 return result;
177 result += box->m_len;
179 return result;
182 Position Position::equivalentLeafPosition() const
184 if (isEmpty())
185 return Position();
187 if (!node()->renderer() || !node()->renderer()->firstChild())
188 return *this;
190 NodeImpl *n = node();
191 int count = 0;
192 while (1) {
193 n = n->nextLeafNode();
194 if (!n || !n->inSameContainingBlockFlowElement(node()))
195 return *this;
196 if (count + n->maxOffset() >= offset()) {
197 count = offset() - count;
198 break;
200 count += n->maxOffset();
202 return Position(n, count);
205 Position Position::previousRenderedEditablePosition() const
207 if (isEmpty())
208 return Position();
210 if ((node()->document()->part()->isCaretMode() || node()->isContentEditable()) && node()->hasChildNodes() == false && inRenderedContent())
211 return *this;
213 NodeImpl *n = node();
214 while (1) {
215 n = n->previousEditable();
216 if (!n)
217 return Position();
218 if (n->renderer() && n->renderer()->style()->visibility() == khtml::VISIBLE)
219 break;
222 return Position(n, 0);
225 Position Position::nextRenderedEditablePosition() const
227 if (isEmpty())
228 return Position();
230 if ((node()->document()->part()->isCaretMode() || node()->isContentEditable()) && node()->hasChildNodes() == false && inRenderedContent())
231 return *this;
233 NodeImpl *n = node();
234 while (1) {
235 n = n->nextEditable();
236 if (!n)
237 return Position();
238 if (n->renderer() && n->renderer()->style()->visibility() == khtml::VISIBLE)
239 break;
242 return Position(n, 0);
245 Position Position::previousCharacterPosition() const
247 if (isEmpty())
248 return Position();
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)
260 return *this;
262 if (atStartOfLine) {
263 if (pos.inRenderedContent())
264 return pos;
266 else if (rendersInDifferentPosition(pos))
267 return pos;
270 return *this;
273 Position Position::nextCharacterPosition() const
275 if (isEmpty())
276 return Position();
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)
287 return *this;
289 if (atEndOfLine) {
290 if (pos.inRenderedContent())
291 return pos;
293 else if (rendersInDifferentPosition(pos))
294 return pos;
297 return *this;
300 Position Position::previousWordPosition() const
302 if (isEmpty())
303 return Position();
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();
311 int start, end;
312 khtml::findWordBoundary(chars, len, it.current().offset(), &start, &end);
313 pos = Position(it.current().node(), start);
315 else {
316 pos = Position(it.current().node(), it.current().node()->caretMinOffset());
318 if (pos != *this)
319 return pos;
320 it.setPosition(pos);
323 return *this;
326 Position Position::nextWordPosition() const
328 if (isEmpty())
329 return Position();
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();
337 int start, end;
338 khtml::findWordBoundary(chars, len, it.current().offset(), &start, &end);
339 pos = Position(it.current().node(), end);
341 else {
342 pos = Position(it.current().node(), it.current().node()->caretMaxOffset());
344 if (pos != *this)
345 return pos;
346 it.setPosition(pos);
349 return *this;
352 Position Position::previousLinePosition(int x) const
354 if (!node())
355 return Position();
357 if (!node()->renderer())
358 return *this;
360 InlineBox *box = node()->renderer()->inlineBox(offset());
361 if (!box)
362 return *this;
364 RenderBlock *containingBlock = 0;
365 RootInlineBox *root = box->root()->prevRootBox();
366 if (root) {
367 containingBlock = node()->renderer()->containingBlock();
369 else {
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();
377 if (n) {
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());
383 assert(box);
384 // previous root line box found
385 root = box->root();
386 containingBlock = n->renderer()->containingBlock();
391 if (root) {
392 int absx, absy;
393 containingBlock->absolutePosition(absx, absy);
394 RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
395 return renderer->positionForCoordinates(x, absy + root->topOverflow());
398 return *this;
401 Position Position::nextLinePosition(int x) const
403 if (!node())
404 return Position();
406 if (!node()->renderer())
407 return *this;
409 InlineBox *box = node()->renderer()->inlineBox(offset());
410 if (!box)
411 return *this;
413 RenderBlock *containingBlock = 0;
414 RootInlineBox *root = box->root()->nextRootBox();
415 if (root) {
416 containingBlock = node()->renderer()->containingBlock();
418 else {
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();
426 if (n) {
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;
433 assert(box);
434 // previous root line box found
435 root = box->root();
436 containingBlock = n->renderer()->containingBlock();
441 if (root) {
442 int absx, absy;
443 containingBlock->absolutePosition(absx, absy);
444 RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
445 return renderer->positionForCoordinates(x, absy + root->topOverflow());
448 return *this;
451 Position Position::equivalentUpstreamPosition() const
453 if (!node())
454 return Position();
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)
462 return it.next();
464 RenderObject *renderer = it.current().node()->renderer();
465 if (!renderer)
466 continue;
468 if (renderer->style()->visibility() != khtml::VISIBLE)
469 continue;
471 if (renderer->isBlockFlow() || renderer->isReplaced() || renderer->isBR()) {
472 if (it.current().offset() >= renderer->caretMaxOffset())
473 return Position(it.current().node(), renderer->caretMaxOffset());
474 else
475 continue;
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)
483 continue;
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())
489 return it.current();
494 return it.current();
497 Position Position::equivalentDownstreamPosition() const
499 if (!node())
500 return Position();
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();
511 if (!renderer)
512 continue;
514 if (renderer->style()->visibility() != khtml::VISIBLE)
515 continue;
517 if (renderer->isBlockFlow() || renderer->isReplaced() || renderer->isBR()) {
518 if (it.current().offset() <= renderer->caretMinOffset())
519 return Position(it.current().node(), renderer->caretMinOffset());
520 else
521 continue;
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)
529 continue;
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())
535 return it.current();
540 return it.current();
543 Position Position::equivalentRangeCompliantPosition() const
545 if (isEmpty())
546 return *this;
548 if (!node()->parentNode())
549 return *this;
551 RenderObject *renderer = node()->renderer();
552 if (!renderer)
553 return *this;
555 if (!renderer->isReplaced() && !renderer->isBR())
556 return *this;
558 int o = 0;
559 const NodeImpl *n = node();
560 while ((n = n->previousSibling()))
561 o++;
563 return Position(node()->parentNode(), o + offset());
566 Position Position::equivalentShallowPosition() const
568 if (isEmpty())
569 return *this;
571 Position pos(*this);
572 while (pos.offset() == pos.node()->caretMinOffset() && pos.node()->parentNode() && pos.node() == pos.node()->parentNode()->firstChild())
573 pos = Position(pos.node()->parentNode(), 0);
574 return pos;
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
589 if (isEmpty())
590 return false;
592 RenderObject *renderer = node()->renderer();
593 if (!renderer || !(node()->document()->part()->isCaretMode() || renderer->isEditable()))
594 return false;
596 if (renderer->style()->visibility() != khtml::VISIBLE)
597 return false;
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) {
606 return true;
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.
612 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())
619 return false;
620 return true;
623 return false;
626 bool Position::inRenderedText() const
628 if (!node()->isTextNode())
629 return false;
631 RenderObject *renderer = node()->renderer();
632 if (!renderer)
633 return false;
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.
641 return false;
643 if (offset() >= box->m_start && offset() <= box->m_start + box->m_len)
644 return true;
647 return false;
650 bool Position::rendersOnSameLine(const Position &pos) const
652 if (isEmpty() || pos.isEmpty())
653 return false;
655 if (node() == pos.node() && offset() == pos.offset())
656 return true;
658 if (node()->enclosingBlockFlowElement() != pos.node()->enclosingBlockFlowElement())
659 return false;
661 RenderObject *renderer = node()->renderer();
662 if (!renderer)
663 return false;
665 RenderObject *posRenderer = pos.node()->renderer();
666 if (!posRenderer)
667 return false;
669 if (renderer->style()->visibility() != khtml::VISIBLE ||
670 posRenderer->style()->visibility() != khtml::VISIBLE)
671 return false;
673 return renderersOnDifferentLine(renderer, offset(), posRenderer, pos.offset());
676 bool Position::rendersInDifferentPosition(const Position &pos) const
678 if (isEmpty() || pos.isEmpty())
679 return false;
681 RenderObject *renderer = node()->renderer();
682 if (!renderer)
683 return false;
685 RenderObject *posRenderer = pos.node()->renderer();
686 if (!posRenderer)
687 return false;
689 if (renderer->style()->visibility() != khtml::VISIBLE ||
690 posRenderer->style()->visibility() != khtml::VISIBLE)
691 return false;
693 if (node() == pos.node()) {
694 if (node()->id() == ID_BR)
695 return false;
697 if (offset() == pos.offset())
698 return false;
700 if (!node()->isTextNode() && !pos.node()->isTextNode()) {
701 if (offset() != pos.offset())
702 return true;
706 if (node()->id() == ID_BR && pos.inRenderedContent())
707 return true;
709 if (pos.node()->id() == ID_BR && inRenderedContent())
710 return true;
712 if (node()->enclosingBlockFlowElement() != pos.node()->enclosingBlockFlowElement())
713 return true;
715 if (node()->isTextNode() && !inRenderedText())
716 return false;
718 if (pos.node()->isTextNode() && !pos.inRenderedText())
719 return false;
721 long thisRenderedOffset = renderedOffset();
722 long posRenderedOffset = pos.renderedOffset();
724 if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
725 return false;
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;
739 if (!b1 || !b2) {
740 return false;
743 if (b1->root() != b2->root()) {
744 return true;
747 if (nextRenderedEditable(node()) == pos.node() &&
748 thisRenderedOffset == (long)node()->caretMaxRenderedOffset() && posRenderedOffset == 0) {
749 return false;
752 if (previousRenderedEditable(node()) == pos.node() &&
753 thisRenderedOffset == 0 && posRenderedOffset == (long)pos.node()->caretMaxRenderedOffset()) {
754 return false;
757 return true;
760 bool Position::isFirstRenderedPositionOnLine() const
762 if (isEmpty())
763 return false;
765 RenderObject *renderer = node()->renderer();
766 if (!renderer)
767 return false;
769 if (renderer->style()->visibility() != khtml::VISIBLE)
770 return false;
772 Position pos(node(), offset());
773 PositionIterator it(pos);
774 while (!it.atStart()) {
775 it.previous();
776 if (it.current().inRenderedContent())
777 return renderersOnDifferentLine(renderer, offset(), it.current().node()->renderer(), it.current().offset());
780 return true;
783 bool Position::isLastRenderedPositionOnLine() const
785 if (isEmpty())
786 return false;
788 RenderObject *renderer = node()->renderer();
789 if (!renderer)
790 return false;
792 if (renderer->style()->visibility() != khtml::VISIBLE)
793 return false;
795 if (node()->id() == ID_BR)
796 return true;
798 Position pos(node(), offset());
799 PositionIterator it(pos);
800 while (!it.atEnd()) {
801 it.next();
802 if (it.current().inRenderedContent())
803 return renderersOnDifferentLine(renderer, offset(), it.current().node()->renderer(), it.current().offset());
806 return true;
809 bool Position::isLastRenderedPositionInEditableBlock() const
811 if (isEmpty())
812 return false;
814 RenderObject *renderer = node()->renderer();
815 if (!renderer)
816 return false;
818 if (renderer->style()->visibility() != khtml::VISIBLE)
819 return false;
821 if (renderedOffset() != (long)node()->caretMaxRenderedOffset())
822 return false;
824 Position pos(node(), offset());
825 PositionIterator it(pos);
826 while (!it.atEnd()) {
827 it.next();
828 if (!it.current().node()->inSameContainingBlockFlowElement(node()))
829 return true;
830 if (it.current().inRenderedContent())
831 return false;
833 return true;
836 bool Position::inFirstEditableInRootEditableElement() const
838 if (isEmpty() || !inRenderedContent())
839 return false;
841 PositionIterator it(*this);
842 while (!it.atStart()) {
843 if (it.previous().inRenderedContent())
844 return false;
847 return true;
850 bool Position::inLastEditableInRootEditableElement() const
852 if (isEmpty() || !inRenderedContent())
853 return false;
855 PositionIterator it(*this);
856 while (!it.atEnd()) {
857 if (it.next().inRenderedContent())
858 return false;
861 return true;
864 bool Position::inFirstEditableInContainingEditableBlock() const
866 if (isEmpty() || !inRenderedContent())
867 return false;
869 NodeImpl *block = node()->enclosingBlockFlowElement();
871 PositionIterator it(*this);
872 while (!it.atStart()) {
873 it.previous();
874 if (!it.current().inRenderedContent())
875 continue;
876 return block != it.current().node()->enclosingBlockFlowElement();
879 return true;
882 bool Position::inLastEditableInContainingEditableBlock() const
884 if (isEmpty() || !inRenderedContent())
885 return false;
887 NodeImpl *block = node()->enclosingBlockFlowElement();
889 PositionIterator it(*this);
890 while (!it.atEnd()) {
891 it.next();
892 if (!it.current().inRenderedContent())
893 continue;
894 return block != it.current().node()->enclosingBlockFlowElement();
897 return true;
900 void Position::debugPosition(const char *msg) const
902 if (isEmpty())
903 fprintf(stderr, "Position [%s]: empty\n", msg);
904 else
905 #ifdef APPLE_CHANGES
906 fprintf(stderr, "Position [%s]: %s [%p] at %ld\n", msg, getTagName(node()->id()).string().latin1(), node(), offset());
907 #else
908 fprintf(stderr, "Position [%s]: %s [%p] at %ld\n", msg,
909 qPrintable(getPrintableName(node()->id())), (void*) node(), offset());
910 #endif
913 } // namespace DOM