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