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, 2010, 2011 Apple Inc. All rights reserved.
7 * Copyright (C) 2011 Motorola Mobility. All rights reserved.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
28 #include "ClientRect.h"
29 #include "ClientRectList.h"
30 #include "DocumentFragment.h"
31 #include "ExceptionCode.h"
32 #include "FloatQuad.h"
34 #include "FrameView.h"
35 #include "HTMLElement.h"
36 #include "HTMLNames.h"
38 #include "NodeTraversal.h"
39 #include "NodeWithIndex.h"
41 #include "ProcessingInstruction.h"
42 #include "RangeException.h"
43 #include "RenderBoxModelObject.h"
44 #include "RenderText.h"
45 #include "ScopedEventQueue.h"
47 #include "TextIterator.h"
48 #include "VisiblePosition.h"
49 #include "VisibleUnits.h"
50 #include "htmlediting.h"
53 #include <wtf/RefCountedLeakCounter.h>
54 #include <wtf/Vector.h>
55 #include <wtf/text/CString.h>
56 #include <wtf/text/StringBuilder.h>
61 using namespace HTMLNames;
63 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, rangeCounter, ("Range"));
65 inline Range::Range(PassRefPtr<Document> ownerDocument)
66 : m_ownerDocument(ownerDocument)
67 , m_start(m_ownerDocument)
68 , m_end(m_ownerDocument)
71 rangeCounter.increment();
74 m_ownerDocument->attachRange(this);
77 PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument)
79 return adoptRef(new Range(ownerDocument));
82 inline Range::Range(PassRefPtr<Document> ownerDocument, PassRefPtr<Node> startContainer, int startOffset, PassRefPtr<Node> endContainer, int endOffset)
83 : m_ownerDocument(ownerDocument)
84 , m_start(m_ownerDocument)
85 , m_end(m_ownerDocument)
88 rangeCounter.increment();
91 m_ownerDocument->attachRange(this);
93 // Simply setting the containers and offsets directly would not do any of the checking
94 // that setStart and setEnd do, so we call those functions.
95 setStart(startContainer, startOffset);
96 setEnd(endContainer, endOffset);
99 PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument, PassRefPtr<Node> startContainer, int startOffset, PassRefPtr<Node> endContainer, int endOffset)
101 return adoptRef(new Range(ownerDocument, startContainer, startOffset, endContainer, endOffset));
104 PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument, const Position& start, const Position& end)
106 return adoptRef(new Range(ownerDocument, start.containerNode(), start.computeOffsetInContainerNode(), end.containerNode(), end.computeOffsetInContainerNode()));
111 // Always detach (even if we've already detached) to fix https://bugs.webkit.org/show_bug.cgi?id=26044
112 m_ownerDocument->detachRange(this);
115 rangeCounter.decrement();
119 void Range::setDocument(Document* document)
121 ASSERT(m_ownerDocument != document);
123 m_ownerDocument->detachRange(this);
124 m_ownerDocument = document;
125 m_start.setToStartOfNode(document);
126 m_end.setToStartOfNode(document);
127 m_ownerDocument->attachRange(this);
130 Node* Range::startContainer(ExceptionCode& ec) const
132 if (!m_start.container()) {
133 ec = INVALID_STATE_ERR;
137 return m_start.container();
140 int Range::startOffset(ExceptionCode& ec) const
142 if (!m_start.container()) {
143 ec = INVALID_STATE_ERR;
147 return m_start.offset();
150 Node* Range::endContainer(ExceptionCode& ec) const
152 if (!m_start.container()) {
153 ec = INVALID_STATE_ERR;
157 return m_end.container();
160 int Range::endOffset(ExceptionCode& ec) const
162 if (!m_start.container()) {
163 ec = INVALID_STATE_ERR;
167 return m_end.offset();
170 Node* Range::commonAncestorContainer(ExceptionCode& ec) const
172 if (!m_start.container()) {
173 ec = INVALID_STATE_ERR;
177 return commonAncestorContainer(m_start.container(), m_end.container());
180 Node* Range::commonAncestorContainer(Node* containerA, Node* containerB)
182 for (Node* parentA = containerA; parentA; parentA = parentA->parentNode()) {
183 for (Node* parentB = containerB; parentB; parentB = parentB->parentNode()) {
184 if (parentA == parentB)
191 bool Range::collapsed(ExceptionCode& ec) const
193 if (!m_start.container()) {
194 ec = INVALID_STATE_ERR;
198 return m_start == m_end;
201 static inline bool checkForDifferentRootContainer(const RangeBoundaryPoint& start, const RangeBoundaryPoint& end)
203 Node* endRootContainer = end.container();
204 while (endRootContainer->parentNode())
205 endRootContainer = endRootContainer->parentNode();
206 Node* startRootContainer = start.container();
207 while (startRootContainer->parentNode())
208 startRootContainer = startRootContainer->parentNode();
210 return startRootContainer != endRootContainer || (Range::compareBoundaryPoints(start, end, ASSERT_NO_EXCEPTION) > 0);
213 void Range::setStart(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec)
215 if (!m_start.container()) {
216 ec = INVALID_STATE_ERR;
225 bool didMoveDocument = false;
226 if (refNode->document() != m_ownerDocument) {
227 setDocument(refNode->document());
228 didMoveDocument = true;
232 Node* childNode = checkNodeWOffset(refNode.get(), offset, ec);
236 m_start.set(refNode, offset, childNode);
238 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end))
242 void Range::setEnd(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec)
244 if (!m_start.container()) {
245 ec = INVALID_STATE_ERR;
254 bool didMoveDocument = false;
255 if (refNode->document() != m_ownerDocument) {
256 setDocument(refNode->document());
257 didMoveDocument = true;
261 Node* childNode = checkNodeWOffset(refNode.get(), offset, ec);
265 m_end.set(refNode, offset, childNode);
267 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end))
271 void Range::setStart(const Position& start, ExceptionCode& ec)
273 Position parentAnchored = start.parentAnchoredEquivalent();
274 setStart(parentAnchored.containerNode(), parentAnchored.offsetInContainerNode(), ec);
277 void Range::setEnd(const Position& end, ExceptionCode& ec)
279 Position parentAnchored = end.parentAnchoredEquivalent();
280 setEnd(parentAnchored.containerNode(), parentAnchored.offsetInContainerNode(), ec);
283 void Range::collapse(bool toStart, ExceptionCode& ec)
285 if (!m_start.container()) {
286 ec = INVALID_STATE_ERR;
296 bool Range::isPointInRange(Node* refNode, int offset, ExceptionCode& ec)
298 if (!m_start.container()) {
299 ec = INVALID_STATE_ERR;
304 ec = HIERARCHY_REQUEST_ERR;
308 if (!refNode->attached() || refNode->document() != m_ownerDocument) {
313 checkNodeWOffset(refNode, offset, ec);
317 return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset(), ec) >= 0 && !ec
318 && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset(), ec) <= 0 && !ec;
321 short Range::comparePoint(Node* refNode, int offset, ExceptionCode& ec) const
323 // http://developer.mozilla.org/en/docs/DOM:range.comparePoint
324 // This method returns -1, 0 or 1 depending on if the point described by the
325 // refNode node and an offset within the node is before, same as, or after the range respectively.
327 if (!m_start.container()) {
328 ec = INVALID_STATE_ERR;
333 ec = HIERARCHY_REQUEST_ERR;
337 if (!refNode->attached() || refNode->document() != m_ownerDocument) {
338 ec = WRONG_DOCUMENT_ERR;
343 checkNodeWOffset(refNode, offset, ec);
347 // compare to start, and point comes before
348 if (compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset(), ec) < 0)
354 // compare to end, and point comes after
355 if (compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset(), ec) > 0 && !ec)
358 // point is in the middle of this range, or on the boundary points
362 Range::CompareResults Range::compareNode(Node* refNode, ExceptionCode& ec) const
364 // http://developer.mozilla.org/en/docs/DOM:range.compareNode
365 // This method returns 0, 1, 2, or 3 based on if the node is before, after,
366 // before and after(surrounds), or inside the range, respectively
373 if (!m_start.container() && refNode->attached()) {
374 ec = INVALID_STATE_ERR;
378 if (m_start.container() && !refNode->attached()) {
379 // Firefox doesn't throw an exception for this case; it returns 0.
383 if (refNode->document() != m_ownerDocument) {
384 // Firefox doesn't throw an exception for this case; it returns 0.
388 ContainerNode* parentNode = refNode->parentNode();
389 int nodeIndex = refNode->nodeIndex();
392 // if the node is the top document we should return NODE_BEFORE_AND_AFTER
393 // but we throw to match firefox behavior
398 if (comparePoint(parentNode, nodeIndex, ec) < 0) { // starts before
399 if (comparePoint(parentNode, nodeIndex + 1, ec) > 0) // ends after the range
400 return NODE_BEFORE_AND_AFTER;
401 return NODE_BEFORE; // ends before or in the range
402 } else { // starts at or after the range start
403 if (comparePoint(parentNode, nodeIndex + 1, ec) > 0) // ends after the range
405 return NODE_INSIDE; // ends inside the range
409 short Range::compareBoundaryPoints(CompareHow how, const Range* sourceRange, ExceptionCode& ec) const
411 if (!m_start.container()) {
412 ec = INVALID_STATE_ERR;
422 Node* thisCont = commonAncestorContainer(ec);
425 Node* sourceCont = sourceRange->commonAncestorContainer(ec);
429 if (thisCont->document() != sourceCont->document()) {
430 ec = WRONG_DOCUMENT_ERR;
434 Node* thisTop = thisCont;
435 Node* sourceTop = sourceCont;
436 while (thisTop->parentNode())
437 thisTop = thisTop->parentNode();
438 while (sourceTop->parentNode())
439 sourceTop = sourceTop->parentNode();
440 if (thisTop != sourceTop) { // in different DocumentFragments
441 ec = WRONG_DOCUMENT_ERR;
447 return compareBoundaryPoints(m_start, sourceRange->m_start, ec);
449 return compareBoundaryPoints(m_end, sourceRange->m_start, ec);
451 return compareBoundaryPoints(m_end, sourceRange->m_end, ec);
453 return compareBoundaryPoints(m_start, sourceRange->m_end, ec);
460 short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB, ExceptionCode& ec)
470 // see DOM2 traversal & range section 2.5
472 // case 1: both points have the same container
473 if (containerA == containerB) {
474 if (offsetA == offsetB)
475 return 0; // A is equal to B
476 if (offsetA < offsetB)
477 return -1; // A is before B
479 return 1; // A is after B
482 // case 2: node C (container B or an ancestor) is a child node of A
483 Node* c = containerB;
484 while (c && c->parentNode() != containerA)
488 Node* n = containerA->firstChild();
489 while (n != c && offsetC < offsetA) {
491 n = n->nextSibling();
494 if (offsetA <= offsetC)
495 return -1; // A is before B
497 return 1; // A is after B
500 // case 3: node C (container A or an ancestor) is a child node of B
502 while (c && c->parentNode() != containerB)
506 Node* n = containerB->firstChild();
507 while (n != c && offsetC < offsetB) {
509 n = n->nextSibling();
512 if (offsetC < offsetB)
513 return -1; // A is before B
515 return 1; // A is after B
518 // case 4: containers A & B are siblings, or children of siblings
519 // ### we need to do a traversal here instead
520 Node* commonAncestor = commonAncestorContainer(containerA, containerB);
521 if (!commonAncestor) {
522 ec = WRONG_DOCUMENT_ERR;
525 Node* childA = containerA;
526 while (childA && childA->parentNode() != commonAncestor)
527 childA = childA->parentNode();
529 childA = commonAncestor;
530 Node* childB = containerB;
531 while (childB && childB->parentNode() != commonAncestor)
532 childB = childB->parentNode();
534 childB = commonAncestor;
536 if (childA == childB)
537 return 0; // A is equal to B
539 Node* n = commonAncestor->firstChild();
542 return -1; // A is before B
544 return 1; // A is after B
545 n = n->nextSibling();
548 // Should never reach this point.
549 ASSERT_NOT_REACHED();
553 short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB, ExceptionCode& ec)
555 return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boundaryB.container(), boundaryB.offset(), ec);
558 bool Range::boundaryPointsValid() const
560 ExceptionCode ec = 0;
561 return m_start.container() && compareBoundaryPoints(m_start, m_end, ec) <= 0 && !ec;
564 void Range::deleteContents(ExceptionCode& ec)
566 checkDeleteExtract(ec);
570 processContents(DELETE_CONTENTS, ec);
573 bool Range::intersectsNode(Node* refNode, ExceptionCode& ec)
575 // http://developer.mozilla.org/en/docs/DOM:range.intersectsNode
576 // Returns a bool if the node intersects the range.
578 // Throw exception if the range is already detached.
579 if (!m_start.container()) {
580 ec = INVALID_STATE_ERR;
588 if (!refNode->attached() || refNode->document() != m_ownerDocument) {
589 // Firefox doesn't throw an exception for these cases; it returns false.
593 ContainerNode* parentNode = refNode->parentNode();
594 int nodeIndex = refNode->nodeIndex();
597 // if the node is the top document we should return NODE_BEFORE_AND_AFTER
598 // but we throw to match firefox behavior
603 if (comparePoint(parentNode, nodeIndex, ec) < 0 && // starts before start
604 comparePoint(parentNode, nodeIndex + 1, ec) < 0) { // ends before start
606 } else if (comparePoint(parentNode, nodeIndex, ec) > 0 && // starts after end
607 comparePoint(parentNode, nodeIndex + 1, ec) > 0) { // ends after end
611 return true; // all other cases
614 static inline Node* highestAncestorUnderCommonRoot(Node* node, Node* commonRoot)
616 if (node == commonRoot)
619 ASSERT(commonRoot->contains(node));
621 while (node->parentNode() != commonRoot)
622 node = node->parentNode();
627 static inline Node* childOfCommonRootBeforeOffset(Node* container, unsigned offset, Node* commonRoot)
632 if (!commonRoot->contains(container))
635 if (container == commonRoot) {
636 container = container->firstChild();
637 for (unsigned i = 0; container && i < offset; i++)
638 container = container->nextSibling();
640 while (container->parentNode() != commonRoot)
641 container = container->parentNode();
647 static inline unsigned lengthOfContentsInNode(Node* node)
649 // This switch statement must be consistent with that of Range::processContentsBetweenOffsets.
650 switch (node->nodeType()) {
651 case Node::TEXT_NODE:
652 case Node::CDATA_SECTION_NODE:
653 case Node::COMMENT_NODE:
654 return static_cast<CharacterData*>(node)->length();
655 case Node::PROCESSING_INSTRUCTION_NODE:
656 return static_cast<ProcessingInstruction*>(node)->data().length();
657 case Node::ELEMENT_NODE:
658 case Node::ATTRIBUTE_NODE:
659 case Node::ENTITY_REFERENCE_NODE:
660 case Node::ENTITY_NODE:
661 case Node::DOCUMENT_NODE:
662 case Node::DOCUMENT_TYPE_NODE:
663 case Node::DOCUMENT_FRAGMENT_NODE:
664 case Node::NOTATION_NODE:
665 case Node::XPATH_NAMESPACE_NODE:
666 return node->childNodeCount();
668 ASSERT_NOT_REACHED();
672 PassRefPtr<DocumentFragment> Range::processContents(ActionType action, ExceptionCode& ec)
674 typedef Vector<RefPtr<Node> > NodeVector;
676 RefPtr<DocumentFragment> fragment;
677 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
678 fragment = DocumentFragment::create(m_ownerDocument.get());
682 return fragment.release();
686 RefPtr<Node> commonRoot = commonAncestorContainer(ec);
691 if (m_start.container() == m_end.container()) {
692 processContentsBetweenOffsets(action, fragment, m_start.container(), m_start.offset(), m_end.offset(), ec);
696 // what is the highest node that partially selects the start / end of the range?
697 RefPtr<Node> partialStart = highestAncestorUnderCommonRoot(m_start.container(), commonRoot.get());
698 RefPtr<Node> partialEnd = highestAncestorUnderCommonRoot(m_end.container(), commonRoot.get());
700 // Start and end containers are different.
701 // There are three possibilities here:
702 // 1. Start container == commonRoot (End container must be a descendant)
703 // 2. End container == commonRoot (Start container must be a descendant)
704 // 3. Neither is commonRoot, they are both descendants
706 // In case 3, we grab everything after the start (up until a direct child
707 // of commonRoot) into leftContents, and everything before the end (up until
708 // a direct child of commonRoot) into rightContents. Then we process all
709 // commonRoot children between leftContents and rightContents
711 // In case 1 or 2, we skip either processing of leftContents or rightContents,
712 // in which case the last lot of nodes either goes from the first or last
713 // child of commonRoot.
715 // These are deleted, cloned, or extracted (i.e. both) depending on action.
717 // Note that we are verifying that our common root hierarchy is still intact
718 // after any DOM mutation event, at various stages below. See webkit bug 60350.
720 RefPtr<Node> leftContents;
721 if (m_start.container() != commonRoot && commonRoot->contains(m_start.container())) {
722 leftContents = processContentsBetweenOffsets(action, 0, m_start.container(), m_start.offset(), lengthOfContentsInNode(m_start.container()), ec);
723 leftContents = processAncestorsAndTheirSiblings(action, m_start.container(), ProcessContentsForward, leftContents, commonRoot.get(), ec);
726 RefPtr<Node> rightContents;
727 if (m_end.container() != commonRoot && commonRoot->contains(m_end.container())) {
728 rightContents = processContentsBetweenOffsets(action, 0, m_end.container(), 0, m_end.offset(), ec);
729 rightContents = processAncestorsAndTheirSiblings(action, m_end.container(), ProcessContentsBackward, rightContents, commonRoot.get(), ec);
732 // delete all children of commonRoot between the start and end container
733 RefPtr<Node> processStart = childOfCommonRootBeforeOffset(m_start.container(), m_start.offset(), commonRoot.get());
734 if (processStart && m_start.container() != commonRoot) // processStart contains nodes before m_start.
735 processStart = processStart->nextSibling();
736 RefPtr<Node> processEnd = childOfCommonRootBeforeOffset(m_end.container(), m_end.offset(), commonRoot.get());
738 // Collapse the range, making sure that the result is not within a node that was partially selected.
739 if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
740 if (partialStart && commonRoot->contains(partialStart.get()))
741 setStart(partialStart->parentNode(), partialStart->nodeIndex() + 1, ec);
742 else if (partialEnd && commonRoot->contains(partialEnd.get()))
743 setStart(partialEnd->parentNode(), partialEnd->nodeIndex(), ec);
749 // Now add leftContents, stuff in between, and rightContents to the fragment
750 // (or just delete the stuff in between)
752 if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && leftContents)
753 fragment->appendChild(leftContents, ec);
757 for (Node* n = processStart.get(); n && n != processEnd; n = n->nextSibling())
759 processNodes(action, nodes, commonRoot, fragment, ec);
762 if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && rightContents)
763 fragment->appendChild(rightContents, ec);
765 return fragment.release();
768 static inline void deleteCharacterData(PassRefPtr<CharacterData> data, unsigned startOffset, unsigned endOffset, ExceptionCode& ec)
770 if (data->length() - endOffset)
771 data->deleteData(endOffset, data->length() - endOffset, ec);
773 data->deleteData(0, startOffset, ec);
776 PassRefPtr<Node> Range::processContentsBetweenOffsets(ActionType action, PassRefPtr<DocumentFragment> fragment,
777 Node* container, unsigned startOffset, unsigned endOffset, ExceptionCode& ec)
780 ASSERT(startOffset <= endOffset);
782 // This switch statement must be consistent with that of lengthOfContentsInNode.
784 switch (container->nodeType()) {
785 case Node::TEXT_NODE:
786 case Node::CDATA_SECTION_NODE:
787 case Node::COMMENT_NODE:
788 ASSERT(endOffset <= static_cast<CharacterData*>(container)->length());
789 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
790 RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(container->cloneNode(true));
791 deleteCharacterData(c, startOffset, endOffset, ec);
794 result->appendChild(c.release(), ec);
796 result = c.release();
798 if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
799 static_cast<CharacterData*>(container)->deleteData(startOffset, endOffset - startOffset, ec);
801 case Node::PROCESSING_INSTRUCTION_NODE:
802 ASSERT(endOffset <= static_cast<ProcessingInstruction*>(container)->data().length());
803 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
804 RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(container->cloneNode(true));
805 c->setData(c->data().substring(startOffset, endOffset - startOffset), ec);
808 result->appendChild(c.release(), ec);
810 result = c.release();
812 if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
813 ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(container);
814 String data(pi->data());
815 data.remove(startOffset, endOffset - startOffset);
816 pi->setData(data, ec);
819 case Node::ELEMENT_NODE:
820 case Node::ATTRIBUTE_NODE:
821 case Node::ENTITY_REFERENCE_NODE:
822 case Node::ENTITY_NODE:
823 case Node::DOCUMENT_NODE:
824 case Node::DOCUMENT_TYPE_NODE:
825 case Node::DOCUMENT_FRAGMENT_NODE:
826 case Node::NOTATION_NODE:
827 case Node::XPATH_NAMESPACE_NODE:
828 // FIXME: Should we assert that some nodes never appear here?
829 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
833 result = container->cloneNode(false);
836 Node* n = container->firstChild();
837 Vector<RefPtr<Node> > nodes;
838 for (unsigned i = startOffset; n && i; i--)
839 n = n->nextSibling();
840 for (unsigned i = startOffset; n && i < endOffset; i++, n = n->nextSibling())
843 processNodes(action, nodes, container, result, ec);
847 return result.release();
850 void Range::processNodes(ActionType action, Vector<RefPtr<Node> >& nodes, PassRefPtr<Node> oldContainer, PassRefPtr<Node> newContainer, ExceptionCode& ec)
852 for (unsigned i = 0; i < nodes.size(); i++) {
854 case DELETE_CONTENTS:
855 oldContainer->removeChild(nodes[i].get(), ec);
857 case EXTRACT_CONTENTS:
858 newContainer->appendChild(nodes[i].release(), ec); // will remove n from its parent
861 newContainer->appendChild(nodes[i]->cloneNode(true), ec);
867 PassRefPtr<Node> Range::processAncestorsAndTheirSiblings(ActionType action, Node* container, ContentsProcessDirection direction, PassRefPtr<Node> passedClonedContainer, Node* commonRoot, ExceptionCode& ec)
869 typedef Vector<RefPtr<Node> > NodeVector;
871 RefPtr<Node> clonedContainer = passedClonedContainer;
872 Vector<RefPtr<Node> > ancestors;
873 for (ContainerNode* n = container->parentNode(); n && n != commonRoot; n = n->parentNode())
876 RefPtr<Node> firstChildInAncestorToProcess = direction == ProcessContentsForward ? container->nextSibling() : container->previousSibling();
877 for (Vector<RefPtr<Node> >::const_iterator it = ancestors.begin(); it != ancestors.end(); ++it) {
878 RefPtr<Node> ancestor = *it;
879 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
880 if (RefPtr<Node> clonedAncestor = ancestor->cloneNode(false)) { // Might have been removed already during mutation event.
881 clonedAncestor->appendChild(clonedContainer, ec);
882 clonedContainer = clonedAncestor;
886 // Copy siblings of an ancestor of start/end containers
887 // FIXME: This assertion may fail if DOM is modified during mutation event
888 // FIXME: Share code with Range::processNodes
889 ASSERT(!firstChildInAncestorToProcess || firstChildInAncestorToProcess->parentNode() == ancestor);
892 for (Node* child = firstChildInAncestorToProcess.get(); child;
893 child = (direction == ProcessContentsForward) ? child->nextSibling() : child->previousSibling())
896 for (NodeVector::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
897 Node* child = it->get();
899 case DELETE_CONTENTS:
900 ancestor->removeChild(child, ec);
902 case EXTRACT_CONTENTS: // will remove child from ancestor
903 if (direction == ProcessContentsForward)
904 clonedContainer->appendChild(child, ec);
906 clonedContainer->insertBefore(child, clonedContainer->firstChild(), ec);
909 if (direction == ProcessContentsForward)
910 clonedContainer->appendChild(child->cloneNode(true), ec);
912 clonedContainer->insertBefore(child->cloneNode(true), clonedContainer->firstChild(), ec);
916 firstChildInAncestorToProcess = direction == ProcessContentsForward ? ancestor->nextSibling() : ancestor->previousSibling();
919 return clonedContainer.release();
922 PassRefPtr<DocumentFragment> Range::extractContents(ExceptionCode& ec)
924 checkDeleteExtract(ec);
928 return processContents(EXTRACT_CONTENTS, ec);
931 PassRefPtr<DocumentFragment> Range::cloneContents(ExceptionCode& ec)
933 if (!m_start.container()) {
934 ec = INVALID_STATE_ERR;
938 return processContents(CLONE_CONTENTS, ec);
941 void Range::insertNode(PassRefPtr<Node> prpNewNode, ExceptionCode& ec)
943 RefPtr<Node> newNode = prpNewNode;
947 if (!m_start.container()) {
948 ec = INVALID_STATE_ERR;
957 // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of
958 // the Range is read-only.
959 if (containedByReadOnly()) {
960 ec = NO_MODIFICATION_ALLOWED_ERR;
964 // HIERARCHY_REQUEST_ERR: Raised if the container of the start of the Range is of a type that
965 // does not allow children of the type of newNode or if newNode is an ancestor of the container.
967 // an extra one here - if a text node is going to split, it must have a parent to insert into
968 bool startIsText = m_start.container()->isTextNode();
969 if (startIsText && !m_start.container()->parentNode()) {
970 ec = HIERARCHY_REQUEST_ERR;
974 // In the case where the container is a text node, we check against the container's parent, because
975 // text nodes get split up upon insertion.
978 checkAgainst = m_start.container()->parentNode();
980 checkAgainst = m_start.container();
982 Node::NodeType newNodeType = newNode->nodeType();
984 if (newNodeType == Node::DOCUMENT_FRAGMENT_NODE && !newNode->isShadowRoot()) {
985 // check each child node, not the DocumentFragment itself
987 for (Node* c = newNode->firstChild(); c; c = c->nextSibling()) {
988 if (!checkAgainst->childTypeAllowed(c->nodeType())) {
989 ec = HIERARCHY_REQUEST_ERR;
996 if (!checkAgainst->childTypeAllowed(newNodeType)) {
997 ec = HIERARCHY_REQUEST_ERR;
1002 for (Node* n = m_start.container(); n; n = n->parentNode()) {
1004 ec = HIERARCHY_REQUEST_ERR;
1009 // INVALID_NODE_TYPE_ERR: Raised if newNode is an Attr, Entity, Notation, ShadowRoot or Document node.
1010 switch (newNodeType) {
1011 case Node::ATTRIBUTE_NODE:
1012 case Node::ENTITY_NODE:
1013 case Node::NOTATION_NODE:
1014 case Node::DOCUMENT_NODE:
1015 ec = RangeException::INVALID_NODE_TYPE_ERR;
1018 if (newNode->isShadowRoot()) {
1019 ec = RangeException::INVALID_NODE_TYPE_ERR;
1025 EventQueueScope scope;
1026 bool collapsed = m_start == m_end;
1027 RefPtr<Node> container;
1029 container = m_start.container();
1030 RefPtr<Text> newText = toText(container.get())->splitText(m_start.offset(), ec);
1034 container = m_start.container();
1035 container->parentNode()->insertBefore(newNode.release(), newText.get(), ec);
1040 m_end.setToBeforeChild(newText.get());
1042 RefPtr<Node> lastChild;
1044 lastChild = (newNodeType == Node::DOCUMENT_FRAGMENT_NODE) ? newNode->lastChild() : newNode;
1046 int startOffset = m_start.offset();
1047 container = m_start.container();
1048 container->insertBefore(newNode.release(), container->childNode(startOffset), ec);
1052 if (collapsed && numNewChildren)
1053 m_end.set(m_start.container(), startOffset + numNewChildren, lastChild.get());
1057 String Range::toString(ExceptionCode& ec) const
1059 if (!m_start.container()) {
1060 ec = INVALID_STATE_ERR;
1064 StringBuilder builder;
1066 Node* pastLast = pastLastNode();
1067 for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(n)) {
1068 if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE) {
1069 String data = static_cast<CharacterData*>(n)->data();
1070 int length = data.length();
1071 int start = (n == m_start.container()) ? min(max(0, m_start.offset()), length) : 0;
1072 int end = (n == m_end.container()) ? min(max(start, m_end.offset()), length) : length;
1073 builder.append(data.characters() + start, end - start);
1077 return builder.toString();
1080 String Range::toHTML() const
1082 return createMarkup(this);
1085 String Range::text() const
1087 if (!m_start.container())
1090 // We need to update layout, since plainText uses line boxes in the render tree.
1091 // FIXME: As with innerText, we'd like this to work even if there are no render objects.
1092 m_start.container()->document()->updateLayout();
1094 return plainText(this);
1097 PassRefPtr<DocumentFragment> Range::createContextualFragment(const String& markup, ExceptionCode& ec)
1099 if (!m_start.container()) {
1100 ec = INVALID_STATE_ERR;
1104 Node* element = m_start.container()->isElementNode() ? m_start.container() : m_start.container()->parentNode();
1105 if (!element || !element->isHTMLElement()) {
1106 ec = NOT_SUPPORTED_ERR;
1110 RefPtr<DocumentFragment> fragment = WebCore::createContextualFragment(markup, toHTMLElement(element), AllowScriptingContentAndDoNotMarkAlreadyStarted, ec);
1114 return fragment.release();
1118 void Range::detach(ExceptionCode& ec)
1120 // Check first to see if we've already detached:
1121 if (!m_start.container()) {
1122 ec = INVALID_STATE_ERR;
1126 m_ownerDocument->detachRange(this);
1132 Node* Range::checkNodeWOffset(Node* n, int offset, ExceptionCode& ec) const
1134 switch (n->nodeType()) {
1135 case Node::DOCUMENT_TYPE_NODE:
1136 case Node::ENTITY_NODE:
1137 case Node::NOTATION_NODE:
1138 ec = RangeException::INVALID_NODE_TYPE_ERR;
1140 case Node::CDATA_SECTION_NODE:
1141 case Node::COMMENT_NODE:
1142 case Node::TEXT_NODE:
1143 if (static_cast<unsigned>(offset) > static_cast<CharacterData*>(n)->length())
1144 ec = INDEX_SIZE_ERR;
1146 case Node::PROCESSING_INSTRUCTION_NODE:
1147 if (static_cast<unsigned>(offset) > static_cast<ProcessingInstruction*>(n)->data().length())
1148 ec = INDEX_SIZE_ERR;
1150 case Node::ATTRIBUTE_NODE:
1151 case Node::DOCUMENT_FRAGMENT_NODE:
1152 case Node::DOCUMENT_NODE:
1153 case Node::ELEMENT_NODE:
1154 case Node::ENTITY_REFERENCE_NODE:
1155 case Node::XPATH_NAMESPACE_NODE: {
1158 Node* childBefore = n->childNode(offset - 1);
1160 ec = INDEX_SIZE_ERR;
1164 ASSERT_NOT_REACHED();
1168 void Range::checkNodeBA(Node* n, ExceptionCode& ec) const
1170 // INVALID_NODE_TYPE_ERR: Raised if the root container of refNode is not an
1171 // Attr, Document, DocumentFragment or ShadowRoot node, or part of a SVG shadow DOM tree,
1172 // or if refNode is a Document, DocumentFragment, ShadowRoot, Attr, Entity, or Notation node.
1174 switch (n->nodeType()) {
1175 case Node::ATTRIBUTE_NODE:
1176 case Node::DOCUMENT_FRAGMENT_NODE:
1177 case Node::DOCUMENT_NODE:
1178 case Node::ENTITY_NODE:
1179 case Node::NOTATION_NODE:
1180 ec = RangeException::INVALID_NODE_TYPE_ERR;
1182 case Node::CDATA_SECTION_NODE:
1183 case Node::COMMENT_NODE:
1184 case Node::DOCUMENT_TYPE_NODE:
1185 case Node::ELEMENT_NODE:
1186 case Node::ENTITY_REFERENCE_NODE:
1187 case Node::PROCESSING_INSTRUCTION_NODE:
1188 case Node::TEXT_NODE:
1189 case Node::XPATH_NAMESPACE_NODE:
1194 while (ContainerNode* parent = root->parentNode())
1197 switch (root->nodeType()) {
1198 case Node::ATTRIBUTE_NODE:
1199 case Node::DOCUMENT_NODE:
1200 case Node::DOCUMENT_FRAGMENT_NODE:
1202 case Node::CDATA_SECTION_NODE:
1203 case Node::COMMENT_NODE:
1204 case Node::DOCUMENT_TYPE_NODE:
1205 case Node::ELEMENT_NODE:
1206 case Node::ENTITY_NODE:
1207 case Node::ENTITY_REFERENCE_NODE:
1208 case Node::NOTATION_NODE:
1209 case Node::PROCESSING_INSTRUCTION_NODE:
1210 case Node::TEXT_NODE:
1211 case Node::XPATH_NAMESPACE_NODE:
1212 ec = RangeException::INVALID_NODE_TYPE_ERR;
1217 PassRefPtr<Range> Range::cloneRange(ExceptionCode& ec) const
1219 if (!m_start.container()) {
1220 ec = INVALID_STATE_ERR;
1224 return Range::create(m_ownerDocument, m_start.container(), m_start.offset(), m_end.container(), m_end.offset());
1227 void Range::setStartAfter(Node* refNode, ExceptionCode& ec)
1229 if (!m_start.container()) {
1230 ec = INVALID_STATE_ERR;
1240 checkNodeBA(refNode, ec);
1244 setStart(refNode->parentNode(), refNode->nodeIndex() + 1, ec);
1247 void Range::setEndBefore(Node* refNode, ExceptionCode& ec)
1249 if (!m_start.container()) {
1250 ec = INVALID_STATE_ERR;
1260 checkNodeBA(refNode, ec);
1264 setEnd(refNode->parentNode(), refNode->nodeIndex(), ec);
1267 void Range::setEndAfter(Node* refNode, ExceptionCode& ec)
1269 if (!m_start.container()) {
1270 ec = INVALID_STATE_ERR;
1280 checkNodeBA(refNode, ec);
1284 setEnd(refNode->parentNode(), refNode->nodeIndex() + 1, ec);
1287 void Range::selectNode(Node* refNode, ExceptionCode& ec)
1289 if (!m_start.container()) {
1290 ec = INVALID_STATE_ERR;
1299 // INVALID_NODE_TYPE_ERR: Raised if an ancestor of refNode is an Entity, Notation or
1300 // DocumentType node or if refNode is a Document, DocumentFragment, ShadowRoot, Attr, Entity, or Notation
1302 for (ContainerNode* anc = refNode->parentNode(); anc; anc = anc->parentNode()) {
1303 switch (anc->nodeType()) {
1304 case Node::ATTRIBUTE_NODE:
1305 case Node::CDATA_SECTION_NODE:
1306 case Node::COMMENT_NODE:
1307 case Node::DOCUMENT_FRAGMENT_NODE:
1308 case Node::DOCUMENT_NODE:
1309 case Node::ELEMENT_NODE:
1310 case Node::ENTITY_REFERENCE_NODE:
1311 case Node::PROCESSING_INSTRUCTION_NODE:
1312 case Node::TEXT_NODE:
1313 case Node::XPATH_NAMESPACE_NODE:
1315 case Node::DOCUMENT_TYPE_NODE:
1316 case Node::ENTITY_NODE:
1317 case Node::NOTATION_NODE:
1318 ec = RangeException::INVALID_NODE_TYPE_ERR;
1323 switch (refNode->nodeType()) {
1324 case Node::CDATA_SECTION_NODE:
1325 case Node::COMMENT_NODE:
1326 case Node::DOCUMENT_TYPE_NODE:
1327 case Node::ELEMENT_NODE:
1328 case Node::ENTITY_REFERENCE_NODE:
1329 case Node::PROCESSING_INSTRUCTION_NODE:
1330 case Node::TEXT_NODE:
1331 case Node::XPATH_NAMESPACE_NODE:
1333 case Node::ATTRIBUTE_NODE:
1334 case Node::DOCUMENT_FRAGMENT_NODE:
1335 case Node::DOCUMENT_NODE:
1336 case Node::ENTITY_NODE:
1337 case Node::NOTATION_NODE:
1338 ec = RangeException::INVALID_NODE_TYPE_ERR;
1342 if (m_ownerDocument != refNode->document())
1343 setDocument(refNode->document());
1346 setStartBefore(refNode, ec);
1349 setEndAfter(refNode, ec);
1352 void Range::selectNodeContents(Node* refNode, ExceptionCode& ec)
1354 if (!m_start.container()) {
1355 ec = INVALID_STATE_ERR;
1364 // INVALID_NODE_TYPE_ERR: Raised if refNode or an ancestor of refNode is an Entity, Notation
1365 // or DocumentType node.
1366 for (Node* n = refNode; n; n = n->parentNode()) {
1367 switch (n->nodeType()) {
1368 case Node::ATTRIBUTE_NODE:
1369 case Node::CDATA_SECTION_NODE:
1370 case Node::COMMENT_NODE:
1371 case Node::DOCUMENT_FRAGMENT_NODE:
1372 case Node::DOCUMENT_NODE:
1373 case Node::ELEMENT_NODE:
1374 case Node::ENTITY_REFERENCE_NODE:
1375 case Node::PROCESSING_INSTRUCTION_NODE:
1376 case Node::TEXT_NODE:
1377 case Node::XPATH_NAMESPACE_NODE:
1379 case Node::DOCUMENT_TYPE_NODE:
1380 case Node::ENTITY_NODE:
1381 case Node::NOTATION_NODE:
1382 ec = RangeException::INVALID_NODE_TYPE_ERR;
1387 if (m_ownerDocument != refNode->document())
1388 setDocument(refNode->document());
1390 m_start.setToStartOfNode(refNode);
1391 m_end.setToEndOfNode(refNode);
1394 void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec)
1396 RefPtr<Node> newParent = passNewParent;
1398 if (!m_start.container()) {
1399 ec = INVALID_STATE_ERR;
1408 // INVALID_NODE_TYPE_ERR: Raised if node is an Attr, Entity, DocumentType, Notation,
1409 // Document, or DocumentFragment node.
1410 switch (newParent->nodeType()) {
1411 case Node::ATTRIBUTE_NODE:
1412 case Node::DOCUMENT_FRAGMENT_NODE:
1413 case Node::DOCUMENT_NODE:
1414 case Node::DOCUMENT_TYPE_NODE:
1415 case Node::ENTITY_NODE:
1416 case Node::NOTATION_NODE:
1417 ec = RangeException::INVALID_NODE_TYPE_ERR;
1419 case Node::CDATA_SECTION_NODE:
1420 case Node::COMMENT_NODE:
1421 case Node::ELEMENT_NODE:
1422 case Node::ENTITY_REFERENCE_NODE:
1423 case Node::PROCESSING_INSTRUCTION_NODE:
1424 case Node::TEXT_NODE:
1425 case Node::XPATH_NAMESPACE_NODE:
1429 // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of
1430 // the Range is read-only.
1431 if (containedByReadOnly()) {
1432 ec = NO_MODIFICATION_ALLOWED_ERR;
1436 // Raise a HIERARCHY_REQUEST_ERR if m_start.container() doesn't accept children like newParent.
1437 Node* parentOfNewParent = m_start.container();
1439 // If m_start.container() is a character data node, it will be split and it will be its parent that will
1440 // need to accept newParent (or in the case of a comment, it logically "would" be inserted into the parent,
1441 // although this will fail below for another reason).
1442 if (parentOfNewParent->isCharacterDataNode())
1443 parentOfNewParent = parentOfNewParent->parentNode();
1444 if (!parentOfNewParent || !parentOfNewParent->childTypeAllowed(newParent->nodeType())) {
1445 ec = HIERARCHY_REQUEST_ERR;
1449 if (newParent->contains(m_start.container())) {
1450 ec = HIERARCHY_REQUEST_ERR;
1454 // FIXME: Do we need a check if the node would end up with a child node of a type not
1455 // allowed by the type of node?
1457 // BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially selects a non-Text node.
1458 Node* startNonTextContainer = m_start.container();
1459 if (startNonTextContainer->nodeType() == Node::TEXT_NODE)
1460 startNonTextContainer = startNonTextContainer->parentNode();
1461 Node* endNonTextContainer = m_end.container();
1462 if (endNonTextContainer->nodeType() == Node::TEXT_NODE)
1463 endNonTextContainer = endNonTextContainer->parentNode();
1464 if (startNonTextContainer != endNonTextContainer) {
1465 ec = RangeException::BAD_BOUNDARYPOINTS_ERR;
1470 while (Node* n = newParent->firstChild()) {
1471 toContainerNode(newParent.get())->removeChild(n, ec);
1475 RefPtr<DocumentFragment> fragment = extractContents(ec);
1478 insertNode(newParent, ec);
1481 newParent->appendChild(fragment.release(), ec);
1484 selectNode(newParent.get(), ec);
1487 void Range::setStartBefore(Node* refNode, ExceptionCode& ec)
1489 if (!m_start.container()) {
1490 ec = INVALID_STATE_ERR;
1500 checkNodeBA(refNode, ec);
1504 setStart(refNode->parentNode(), refNode->nodeIndex(), ec);
1507 void Range::checkDeleteExtract(ExceptionCode& ec)
1509 if (!m_start.container()) {
1510 ec = INVALID_STATE_ERR;
1515 if (!commonAncestorContainer(ec) || ec)
1518 Node* pastLast = pastLastNode();
1519 for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(n)) {
1520 if (n->isReadOnlyNode()) {
1521 ec = NO_MODIFICATION_ALLOWED_ERR;
1524 if (n->nodeType() == Node::DOCUMENT_TYPE_NODE) {
1525 ec = HIERARCHY_REQUEST_ERR;
1530 if (containedByReadOnly()) {
1531 ec = NO_MODIFICATION_ALLOWED_ERR;
1536 bool Range::containedByReadOnly() const
1538 for (Node* n = m_start.container(); n; n = n->parentNode()) {
1539 if (n->isReadOnlyNode())
1542 for (Node* n = m_end.container(); n; n = n->parentNode()) {
1543 if (n->isReadOnlyNode())
1549 Node* Range::firstNode() const
1551 if (!m_start.container())
1553 if (m_start.container()->offsetInCharacters())
1554 return m_start.container();
1555 if (Node* child = m_start.container()->childNode(m_start.offset()))
1557 if (!m_start.offset())
1558 return m_start.container();
1559 return NodeTraversal::nextSkippingChildren(m_start.container());
1562 ShadowRoot* Range::shadowRoot() const
1564 return startContainer() ? startContainer()->containingShadowRoot() : 0;
1567 Node* Range::pastLastNode() const
1569 if (!m_start.container() || !m_end.container())
1571 if (m_end.container()->offsetInCharacters())
1572 return NodeTraversal::nextSkippingChildren(m_end.container());
1573 if (Node* child = m_end.container()->childNode(m_end.offset()))
1575 return NodeTraversal::nextSkippingChildren(m_end.container());
1578 IntRect Range::boundingBox() const
1581 Vector<IntRect> rects;
1583 const size_t n = rects.size();
1584 for (size_t i = 0; i < n; ++i)
1585 result.unite(rects[i]);
1589 void Range::textRects(Vector<IntRect>& rects, bool useSelectionHeight, RangeInFixedPosition* inFixed) const
1591 Node* startContainer = m_start.container();
1592 Node* endContainer = m_end.container();
1594 if (!startContainer || !endContainer) {
1596 *inFixed = NotFixedPosition;
1600 bool allFixed = true;
1601 bool someFixed = false;
1603 Node* stopNode = pastLastNode();
1604 for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next(node)) {
1605 RenderObject* r = node->renderer();
1606 if (!r || !r->isText())
1608 RenderText* renderText = toRenderText(r);
1609 int startOffset = node == startContainer ? m_start.offset() : 0;
1610 int endOffset = node == endContainer ? m_end.offset() : numeric_limits<int>::max();
1611 bool isFixed = false;
1612 renderText->absoluteRectsForRange(rects, startOffset, endOffset, useSelectionHeight, &isFixed);
1613 allFixed &= isFixed;
1614 someFixed |= isFixed;
1618 *inFixed = allFixed ? EntirelyFixedPosition : (someFixed ? PartiallyFixedPosition : NotFixedPosition);
1621 void Range::textQuads(Vector<FloatQuad>& quads, bool useSelectionHeight, RangeInFixedPosition* inFixed) const
1623 Node* startContainer = m_start.container();
1624 Node* endContainer = m_end.container();
1626 if (!startContainer || !endContainer) {
1628 *inFixed = NotFixedPosition;
1632 bool allFixed = true;
1633 bool someFixed = false;
1635 Node* stopNode = pastLastNode();
1636 for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next(node)) {
1637 RenderObject* r = node->renderer();
1638 if (!r || !r->isText())
1640 RenderText* renderText = toRenderText(r);
1641 int startOffset = node == startContainer ? m_start.offset() : 0;
1642 int endOffset = node == endContainer ? m_end.offset() : numeric_limits<int>::max();
1643 bool isFixed = false;
1644 renderText->absoluteQuadsForRange(quads, startOffset, endOffset, useSelectionHeight, &isFixed);
1645 allFixed &= isFixed;
1646 someFixed |= isFixed;
1650 *inFixed = allFixed ? EntirelyFixedPosition : (someFixed ? PartiallyFixedPosition : NotFixedPosition);
1654 void Range::formatForDebugger(char* buffer, unsigned length) const
1656 StringBuilder result;
1659 if (!m_start.container() || !m_end.container())
1660 result.appendLiteral("<empty>");
1662 const int FormatBufferSize = 1024;
1663 char s[FormatBufferSize];
1664 result.appendLiteral("from offset ");
1665 result.appendNumber(m_start.offset());
1666 result.appendLiteral(" of ");
1667 m_start.container()->formatForDebugger(s, FormatBufferSize);
1669 result.appendLiteral(" to offset ");
1670 result.appendNumber(m_end.offset());
1671 result.appendLiteral(" of ");
1672 m_end.container()->formatForDebugger(s, FormatBufferSize);
1676 strncpy(buffer, result.toString().utf8().data(), length - 1);
1680 bool areRangesEqual(const Range* a, const Range* b)
1686 return a->startPosition() == b->startPosition() && a->endPosition() == b->endPosition();
1689 PassRefPtr<Range> rangeOfContents(Node* node)
1692 RefPtr<Range> range = Range::create(node->document());
1694 range->selectNodeContents(node, exception);
1695 return range.release();
1698 int Range::maxStartOffset() const
1700 if (!m_start.container())
1702 if (!m_start.container()->offsetInCharacters())
1703 return m_start.container()->childNodeCount();
1704 return m_start.container()->maxCharacterOffset();
1707 int Range::maxEndOffset() const
1709 if (!m_end.container())
1711 if (!m_end.container()->offsetInCharacters())
1712 return m_end.container()->childNodeCount();
1713 return m_end.container()->maxCharacterOffset();
1716 static inline void boundaryNodeChildrenChanged(RangeBoundaryPoint& boundary, ContainerNode* container)
1718 if (!boundary.childBefore())
1720 if (boundary.container() != container)
1722 boundary.invalidateOffset();
1725 void Range::nodeChildrenChanged(ContainerNode* container)
1728 ASSERT(container->document() == m_ownerDocument);
1729 boundaryNodeChildrenChanged(m_start, container);
1730 boundaryNodeChildrenChanged(m_end, container);
1733 static inline void boundaryNodeChildrenWillBeRemoved(RangeBoundaryPoint& boundary, ContainerNode* container)
1735 for (Node* nodeToBeRemoved = container->firstChild(); nodeToBeRemoved; nodeToBeRemoved = nodeToBeRemoved->nextSibling()) {
1736 if (boundary.childBefore() == nodeToBeRemoved) {
1737 boundary.setToStartOfNode(container);
1741 for (Node* n = boundary.container(); n; n = n->parentNode()) {
1742 if (n == nodeToBeRemoved) {
1743 boundary.setToStartOfNode(container);
1750 void Range::nodeChildrenWillBeRemoved(ContainerNode* container)
1753 ASSERT(container->document() == m_ownerDocument);
1754 boundaryNodeChildrenWillBeRemoved(m_start, container);
1755 boundaryNodeChildrenWillBeRemoved(m_end, container);
1758 static inline void boundaryNodeWillBeRemoved(RangeBoundaryPoint& boundary, Node* nodeToBeRemoved)
1760 if (boundary.childBefore() == nodeToBeRemoved) {
1761 boundary.childBeforeWillBeRemoved();
1765 for (Node* n = boundary.container(); n; n = n->parentNode()) {
1766 if (n == nodeToBeRemoved) {
1767 boundary.setToBeforeChild(nodeToBeRemoved);
1773 void Range::nodeWillBeRemoved(Node* node)
1776 ASSERT(node->document() == m_ownerDocument);
1777 ASSERT(node != m_ownerDocument);
1778 ASSERT(node->parentNode());
1779 boundaryNodeWillBeRemoved(m_start, node);
1780 boundaryNodeWillBeRemoved(m_end, node);
1783 static inline void boundaryTextInserted(RangeBoundaryPoint& boundary, Node* text, unsigned offset, unsigned length)
1785 if (boundary.container() != text)
1787 unsigned boundaryOffset = boundary.offset();
1788 if (offset >= boundaryOffset)
1790 boundary.setOffset(boundaryOffset + length);
1793 void Range::textInserted(Node* text, unsigned offset, unsigned length)
1796 ASSERT(text->document() == m_ownerDocument);
1797 boundaryTextInserted(m_start, text, offset, length);
1798 boundaryTextInserted(m_end, text, offset, length);
1801 static inline void boundaryTextRemoved(RangeBoundaryPoint& boundary, Node* text, unsigned offset, unsigned length)
1803 if (boundary.container() != text)
1805 unsigned boundaryOffset = boundary.offset();
1806 if (offset >= boundaryOffset)
1808 if (offset + length >= boundaryOffset)
1809 boundary.setOffset(offset);
1811 boundary.setOffset(boundaryOffset - length);
1814 void Range::textRemoved(Node* text, unsigned offset, unsigned length)
1817 ASSERT(text->document() == m_ownerDocument);
1818 boundaryTextRemoved(m_start, text, offset, length);
1819 boundaryTextRemoved(m_end, text, offset, length);
1822 static inline void boundaryTextNodesMerged(RangeBoundaryPoint& boundary, NodeWithIndex& oldNode, unsigned offset)
1824 if (boundary.container() == oldNode.node())
1825 boundary.set(oldNode.node()->previousSibling(), boundary.offset() + offset, 0);
1826 else if (boundary.container() == oldNode.node()->parentNode() && boundary.offset() == oldNode.index())
1827 boundary.set(oldNode.node()->previousSibling(), offset, 0);
1830 void Range::textNodesMerged(NodeWithIndex& oldNode, unsigned offset)
1832 ASSERT(oldNode.node());
1833 ASSERT(oldNode.node()->document() == m_ownerDocument);
1834 ASSERT(oldNode.node()->parentNode());
1835 ASSERT(oldNode.node()->isTextNode());
1836 ASSERT(oldNode.node()->previousSibling());
1837 ASSERT(oldNode.node()->previousSibling()->isTextNode());
1838 boundaryTextNodesMerged(m_start, oldNode, offset);
1839 boundaryTextNodesMerged(m_end, oldNode, offset);
1842 static inline void boundaryTextNodesSplit(RangeBoundaryPoint& boundary, Text* oldNode)
1844 if (boundary.container() != oldNode)
1846 unsigned boundaryOffset = boundary.offset();
1847 if (boundaryOffset <= oldNode->length())
1849 boundary.set(oldNode->nextSibling(), boundaryOffset - oldNode->length(), 0);
1852 void Range::textNodeSplit(Text* oldNode)
1855 ASSERT(oldNode->document() == m_ownerDocument);
1856 ASSERT(oldNode->parentNode());
1857 ASSERT(oldNode->isTextNode());
1858 ASSERT(oldNode->nextSibling());
1859 ASSERT(oldNode->nextSibling()->isTextNode());
1860 boundaryTextNodesSplit(m_start, oldNode);
1861 boundaryTextNodesSplit(m_end, oldNode);
1864 void Range::expand(const String& unit, ExceptionCode& ec)
1866 VisiblePosition start(startPosition());
1867 VisiblePosition end(endPosition());
1868 if (unit == "word") {
1869 start = startOfWord(start);
1870 end = endOfWord(end);
1871 } else if (unit == "sentence") {
1872 start = startOfSentence(start);
1873 end = endOfSentence(end);
1874 } else if (unit == "block") {
1875 start = startOfParagraph(start);
1876 end = endOfParagraph(end);
1877 } else if (unit == "document") {
1878 start = startOfDocument(start);
1879 end = endOfDocument(end);
1882 setStart(start.deepEquivalent().containerNode(), start.deepEquivalent().computeOffsetInContainerNode(), ec);
1883 setEnd(end.deepEquivalent().containerNode(), end.deepEquivalent().computeOffsetInContainerNode(), ec);
1886 PassRefPtr<ClientRectList> Range::getClientRects() const
1888 if (!m_start.container())
1889 return ClientRectList::create();
1891 m_ownerDocument->updateLayoutIgnorePendingStylesheets();
1893 Vector<FloatQuad> quads;
1894 getBorderAndTextQuads(quads);
1896 return ClientRectList::create(quads);
1899 PassRefPtr<ClientRect> Range::getBoundingClientRect() const
1901 return ClientRect::create(boundingRect());
1904 void Range::getBorderAndTextQuads(Vector<FloatQuad>& quads) const
1906 Node* startContainer = m_start.container();
1907 Node* endContainer = m_end.container();
1908 Node* stopNode = pastLastNode();
1910 HashSet<Node*> selectedElementsSet;
1911 for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next(node)) {
1912 if (node->isElementNode())
1913 selectedElementsSet.add(node);
1916 // Don't include elements that are only partially selected.
1917 Node* lastNode = m_end.childBefore() ? m_end.childBefore() : endContainer;
1918 for (Node* parent = lastNode->parentNode(); parent; parent = parent->parentNode())
1919 selectedElementsSet.remove(parent);
1921 for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next(node)) {
1922 if (node->isElementNode() && selectedElementsSet.contains(node) && !selectedElementsSet.contains(node->parentNode())) {
1923 if (RenderBoxModelObject* renderBoxModelObject = toElement(node)->renderBoxModelObject()) {
1924 Vector<FloatQuad> elementQuads;
1925 renderBoxModelObject->absoluteQuads(elementQuads);
1926 m_ownerDocument->adjustFloatQuadsForScrollAndAbsoluteZoomAndFrameScale(elementQuads, renderBoxModelObject);
1928 quads.appendVector(elementQuads);
1930 } else if (node->isTextNode()) {
1931 if (RenderObject* renderer = toText(node)->renderer()) {
1932 RenderText* renderText = toRenderText(renderer);
1933 int startOffset = (node == startContainer) ? m_start.offset() : 0;
1934 int endOffset = (node == endContainer) ? m_end.offset() : INT_MAX;
1936 Vector<FloatQuad> textQuads;
1937 renderText->absoluteQuadsForRange(textQuads, startOffset, endOffset);
1938 m_ownerDocument->adjustFloatQuadsForScrollAndAbsoluteZoomAndFrameScale(textQuads, renderText);
1940 quads.appendVector(textQuads);
1946 FloatRect Range::boundingRect() const
1948 if (!m_start.container())
1951 m_ownerDocument->updateLayoutIgnorePendingStylesheets();
1953 Vector<FloatQuad> quads;
1954 getBorderAndTextQuads(quads);
1955 if (quads.isEmpty())
1959 for (size_t i = 0; i < quads.size(); ++i)
1960 result.unite(quads[i].boundingBox());
1965 } // namespace WebCore
1969 void showTree(const WebCore::Range* range)
1971 if (range && range->boundaryPointsValid()) {
1972 range->startContainer()->showTreeAndMark(range->startContainer(), "S", range->endContainer(), "E");
1973 fprintf(stderr, "start offset: %d, end offset: %d\n", range->startOffset(), range->endOffset());