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