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