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, 2009 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"
29 #include "ClientRect.h"
30 #include "ClientRectList.h"
31 #include "DocumentFragment.h"
32 #include "FrameView.h"
33 #include "HTMLElement.h"
34 #include "NodeWithIndex.h"
35 #include "ProcessingInstruction.h"
37 #include "TextIterator.h"
38 #include "VisiblePosition.h"
39 #include "htmlediting.h"
41 #include "visible_units.h"
43 #include <wtf/RefCountedLeakCounter.h>
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 // FIXME: we shouldn't be using deprecatedEditingOffset here
98 return adoptRef(new Range(ownerDocument
, start
.node(), start
.deprecatedEditingOffset(), end
.node(), end
.deprecatedEditingOffset()));
103 // Always detach (even if we've already detached) to fix https://bugs.webkit.org/show_bug.cgi?id=26044
104 m_ownerDocument
->detachRange(this);
107 rangeCounter
.decrement();
111 Node
* Range::startContainer(ExceptionCode
& ec
) const
113 if (!m_start
.container()) {
114 ec
= INVALID_STATE_ERR
;
118 return m_start
.container();
121 int Range::startOffset(ExceptionCode
& ec
) const
123 if (!m_start
.container()) {
124 ec
= INVALID_STATE_ERR
;
128 return m_start
.offset();
131 Node
* Range::endContainer(ExceptionCode
& ec
) const
133 if (!m_start
.container()) {
134 ec
= INVALID_STATE_ERR
;
138 return m_end
.container();
141 int Range::endOffset(ExceptionCode
& ec
) const
143 if (!m_start
.container()) {
144 ec
= INVALID_STATE_ERR
;
148 return m_end
.offset();
151 Node
* Range::commonAncestorContainer(ExceptionCode
& ec
) const
153 if (!m_start
.container()) {
154 ec
= INVALID_STATE_ERR
;
158 return commonAncestorContainer(m_start
.container(), m_end
.container());
161 Node
* Range::commonAncestorContainer(Node
* containerA
, Node
* containerB
)
163 for (Node
* parentA
= containerA
; parentA
; parentA
= parentA
->parentNode()) {
164 for (Node
* parentB
= containerB
; parentB
; parentB
= parentB
->parentNode()) {
165 if (parentA
== parentB
)
172 bool Range::collapsed(ExceptionCode
& ec
) const
174 if (!m_start
.container()) {
175 ec
= INVALID_STATE_ERR
;
179 return m_start
== m_end
;
182 void Range::setStart(PassRefPtr
<Node
> refNode
, int offset
, ExceptionCode
& ec
)
184 if (!m_start
.container()) {
185 ec
= INVALID_STATE_ERR
;
194 if (refNode
->document() != m_ownerDocument
) {
195 ec
= WRONG_DOCUMENT_ERR
;
200 Node
* childNode
= checkNodeWOffset(refNode
.get(), offset
, ec
);
204 m_start
.set(refNode
, offset
, childNode
);
206 // check if different root container
207 Node
* endRootContainer
= m_end
.container();
208 while (endRootContainer
->parentNode())
209 endRootContainer
= endRootContainer
->parentNode();
210 Node
* startRootContainer
= m_start
.container();
211 while (startRootContainer
->parentNode())
212 startRootContainer
= startRootContainer
->parentNode();
213 if (startRootContainer
!= endRootContainer
)
215 // check if new start after end
216 else if (compareBoundaryPoints(m_start
, m_end
) > 0)
220 void Range::setEnd(PassRefPtr
<Node
> refNode
, int offset
, ExceptionCode
& ec
)
222 if (!m_start
.container()) {
223 ec
= INVALID_STATE_ERR
;
232 if (refNode
->document() != m_ownerDocument
) {
233 ec
= WRONG_DOCUMENT_ERR
;
238 Node
* childNode
= checkNodeWOffset(refNode
.get(), offset
, ec
);
242 m_end
.set(refNode
, offset
, childNode
);
244 // check if different root container
245 Node
* endRootContainer
= m_end
.container();
246 while (endRootContainer
->parentNode())
247 endRootContainer
= endRootContainer
->parentNode();
248 Node
* startRootContainer
= m_start
.container();
249 while (startRootContainer
->parentNode())
250 startRootContainer
= startRootContainer
->parentNode();
251 if (startRootContainer
!= endRootContainer
)
253 // check if new end before start
254 if (compareBoundaryPoints(m_start
, m_end
) > 0)
258 void Range::collapse(bool toStart
, ExceptionCode
& ec
)
260 if (!m_start
.container()) {
261 ec
= INVALID_STATE_ERR
;
271 bool Range::isPointInRange(Node
* refNode
, int offset
, ExceptionCode
& ec
)
273 if (!m_start
.container()) {
274 ec
= INVALID_STATE_ERR
;
279 ec
= HIERARCHY_REQUEST_ERR
;
283 if (!refNode
->attached()) {
284 // Firefox doesn't throw an exception for this case; it returns false.
288 if (refNode
->document() != m_ownerDocument
) {
289 ec
= WRONG_DOCUMENT_ERR
;
294 checkNodeWOffset(refNode
, offset
, ec
);
298 return compareBoundaryPoints(refNode
, offset
, m_start
.container(), m_start
.offset()) >= 0
299 && compareBoundaryPoints(refNode
, offset
, m_end
.container(), m_end
.offset()) <= 0;
302 short Range::comparePoint(Node
* refNode
, int offset
, ExceptionCode
& ec
) const
304 // http://developer.mozilla.org/en/docs/DOM:range.comparePoint
305 // This method returns -1, 0 or 1 depending on if the point described by the
306 // refNode node and an offset within the node is before, same as, or after the range respectively.
308 if (!m_start
.container()) {
309 ec
= INVALID_STATE_ERR
;
314 ec
= HIERARCHY_REQUEST_ERR
;
318 if (!refNode
->attached() || refNode
->document() != m_ownerDocument
) {
319 ec
= WRONG_DOCUMENT_ERR
;
324 checkNodeWOffset(refNode
, offset
, ec
);
328 // compare to start, and point comes before
329 if (compareBoundaryPoints(refNode
, offset
, m_start
.container(), m_start
.offset()) < 0)
332 // compare to end, and point comes after
333 if (compareBoundaryPoints(refNode
, offset
, m_end
.container(), m_end
.offset()) > 0)
336 // point is in the middle of this range, or on the boundary points
340 Range::CompareResults
Range::compareNode(Node
* refNode
, ExceptionCode
& ec
) const
342 // http://developer.mozilla.org/en/docs/DOM:range.compareNode
343 // This method returns 0, 1, 2, or 3 based on if the node is before, after,
344 // before and after(surrounds), or inside the range, respectively
351 if (!m_start
.container() && refNode
->attached()) {
352 ec
= INVALID_STATE_ERR
;
356 if (m_start
.container() && !refNode
->attached()) {
357 // Firefox doesn't throw an exception for this case; it returns 0.
361 if (refNode
->document() != m_ownerDocument
) {
362 // Firefox doesn't throw an exception for this case; it returns 0.
366 Node
* parentNode
= refNode
->parentNode();
367 int nodeIndex
= refNode
->nodeIndex();
370 // if the node is the top document we should return NODE_BEFORE_AND_AFTER
371 // but we throw to match firefox behavior
376 if (comparePoint(parentNode
, nodeIndex
, ec
) < 0) { // starts before
377 if (comparePoint(parentNode
, nodeIndex
+ 1, ec
) > 0) // ends after the range
378 return NODE_BEFORE_AND_AFTER
;
379 return NODE_BEFORE
; // ends before or in the range
380 } else { // starts at or after the range start
381 if (comparePoint(parentNode
, nodeIndex
+ 1, ec
) > 0) // ends after the range
383 return NODE_INSIDE
; // ends inside the range
387 short Range::compareBoundaryPoints(CompareHow how
, const Range
* sourceRange
, ExceptionCode
& ec
) const
389 if (!m_start
.container()) {
390 ec
= INVALID_STATE_ERR
;
400 Node
* thisCont
= commonAncestorContainer(ec
);
403 Node
* sourceCont
= sourceRange
->commonAncestorContainer(ec
);
407 if (thisCont
->document() != sourceCont
->document()) {
408 ec
= WRONG_DOCUMENT_ERR
;
412 Node
* thisTop
= thisCont
;
413 Node
* sourceTop
= sourceCont
;
414 while (thisTop
->parentNode())
415 thisTop
= thisTop
->parentNode();
416 while (sourceTop
->parentNode())
417 sourceTop
= sourceTop
->parentNode();
418 if (thisTop
!= sourceTop
) { // in different DocumentFragments
419 ec
= WRONG_DOCUMENT_ERR
;
425 return compareBoundaryPoints(m_start
, sourceRange
->m_start
);
427 return compareBoundaryPoints(m_end
, sourceRange
->m_start
);
429 return compareBoundaryPoints(m_end
, sourceRange
->m_end
);
431 return compareBoundaryPoints(m_start
, sourceRange
->m_end
);
438 short Range::compareBoundaryPoints(Node
* containerA
, int offsetA
, Node
* containerB
, int offsetB
)
448 // see DOM2 traversal & range section 2.5
450 // case 1: both points have the same container
451 if (containerA
== containerB
) {
452 if (offsetA
== offsetB
)
453 return 0; // A is equal to B
454 if (offsetA
< offsetB
)
455 return -1; // A is before B
457 return 1; // A is after B
460 // case 2: node C (container B or an ancestor) is a child node of A
461 Node
* c
= containerB
;
462 while (c
&& c
->parentNode() != containerA
)
466 Node
* n
= containerA
->firstChild();
467 while (n
!= c
&& offsetC
< offsetA
) {
469 n
= n
->nextSibling();
472 if (offsetA
<= offsetC
)
473 return -1; // A is before B
475 return 1; // A is after B
478 // case 3: node C (container A or an ancestor) is a child node of B
480 while (c
&& c
->parentNode() != containerB
)
484 Node
* n
= containerB
->firstChild();
485 while (n
!= c
&& offsetC
< offsetB
) {
487 n
= n
->nextSibling();
490 if (offsetC
< offsetB
)
491 return -1; // A is before B
493 return 1; // A is after B
496 // case 4: containers A & B are siblings, or children of siblings
497 // ### we need to do a traversal here instead
498 Node
* commonAncestor
= commonAncestorContainer(containerA
, containerB
);
501 Node
* childA
= containerA
;
502 while (childA
&& childA
->parentNode() != commonAncestor
)
503 childA
= childA
->parentNode();
505 childA
= commonAncestor
;
506 Node
* childB
= containerB
;
507 while (childB
&& childB
->parentNode() != commonAncestor
)
508 childB
= childB
->parentNode();
510 childB
= commonAncestor
;
512 if (childA
== childB
)
513 return 0; // A is equal to B
515 Node
* n
= commonAncestor
->firstChild();
518 return -1; // A is before B
520 return 1; // A is after B
521 n
= n
->nextSibling();
524 // Should never reach this point.
525 ASSERT_NOT_REACHED();
529 short Range::compareBoundaryPoints(const RangeBoundaryPoint
& boundaryA
, const RangeBoundaryPoint
& boundaryB
)
531 return compareBoundaryPoints(boundaryA
.container(), boundaryA
.offset(), boundaryB
.container(), boundaryB
.offset());
534 bool Range::boundaryPointsValid() const
536 return m_start
.container() && compareBoundaryPoints(m_start
, m_end
) <= 0;
539 void Range::deleteContents(ExceptionCode
& ec
)
541 checkDeleteExtract(ec
);
545 processContents(DELETE_CONTENTS
, ec
);
548 bool Range::intersectsNode(Node
* refNode
, ExceptionCode
& ec
)
550 // http://developer.mozilla.org/en/docs/DOM:range.intersectsNode
551 // Returns a bool if the node intersects the range.
558 if ((!m_start
.container() && refNode
->attached())
559 || (m_start
.container() && !refNode
->attached())
560 || refNode
->document() != m_ownerDocument
) {
561 // Firefox doesn't throw an exception for these cases; it returns false.
565 Node
* parentNode
= refNode
->parentNode();
566 int nodeIndex
= refNode
->nodeIndex();
569 // if the node is the top document we should return NODE_BEFORE_AND_AFTER
570 // but we throw to match firefox behavior
575 if (comparePoint(parentNode
, nodeIndex
, ec
) < 0 && // starts before start
576 comparePoint(parentNode
, nodeIndex
+ 1, ec
) < 0) { // ends before start
578 } else if (comparePoint(parentNode
, nodeIndex
, ec
) > 0 && // starts after end
579 comparePoint(parentNode
, nodeIndex
+ 1, ec
) > 0) { // ends after end
583 return true; // all other cases
586 PassRefPtr
<DocumentFragment
> Range::processContents(ActionType action
, ExceptionCode
& ec
)
588 // FIXME: To work properly with mutation events, we will have to take into account
589 // situations where the tree is being transformed while we work on it - ugh!
591 RefPtr
<DocumentFragment
> fragment
;
592 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
)
593 fragment
= DocumentFragment::create(m_ownerDocument
.get());
597 return fragment
.release();
601 Node
* commonRoot
= commonAncestorContainer(ec
);
606 // what is the highest node that partially selects the start of the range?
607 Node
* partialStart
= 0;
608 if (m_start
.container() != commonRoot
) {
609 partialStart
= m_start
.container();
610 while (partialStart
->parentNode() != commonRoot
)
611 partialStart
= partialStart
->parentNode();
614 // what is the highest node that partially selects the end of the range?
615 Node
* partialEnd
= 0;
616 if (m_end
.container() != commonRoot
) {
617 partialEnd
= m_end
.container();
618 while (partialEnd
->parentNode() != commonRoot
)
619 partialEnd
= partialEnd
->parentNode();
622 // Simple case: the start and end containers are the same. We just grab
623 // everything >= start offset and < end offset
624 if (m_start
.container() == m_end
.container()) {
625 Node::NodeType startNodeType
= m_start
.container()->nodeType();
626 if (startNodeType
== Node::TEXT_NODE
|| startNodeType
== Node::CDATA_SECTION_NODE
|| startNodeType
== Node::COMMENT_NODE
) {
627 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
628 RefPtr
<CharacterData
> c
= static_pointer_cast
<CharacterData
>(m_start
.container()->cloneNode(true));
629 c
->deleteData(m_end
.offset(), c
->length() - m_end
.offset(), ec
);
630 c
->deleteData(0, m_start
.offset(), ec
);
631 fragment
->appendChild(c
.release(), ec
);
633 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
)
634 static_cast<CharacterData
*>(m_start
.container())->deleteData(m_start
.offset(), m_end
.offset() - m_start
.offset(), ec
);
635 } else if (startNodeType
== Node::PROCESSING_INSTRUCTION_NODE
) {
636 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
637 RefPtr
<ProcessingInstruction
> c
= static_pointer_cast
<ProcessingInstruction
>(m_start
.container()->cloneNode(true));
638 c
->setData(c
->data().substring(m_start
.offset(), m_end
.offset() - m_start
.offset()), ec
);
639 fragment
->appendChild(c
.release(), ec
);
641 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
) {
642 ProcessingInstruction
* pi
= static_cast<ProcessingInstruction
*>(m_start
.container());
643 String
data(pi
->data());
644 data
.remove(m_start
.offset(), m_end
.offset() - m_start
.offset());
645 pi
->setData(data
, ec
);
648 Node
* n
= m_start
.container()->firstChild();
650 for (i
= 0; n
&& i
< m_start
.offset(); i
++) // skip until start offset
651 n
= n
->nextSibling();
652 int endOffset
= m_end
.offset();
653 while (n
&& i
< endOffset
) { // delete until end offset
654 Node
* next
= n
->nextSibling();
655 if (action
== EXTRACT_CONTENTS
)
656 fragment
->appendChild(n
, ec
); // will remove n from its parent
657 else if (action
== CLONE_CONTENTS
)
658 fragment
->appendChild(n
->cloneNode(true), ec
);
660 m_start
.container()->removeChild(n
, ec
);
665 return fragment
.release();
668 // Complex case: Start and end containers are different.
669 // There are three possiblities here:
670 // 1. Start container == commonRoot (End container must be a descendant)
671 // 2. End container == commonRoot (Start container must be a descendant)
672 // 3. Neither is commonRoot, they are both descendants
674 // In case 3, we grab everything after the start (up until a direct child
675 // of commonRoot) into leftContents, and everything before the end (up until
676 // a direct child of commonRoot) into rightContents. Then we process all
677 // commonRoot children between leftContents and rightContents
679 // In case 1 or 2, we skip either processing of leftContents or rightContents,
680 // in which case the last lot of nodes either goes from the first or last
681 // child of commonRoot.
683 // These are deleted, cloned, or extracted (i.e. both) depending on action.
685 RefPtr
<Node
> leftContents
;
686 if (m_start
.container() != commonRoot
) {
687 // process the left-hand side of the range, up until the last ancestor of
688 // start container before commonRoot
689 Node::NodeType startNodeType
= m_start
.container()->nodeType();
690 if (startNodeType
== Node::TEXT_NODE
|| startNodeType
== Node::CDATA_SECTION_NODE
|| startNodeType
== Node::COMMENT_NODE
) {
691 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
692 RefPtr
<CharacterData
> c
= static_pointer_cast
<CharacterData
>(m_start
.container()->cloneNode(true));
693 c
->deleteData(0, m_start
.offset(), ec
);
694 leftContents
= c
.release();
696 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
)
697 static_cast<CharacterData
*>(m_start
.container())->deleteData(
698 m_start
.offset(), static_cast<CharacterData
*>(m_start
.container())->length() - m_start
.offset(), ec
);
699 } else if (startNodeType
== Node::PROCESSING_INSTRUCTION_NODE
) {
700 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
701 RefPtr
<ProcessingInstruction
> c
= static_pointer_cast
<ProcessingInstruction
>(m_start
.container()->cloneNode(true));
702 c
->setData(c
->data().substring(m_start
.offset()), ec
);
703 leftContents
= c
.release();
705 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
) {
706 ProcessingInstruction
* pi
= static_cast<ProcessingInstruction
*>(m_start
.container());
707 String
data(pi
->data());
708 pi
->setData(data
.left(m_start
.offset()), ec
);
711 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
)
712 leftContents
= m_start
.container()->cloneNode(false);
713 Node
* n
= m_start
.container()->firstChild();
714 for (int i
= 0; n
&& i
< m_start
.offset(); i
++) // skip until start offset
715 n
= n
->nextSibling();
716 while (n
) { // process until end
717 Node
* next
= n
->nextSibling();
718 if (action
== EXTRACT_CONTENTS
)
719 leftContents
->appendChild(n
, ec
); // will remove n from start container
720 else if (action
== CLONE_CONTENTS
)
721 leftContents
->appendChild(n
->cloneNode(true), ec
);
723 m_start
.container()->removeChild(n
, ec
);
728 Node
* leftParent
= m_start
.container()->parentNode();
729 Node
* n
= m_start
.container()->nextSibling();
730 for (; leftParent
!= commonRoot
; leftParent
= leftParent
->parentNode()) {
731 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
732 RefPtr
<Node
> leftContentsParent
= leftParent
->cloneNode(false);
733 leftContentsParent
->appendChild(leftContents
, ec
);
734 leftContents
= leftContentsParent
;
738 for (; n
; n
= next
) {
739 next
= n
->nextSibling();
740 if (action
== EXTRACT_CONTENTS
)
741 leftContents
->appendChild(n
, ec
); // will remove n from leftParent
742 else if (action
== CLONE_CONTENTS
)
743 leftContents
->appendChild(n
->cloneNode(true), ec
);
745 leftParent
->removeChild(n
, ec
);
747 n
= leftParent
->nextSibling();
751 RefPtr
<Node
> rightContents
;
752 if (m_end
.container() != commonRoot
) {
753 // delete the right-hand side of the range, up until the last ancestor of
754 // end container before commonRoot
755 Node::NodeType endNodeType
= m_end
.container()->nodeType();
756 if (endNodeType
== Node::TEXT_NODE
|| endNodeType
== Node::CDATA_SECTION_NODE
|| endNodeType
== Node::COMMENT_NODE
) {
757 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
758 RefPtr
<CharacterData
> c
= static_pointer_cast
<CharacterData
>(m_end
.container()->cloneNode(true));
759 c
->deleteData(m_end
.offset(), static_cast<CharacterData
*>(m_end
.container())->length() - m_end
.offset(), ec
);
762 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
)
763 static_cast<CharacterData
*>(m_end
.container())->deleteData(0, m_end
.offset(), ec
);
764 } else if (endNodeType
== Node::PROCESSING_INSTRUCTION_NODE
) {
765 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
766 RefPtr
<ProcessingInstruction
> c
= static_pointer_cast
<ProcessingInstruction
>(m_end
.container()->cloneNode(true));
767 c
->setData(c
->data().left(m_end
.offset()), ec
);
768 rightContents
= c
.release();
770 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
) {
771 ProcessingInstruction
* pi
= static_cast<ProcessingInstruction
*>(m_end
.container());
772 pi
->setData(pi
->data().substring(m_end
.offset()), ec
);
775 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
)
776 rightContents
= m_end
.container()->cloneNode(false);
777 Node
* n
= m_end
.container()->firstChild();
778 if (n
&& m_end
.offset()) {
779 for (int i
= 0; i
+ 1 < m_end
.offset(); i
++) { // skip to end.offset()
780 Node
* next
= n
->nextSibling();
786 for (; n
; n
= prev
) {
787 prev
= n
->previousSibling();
788 if (action
== EXTRACT_CONTENTS
)
789 rightContents
->insertBefore(n
, rightContents
->firstChild(), ec
); // will remove n from its parent
790 else if (action
== CLONE_CONTENTS
)
791 rightContents
->insertBefore(n
->cloneNode(true), rightContents
->firstChild(), ec
);
793 m_end
.container()->removeChild(n
, ec
);
798 Node
* rightParent
= m_end
.container()->parentNode();
799 Node
* n
= m_end
.container()->previousSibling();
800 for (; rightParent
!= commonRoot
; rightParent
= rightParent
->parentNode()) {
801 if (action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) {
802 RefPtr
<Node
> rightContentsParent
= rightParent
->cloneNode(false);
803 rightContentsParent
->appendChild(rightContents
, ec
);
804 rightContents
= rightContentsParent
;
807 for (; n
; n
= prev
) {
808 prev
= n
->previousSibling();
809 if (action
== EXTRACT_CONTENTS
)
810 rightContents
->insertBefore(n
, rightContents
->firstChild(), ec
); // will remove n from its parent
811 else if (action
== CLONE_CONTENTS
)
812 rightContents
->insertBefore(n
->cloneNode(true), rightContents
->firstChild(), ec
);
814 rightParent
->removeChild(n
, ec
);
816 n
= rightParent
->previousSibling();
820 // delete all children of commonRoot between the start and end container
822 Node
* processStart
; // child of commonRoot
823 if (m_start
.container() == commonRoot
) {
824 processStart
= m_start
.container()->firstChild();
825 for (int i
= 0; i
< m_start
.offset(); i
++)
826 processStart
= processStart
->nextSibling();
828 processStart
= m_start
.container();
829 while (processStart
->parentNode() != commonRoot
)
830 processStart
= processStart
->parentNode();
831 processStart
= processStart
->nextSibling();
833 Node
* processEnd
; // child of commonRoot
834 if (m_end
.container() == commonRoot
) {
835 processEnd
= m_end
.container()->firstChild();
836 for (int i
= 0; i
< m_end
.offset(); i
++)
837 processEnd
= processEnd
->nextSibling();
839 processEnd
= m_end
.container();
840 while (processEnd
->parentNode() != commonRoot
)
841 processEnd
= processEnd
->parentNode();
844 // Collapse the range, making sure that the result is not within a node that was partially selected.
845 if (action
== EXTRACT_CONTENTS
|| action
== DELETE_CONTENTS
) {
847 setStart(partialStart
->parentNode(), partialStart
->nodeIndex() + 1, ec
);
849 setStart(partialEnd
->parentNode(), partialEnd
->nodeIndex(), ec
);
855 // Now add leftContents, stuff in between, and rightContents to the fragment
856 // (or just delete the stuff in between)
858 if ((action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) && leftContents
)
859 fragment
->appendChild(leftContents
, ec
);
864 for (n
= processStart
; n
&& n
!= processEnd
; n
= next
) {
865 next
= n
->nextSibling();
866 if (action
== EXTRACT_CONTENTS
)
867 fragment
->appendChild(n
, ec
); // will remove from commonRoot
868 else if (action
== CLONE_CONTENTS
)
869 fragment
->appendChild(n
->cloneNode(true), ec
);
871 commonRoot
->removeChild(n
, ec
);
875 if ((action
== EXTRACT_CONTENTS
|| action
== CLONE_CONTENTS
) && rightContents
)
876 fragment
->appendChild(rightContents
, ec
);
878 return fragment
.release();
881 PassRefPtr
<DocumentFragment
> Range::extractContents(ExceptionCode
& ec
)
883 checkDeleteExtract(ec
);
887 return processContents(EXTRACT_CONTENTS
, ec
);
890 PassRefPtr
<DocumentFragment
> Range::cloneContents(ExceptionCode
& ec
)
892 if (!m_start
.container()) {
893 ec
= INVALID_STATE_ERR
;
897 return processContents(CLONE_CONTENTS
, ec
);
900 void Range::insertNode(PassRefPtr
<Node
> prpNewNode
, ExceptionCode
& ec
)
902 RefPtr
<Node
> newNode
= prpNewNode
;
906 if (!m_start
.container()) {
907 ec
= INVALID_STATE_ERR
;
916 // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of
917 // the Range is read-only.
918 if (containedByReadOnly()) {
919 ec
= NO_MODIFICATION_ALLOWED_ERR
;
923 // WRONG_DOCUMENT_ERR: Raised if newParent and the container of the start of the Range were
924 // not created from the same document.
925 if (newNode
->document() != m_start
.container()->document()) {
926 ec
= WRONG_DOCUMENT_ERR
;
930 // HIERARCHY_REQUEST_ERR: Raised if the container of the start of the Range is of a type that
931 // does not allow children of the type of newNode or if newNode is an ancestor of the container.
933 // an extra one here - if a text node is going to split, it must have a parent to insert into
934 bool startIsText
= m_start
.container()->isTextNode();
935 if (startIsText
&& !m_start
.container()->parentNode()) {
936 ec
= HIERARCHY_REQUEST_ERR
;
940 // In the case where the container is a text node, we check against the container's parent, because
941 // text nodes get split up upon insertion.
944 checkAgainst
= m_start
.container()->parentNode();
946 checkAgainst
= m_start
.container();
948 Node::NodeType newNodeType
= newNode
->nodeType();
950 if (newNodeType
== Node::DOCUMENT_FRAGMENT_NODE
) {
951 // check each child node, not the DocumentFragment itself
953 for (Node
* c
= newNode
->firstChild(); c
; c
= c
->nextSibling()) {
954 if (!checkAgainst
->childTypeAllowed(c
->nodeType())) {
955 ec
= HIERARCHY_REQUEST_ERR
;
962 if (!checkAgainst
->childTypeAllowed(newNodeType
)) {
963 ec
= HIERARCHY_REQUEST_ERR
;
968 for (Node
* n
= m_start
.container(); n
; n
= n
->parentNode()) {
970 ec
= HIERARCHY_REQUEST_ERR
;
975 // INVALID_NODE_TYPE_ERR: Raised if newNode is an Attr, Entity, Notation, or Document node.
976 if (newNodeType
== Node::ATTRIBUTE_NODE
|| newNodeType
== Node::ENTITY_NODE
977 || newNodeType
== Node::NOTATION_NODE
|| newNodeType
== Node::DOCUMENT_NODE
) {
978 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
982 bool collapsed
= m_start
== m_end
;
984 RefPtr
<Text
> newText
= static_cast<Text
*>(m_start
.container())->splitText(m_start
.offset(), ec
);
987 m_start
.container()->parentNode()->insertBefore(newNode
.release(), newText
.get(), ec
);
991 // This special case doesn't seem to match the DOM specification, but it's currently required
992 // to pass Acid3. We might later decide to remove this.
994 m_end
.setToBeforeChild(newText
.get());
996 RefPtr
<Node
> lastChild
;
998 lastChild
= (newNodeType
== Node::DOCUMENT_FRAGMENT_NODE
) ? newNode
->lastChild() : newNode
;
1000 int startOffset
= m_start
.offset();
1001 m_start
.container()->insertBefore(newNode
.release(), m_start
.container()->childNode(startOffset
), ec
);
1005 // This special case doesn't seem to match the DOM specification, but it's currently required
1006 // to pass Acid3. We might later decide to remove this.
1008 m_end
.set(m_start
.container(), startOffset
+ numNewChildren
, lastChild
.get());
1012 String
Range::toString(ExceptionCode
& ec
) const
1014 if (!m_start
.container()) {
1015 ec
= INVALID_STATE_ERR
;
1019 Vector
<UChar
> result
;
1021 Node
* pastLast
= pastLastNode();
1022 for (Node
* n
= firstNode(); n
!= pastLast
; n
= n
->traverseNextNode()) {
1023 if (n
->nodeType() == Node::TEXT_NODE
|| n
->nodeType() == Node::CDATA_SECTION_NODE
) {
1024 String data
= static_cast<CharacterData
*>(n
)->data();
1025 int length
= data
.length();
1026 int start
= (n
== m_start
.container()) ? min(max(0, m_start
.offset()), length
) : 0;
1027 int end
= (n
== m_end
.container()) ? min(max(start
, m_end
.offset()), length
) : length
;
1028 result
.append(data
.characters() + start
, end
- start
);
1032 return String::adopt(result
);
1035 String
Range::toHTML() const
1037 return createMarkup(this);
1040 String
Range::text() const
1042 if (!m_start
.container())
1045 // We need to update layout, since plainText uses line boxes in the render tree.
1046 // FIXME: As with innerText, we'd like this to work even if there are no render objects.
1047 m_start
.container()->document()->updateLayout();
1049 return plainText(this);
1052 PassRefPtr
<DocumentFragment
> Range::createContextualFragment(const String
& markup
, ExceptionCode
& ec
) const
1054 if (!m_start
.container()) {
1055 ec
= INVALID_STATE_ERR
;
1059 Node
* element
= m_start
.container()->isElementNode() ? m_start
.container() : m_start
.container()->parentNode();
1060 if (!element
|| !element
->isHTMLElement()) {
1061 ec
= NOT_SUPPORTED_ERR
;
1065 RefPtr
<DocumentFragment
> fragment
= static_cast<HTMLElement
*>(element
)->createContextualFragment(markup
);
1067 ec
= NOT_SUPPORTED_ERR
;
1071 return fragment
.release();
1075 void Range::detach(ExceptionCode
& ec
)
1077 // Check first to see if we've already detached:
1078 if (!m_start
.container()) {
1079 ec
= INVALID_STATE_ERR
;
1083 m_ownerDocument
->detachRange(this);
1089 Node
* Range::checkNodeWOffset(Node
* n
, int offset
, ExceptionCode
& ec
) const
1091 switch (n
->nodeType()) {
1092 case Node::DOCUMENT_TYPE_NODE
:
1093 case Node::ENTITY_NODE
:
1094 case Node::NOTATION_NODE
:
1095 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1097 case Node::CDATA_SECTION_NODE
:
1098 case Node::COMMENT_NODE
:
1099 case Node::TEXT_NODE
:
1100 if (static_cast<unsigned>(offset
) > static_cast<CharacterData
*>(n
)->length())
1101 ec
= INDEX_SIZE_ERR
;
1103 case Node::PROCESSING_INSTRUCTION_NODE
:
1104 if (static_cast<unsigned>(offset
) > static_cast<ProcessingInstruction
*>(n
)->data().length())
1105 ec
= INDEX_SIZE_ERR
;
1107 case Node::ATTRIBUTE_NODE
:
1108 case Node::DOCUMENT_FRAGMENT_NODE
:
1109 case Node::DOCUMENT_NODE
:
1110 case Node::ELEMENT_NODE
:
1111 case Node::ENTITY_REFERENCE_NODE
:
1112 case Node::XPATH_NAMESPACE_NODE
: {
1115 Node
* childBefore
= n
->childNode(offset
- 1);
1117 ec
= INDEX_SIZE_ERR
;
1121 ASSERT_NOT_REACHED();
1125 void Range::checkNodeBA(Node
* n
, ExceptionCode
& ec
) const
1127 // INVALID_NODE_TYPE_ERR: Raised if the root container of refNode is not an
1128 // Attr, Document or DocumentFragment node or part of a shadow DOM tree
1129 // or if refNode is a Document, DocumentFragment, Attr, Entity, or Notation node.
1131 switch (n
->nodeType()) {
1132 case Node::ATTRIBUTE_NODE
:
1133 case Node::DOCUMENT_FRAGMENT_NODE
:
1134 case Node::DOCUMENT_NODE
:
1135 case Node::ENTITY_NODE
:
1136 case Node::NOTATION_NODE
:
1137 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1139 case Node::CDATA_SECTION_NODE
:
1140 case Node::COMMENT_NODE
:
1141 case Node::DOCUMENT_TYPE_NODE
:
1142 case Node::ELEMENT_NODE
:
1143 case Node::ENTITY_REFERENCE_NODE
:
1144 case Node::PROCESSING_INSTRUCTION_NODE
:
1145 case Node::TEXT_NODE
:
1146 case Node::XPATH_NAMESPACE_NODE
:
1151 while (Node
* parent
= root
->parentNode())
1154 switch (root
->nodeType()) {
1155 case Node::ATTRIBUTE_NODE
:
1156 case Node::DOCUMENT_NODE
:
1157 case Node::DOCUMENT_FRAGMENT_NODE
:
1159 case Node::CDATA_SECTION_NODE
:
1160 case Node::COMMENT_NODE
:
1161 case Node::DOCUMENT_TYPE_NODE
:
1162 case Node::ELEMENT_NODE
:
1163 case Node::ENTITY_NODE
:
1164 case Node::ENTITY_REFERENCE_NODE
:
1165 case Node::NOTATION_NODE
:
1166 case Node::PROCESSING_INSTRUCTION_NODE
:
1167 case Node::TEXT_NODE
:
1168 case Node::XPATH_NAMESPACE_NODE
:
1169 if (root
->isShadowNode())
1171 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1176 PassRefPtr
<Range
> Range::cloneRange(ExceptionCode
& ec
) const
1178 if (!m_start
.container()) {
1179 ec
= INVALID_STATE_ERR
;
1183 return Range::create(m_ownerDocument
, m_start
.container(), m_start
.offset(), m_end
.container(), m_end
.offset());
1186 void Range::setStartAfter(Node
* refNode
, ExceptionCode
& ec
)
1188 if (!m_start
.container()) {
1189 ec
= INVALID_STATE_ERR
;
1198 if (refNode
->document() != m_ownerDocument
) {
1199 ec
= WRONG_DOCUMENT_ERR
;
1204 checkNodeBA(refNode
, ec
);
1208 setStart(refNode
->parentNode(), refNode
->nodeIndex() + 1, ec
);
1211 void Range::setEndBefore(Node
* refNode
, ExceptionCode
& ec
)
1213 if (!m_start
.container()) {
1214 ec
= INVALID_STATE_ERR
;
1223 if (refNode
->document() != m_ownerDocument
) {
1224 ec
= WRONG_DOCUMENT_ERR
;
1229 checkNodeBA(refNode
, ec
);
1233 setEnd(refNode
->parentNode(), refNode
->nodeIndex(), ec
);
1236 void Range::setEndAfter(Node
* refNode
, ExceptionCode
& ec
)
1238 if (!m_start
.container()) {
1239 ec
= INVALID_STATE_ERR
;
1248 if (refNode
->document() != m_ownerDocument
) {
1249 ec
= WRONG_DOCUMENT_ERR
;
1254 checkNodeBA(refNode
, ec
);
1258 setEnd(refNode
->parentNode(), refNode
->nodeIndex() + 1, ec
);
1262 void Range::selectNode(Node
* refNode
, ExceptionCode
& ec
)
1264 if (!m_start
.container()) {
1265 ec
= INVALID_STATE_ERR
;
1274 // INVALID_NODE_TYPE_ERR: Raised if an ancestor of refNode is an Entity, Notation or
1275 // DocumentType node or if refNode is a Document, DocumentFragment, Attr, Entity, or Notation
1277 for (Node
* anc
= refNode
->parentNode(); anc
; anc
= anc
->parentNode()) {
1278 switch (anc
->nodeType()) {
1279 case Node::ATTRIBUTE_NODE
:
1280 case Node::CDATA_SECTION_NODE
:
1281 case Node::COMMENT_NODE
:
1282 case Node::DOCUMENT_FRAGMENT_NODE
:
1283 case Node::DOCUMENT_NODE
:
1284 case Node::ELEMENT_NODE
:
1285 case Node::ENTITY_REFERENCE_NODE
:
1286 case Node::PROCESSING_INSTRUCTION_NODE
:
1287 case Node::TEXT_NODE
:
1288 case Node::XPATH_NAMESPACE_NODE
:
1290 case Node::DOCUMENT_TYPE_NODE
:
1291 case Node::ENTITY_NODE
:
1292 case Node::NOTATION_NODE
:
1293 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1298 switch (refNode
->nodeType()) {
1299 case Node::CDATA_SECTION_NODE
:
1300 case Node::COMMENT_NODE
:
1301 case Node::DOCUMENT_TYPE_NODE
:
1302 case Node::ELEMENT_NODE
:
1303 case Node::ENTITY_REFERENCE_NODE
:
1304 case Node::PROCESSING_INSTRUCTION_NODE
:
1305 case Node::TEXT_NODE
:
1306 case Node::XPATH_NAMESPACE_NODE
:
1308 case Node::ATTRIBUTE_NODE
:
1309 case Node::DOCUMENT_FRAGMENT_NODE
:
1310 case Node::DOCUMENT_NODE
:
1311 case Node::ENTITY_NODE
:
1312 case Node::NOTATION_NODE
:
1313 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1318 setStartBefore(refNode
, ec
);
1321 setEndAfter(refNode
, ec
);
1324 void Range::selectNodeContents(Node
* refNode
, ExceptionCode
& ec
)
1326 if (!m_start
.container()) {
1327 ec
= INVALID_STATE_ERR
;
1336 // INVALID_NODE_TYPE_ERR: Raised if refNode or an ancestor of refNode is an Entity, Notation
1337 // or DocumentType node.
1338 for (Node
* n
= refNode
; n
; n
= n
->parentNode()) {
1339 switch (n
->nodeType()) {
1340 case Node::ATTRIBUTE_NODE
:
1341 case Node::CDATA_SECTION_NODE
:
1342 case Node::COMMENT_NODE
:
1343 case Node::DOCUMENT_FRAGMENT_NODE
:
1344 case Node::DOCUMENT_NODE
:
1345 case Node::ELEMENT_NODE
:
1346 case Node::ENTITY_REFERENCE_NODE
:
1347 case Node::PROCESSING_INSTRUCTION_NODE
:
1348 case Node::TEXT_NODE
:
1349 case Node::XPATH_NAMESPACE_NODE
:
1351 case Node::DOCUMENT_TYPE_NODE
:
1352 case Node::ENTITY_NODE
:
1353 case Node::NOTATION_NODE
:
1354 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1359 m_start
.setToStartOfNode(refNode
);
1360 m_end
.setToEndOfNode(refNode
);
1363 void Range::surroundContents(PassRefPtr
<Node
> passNewParent
, ExceptionCode
& ec
)
1365 RefPtr
<Node
> newParent
= passNewParent
;
1367 if (!m_start
.container()) {
1368 ec
= INVALID_STATE_ERR
;
1377 // INVALID_NODE_TYPE_ERR: Raised if node is an Attr, Entity, DocumentType, Notation,
1378 // Document, or DocumentFragment node.
1379 switch (newParent
->nodeType()) {
1380 case Node::ATTRIBUTE_NODE
:
1381 case Node::DOCUMENT_FRAGMENT_NODE
:
1382 case Node::DOCUMENT_NODE
:
1383 case Node::DOCUMENT_TYPE_NODE
:
1384 case Node::ENTITY_NODE
:
1385 case Node::NOTATION_NODE
:
1386 ec
= RangeException::INVALID_NODE_TYPE_ERR
;
1388 case Node::CDATA_SECTION_NODE
:
1389 case Node::COMMENT_NODE
:
1390 case Node::ELEMENT_NODE
:
1391 case Node::ENTITY_REFERENCE_NODE
:
1392 case Node::PROCESSING_INSTRUCTION_NODE
:
1393 case Node::TEXT_NODE
:
1394 case Node::XPATH_NAMESPACE_NODE
:
1398 // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of
1399 // the Range is read-only.
1400 if (containedByReadOnly()) {
1401 ec
= NO_MODIFICATION_ALLOWED_ERR
;
1405 // WRONG_DOCUMENT_ERR: Raised if newParent and the container of the start of the Range were
1406 // not created from the same document.
1407 if (newParent
->document() != m_start
.container()->document()) {
1408 ec
= WRONG_DOCUMENT_ERR
;
1412 // Raise a HIERARCHY_REQUEST_ERR if m_start.container() doesn't accept children like newParent.
1413 Node
* parentOfNewParent
= m_start
.container();
1415 // If m_start.container() is a character data node, it will be split and it will be its parent that will
1416 // need to accept newParent (or in the case of a comment, it logically "would" be inserted into the parent,
1417 // although this will fail below for another reason).
1418 if (parentOfNewParent
->isCharacterDataNode())
1419 parentOfNewParent
= parentOfNewParent
->parentNode();
1420 if (!parentOfNewParent
->childTypeAllowed(newParent
->nodeType())) {
1421 ec
= HIERARCHY_REQUEST_ERR
;
1425 if (m_start
.container() == newParent
|| m_start
.container()->isDescendantOf(newParent
.get())) {
1426 ec
= HIERARCHY_REQUEST_ERR
;
1430 // FIXME: Do we need a check if the node would end up with a child node of a type not
1431 // allowed by the type of node?
1433 // BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially selects a non-Text node.
1434 Node
* startNonTextContainer
= m_start
.container();
1435 if (startNonTextContainer
->nodeType() == Node::TEXT_NODE
)
1436 startNonTextContainer
= startNonTextContainer
->parentNode();
1437 Node
* endNonTextContainer
= m_end
.container();
1438 if (endNonTextContainer
->nodeType() == Node::TEXT_NODE
)
1439 endNonTextContainer
= endNonTextContainer
->parentNode();
1440 if (startNonTextContainer
!= endNonTextContainer
) {
1441 ec
= RangeException::BAD_BOUNDARYPOINTS_ERR
;
1446 while (Node
* n
= newParent
->firstChild()) {
1447 newParent
->removeChild(n
, ec
);
1451 RefPtr
<DocumentFragment
> fragment
= extractContents(ec
);
1454 insertNode(newParent
, ec
);
1457 newParent
->appendChild(fragment
.release(), ec
);
1460 selectNode(newParent
.get(), ec
);
1463 void Range::setStartBefore(Node
* refNode
, ExceptionCode
& ec
)
1465 if (!m_start
.container()) {
1466 ec
= INVALID_STATE_ERR
;
1475 if (refNode
->document() != m_ownerDocument
) {
1476 ec
= WRONG_DOCUMENT_ERR
;
1481 checkNodeBA(refNode
, ec
);
1485 setStart(refNode
->parentNode(), refNode
->nodeIndex(), ec
);
1488 void Range::checkDeleteExtract(ExceptionCode
& ec
)
1490 if (!m_start
.container()) {
1491 ec
= INVALID_STATE_ERR
;
1496 if (!commonAncestorContainer(ec
) || ec
)
1499 Node
* pastLast
= pastLastNode();
1500 for (Node
* n
= firstNode(); n
!= pastLast
; n
= n
->traverseNextNode()) {
1501 if (n
->isReadOnlyNode()) {
1502 ec
= NO_MODIFICATION_ALLOWED_ERR
;
1505 if (n
->nodeType() == Node::DOCUMENT_TYPE_NODE
) {
1506 ec
= HIERARCHY_REQUEST_ERR
;
1511 if (containedByReadOnly()) {
1512 ec
= NO_MODIFICATION_ALLOWED_ERR
;
1517 bool Range::containedByReadOnly() const
1519 for (Node
* n
= m_start
.container(); n
; n
= n
->parentNode()) {
1520 if (n
->isReadOnlyNode())
1523 for (Node
* n
= m_end
.container(); n
; n
= n
->parentNode()) {
1524 if (n
->isReadOnlyNode())
1530 Node
* Range::firstNode() const
1532 if (!m_start
.container())
1534 if (m_start
.container()->offsetInCharacters())
1535 return m_start
.container();
1536 if (Node
* child
= m_start
.container()->childNode(m_start
.offset()))
1538 if (!m_start
.offset())
1539 return m_start
.container();
1540 return m_start
.container()->traverseNextSibling();
1543 Position
Range::editingStartPosition() const
1545 // This function is used by range style computations to avoid bugs like:
1546 // <rdar://problem/4017641> REGRESSION (Mail): you can only bold/unbold a selection starting from end of line once
1547 // It is important to skip certain irrelevant content at the start of the selection, so we do not wind up
1548 // with a spurious "mixed" style.
1550 VisiblePosition
visiblePosition(m_start
.container(), m_start
.offset(), VP_DEFAULT_AFFINITY
);
1551 if (visiblePosition
.isNull())
1554 ExceptionCode ec
= 0;
1555 // if the selection is a caret, just return the position, since the style
1556 // behind us is relevant
1558 return visiblePosition
.deepEquivalent();
1560 // if the selection starts just before a paragraph break, skip over it
1561 if (isEndOfParagraph(visiblePosition
))
1562 return visiblePosition
.next().deepEquivalent().downstream();
1564 // otherwise, make sure to be at the start of the first selected node,
1565 // instead of possibly at the end of the last node before the selection
1566 return visiblePosition
.deepEquivalent().downstream();
1569 Node
* Range::shadowTreeRootNode() const
1571 return startContainer() ? startContainer()->shadowTreeRootNode() : 0;
1574 Node
* Range::pastLastNode() const
1576 if (!m_start
.container() || !m_end
.container())
1578 if (m_end
.container()->offsetInCharacters())
1579 return m_end
.container()->traverseNextSibling();
1580 if (Node
* child
= m_end
.container()->childNode(m_end
.offset()))
1582 return m_end
.container()->traverseNextSibling();
1585 IntRect
Range::boundingBox()
1588 Vector
<IntRect
> rects
;
1590 const size_t n
= rects
.size();
1591 for (size_t i
= 0; i
< n
; ++i
)
1592 result
.unite(rects
[i
]);
1596 void Range::textRects(Vector
<IntRect
>& rects
, bool useSelectionHeight
)
1598 Node
* startContainer
= m_start
.container();
1599 Node
* endContainer
= m_end
.container();
1601 if (!startContainer
|| !endContainer
)
1604 Node
* stopNode
= pastLastNode();
1605 for (Node
* node
= firstNode(); node
!= stopNode
; node
= node
->traverseNextNode()) {
1606 RenderObject
* r
= node
->renderer();
1607 if (!r
|| !r
->isText())
1609 RenderText
* renderText
= toRenderText(r
);
1610 int startOffset
= node
== startContainer
? m_start
.offset() : 0;
1611 int endOffset
= node
== endContainer
? m_end
.offset() : numeric_limits
<int>::max();
1612 renderText
->absoluteRectsForRange(rects
, startOffset
, endOffset
, useSelectionHeight
);
1616 void Range::textQuads(Vector
<FloatQuad
>& quads
, bool useSelectionHeight
)
1618 Node
* startContainer
= m_start
.container();
1619 Node
* endContainer
= m_end
.container();
1621 if (!startContainer
|| !endContainer
)
1624 Node
* stopNode
= pastLastNode();
1625 for (Node
* node
= firstNode(); node
!= stopNode
; node
= node
->traverseNextNode()) {
1626 RenderObject
* r
= node
->renderer();
1627 if (!r
|| !r
->isText())
1629 RenderText
* renderText
= toRenderText(r
);
1630 int startOffset
= node
== startContainer
? m_start
.offset() : 0;
1631 int endOffset
= node
== endContainer
? m_end
.offset() : numeric_limits
<int>::max();
1632 renderText
->absoluteQuadsForRange(quads
, startOffset
, endOffset
, useSelectionHeight
);
1637 #define FormatBufferSize 1024
1638 void Range::formatForDebugger(char* buffer
, unsigned length
) const
1643 if (!m_start
.container() || !m_end
.container())
1646 char s
[FormatBufferSize
];
1647 result
+= "from offset ";
1648 result
+= String::number(m_start
.offset());
1650 m_start
.container()->formatForDebugger(s
, FormatBufferSize
);
1652 result
+= " to offset ";
1653 result
+= String::number(m_end
.offset());
1655 m_end
.container()->formatForDebugger(s
, FormatBufferSize
);
1659 strncpy(buffer
, result
.utf8().data(), length
- 1);
1661 #undef FormatBufferSize
1664 bool operator==(const Range
& a
, const Range
& b
)
1668 // Not strictly legal C++, but in practice this can happen, and this check works
1669 // fine with GCC to detect such cases and return false rather than crashing.
1672 return a
.startPosition() == b
.startPosition() && a
.endPosition() == b
.endPosition();
1675 PassRefPtr
<Range
> rangeOfContents(Node
* node
)
1678 RefPtr
<Range
> range
= Range::create(node
->document());
1680 range
->selectNodeContents(node
, exception
);
1681 return range
.release();
1684 int Range::maxStartOffset() const
1686 if (!m_start
.container())
1688 if (!m_start
.container()->offsetInCharacters())
1689 return m_start
.container()->childNodeCount();
1690 return m_start
.container()->maxCharacterOffset();
1693 int Range::maxEndOffset() const
1695 if (!m_end
.container())
1697 if (!m_end
.container()->offsetInCharacters())
1698 return m_end
.container()->childNodeCount();
1699 return m_end
.container()->maxCharacterOffset();
1702 static inline void boundaryNodeChildrenChanged(RangeBoundaryPoint
& boundary
, ContainerNode
* container
)
1704 if (!boundary
.childBefore())
1706 if (boundary
.container() != container
)
1708 boundary
.invalidateOffset();
1711 void Range::nodeChildrenChanged(ContainerNode
* container
)
1714 ASSERT(container
->document() == m_ownerDocument
);
1715 boundaryNodeChildrenChanged(m_start
, container
);
1716 boundaryNodeChildrenChanged(m_end
, container
);
1719 static inline void boundaryNodeWillBeRemoved(RangeBoundaryPoint
& boundary
, Node
* nodeToBeRemoved
)
1721 if (boundary
.childBefore() == nodeToBeRemoved
) {
1722 boundary
.childBeforeWillBeRemoved();
1726 for (Node
* n
= boundary
.container(); n
; n
= n
->parentNode()) {
1727 if (n
== nodeToBeRemoved
) {
1728 boundary
.setToBeforeChild(nodeToBeRemoved
);
1734 void Range::nodeWillBeRemoved(Node
* node
)
1737 ASSERT(node
->document() == m_ownerDocument
);
1738 ASSERT(node
!= m_ownerDocument
);
1739 ASSERT(node
->parentNode());
1740 boundaryNodeWillBeRemoved(m_start
, node
);
1741 boundaryNodeWillBeRemoved(m_end
, node
);
1744 static inline void boundaryTextInserted(RangeBoundaryPoint
& boundary
, Node
* text
, unsigned offset
, unsigned length
)
1746 if (boundary
.container() != text
)
1748 unsigned boundaryOffset
= boundary
.offset();
1749 if (offset
>= boundaryOffset
)
1751 boundary
.setOffset(boundaryOffset
+ length
);
1754 void Range::textInserted(Node
* text
, unsigned offset
, unsigned length
)
1757 ASSERT(text
->document() == m_ownerDocument
);
1758 boundaryTextInserted(m_start
, text
, offset
, length
);
1759 boundaryTextInserted(m_end
, text
, offset
, length
);
1762 static inline void boundaryTextRemoved(RangeBoundaryPoint
& boundary
, Node
* text
, unsigned offset
, unsigned length
)
1764 if (boundary
.container() != text
)
1766 unsigned boundaryOffset
= boundary
.offset();
1767 if (offset
>= boundaryOffset
)
1769 if (offset
+ length
>= boundaryOffset
)
1770 boundary
.setOffset(offset
);
1772 boundary
.setOffset(boundaryOffset
- length
);
1775 void Range::textRemoved(Node
* text
, unsigned offset
, unsigned length
)
1778 ASSERT(text
->document() == m_ownerDocument
);
1779 boundaryTextRemoved(m_start
, text
, offset
, length
);
1780 boundaryTextRemoved(m_end
, text
, offset
, length
);
1783 static inline void boundaryTextNodesMerged(RangeBoundaryPoint
& boundary
, NodeWithIndex
& oldNode
, unsigned offset
)
1785 if (boundary
.container() == oldNode
.node())
1786 boundary
.set(oldNode
.node()->previousSibling(), boundary
.offset() + offset
, 0);
1787 else if (boundary
.container() == oldNode
.node()->parentNode() && boundary
.offset() == oldNode
.index())
1788 boundary
.set(oldNode
.node()->previousSibling(), offset
, 0);
1791 void Range::textNodesMerged(NodeWithIndex
& oldNode
, unsigned offset
)
1793 ASSERT(oldNode
.node());
1794 ASSERT(oldNode
.node()->document() == m_ownerDocument
);
1795 ASSERT(oldNode
.node()->parentNode());
1796 ASSERT(oldNode
.node()->isTextNode());
1797 ASSERT(oldNode
.node()->previousSibling());
1798 ASSERT(oldNode
.node()->previousSibling()->isTextNode());
1799 boundaryTextNodesMerged(m_start
, oldNode
, offset
);
1800 boundaryTextNodesMerged(m_end
, oldNode
, offset
);
1803 static inline void boundaryTextNodesSplit(RangeBoundaryPoint
& boundary
, Text
* oldNode
)
1805 if (boundary
.container() != oldNode
)
1807 unsigned boundaryOffset
= boundary
.offset();
1808 if (boundaryOffset
<= oldNode
->length())
1810 boundary
.set(oldNode
->nextSibling(), boundaryOffset
- oldNode
->length(), 0);
1813 void Range::textNodeSplit(Text
* oldNode
)
1816 ASSERT(oldNode
->document() == m_ownerDocument
);
1817 ASSERT(oldNode
->parentNode());
1818 ASSERT(oldNode
->isTextNode());
1819 ASSERT(oldNode
->nextSibling());
1820 ASSERT(oldNode
->nextSibling()->isTextNode());
1821 boundaryTextNodesSplit(m_start
, oldNode
);
1822 boundaryTextNodesSplit(m_end
, oldNode
);
1825 void Range::expand(const String
& unit
, ExceptionCode
& ec
)
1827 VisiblePosition
start(startPosition());
1828 VisiblePosition
end(endPosition());
1829 if (unit
== "word") {
1830 start
= startOfWord(start
);
1831 end
= endOfWord(end
);
1832 } else if (unit
== "sentence") {
1833 start
= startOfSentence(start
);
1834 end
= endOfSentence(end
);
1835 } else if (unit
== "block") {
1836 start
= startOfParagraph(start
);
1837 end
= endOfParagraph(end
);
1838 } else if (unit
== "document") {
1839 start
= startOfDocument(start
);
1840 end
= endOfDocument(end
);
1843 setStart(start
.deepEquivalent().containerNode(), start
.deepEquivalent().computeOffsetInContainerNode(), ec
);
1844 setEnd(end
.deepEquivalent().containerNode(), end
.deepEquivalent().computeOffsetInContainerNode(), ec
);
1847 PassRefPtr
<ClientRectList
> Range::getClientRects() const
1849 if (!m_start
.container())
1852 m_ownerDocument
->updateLayoutIgnorePendingStylesheets();
1854 Vector
<FloatQuad
> quads
;
1855 getBorderAndTextQuads(quads
);
1857 return ClientRectList::create(quads
);
1860 PassRefPtr
<ClientRect
> Range::getBoundingClientRect() const
1862 if (!m_start
.container())
1865 m_ownerDocument
->updateLayoutIgnorePendingStylesheets();
1867 Vector
<FloatQuad
> quads
;
1868 getBorderAndTextQuads(quads
);
1870 if (quads
.isEmpty())
1871 return ClientRect::create();
1874 for (size_t i
= 0; i
< quads
.size(); ++i
)
1875 result
.unite(quads
[i
].enclosingBoundingBox());
1877 return ClientRect::create(result
);
1880 static void adjustFloatQuadsForScrollAndAbsoluteZoom(Vector
<FloatQuad
>& quads
, Document
* document
, RenderObject
* renderer
)
1882 FrameView
* view
= document
->view();
1886 IntRect visibleContentRect
= view
->visibleContentRect();
1887 for (size_t i
= 0; i
< quads
.size(); ++i
) {
1888 quads
[i
].move(-visibleContentRect
.x(), -visibleContentRect
.y());
1889 adjustFloatQuadForAbsoluteZoom(quads
[i
], renderer
);
1893 void Range::getBorderAndTextQuads(Vector
<FloatQuad
>& quads
) const
1895 Node
* startContainer
= m_start
.container();
1896 Node
* endContainer
= m_end
.container();
1897 Node
* stopNode
= pastLastNode();
1899 HashSet
<Node
*> nodeSet
;
1900 for (Node
* node
= firstNode(); node
!= stopNode
; node
= node
->traverseNextNode()) {
1901 if (node
->isElementNode())
1905 for (Node
* node
= firstNode(); node
!= stopNode
; node
= node
->traverseNextNode()) {
1906 if (node
->isElementNode()) {
1907 if (!nodeSet
.contains(node
->parentNode())) {
1908 if (RenderBoxModelObject
* renderBoxModelObject
= static_cast<Element
*>(node
)->renderBoxModelObject()) {
1909 Vector
<FloatQuad
> elementQuads
;
1910 renderBoxModelObject
->absoluteQuads(elementQuads
);
1911 adjustFloatQuadsForScrollAndAbsoluteZoom(elementQuads
, m_ownerDocument
.get(), renderBoxModelObject
);
1913 quads
.append(elementQuads
);
1916 } else if (node
->isTextNode()) {
1917 if (RenderObject
* renderer
= static_cast<Text
*>(node
)->renderer()) {
1918 RenderText
* renderText
= toRenderText(renderer
);
1919 int startOffset
= (node
== startContainer
) ? m_start
.offset() : 0;
1920 int endOffset
= (node
== endContainer
) ? m_end
.offset() : INT_MAX
;
1922 Vector
<FloatQuad
> textQuads
;
1923 renderText
->absoluteQuadsForRange(textQuads
, startOffset
, endOffset
);
1924 adjustFloatQuadsForScrollAndAbsoluteZoom(textQuads
, m_ownerDocument
.get(), renderText
);
1926 quads
.append(textQuads
);
1932 } // namespace WebCore