• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 1999 Lars Knoll (knoll@kde.org)
3  * (C) 2000 Gunnstein Lye (gunnstein@netcom.no)
4  * (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
5  * (C) 2001 Peter Kelly (pmk@post.com)
6  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 
24 #include "config.h"
25 #include "Range.h"
26 #include "RangeException.h"
27 
28 #include "CString.h"
29 #include "DocumentFragment.h"
30 #include "HTMLElement.h"
31 #include "NodeWithIndex.h"
32 #include "ProcessingInstruction.h"
33 #include "Text.h"
34 #include "TextIterator.h"
35 #include "VisiblePosition.h"
36 #include "markup.h"
37 #include "visible_units.h"
38 #include <stdio.h>
39 #include <wtf/RefCountedLeakCounter.h>
40 
41 namespace WebCore {
42 
43 using namespace std;
44 
45 #ifndef NDEBUG
46 static WTF::RefCountedLeakCounter rangeCounter("Range");
47 #endif
48 
Range(PassRefPtr<Document> ownerDocument)49 inline Range::Range(PassRefPtr<Document> ownerDocument)
50     : m_ownerDocument(ownerDocument)
51     , m_start(m_ownerDocument)
52     , m_end(m_ownerDocument)
53 {
54 #ifndef NDEBUG
55     rangeCounter.increment();
56 #endif
57 
58     m_ownerDocument->attachRange(this);
59 }
60 
create(PassRefPtr<Document> ownerDocument)61 PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument)
62 {
63     return adoptRef(new Range(ownerDocument));
64 }
65 
Range(PassRefPtr<Document> ownerDocument,PassRefPtr<Node> startContainer,int startOffset,PassRefPtr<Node> endContainer,int endOffset)66 inline Range::Range(PassRefPtr<Document> ownerDocument, PassRefPtr<Node> startContainer, int startOffset, PassRefPtr<Node> endContainer, int endOffset)
67     : m_ownerDocument(ownerDocument)
68     , m_start(m_ownerDocument)
69     , m_end(m_ownerDocument)
70 {
71 #ifndef NDEBUG
72     rangeCounter.increment();
73 #endif
74 
75     m_ownerDocument->attachRange(this);
76 
77     // Simply setting the containers and offsets directly would not do any of the checking
78     // that setStart and setEnd do, so we call those functions.
79     ExceptionCode ec = 0;
80     setStart(startContainer, startOffset, ec);
81     ASSERT(!ec);
82     setEnd(endContainer, endOffset, ec);
83     ASSERT(!ec);
84 }
85 
create(PassRefPtr<Document> ownerDocument,PassRefPtr<Node> startContainer,int startOffset,PassRefPtr<Node> endContainer,int endOffset)86 PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument, PassRefPtr<Node> startContainer, int startOffset, PassRefPtr<Node> endContainer, int endOffset)
87 {
88     return adoptRef(new Range(ownerDocument, startContainer, startOffset, endContainer, endOffset));
89 }
90 
create(PassRefPtr<Document> ownerDocument,const Position & start,const Position & end)91 PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument, const Position& start, const Position& end)
92 {
93     // FIXME: we shouldn't be using deprecatedEditingOffset here
94     return adoptRef(new Range(ownerDocument, start.node(), start.deprecatedEditingOffset(), end.node(), end.deprecatedEditingOffset()));
95 }
96 
~Range()97 Range::~Range()
98 {
99     // Always detach (even if we've already detached) to fix https://bugs.webkit.org/show_bug.cgi?id=26044
100     m_ownerDocument->detachRange(this);
101 
102 #ifndef NDEBUG
103     rangeCounter.decrement();
104 #endif
105 }
106 
startContainer(ExceptionCode & ec) const107 Node* Range::startContainer(ExceptionCode& ec) const
108 {
109     if (!m_start.container()) {
110         ec = INVALID_STATE_ERR;
111         return 0;
112     }
113 
114     return m_start.container();
115 }
116 
startOffset(ExceptionCode & ec) const117 int Range::startOffset(ExceptionCode& ec) const
118 {
119     if (!m_start.container()) {
120         ec = INVALID_STATE_ERR;
121         return 0;
122     }
123 
124     return m_start.offset();
125 }
126 
endContainer(ExceptionCode & ec) const127 Node* Range::endContainer(ExceptionCode& ec) const
128 {
129     if (!m_start.container()) {
130         ec = INVALID_STATE_ERR;
131         return 0;
132     }
133 
134     return m_end.container();
135 }
136 
endOffset(ExceptionCode & ec) const137 int Range::endOffset(ExceptionCode& ec) const
138 {
139     if (!m_start.container()) {
140         ec = INVALID_STATE_ERR;
141         return 0;
142     }
143 
144     return m_end.offset();
145 }
146 
commonAncestorContainer(ExceptionCode & ec) const147 Node* Range::commonAncestorContainer(ExceptionCode& ec) const
148 {
149     if (!m_start.container()) {
150         ec = INVALID_STATE_ERR;
151         return 0;
152     }
153 
154     return commonAncestorContainer(m_start.container(), m_end.container());
155 }
156 
commonAncestorContainer(Node * containerA,Node * containerB)157 Node* Range::commonAncestorContainer(Node* containerA, Node* containerB)
158 {
159     for (Node* parentA = containerA; parentA; parentA = parentA->parentNode()) {
160         for (Node* parentB = containerB; parentB; parentB = parentB->parentNode()) {
161             if (parentA == parentB)
162                 return parentA;
163         }
164     }
165     return 0;
166 }
167 
collapsed(ExceptionCode & ec) const168 bool Range::collapsed(ExceptionCode& ec) const
169 {
170     if (!m_start.container()) {
171         ec = INVALID_STATE_ERR;
172         return 0;
173     }
174 
175     return m_start == m_end;
176 }
177 
setStart(PassRefPtr<Node> refNode,int offset,ExceptionCode & ec)178 void Range::setStart(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec)
179 {
180     if (!m_start.container()) {
181         ec = INVALID_STATE_ERR;
182         return;
183     }
184 
185     if (!refNode) {
186         ec = NOT_FOUND_ERR;
187         return;
188     }
189 
190     if (refNode->document() != m_ownerDocument) {
191         ec = WRONG_DOCUMENT_ERR;
192         return;
193     }
194 
195     ec = 0;
196     Node* childNode = checkNodeWOffset(refNode.get(), offset, ec);
197     if (ec)
198         return;
199 
200     m_start.set(refNode, offset, childNode);
201 
202     // check if different root container
203     Node* endRootContainer = m_end.container();
204     while (endRootContainer->parentNode())
205         endRootContainer = endRootContainer->parentNode();
206     Node* startRootContainer = m_start.container();
207     while (startRootContainer->parentNode())
208         startRootContainer = startRootContainer->parentNode();
209     if (startRootContainer != endRootContainer)
210         collapse(true, ec);
211     // check if new start after end
212     else if (compareBoundaryPoints(m_start, m_end) > 0)
213         collapse(true, ec);
214 }
215 
setEnd(PassRefPtr<Node> refNode,int offset,ExceptionCode & ec)216 void Range::setEnd(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec)
217 {
218     if (!m_start.container()) {
219         ec = INVALID_STATE_ERR;
220         return;
221     }
222 
223     if (!refNode) {
224         ec = NOT_FOUND_ERR;
225         return;
226     }
227 
228     if (refNode->document() != m_ownerDocument) {
229         ec = WRONG_DOCUMENT_ERR;
230         return;
231     }
232 
233     ec = 0;
234     Node* childNode = checkNodeWOffset(refNode.get(), offset, ec);
235     if (ec)
236         return;
237 
238     m_end.set(refNode, offset, childNode);
239 
240     // check if different root container
241     Node* endRootContainer = m_end.container();
242     while (endRootContainer->parentNode())
243         endRootContainer = endRootContainer->parentNode();
244     Node* startRootContainer = m_start.container();
245     while (startRootContainer->parentNode())
246         startRootContainer = startRootContainer->parentNode();
247     if (startRootContainer != endRootContainer)
248         collapse(false, ec);
249     // check if new end before start
250     if (compareBoundaryPoints(m_start, m_end) > 0)
251         collapse(false, ec);
252 }
253 
collapse(bool toStart,ExceptionCode & ec)254 void Range::collapse(bool toStart, ExceptionCode& ec)
255 {
256     if (!m_start.container()) {
257         ec = INVALID_STATE_ERR;
258         return;
259     }
260 
261     if (toStart)
262         m_end = m_start;
263     else
264         m_start = m_end;
265 }
266 
isPointInRange(Node * refNode,int offset,ExceptionCode & ec)267 bool Range::isPointInRange(Node* refNode, int offset, ExceptionCode& ec)
268 {
269     if (!m_start.container()) {
270         ec = INVALID_STATE_ERR;
271         return false;
272     }
273 
274     if (!refNode) {
275         ec = HIERARCHY_REQUEST_ERR;
276         return false;
277     }
278 
279     if (!refNode->attached()) {
280         // Firefox doesn't throw an exception for this case; it returns false.
281         return false;
282     }
283 
284     if (refNode->document() != m_ownerDocument) {
285         ec = WRONG_DOCUMENT_ERR;
286         return false;
287     }
288 
289     ec = 0;
290     checkNodeWOffset(refNode, offset, ec);
291     if (ec)
292         return false;
293 
294     return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset()) >= 0
295         && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset()) <= 0;
296 }
297 
comparePoint(Node * refNode,int offset,ExceptionCode & ec) const298 short Range::comparePoint(Node* refNode, int offset, ExceptionCode& ec) const
299 {
300     // http://developer.mozilla.org/en/docs/DOM:range.comparePoint
301     // This method returns -1, 0 or 1 depending on if the point described by the
302     // refNode node and an offset within the node is before, same as, or after the range respectively.
303 
304     if (!m_start.container()) {
305         ec = INVALID_STATE_ERR;
306         return 0;
307     }
308 
309     if (!refNode) {
310         ec = HIERARCHY_REQUEST_ERR;
311         return 0;
312     }
313 
314     if (!refNode->attached() || refNode->document() != m_ownerDocument) {
315         ec = WRONG_DOCUMENT_ERR;
316         return 0;
317     }
318 
319     ec = 0;
320     checkNodeWOffset(refNode, offset, ec);
321     if (ec)
322         return 0;
323 
324     // compare to start, and point comes before
325     if (compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset()) < 0)
326         return -1;
327 
328     // compare to end, and point comes after
329     if (compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset()) > 0)
330         return 1;
331 
332     // point is in the middle of this range, or on the boundary points
333     return 0;
334 }
335 
compareNode(Node * refNode,ExceptionCode & ec) const336 Range::CompareResults Range::compareNode(Node* refNode, ExceptionCode& ec) const
337 {
338     // http://developer.mozilla.org/en/docs/DOM:range.compareNode
339     // This method returns 0, 1, 2, or 3 based on if the node is before, after,
340     // before and after(surrounds), or inside the range, respectively
341 
342     if (!refNode) {
343         ec = NOT_FOUND_ERR;
344         return NODE_BEFORE;
345     }
346 
347     if (!m_start.container() && refNode->attached()) {
348         ec = INVALID_STATE_ERR;
349         return NODE_BEFORE;
350     }
351 
352     if (m_start.container() && !refNode->attached()) {
353         // Firefox doesn't throw an exception for this case; it returns 0.
354         return NODE_BEFORE;
355     }
356 
357     if (refNode->document() != m_ownerDocument) {
358         // Firefox doesn't throw an exception for this case; it returns 0.
359         return NODE_BEFORE;
360     }
361 
362     Node* parentNode = refNode->parentNode();
363     int nodeIndex = refNode->nodeIndex();
364 
365     if (!parentNode) {
366         // if the node is the top document we should return NODE_BEFORE_AND_AFTER
367         // but we throw to match firefox behavior
368         ec = NOT_FOUND_ERR;
369         return NODE_BEFORE;
370     }
371 
372     if (comparePoint(parentNode, nodeIndex, ec) < 0) { // starts before
373         if (comparePoint(parentNode, nodeIndex + 1, ec) > 0) // ends after the range
374             return NODE_BEFORE_AND_AFTER;
375         return NODE_BEFORE; // ends before or in the range
376     } else { // starts at or after the range start
377         if (comparePoint(parentNode, nodeIndex + 1, ec) > 0) // ends after the range
378             return NODE_AFTER;
379         return NODE_INSIDE; // ends inside the range
380     }
381 }
382 
compareBoundaryPoints(CompareHow how,const Range * sourceRange,ExceptionCode & ec) const383 short Range::compareBoundaryPoints(CompareHow how, const Range* sourceRange, ExceptionCode& ec) const
384 {
385     if (!m_start.container()) {
386         ec = INVALID_STATE_ERR;
387         return 0;
388     }
389 
390     if (!sourceRange) {
391         ec = NOT_FOUND_ERR;
392         return 0;
393     }
394 
395     ec = 0;
396     Node* thisCont = commonAncestorContainer(ec);
397     if (ec)
398         return 0;
399     Node* sourceCont = sourceRange->commonAncestorContainer(ec);
400     if (ec)
401         return 0;
402 
403     if (thisCont->document() != sourceCont->document()) {
404         ec = WRONG_DOCUMENT_ERR;
405         return 0;
406     }
407 
408     Node* thisTop = thisCont;
409     Node* sourceTop = sourceCont;
410     while (thisTop->parentNode())
411         thisTop = thisTop->parentNode();
412     while (sourceTop->parentNode())
413         sourceTop = sourceTop->parentNode();
414     if (thisTop != sourceTop) { // in different DocumentFragments
415         ec = WRONG_DOCUMENT_ERR;
416         return 0;
417     }
418 
419     switch (how) {
420         case START_TO_START:
421             return compareBoundaryPoints(m_start, sourceRange->m_start);
422         case START_TO_END:
423             return compareBoundaryPoints(m_end, sourceRange->m_start);
424         case END_TO_END:
425             return compareBoundaryPoints(m_end, sourceRange->m_end);
426         case END_TO_START:
427             return compareBoundaryPoints(m_start, sourceRange->m_end);
428     }
429 
430     ec = SYNTAX_ERR;
431     return 0;
432 }
433 
compareBoundaryPoints(Node * containerA,int offsetA,Node * containerB,int offsetB)434 short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB)
435 {
436     ASSERT(containerA);
437     ASSERT(containerB);
438 
439     if (!containerA)
440         return -1;
441     if (!containerB)
442         return 1;
443 
444     // see DOM2 traversal & range section 2.5
445 
446     // case 1: both points have the same container
447     if (containerA == containerB) {
448         if (offsetA == offsetB)
449             return 0;           // A is equal to B
450         if (offsetA < offsetB)
451             return -1;          // A is before B
452         else
453             return 1;           // A is after B
454     }
455 
456     // case 2: node C (container B or an ancestor) is a child node of A
457     Node* c = containerB;
458     while (c && c->parentNode() != containerA)
459         c = c->parentNode();
460     if (c) {
461         int offsetC = 0;
462         Node* n = containerA->firstChild();
463         while (n != c && offsetC < offsetA) {
464             offsetC++;
465             n = n->nextSibling();
466         }
467 
468         if (offsetA <= offsetC)
469             return -1;              // A is before B
470         else
471             return 1;               // A is after B
472     }
473 
474     // case 3: node C (container A or an ancestor) is a child node of B
475     c = containerA;
476     while (c && c->parentNode() != containerB)
477         c = c->parentNode();
478     if (c) {
479         int offsetC = 0;
480         Node* n = containerB->firstChild();
481         while (n != c && offsetC < offsetB) {
482             offsetC++;
483             n = n->nextSibling();
484         }
485 
486         if (offsetC < offsetB)
487             return -1;              // A is before B
488         else
489             return 1;               // A is after B
490     }
491 
492     // case 4: containers A & B are siblings, or children of siblings
493     // ### we need to do a traversal here instead
494     Node* commonAncestor = commonAncestorContainer(containerA, containerB);
495     if (!commonAncestor)
496         return 0;
497     Node* childA = containerA;
498     while (childA && childA->parentNode() != commonAncestor)
499         childA = childA->parentNode();
500     if (!childA)
501         childA = commonAncestor;
502     Node* childB = containerB;
503     while (childB && childB->parentNode() != commonAncestor)
504         childB = childB->parentNode();
505     if (!childB)
506         childB = commonAncestor;
507 
508     if (childA == childB)
509         return 0; // A is equal to B
510 
511     Node* n = commonAncestor->firstChild();
512     while (n) {
513         if (n == childA)
514             return -1; // A is before B
515         if (n == childB)
516             return 1; // A is after B
517         n = n->nextSibling();
518     }
519 
520     // Should never reach this point.
521     ASSERT_NOT_REACHED();
522     return 0;
523 }
524 
compareBoundaryPoints(const RangeBoundaryPoint & boundaryA,const RangeBoundaryPoint & boundaryB)525 short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB)
526 {
527     return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boundaryB.container(), boundaryB.offset());
528 }
529 
boundaryPointsValid() const530 bool Range::boundaryPointsValid() const
531 {
532     return m_start.container() && compareBoundaryPoints(m_start, m_end) <= 0;
533 }
534 
deleteContents(ExceptionCode & ec)535 void Range::deleteContents(ExceptionCode& ec)
536 {
537     checkDeleteExtract(ec);
538     if (ec)
539         return;
540 
541     processContents(DELETE_CONTENTS, ec);
542 }
543 
intersectsNode(Node * refNode,ExceptionCode & ec)544 bool Range::intersectsNode(Node* refNode, ExceptionCode& ec)
545 {
546     // http://developer.mozilla.org/en/docs/DOM:range.intersectsNode
547     // Returns a bool if the node intersects the range.
548 
549     if (!refNode) {
550         ec = NOT_FOUND_ERR;
551         return false;
552     }
553 
554     if ((!m_start.container() && refNode->attached())
555             || (m_start.container() && !refNode->attached())
556             || refNode->document() != m_ownerDocument) {
557         // Firefox doesn't throw an exception for these cases; it returns false.
558         return false;
559     }
560 
561     Node* parentNode = refNode->parentNode();
562     int nodeIndex = refNode->nodeIndex();
563 
564     if (!parentNode) {
565         // if the node is the top document we should return NODE_BEFORE_AND_AFTER
566         // but we throw to match firefox behavior
567         ec = NOT_FOUND_ERR;
568         return false;
569     }
570 
571     if (comparePoint(parentNode, nodeIndex, ec) < 0 && // starts before start
572         comparePoint(parentNode, nodeIndex + 1, ec) < 0) { // ends before start
573         return false;
574     } else if (comparePoint(parentNode, nodeIndex, ec) > 0 && // starts after end
575                comparePoint(parentNode, nodeIndex + 1, ec) > 0) { // ends after end
576         return false;
577     }
578 
579     return true; // all other cases
580 }
581 
processContents(ActionType action,ExceptionCode & ec)582 PassRefPtr<DocumentFragment> Range::processContents(ActionType action, ExceptionCode& ec)
583 {
584     // FIXME: To work properly with mutation events, we will have to take into account
585     // situations where the tree is being transformed while we work on it - ugh!
586 
587     RefPtr<DocumentFragment> fragment;
588     if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
589         fragment = new DocumentFragment(m_ownerDocument.get());
590 
591     ec = 0;
592     if (collapsed(ec))
593         return fragment.release();
594     if (ec)
595         return 0;
596 
597     Node* commonRoot = commonAncestorContainer(ec);
598     if (ec)
599         return 0;
600     ASSERT(commonRoot);
601 
602     // what is the highest node that partially selects the start of the range?
603     Node* partialStart = 0;
604     if (m_start.container() != commonRoot) {
605         partialStart = m_start.container();
606         while (partialStart->parentNode() != commonRoot)
607             partialStart = partialStart->parentNode();
608     }
609 
610     // what is the highest node that partially selects the end of the range?
611     Node* partialEnd = 0;
612     if (m_end.container() != commonRoot) {
613         partialEnd = m_end.container();
614         while (partialEnd->parentNode() != commonRoot)
615             partialEnd = partialEnd->parentNode();
616     }
617 
618     // Simple case: the start and end containers are the same. We just grab
619     // everything >= start offset and < end offset
620     if (m_start.container() == m_end.container()) {
621         Node::NodeType startNodeType = m_start.container()->nodeType();
622         if (startNodeType == Node::TEXT_NODE || startNodeType == Node::CDATA_SECTION_NODE || startNodeType == Node::COMMENT_NODE) {
623             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
624                 RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_start.container()->cloneNode(true));
625                 c->deleteData(m_end.offset(), c->length() - m_end.offset(), ec);
626                 c->deleteData(0, m_start.offset(), ec);
627                 fragment->appendChild(c.release(), ec);
628             }
629             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
630                 static_cast<CharacterData*>(m_start.container())->deleteData(m_start.offset(), m_end.offset() - m_start.offset(), ec);
631         } else if (startNodeType == Node::PROCESSING_INSTRUCTION_NODE) {
632             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
633                 RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_start.container()->cloneNode(true));
634                 c->setData(c->data().substring(m_start.offset(), m_end.offset() - m_start.offset()), ec);
635                 fragment->appendChild(c.release(), ec);
636             }
637             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
638                 ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_start.container());
639                 String data(pi->data());
640                 data.remove(m_start.offset(), m_end.offset() - m_start.offset());
641                 pi->setData(data, ec);
642             }
643         } else {
644             Node* n = m_start.container()->firstChild();
645             int i;
646             for (i = 0; n && i < m_start.offset(); i++) // skip until start offset
647                 n = n->nextSibling();
648             int endOffset = m_end.offset();
649             while (n && i < endOffset) { // delete until end offset
650                 Node* next = n->nextSibling();
651                 if (action == EXTRACT_CONTENTS)
652                     fragment->appendChild(n, ec); // will remove n from its parent
653                 else if (action == CLONE_CONTENTS)
654                     fragment->appendChild(n->cloneNode(true), ec);
655                 else
656                     m_start.container()->removeChild(n, ec);
657                 n = next;
658                 i++;
659             }
660         }
661         return fragment.release();
662     }
663 
664     // Complex case: Start and end containers are different.
665     // There are three possiblities here:
666     // 1. Start container == commonRoot (End container must be a descendant)
667     // 2. End container == commonRoot (Start container must be a descendant)
668     // 3. Neither is commonRoot, they are both descendants
669     //
670     // In case 3, we grab everything after the start (up until a direct child
671     // of commonRoot) into leftContents, and everything before the end (up until
672     // a direct child of commonRoot) into rightContents. Then we process all
673     // commonRoot children between leftContents and rightContents
674     //
675     // In case 1 or 2, we skip either processing of leftContents or rightContents,
676     // in which case the last lot of nodes either goes from the first or last
677     // child of commonRoot.
678     //
679     // These are deleted, cloned, or extracted (i.e. both) depending on action.
680 
681     RefPtr<Node> leftContents;
682     if (m_start.container() != commonRoot) {
683         // process the left-hand side of the range, up until the last ancestor of
684         // start container before commonRoot
685         Node::NodeType startNodeType = m_start.container()->nodeType();
686         if (startNodeType == Node::TEXT_NODE || startNodeType == Node::CDATA_SECTION_NODE || startNodeType == Node::COMMENT_NODE) {
687             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
688                 RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_start.container()->cloneNode(true));
689                 c->deleteData(0, m_start.offset(), ec);
690                 leftContents = c.release();
691             }
692             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
693                 static_cast<CharacterData*>(m_start.container())->deleteData(
694                     m_start.offset(), static_cast<CharacterData*>(m_start.container())->length() - m_start.offset(), ec);
695         } else if (startNodeType == Node::PROCESSING_INSTRUCTION_NODE) {
696             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
697                 RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_start.container()->cloneNode(true));
698                 c->setData(c->data().substring(m_start.offset()), ec);
699                 leftContents = c.release();
700             }
701             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
702                 ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_start.container());
703                 String data(pi->data());
704                 pi->setData(data.left(m_start.offset()), ec);
705             }
706         } else {
707             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
708                 leftContents = m_start.container()->cloneNode(false);
709             Node* n = m_start.container()->firstChild();
710             for (int i = 0; n && i < m_start.offset(); i++) // skip until start offset
711                 n = n->nextSibling();
712             while (n) { // process until end
713                 Node* next = n->nextSibling();
714                 if (action == EXTRACT_CONTENTS)
715                     leftContents->appendChild(n, ec); // will remove n from start container
716                 else if (action == CLONE_CONTENTS)
717                     leftContents->appendChild(n->cloneNode(true), ec);
718                 else
719                     m_start.container()->removeChild(n, ec);
720                 n = next;
721             }
722         }
723 
724         Node* leftParent = m_start.container()->parentNode();
725         Node* n = m_start.container()->nextSibling();
726         for (; leftParent != commonRoot; leftParent = leftParent->parentNode()) {
727             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
728                 RefPtr<Node> leftContentsParent = leftParent->cloneNode(false);
729                 leftContentsParent->appendChild(leftContents, ec);
730                 leftContents = leftContentsParent;
731             }
732 
733             Node* next;
734             for (; n; n = next) {
735                 next = n->nextSibling();
736                 if (action == EXTRACT_CONTENTS)
737                     leftContents->appendChild(n, ec); // will remove n from leftParent
738                 else if (action == CLONE_CONTENTS)
739                     leftContents->appendChild(n->cloneNode(true), ec);
740                 else
741                     leftParent->removeChild(n, ec);
742             }
743             n = leftParent->nextSibling();
744         }
745     }
746 
747     RefPtr<Node> rightContents;
748     if (m_end.container() != commonRoot) {
749         // delete the right-hand side of the range, up until the last ancestor of
750         // end container before commonRoot
751         Node::NodeType endNodeType = m_end.container()->nodeType();
752         if (endNodeType == Node::TEXT_NODE || endNodeType == Node::CDATA_SECTION_NODE || endNodeType == Node::COMMENT_NODE) {
753             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
754                 RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_end.container()->cloneNode(true));
755                 c->deleteData(m_end.offset(), static_cast<CharacterData*>(m_end.container())->length() - m_end.offset(), ec);
756                 rightContents = c;
757             }
758             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
759                 static_cast<CharacterData*>(m_end.container())->deleteData(0, m_end.offset(), ec);
760         } else if (endNodeType == Node::PROCESSING_INSTRUCTION_NODE) {
761             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
762                 RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_end.container()->cloneNode(true));
763                 c->setData(c->data().left(m_end.offset()), ec);
764                 rightContents = c.release();
765             }
766             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
767                 ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_end.container());
768                 pi->setData(pi->data().substring(m_end.offset()), ec);
769             }
770         } else {
771             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
772                 rightContents = m_end.container()->cloneNode(false);
773             Node* n = m_end.container()->firstChild();
774             if (n && m_end.offset()) {
775                 for (int i = 0; i + 1 < m_end.offset(); i++) { // skip to end.offset()
776                     Node* next = n->nextSibling();
777                     if (!next)
778                         break;
779                     n = next;
780                 }
781                 Node* prev;
782                 for (; n; n = prev) {
783                     prev = n->previousSibling();
784                     if (action == EXTRACT_CONTENTS)
785                         rightContents->insertBefore(n, rightContents->firstChild(), ec); // will remove n from its parent
786                     else if (action == CLONE_CONTENTS)
787                         rightContents->insertBefore(n->cloneNode(true), rightContents->firstChild(), ec);
788                     else
789                         m_end.container()->removeChild(n, ec);
790                 }
791             }
792         }
793 
794         Node* rightParent = m_end.container()->parentNode();
795         Node* n = m_end.container()->previousSibling();
796         for (; rightParent != commonRoot; rightParent = rightParent->parentNode()) {
797             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
798                 RefPtr<Node> rightContentsParent = rightParent->cloneNode(false);
799                 rightContentsParent->appendChild(rightContents, ec);
800                 rightContents = rightContentsParent;
801             }
802             Node* prev;
803             for (; n; n = prev) {
804                 prev = n->previousSibling();
805                 if (action == EXTRACT_CONTENTS)
806                     rightContents->insertBefore(n, rightContents->firstChild(), ec); // will remove n from its parent
807                 else if (action == CLONE_CONTENTS)
808                     rightContents->insertBefore(n->cloneNode(true), rightContents->firstChild(), ec);
809                 else
810                     rightParent->removeChild(n, ec);
811             }
812             n = rightParent->previousSibling();
813         }
814     }
815 
816     // delete all children of commonRoot between the start and end container
817 
818     Node* processStart; // child of commonRoot
819     if (m_start.container() == commonRoot) {
820         processStart = m_start.container()->firstChild();
821         for (int i = 0; i < m_start.offset(); i++)
822             processStart = processStart->nextSibling();
823     } else {
824         processStart = m_start.container();
825         while (processStart->parentNode() != commonRoot)
826             processStart = processStart->parentNode();
827         processStart = processStart->nextSibling();
828     }
829     Node* processEnd; // child of commonRoot
830     if (m_end.container() == commonRoot) {
831         processEnd = m_end.container()->firstChild();
832         for (int i = 0; i < m_end.offset(); i++)
833             processEnd = processEnd->nextSibling();
834     } else {
835         processEnd = m_end.container();
836         while (processEnd->parentNode() != commonRoot)
837             processEnd = processEnd->parentNode();
838     }
839 
840     // Collapse the range, making sure that the result is not within a node that was partially selected.
841     if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
842         if (partialStart)
843             setStart(partialStart->parentNode(), partialStart->nodeIndex() + 1, ec);
844         else if (partialEnd)
845             setStart(partialEnd->parentNode(), partialEnd->nodeIndex(), ec);
846         if (ec)
847             return 0;
848         m_end = m_start;
849     }
850 
851     // Now add leftContents, stuff in between, and rightContents to the fragment
852     // (or just delete the stuff in between)
853 
854     if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && leftContents)
855         fragment->appendChild(leftContents, ec);
856 
857     Node* next;
858     Node* n;
859     if (processStart) {
860         for (n = processStart; n && n != processEnd; n = next) {
861             next = n->nextSibling();
862             if (action == EXTRACT_CONTENTS)
863                 fragment->appendChild(n, ec); // will remove from commonRoot
864             else if (action == CLONE_CONTENTS)
865                 fragment->appendChild(n->cloneNode(true), ec);
866             else
867                 commonRoot->removeChild(n, ec);
868         }
869     }
870 
871     if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && rightContents)
872         fragment->appendChild(rightContents, ec);
873 
874     return fragment.release();
875 }
876 
extractContents(ExceptionCode & ec)877 PassRefPtr<DocumentFragment> Range::extractContents(ExceptionCode& ec)
878 {
879     checkDeleteExtract(ec);
880     if (ec)
881         return 0;
882 
883     return processContents(EXTRACT_CONTENTS, ec);
884 }
885 
cloneContents(ExceptionCode & ec)886 PassRefPtr<DocumentFragment> Range::cloneContents(ExceptionCode& ec)
887 {
888     if (!m_start.container()) {
889         ec = INVALID_STATE_ERR;
890         return 0;
891     }
892 
893     return processContents(CLONE_CONTENTS, ec);
894 }
895 
insertNode(PassRefPtr<Node> prpNewNode,ExceptionCode & ec)896 void Range::insertNode(PassRefPtr<Node> prpNewNode, ExceptionCode& ec)
897 {
898     RefPtr<Node> newNode = prpNewNode;
899 
900     ec = 0;
901 
902     if (!m_start.container()) {
903         ec = INVALID_STATE_ERR;
904         return;
905     }
906 
907     if (!newNode) {
908         ec = NOT_FOUND_ERR;
909         return;
910     }
911 
912     // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of
913     // the Range is read-only.
914     if (containedByReadOnly()) {
915         ec = NO_MODIFICATION_ALLOWED_ERR;
916         return;
917     }
918 
919     // WRONG_DOCUMENT_ERR: Raised if newParent and the container of the start of the Range were
920     // not created from the same document.
921     if (newNode->document() != m_start.container()->document()) {
922         ec = WRONG_DOCUMENT_ERR;
923         return;
924     }
925 
926     // HIERARCHY_REQUEST_ERR: Raised if the container of the start of the Range is of a type that
927     // does not allow children of the type of newNode or if newNode is an ancestor of the container.
928 
929     // an extra one here - if a text node is going to split, it must have a parent to insert into
930     bool startIsText = m_start.container()->isTextNode();
931     if (startIsText && !m_start.container()->parentNode()) {
932         ec = HIERARCHY_REQUEST_ERR;
933         return;
934     }
935 
936     // In the case where the container is a text node, we check against the container's parent, because
937     // text nodes get split up upon insertion.
938     Node* checkAgainst;
939     if (startIsText)
940         checkAgainst = m_start.container()->parentNode();
941     else
942         checkAgainst = m_start.container();
943 
944     Node::NodeType newNodeType = newNode->nodeType();
945     int numNewChildren;
946     if (newNodeType == Node::DOCUMENT_FRAGMENT_NODE) {
947         // check each child node, not the DocumentFragment itself
948         numNewChildren = 0;
949         for (Node* c = newNode->firstChild(); c; c = c->nextSibling()) {
950             if (!checkAgainst->childTypeAllowed(c->nodeType())) {
951                 ec = HIERARCHY_REQUEST_ERR;
952                 return;
953             }
954             ++numNewChildren;
955         }
956     } else {
957         numNewChildren = 1;
958         if (!checkAgainst->childTypeAllowed(newNodeType)) {
959             ec = HIERARCHY_REQUEST_ERR;
960             return;
961         }
962     }
963 
964     for (Node* n = m_start.container(); n; n = n->parentNode()) {
965         if (n == newNode) {
966             ec = HIERARCHY_REQUEST_ERR;
967             return;
968         }
969     }
970 
971     // INVALID_NODE_TYPE_ERR: Raised if newNode is an Attr, Entity, Notation, or Document node.
972     if (newNodeType == Node::ATTRIBUTE_NODE || newNodeType == Node::ENTITY_NODE
973             || newNodeType == Node::NOTATION_NODE || newNodeType == Node::DOCUMENT_NODE) {
974         ec = RangeException::INVALID_NODE_TYPE_ERR;
975         return;
976     }
977 
978     bool collapsed = m_start == m_end;
979     if (startIsText) {
980         RefPtr<Text> newText = static_cast<Text*>(m_start.container())->splitText(m_start.offset(), ec);
981         if (ec)
982             return;
983         m_start.container()->parentNode()->insertBefore(newNode.release(), newText.get(), ec);
984         if (ec)
985             return;
986 
987         // This special case doesn't seem to match the DOM specification, but it's currently required
988         // to pass Acid3. We might later decide to remove this.
989         if (collapsed)
990             m_end.setToBeforeChild(newText.get());
991     } else {
992         RefPtr<Node> lastChild;
993         if (collapsed)
994             lastChild = (newNodeType == Node::DOCUMENT_FRAGMENT_NODE) ? newNode->lastChild() : newNode;
995 
996         int startOffset = m_start.offset();
997         m_start.container()->insertBefore(newNode.release(), m_start.container()->childNode(startOffset), ec);
998         if (ec)
999             return;
1000 
1001         // This special case doesn't seem to match the DOM specification, but it's currently required
1002         // to pass Acid3. We might later decide to remove this.
1003         if (collapsed)
1004             m_end.set(m_start.container(), startOffset + numNewChildren, lastChild.get());
1005     }
1006 }
1007 
toString(ExceptionCode & ec) const1008 String Range::toString(ExceptionCode& ec) const
1009 {
1010     if (!m_start.container()) {
1011         ec = INVALID_STATE_ERR;
1012         return String();
1013     }
1014 
1015     Vector<UChar> result;
1016 
1017     Node* pastLast = pastLastNode();
1018     for (Node* n = firstNode(); n != pastLast; n = n->traverseNextNode()) {
1019         if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE) {
1020             String data = static_cast<CharacterData*>(n)->data();
1021             int length = data.length();
1022             int start = (n == m_start.container()) ? min(max(0, m_start.offset()), length) : 0;
1023             int end = (n == m_end.container()) ? min(max(start, m_end.offset()), length) : length;
1024             result.append(data.characters() + start, end - start);
1025         }
1026     }
1027 
1028     return String::adopt(result);
1029 }
1030 
toHTML() const1031 String Range::toHTML() const
1032 {
1033     return createMarkup(this);
1034 }
1035 
text() const1036 String Range::text() const
1037 {
1038     if (!m_start.container())
1039         return String();
1040 
1041     // We need to update layout, since plainText uses line boxes in the render tree.
1042     // FIXME: As with innerText, we'd like this to work even if there are no render objects.
1043     m_start.container()->document()->updateLayout();
1044 
1045     return plainText(this);
1046 }
1047 
createContextualFragment(const String & markup,ExceptionCode & ec) const1048 PassRefPtr<DocumentFragment> Range::createContextualFragment(const String& markup, ExceptionCode& ec) const
1049 {
1050     if (!m_start.container()) {
1051         ec = INVALID_STATE_ERR;
1052         return 0;
1053     }
1054 
1055     Node* element = m_start.container()->isElementNode() ? m_start.container() : m_start.container()->parentNode();
1056     if (!element || !element->isHTMLElement()) {
1057         ec = NOT_SUPPORTED_ERR;
1058         return 0;
1059     }
1060 
1061     RefPtr<DocumentFragment> fragment = static_cast<HTMLElement*>(element)->createContextualFragment(markup);
1062     if (!fragment) {
1063         ec = NOT_SUPPORTED_ERR;
1064         return 0;
1065     }
1066 
1067     return fragment.release();
1068 }
1069 
1070 
detach(ExceptionCode & ec)1071 void Range::detach(ExceptionCode& ec)
1072 {
1073     // Check first to see if we've already detached:
1074     if (!m_start.container()) {
1075         ec = INVALID_STATE_ERR;
1076         return;
1077     }
1078 
1079     m_ownerDocument->detachRange(this);
1080 
1081     m_start.clear();
1082     m_end.clear();
1083 }
1084 
checkNodeWOffset(Node * n,int offset,ExceptionCode & ec) const1085 Node* Range::checkNodeWOffset(Node* n, int offset, ExceptionCode& ec) const
1086 {
1087     switch (n->nodeType()) {
1088         case Node::DOCUMENT_TYPE_NODE:
1089         case Node::ENTITY_NODE:
1090         case Node::NOTATION_NODE:
1091             ec = RangeException::INVALID_NODE_TYPE_ERR;
1092             return 0;
1093         case Node::CDATA_SECTION_NODE:
1094         case Node::COMMENT_NODE:
1095         case Node::TEXT_NODE:
1096             if (static_cast<unsigned>(offset) > static_cast<CharacterData*>(n)->length())
1097                 ec = INDEX_SIZE_ERR;
1098             return 0;
1099         case Node::PROCESSING_INSTRUCTION_NODE:
1100             if (static_cast<unsigned>(offset) > static_cast<ProcessingInstruction*>(n)->data().length())
1101                 ec = INDEX_SIZE_ERR;
1102             return 0;
1103         case Node::ATTRIBUTE_NODE:
1104         case Node::DOCUMENT_FRAGMENT_NODE:
1105         case Node::DOCUMENT_NODE:
1106         case Node::ELEMENT_NODE:
1107         case Node::ENTITY_REFERENCE_NODE:
1108         case Node::XPATH_NAMESPACE_NODE: {
1109             if (!offset)
1110                 return 0;
1111             Node* childBefore = n->childNode(offset - 1);
1112             if (!childBefore)
1113                 ec = INDEX_SIZE_ERR;
1114             return childBefore;
1115         }
1116     }
1117     ASSERT_NOT_REACHED();
1118     return 0;
1119 }
1120 
checkNodeBA(Node * n,ExceptionCode & ec) const1121 void Range::checkNodeBA(Node* n, ExceptionCode& ec) const
1122 {
1123     // INVALID_NODE_TYPE_ERR: Raised if the root container of refNode is not an
1124     // Attr, Document or DocumentFragment node or part of a shadow DOM tree
1125     // or if refNode is a Document, DocumentFragment, Attr, Entity, or Notation node.
1126 
1127     switch (n->nodeType()) {
1128         case Node::ATTRIBUTE_NODE:
1129         case Node::DOCUMENT_FRAGMENT_NODE:
1130         case Node::DOCUMENT_NODE:
1131         case Node::ENTITY_NODE:
1132         case Node::NOTATION_NODE:
1133             ec = RangeException::INVALID_NODE_TYPE_ERR;
1134             return;
1135         case Node::CDATA_SECTION_NODE:
1136         case Node::COMMENT_NODE:
1137         case Node::DOCUMENT_TYPE_NODE:
1138         case Node::ELEMENT_NODE:
1139         case Node::ENTITY_REFERENCE_NODE:
1140         case Node::PROCESSING_INSTRUCTION_NODE:
1141         case Node::TEXT_NODE:
1142         case Node::XPATH_NAMESPACE_NODE:
1143             break;
1144     }
1145 
1146     Node* root = n;
1147     while (Node* parent = root->parentNode())
1148         root = parent;
1149 
1150     switch (root->nodeType()) {
1151         case Node::ATTRIBUTE_NODE:
1152         case Node::DOCUMENT_NODE:
1153         case Node::DOCUMENT_FRAGMENT_NODE:
1154             break;
1155         case Node::CDATA_SECTION_NODE:
1156         case Node::COMMENT_NODE:
1157         case Node::DOCUMENT_TYPE_NODE:
1158         case Node::ELEMENT_NODE:
1159         case Node::ENTITY_NODE:
1160         case Node::ENTITY_REFERENCE_NODE:
1161         case Node::NOTATION_NODE:
1162         case Node::PROCESSING_INSTRUCTION_NODE:
1163         case Node::TEXT_NODE:
1164         case Node::XPATH_NAMESPACE_NODE:
1165             if (root->isShadowNode())
1166                 break;
1167             ec = RangeException::INVALID_NODE_TYPE_ERR;
1168             return;
1169     }
1170 }
1171 
cloneRange(ExceptionCode & ec) const1172 PassRefPtr<Range> Range::cloneRange(ExceptionCode& ec) const
1173 {
1174     if (!m_start.container()) {
1175         ec = INVALID_STATE_ERR;
1176         return 0;
1177     }
1178 
1179     return Range::create(m_ownerDocument, m_start.container(), m_start.offset(), m_end.container(), m_end.offset());
1180 }
1181 
setStartAfter(Node * refNode,ExceptionCode & ec)1182 void Range::setStartAfter(Node* refNode, ExceptionCode& ec)
1183 {
1184     if (!m_start.container()) {
1185         ec = INVALID_STATE_ERR;
1186         return;
1187     }
1188 
1189     if (!refNode) {
1190         ec = NOT_FOUND_ERR;
1191         return;
1192     }
1193 
1194     if (refNode->document() != m_ownerDocument) {
1195         ec = WRONG_DOCUMENT_ERR;
1196         return;
1197     }
1198 
1199     ec = 0;
1200     checkNodeBA(refNode, ec);
1201     if (ec)
1202         return;
1203 
1204     setStart(refNode->parentNode(), refNode->nodeIndex() + 1, ec);
1205 }
1206 
setEndBefore(Node * refNode,ExceptionCode & ec)1207 void Range::setEndBefore(Node* refNode, ExceptionCode& ec)
1208 {
1209     if (!m_start.container()) {
1210         ec = INVALID_STATE_ERR;
1211         return;
1212     }
1213 
1214     if (!refNode) {
1215         ec = NOT_FOUND_ERR;
1216         return;
1217     }
1218 
1219     if (refNode->document() != m_ownerDocument) {
1220         ec = WRONG_DOCUMENT_ERR;
1221         return;
1222     }
1223 
1224     ec = 0;
1225     checkNodeBA(refNode, ec);
1226     if (ec)
1227         return;
1228 
1229     setEnd(refNode->parentNode(), refNode->nodeIndex(), ec);
1230 }
1231 
setEndAfter(Node * refNode,ExceptionCode & ec)1232 void Range::setEndAfter(Node* refNode, ExceptionCode& ec)
1233 {
1234     if (!m_start.container()) {
1235         ec = INVALID_STATE_ERR;
1236         return;
1237     }
1238 
1239     if (!refNode) {
1240         ec = NOT_FOUND_ERR;
1241         return;
1242     }
1243 
1244     if (refNode->document() != m_ownerDocument) {
1245         ec = WRONG_DOCUMENT_ERR;
1246         return;
1247     }
1248 
1249     ec = 0;
1250     checkNodeBA(refNode, ec);
1251     if (ec)
1252         return;
1253 
1254     setEnd(refNode->parentNode(), refNode->nodeIndex() + 1, ec);
1255 
1256 }
1257 
selectNode(Node * refNode,ExceptionCode & ec)1258 void Range::selectNode(Node* refNode, ExceptionCode& ec)
1259 {
1260     if (!m_start.container()) {
1261         ec = INVALID_STATE_ERR;
1262         return;
1263     }
1264 
1265     if (!refNode) {
1266         ec = NOT_FOUND_ERR;
1267         return;
1268     }
1269 
1270     // INVALID_NODE_TYPE_ERR: Raised if an ancestor of refNode is an Entity, Notation or
1271     // DocumentType node or if refNode is a Document, DocumentFragment, Attr, Entity, or Notation
1272     // node.
1273     for (Node* anc = refNode->parentNode(); anc; anc = anc->parentNode()) {
1274         switch (anc->nodeType()) {
1275             case Node::ATTRIBUTE_NODE:
1276             case Node::CDATA_SECTION_NODE:
1277             case Node::COMMENT_NODE:
1278             case Node::DOCUMENT_FRAGMENT_NODE:
1279             case Node::DOCUMENT_NODE:
1280             case Node::ELEMENT_NODE:
1281             case Node::ENTITY_REFERENCE_NODE:
1282             case Node::PROCESSING_INSTRUCTION_NODE:
1283             case Node::TEXT_NODE:
1284             case Node::XPATH_NAMESPACE_NODE:
1285                 break;
1286             case Node::DOCUMENT_TYPE_NODE:
1287             case Node::ENTITY_NODE:
1288             case Node::NOTATION_NODE:
1289                 ec = RangeException::INVALID_NODE_TYPE_ERR;
1290                 return;
1291         }
1292     }
1293 
1294     switch (refNode->nodeType()) {
1295         case Node::CDATA_SECTION_NODE:
1296         case Node::COMMENT_NODE:
1297         case Node::DOCUMENT_TYPE_NODE:
1298         case Node::ELEMENT_NODE:
1299         case Node::ENTITY_REFERENCE_NODE:
1300         case Node::PROCESSING_INSTRUCTION_NODE:
1301         case Node::TEXT_NODE:
1302         case Node::XPATH_NAMESPACE_NODE:
1303             break;
1304         case Node::ATTRIBUTE_NODE:
1305         case Node::DOCUMENT_FRAGMENT_NODE:
1306         case Node::DOCUMENT_NODE:
1307         case Node::ENTITY_NODE:
1308         case Node::NOTATION_NODE:
1309             ec = RangeException::INVALID_NODE_TYPE_ERR;
1310             return;
1311     }
1312 
1313     ec = 0;
1314     setStartBefore(refNode, ec);
1315     if (ec)
1316         return;
1317     setEndAfter(refNode, ec);
1318 }
1319 
selectNodeContents(Node * refNode,ExceptionCode & ec)1320 void Range::selectNodeContents(Node* refNode, ExceptionCode& ec)
1321 {
1322     if (!m_start.container()) {
1323         ec = INVALID_STATE_ERR;
1324         return;
1325     }
1326 
1327     if (!refNode) {
1328         ec = NOT_FOUND_ERR;
1329         return;
1330     }
1331 
1332     // INVALID_NODE_TYPE_ERR: Raised if refNode or an ancestor of refNode is an Entity, Notation
1333     // or DocumentType node.
1334     for (Node* n = refNode; n; n = n->parentNode()) {
1335         switch (n->nodeType()) {
1336             case Node::ATTRIBUTE_NODE:
1337             case Node::CDATA_SECTION_NODE:
1338             case Node::COMMENT_NODE:
1339             case Node::DOCUMENT_FRAGMENT_NODE:
1340             case Node::DOCUMENT_NODE:
1341             case Node::ELEMENT_NODE:
1342             case Node::ENTITY_REFERENCE_NODE:
1343             case Node::PROCESSING_INSTRUCTION_NODE:
1344             case Node::TEXT_NODE:
1345             case Node::XPATH_NAMESPACE_NODE:
1346                 break;
1347             case Node::DOCUMENT_TYPE_NODE:
1348             case Node::ENTITY_NODE:
1349             case Node::NOTATION_NODE:
1350                 ec = RangeException::INVALID_NODE_TYPE_ERR;
1351                 return;
1352         }
1353     }
1354 
1355     m_start.setToStartOfNode(refNode);
1356     m_end.setToEndOfNode(refNode);
1357 }
1358 
surroundContents(PassRefPtr<Node> passNewParent,ExceptionCode & ec)1359 void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec)
1360 {
1361     RefPtr<Node> newParent = passNewParent;
1362 
1363     if (!m_start.container()) {
1364         ec = INVALID_STATE_ERR;
1365         return;
1366     }
1367 
1368     if (!newParent) {
1369         ec = NOT_FOUND_ERR;
1370         return;
1371     }
1372 
1373     // INVALID_NODE_TYPE_ERR: Raised if node is an Attr, Entity, DocumentType, Notation,
1374     // Document, or DocumentFragment node.
1375     switch (newParent->nodeType()) {
1376         case Node::ATTRIBUTE_NODE:
1377         case Node::DOCUMENT_FRAGMENT_NODE:
1378         case Node::DOCUMENT_NODE:
1379         case Node::DOCUMENT_TYPE_NODE:
1380         case Node::ENTITY_NODE:
1381         case Node::NOTATION_NODE:
1382             ec = RangeException::INVALID_NODE_TYPE_ERR;
1383             return;
1384         case Node::CDATA_SECTION_NODE:
1385         case Node::COMMENT_NODE:
1386         case Node::ELEMENT_NODE:
1387         case Node::ENTITY_REFERENCE_NODE:
1388         case Node::PROCESSING_INSTRUCTION_NODE:
1389         case Node::TEXT_NODE:
1390         case Node::XPATH_NAMESPACE_NODE:
1391             break;
1392     }
1393 
1394     // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of
1395     // the Range is read-only.
1396     if (containedByReadOnly()) {
1397         ec = NO_MODIFICATION_ALLOWED_ERR;
1398         return;
1399     }
1400 
1401     // WRONG_DOCUMENT_ERR: Raised if newParent and the container of the start of the Range were
1402     // not created from the same document.
1403     if (newParent->document() != m_start.container()->document()) {
1404         ec = WRONG_DOCUMENT_ERR;
1405         return;
1406     }
1407 
1408     // Raise a HIERARCHY_REQUEST_ERR if m_start.container() doesn't accept children like newParent.
1409     Node* parentOfNewParent = m_start.container();
1410 
1411     // If m_start.container() is a character data node, it will be split and it will be its parent that will
1412     // need to accept newParent (or in the case of a comment, it logically "would" be inserted into the parent,
1413     // although this will fail below for another reason).
1414     if (parentOfNewParent->isCharacterDataNode())
1415         parentOfNewParent = parentOfNewParent->parentNode();
1416     if (!parentOfNewParent->childTypeAllowed(newParent->nodeType())) {
1417         ec = HIERARCHY_REQUEST_ERR;
1418         return;
1419     }
1420 
1421     if (m_start.container() == newParent || m_start.container()->isDescendantOf(newParent.get())) {
1422         ec = HIERARCHY_REQUEST_ERR;
1423         return;
1424     }
1425 
1426     // FIXME: Do we need a check if the node would end up with a child node of a type not
1427     // allowed by the type of node?
1428 
1429     // BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially selects a non-Text node.
1430     Node* startNonTextContainer = m_start.container();
1431     if (startNonTextContainer->nodeType() == Node::TEXT_NODE)
1432         startNonTextContainer = startNonTextContainer->parentNode();
1433     Node* endNonTextContainer = m_end.container();
1434     if (endNonTextContainer->nodeType() == Node::TEXT_NODE)
1435         endNonTextContainer = endNonTextContainer->parentNode();
1436     if (startNonTextContainer != endNonTextContainer) {
1437         ec = RangeException::BAD_BOUNDARYPOINTS_ERR;
1438         return;
1439     }
1440 
1441     ec = 0;
1442     while (Node* n = newParent->firstChild()) {
1443         newParent->removeChild(n, ec);
1444         if (ec)
1445             return;
1446     }
1447     RefPtr<DocumentFragment> fragment = extractContents(ec);
1448     if (ec)
1449         return;
1450     insertNode(newParent, ec);
1451     if (ec)
1452         return;
1453     newParent->appendChild(fragment.release(), ec);
1454     if (ec)
1455         return;
1456     selectNode(newParent.get(), ec);
1457 }
1458 
setStartBefore(Node * refNode,ExceptionCode & ec)1459 void Range::setStartBefore(Node* refNode, ExceptionCode& ec)
1460 {
1461     if (!m_start.container()) {
1462         ec = INVALID_STATE_ERR;
1463         return;
1464     }
1465 
1466     if (!refNode) {
1467         ec = NOT_FOUND_ERR;
1468         return;
1469     }
1470 
1471     if (refNode->document() != m_ownerDocument) {
1472         ec = WRONG_DOCUMENT_ERR;
1473         return;
1474     }
1475 
1476     ec = 0;
1477     checkNodeBA(refNode, ec);
1478     if (ec)
1479         return;
1480 
1481     setStart(refNode->parentNode(), refNode->nodeIndex(), ec);
1482 }
1483 
checkDeleteExtract(ExceptionCode & ec)1484 void Range::checkDeleteExtract(ExceptionCode& ec)
1485 {
1486     if (!m_start.container()) {
1487         ec = INVALID_STATE_ERR;
1488         return;
1489     }
1490 
1491     ec = 0;
1492     if (!commonAncestorContainer(ec) || ec)
1493         return;
1494 
1495     Node* pastLast = pastLastNode();
1496     for (Node* n = firstNode(); n != pastLast; n = n->traverseNextNode()) {
1497         if (n->isReadOnlyNode()) {
1498             ec = NO_MODIFICATION_ALLOWED_ERR;
1499             return;
1500         }
1501         if (n->nodeType() == Node::DOCUMENT_TYPE_NODE) {
1502             ec = HIERARCHY_REQUEST_ERR;
1503             return;
1504         }
1505     }
1506 
1507     if (containedByReadOnly()) {
1508         ec = NO_MODIFICATION_ALLOWED_ERR;
1509         return;
1510     }
1511 }
1512 
containedByReadOnly() const1513 bool Range::containedByReadOnly() const
1514 {
1515     for (Node* n = m_start.container(); n; n = n->parentNode()) {
1516         if (n->isReadOnlyNode())
1517             return true;
1518     }
1519     for (Node* n = m_end.container(); n; n = n->parentNode()) {
1520         if (n->isReadOnlyNode())
1521             return true;
1522     }
1523     return false;
1524 }
1525 
firstNode() const1526 Node* Range::firstNode() const
1527 {
1528     if (!m_start.container())
1529         return 0;
1530     if (m_start.container()->offsetInCharacters())
1531         return m_start.container();
1532     if (Node* child = m_start.container()->childNode(m_start.offset()))
1533         return child;
1534     if (!m_start.offset())
1535         return m_start.container();
1536     return m_start.container()->traverseNextSibling();
1537 }
1538 
editingStartPosition() const1539 Position Range::editingStartPosition() const
1540 {
1541     // This function is used by range style computations to avoid bugs like:
1542     // <rdar://problem/4017641> REGRESSION (Mail): you can only bold/unbold a selection starting from end of line once
1543     // It is important to skip certain irrelevant content at the start of the selection, so we do not wind up
1544     // with a spurious "mixed" style.
1545 
1546     VisiblePosition visiblePosition(m_start.container(), m_start.offset(), VP_DEFAULT_AFFINITY);
1547     if (visiblePosition.isNull())
1548         return Position();
1549 
1550     ExceptionCode ec = 0;
1551     // if the selection is a caret, just return the position, since the style
1552     // behind us is relevant
1553     if (collapsed(ec))
1554         return visiblePosition.deepEquivalent();
1555 
1556     // if the selection starts just before a paragraph break, skip over it
1557     if (isEndOfParagraph(visiblePosition))
1558         return visiblePosition.next().deepEquivalent().downstream();
1559 
1560     // otherwise, make sure to be at the start of the first selected node,
1561     // instead of possibly at the end of the last node before the selection
1562     return visiblePosition.deepEquivalent().downstream();
1563 }
1564 
shadowTreeRootNode() const1565 Node* Range::shadowTreeRootNode() const
1566 {
1567     return startContainer() ? startContainer()->shadowTreeRootNode() : 0;
1568 }
1569 
pastLastNode() const1570 Node* Range::pastLastNode() const
1571 {
1572     if (!m_start.container() || !m_end.container())
1573         return 0;
1574     if (m_end.container()->offsetInCharacters())
1575         return m_end.container()->traverseNextSibling();
1576     if (Node* child = m_end.container()->childNode(m_end.offset()))
1577         return child;
1578     return m_end.container()->traverseNextSibling();
1579 }
1580 
boundingBox()1581 IntRect Range::boundingBox()
1582 {
1583     IntRect result;
1584     Vector<IntRect> rects;
1585     textRects(rects);
1586     const size_t n = rects.size();
1587     for (size_t i = 0; i < n; ++i)
1588         result.unite(rects[i]);
1589     return result;
1590 }
1591 
textRects(Vector<IntRect> & rects,bool useSelectionHeight)1592 void Range::textRects(Vector<IntRect>& rects, bool useSelectionHeight)
1593 {
1594     if (!m_start.container() || !m_end.container())
1595         return;
1596 
1597     Node* startContainer = m_start.container();
1598     Node* endContainer = m_end.container();
1599 
1600     Node* stopNode = pastLastNode();
1601     for (Node* node = firstNode(); node != stopNode; node = node->traverseNextNode()) {
1602         RenderObject* r = node->renderer();
1603         if (!r || !r->isText())
1604             continue;
1605         RenderText* renderText = toRenderText(r);
1606         int startOffset = node == startContainer ? m_start.offset() : 0;
1607         int endOffset = node == endContainer ? m_end.offset() : INT_MAX;
1608         renderText->absoluteRectsForRange(rects, startOffset, endOffset, useSelectionHeight);
1609     }
1610 }
1611 
1612 #ifndef NDEBUG
1613 #define FormatBufferSize 1024
formatForDebugger(char * buffer,unsigned length) const1614 void Range::formatForDebugger(char* buffer, unsigned length) const
1615 {
1616     String result;
1617     String s;
1618 
1619     if (!m_start.container() || !m_end.container())
1620         result = "<empty>";
1621     else {
1622         char s[FormatBufferSize];
1623         result += "from offset ";
1624         result += String::number(m_start.offset());
1625         result += " of ";
1626         m_start.container()->formatForDebugger(s, FormatBufferSize);
1627         result += s;
1628         result += " to offset ";
1629         result += String::number(m_end.offset());
1630         result += " of ";
1631         m_end.container()->formatForDebugger(s, FormatBufferSize);
1632         result += s;
1633     }
1634 
1635     strncpy(buffer, result.utf8().data(), length - 1);
1636 }
1637 #undef FormatBufferSize
1638 #endif
1639 
operator ==(const Range & a,const Range & b)1640 bool operator==(const Range& a, const Range& b)
1641 {
1642     if (&a == &b)
1643         return true;
1644     // Not strictly legal C++, but in practice this can happen, and this check works
1645     // fine with GCC to detect such cases and return false rather than crashing.
1646     if (!&a || !&b)
1647         return false;
1648     return a.startPosition() == b.startPosition() && a.endPosition() == b.endPosition();
1649 }
1650 
rangeOfContents(Node * node)1651 PassRefPtr<Range> rangeOfContents(Node* node)
1652 {
1653     ASSERT(node);
1654     RefPtr<Range> range = Range::create(node->document());
1655     int exception = 0;
1656     range->selectNodeContents(node, exception);
1657     return range.release();
1658 }
1659 
maxStartOffset() const1660 int Range::maxStartOffset() const
1661 {
1662     if (!m_start.container())
1663         return 0;
1664     if (!m_start.container()->offsetInCharacters())
1665         return m_start.container()->childNodeCount();
1666     return m_start.container()->maxCharacterOffset();
1667 }
1668 
maxEndOffset() const1669 int Range::maxEndOffset() const
1670 {
1671     if (!m_end.container())
1672         return 0;
1673     if (!m_end.container()->offsetInCharacters())
1674         return m_end.container()->childNodeCount();
1675     return m_end.container()->maxCharacterOffset();
1676 }
1677 
boundaryNodeChildrenChanged(RangeBoundaryPoint & boundary,ContainerNode * container)1678 static inline void boundaryNodeChildrenChanged(RangeBoundaryPoint& boundary, ContainerNode* container)
1679 {
1680     if (!boundary.childBefore())
1681         return;
1682     if (boundary.container() != container)
1683         return;
1684     boundary.invalidateOffset();
1685 }
1686 
nodeChildrenChanged(ContainerNode * container)1687 void Range::nodeChildrenChanged(ContainerNode* container)
1688 {
1689     ASSERT(container);
1690     ASSERT(container->document() == m_ownerDocument);
1691     boundaryNodeChildrenChanged(m_start, container);
1692     boundaryNodeChildrenChanged(m_end, container);
1693 }
1694 
boundaryNodeWillBeRemoved(RangeBoundaryPoint & boundary,Node * nodeToBeRemoved)1695 static inline void boundaryNodeWillBeRemoved(RangeBoundaryPoint& boundary, Node* nodeToBeRemoved)
1696 {
1697     if (boundary.childBefore() == nodeToBeRemoved) {
1698         boundary.childBeforeWillBeRemoved();
1699         return;
1700     }
1701 
1702     for (Node* n = boundary.container(); n; n = n->parentNode()) {
1703         if (n == nodeToBeRemoved) {
1704             boundary.setToBeforeChild(nodeToBeRemoved);
1705             return;
1706         }
1707     }
1708 }
1709 
nodeWillBeRemoved(Node * node)1710 void Range::nodeWillBeRemoved(Node* node)
1711 {
1712     ASSERT(node);
1713     ASSERT(node->document() == m_ownerDocument);
1714     ASSERT(node != m_ownerDocument);
1715     ASSERT(node->parentNode());
1716     boundaryNodeWillBeRemoved(m_start, node);
1717     boundaryNodeWillBeRemoved(m_end, node);
1718 }
1719 
boundaryTextInserted(RangeBoundaryPoint & boundary,Node * text,unsigned offset,unsigned length)1720 static inline void boundaryTextInserted(RangeBoundaryPoint& boundary, Node* text, unsigned offset, unsigned length)
1721 {
1722     if (boundary.container() != text)
1723         return;
1724     unsigned boundaryOffset = boundary.offset();
1725     if (offset >= boundaryOffset)
1726         return;
1727     boundary.setOffset(boundaryOffset + length);
1728 }
1729 
textInserted(Node * text,unsigned offset,unsigned length)1730 void Range::textInserted(Node* text, unsigned offset, unsigned length)
1731 {
1732     ASSERT(text);
1733     ASSERT(text->document() == m_ownerDocument);
1734     boundaryTextInserted(m_start, text, offset, length);
1735     boundaryTextInserted(m_end, text, offset, length);
1736 }
1737 
boundaryTextRemoved(RangeBoundaryPoint & boundary,Node * text,unsigned offset,unsigned length)1738 static inline void boundaryTextRemoved(RangeBoundaryPoint& boundary, Node* text, unsigned offset, unsigned length)
1739 {
1740     if (boundary.container() != text)
1741         return;
1742     unsigned boundaryOffset = boundary.offset();
1743     if (offset >= boundaryOffset)
1744         return;
1745     if (offset + length >= boundaryOffset)
1746         boundary.setOffset(offset);
1747     else
1748         boundary.setOffset(boundaryOffset - length);
1749 }
1750 
textRemoved(Node * text,unsigned offset,unsigned length)1751 void Range::textRemoved(Node* text, unsigned offset, unsigned length)
1752 {
1753     ASSERT(text);
1754     ASSERT(text->document() == m_ownerDocument);
1755     boundaryTextRemoved(m_start, text, offset, length);
1756     boundaryTextRemoved(m_end, text, offset, length);
1757 }
1758 
boundaryTextNodesMerged(RangeBoundaryPoint & boundary,NodeWithIndex & oldNode,unsigned offset)1759 static inline void boundaryTextNodesMerged(RangeBoundaryPoint& boundary, NodeWithIndex& oldNode, unsigned offset)
1760 {
1761     if (boundary.container() == oldNode.node())
1762         boundary.set(oldNode.node()->previousSibling(), boundary.offset() + offset, 0);
1763     else if (boundary.container() == oldNode.node()->parentNode() && boundary.offset() == oldNode.index())
1764         boundary.set(oldNode.node()->previousSibling(), offset, 0);
1765 }
1766 
textNodesMerged(NodeWithIndex & oldNode,unsigned offset)1767 void Range::textNodesMerged(NodeWithIndex& oldNode, unsigned offset)
1768 {
1769     ASSERT(oldNode.node());
1770     ASSERT(oldNode.node()->document() == m_ownerDocument);
1771     ASSERT(oldNode.node()->parentNode());
1772     ASSERT(oldNode.node()->isTextNode());
1773     ASSERT(oldNode.node()->previousSibling());
1774     ASSERT(oldNode.node()->previousSibling()->isTextNode());
1775     boundaryTextNodesMerged(m_start, oldNode, offset);
1776     boundaryTextNodesMerged(m_end, oldNode, offset);
1777 }
1778 
boundaryTextNodesSplit(RangeBoundaryPoint & boundary,Text * oldNode)1779 static inline void boundaryTextNodesSplit(RangeBoundaryPoint& boundary, Text* oldNode)
1780 {
1781     if (boundary.container() != oldNode)
1782         return;
1783     unsigned boundaryOffset = boundary.offset();
1784     if (boundaryOffset <= oldNode->length())
1785         return;
1786     boundary.set(oldNode->nextSibling(), boundaryOffset - oldNode->length(), 0);
1787 }
1788 
textNodeSplit(Text * oldNode)1789 void Range::textNodeSplit(Text* oldNode)
1790 {
1791     ASSERT(oldNode);
1792     ASSERT(oldNode->document() == m_ownerDocument);
1793     ASSERT(oldNode->parentNode());
1794     ASSERT(oldNode->isTextNode());
1795     ASSERT(oldNode->nextSibling());
1796     ASSERT(oldNode->nextSibling()->isTextNode());
1797     boundaryTextNodesSplit(m_start, oldNode);
1798     boundaryTextNodesSplit(m_end, oldNode);
1799 }
1800 
1801 }
1802