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