Home | History | Annotate | Download | only in dom
      1 /*
      2  * (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  * (C) 2000 Gunnstein Lye (gunnstein (at) netcom.no)
      4  * (C) 2000 Frederik Holljen (frederik.holljen (at) hig.no)
      5  * (C) 2001 Peter Kelly (pmk (at) 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.
      8  *
      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.
     13  *
     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.
     18  *
     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.
     23  */
     24 
     25 #include "config.h"
     26 #include "core/dom/Range.h"
     27 
     28 #include "bindings/v8/ExceptionState.h"
     29 #include "core/dom/ClientRect.h"
     30 #include "core/dom/ClientRectList.h"
     31 #include "core/dom/DocumentFragment.h"
     32 #include "core/dom/ExceptionCode.h"
     33 #include "core/dom/Node.h"
     34 #include "core/dom/NodeTraversal.h"
     35 #include "core/dom/NodeWithIndex.h"
     36 #include "core/dom/ProcessingInstruction.h"
     37 #include "core/dom/Text.h"
     38 #include "core/editing/TextIterator.h"
     39 #include "core/editing/VisiblePosition.h"
     40 #include "core/editing/VisibleUnits.h"
     41 #include "core/editing/markup.h"
     42 #include "core/events/ScopedEventQueue.h"
     43 #include "core/html/HTMLElement.h"
     44 #include "core/rendering/RenderBoxModelObject.h"
     45 #include "core/rendering/RenderText.h"
     46 #include "platform/geometry/FloatQuad.h"
     47 #include "wtf/RefCountedLeakCounter.h"
     48 #include "wtf/text/CString.h"
     49 #include "wtf/text/StringBuilder.h"
     50 #ifndef NDEBUG
     51 #include <stdio.h>
     52 #endif
     53 
     54 namespace WebCore {
     55 
     56 using namespace HTMLNames;
     57 
     58 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, rangeCounter, ("Range"));
     59 
     60 inline Range::Range(Document& ownerDocument)
     61     : m_ownerDocument(&ownerDocument)
     62     , m_start(m_ownerDocument)
     63     , m_end(m_ownerDocument)
     64 {
     65 #ifndef NDEBUG
     66     rangeCounter.increment();
     67 #endif
     68 
     69     ScriptWrappable::init(this);
     70     m_ownerDocument->attachRange(this);
     71 }
     72 
     73 PassRefPtrWillBeRawPtr<Range> Range::create(Document& ownerDocument)
     74 {
     75     return adoptRefWillBeNoop(new Range(ownerDocument));
     76 }
     77 
     78 inline Range::Range(Document& ownerDocument, Node* startContainer, int startOffset, Node* endContainer, int endOffset)
     79     : m_ownerDocument(&ownerDocument)
     80     , m_start(m_ownerDocument)
     81     , m_end(m_ownerDocument)
     82 {
     83 #ifndef NDEBUG
     84     rangeCounter.increment();
     85 #endif
     86 
     87     ScriptWrappable::init(this);
     88     m_ownerDocument->attachRange(this);
     89 
     90     // Simply setting the containers and offsets directly would not do any of the checking
     91     // that setStart and setEnd do, so we call those functions.
     92     setStart(startContainer, startOffset);
     93     setEnd(endContainer, endOffset);
     94 }
     95 
     96 PassRefPtrWillBeRawPtr<Range> Range::create(Document& ownerDocument, Node* startContainer, int startOffset, Node* endContainer, int endOffset)
     97 {
     98     return adoptRefWillBeNoop(new Range(ownerDocument, startContainer, startOffset, endContainer, endOffset));
     99 }
    100 
    101 PassRefPtrWillBeRawPtr<Range> Range::create(Document& ownerDocument, const Position& start, const Position& end)
    102 {
    103     return adoptRefWillBeNoop(new Range(ownerDocument, start.containerNode(), start.computeOffsetInContainerNode(), end.containerNode(), end.computeOffsetInContainerNode()));
    104 }
    105 
    106 Range::~Range()
    107 {
    108 #if !ENABLE(OILPAN)
    109     // Always detach (even if we've already detached) to fix https://bugs.webkit.org/show_bug.cgi?id=26044
    110     m_ownerDocument->detachRange(this);
    111 #endif
    112 
    113 #ifndef NDEBUG
    114     rangeCounter.decrement();
    115 #endif
    116 }
    117 
    118 void Range::setDocument(Document& document)
    119 {
    120     ASSERT(m_ownerDocument != document);
    121     ASSERT(m_ownerDocument);
    122     m_ownerDocument->detachRange(this);
    123     m_ownerDocument = &document;
    124     m_start.setToStartOfNode(document);
    125     m_end.setToStartOfNode(document);
    126     m_ownerDocument->attachRange(this);
    127 }
    128 
    129 Node* Range::commonAncestorContainer() const
    130 {
    131     return commonAncestorContainer(m_start.container(), m_end.container());
    132 }
    133 
    134 Node* Range::commonAncestorContainer(Node* containerA, Node* containerB)
    135 {
    136     for (Node* parentA = containerA; parentA; parentA = parentA->parentNode()) {
    137         for (Node* parentB = containerB; parentB; parentB = parentB->parentNode()) {
    138             if (parentA == parentB)
    139                 return parentA;
    140         }
    141     }
    142     return 0;
    143 }
    144 
    145 static inline bool checkForDifferentRootContainer(const RangeBoundaryPoint& start, const RangeBoundaryPoint& end)
    146 {
    147     Node* endRootContainer = end.container();
    148     while (endRootContainer->parentNode())
    149         endRootContainer = endRootContainer->parentNode();
    150     Node* startRootContainer = start.container();
    151     while (startRootContainer->parentNode())
    152         startRootContainer = startRootContainer->parentNode();
    153 
    154     return startRootContainer != endRootContainer || (Range::compareBoundaryPoints(start, end, ASSERT_NO_EXCEPTION) > 0);
    155 }
    156 
    157 void Range::setStart(PassRefPtrWillBeRawPtr<Node> refNode, int offset, ExceptionState& exceptionState)
    158 {
    159     if (!refNode) {
    160         exceptionState.throwDOMException(NotFoundError, "The node provided was null.");
    161         return;
    162     }
    163 
    164     bool didMoveDocument = false;
    165     if (refNode->document() != m_ownerDocument) {
    166         setDocument(refNode->document());
    167         didMoveDocument = true;
    168     }
    169 
    170     Node* childNode = checkNodeWOffset(refNode.get(), offset, exceptionState);
    171     if (exceptionState.hadException())
    172         return;
    173 
    174     m_start.set(refNode, offset, childNode);
    175 
    176     if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end))
    177         collapse(true);
    178 }
    179 
    180 void Range::setEnd(PassRefPtrWillBeRawPtr<Node> refNode, int offset, ExceptionState& exceptionState)
    181 {
    182     if (!refNode) {
    183         exceptionState.throwDOMException(NotFoundError, "The node provided was null.");
    184         return;
    185     }
    186 
    187     bool didMoveDocument = false;
    188     if (refNode->document() != m_ownerDocument) {
    189         setDocument(refNode->document());
    190         didMoveDocument = true;
    191     }
    192 
    193     Node* childNode = checkNodeWOffset(refNode.get(), offset, exceptionState);
    194     if (exceptionState.hadException())
    195         return;
    196 
    197     m_end.set(refNode, offset, childNode);
    198 
    199     if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end))
    200         collapse(false);
    201 }
    202 
    203 void Range::setStart(const Position& start, ExceptionState& exceptionState)
    204 {
    205     Position parentAnchored = start.parentAnchoredEquivalent();
    206     setStart(parentAnchored.containerNode(), parentAnchored.offsetInContainerNode(), exceptionState);
    207 }
    208 
    209 void Range::setEnd(const Position& end, ExceptionState& exceptionState)
    210 {
    211     Position parentAnchored = end.parentAnchoredEquivalent();
    212     setEnd(parentAnchored.containerNode(), parentAnchored.offsetInContainerNode(), exceptionState);
    213 }
    214 
    215 void Range::collapse(bool toStart)
    216 {
    217     if (toStart)
    218         m_end = m_start;
    219     else
    220         m_start = m_end;
    221 }
    222 
    223 bool Range::isPointInRange(Node* refNode, int offset, ExceptionState& exceptionState)
    224 {
    225     if (!refNode) {
    226         exceptionState.throwDOMException(HierarchyRequestError, "The node provided was null.");
    227         return false;
    228     }
    229 
    230     if (!refNode->inActiveDocument() || refNode->document() != m_ownerDocument) {
    231         return false;
    232     }
    233 
    234     checkNodeWOffset(refNode, offset, exceptionState);
    235     if (exceptionState.hadException())
    236         return false;
    237 
    238     return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset(), exceptionState) >= 0 && !exceptionState.hadException()
    239         && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset(), exceptionState) <= 0 && !exceptionState.hadException();
    240 }
    241 
    242 short Range::comparePoint(Node* refNode, int offset, ExceptionState& exceptionState) const
    243 {
    244     // http://developer.mozilla.org/en/docs/DOM:range.comparePoint
    245     // This method returns -1, 0 or 1 depending on if the point described by the
    246     // refNode node and an offset within the node is before, same as, or after the range respectively.
    247 
    248     if (!refNode) {
    249         exceptionState.throwDOMException(HierarchyRequestError, "The node provided was null.");
    250         return 0;
    251     }
    252 
    253     if (!refNode->inActiveDocument()) {
    254         exceptionState.throwDOMException(WrongDocumentError, "The node provided is not in an active document.");
    255         return 0;
    256     }
    257 
    258     if (refNode->document() != m_ownerDocument) {
    259         exceptionState.throwDOMException(WrongDocumentError, "The node provided is not in this Range's Document.");
    260         return 0;
    261     }
    262 
    263     checkNodeWOffset(refNode, offset, exceptionState);
    264     if (exceptionState.hadException())
    265         return 0;
    266 
    267     // compare to start, and point comes before
    268     if (compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset(), exceptionState) < 0)
    269         return -1;
    270 
    271     if (exceptionState.hadException())
    272         return 0;
    273 
    274     // compare to end, and point comes after
    275     if (compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset(), exceptionState) > 0 && !exceptionState.hadException())
    276         return 1;
    277 
    278     // point is in the middle of this range, or on the boundary points
    279     return 0;
    280 }
    281 
    282 Range::CompareResults Range::compareNode(Node* refNode, ExceptionState& exceptionState) const
    283 {
    284     // http://developer.mozilla.org/en/docs/DOM:range.compareNode
    285     // This method returns 0, 1, 2, or 3 based on if the node is before, after,
    286     // before and after(surrounds), or inside the range, respectively
    287 
    288     if (!refNode) {
    289         exceptionState.throwDOMException(NotFoundError, "The node provided was null.");
    290         return NODE_BEFORE;
    291     }
    292 
    293     if (!refNode->inActiveDocument()) {
    294         // Firefox doesn't throw an exception for this case; it returns 0.
    295         return NODE_BEFORE;
    296     }
    297 
    298     if (refNode->document() != m_ownerDocument) {
    299         // Firefox doesn't throw an exception for this case; it returns 0.
    300         return NODE_BEFORE;
    301     }
    302 
    303     ContainerNode* parentNode = refNode->parentNode();
    304     int nodeIndex = refNode->nodeIndex();
    305 
    306     if (!parentNode) {
    307         // if the node is the top document we should return NODE_BEFORE_AND_AFTER
    308         // but we throw to match firefox behavior
    309         exceptionState.throwDOMException(NotFoundError, "The provided node has no parent.");
    310         return NODE_BEFORE;
    311     }
    312 
    313     if (comparePoint(parentNode, nodeIndex, exceptionState) < 0) { // starts before
    314         if (comparePoint(parentNode, nodeIndex + 1, exceptionState) > 0) // ends after the range
    315             return NODE_BEFORE_AND_AFTER;
    316         return NODE_BEFORE; // ends before or in the range
    317     }
    318     // starts at or after the range start
    319     if (comparePoint(parentNode, nodeIndex + 1, exceptionState) > 0) // ends after the range
    320         return NODE_AFTER;
    321     return NODE_INSIDE; // ends inside the range
    322 }
    323 
    324 short Range::compareBoundaryPoints(CompareHow how, const Range* sourceRange, ExceptionState& exceptionState) const
    325 {
    326     if (!sourceRange) {
    327         exceptionState.throwDOMException(NotFoundError, "The source range provided was null.");
    328         return 0;
    329     }
    330 
    331     Node* thisCont = commonAncestorContainer();
    332     Node* sourceCont = sourceRange->commonAncestorContainer();
    333     if (thisCont->document() != sourceCont->document()) {
    334         exceptionState.throwDOMException(WrongDocumentError, "The source range is in a different document than this range.");
    335         return 0;
    336     }
    337 
    338     Node* thisTop = thisCont;
    339     Node* sourceTop = sourceCont;
    340     while (thisTop->parentNode())
    341         thisTop = thisTop->parentNode();
    342     while (sourceTop->parentNode())
    343         sourceTop = sourceTop->parentNode();
    344     if (thisTop != sourceTop) { // in different DocumentFragments
    345         exceptionState.throwDOMException(WrongDocumentError, "The source range is in a different document than this range.");
    346         return 0;
    347     }
    348 
    349     switch (how) {
    350         case START_TO_START:
    351             return compareBoundaryPoints(m_start, sourceRange->m_start, exceptionState);
    352         case START_TO_END:
    353             return compareBoundaryPoints(m_end, sourceRange->m_start, exceptionState);
    354         case END_TO_END:
    355             return compareBoundaryPoints(m_end, sourceRange->m_end, exceptionState);
    356         case END_TO_START:
    357             return compareBoundaryPoints(m_start, sourceRange->m_end, exceptionState);
    358     }
    359 
    360     exceptionState.throwDOMException(SyntaxError, "The comparison method provided must be one of 'START_TO_START', 'START_TO_END', 'END_TO_END', or 'END_TO_START'.");
    361     return 0;
    362 }
    363 
    364 short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB, ExceptionState& exceptionState)
    365 {
    366     ASSERT(containerA);
    367     ASSERT(containerB);
    368 
    369     if (!containerA)
    370         return -1;
    371     if (!containerB)
    372         return 1;
    373 
    374     // see DOM2 traversal & range section 2.5
    375 
    376     // case 1: both points have the same container
    377     if (containerA == containerB) {
    378         if (offsetA == offsetB)
    379             return 0;           // A is equal to B
    380         if (offsetA < offsetB)
    381             return -1;          // A is before B
    382         else
    383             return 1;           // A is after B
    384     }
    385 
    386     // case 2: node C (container B or an ancestor) is a child node of A
    387     Node* c = containerB;
    388     while (c && c->parentNode() != containerA)
    389         c = c->parentNode();
    390     if (c) {
    391         int offsetC = 0;
    392         Node* n = containerA->firstChild();
    393         while (n != c && offsetC < offsetA) {
    394             offsetC++;
    395             n = n->nextSibling();
    396         }
    397 
    398         if (offsetA <= offsetC)
    399             return -1;              // A is before B
    400         else
    401             return 1;               // A is after B
    402     }
    403 
    404     // case 3: node C (container A or an ancestor) is a child node of B
    405     c = containerA;
    406     while (c && c->parentNode() != containerB)
    407         c = c->parentNode();
    408     if (c) {
    409         int offsetC = 0;
    410         Node* n = containerB->firstChild();
    411         while (n != c && offsetC < offsetB) {
    412             offsetC++;
    413             n = n->nextSibling();
    414         }
    415 
    416         if (offsetC < offsetB)
    417             return -1;              // A is before B
    418         else
    419             return 1;               // A is after B
    420     }
    421 
    422     // case 4: containers A & B are siblings, or children of siblings
    423     // ### we need to do a traversal here instead
    424     Node* commonAncestor = commonAncestorContainer(containerA, containerB);
    425     if (!commonAncestor) {
    426         exceptionState.throwDOMException(WrongDocumentError, "The two ranges are in separate documents.");
    427         return 0;
    428     }
    429     Node* childA = containerA;
    430     while (childA && childA->parentNode() != commonAncestor)
    431         childA = childA->parentNode();
    432     if (!childA)
    433         childA = commonAncestor;
    434     Node* childB = containerB;
    435     while (childB && childB->parentNode() != commonAncestor)
    436         childB = childB->parentNode();
    437     if (!childB)
    438         childB = commonAncestor;
    439 
    440     if (childA == childB)
    441         return 0; // A is equal to B
    442 
    443     Node* n = commonAncestor->firstChild();
    444     while (n) {
    445         if (n == childA)
    446             return -1; // A is before B
    447         if (n == childB)
    448             return 1; // A is after B
    449         n = n->nextSibling();
    450     }
    451 
    452     // Should never reach this point.
    453     ASSERT_NOT_REACHED();
    454     return 0;
    455 }
    456 
    457 short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB, ExceptionState& exceptionState)
    458 {
    459     return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boundaryB.container(), boundaryB.offset(), exceptionState);
    460 }
    461 
    462 bool Range::boundaryPointsValid() const
    463 {
    464     TrackExceptionState exceptionState;
    465     return compareBoundaryPoints(m_start, m_end, exceptionState) <= 0 && !exceptionState.hadException();
    466 }
    467 
    468 void Range::deleteContents(ExceptionState& exceptionState)
    469 {
    470     checkDeleteExtract(exceptionState);
    471     if (exceptionState.hadException())
    472         return;
    473 
    474     {
    475         EventQueueScope eventQueueScope;
    476         processContents(DELETE_CONTENTS, exceptionState);
    477     }
    478 }
    479 
    480 bool Range::intersectsNode(Node* refNode, ExceptionState& exceptionState)
    481 {
    482     // http://developer.mozilla.org/en/docs/DOM:range.intersectsNode
    483     // Returns a bool if the node intersects the range.
    484     if (!refNode) {
    485         exceptionState.throwDOMException(NotFoundError, "The node provided is null.");
    486         return false;
    487     }
    488 
    489     if (!refNode->inActiveDocument() || refNode->document() != m_ownerDocument) {
    490         // Firefox doesn't throw an exception for these cases; it returns false.
    491         return false;
    492     }
    493 
    494     ContainerNode* parentNode = refNode->parentNode();
    495     int nodeIndex = refNode->nodeIndex();
    496 
    497     if (!parentNode) {
    498         // if the node is the top document we should return NODE_BEFORE_AND_AFTER
    499         // but we throw to match firefox behavior
    500         exceptionState.throwDOMException(NotFoundError, "The node provided has no parent.");
    501         return false;
    502     }
    503 
    504     if (comparePoint(parentNode, nodeIndex, exceptionState) < 0 // starts before start
    505         && comparePoint(parentNode, nodeIndex + 1, exceptionState) < 0) { // ends before start
    506         return false;
    507     }
    508 
    509     if (comparePoint(parentNode, nodeIndex, exceptionState) > 0 // starts after end
    510         && comparePoint(parentNode, nodeIndex + 1, exceptionState) > 0) { // ends after end
    511         return false;
    512     }
    513 
    514     return true; // all other cases
    515 }
    516 
    517 static inline Node* highestAncestorUnderCommonRoot(Node* node, Node* commonRoot)
    518 {
    519     if (node == commonRoot)
    520         return 0;
    521 
    522     ASSERT(commonRoot->contains(node));
    523 
    524     while (node->parentNode() != commonRoot)
    525         node = node->parentNode();
    526 
    527     return node;
    528 }
    529 
    530 static inline Node* childOfCommonRootBeforeOffset(Node* container, unsigned offset, Node* commonRoot)
    531 {
    532     ASSERT(container);
    533     ASSERT(commonRoot);
    534 
    535     if (!commonRoot->contains(container))
    536         return 0;
    537 
    538     if (container == commonRoot) {
    539         container = container->firstChild();
    540         for (unsigned i = 0; container && i < offset; i++)
    541             container = container->nextSibling();
    542     } else {
    543         while (container->parentNode() != commonRoot)
    544             container = container->parentNode();
    545     }
    546 
    547     return container;
    548 }
    549 
    550 PassRefPtrWillBeRawPtr<DocumentFragment> Range::processContents(ActionType action, ExceptionState& exceptionState)
    551 {
    552     typedef WillBeHeapVector<RefPtrWillBeMember<Node> > NodeVector;
    553 
    554     RefPtrWillBeRawPtr<DocumentFragment> fragment = nullptr;
    555     if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
    556         fragment = DocumentFragment::create(*m_ownerDocument.get());
    557 
    558     if (collapsed())
    559         return fragment.release();
    560 
    561     RefPtrWillBeRawPtr<Node> commonRoot = commonAncestorContainer();
    562     ASSERT(commonRoot);
    563 
    564     if (m_start.container() == m_end.container()) {
    565         processContentsBetweenOffsets(action, fragment, m_start.container(), m_start.offset(), m_end.offset(), exceptionState);
    566         return fragment;
    567     }
    568 
    569     // Since mutation observers can modify the range during the process, the boundary points need to be saved.
    570     RangeBoundaryPoint originalStart(m_start);
    571     RangeBoundaryPoint originalEnd(m_end);
    572 
    573     // what is the highest node that partially selects the start / end of the range?
    574     RefPtrWillBeRawPtr<Node> partialStart = highestAncestorUnderCommonRoot(originalStart.container(), commonRoot.get());
    575     RefPtrWillBeRawPtr<Node> partialEnd = highestAncestorUnderCommonRoot(originalEnd.container(), commonRoot.get());
    576 
    577     // Start and end containers are different.
    578     // There are three possibilities here:
    579     // 1. Start container == commonRoot (End container must be a descendant)
    580     // 2. End container == commonRoot (Start container must be a descendant)
    581     // 3. Neither is commonRoot, they are both descendants
    582     //
    583     // In case 3, we grab everything after the start (up until a direct child
    584     // of commonRoot) into leftContents, and everything before the end (up until
    585     // a direct child of commonRoot) into rightContents. Then we process all
    586     // commonRoot children between leftContents and rightContents
    587     //
    588     // In case 1 or 2, we skip either processing of leftContents or rightContents,
    589     // in which case the last lot of nodes either goes from the first or last
    590     // child of commonRoot.
    591     //
    592     // These are deleted, cloned, or extracted (i.e. both) depending on action.
    593 
    594     // Note that we are verifying that our common root hierarchy is still intact
    595     // after any DOM mutation event, at various stages below. See webkit bug 60350.
    596 
    597     RefPtrWillBeRawPtr<Node> leftContents = nullptr;
    598     if (originalStart.container() != commonRoot && commonRoot->contains(originalStart.container())) {
    599         leftContents = processContentsBetweenOffsets(action, nullptr, originalStart.container(), originalStart.offset(), originalStart.container()->lengthOfContents(), exceptionState);
    600         leftContents = processAncestorsAndTheirSiblings(action, originalStart.container(), ProcessContentsForward, leftContents, commonRoot.get(), exceptionState);
    601     }
    602 
    603     RefPtrWillBeRawPtr<Node> rightContents = nullptr;
    604     if (m_end.container() != commonRoot && commonRoot->contains(originalEnd.container())) {
    605         rightContents = processContentsBetweenOffsets(action, nullptr, originalEnd.container(), 0, originalEnd.offset(), exceptionState);
    606         rightContents = processAncestorsAndTheirSiblings(action, originalEnd.container(), ProcessContentsBackward, rightContents, commonRoot.get(), exceptionState);
    607     }
    608 
    609     // delete all children of commonRoot between the start and end container
    610     RefPtrWillBeRawPtr<Node> processStart = childOfCommonRootBeforeOffset(originalStart.container(), originalStart.offset(), commonRoot.get());
    611     if (processStart && originalStart.container() != commonRoot) // processStart contains nodes before m_start.
    612         processStart = processStart->nextSibling();
    613     RefPtrWillBeRawPtr<Node> processEnd = childOfCommonRootBeforeOffset(originalEnd.container(), originalEnd.offset(), commonRoot.get());
    614 
    615     // Collapse the range, making sure that the result is not within a node that was partially selected.
    616     if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
    617         if (partialStart && commonRoot->contains(partialStart.get())) {
    618             // FIXME: We should not continue if we have an earlier error.
    619             exceptionState.clearException();
    620             setStart(partialStart->parentNode(), partialStart->nodeIndex() + 1, exceptionState);
    621         } else if (partialEnd && commonRoot->contains(partialEnd.get())) {
    622             // FIXME: We should not continue if we have an earlier error.
    623             exceptionState.clearException();
    624             setStart(partialEnd->parentNode(), partialEnd->nodeIndex(), exceptionState);
    625         }
    626         if (exceptionState.hadException())
    627             return nullptr;
    628         m_end = m_start;
    629     }
    630 
    631     originalStart.clear();
    632     originalEnd.clear();
    633 
    634     // Now add leftContents, stuff in between, and rightContents to the fragment
    635     // (or just delete the stuff in between)
    636 
    637     if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && leftContents)
    638         fragment->appendChild(leftContents, exceptionState);
    639 
    640     if (processStart) {
    641         NodeVector nodes;
    642         for (Node* n = processStart.get(); n && n != processEnd; n = n->nextSibling())
    643             nodes.append(n);
    644         processNodes(action, nodes, commonRoot, fragment, exceptionState);
    645     }
    646 
    647     if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && rightContents)
    648         fragment->appendChild(rightContents, exceptionState);
    649 
    650     return fragment.release();
    651 }
    652 
    653 static inline void deleteCharacterData(PassRefPtrWillBeRawPtr<CharacterData> data, unsigned startOffset, unsigned endOffset, ExceptionState& exceptionState)
    654 {
    655     if (data->length() - endOffset)
    656         data->deleteData(endOffset, data->length() - endOffset, exceptionState);
    657     if (startOffset)
    658         data->deleteData(0, startOffset, exceptionState);
    659 }
    660 
    661 PassRefPtrWillBeRawPtr<Node> Range::processContentsBetweenOffsets(ActionType action, PassRefPtrWillBeRawPtr<DocumentFragment> fragment,
    662     Node* container, unsigned startOffset, unsigned endOffset, ExceptionState& exceptionState)
    663 {
    664     ASSERT(container);
    665     ASSERT(startOffset <= endOffset);
    666 
    667     // This switch statement must be consistent with that of Node::lengthOfContents.
    668     RefPtrWillBeRawPtr<Node> result = nullptr;
    669     switch (container->nodeType()) {
    670     case Node::TEXT_NODE:
    671     case Node::CDATA_SECTION_NODE:
    672     case Node::COMMENT_NODE:
    673         endOffset = std::min(endOffset, toCharacterData(container)->length());
    674         if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
    675             RefPtrWillBeRawPtr<CharacterData> c = static_pointer_cast<CharacterData>(container->cloneNode(true));
    676             deleteCharacterData(c, startOffset, endOffset, exceptionState);
    677             if (fragment) {
    678                 result = fragment;
    679                 result->appendChild(c.release(), exceptionState);
    680             } else
    681                 result = c.release();
    682         }
    683         if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
    684             toCharacterData(container)->deleteData(startOffset, endOffset - startOffset, exceptionState);
    685         break;
    686     case Node::PROCESSING_INSTRUCTION_NODE:
    687         endOffset = std::min(endOffset, toProcessingInstruction(container)->data().length());
    688         if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
    689             RefPtrWillBeRawPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(container->cloneNode(true));
    690             c->setData(c->data().substring(startOffset, endOffset - startOffset));
    691             if (fragment) {
    692                 result = fragment;
    693                 result->appendChild(c.release(), exceptionState);
    694             } else
    695                 result = c.release();
    696         }
    697         if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
    698             ProcessingInstruction* pi = toProcessingInstruction(container);
    699             String data(pi->data());
    700             data.remove(startOffset, endOffset - startOffset);
    701             pi->setData(data);
    702         }
    703         break;
    704     case Node::ELEMENT_NODE:
    705     case Node::ATTRIBUTE_NODE:
    706     case Node::DOCUMENT_NODE:
    707     case Node::DOCUMENT_TYPE_NODE:
    708     case Node::DOCUMENT_FRAGMENT_NODE:
    709         // FIXME: Should we assert that some nodes never appear here?
    710         if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
    711             if (fragment)
    712                 result = fragment;
    713             else
    714                 result = container->cloneNode(false);
    715         }
    716 
    717         Node* n = container->firstChild();
    718         WillBeHeapVector<RefPtrWillBeMember<Node> > nodes;
    719         for (unsigned i = startOffset; n && i; i--)
    720             n = n->nextSibling();
    721         for (unsigned i = startOffset; n && i < endOffset; i++, n = n->nextSibling())
    722             nodes.append(n);
    723 
    724         processNodes(action, nodes, container, result, exceptionState);
    725         break;
    726     }
    727 
    728     return result.release();
    729 }
    730 
    731 void Range::processNodes(ActionType action, WillBeHeapVector<RefPtrWillBeMember<Node> >& nodes, PassRefPtrWillBeRawPtr<Node> oldContainer, PassRefPtrWillBeRawPtr<Node> newContainer, ExceptionState& exceptionState)
    732 {
    733     for (unsigned i = 0; i < nodes.size(); i++) {
    734         switch (action) {
    735         case DELETE_CONTENTS:
    736             oldContainer->removeChild(nodes[i].get(), exceptionState);
    737             break;
    738         case EXTRACT_CONTENTS:
    739             newContainer->appendChild(nodes[i].release(), exceptionState); // will remove n from its parent
    740             break;
    741         case CLONE_CONTENTS:
    742             newContainer->appendChild(nodes[i]->cloneNode(true), exceptionState);
    743             break;
    744         }
    745     }
    746 }
    747 
    748 PassRefPtrWillBeRawPtr<Node> Range::processAncestorsAndTheirSiblings(ActionType action, Node* container, ContentsProcessDirection direction, PassRefPtrWillBeRawPtr<Node> passedClonedContainer, Node* commonRoot, ExceptionState& exceptionState)
    749 {
    750     typedef WillBeHeapVector<RefPtrWillBeMember<Node> > NodeVector;
    751 
    752     RefPtrWillBeRawPtr<Node> clonedContainer = passedClonedContainer;
    753     NodeVector ancestors;
    754     for (ContainerNode* n = container->parentNode(); n && n != commonRoot; n = n->parentNode())
    755         ancestors.append(n);
    756 
    757     RefPtrWillBeRawPtr<Node> firstChildInAncestorToProcess = direction == ProcessContentsForward ? container->nextSibling() : container->previousSibling();
    758     for (NodeVector::const_iterator it = ancestors.begin(); it != ancestors.end(); ++it) {
    759         RefPtrWillBeRawPtr<Node> ancestor = *it;
    760         if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
    761             if (RefPtrWillBeRawPtr<Node> clonedAncestor = ancestor->cloneNode(false)) { // Might have been removed already during mutation event.
    762                 clonedAncestor->appendChild(clonedContainer, exceptionState);
    763                 clonedContainer = clonedAncestor;
    764             }
    765         }
    766 
    767         // Copy siblings of an ancestor of start/end containers
    768         // FIXME: This assertion may fail if DOM is modified during mutation event
    769         // FIXME: Share code with Range::processNodes
    770         ASSERT(!firstChildInAncestorToProcess || firstChildInAncestorToProcess->parentNode() == ancestor);
    771 
    772         NodeVector nodes;
    773         for (Node* child = firstChildInAncestorToProcess.get(); child;
    774             child = (direction == ProcessContentsForward) ? child->nextSibling() : child->previousSibling())
    775             nodes.append(child);
    776 
    777         for (NodeVector::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
    778             Node* child = it->get();
    779             switch (action) {
    780             case DELETE_CONTENTS:
    781                 // Prior call of ancestor->removeChild() may cause a tree change due to DOMSubtreeModified event.
    782                 // Therefore, we need to make sure |ancestor| is still |child|'s parent.
    783                 if (ancestor == child->parentNode())
    784                     ancestor->removeChild(child, exceptionState);
    785                 break;
    786             case EXTRACT_CONTENTS: // will remove child from ancestor
    787                 if (direction == ProcessContentsForward)
    788                     clonedContainer->appendChild(child, exceptionState);
    789                 else
    790                     clonedContainer->insertBefore(child, clonedContainer->firstChild(), exceptionState);
    791                 break;
    792             case CLONE_CONTENTS:
    793                 if (direction == ProcessContentsForward)
    794                     clonedContainer->appendChild(child->cloneNode(true), exceptionState);
    795                 else
    796                     clonedContainer->insertBefore(child->cloneNode(true), clonedContainer->firstChild(), exceptionState);
    797                 break;
    798             }
    799         }
    800         firstChildInAncestorToProcess = direction == ProcessContentsForward ? ancestor->nextSibling() : ancestor->previousSibling();
    801     }
    802 
    803     return clonedContainer.release();
    804 }
    805 
    806 PassRefPtrWillBeRawPtr<DocumentFragment> Range::extractContents(ExceptionState& exceptionState)
    807 {
    808     checkDeleteExtract(exceptionState);
    809     if (exceptionState.hadException())
    810         return nullptr;
    811 
    812     return processContents(EXTRACT_CONTENTS, exceptionState);
    813 }
    814 
    815 PassRefPtrWillBeRawPtr<DocumentFragment> Range::cloneContents(ExceptionState& exceptionState)
    816 {
    817     return processContents(CLONE_CONTENTS, exceptionState);
    818 }
    819 
    820 void Range::insertNode(PassRefPtrWillBeRawPtr<Node> prpNewNode, ExceptionState& exceptionState)
    821 {
    822     RefPtrWillBeRawPtr<Node> newNode = prpNewNode;
    823 
    824     if (!newNode) {
    825         exceptionState.throwDOMException(NotFoundError, "The node provided is null.");
    826         return;
    827     }
    828 
    829     // HierarchyRequestError: Raised if the container of the start of the Range is of a type that
    830     // does not allow children of the type of newNode or if newNode is an ancestor of the container.
    831 
    832     // an extra one here - if a text node is going to split, it must have a parent to insert into
    833     bool startIsText = m_start.container()->isTextNode();
    834     if (startIsText && !m_start.container()->parentNode()) {
    835         exceptionState.throwDOMException(HierarchyRequestError, "This operation would split a text node, but there's no parent into which to insert.");
    836         return;
    837     }
    838 
    839     // In the case where the container is a text node, we check against the container's parent, because
    840     // text nodes get split up upon insertion.
    841     Node* checkAgainst;
    842     if (startIsText)
    843         checkAgainst = m_start.container()->parentNode();
    844     else
    845         checkAgainst = m_start.container();
    846 
    847     Node::NodeType newNodeType = newNode->nodeType();
    848     int numNewChildren;
    849     if (newNodeType == Node::DOCUMENT_FRAGMENT_NODE && !newNode->isShadowRoot()) {
    850         // check each child node, not the DocumentFragment itself
    851         numNewChildren = 0;
    852         for (Node* c = toDocumentFragment(newNode)->firstChild(); c; c = c->nextSibling()) {
    853             if (!checkAgainst->childTypeAllowed(c->nodeType())) {
    854                 exceptionState.throwDOMException(HierarchyRequestError, "The node to be inserted contains a '" + c->nodeName() + "' node, which may not be inserted here.");
    855                 return;
    856             }
    857             ++numNewChildren;
    858         }
    859     } else {
    860         numNewChildren = 1;
    861         if (!checkAgainst->childTypeAllowed(newNodeType)) {
    862             exceptionState.throwDOMException(HierarchyRequestError, "The node to be inserted is a '" + newNode->nodeName() + "' node, which may not be inserted here.");
    863             return;
    864         }
    865     }
    866 
    867     for (Node* n = m_start.container(); n; n = n->parentNode()) {
    868         if (n == newNode) {
    869             exceptionState.throwDOMException(HierarchyRequestError, "The node to be inserted contains the insertion point; it may not be inserted into itself.");
    870             return;
    871         }
    872     }
    873 
    874     // InvalidNodeTypeError: Raised if newNode is an Attr, Entity, Notation, ShadowRoot or Document node.
    875     switch (newNodeType) {
    876     case Node::ATTRIBUTE_NODE:
    877     case Node::DOCUMENT_NODE:
    878         exceptionState.throwDOMException(InvalidNodeTypeError, "The node to be inserted is a '" + newNode->nodeName() + "' node, which may not be inserted here.");
    879         return;
    880     default:
    881         if (newNode->isShadowRoot()) {
    882             exceptionState.throwDOMException(InvalidNodeTypeError, "The node to be inserted is a shadow root, which may not be inserted here.");
    883             return;
    884         }
    885         break;
    886     }
    887 
    888     EventQueueScope scope;
    889     bool collapsed = m_start == m_end;
    890     RefPtrWillBeRawPtr<Node> container = nullptr;
    891     if (startIsText) {
    892         container = m_start.container();
    893         RefPtrWillBeRawPtr<Text> newText = toText(container)->splitText(m_start.offset(), exceptionState);
    894         if (exceptionState.hadException())
    895             return;
    896 
    897         container = m_start.container();
    898         container->parentNode()->insertBefore(newNode.release(), newText.get(), exceptionState);
    899         if (exceptionState.hadException())
    900             return;
    901 
    902         if (collapsed)
    903             m_end.setToBeforeChild(*newText);
    904     } else {
    905         RefPtrWillBeRawPtr<Node> lastChild = (newNodeType == Node::DOCUMENT_FRAGMENT_NODE) ? toDocumentFragment(newNode)->lastChild() : newNode.get();
    906         if (lastChild && lastChild == m_start.childBefore()) {
    907             // The insertion will do nothing, but we need to extend the range to include
    908             // the inserted nodes.
    909             Node* firstChild = (newNodeType == Node::DOCUMENT_FRAGMENT_NODE) ? toDocumentFragment(newNode)->firstChild() : newNode.get();
    910             ASSERT(firstChild);
    911             m_start.setToBeforeChild(*firstChild);
    912             return;
    913         }
    914 
    915         container = m_start.container();
    916         container->insertBefore(newNode.release(), container->traverseToChildAt(m_start.offset()), exceptionState);
    917         if (exceptionState.hadException())
    918             return;
    919 
    920         // Note that m_start.offset() may have changed as a result of container->insertBefore,
    921         // when the node we are inserting comes before the range in the same container.
    922         if (collapsed && numNewChildren)
    923             m_end.set(m_start.container(), m_start.offset() + numNewChildren, lastChild.get());
    924     }
    925 }
    926 
    927 String Range::toString() const
    928 {
    929     StringBuilder builder;
    930 
    931     Node* pastLast = pastLastNode();
    932     for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(*n)) {
    933         Node::NodeType type = n->nodeType();
    934         if (type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE) {
    935             String data = toCharacterData(n)->data();
    936             int length = data.length();
    937             int start = (n == m_start.container()) ? std::min(std::max(0, m_start.offset()), length) : 0;
    938             int end = (n == m_end.container()) ? std::min(std::max(start, m_end.offset()), length) : length;
    939             builder.append(data, start, end - start);
    940         }
    941     }
    942 
    943     return builder.toString();
    944 }
    945 
    946 String Range::toHTML() const
    947 {
    948     return createMarkup(this);
    949 }
    950 
    951 String Range::text() const
    952 {
    953     // We need to update layout, since plainText uses line boxes in the render tree.
    954     // FIXME: As with innerText, we'd like this to work even if there are no render objects.
    955     m_start.container()->document().updateLayout();
    956 
    957     return plainText(this, TextIteratorEmitsObjectReplacementCharacter);
    958 }
    959 
    960 PassRefPtrWillBeRawPtr<DocumentFragment> Range::createContextualFragment(const String& markup, ExceptionState& exceptionState)
    961 {
    962     Node* element = m_start.container()->isElementNode() ? m_start.container() : m_start.container()->parentNode();
    963     if (!element || !element->isHTMLElement()) {
    964         exceptionState.throwDOMException(NotSupportedError, "The range's container must be an HTML element.");
    965         return nullptr;
    966     }
    967 
    968     RefPtrWillBeRawPtr<DocumentFragment> fragment = WebCore::createContextualFragment(markup, toHTMLElement(element), AllowScriptingContentAndDoNotMarkAlreadyStarted, exceptionState);
    969     if (!fragment)
    970         return nullptr;
    971 
    972     return fragment.release();
    973 }
    974 
    975 
    976 void Range::detach()
    977 {
    978     // This is now a no-op as per the DOM specification.
    979 }
    980 
    981 Node* Range::checkNodeWOffset(Node* n, int offset, ExceptionState& exceptionState) const
    982 {
    983     switch (n->nodeType()) {
    984         case Node::DOCUMENT_TYPE_NODE:
    985             exceptionState.throwDOMException(InvalidNodeTypeError, "The node provided is of type '" + n->nodeName() + "'.");
    986             return 0;
    987         case Node::CDATA_SECTION_NODE:
    988         case Node::COMMENT_NODE:
    989         case Node::TEXT_NODE:
    990             if (static_cast<unsigned>(offset) > toCharacterData(n)->length())
    991                 exceptionState.throwDOMException(IndexSizeError, "The offset " + String::number(offset) + " is larger than or equal to the node's length (" + String::number(toCharacterData(n)->length()) + ").");
    992             return 0;
    993         case Node::PROCESSING_INSTRUCTION_NODE:
    994             if (static_cast<unsigned>(offset) > toProcessingInstruction(n)->data().length())
    995                 exceptionState.throwDOMException(IndexSizeError, "The offset " + String::number(offset) + " is larger than or equal to than the node's length (" + String::number(toProcessingInstruction(n)->data().length()) + ").");
    996             return 0;
    997         case Node::ATTRIBUTE_NODE:
    998         case Node::DOCUMENT_FRAGMENT_NODE:
    999         case Node::DOCUMENT_NODE:
   1000         case Node::ELEMENT_NODE: {
   1001             if (!offset)
   1002                 return 0;
   1003             Node* childBefore = n->traverseToChildAt(offset - 1);
   1004             if (!childBefore)
   1005                 exceptionState.throwDOMException(IndexSizeError, "There is no child at offset " + String::number(offset) + ".");
   1006             return childBefore;
   1007         }
   1008     }
   1009     ASSERT_NOT_REACHED();
   1010     return 0;
   1011 }
   1012 
   1013 void Range::checkNodeBA(Node* n, ExceptionState& exceptionState) const
   1014 {
   1015     if (!n) {
   1016         exceptionState.throwDOMException(NotFoundError, "The node provided is null.");
   1017         return;
   1018     }
   1019 
   1020     // InvalidNodeTypeError: Raised if the root container of refNode is not an
   1021     // Attr, Document, DocumentFragment or ShadowRoot node, or part of a SVG shadow DOM tree,
   1022     // or if refNode is a Document, DocumentFragment, ShadowRoot, Attr, Entity, or Notation node.
   1023 
   1024     if (!n->parentNode()) {
   1025         exceptionState.throwDOMException(InvalidNodeTypeError, "the given Node has no parent.");
   1026         return;
   1027     }
   1028 
   1029     switch (n->nodeType()) {
   1030         case Node::ATTRIBUTE_NODE:
   1031         case Node::DOCUMENT_FRAGMENT_NODE:
   1032         case Node::DOCUMENT_NODE:
   1033             exceptionState.throwDOMException(InvalidNodeTypeError, "The node provided is of type '" + n->nodeName() + "'.");
   1034             return;
   1035         case Node::CDATA_SECTION_NODE:
   1036         case Node::COMMENT_NODE:
   1037         case Node::DOCUMENT_TYPE_NODE:
   1038         case Node::ELEMENT_NODE:
   1039         case Node::PROCESSING_INSTRUCTION_NODE:
   1040         case Node::TEXT_NODE:
   1041             break;
   1042     }
   1043 
   1044     Node* root = n;
   1045     while (ContainerNode* parent = root->parentNode())
   1046         root = parent;
   1047 
   1048     switch (root->nodeType()) {
   1049         case Node::ATTRIBUTE_NODE:
   1050         case Node::DOCUMENT_NODE:
   1051         case Node::DOCUMENT_FRAGMENT_NODE:
   1052         case Node::ELEMENT_NODE:
   1053             break;
   1054         case Node::CDATA_SECTION_NODE:
   1055         case Node::COMMENT_NODE:
   1056         case Node::DOCUMENT_TYPE_NODE:
   1057         case Node::PROCESSING_INSTRUCTION_NODE:
   1058         case Node::TEXT_NODE:
   1059             exceptionState.throwDOMException(InvalidNodeTypeError, "The node provided is of type '" + n->nodeName() + "'.");
   1060             return;
   1061     }
   1062 }
   1063 
   1064 PassRefPtrWillBeRawPtr<Range> Range::cloneRange() const
   1065 {
   1066     return Range::create(*m_ownerDocument.get(), m_start.container(), m_start.offset(), m_end.container(), m_end.offset());
   1067 }
   1068 
   1069 void Range::setStartAfter(Node* refNode, ExceptionState& exceptionState)
   1070 {
   1071     checkNodeBA(refNode, exceptionState);
   1072     if (exceptionState.hadException())
   1073         return;
   1074 
   1075     setStart(refNode->parentNode(), refNode->nodeIndex() + 1, exceptionState);
   1076 }
   1077 
   1078 void Range::setEndBefore(Node* refNode, ExceptionState& exceptionState)
   1079 {
   1080     checkNodeBA(refNode, exceptionState);
   1081     if (exceptionState.hadException())
   1082         return;
   1083 
   1084     setEnd(refNode->parentNode(), refNode->nodeIndex(), exceptionState);
   1085 }
   1086 
   1087 void Range::setEndAfter(Node* refNode, ExceptionState& exceptionState)
   1088 {
   1089     checkNodeBA(refNode, exceptionState);
   1090     if (exceptionState.hadException())
   1091         return;
   1092 
   1093     setEnd(refNode->parentNode(), refNode->nodeIndex() + 1, exceptionState);
   1094 }
   1095 
   1096 void Range::selectNode(Node* refNode, ExceptionState& exceptionState)
   1097 {
   1098     if (!refNode) {
   1099         exceptionState.throwDOMException(NotFoundError, "The node provided is null.");
   1100         return;
   1101     }
   1102 
   1103     if (!refNode->parentNode()) {
   1104         exceptionState.throwDOMException(InvalidNodeTypeError, "the given Node has no parent.");
   1105         return;
   1106     }
   1107 
   1108     // InvalidNodeTypeError: Raised if an ancestor of refNode is an Entity, Notation or
   1109     // DocumentType node or if refNode is a Document, DocumentFragment, ShadowRoot, Attr, Entity, or Notation
   1110     // node.
   1111     for (ContainerNode* anc = refNode->parentNode(); anc; anc = anc->parentNode()) {
   1112         switch (anc->nodeType()) {
   1113             case Node::ATTRIBUTE_NODE:
   1114             case Node::CDATA_SECTION_NODE:
   1115             case Node::COMMENT_NODE:
   1116             case Node::DOCUMENT_FRAGMENT_NODE:
   1117             case Node::DOCUMENT_NODE:
   1118             case Node::ELEMENT_NODE:
   1119             case Node::PROCESSING_INSTRUCTION_NODE:
   1120             case Node::TEXT_NODE:
   1121                 break;
   1122             case Node::DOCUMENT_TYPE_NODE:
   1123                 exceptionState.throwDOMException(InvalidNodeTypeError, "The node provided has an ancestor of type '" + anc->nodeName() + "'.");
   1124                 return;
   1125         }
   1126     }
   1127 
   1128     switch (refNode->nodeType()) {
   1129         case Node::CDATA_SECTION_NODE:
   1130         case Node::COMMENT_NODE:
   1131         case Node::DOCUMENT_TYPE_NODE:
   1132         case Node::ELEMENT_NODE:
   1133         case Node::PROCESSING_INSTRUCTION_NODE:
   1134         case Node::TEXT_NODE:
   1135             break;
   1136         case Node::ATTRIBUTE_NODE:
   1137         case Node::DOCUMENT_FRAGMENT_NODE:
   1138         case Node::DOCUMENT_NODE:
   1139             exceptionState.throwDOMException(InvalidNodeTypeError, "The node provided is of type '" + refNode->nodeName() + "'.");
   1140             return;
   1141     }
   1142 
   1143     if (m_ownerDocument != refNode->document())
   1144         setDocument(refNode->document());
   1145 
   1146     setStartBefore(refNode);
   1147     setEndAfter(refNode);
   1148 }
   1149 
   1150 void Range::selectNodeContents(Node* refNode, ExceptionState& exceptionState)
   1151 {
   1152     if (!refNode) {
   1153         exceptionState.throwDOMException(NotFoundError, "The node provided is null.");
   1154         return;
   1155     }
   1156 
   1157     // InvalidNodeTypeError: Raised if refNode or an ancestor of refNode is an Entity, Notation
   1158     // or DocumentType node.
   1159     for (Node* n = refNode; n; n = n->parentNode()) {
   1160         switch (n->nodeType()) {
   1161             case Node::ATTRIBUTE_NODE:
   1162             case Node::CDATA_SECTION_NODE:
   1163             case Node::COMMENT_NODE:
   1164             case Node::DOCUMENT_FRAGMENT_NODE:
   1165             case Node::DOCUMENT_NODE:
   1166             case Node::ELEMENT_NODE:
   1167             case Node::PROCESSING_INSTRUCTION_NODE:
   1168             case Node::TEXT_NODE:
   1169                 break;
   1170             case Node::DOCUMENT_TYPE_NODE:
   1171                 exceptionState.throwDOMException(InvalidNodeTypeError, "The node provided is of type '" + refNode->nodeName() + "'.");
   1172                 return;
   1173         }
   1174     }
   1175 
   1176     if (m_ownerDocument != refNode->document())
   1177         setDocument(refNode->document());
   1178 
   1179     m_start.setToStartOfNode(*refNode);
   1180     m_end.setToEndOfNode(*refNode);
   1181 }
   1182 
   1183 void Range::surroundContents(PassRefPtrWillBeRawPtr<Node> passNewParent, ExceptionState& exceptionState)
   1184 {
   1185     RefPtrWillBeRawPtr<Node> newParent = passNewParent;
   1186     if (!newParent) {
   1187         exceptionState.throwDOMException(NotFoundError, "The node provided is null.");
   1188         return;
   1189     }
   1190 
   1191     // InvalidNodeTypeError: Raised if node is an Attr, Entity, DocumentType, Notation,
   1192     // Document, or DocumentFragment node.
   1193     switch (newParent->nodeType()) {
   1194         case Node::ATTRIBUTE_NODE:
   1195         case Node::DOCUMENT_FRAGMENT_NODE:
   1196         case Node::DOCUMENT_NODE:
   1197         case Node::DOCUMENT_TYPE_NODE:
   1198             exceptionState.throwDOMException(InvalidNodeTypeError, "The node provided is of type '" + newParent->nodeName() + "'.");
   1199             return;
   1200         case Node::CDATA_SECTION_NODE:
   1201         case Node::COMMENT_NODE:
   1202         case Node::ELEMENT_NODE:
   1203         case Node::PROCESSING_INSTRUCTION_NODE:
   1204         case Node::TEXT_NODE:
   1205             break;
   1206     }
   1207 
   1208     // Raise a HierarchyRequestError if m_start.container() doesn't accept children like newParent.
   1209     Node* parentOfNewParent = m_start.container();
   1210 
   1211     // If m_start.container() is a character data node, it will be split and it will be its parent that will
   1212     // need to accept newParent (or in the case of a comment, it logically "would" be inserted into the parent,
   1213     // although this will fail below for another reason).
   1214     if (parentOfNewParent->isCharacterDataNode())
   1215         parentOfNewParent = parentOfNewParent->parentNode();
   1216 
   1217     if (!parentOfNewParent) {
   1218         exceptionState.throwDOMException(HierarchyRequestError, "The container node is a detached character data node; no parent node is available for insertion.");
   1219         return;
   1220     }
   1221 
   1222     if (!parentOfNewParent->childTypeAllowed(newParent->nodeType())) {
   1223         exceptionState.throwDOMException(HierarchyRequestError, "The node provided is of type '" + newParent->nodeName() + "', which may not be inserted here.");
   1224         return;
   1225     }
   1226 
   1227     if (newParent->contains(m_start.container())) {
   1228         exceptionState.throwDOMException(HierarchyRequestError, "The node provided contains the insertion point; it may not be inserted into itself.");
   1229         return;
   1230     }
   1231 
   1232     // FIXME: Do we need a check if the node would end up with a child node of a type not
   1233     // allowed by the type of node?
   1234 
   1235     // BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially selects a non-Text node.
   1236     Node* startNonTextContainer = m_start.container();
   1237     if (startNonTextContainer->nodeType() == Node::TEXT_NODE)
   1238         startNonTextContainer = startNonTextContainer->parentNode();
   1239     Node* endNonTextContainer = m_end.container();
   1240     if (endNonTextContainer->nodeType() == Node::TEXT_NODE)
   1241         endNonTextContainer = endNonTextContainer->parentNode();
   1242     if (startNonTextContainer != endNonTextContainer) {
   1243         exceptionState.throwDOMException(InvalidStateError, "The Range has partially selected a non-Text node.");
   1244         return;
   1245     }
   1246 
   1247     while (Node* n = newParent->firstChild()) {
   1248         toContainerNode(newParent)->removeChild(n, exceptionState);
   1249         if (exceptionState.hadException())
   1250             return;
   1251     }
   1252     RefPtrWillBeRawPtr<DocumentFragment> fragment = extractContents(exceptionState);
   1253     if (exceptionState.hadException())
   1254         return;
   1255     insertNode(newParent, exceptionState);
   1256     if (exceptionState.hadException())
   1257         return;
   1258     newParent->appendChild(fragment.release(), exceptionState);
   1259     if (exceptionState.hadException())
   1260         return;
   1261     selectNode(newParent.get(), exceptionState);
   1262 }
   1263 
   1264 void Range::setStartBefore(Node* refNode, ExceptionState& exceptionState)
   1265 {
   1266     checkNodeBA(refNode, exceptionState);
   1267     if (exceptionState.hadException())
   1268         return;
   1269 
   1270     setStart(refNode->parentNode(), refNode->nodeIndex(), exceptionState);
   1271 }
   1272 
   1273 void Range::checkDeleteExtract(ExceptionState& exceptionState)
   1274 {
   1275     ASSERT(boundaryPointsValid());
   1276 
   1277     if (!commonAncestorContainer())
   1278         return;
   1279 
   1280     Node* pastLast = pastLastNode();
   1281     for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(*n)) {
   1282         if (n->isDocumentTypeNode()) {
   1283             exceptionState.throwDOMException(HierarchyRequestError, "The Range contains a doctype node.");
   1284             return;
   1285         }
   1286     }
   1287 }
   1288 
   1289 Node* Range::firstNode() const
   1290 {
   1291     if (m_start.container()->offsetInCharacters())
   1292         return m_start.container();
   1293     if (Node* child = m_start.container()->traverseToChildAt(m_start.offset()))
   1294         return child;
   1295     if (!m_start.offset())
   1296         return m_start.container();
   1297     return NodeTraversal::nextSkippingChildren(*m_start.container());
   1298 }
   1299 
   1300 ShadowRoot* Range::shadowRoot() const
   1301 {
   1302     return startContainer() ? startContainer()->containingShadowRoot() : 0;
   1303 }
   1304 
   1305 Node* Range::pastLastNode() const
   1306 {
   1307     if (m_end.container()->offsetInCharacters())
   1308         return NodeTraversal::nextSkippingChildren(*m_end.container());
   1309     if (Node* child = m_end.container()->traverseToChildAt(m_end.offset()))
   1310         return child;
   1311     return NodeTraversal::nextSkippingChildren(*m_end.container());
   1312 }
   1313 
   1314 IntRect Range::boundingBox() const
   1315 {
   1316     IntRect result;
   1317     Vector<IntRect> rects;
   1318     textRects(rects);
   1319     const size_t n = rects.size();
   1320     for (size_t i = 0; i < n; ++i)
   1321         result.unite(rects[i]);
   1322     return result;
   1323 }
   1324 
   1325 void Range::textRects(Vector<IntRect>& rects, bool useSelectionHeight, RangeInFixedPosition* inFixed) const
   1326 {
   1327     Node* startContainer = m_start.container();
   1328     ASSERT(startContainer);
   1329     Node* endContainer = m_end.container();
   1330     ASSERT(endContainer);
   1331 
   1332     bool allFixed = true;
   1333     bool someFixed = false;
   1334 
   1335     Node* stopNode = pastLastNode();
   1336     for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next(*node)) {
   1337         RenderObject* r = node->renderer();
   1338         if (!r || !r->isText())
   1339             continue;
   1340         RenderText* renderText = toRenderText(r);
   1341         int startOffset = node == startContainer ? m_start.offset() : 0;
   1342         int endOffset = node == endContainer ? m_end.offset() : std::numeric_limits<int>::max();
   1343         bool isFixed = false;
   1344         renderText->absoluteRectsForRange(rects, startOffset, endOffset, useSelectionHeight, &isFixed);
   1345         allFixed &= isFixed;
   1346         someFixed |= isFixed;
   1347     }
   1348 
   1349     if (inFixed)
   1350         *inFixed = allFixed ? EntirelyFixedPosition : (someFixed ? PartiallyFixedPosition : NotFixedPosition);
   1351 }
   1352 
   1353 void Range::textQuads(Vector<FloatQuad>& quads, bool useSelectionHeight, RangeInFixedPosition* inFixed) const
   1354 {
   1355     Node* startContainer = m_start.container();
   1356     ASSERT(startContainer);
   1357     Node* endContainer = m_end.container();
   1358     ASSERT(endContainer);
   1359 
   1360     bool allFixed = true;
   1361     bool someFixed = false;
   1362 
   1363     Node* stopNode = pastLastNode();
   1364     for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next(*node)) {
   1365         RenderObject* r = node->renderer();
   1366         if (!r || !r->isText())
   1367             continue;
   1368         RenderText* renderText = toRenderText(r);
   1369         int startOffset = node == startContainer ? m_start.offset() : 0;
   1370         int endOffset = node == endContainer ? m_end.offset() : std::numeric_limits<int>::max();
   1371         bool isFixed = false;
   1372         renderText->absoluteQuadsForRange(quads, startOffset, endOffset, useSelectionHeight, &isFixed);
   1373         allFixed &= isFixed;
   1374         someFixed |= isFixed;
   1375     }
   1376 
   1377     if (inFixed)
   1378         *inFixed = allFixed ? EntirelyFixedPosition : (someFixed ? PartiallyFixedPosition : NotFixedPosition);
   1379 }
   1380 
   1381 #ifndef NDEBUG
   1382 void Range::formatForDebugger(char* buffer, unsigned length) const
   1383 {
   1384     StringBuilder result;
   1385 
   1386     const int FormatBufferSize = 1024;
   1387     char s[FormatBufferSize];
   1388     result.appendLiteral("from offset ");
   1389     result.appendNumber(m_start.offset());
   1390     result.appendLiteral(" of ");
   1391     m_start.container()->formatForDebugger(s, FormatBufferSize);
   1392     result.append(s);
   1393     result.appendLiteral(" to offset ");
   1394     result.appendNumber(m_end.offset());
   1395     result.appendLiteral(" of ");
   1396     m_end.container()->formatForDebugger(s, FormatBufferSize);
   1397     result.append(s);
   1398 
   1399     strncpy(buffer, result.toString().utf8().data(), length - 1);
   1400 }
   1401 #endif
   1402 
   1403 bool areRangesEqual(const Range* a, const Range* b)
   1404 {
   1405     if (a == b)
   1406         return true;
   1407     if (!a || !b)
   1408         return false;
   1409     return a->startPosition() == b->startPosition() && a->endPosition() == b->endPosition();
   1410 }
   1411 
   1412 PassRefPtrWillBeRawPtr<Range> rangeOfContents(Node* node)
   1413 {
   1414     ASSERT(node);
   1415     RefPtrWillBeRawPtr<Range> range = Range::create(node->document());
   1416     range->selectNodeContents(node, IGNORE_EXCEPTION);
   1417     return range.release();
   1418 }
   1419 
   1420 static inline void boundaryNodeChildrenChanged(RangeBoundaryPoint& boundary, ContainerNode* container)
   1421 {
   1422     if (!boundary.childBefore())
   1423         return;
   1424     if (boundary.container() != container)
   1425         return;
   1426     boundary.invalidateOffset();
   1427 }
   1428 
   1429 void Range::nodeChildrenChanged(ContainerNode* container)
   1430 {
   1431     ASSERT(container);
   1432     ASSERT(container->document() == m_ownerDocument);
   1433     boundaryNodeChildrenChanged(m_start, container);
   1434     boundaryNodeChildrenChanged(m_end, container);
   1435 }
   1436 
   1437 static inline void boundaryNodeChildrenWillBeRemoved(RangeBoundaryPoint& boundary, ContainerNode& container)
   1438 {
   1439     for (Node* nodeToBeRemoved = container.firstChild(); nodeToBeRemoved; nodeToBeRemoved = nodeToBeRemoved->nextSibling()) {
   1440         if (boundary.childBefore() == nodeToBeRemoved) {
   1441             boundary.setToStartOfNode(container);
   1442             return;
   1443         }
   1444 
   1445         for (Node* n = boundary.container(); n; n = n->parentNode()) {
   1446             if (n == nodeToBeRemoved) {
   1447                 boundary.setToStartOfNode(container);
   1448                 return;
   1449             }
   1450         }
   1451     }
   1452 }
   1453 
   1454 void Range::nodeChildrenWillBeRemoved(ContainerNode& container)
   1455 {
   1456     ASSERT(container.document() == m_ownerDocument);
   1457     boundaryNodeChildrenWillBeRemoved(m_start, container);
   1458     boundaryNodeChildrenWillBeRemoved(m_end, container);
   1459 }
   1460 
   1461 static inline void boundaryNodeWillBeRemoved(RangeBoundaryPoint& boundary, Node& nodeToBeRemoved)
   1462 {
   1463     if (boundary.childBefore() == nodeToBeRemoved) {
   1464         boundary.childBeforeWillBeRemoved();
   1465         return;
   1466     }
   1467 
   1468     for (Node* n = boundary.container(); n; n = n->parentNode()) {
   1469         if (n == nodeToBeRemoved) {
   1470             boundary.setToBeforeChild(nodeToBeRemoved);
   1471             return;
   1472         }
   1473     }
   1474 }
   1475 
   1476 void Range::nodeWillBeRemoved(Node& node)
   1477 {
   1478     ASSERT(node.document() == m_ownerDocument);
   1479     ASSERT(node != m_ownerDocument.get());
   1480 
   1481     // FIXME: Once DOMNodeRemovedFromDocument mutation event removed, we
   1482     // should change following if-statement to ASSERT(!node->parentNode).
   1483     if (!node.parentNode())
   1484         return;
   1485     boundaryNodeWillBeRemoved(m_start, node);
   1486     boundaryNodeWillBeRemoved(m_end, node);
   1487 }
   1488 
   1489 static inline void boundaryTextInserted(RangeBoundaryPoint& boundary, Node* text, unsigned offset, unsigned length)
   1490 {
   1491     if (boundary.container() != text)
   1492         return;
   1493     unsigned boundaryOffset = boundary.offset();
   1494     if (offset >= boundaryOffset)
   1495         return;
   1496     boundary.setOffset(boundaryOffset + length);
   1497 }
   1498 
   1499 void Range::didInsertText(Node* text, unsigned offset, unsigned length)
   1500 {
   1501     ASSERT(text);
   1502     ASSERT(text->document() == m_ownerDocument);
   1503     boundaryTextInserted(m_start, text, offset, length);
   1504     boundaryTextInserted(m_end, text, offset, length);
   1505 }
   1506 
   1507 static inline void boundaryTextRemoved(RangeBoundaryPoint& boundary, Node* text, unsigned offset, unsigned length)
   1508 {
   1509     if (boundary.container() != text)
   1510         return;
   1511     unsigned boundaryOffset = boundary.offset();
   1512     if (offset >= boundaryOffset)
   1513         return;
   1514     if (offset + length >= boundaryOffset)
   1515         boundary.setOffset(offset);
   1516     else
   1517         boundary.setOffset(boundaryOffset - length);
   1518 }
   1519 
   1520 void Range::didRemoveText(Node* text, unsigned offset, unsigned length)
   1521 {
   1522     ASSERT(text);
   1523     ASSERT(text->document() == m_ownerDocument);
   1524     boundaryTextRemoved(m_start, text, offset, length);
   1525     boundaryTextRemoved(m_end, text, offset, length);
   1526 }
   1527 
   1528 static inline void boundaryTextNodesMerged(RangeBoundaryPoint& boundary, const NodeWithIndex& oldNode, unsigned offset)
   1529 {
   1530     if (boundary.container() == oldNode.node())
   1531         boundary.set(oldNode.node().previousSibling(), boundary.offset() + offset, 0);
   1532     else if (boundary.container() == oldNode.node().parentNode() && boundary.offset() == oldNode.index())
   1533         boundary.set(oldNode.node().previousSibling(), offset, 0);
   1534 }
   1535 
   1536 void Range::didMergeTextNodes(const NodeWithIndex& oldNode, unsigned offset)
   1537 {
   1538     ASSERT(oldNode.node().document() == m_ownerDocument);
   1539     ASSERT(oldNode.node().parentNode());
   1540     ASSERT(oldNode.node().isTextNode());
   1541     ASSERT(oldNode.node().previousSibling());
   1542     ASSERT(oldNode.node().previousSibling()->isTextNode());
   1543     boundaryTextNodesMerged(m_start, oldNode, offset);
   1544     boundaryTextNodesMerged(m_end, oldNode, offset);
   1545 }
   1546 
   1547 void Range::updateOwnerDocumentIfNeeded()
   1548 {
   1549     ASSERT(m_start.container());
   1550     ASSERT(m_end.container());
   1551     Document& newDocument = m_start.container()->document();
   1552     ASSERT(newDocument == m_end.container()->document());
   1553     if (newDocument == m_ownerDocument)
   1554         return;
   1555     m_ownerDocument->detachRange(this);
   1556     m_ownerDocument = &newDocument;
   1557     m_ownerDocument->attachRange(this);
   1558 }
   1559 
   1560 static inline void boundaryTextNodeSplit(RangeBoundaryPoint& boundary, Text& oldNode)
   1561 {
   1562     Node* boundaryContainer = boundary.container();
   1563     unsigned boundaryOffset = boundary.offset();
   1564     if (boundary.childBefore() == &oldNode)
   1565         boundary.set(boundaryContainer, boundaryOffset + 1, oldNode.nextSibling());
   1566     else if (boundary.container() == &oldNode && boundaryOffset > oldNode.length())
   1567         boundary.set(oldNode.nextSibling(), boundaryOffset - oldNode.length(), 0);
   1568 }
   1569 
   1570 void Range::didSplitTextNode(Text& oldNode)
   1571 {
   1572     ASSERT(oldNode.document() == m_ownerDocument);
   1573     ASSERT(oldNode.parentNode());
   1574     ASSERT(oldNode.isTextNode());
   1575     ASSERT(oldNode.nextSibling());
   1576     ASSERT(oldNode.nextSibling()->isTextNode());
   1577     boundaryTextNodeSplit(m_start, oldNode);
   1578     boundaryTextNodeSplit(m_end, oldNode);
   1579     ASSERT(boundaryPointsValid());
   1580 }
   1581 
   1582 void Range::expand(const String& unit, ExceptionState& exceptionState)
   1583 {
   1584     VisiblePosition start(startPosition());
   1585     VisiblePosition end(endPosition());
   1586     if (unit == "word") {
   1587         start = startOfWord(start);
   1588         end = endOfWord(end);
   1589     } else if (unit == "sentence") {
   1590         start = startOfSentence(start);
   1591         end = endOfSentence(end);
   1592     } else if (unit == "block") {
   1593         start = startOfParagraph(start);
   1594         end = endOfParagraph(end);
   1595     } else if (unit == "document") {
   1596         start = startOfDocument(start);
   1597         end = endOfDocument(end);
   1598     } else
   1599         return;
   1600     setStart(start.deepEquivalent().containerNode(), start.deepEquivalent().computeOffsetInContainerNode(), exceptionState);
   1601     setEnd(end.deepEquivalent().containerNode(), end.deepEquivalent().computeOffsetInContainerNode(), exceptionState);
   1602 }
   1603 
   1604 PassRefPtrWillBeRawPtr<ClientRectList> Range::getClientRects() const
   1605 {
   1606     m_ownerDocument->updateLayoutIgnorePendingStylesheets();
   1607 
   1608     Vector<FloatQuad> quads;
   1609     getBorderAndTextQuads(quads);
   1610 
   1611     return ClientRectList::create(quads);
   1612 }
   1613 
   1614 PassRefPtrWillBeRawPtr<ClientRect> Range::getBoundingClientRect() const
   1615 {
   1616     return ClientRect::create(boundingRect());
   1617 }
   1618 
   1619 void Range::getBorderAndTextQuads(Vector<FloatQuad>& quads) const
   1620 {
   1621     Node* startContainer = m_start.container();
   1622     Node* endContainer = m_end.container();
   1623     Node* stopNode = pastLastNode();
   1624 
   1625     HashSet<Node*> nodeSet;
   1626     for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next(*node)) {
   1627         if (node->isElementNode())
   1628             nodeSet.add(node);
   1629     }
   1630 
   1631     for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next(*node)) {
   1632         if (node->isElementNode()) {
   1633             if (!nodeSet.contains(node->parentNode())) {
   1634                 if (RenderBoxModelObject* renderBoxModelObject = toElement(node)->renderBoxModelObject()) {
   1635                     Vector<FloatQuad> elementQuads;
   1636                     renderBoxModelObject->absoluteQuads(elementQuads);
   1637                     m_ownerDocument->adjustFloatQuadsForScrollAndAbsoluteZoom(elementQuads, *renderBoxModelObject);
   1638 
   1639                     quads.appendVector(elementQuads);
   1640                 }
   1641             }
   1642         } else if (node->isTextNode()) {
   1643             if (RenderObject* renderer = toText(node)->renderer()) {
   1644                 RenderText& renderText = toRenderText(*renderer);
   1645                 int startOffset = (node == startContainer) ? m_start.offset() : 0;
   1646                 int endOffset = (node == endContainer) ? m_end.offset() : INT_MAX;
   1647 
   1648                 Vector<FloatQuad> textQuads;
   1649                 renderText.absoluteQuadsForRange(textQuads, startOffset, endOffset);
   1650                 m_ownerDocument->adjustFloatQuadsForScrollAndAbsoluteZoom(textQuads, renderText);
   1651 
   1652                 quads.appendVector(textQuads);
   1653             }
   1654         }
   1655     }
   1656 }
   1657 
   1658 FloatRect Range::boundingRect() const
   1659 {
   1660     m_ownerDocument->updateLayoutIgnorePendingStylesheets();
   1661 
   1662     Vector<FloatQuad> quads;
   1663     getBorderAndTextQuads(quads);
   1664     if (quads.isEmpty())
   1665         return FloatRect();
   1666 
   1667     FloatRect result;
   1668     for (size_t i = 0; i < quads.size(); ++i)
   1669         result.unite(quads[i].boundingBox());
   1670 
   1671     return result;
   1672 }
   1673 
   1674 void Range::trace(Visitor* visitor)
   1675 {
   1676     visitor->trace(m_ownerDocument);
   1677     visitor->trace(m_start);
   1678     visitor->trace(m_end);
   1679 }
   1680 
   1681 } // namespace WebCore
   1682 
   1683 #ifndef NDEBUG
   1684 
   1685 void showTree(const WebCore::Range* range)
   1686 {
   1687     if (range && range->boundaryPointsValid()) {
   1688         range->startContainer()->showTreeAndMark(range->startContainer(), "S", range->endContainer(), "E");
   1689         fprintf(stderr, "start offset: %d, end offset: %d\n", range->startOffset(), range->endOffset());
   1690     }
   1691 }
   1692 
   1693 #endif
   1694