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