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