2 * (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2000 Gunnstein Lye (gunnstein@netcom.no)
4 * (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
5 * (C) 2001 Peter Kelly (pmk@post.com)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
26 #include "RangeException.h"
30 #include "DocumentFragment.h"
31 #include "ExceptionCode.h"
32 #include "HTMLElement.h"
33 #include "HTMLNames.h"
34 #include "NodeWithIndex.h"
35 #include "ProcessingInstruction.h"
36 #include "RenderBlock.h"
38 #include "TextIterator.h"
40 #include "visible_units.h"
42 #include <wtf/RefCountedLeakCounter.h>
47 using namespace HTMLNames
;
50 static WTF::RefCountedLeakCounter
rangeCounter("Range");
53 inline Range::Range(PassRefPtr
<Document
> ownerDocument
)
54 : m_ownerDocument(ownerDocument
)
55 , m_start(m_ownerDocument
)
56 , m_end(m_ownerDocument
)
59 rangeCounter
.increment();
62 m_ownerDocument
->attachRange(this);
65 PassRefPtr
<Range
> Range::create(PassRefPtr
<Document
> ownerDocument
)
67 return adoptRef(new Range(ownerDocument
));
70 inline Range::Range(PassRefPtr
<Document
> ownerDocument
, PassRefPtr
<Node
> startContainer
, int startOffset
, PassRefPtr
<Node
> endContainer
, int endOffset
)
71 : m_ownerDocument(ownerDocument
)
72 , m_start(m_ownerDocument
)
73 , m_end(m_ownerDocument
)
76 rangeCounter
.increment();
79 m_ownerDocument
->attachRange(this);
81 // Simply setting the containers and offsets directly would not do any of the checking
82 // that setStart and setEnd do, so we call those functions.
84 setStart(startContainer
, startOffset
, ec
);
86 setEnd(endContainer
, endOffset
, ec
);
90 PassRefPtr
<Range
> Range::create(PassRefPtr
<Document
> ownerDocument
, PassRefPtr
<Node
> startContainer
, int startOffset
, PassRefPtr
<Node
> endContainer
, int endOffset
)
92 return adoptRef(new Range(ownerDocument
, startContainer
, startOffset
, endContainer
, endOffset
));
95 PassRefPtr
<Range
> Range::create(PassRefPtr
<Document
> ownerDocument
, const Position
& start
, const Position
& end
)
97 return adoptRef(new Range(ownerDocument
, start
.container
.get(), start
.posOffset
, end
.container
.get(), end
.posOffset
));
102 if (m_start
.container())
103 m_ownerDocument
->detachRange(this);
106 rangeCounter
.decrement();
110 Node
* Range::startContainer(ExceptionCode
& ec
) const
112 if (!m_start
.container()) {
113 ec
= INVALID_STATE_ERR
;
117 return m_start
.container();
120 int Range::startOffset(ExceptionCode
& ec
) const
122 if (!m_start
.container()) {
123 ec
= INVALID_STATE_ERR
;
127 return m_start
.offset();
130 Node
* Range::endContainer(ExceptionCode
& ec
) const
132 if (!m_start
.container()) {
133 ec
= INVALID_STATE_ERR
;
137 return m_end
.container();
140 int Range::endOffset(ExceptionCode
& ec
) const
142 if (!m_start
.container()) {
143 ec
= INVALID_STATE_ERR
;
147 return m_end
.offset();
150 Node
* Range::commonAncestorContainer(ExceptionCode
& ec
) const
152 if (!m_start
.container()) {
153 ec
= INVALID_STATE_ERR
;
157 return commonAncestorContainer(m_start
.container(), m_end
.container());
160 Node
* Range::commonAncestorContainer(Node
* containerA
, Node
* containerB
)
162 for (Node
* parentA
= containerA
; parentA
; parentA
= parentA
->parentNode()) {
163 for (Node
* parentB
= containerB
; parentB
; parentB
= parentB
->parentNode()) {
164 if (parentA
== parentB
)
171 bool Range::collapsed(ExceptionCode
& ec
) const
173 if (!m_start
.container()) {
174 ec
= INVALID_STATE_ERR
;
178 return m_start
== m_end
;
181 void Range::setStart(PassRefPtr
<Node
> refNode
, int offset
, ExceptionCode
& ec
)
183 if (!m_start
.container()) {
184 ec
= INVALID_STATE_ERR
;
193 if (refNode
->document() != m_ownerDocument
) {
194 ec
= WRONG_DOCUMENT_ERR
;
199 Node
* childNode
= checkNodeWOffset(refNode
.get(), offset
, ec
);
203 m_start
.set(refNode
, offset
, childNode
);
205 // check if different root container
206 Node
* endRootContainer
= m_end
.container();
207 while (endRootContainer
->parentNode())
208 endRootContainer
= endRootContainer
->parentNode();
209 Node
* startRootContainer
= m_start
.container();
210 while (startRootContainer
->parentNode())
211 startRootContainer
= startRootContainer
->parentNode();
212 if (startRootContainer
!= endRootContainer
)
214 // check if new start after end
215 else if (compareBoundaryPoints(m_start
.container(), m_start
.offset(), m_end
.container(), m_end
.offset()) > 0)
219 void Range::setEnd(PassRefPtr
<Node
> refNode
, int offset
, ExceptionCode
& ec
)
221 if (!m_start
.container()) {
222 ec
= INVALID_STATE_ERR
;
231 if (refNode
->document() != m_ownerDocument
) {
232 ec
= WRONG_DOCUMENT_ERR
;
237 Node
* childNode
= checkNodeWOffset(refNode
.get(), offset
, ec
);
241 m_end
.set(refNode
, offset
, childNode
);
243 // check if different root container
244 Node
* endRootContainer
= m_end
.container();
245 while (endRootContainer
->parentNode())
246 endRootContainer
= endRootContainer
->parentNode();
247 Node
* startRootContainer
= m_start
.container();
248 while (startRootContainer
->parentNode())
249 startRootContainer
= startRootContainer
->parentNode();
250 if (startRootContainer
!= endRootContainer
)
252 // check if new end before start
253 if (compareBoundaryPoints(m_start
.container(), m_start
.offset(), m_end
.container(), m_end
.offset()) > 0)
257 void Range::collapse(bool toStart
, ExceptionCode
& ec
)
259 if (!m_start
.container()) {
260 ec
= INVALID_STATE_ERR
;
270 bool Range::isPointInRange(Node
* refNode
, int offset
, ExceptionCode
& ec
)
277 if (!m_start
.container() && refNode
->attached()) {
278 ec
= INVALID_STATE_ERR
;
282 if (m_start
.container() && !refNode
->attached()) {
283 // Firefox doesn't throw an exception for this case; it returns false.
287 if (refNode
->document() != m_ownerDocument
) {
288 ec
= WRONG_DOCUMENT_ERR
;
293 checkNodeWOffset(refNode
, offset
, ec
);
297 return compareBoundaryPoints(refNode
, offset
, m_start
.container(), m_start
.offset()) >= 0
298 && compareBoundaryPoints(refNode
, offset
, m_end
.container(), m_end
.offset()) <= 0;
301 short Range::comparePoint(Node
* refNode
, int offset
, ExceptionCode
& ec
)
303 // http://developer.mozilla.org/en/docs/DOM:range.comparePoint
304 // This method returns -1, 0 or 1 depending on if the point described by the
305 // refNode node and an offset within the node is before, same as, or after the range respectively.
312 if (!m_start
.container() && refNode
->attached()) {
313 ec
= INVALID_STATE_ERR
;
317 if (m_start
.container() && !refNode
->attached()) {
318 // Firefox doesn't throw an exception for this case; it returns -1.
322 if (refNode
->document() != m_ownerDocument
) {
323 ec
= WRONG_DOCUMENT_ERR
;
328 checkNodeWOffset(refNode
, offset
, ec
);
332 // compare to start, and point comes before
333 if (compareBoundaryPoints(refNode
, offset
, m_start
.container(), m_start
.offset()) < 0)
336 // compare to end, and point comes after
337 if (compareBoundaryPoints(refNode
, offset
, m_end
.container(), m_end
.offset()) > 0)
340 // point is in the middle of this range, or on the boundary points
344 Range::CompareResults
Range::compareNode(Node
* refNode
, ExceptionCode
& ec
)
346 // http://developer.mozilla.org/en/docs/DOM:range.compareNode
347 // This method returns 0, 1, 2, or 3 based on if the node is before, after,
348 // before and after(surrounds), or inside the range, respectively
355 if (!m_start
.container() && refNode
->attached()) {
356 ec
= INVALID_STATE_ERR
;
360 if (m_start
.container() && !refNode
->attached()) {
361 // Firefox doesn't throw an exception for this case; it returns 0.
365 if (refNode
->document() != m_ownerDocument
) {
366 // Firefox doesn't throw an exception for this case; it returns 0.
370 Node
* parentNode
= refNode
->parentNode();
371 int nodeIndex
= refNode
->nodeIndex();
374 // if the node is the top document we should return NODE_BEFORE_AND_AFTER
375 // but we throw to match firefox behavior
380 if (comparePoint(parentNode
, nodeIndex
, ec
) < 0) { // starts before
381 if (comparePoint(parentNode
, nodeIndex
+ 1, ec
) > 0) // ends after the range
382 return NODE_BEFORE_AND_AFTER
;
383 return NODE_BEFORE
; // ends before or in the range
384 } else { // starts at or after the range start
385 if (comparePoint(parentNode
, nodeIndex
+ 1, ec
) > 0) // ends after the range
387 return NODE_INSIDE
; // ends inside the range
392 short Range::compareBoundaryPoints(CompareHow how
, const Range
* sourceRange
, ExceptionCode
& ec
) const
394 if (!m_start
.container()) {
395 ec
= INVALID_STATE_ERR
;
405 Node
* thisCont
= commonAncestorContainer(ec
);
408 Node
* sourceCont
= sourceRange
->commonAncestorContainer(ec
);
412 if (thisCont
->document() != sourceCont
->document()) {
413 ec
= WRONG_DOCUMENT_ERR
;
417 Node
* thisTop
= thisCont
;
418 Node
* sourceTop
= sourceCont
;
419 while (thisTop
->parentNode())
420 thisTop
= thisTop
->parentNode();
421 while (sourceTop
->parentNode())
422 sourceTop
= sourceTop
->parentNode();
423 if (thisTop
!= sourceTop
) { // in different DocumentFragments
424 ec
= WRONG_DOCUMENT_ERR
;
430 return compareBoundaryPoints(m_start
.container(), m_start
.offset(),
431 sourceRange
->m_start
.container(), sourceRange
->m_start
.offset());
433 return compareBoundaryPoints(m_end
.container(), m_end
.offset(),
434 sourceRange
->m_start
.container(), sourceRange
->m_start
.offset());
436 return compareBoundaryPoints(m_end
.container(), m_end
.offset(),
437 sourceRange
->m_end
.container(), sourceRange
->m_end
.offset());
439 return compareBoundaryPoints(m_start
.container(), m_start
.offset(),
440 sourceRange
->m_end
.container(), sourceRange
->m_end
.offset());
447 short Range::compareBoundaryPoints(Node
* containerA
, int offsetA
, Node
* containerB
, int offsetB
)
449 ASSERT(containerA
&& containerB
);
454 // see DOM2 traversal & range section 2.5
456 // case 1: both points have the same container
457 if (containerA
== containerB
) {
458 if (offsetA
== offsetB
)
459 return 0; // A is equal to B
460 if (offsetA
< offsetB
)
461 return -1; // A is before B
463 return 1; // A is after B
466 // case 2: node C (container B or an ancestor) is a child node of A
467 Node
* c
= containerB
;
468 while (c
&& c
->parentNode() != containerA
)
472 Node
* n
= containerA
->firstChild();
473 while (n
!= c
&& offsetC
< offsetA
) {
475 n
= n
->nextSibling();
478 if (offsetA
<= offsetC
)
479 return -1; // A is before B
481 return 1; // A is after B
484 // case 3: node C (container A or an ancestor) is a child node of B
486 while (c
&& c
->parentNode() != containerB
)
490 Node
* n
= containerB
->firstChild();
491 while (n
!= c
&& offsetC
< offsetB
) {
493 n
= n
->nextSibling();
496 if (offsetC
< offsetB
)
497 return -1; // A is before B
499 return 1; // A is after B
502 // case 4: containers A & B are siblings, or children of siblings
503 // ### we need to do a traversal here instead
504 Node
* commonAncestor
= commonAncestorContainer(containerA
, containerB
);
507 Node
* childA
= containerA
;
508 while (childA
&& childA
->parentNode() != commonAncestor
)
509 childA
= childA
->parentNode();
511 childA
= commonAncestor
;
512 Node
* childB
= containerB
;
513 while (childB
&& childB
->parentNode() != commonAncestor
)
514 childB
= childB
->parentNode();
516 childB
= commonAncestor
;
518 if (childA
== childB
)
519 return 0; // A is equal to B
521 Node
* n
= commonAncestor
->firstChild();
524 return -1; // A is before B
526 return 1; // A is after B
527 n
= n
->nextSibling();
530 // Should never reach this point.
531 ASSERT_NOT_REACHED();
535 short Range::compareBoundaryPoints(const Position
& a
, const Position
& b
)
537 return compareBoundaryPoints(a
.container
.get(), a
.posOffset
, b
.container
.get(), b
.posOffset
);
540 bool Range::boundaryPointsValid() const
542 return m_start
.container() && compareBoundaryPoints(m_start
.container(), m_start
.offset(), m_end
.container(), m_end
.offset()) <= 0;
545 void Range::deleteContents(ExceptionCode
& ec
)
547 checkDeleteExtract(ec
);
551 processContents(DELETE_CONTENTS
, ec
);
554 bool Range::intersectsNode(Node
* refNode
, ExceptionCode
& ec
)
556 // http://developer.mozilla.org/en/docs/DOM:range.intersectsNode
557 // Returns a bool if the node intersects the range.
564 if (!m_start
.container() && refNode
->attached()
565 || m_start
.container() && !refNode
->attached()
566 || refNode
->document() != m_ownerDocument
) {
567 // Firefox doesn't throw an exception for these cases; it returns false.
571 Node
* parentNode
= refNode
->parentNode();
572 int nodeIndex
= refNode
->nodeIndex();
575 // if the node is the top document we should return NODE_BEFORE_AND_AFTER
576 // but we throw to match firefox behavior
581 if (comparePoint(parentNode
, nodeIndex
, ec
) < 0 && // starts before start
582 comparePoint(parentNode
, nodeIndex
+ 1, ec
) < 0) { // ends before start
584 } else if (comparePoint(parentNode
, nodeIndex
, ec
) > 0 && // starts after end
585 comparePoint(parentNode
, nodeIndex
+ 1, ec
) > 0) { // ends after end
589 return true; // all other cases
592 PassRefPtr
<DocumentFragment
> Range::processContents(ActionType action
, ExceptionCode
& ec
)
594 // FIXME: To work properly with mutation events, we will have to take into account
595 // situations where the tree is being transformed while we work on it - ugh!
597 RefPtr
<DocumentFragment
> fragment
;
598 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
)
599 fragment
= new DocumentFragment(m_ownerDocument
.get());
603 return fragment
.release();
607 Node
* commonRoot
= commonAncestorContainer(ec
);
612 // what is the highest node that partially selects the start of the range?
613 Node
* partialStart
= 0;
614 if (m_start
.container() != commonRoot
) {
615 partialStart
= m_start
.container();
616 while (partialStart
->parentNode() != commonRoot
)
617 partialStart
= partialStart
->parentNode();
620 // what is the highest node that partially selects the end of the range?
621 Node
* partialEnd
= 0;
622 if (m_end
.container() != commonRoot
) {
623 partialEnd
= m_end
.container();
624 while (partialEnd
->parentNode() != commonRoot
)
625 partialEnd
= partialEnd
->parentNode();
628 // Simple case: the start and end containers are the same. We just grab
629 // everything >= start offset and < end offset
630 if (m_start
.container() == m_end
.container()) {
631 Node::NodeType startNodeType
= m_start
.container()->nodeType();
632 if (startNodeType
== Node::TEXT_NODE
|| startNodeType
== Node::CDATA_SECTION_NODE
|| startNodeType
== Node::COMMENT_NODE
) {
633 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
634 RefPtr
<CharacterData
> c
= static_pointer_cast
<CharacterData
>(m_start
.container()->cloneNode(true));
635 c
->deleteData(m_end
.offset(), c
->length() - m_end
.offset(), ec
);
636 c
->deleteData(0, m_start
.offset(), ec
);
637 fragment
->appendChild(c
.release(), ec
);
639 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
)
640 static_cast<CharacterData
*>(m_start
.container())->deleteData(m_start
.offset(), m_end
.offset() - m_start
.offset(), ec
);
641 } else if (startNodeType
== Node::PROCESSING_INSTRUCTION_NODE
) {
642 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
643 RefPtr
<ProcessingInstruction
> c
= static_pointer_cast
<ProcessingInstruction
>(m_start
.container()->cloneNode(true));
644 c
->setData(c
->data().substring(m_start
.offset(), m_end
.offset() - m_start
.offset()), ec
);
645 fragment
->appendChild(c
.release(), ec
);
647 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
) {
648 ProcessingInstruction
* pi
= static_cast<ProcessingInstruction
*>(m_start
.container());
649 String
data(pi
->data());
650 data
.remove(m_start
.offset(), m_end
.offset() - m_start
.offset());
651 pi
->setData(data
, ec
);
654 Node
* n
= m_start
.container()->firstChild();
656 for (i
= 0; n
&& i
< m_start
.offset(); i
++) // skip until start offset
657 n
= n
->nextSibling();
658 int endOffset
= m_end
.offset();
659 while (n
&& i
< endOffset
) { // delete until end offset
660 Node
* next
= n
->nextSibling();
661 if (action
== EXTRACT_CONTENTS
)
662 fragment
->appendChild(n
, ec
); // will remove n from its parent
663 else if (action
== CLONE_CONTENTS
)
664 fragment
->appendChild(n
->cloneNode(true), ec
);
666 m_start
.container()->removeChild(n
, ec
);
671 return fragment
.release();
674 // Complex case: Start and end containers are different.
675 // There are three possiblities here:
676 // 1. Start container == commonRoot (End container must be a descendant)
677 // 2. End container == commonRoot (Start container must be a descendant)
678 // 3. Neither is commonRoot, they are both descendants
680 // In case 3, we grab everything after the start (up until a direct child
681 // of commonRoot) into leftContents, and everything before the end (up until
682 // a direct child of commonRoot) into rightContents. Then we process all
683 // commonRoot children between leftContents and rightContents
685 // In case 1 or 2, we skip either processing of leftContents or rightContents,
686 // in which case the last lot of nodes either goes from the first or last
687 // child of commonRoot.
689 // These are deleted, cloned, or extracted (i.e. both) depending on action.
691 RefPtr
<Node
> leftContents
;
692 if (m_start
.container() != commonRoot
) {
693 // process the left-hand side of the range, up until the last ancestor of
694 // start container before commonRoot
695 Node::NodeType startNodeType
= m_start
.container()->nodeType();
696 if (startNodeType
== Node::TEXT_NODE
|| startNodeType
== Node::CDATA_SECTION_NODE
|| startNodeType
== Node::COMMENT_NODE
) {
697 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
698 RefPtr
<CharacterData
> c
= static_pointer_cast
<CharacterData
>(m_start
.container()->cloneNode(true));
699 c
->deleteData(0, m_start
.offset(), ec
);
700 leftContents
= c
.release();
702 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
)
703 static_cast<CharacterData
*>(m_start
.container())->deleteData(
704 m_start
.offset(), static_cast<CharacterData
*>(m_start
.container())->length() - m_start
.offset(), ec
);
705 } else if (startNodeType
== Node::PROCESSING_INSTRUCTION_NODE
) {
706 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
707 RefPtr
<ProcessingInstruction
> c
= static_pointer_cast
<ProcessingInstruction
>(m_start
.container()->cloneNode(true));
708 c
->setData(c
->data().substring(m_start
.offset()), ec
);
709 leftContents
= c
.release();
711 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
) {
712 ProcessingInstruction
* pi
= static_cast<ProcessingInstruction
*>(m_start
.container());
713 String
data(pi
->data());
714 pi
->setData(data
.left(m_start
.offset()), ec
);
717 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
)
718 leftContents
= m_start
.container()->cloneNode(false);
719 Node
* n
= m_start
.container()->firstChild();
720 for (int i
= 0; n
&& i
< m_start
.offset(); i
++) // skip until start offset
721 n
= n
->nextSibling();
722 while (n
) { // process until end
723 Node
* next
= n
->nextSibling();
724 if (action
== EXTRACT_CONTENTS
)
725 leftContents
->appendChild(n
, ec
); // will remove n from start container
726 else if (action
== CLONE_CONTENTS
)
727 leftContents
->appendChild(n
->cloneNode(true), ec
);
729 m_start
.container()->removeChild(n
, ec
);
734 Node
* leftParent
= m_start
.container()->parentNode();
735 Node
* n
= m_start
.container()->nextSibling();
736 for (; leftParent
!= commonRoot
; leftParent
= leftParent
->parentNode()) {
737 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
738 RefPtr
<Node
> leftContentsParent
= leftParent
->cloneNode(false);
739 leftContentsParent
->appendChild(leftContents
,ec
);
740 leftContents
= leftContentsParent
;
744 for (; n
; n
= next
) {
745 next
= n
->nextSibling();
746 if (action
== EXTRACT_CONTENTS
)
747 leftContents
->appendChild(n
,ec
); // will remove n from leftParent
748 else if (action
== CLONE_CONTENTS
)
749 leftContents
->appendChild(n
->cloneNode(true),ec
);
751 leftParent
->removeChild(n
,ec
);
753 n
= leftParent
->nextSibling();
757 RefPtr
<Node
> rightContents
;
758 if (m_end
.container() != commonRoot
) {
759 // delete the right-hand side of the range, up until the last ancestor of
760 // end container before commonRoot
761 Node::NodeType endNodeType
= m_end
.container()->nodeType();
762 if (endNodeType
== Node::TEXT_NODE
|| endNodeType
== Node::CDATA_SECTION_NODE
|| endNodeType
== Node::COMMENT_NODE
) {
763 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
764 RefPtr
<CharacterData
> c
= static_pointer_cast
<CharacterData
>(m_end
.container()->cloneNode(true));
765 c
->deleteData(m_end
.offset(), static_cast<CharacterData
*>(m_end
.container())->length() - m_end
.offset(), ec
);
768 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
)
769 static_cast<CharacterData
*>(m_end
.container())->deleteData(0, m_end
.offset(), ec
);
770 } else if (endNodeType
== Node::PROCESSING_INSTRUCTION_NODE
) {
771 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
772 RefPtr
<ProcessingInstruction
> c
= static_pointer_cast
<ProcessingInstruction
>(m_end
.container()->cloneNode(true));
773 c
->setData(c
->data().left(m_end
.offset()), ec
);
774 rightContents
= c
.release();
776 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
) {
777 ProcessingInstruction
* pi
= static_cast<ProcessingInstruction
*>(m_end
.container());
778 pi
->setData(pi
->data().substring(m_end
.offset()), ec
);
781 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
)
782 rightContents
= m_end
.container()->cloneNode(false);
783 Node
* n
= m_end
.container()->firstChild();
784 if (n
&& m_end
.offset()) {
785 for (int i
= 0; i
+ 1 < m_end
.offset(); i
++) { // skip to end.offset()
786 Node
* next
= n
->nextSibling();
792 for (; n
; n
= prev
) {
793 prev
= n
->previousSibling();
794 if (action
== EXTRACT_CONTENTS
)
795 rightContents
->insertBefore(n
, rightContents
->firstChild(), ec
); // will remove n from its parent
796 else if (action
== CLONE_CONTENTS
)
797 rightContents
->insertBefore(n
->cloneNode(true), rightContents
->firstChild(), ec
);
799 m_end
.container()->removeChild(n
, ec
);
804 Node
* rightParent
= m_end
.container()->parentNode();
805 Node
* n
= m_end
.container()->previousSibling();
806 for (; rightParent
!= commonRoot
; rightParent
= rightParent
->parentNode()) {
807 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
808 RefPtr
<Node
> rightContentsParent
= rightParent
->cloneNode(false);
809 rightContentsParent
->appendChild(rightContents
,ec
);
810 rightContents
= rightContentsParent
;
813 for (; n
; n
= prev
) {
814 prev
= n
->previousSibling();
815 if (action
== EXTRACT_CONTENTS
)
816 rightContents
->insertBefore(n
, rightContents
->firstChild(), ec
); // will remove n from its parent
817 else if (action
== CLONE_CONTENTS
)
818 rightContents
->insertBefore(n
->cloneNode(true), rightContents
->firstChild(), ec
);
820 rightParent
->removeChild(n
, ec
);
822 n
= rightParent
->previousSibling();
826 // delete all children of commonRoot between the start and end container
828 Node
* processStart
; // child of commonRoot
829 if (m_start
.container() == commonRoot
) {
830 processStart
= m_start
.container()->firstChild();
831 for (int i
= 0; i
< m_start
.offset(); i
++)
832 processStart
= processStart
->nextSibling();
834 processStart
= m_start
.container();
835 while (processStart
->parentNode() != commonRoot
)
836 processStart
= processStart
->parentNode();
837 processStart
= processStart
->nextSibling();
839 Node
* processEnd
; // child of commonRoot
840 if (m_end
.container() == commonRoot
) {
841 processEnd
= m_end
.container()->firstChild();
842 for (int i
= 0; i
< m_end
.offset(); i
++)
843 processEnd
= processEnd
->nextSibling();
845 processEnd
= m_end
.container();
846 while (processEnd
->parentNode() != commonRoot
)
847 processEnd
= processEnd
->parentNode();
850 // Now add leftContents, stuff in between, and rightContents to the fragment
851 // (or just delete the stuff in between)
853 if ((action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) && leftContents
)
854 fragment
->appendChild(leftContents
, ec
);
859 for (n
= processStart
; n
&& n
!= processEnd
; n
= next
) {
860 next
= n
->nextSibling();
861 if (action
== EXTRACT_CONTENTS
)
862 fragment
->appendChild(n
, ec
); // will remove from commonRoot
863 else if (action
== CLONE_CONTENTS
)
864 fragment
->appendChild(n
->cloneNode(true), ec
);
866 commonRoot
->removeChild(n
, ec
);
870 if ((action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) && rightContents
)
871 fragment
->appendChild(rightContents
, ec
);
873 return fragment
.release();
876 PassRefPtr
<DocumentFragment
> Range::extractContents(ExceptionCode
& ec
)
878 checkDeleteExtract(ec
);
882 return processContents(EXTRACT_CONTENTS
, ec
);
885 PassRefPtr
<DocumentFragment
> Range::cloneContents(ExceptionCode
& ec
)
887 if (!m_start
.container()) {
888 ec
= INVALID_STATE_ERR
;
892 return processContents(CLONE_CONTENTS
, ec
);
895 void Range::insertNode(PassRefPtr
<Node
> prpNewNode
, ExceptionCode
& ec
)
897 RefPtr
<Node
> newNode
= prpNewNode
;
901 if (!m_start
.container()) {
902 ec
= INVALID_STATE_ERR
;
911 // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of
912 // the Range is read-only.
913 if (containedByReadOnly()) {
914 ec
= NO_MODIFICATION_ALLOWED_ERR
;
918 // WRONG_DOCUMENT_ERR: Raised if newParent and the container of the start of the Range were
919 // not created from the same document.
920 if (newNode
->document() != m_start
.container()->document()) {
921 ec
= WRONG_DOCUMENT_ERR
;
925 // HIERARCHY_REQUEST_ERR: Raised if the container of the start of the Range is of a type that
926 // does not allow children of the type of newNode or if newNode is an ancestor of the container.
928 // an extra one here - if a text node is going to split, it must have a parent to insert into
929 bool startIsText
= m_start
.container()->isTextNode();
930 if (startIsText
&& !m_start
.container()->parentNode()) {
931 ec
= HIERARCHY_REQUEST_ERR
;
935 // In the case where the container is a text node, we check against the container's parent, because
936 // text nodes get split up upon insertion.
939 checkAgainst
= m_start
.container()->parentNode();
941 checkAgainst
= m_start
.container();
943 Node::NodeType newNodeType
= newNode
->nodeType();
945 if (newNodeType
== Node::DOCUMENT_FRAGMENT_NODE
) {
946 // check each child node, not the DocumentFragment itself
948 for (Node
* c
= newNode
->firstChild(); c
; c
= c
->nextSibling()) {
949 if (!checkAgainst
->childTypeAllowed(c
->nodeType())) {
950 ec
= HIERARCHY_REQUEST_ERR
;
957 if (!checkAgainst
->childTypeAllowed(newNodeType
)) {
958 ec
= HIERARCHY_REQUEST_ERR
;
963 for (Node
* n
= m_start
.container(); n
; n
= n
->parentNode()) {
965 ec
= HIERARCHY_REQUEST_ERR
;
970 // INVALID_NODE_TYPE_ERR: Raised if newNode is an Attr, Entity, Notation, or Document node.
971 if (newNodeType
== Node::ATTRIBUTE_NODE
|| newNodeType
== Node::ENTITY_NODE
972 || newNodeType
== Node::NOTATION_NODE
|| newNodeType
== Node::DOCUMENT_NODE
) {
973 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
977 bool collapsed
= m_start
== m_end
;
979 RefPtr
<Text
> newText
= static_cast<Text
*>(m_start
.container())->splitText(m_start
.offset(), ec
);
982 m_start
.container()->parentNode()->insertBefore(newNode
.release(), newText
.get(), ec
);
986 // This special case doesn't seem to match the DOM specification, but it's currently required
987 // to pass Acid3. We might later decide to remove this.
989 m_end
.setToChild(newText
.get());
991 RefPtr
<Node
> lastChild
;
993 lastChild
= (newNodeType
== Node::DOCUMENT_FRAGMENT_NODE
) ? newNode
->lastChild() : newNode
;
995 int startOffset
= m_start
.offset();
996 m_start
.container()->insertBefore(newNode
.release(), m_start
.container()->childNode(startOffset
), ec
);
1000 // This special case doesn't seem to match the DOM specification, but it's currently required
1001 // to pass Acid3. We might later decide to remove this.
1003 m_end
.set(m_start
.container(), startOffset
+ numNewChildren
, lastChild
.get());
1007 String
Range::toString(ExceptionCode
& ec
) const
1009 if (!m_start
.container()) {
1010 ec
= INVALID_STATE_ERR
;
1014 Vector
<UChar
> result
;
1016 Node
* pastLast
= pastLastNode();
1017 for (Node
* n
= firstNode(); n
!= pastLast
; n
= n
->traverseNextNode()) {
1018 if (n
->nodeType() == Node::TEXT_NODE
|| n
->nodeType() == Node::CDATA_SECTION_NODE
) {
1019 String data
= static_cast<CharacterData
*>(n
)->data();
1020 int length
= data
.length();
1021 int start
= (n
== m_start
.container()) ? min(max(0, m_start
.offset()), length
) : 0;
1022 int end
= (n
== m_end
.container()) ? min(max(start
, m_end
.offset()), length
) : length
;
1023 result
.append(data
.characters() + start
, end
- start
);
1027 return String::adopt(result
);
1030 String
Range::toHTML() const
1032 return createMarkup(this);
1035 String
Range::text() const
1037 if (!m_start
.container())
1040 // We need to update layout, since plainText uses line boxes in the render tree.
1041 // FIXME: As with innerText, we'd like this to work even if there are no render objects.
1042 m_start
.container()->document()->updateLayout();
1044 return plainText(this);
1047 PassRefPtr
<DocumentFragment
> Range::createContextualFragment(const String
& markup
, ExceptionCode
& ec
) const
1049 if (!m_start
.container()) {
1050 ec
= INVALID_STATE_ERR
;
1054 Node
* element
= m_start
.container()->isElementNode() ? m_start
.container() : m_start
.container()->parentNode();
1055 if (!element
|| !element
->isHTMLElement()) {
1056 ec
= NOT_SUPPORTED_ERR
;
1060 RefPtr
<DocumentFragment
> fragment
= static_cast<HTMLElement
*>(element
)->createContextualFragment(markup
);
1062 ec
= NOT_SUPPORTED_ERR
;
1066 return fragment
.release();
1070 void Range::detach(ExceptionCode
& ec
)
1072 if (!m_start
.container()) {
1073 ec
= INVALID_STATE_ERR
;
1077 m_ownerDocument
->detachRange(this);
1083 Node
* Range::checkNodeWOffset(Node
* n
, int offset
, ExceptionCode
& ec
) const
1085 switch (n
->nodeType()) {
1086 case Node::DOCUMENT_TYPE_NODE
:
1087 case Node::ENTITY_NODE
:
1088 case Node::NOTATION_NODE
:
1089 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1091 case Node::CDATA_SECTION_NODE
:
1092 case Node::COMMENT_NODE
:
1093 case Node::TEXT_NODE
:
1094 if (static_cast<unsigned>(offset
) > static_cast<CharacterData
*>(n
)->length())
1095 ec
= INDEX_SIZE_ERR
;
1097 case Node::PROCESSING_INSTRUCTION_NODE
:
1098 if (static_cast<unsigned>(offset
) > static_cast<ProcessingInstruction
*>(n
)->data().length())
1099 ec
= INDEX_SIZE_ERR
;
1101 case Node::ATTRIBUTE_NODE
:
1102 case Node::DOCUMENT_FRAGMENT_NODE
:
1103 case Node::DOCUMENT_NODE
:
1104 case Node::ELEMENT_NODE
:
1105 case Node::ENTITY_REFERENCE_NODE
:
1106 case Node::XPATH_NAMESPACE_NODE
: {
1109 Node
* childBefore
= n
->childNode(offset
- 1);
1111 ec
= INDEX_SIZE_ERR
;
1115 ASSERT_NOT_REACHED();
1119 void Range::checkNodeBA(Node
* n
, ExceptionCode
& ec
) const
1121 // INVALID_NODE_TYPE_ERR: Raised if the root container of refNode is not an
1122 // Attr, Document or DocumentFragment node or part of a shadow DOM tree
1123 // or if refNode is a Document, DocumentFragment, Attr, Entity, or Notation node.
1125 switch (n
->nodeType()) {
1126 case Node::ATTRIBUTE_NODE
:
1127 case Node::DOCUMENT_FRAGMENT_NODE
:
1128 case Node::DOCUMENT_NODE
:
1129 case Node::ENTITY_NODE
:
1130 case Node::NOTATION_NODE
:
1131 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1133 case Node::CDATA_SECTION_NODE
:
1134 case Node::COMMENT_NODE
:
1135 case Node::DOCUMENT_TYPE_NODE
:
1136 case Node::ELEMENT_NODE
:
1137 case Node::ENTITY_REFERENCE_NODE
:
1138 case Node::PROCESSING_INSTRUCTION_NODE
:
1139 case Node::TEXT_NODE
:
1140 case Node::XPATH_NAMESPACE_NODE
:
1145 while (Node
* parent
= root
->parentNode())
1148 switch (root
->nodeType()) {
1149 case Node::ATTRIBUTE_NODE
:
1150 case Node::DOCUMENT_NODE
:
1151 case Node::DOCUMENT_FRAGMENT_NODE
:
1153 case Node::CDATA_SECTION_NODE
:
1154 case Node::COMMENT_NODE
:
1155 case Node::DOCUMENT_TYPE_NODE
:
1156 case Node::ELEMENT_NODE
:
1157 case Node::ENTITY_NODE
:
1158 case Node::ENTITY_REFERENCE_NODE
:
1159 case Node::NOTATION_NODE
:
1160 case Node::PROCESSING_INSTRUCTION_NODE
:
1161 case Node::TEXT_NODE
:
1162 case Node::XPATH_NAMESPACE_NODE
:
1163 if (root
->isShadowNode())
1165 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1170 PassRefPtr
<Range
> Range::cloneRange(ExceptionCode
& ec
) const
1172 if (!m_start
.container()) {
1173 ec
= INVALID_STATE_ERR
;
1177 return Range::create(m_ownerDocument
, m_start
.container(), m_start
.offset(), m_end
.container(), m_end
.offset());
1180 void Range::setStartAfter(Node
* refNode
, ExceptionCode
& ec
)
1182 if (!m_start
.container()) {
1183 ec
= INVALID_STATE_ERR
;
1192 if (refNode
->document() != m_ownerDocument
) {
1193 ec
= WRONG_DOCUMENT_ERR
;
1198 checkNodeBA(refNode
, ec
);
1202 setStart(refNode
->parentNode(), refNode
->nodeIndex() + 1, ec
);
1205 void Range::setEndBefore(Node
* refNode
, ExceptionCode
& ec
)
1207 if (!m_start
.container()) {
1208 ec
= INVALID_STATE_ERR
;
1217 if (refNode
->document() != m_ownerDocument
) {
1218 ec
= WRONG_DOCUMENT_ERR
;
1223 checkNodeBA(refNode
, ec
);
1227 setEnd(refNode
->parentNode(), refNode
->nodeIndex(), ec
);
1230 void Range::setEndAfter(Node
* refNode
, ExceptionCode
& ec
)
1232 if (!m_start
.container()) {
1233 ec
= INVALID_STATE_ERR
;
1242 if (refNode
->document() != m_ownerDocument
) {
1243 ec
= WRONG_DOCUMENT_ERR
;
1248 checkNodeBA(refNode
, ec
);
1252 setEnd(refNode
->parentNode(), refNode
->nodeIndex() + 1, ec
);
1256 void Range::selectNode(Node
* refNode
, ExceptionCode
& ec
)
1258 if (!m_start
.container()) {
1259 ec
= INVALID_STATE_ERR
;
1268 // INVALID_NODE_TYPE_ERR: Raised if an ancestor of refNode is an Entity, Notation or
1269 // DocumentType node or if refNode is a Document, DocumentFragment, Attr, Entity, or Notation
1271 for (Node
* anc
= refNode
->parentNode(); anc
; anc
= anc
->parentNode()) {
1272 switch (anc
->nodeType()) {
1273 case Node::ATTRIBUTE_NODE
:
1274 case Node::CDATA_SECTION_NODE
:
1275 case Node::COMMENT_NODE
:
1276 case Node::DOCUMENT_FRAGMENT_NODE
:
1277 case Node::DOCUMENT_NODE
:
1278 case Node::ELEMENT_NODE
:
1279 case Node::ENTITY_REFERENCE_NODE
:
1280 case Node::PROCESSING_INSTRUCTION_NODE
:
1281 case Node::TEXT_NODE
:
1282 case Node::XPATH_NAMESPACE_NODE
:
1284 case Node::DOCUMENT_TYPE_NODE
:
1285 case Node::ENTITY_NODE
:
1286 case Node::NOTATION_NODE
:
1287 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1292 switch (refNode
->nodeType()) {
1293 case Node::CDATA_SECTION_NODE
:
1294 case Node::COMMENT_NODE
:
1295 case Node::DOCUMENT_TYPE_NODE
:
1296 case Node::ELEMENT_NODE
:
1297 case Node::ENTITY_REFERENCE_NODE
:
1298 case Node::PROCESSING_INSTRUCTION_NODE
:
1299 case Node::TEXT_NODE
:
1300 case Node::XPATH_NAMESPACE_NODE
:
1302 case Node::ATTRIBUTE_NODE
:
1303 case Node::DOCUMENT_FRAGMENT_NODE
:
1304 case Node::DOCUMENT_NODE
:
1305 case Node::ENTITY_NODE
:
1306 case Node::NOTATION_NODE
:
1307 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1312 setStartBefore(refNode
, ec
);
1315 setEndAfter(refNode
, ec
);
1318 void Range::selectNodeContents(Node
* refNode
, ExceptionCode
& ec
)
1320 if (!m_start
.container()) {
1321 ec
= INVALID_STATE_ERR
;
1330 // INVALID_NODE_TYPE_ERR: Raised if refNode or an ancestor of refNode is an Entity, Notation
1331 // or DocumentType node.
1332 for (Node
* n
= refNode
; n
; n
= n
->parentNode()) {
1333 switch (n
->nodeType()) {
1334 case Node::ATTRIBUTE_NODE
:
1335 case Node::CDATA_SECTION_NODE
:
1336 case Node::COMMENT_NODE
:
1337 case Node::DOCUMENT_FRAGMENT_NODE
:
1338 case Node::DOCUMENT_NODE
:
1339 case Node::ELEMENT_NODE
:
1340 case Node::ENTITY_REFERENCE_NODE
:
1341 case Node::PROCESSING_INSTRUCTION_NODE
:
1342 case Node::TEXT_NODE
:
1343 case Node::XPATH_NAMESPACE_NODE
:
1345 case Node::DOCUMENT_TYPE_NODE
:
1346 case Node::ENTITY_NODE
:
1347 case Node::NOTATION_NODE
:
1348 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1353 m_start
.setToStart(refNode
);
1354 m_end
.setToEnd(refNode
);
1357 void Range::surroundContents(PassRefPtr
<Node
> passNewParent
, ExceptionCode
& ec
)
1359 RefPtr
<Node
> newParent
= passNewParent
;
1361 if (!m_start
.container()) {
1362 ec
= INVALID_STATE_ERR
;
1371 // INVALID_NODE_TYPE_ERR: Raised if node is an Attr, Entity, DocumentType, Notation,
1372 // Document, or DocumentFragment node.
1373 switch (newParent
->nodeType()) {
1374 case Node::ATTRIBUTE_NODE
:
1375 case Node::DOCUMENT_FRAGMENT_NODE
:
1376 case Node::DOCUMENT_NODE
:
1377 case Node::DOCUMENT_TYPE_NODE
:
1378 case Node::ENTITY_NODE
:
1379 case Node::NOTATION_NODE
:
1380 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1382 case Node::CDATA_SECTION_NODE
:
1383 case Node::COMMENT_NODE
:
1384 case Node::ELEMENT_NODE
:
1385 case Node::ENTITY_REFERENCE_NODE
:
1386 case Node::PROCESSING_INSTRUCTION_NODE
:
1387 case Node::TEXT_NODE
:
1388 case Node::XPATH_NAMESPACE_NODE
:
1392 // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of
1393 // the Range is read-only.
1394 if (containedByReadOnly()) {
1395 ec
= NO_MODIFICATION_ALLOWED_ERR
;
1399 // WRONG_DOCUMENT_ERR: Raised if newParent and the container of the start of the Range were
1400 // not created from the same document.
1401 if (newParent
->document() != m_start
.container()->document()) {
1402 ec
= WRONG_DOCUMENT_ERR
;
1406 // Raise a HIERARCHY_REQUEST_ERR if m_start.container() doesn't accept children like newParent.
1407 Node
* parentOfNewParent
= m_start
.container();
1409 // If m_start.container() is a character data node, it will be split and it will be its parent that will
1410 // need to accept newParent (or in the case of a comment, it logically "would" be inserted into the parent,
1411 // although this will fail below for another reason).
1412 if (parentOfNewParent
->isCharacterDataNode())
1413 parentOfNewParent
= parentOfNewParent
->parentNode();
1414 if (!parentOfNewParent
->childTypeAllowed(newParent
->nodeType())) {
1415 ec
= HIERARCHY_REQUEST_ERR
;
1419 if (m_start
.container() == newParent
|| m_start
.container()->isDescendantOf(newParent
.get())) {
1420 ec
= HIERARCHY_REQUEST_ERR
;
1424 // FIXME: Do we need a check if the node would end up with a child node of a type not
1425 // allowed by the type of node?
1427 // BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially selects a non-Text node.
1428 if (m_start
.container()->nodeType() != Node::TEXT_NODE
) {
1429 if (m_start
.offset() > 0 && m_start
.offset() < maxStartOffset()) {
1430 ec
= RangeException::BAD_BOUNDARYPOINTS_ERR
;
1434 if (m_end
.container()->nodeType() != Node::TEXT_NODE
) {
1435 if (m_end
.offset() > 0 && m_end
.offset() < maxEndOffset()) {
1436 ec
= RangeException::BAD_BOUNDARYPOINTS_ERR
;
1442 while (Node
* n
= newParent
->firstChild()) {
1443 newParent
->removeChild(n
, ec
);
1447 RefPtr
<DocumentFragment
> fragment
= extractContents(ec
);
1450 insertNode(newParent
, ec
);
1453 newParent
->appendChild(fragment
.release(), ec
);
1456 selectNode(newParent
.get(), ec
);
1459 void Range::setStartBefore(Node
* refNode
, ExceptionCode
& ec
)
1461 if (!m_start
.container()) {
1462 ec
= INVALID_STATE_ERR
;
1471 if (refNode
->document() != m_ownerDocument
) {
1472 ec
= WRONG_DOCUMENT_ERR
;
1477 checkNodeBA(refNode
, ec
);
1481 setStart(refNode
->parentNode(), refNode
->nodeIndex(), ec
);
1484 void Range::checkDeleteExtract(ExceptionCode
& ec
)
1486 if (!m_start
.container()) {
1487 ec
= INVALID_STATE_ERR
;
1492 if (!commonAncestorContainer(ec
) || ec
)
1495 Node
* pastLast
= pastLastNode();
1496 for (Node
* n
= firstNode(); n
!= pastLast
; n
= n
->traverseNextNode()) {
1497 if (n
->isReadOnlyNode()) {
1498 ec
= NO_MODIFICATION_ALLOWED_ERR
;
1501 if (n
->nodeType() == Node::DOCUMENT_TYPE_NODE
) {
1502 ec
= HIERARCHY_REQUEST_ERR
;
1507 if (containedByReadOnly()) {
1508 ec
= NO_MODIFICATION_ALLOWED_ERR
;
1513 bool Range::containedByReadOnly() const
1515 for (Node
* n
= m_start
.container(); n
; n
= n
->parentNode()) {
1516 if (n
->isReadOnlyNode())
1519 for (Node
* n
= m_end
.container(); n
; n
= n
->parentNode()) {
1520 if (n
->isReadOnlyNode())
1526 Node
* Range::firstNode() const
1528 if (!m_start
.container())
1530 if (m_start
.container()->offsetInCharacters())
1531 return m_start
.container();
1532 if (Node
* child
= m_start
.container()->childNode(m_start
.offset()))
1534 if (!m_start
.offset())
1535 return m_start
.container();
1536 return m_start
.container()->traverseNextSibling();
1539 Position
Range::editingStartPosition() const
1541 // This function is used by range style computations to avoid bugs like:
1542 // <rdar://problem/4017641> REGRESSION (Mail): you can only bold/unbold a selection starting from end of line once
1543 // It is important to skip certain irrelevant content at the start of the selection, so we do not wind up
1544 // with a spurious "mixed" style.
1546 VisiblePosition
visiblePosition(m_start
.container(), m_start
.offset(), VP_DEFAULT_AFFINITY
);
1547 if (visiblePosition
.isNull())
1550 ExceptionCode ec
= 0;
1551 // if the selection is a caret, just return the position, since the style
1552 // behind us is relevant
1554 return visiblePosition
.deepEquivalent();
1556 // if the selection starts just before a paragraph break, skip over it
1557 if (isEndOfParagraph(visiblePosition
))
1558 return visiblePosition
.next().deepEquivalent().downstream();
1560 // otherwise, make sure to be at the start of the first selected node,
1561 // instead of possibly at the end of the last node before the selection
1562 return visiblePosition
.deepEquivalent().downstream();
1565 Node
* Range::shadowTreeRootNode() const
1567 return startContainer() ? startContainer()->shadowTreeRootNode() : 0;
1570 Node
* Range::pastLastNode() const
1572 if (!m_start
.container() || !m_end
.container())
1574 if (m_end
.container()->offsetInCharacters())
1575 return m_end
.container()->traverseNextSibling();
1576 if (Node
* child
= m_end
.container()->childNode(m_end
.offset()))
1578 return m_end
.container()->traverseNextSibling();
1581 IntRect
Range::boundingBox()
1584 Vector
<IntRect
> rects
;
1585 addLineBoxRects(rects
);
1586 const size_t n
= rects
.size();
1587 for (size_t i
= 0; i
< n
; ++i
)
1588 result
.unite(rects
[i
]);
1592 void Range::addLineBoxRects(Vector
<IntRect
>& rects
, bool useSelectionHeight
)
1594 if (!m_start
.container() || !m_end
.container())
1597 RenderObject
* start
= m_start
.container()->renderer();
1598 RenderObject
* end
= m_end
.container()->renderer();
1602 RenderObject
* stop
= end
->nextInPreOrderAfterChildren();
1603 for (RenderObject
* r
= start
; r
&& r
!= stop
; r
= r
->nextInPreOrder()) {
1604 // only ask leaf render objects for their line box rects
1605 if (!r
->firstChild()) {
1606 int startOffset
= r
== start
? m_start
.offset() : 0;
1607 int endOffset
= r
== end
? m_end
.offset() : INT_MAX
;
1608 r
->addLineBoxRects(rects
, startOffset
, endOffset
, useSelectionHeight
);
1614 #define FormatBufferSize 1024
1615 void Range::formatForDebugger(char* buffer
, unsigned length
) const
1620 if (!m_start
.container() || !m_end
.container())
1623 char s
[FormatBufferSize
];
1624 result
+= "from offset ";
1625 result
+= String::number(m_start
.offset());
1627 m_start
.container()->formatForDebugger(s
, FormatBufferSize
);
1629 result
+= " to offset ";
1630 result
+= String::number(m_end
.offset());
1632 m_end
.container()->formatForDebugger(s
, FormatBufferSize
);
1636 strncpy(buffer
, result
.utf8().data(), length
- 1);
1638 #undef FormatBufferSize
1641 bool operator==(const Range
& a
, const Range
& b
)
1645 // Not strictly legal C++, but in practice this can happen, and this check works
1646 // fine with GCC to detect such cases and return false rather than crashing.
1649 return a
.startPosition() == b
.startPosition() && a
.endPosition() == b
.endPosition();
1652 PassRefPtr
<Range
> rangeOfContents(Node
* node
)
1655 RefPtr
<Range
> range
= Range::create(node
->document());
1657 range
->selectNodeContents(node
, exception
);
1658 return range
.release();
1661 int Range::maxStartOffset() const
1663 if (!m_start
.container())
1665 if (!m_start
.container()->offsetInCharacters())
1666 return m_start
.container()->childNodeCount();
1667 return m_start
.container()->maxCharacterOffset();
1670 int Range::maxEndOffset() const
1672 if (!m_end
.container())
1674 if (!m_end
.container()->offsetInCharacters())
1675 return m_end
.container()->childNodeCount();
1676 return m_end
.container()->maxCharacterOffset();
1679 static inline void boundaryNodeChildrenChanged(RangeBoundaryPoint
& boundary
, ContainerNode
* container
)
1681 if (!boundary
.childBefore())
1683 if (boundary
.container() != container
)
1685 boundary
.invalidateOffset();
1688 void Range::nodeChildrenChanged(ContainerNode
* container
)
1691 ASSERT(container
->document() == m_ownerDocument
);
1692 boundaryNodeChildrenChanged(m_start
, container
);
1693 boundaryNodeChildrenChanged(m_end
, container
);
1696 static inline void boundaryNodeWillBeRemoved(RangeBoundaryPoint
& boundary
, Node
* nodeToBeRemoved
)
1698 if (boundary
.childBefore() == nodeToBeRemoved
) {
1699 boundary
.childBeforeWillBeRemoved();
1703 for (Node
* n
= boundary
.container(); n
; n
= n
->parentNode()) {
1704 if (n
== nodeToBeRemoved
) {
1705 boundary
.setToChild(nodeToBeRemoved
);
1711 void Range::nodeWillBeRemoved(Node
* node
)
1714 ASSERT(node
->document() == m_ownerDocument
);
1715 ASSERT(node
!= m_ownerDocument
);
1716 ASSERT(node
->parentNode());
1717 boundaryNodeWillBeRemoved(m_start
, node
);
1718 boundaryNodeWillBeRemoved(m_end
, node
);
1721 static inline void boundaryTextInserted(RangeBoundaryPoint
& boundary
, Node
* text
, unsigned offset
, unsigned length
)
1723 if (boundary
.container() != text
)
1725 unsigned boundaryOffset
= boundary
.offset();
1726 if (offset
>= boundaryOffset
)
1728 boundary
.setOffset(boundaryOffset
+ length
);
1731 void Range::textInserted(Node
* text
, unsigned offset
, unsigned length
)
1734 ASSERT(text
->document() == m_ownerDocument
);
1735 boundaryTextInserted(m_start
, text
, offset
, length
);
1736 boundaryTextInserted(m_end
, text
, offset
, length
);
1739 static inline void boundaryTextRemoved(RangeBoundaryPoint
& boundary
, Node
* text
, unsigned offset
, unsigned length
)
1741 if (boundary
.container() != text
)
1743 unsigned boundaryOffset
= boundary
.offset();
1744 if (offset
>= boundaryOffset
)
1746 if (offset
+ length
>= boundaryOffset
)
1747 boundary
.setOffset(offset
);
1749 boundary
.setOffset(boundaryOffset
- length
);
1752 void Range::textRemoved(Node
* text
, unsigned offset
, unsigned length
)
1755 ASSERT(text
->document() == m_ownerDocument
);
1756 boundaryTextRemoved(m_start
, text
, offset
, length
);
1757 boundaryTextRemoved(m_end
, text
, offset
, length
);
1760 static inline void boundaryTextNodesMerged(RangeBoundaryPoint
& boundary
, NodeWithIndex
& oldNode
, unsigned offset
)
1762 if (boundary
.container() == oldNode
.node())
1763 boundary
.set(oldNode
.node()->previousSibling(), boundary
.offset() + offset
, 0);
1764 else if (boundary
.container() == oldNode
.node()->parentNode() && boundary
.offset() == oldNode
.index())
1765 boundary
.set(oldNode
.node()->previousSibling(), offset
, 0);
1768 void Range::textNodesMerged(NodeWithIndex
& oldNode
, unsigned offset
)
1770 ASSERT(oldNode
.node());
1771 ASSERT(oldNode
.node()->document() == m_ownerDocument
);
1772 ASSERT(oldNode
.node()->parentNode());
1773 ASSERT(oldNode
.node()->isTextNode());
1774 ASSERT(oldNode
.node()->previousSibling());
1775 ASSERT(oldNode
.node()->previousSibling()->isTextNode());
1776 boundaryTextNodesMerged(m_start
, oldNode
, offset
);
1777 boundaryTextNodesMerged(m_end
, oldNode
, offset
);
1780 static inline void boundaryTextNodesSplit(RangeBoundaryPoint
& boundary
, Text
* oldNode
)
1782 if (boundary
.container() != oldNode
)
1784 unsigned boundaryOffset
= boundary
.offset();
1785 if (boundaryOffset
<= oldNode
->length())
1787 boundary
.set(oldNode
->nextSibling(), boundaryOffset
- oldNode
->length(), 0);
1790 void Range::textNodeSplit(Text
* oldNode
)
1793 ASSERT(oldNode
->document() == m_ownerDocument
);
1794 ASSERT(oldNode
->parentNode());
1795 ASSERT(oldNode
->isTextNode());
1796 ASSERT(oldNode
->nextSibling());
1797 ASSERT(oldNode
->nextSibling()->isTextNode());
1798 boundaryTextNodesSplit(m_start
, oldNode
);
1799 boundaryTextNodesSplit(m_end
, oldNode
);