| OLD | NEW |
| 1 /* | 1 /* |
| 2 * (C) 1999 Lars Knoll (knoll@kde.org) | 2 * (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 2000 Gunnstein Lye (gunnstein@netcom.no) | 3 * (C) 2000 Gunnstein Lye (gunnstein@netcom.no) |
| 4 * (C) 2000 Frederik Holljen (frederik.holljen@hig.no) | 4 * (C) 2000 Frederik Holljen (frederik.holljen@hig.no) |
| 5 * (C) 2001 Peter Kelly (pmk@post.com) | 5 * (C) 2001 Peter Kelly (pmk@post.com) |
| 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r
ights reserved. | 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All |
| 7 * rights reserved. |
| 7 * Copyright (C) 2011 Motorola Mobility. All rights reserved. | 8 * Copyright (C) 2011 Motorola Mobility. All rights reserved. |
| 8 * | 9 * |
| 9 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
| 10 * modify it under the terms of the GNU Library General Public | 11 * modify it under the terms of the GNU Library General Public |
| 11 * License as published by the Free Software Foundation; either | 12 * License as published by the Free Software Foundation; either |
| 12 * version 2 of the License, or (at your option) any later version. | 13 * version 2 of the License, or (at your option) any later version. |
| 13 * | 14 * |
| 14 * This library is distributed in the hope that it will be useful, | 15 * This library is distributed in the hope that it will be useful, |
| 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 inline Range::Range(Document& ownerDocument, | 69 inline Range::Range(Document& ownerDocument, |
| 69 Node* startContainer, | 70 Node* startContainer, |
| 70 int startOffset, | 71 int startOffset, |
| 71 Node* endContainer, | 72 Node* endContainer, |
| 72 int endOffset) | 73 int endOffset) |
| 73 : m_ownerDocument(&ownerDocument), | 74 : m_ownerDocument(&ownerDocument), |
| 74 m_start(m_ownerDocument), | 75 m_start(m_ownerDocument), |
| 75 m_end(m_ownerDocument) { | 76 m_end(m_ownerDocument) { |
| 76 m_ownerDocument->attachRange(this); | 77 m_ownerDocument->attachRange(this); |
| 77 | 78 |
| 78 // Simply setting the containers and offsets directly would not do any of the
checking | 79 // Simply setting the containers and offsets directly would not do any of the |
| 79 // that setStart and setEnd do, so we call those functions. | 80 // checking that setStart and setEnd do, so we call those functions. |
| 80 setStart(startContainer, startOffset); | 81 setStart(startContainer, startOffset); |
| 81 setEnd(endContainer, endOffset); | 82 setEnd(endContainer, endOffset); |
| 82 } | 83 } |
| 83 | 84 |
| 84 Range* Range::create(Document& ownerDocument, | 85 Range* Range::create(Document& ownerDocument, |
| 85 Node* startContainer, | 86 Node* startContainer, |
| 86 int startOffset, | 87 int startOffset, |
| 87 Node* endContainer, | 88 Node* endContainer, |
| 88 int endOffset) { | 89 int endOffset) { |
| 89 return new Range(ownerDocument, startContainer, startOffset, endContainer, | 90 return new Range(ownerDocument, startContainer, startOffset, endContainer, |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 startRootContainer = startRootContainer->parentNode(); | 163 startRootContainer = startRootContainer->parentNode(); |
| 163 | 164 |
| 164 return startRootContainer != endRootContainer || | 165 return startRootContainer != endRootContainer || |
| 165 (Range::compareBoundaryPoints(start, end, ASSERT_NO_EXCEPTION) > 0); | 166 (Range::compareBoundaryPoints(start, end, ASSERT_NO_EXCEPTION) > 0); |
| 166 } | 167 } |
| 167 | 168 |
| 168 void Range::setStart(Node* refNode, | 169 void Range::setStart(Node* refNode, |
| 169 int offset, | 170 int offset, |
| 170 ExceptionState& exceptionState) { | 171 ExceptionState& exceptionState) { |
| 171 if (!refNode) { | 172 if (!refNode) { |
| 172 // FIXME: Generated bindings code never calls with null, and neither should
other callers! | 173 // FIXME: Generated bindings code never calls with null, and neither should |
| 174 // other callers! |
| 173 exceptionState.throwTypeError("The node provided is null."); | 175 exceptionState.throwTypeError("The node provided is null."); |
| 174 return; | 176 return; |
| 175 } | 177 } |
| 176 | 178 |
| 177 bool didMoveDocument = false; | 179 bool didMoveDocument = false; |
| 178 if (refNode->document() != m_ownerDocument) { | 180 if (refNode->document() != m_ownerDocument) { |
| 179 setDocument(refNode->document()); | 181 setDocument(refNode->document()); |
| 180 didMoveDocument = true; | 182 didMoveDocument = true; |
| 181 } | 183 } |
| 182 | 184 |
| 183 Node* childNode = checkNodeWOffset(refNode, offset, exceptionState); | 185 Node* childNode = checkNodeWOffset(refNode, offset, exceptionState); |
| 184 if (exceptionState.hadException()) | 186 if (exceptionState.hadException()) |
| 185 return; | 187 return; |
| 186 | 188 |
| 187 m_start.set(refNode, offset, childNode); | 189 m_start.set(refNode, offset, childNode); |
| 188 | 190 |
| 189 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) | 191 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) |
| 190 collapse(true); | 192 collapse(true); |
| 191 } | 193 } |
| 192 | 194 |
| 193 void Range::setEnd(Node* refNode, int offset, ExceptionState& exceptionState) { | 195 void Range::setEnd(Node* refNode, int offset, ExceptionState& exceptionState) { |
| 194 if (!refNode) { | 196 if (!refNode) { |
| 195 // FIXME: Generated bindings code never calls with null, and neither should
other callers! | 197 // FIXME: Generated bindings code never calls with null, and neither should |
| 198 // other callers! |
| 196 exceptionState.throwTypeError("The node provided is null."); | 199 exceptionState.throwTypeError("The node provided is null."); |
| 197 return; | 200 return; |
| 198 } | 201 } |
| 199 | 202 |
| 200 bool didMoveDocument = false; | 203 bool didMoveDocument = false; |
| 201 if (refNode->document() != m_ownerDocument) { | 204 if (refNode->document() != m_ownerDocument) { |
| 202 setDocument(refNode->document()); | 205 setDocument(refNode->document()); |
| 203 didMoveDocument = true; | 206 didMoveDocument = true; |
| 204 } | 207 } |
| 205 | 208 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 228 void Range::collapse(bool toStart) { | 231 void Range::collapse(bool toStart) { |
| 229 if (toStart) | 232 if (toStart) |
| 230 m_end = m_start; | 233 m_end = m_start; |
| 231 else | 234 else |
| 232 m_start = m_end; | 235 m_start = m_end; |
| 233 } | 236 } |
| 234 | 237 |
| 235 bool Range::isNodeFullyContained(Node& node) const { | 238 bool Range::isNodeFullyContained(Node& node) const { |
| 236 ContainerNode* parentNode = node.parentNode(); | 239 ContainerNode* parentNode = node.parentNode(); |
| 237 int nodeIndex = node.nodeIndex(); | 240 int nodeIndex = node.nodeIndex(); |
| 238 return isPointInRange( | 241 return isPointInRange(parentNode, nodeIndex, |
| 239 parentNode, nodeIndex, | 242 IGNORE_EXCEPTION) // starts in the middle of this |
| 240 IGNORE_EXCEPTION) // starts in the middle of this range, or on the
boundary points. | 243 // range, or on the boundary points. |
| 241 && | 244 && isPointInRange(parentNode, nodeIndex + 1, |
| 242 isPointInRange( | 245 IGNORE_EXCEPTION); // ends in the middle of this |
| 243 parentNode, nodeIndex + 1, | 246 // range, or on the boundary |
| 244 IGNORE_EXCEPTION); // ends in the middle of this range, or on the
boundary points. | 247 // points. |
| 245 } | 248 } |
| 246 | 249 |
| 247 bool Range::isPointInRange(Node* refNode, | 250 bool Range::isPointInRange(Node* refNode, |
| 248 int offset, | 251 int offset, |
| 249 ExceptionState& exceptionState) const { | 252 ExceptionState& exceptionState) const { |
| 250 if (!refNode) { | 253 if (!refNode) { |
| 251 // FIXME: Generated bindings code never calls with null, and neither should
other callers! | 254 // FIXME: Generated bindings code never calls with null, and neither should |
| 255 // other callers! |
| 252 exceptionState.throwTypeError("The node provided is null."); | 256 exceptionState.throwTypeError("The node provided is null."); |
| 253 return false; | 257 return false; |
| 254 } | 258 } |
| 255 | 259 |
| 256 if (!refNode->inActiveDocument() || refNode->document() != m_ownerDocument) { | 260 if (!refNode->inActiveDocument() || refNode->document() != m_ownerDocument) { |
| 257 return false; | 261 return false; |
| 258 } | 262 } |
| 259 | 263 |
| 260 checkNodeWOffset(refNode, offset, exceptionState); | 264 checkNodeWOffset(refNode, offset, exceptionState); |
| 261 if (exceptionState.hadException()) | 265 if (exceptionState.hadException()) |
| 262 return false; | 266 return false; |
| 263 | 267 |
| 264 return compareBoundaryPoints(refNode, offset, m_start.container(), | 268 return compareBoundaryPoints(refNode, offset, m_start.container(), |
| 265 m_start.offset(), exceptionState) >= 0 && | 269 m_start.offset(), exceptionState) >= 0 && |
| 266 !exceptionState.hadException() && | 270 !exceptionState.hadException() && |
| 267 compareBoundaryPoints(refNode, offset, m_end.container(), | 271 compareBoundaryPoints(refNode, offset, m_end.container(), |
| 268 m_end.offset(), exceptionState) <= 0 && | 272 m_end.offset(), exceptionState) <= 0 && |
| 269 !exceptionState.hadException(); | 273 !exceptionState.hadException(); |
| 270 } | 274 } |
| 271 | 275 |
| 272 short Range::comparePoint(Node* refNode, | 276 short Range::comparePoint(Node* refNode, |
| 273 int offset, | 277 int offset, |
| 274 ExceptionState& exceptionState) const { | 278 ExceptionState& exceptionState) const { |
| 275 // http://developer.mozilla.org/en/docs/DOM:range.comparePoint | 279 // http://developer.mozilla.org/en/docs/DOM:range.comparePoint |
| 276 // This method returns -1, 0 or 1 depending on if the point described by the | 280 // This method returns -1, 0 or 1 depending on if the point described by the |
| 277 // refNode node and an offset within the node is before, same as, or after the
range respectively. | 281 // refNode node and an offset within the node is before, same as, or after the |
| 282 // range respectively. |
| 278 | 283 |
| 279 if (!refNode->inActiveDocument()) { | 284 if (!refNode->inActiveDocument()) { |
| 280 exceptionState.throwDOMException( | 285 exceptionState.throwDOMException( |
| 281 WrongDocumentError, "The node provided is not in an active document."); | 286 WrongDocumentError, "The node provided is not in an active document."); |
| 282 return 0; | 287 return 0; |
| 283 } | 288 } |
| 284 | 289 |
| 285 if (refNode->document() != m_ownerDocument) { | 290 if (refNode->document() != m_ownerDocument) { |
| 286 exceptionState.throwDOMException( | 291 exceptionState.throwDOMException( |
| 287 WrongDocumentError, | 292 WrongDocumentError, |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 { | 402 { |
| 398 EventQueueScope eventQueueScope; | 403 EventQueueScope eventQueueScope; |
| 399 processContents(DELETE_CONTENTS, exceptionState); | 404 processContents(DELETE_CONTENTS, exceptionState); |
| 400 } | 405 } |
| 401 } | 406 } |
| 402 | 407 |
| 403 static bool nodeValidForIntersects(Node* refNode, | 408 static bool nodeValidForIntersects(Node* refNode, |
| 404 Document* expectedDocument, | 409 Document* expectedDocument, |
| 405 ExceptionState& exceptionState) { | 410 ExceptionState& exceptionState) { |
| 406 if (!refNode) { | 411 if (!refNode) { |
| 407 // FIXME: Generated bindings code never calls with null, and neither should
other callers! | 412 // FIXME: Generated bindings code never calls with null, and neither should |
| 413 // other callers! |
| 408 exceptionState.throwTypeError("The node provided is null."); | 414 exceptionState.throwTypeError("The node provided is null."); |
| 409 return false; | 415 return false; |
| 410 } | 416 } |
| 411 | 417 |
| 412 if (!refNode->inActiveDocument() || refNode->document() != expectedDocument) { | 418 if (!refNode->inActiveDocument() || refNode->document() != expectedDocument) { |
| 413 // Firefox doesn't throw an exception for these cases; it returns false. | 419 // Firefox doesn't throw an exception for these cases; it returns false. |
| 414 return false; | 420 return false; |
| 415 } | 421 } |
| 416 | 422 |
| 417 return true; | 423 return true; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 Node* commonRoot = commonAncestorContainer(); | 546 Node* commonRoot = commonAncestorContainer(); |
| 541 DCHECK(commonRoot); | 547 DCHECK(commonRoot); |
| 542 | 548 |
| 543 if (m_start.container() == m_end.container()) { | 549 if (m_start.container() == m_end.container()) { |
| 544 processContentsBetweenOffsets(action, fragment, m_start.container(), | 550 processContentsBetweenOffsets(action, fragment, m_start.container(), |
| 545 m_start.offset(), m_end.offset(), | 551 m_start.offset(), m_end.offset(), |
| 546 exceptionState); | 552 exceptionState); |
| 547 return fragment; | 553 return fragment; |
| 548 } | 554 } |
| 549 | 555 |
| 550 // Since mutation observers can modify the range during the process, the bound
ary points need to be saved. | 556 // Since mutation observers can modify the range during the process, the |
| 557 // boundary points need to be saved. |
| 551 RangeBoundaryPoint originalStart(m_start); | 558 RangeBoundaryPoint originalStart(m_start); |
| 552 RangeBoundaryPoint originalEnd(m_end); | 559 RangeBoundaryPoint originalEnd(m_end); |
| 553 | 560 |
| 554 // what is the highest node that partially selects the start / end of the rang
e? | 561 // what is the highest node that partially selects the start / end of the |
| 562 // range? |
| 555 Node* partialStart = | 563 Node* partialStart = |
| 556 highestAncestorUnderCommonRoot(originalStart.container(), commonRoot); | 564 highestAncestorUnderCommonRoot(originalStart.container(), commonRoot); |
| 557 Node* partialEnd = | 565 Node* partialEnd = |
| 558 highestAncestorUnderCommonRoot(originalEnd.container(), commonRoot); | 566 highestAncestorUnderCommonRoot(originalEnd.container(), commonRoot); |
| 559 | 567 |
| 560 // Start and end containers are different. | 568 // Start and end containers are different. |
| 561 // There are three possibilities here: | 569 // There are three possibilities here: |
| 562 // 1. Start container == commonRoot (End container must be a descendant) | 570 // 1. Start container == commonRoot (End container must be a descendant) |
| 563 // 2. End container == commonRoot (Start container must be a descendant) | 571 // 2. End container == commonRoot (Start container must be a descendant) |
| 564 // 3. Neither is commonRoot, they are both descendants | 572 // 3. Neither is commonRoot, they are both descendants |
| 565 // | 573 // |
| 566 // In case 3, we grab everything after the start (up until a direct child | 574 // In case 3, we grab everything after the start (up until a direct child |
| 567 // of commonRoot) into leftContents, and everything before the end (up until | 575 // of commonRoot) into leftContents, and everything before the end (up until |
| 568 // a direct child of commonRoot) into rightContents. Then we process all | 576 // a direct child of commonRoot) into rightContents. Then we process all |
| 569 // commonRoot children between leftContents and rightContents | 577 // commonRoot children between leftContents and rightContents |
| 570 // | 578 // |
| 571 // In case 1 or 2, we skip either processing of leftContents or rightContents, | 579 // In case 1 or 2, we skip either processing of leftContents or rightContents, |
| 572 // in which case the last lot of nodes either goes from the first or last | 580 // in which case the last lot of nodes either goes from the first or last |
| 573 // child of commonRoot. | 581 // child of commonRoot. |
| 574 // | 582 // |
| 575 // These are deleted, cloned, or extracted (i.e. both) depending on action. | 583 // These are deleted, cloned, or extracted (i.e. both) depending on action. |
| 576 | 584 |
| 577 // Note that we are verifying that our common root hierarchy is still intact | 585 // Note that we are verifying that our common root hierarchy is still intact |
| 578 // after any DOM mutation event, at various stages below. See webkit bug 60350
. | 586 // after any DOM mutation event, at various stages below. See webkit bug |
| 587 // 60350. |
| 579 | 588 |
| 580 Node* leftContents = nullptr; | 589 Node* leftContents = nullptr; |
| 581 if (originalStart.container() != commonRoot && | 590 if (originalStart.container() != commonRoot && |
| 582 commonRoot->contains(originalStart.container())) { | 591 commonRoot->contains(originalStart.container())) { |
| 583 leftContents = processContentsBetweenOffsets( | 592 leftContents = processContentsBetweenOffsets( |
| 584 action, nullptr, originalStart.container(), originalStart.offset(), | 593 action, nullptr, originalStart.container(), originalStart.offset(), |
| 585 originalStart.container()->lengthOfContents(), exceptionState); | 594 originalStart.container()->lengthOfContents(), exceptionState); |
| 586 leftContents = processAncestorsAndTheirSiblings( | 595 leftContents = processAncestorsAndTheirSiblings( |
| 587 action, originalStart.container(), ProcessContentsForward, leftContents, | 596 action, originalStart.container(), ProcessContentsForward, leftContents, |
| 588 commonRoot, exceptionState); | 597 commonRoot, exceptionState); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 602 // delete all children of commonRoot between the start and end container | 611 // delete all children of commonRoot between the start and end container |
| 603 Node* processStart = childOfCommonRootBeforeOffset( | 612 Node* processStart = childOfCommonRootBeforeOffset( |
| 604 originalStart.container(), originalStart.offset(), commonRoot); | 613 originalStart.container(), originalStart.offset(), commonRoot); |
| 605 if (processStart && | 614 if (processStart && |
| 606 originalStart.container() != | 615 originalStart.container() != |
| 607 commonRoot) // processStart contains nodes before m_start. | 616 commonRoot) // processStart contains nodes before m_start. |
| 608 processStart = processStart->nextSibling(); | 617 processStart = processStart->nextSibling(); |
| 609 Node* processEnd = childOfCommonRootBeforeOffset( | 618 Node* processEnd = childOfCommonRootBeforeOffset( |
| 610 originalEnd.container(), originalEnd.offset(), commonRoot); | 619 originalEnd.container(), originalEnd.offset(), commonRoot); |
| 611 | 620 |
| 612 // Collapse the range, making sure that the result is not within a node that w
as partially selected. | 621 // Collapse the range, making sure that the result is not within a node that |
| 622 // was partially selected. |
| 613 if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) { | 623 if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) { |
| 614 if (partialStart && commonRoot->contains(partialStart)) { | 624 if (partialStart && commonRoot->contains(partialStart)) { |
| 615 // FIXME: We should not continue if we have an earlier error. | 625 // FIXME: We should not continue if we have an earlier error. |
| 616 exceptionState.clearException(); | 626 exceptionState.clearException(); |
| 617 setStart(partialStart->parentNode(), partialStart->nodeIndex() + 1, | 627 setStart(partialStart->parentNode(), partialStart->nodeIndex() + 1, |
| 618 exceptionState); | 628 exceptionState); |
| 619 } else if (partialEnd && commonRoot->contains(partialEnd)) { | 629 } else if (partialEnd && commonRoot->contains(partialEnd)) { |
| 620 // FIXME: We should not continue if we have an earlier error. | 630 // FIXME: We should not continue if we have an earlier error. |
| 621 exceptionState.clearException(); | 631 exceptionState.clearException(); |
| 622 setStart(partialEnd->parentNode(), partialEnd->nodeIndex(), | 632 setStart(partialEnd->parentNode(), partialEnd->nodeIndex(), |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 661 | 671 |
| 662 Node* Range::processContentsBetweenOffsets(ActionType action, | 672 Node* Range::processContentsBetweenOffsets(ActionType action, |
| 663 DocumentFragment* fragment, | 673 DocumentFragment* fragment, |
| 664 Node* container, | 674 Node* container, |
| 665 unsigned startOffset, | 675 unsigned startOffset, |
| 666 unsigned endOffset, | 676 unsigned endOffset, |
| 667 ExceptionState& exceptionState) { | 677 ExceptionState& exceptionState) { |
| 668 DCHECK(container); | 678 DCHECK(container); |
| 669 DCHECK_LE(startOffset, endOffset); | 679 DCHECK_LE(startOffset, endOffset); |
| 670 | 680 |
| 671 // This switch statement must be consistent with that of Node::lengthOfContent
s. | 681 // This switch statement must be consistent with that of |
| 682 // Node::lengthOfContents. |
| 672 Node* result = nullptr; | 683 Node* result = nullptr; |
| 673 switch (container->getNodeType()) { | 684 switch (container->getNodeType()) { |
| 674 case Node::kTextNode: | 685 case Node::kTextNode: |
| 675 case Node::kCdataSectionNode: | 686 case Node::kCdataSectionNode: |
| 676 case Node::kCommentNode: | 687 case Node::kCommentNode: |
| 677 case Node::kProcessingInstructionNode: | 688 case Node::kProcessingInstructionNode: |
| 678 endOffset = std::min(endOffset, toCharacterData(container)->length()); | 689 endOffset = std::min(endOffset, toCharacterData(container)->length()); |
| 679 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { | 690 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { |
| 680 CharacterData* c = | 691 CharacterData* c = |
| 681 static_cast<CharacterData*>(container->cloneNode(true)); | 692 static_cast<CharacterData*>(container->cloneNode(true)); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 754 if (runner == commonRoot) | 765 if (runner == commonRoot) |
| 755 break; | 766 break; |
| 756 ancestors.append(runner); | 767 ancestors.append(runner); |
| 757 } | 768 } |
| 758 | 769 |
| 759 Node* firstChildInAncestorToProcess = direction == ProcessContentsForward | 770 Node* firstChildInAncestorToProcess = direction == ProcessContentsForward |
| 760 ? container->nextSibling() | 771 ? container->nextSibling() |
| 761 : container->previousSibling(); | 772 : container->previousSibling(); |
| 762 for (const auto& ancestor : ancestors) { | 773 for (const auto& ancestor : ancestors) { |
| 763 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { | 774 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { |
| 764 if (Node* clonedAncestor = ancestor->cloneNode( | 775 // Might have been removed already during mutation event. |
| 765 false)) { // Might have been removed already during mutation even
t. | 776 if (Node* clonedAncestor = ancestor->cloneNode(false)) { |
| 766 clonedAncestor->appendChild(clonedContainer, exceptionState); | 777 clonedAncestor->appendChild(clonedContainer, exceptionState); |
| 767 clonedContainer = clonedAncestor; | 778 clonedContainer = clonedAncestor; |
| 768 } | 779 } |
| 769 } | 780 } |
| 770 | 781 |
| 771 // Copy siblings of an ancestor of start/end containers | 782 // Copy siblings of an ancestor of start/end containers |
| 772 // FIXME: This assertion may fail if DOM is modified during mutation event | 783 // FIXME: This assertion may fail if DOM is modified during mutation event |
| 773 // FIXME: Share code with Range::processNodes | 784 // FIXME: Share code with Range::processNodes |
| 774 DCHECK(!firstChildInAncestorToProcess || | 785 DCHECK(!firstChildInAncestorToProcess || |
| 775 firstChildInAncestorToProcess->parentNode() == ancestor); | 786 firstChildInAncestorToProcess->parentNode() == ancestor); |
| 776 | 787 |
| 777 NodeVector nodes; | 788 NodeVector nodes; |
| 778 for (Node* child = firstChildInAncestorToProcess; child; | 789 for (Node* child = firstChildInAncestorToProcess; child; |
| 779 child = (direction == ProcessContentsForward) | 790 child = (direction == ProcessContentsForward) |
| 780 ? child->nextSibling() | 791 ? child->nextSibling() |
| 781 : child->previousSibling()) | 792 : child->previousSibling()) |
| 782 nodes.append(child); | 793 nodes.append(child); |
| 783 | 794 |
| 784 for (const auto& node : nodes) { | 795 for (const auto& node : nodes) { |
| 785 Node* child = node.get(); | 796 Node* child = node.get(); |
| 786 switch (action) { | 797 switch (action) { |
| 787 case DELETE_CONTENTS: | 798 case DELETE_CONTENTS: |
| 788 // Prior call of ancestor->removeChild() may cause a tree change due t
o DOMSubtreeModified event. | 799 // Prior call of ancestor->removeChild() may cause a tree change due |
| 789 // Therefore, we need to make sure |ancestor| is still |child|'s paren
t. | 800 // to DOMSubtreeModified event. Therefore, we need to make sure |
| 801 // |ancestor| is still |child|'s parent. |
| 790 if (ancestor == child->parentNode()) | 802 if (ancestor == child->parentNode()) |
| 791 ancestor->removeChild(child, exceptionState); | 803 ancestor->removeChild(child, exceptionState); |
| 792 break; | 804 break; |
| 793 case EXTRACT_CONTENTS: // will remove child from ancestor | 805 case EXTRACT_CONTENTS: // will remove child from ancestor |
| 794 if (direction == ProcessContentsForward) | 806 if (direction == ProcessContentsForward) |
| 795 clonedContainer->appendChild(child, exceptionState); | 807 clonedContainer->appendChild(child, exceptionState); |
| 796 else | 808 else |
| 797 clonedContainer->insertBefore(child, clonedContainer->firstChild(), | 809 clonedContainer->insertBefore(child, clonedContainer->firstChild(), |
| 798 exceptionState); | 810 exceptionState); |
| 799 break; | 811 break; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 823 | 835 |
| 824 return processContents(EXTRACT_CONTENTS, exceptionState); | 836 return processContents(EXTRACT_CONTENTS, exceptionState); |
| 825 } | 837 } |
| 826 | 838 |
| 827 DocumentFragment* Range::cloneContents(ExceptionState& exceptionState) { | 839 DocumentFragment* Range::cloneContents(ExceptionState& exceptionState) { |
| 828 return processContents(CLONE_CONTENTS, exceptionState); | 840 return processContents(CLONE_CONTENTS, exceptionState); |
| 829 } | 841 } |
| 830 | 842 |
| 831 void Range::insertNode(Node* newNode, ExceptionState& exceptionState) { | 843 void Range::insertNode(Node* newNode, ExceptionState& exceptionState) { |
| 832 if (!newNode) { | 844 if (!newNode) { |
| 833 // FIXME: Generated bindings code never calls with null, and neither should
other callers! | 845 // FIXME: Generated bindings code never calls with null, and neither should |
| 846 // other callers! |
| 834 exceptionState.throwTypeError("The node provided is null."); | 847 exceptionState.throwTypeError("The node provided is null."); |
| 835 return; | 848 return; |
| 836 } | 849 } |
| 837 | 850 |
| 838 // HierarchyRequestError: Raised if the container of the start of the Range is
of a type that | 851 // HierarchyRequestError: Raised if the container of the start of the Range is |
| 839 // does not allow children of the type of newNode or if newNode is an ancestor
of the container. | 852 // of a type that does not allow children of the type of newNode or if newNode |
| 853 // is an ancestor of the container. |
| 840 | 854 |
| 841 // an extra one here - if a text node is going to split, it must have a parent
to insert into | 855 // an extra one here - if a text node is going to split, it must have a parent |
| 856 // to insert into |
| 842 bool startIsText = m_start.container()->isTextNode(); | 857 bool startIsText = m_start.container()->isTextNode(); |
| 843 if (startIsText && !m_start.container()->parentNode()) { | 858 if (startIsText && !m_start.container()->parentNode()) { |
| 844 exceptionState.throwDOMException(HierarchyRequestError, | 859 exceptionState.throwDOMException(HierarchyRequestError, |
| 845 "This operation would split a text node, " | 860 "This operation would split a text node, " |
| 846 "but there's no parent into which to " | 861 "but there's no parent into which to " |
| 847 "insert."); | 862 "insert."); |
| 848 return; | 863 return; |
| 849 } | 864 } |
| 850 | 865 |
| 851 // In the case where the container is a text node, we check against the contai
ner's parent, because | 866 // In the case where the container is a text node, we check against the |
| 852 // text nodes get split up upon insertion. | 867 // container's parent, because text nodes get split up upon insertion. |
| 853 Node* checkAgainst; | 868 Node* checkAgainst; |
| 854 if (startIsText) | 869 if (startIsText) |
| 855 checkAgainst = m_start.container()->parentNode(); | 870 checkAgainst = m_start.container()->parentNode(); |
| 856 else | 871 else |
| 857 checkAgainst = m_start.container(); | 872 checkAgainst = m_start.container(); |
| 858 | 873 |
| 859 Node::NodeType newNodeType = newNode->getNodeType(); | 874 Node::NodeType newNodeType = newNode->getNodeType(); |
| 860 int numNewChildren; | 875 int numNewChildren; |
| 861 if (newNodeType == Node::kDocumentFragmentNode && !newNode->isShadowRoot()) { | 876 if (newNodeType == Node::kDocumentFragmentNode && !newNode->isShadowRoot()) { |
| 862 // check each child node, not the DocumentFragment itself | 877 // check each child node, not the DocumentFragment itself |
| (...skipping 23 matching lines...) Expand all Loading... |
| 886 for (Node& node : NodeTraversal::inclusiveAncestorsOf(*m_start.container())) { | 901 for (Node& node : NodeTraversal::inclusiveAncestorsOf(*m_start.container())) { |
| 887 if (node == newNode) { | 902 if (node == newNode) { |
| 888 exceptionState.throwDOMException(HierarchyRequestError, | 903 exceptionState.throwDOMException(HierarchyRequestError, |
| 889 "The node to be inserted contains the " | 904 "The node to be inserted contains the " |
| 890 "insertion point; it may not be " | 905 "insertion point; it may not be " |
| 891 "inserted into itself."); | 906 "inserted into itself."); |
| 892 return; | 907 return; |
| 893 } | 908 } |
| 894 } | 909 } |
| 895 | 910 |
| 896 // InvalidNodeTypeError: Raised if newNode is an Attr, Entity, Notation, Shado
wRoot or Document node. | 911 // InvalidNodeTypeError: Raised if newNode is an Attr, Entity, Notation, |
| 912 // ShadowRoot or Document node. |
| 897 switch (newNodeType) { | 913 switch (newNodeType) { |
| 898 case Node::kAttributeNode: | 914 case Node::kAttributeNode: |
| 899 case Node::kDocumentNode: | 915 case Node::kDocumentNode: |
| 900 exceptionState.throwDOMException( | 916 exceptionState.throwDOMException( |
| 901 InvalidNodeTypeError, "The node to be inserted is a '" + | 917 InvalidNodeTypeError, "The node to be inserted is a '" + |
| 902 newNode->nodeName() + | 918 newNode->nodeName() + |
| 903 "' node, which may not be inserted here."); | 919 "' node, which may not be inserted here."); |
| 904 return; | 920 return; |
| 905 default: | 921 default: |
| 906 if (newNode->isShadowRoot()) { | 922 if (newNode->isShadowRoot()) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 939 "but there's no parent into which to continue."); | 955 "but there's no parent into which to continue."); |
| 940 return; | 956 return; |
| 941 } | 957 } |
| 942 m_end.setToBeforeChild(*newText); | 958 m_end.setToBeforeChild(*newText); |
| 943 } | 959 } |
| 944 } else { | 960 } else { |
| 945 Node* lastChild = (newNodeType == Node::kDocumentFragmentNode) | 961 Node* lastChild = (newNodeType == Node::kDocumentFragmentNode) |
| 946 ? toDocumentFragment(newNode)->lastChild() | 962 ? toDocumentFragment(newNode)->lastChild() |
| 947 : newNode; | 963 : newNode; |
| 948 if (lastChild && lastChild == m_start.childBefore()) { | 964 if (lastChild && lastChild == m_start.childBefore()) { |
| 949 // The insertion will do nothing, but we need to extend the range to inclu
de | 965 // The insertion will do nothing, but we need to extend the range to |
| 950 // the inserted nodes. | 966 // include the inserted nodes. |
| 951 Node* firstChild = (newNodeType == Node::kDocumentFragmentNode) | 967 Node* firstChild = (newNodeType == Node::kDocumentFragmentNode) |
| 952 ? toDocumentFragment(newNode)->firstChild() | 968 ? toDocumentFragment(newNode)->firstChild() |
| 953 : newNode; | 969 : newNode; |
| 954 DCHECK(firstChild); | 970 DCHECK(firstChild); |
| 955 m_start.setToBeforeChild(*firstChild); | 971 m_start.setToBeforeChild(*firstChild); |
| 956 return; | 972 return; |
| 957 } | 973 } |
| 958 | 974 |
| 959 container = m_start.container(); | 975 container = m_start.container(); |
| 960 container->insertBefore( | 976 container->insertBefore( |
| 961 newNode, NodeTraversal::childAt(*container, m_start.offset()), | 977 newNode, NodeTraversal::childAt(*container, m_start.offset()), |
| 962 exceptionState); | 978 exceptionState); |
| 963 if (exceptionState.hadException()) | 979 if (exceptionState.hadException()) |
| 964 return; | 980 return; |
| 965 | 981 |
| 966 // Note that m_start.offset() may have changed as a result of container->ins
ertBefore, | 982 // Note that m_start.offset() may have changed as a result of |
| 967 // when the node we are inserting comes before the range in the same contain
er. | 983 // container->insertBefore, when the node we are inserting comes before the |
| 984 // range in the same container. |
| 968 if (collapsed && numNewChildren) | 985 if (collapsed && numNewChildren) |
| 969 m_end.set(m_start.container(), m_start.offset() + numNewChildren, | 986 m_end.set(m_start.container(), m_start.offset() + numNewChildren, |
| 970 lastChild); | 987 lastChild); |
| 971 } | 988 } |
| 972 } | 989 } |
| 973 | 990 |
| 974 String Range::toString() const { | 991 String Range::toString() const { |
| 975 StringBuilder builder; | 992 StringBuilder builder; |
| 976 | 993 |
| 977 Node* pastLast = pastLastNode(); | 994 Node* pastLast = pastLastNode(); |
| 978 for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(*n)) { | 995 for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(*n)) { |
| 979 Node::NodeType type = n->getNodeType(); | 996 Node::NodeType type = n->getNodeType(); |
| 980 if (type == Node::kTextNode || type == Node::kCdataSectionNode) { | 997 if (type == Node::kTextNode || type == Node::kCdataSectionNode) { |
| 981 String data = toCharacterData(n)->data(); | 998 String data = toCharacterData(n)->data(); |
| 982 int length = data.length(); | 999 int length = data.length(); |
| 983 int start = (n == m_start.container()) | 1000 int start = (n == m_start.container()) |
| 984 ? std::min(std::max(0, m_start.offset()), length) | 1001 ? std::min(std::max(0, m_start.offset()), length) |
| 985 : 0; | 1002 : 0; |
| 986 int end = (n == m_end.container()) | 1003 int end = (n == m_end.container()) |
| 987 ? std::min(std::max(start, m_end.offset()), length) | 1004 ? std::min(std::max(start, m_end.offset()), length) |
| 988 : length; | 1005 : length; |
| 989 builder.append(data, start, end - start); | 1006 builder.append(data, start, end - start); |
| 990 } | 1007 } |
| 991 } | 1008 } |
| 992 | 1009 |
| 993 return builder.toString(); | 1010 return builder.toString(); |
| 994 } | 1011 } |
| 995 | 1012 |
| 996 String Range::text() const { | 1013 String Range::text() const { |
| 997 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets n
eeds to be audited. | 1014 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
| 998 // see http://crbug.com/590369 for more details. | 1015 // needs to be audited. see http://crbug.com/590369 for more details. |
| 999 ownerDocument().updateStyleAndLayoutIgnorePendingStylesheets(); | 1016 ownerDocument().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 1000 | 1017 |
| 1001 return plainText(EphemeralRange(this), | 1018 return plainText(EphemeralRange(this), |
| 1002 TextIteratorEmitsObjectReplacementCharacter); | 1019 TextIteratorEmitsObjectReplacementCharacter); |
| 1003 } | 1020 } |
| 1004 | 1021 |
| 1005 DocumentFragment* Range::createContextualFragment( | 1022 DocumentFragment* Range::createContextualFragment( |
| 1006 const String& markup, | 1023 const String& markup, |
| 1007 ExceptionState& exceptionState) { | 1024 ExceptionState& exceptionState) { |
| 1008 // Algorithm: http://domparsing.spec.whatwg.org/#extensions-to-the-range-inter
face | 1025 // Algorithm: |
| 1026 // http://domparsing.spec.whatwg.org/#extensions-to-the-range-interface |
| 1009 | 1027 |
| 1010 Node* node = m_start.container(); | 1028 Node* node = m_start.container(); |
| 1011 | 1029 |
| 1012 // Step 1. | 1030 // Step 1. |
| 1013 Element* element; | 1031 Element* element; |
| 1014 if (!m_start.offset() && | 1032 if (!m_start.offset() && |
| 1015 (node->isDocumentNode() || node->isDocumentFragment())) | 1033 (node->isDocumentNode() || node->isDocumentFragment())) |
| 1016 element = nullptr; | 1034 element = nullptr; |
| 1017 else if (node->isElementNode()) | 1035 else if (node->isElementNode()) |
| 1018 element = toElement(node); | 1036 element = toElement(node); |
| 1019 else | 1037 else |
| 1020 element = node->parentElement(); | 1038 element = node->parentElement(); |
| 1021 | 1039 |
| 1022 // Step 2. | 1040 // Step 2. |
| 1023 if (!element || isHTMLHtmlElement(element)) { | 1041 if (!element || isHTMLHtmlElement(element)) { |
| 1024 Document& document = node->document(); | 1042 Document& document = node->document(); |
| 1025 | 1043 |
| 1026 if (document.isSVGDocument()) { | 1044 if (document.isSVGDocument()) { |
| 1027 element = document.documentElement(); | 1045 element = document.documentElement(); |
| 1028 if (!element) | 1046 if (!element) |
| 1029 element = SVGSVGElement::create(document); | 1047 element = SVGSVGElement::create(document); |
| 1030 } else { | 1048 } else { |
| 1031 // Optimization over spec: try to reuse the existing <body> element, if it
is available. | 1049 // Optimization over spec: try to reuse the existing <body> element, if it |
| 1050 // is available. |
| 1032 element = document.body(); | 1051 element = document.body(); |
| 1033 if (!element) | 1052 if (!element) |
| 1034 element = HTMLBodyElement::create(document); | 1053 element = HTMLBodyElement::create(document); |
| 1035 } | 1054 } |
| 1036 } | 1055 } |
| 1037 | 1056 |
| 1038 // Steps 3, 4, 5. | 1057 // Steps 3, 4, 5. |
| 1039 return blink::createContextualFragment( | 1058 return blink::createContextualFragment( |
| 1040 markup, element, AllowScriptingContentAndDoNotMarkAlreadyStarted, | 1059 markup, element, AllowScriptingContentAndDoNotMarkAlreadyStarted, |
| 1041 exceptionState); | 1060 exceptionState); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1087 "There is no child at offset " + String::number(offset) + "."); | 1106 "There is no child at offset " + String::number(offset) + "."); |
| 1088 return childBefore; | 1107 return childBefore; |
| 1089 } | 1108 } |
| 1090 } | 1109 } |
| 1091 ASSERT_NOT_REACHED(); | 1110 ASSERT_NOT_REACHED(); |
| 1092 return nullptr; | 1111 return nullptr; |
| 1093 } | 1112 } |
| 1094 | 1113 |
| 1095 void Range::checkNodeBA(Node* n, ExceptionState& exceptionState) const { | 1114 void Range::checkNodeBA(Node* n, ExceptionState& exceptionState) const { |
| 1096 if (!n) { | 1115 if (!n) { |
| 1097 // FIXME: Generated bindings code never calls with null, and neither should
other callers! | 1116 // FIXME: Generated bindings code never calls with null, and neither should |
| 1117 // other callers! |
| 1098 exceptionState.throwTypeError("The node provided is null."); | 1118 exceptionState.throwTypeError("The node provided is null."); |
| 1099 return; | 1119 return; |
| 1100 } | 1120 } |
| 1101 | 1121 |
| 1102 // InvalidNodeTypeError: Raised if the root container of refNode is not an | 1122 // InvalidNodeTypeError: Raised if the root container of refNode is not an |
| 1103 // Attr, Document, DocumentFragment or ShadowRoot node, or part of a SVG shado
w DOM tree, | 1123 // Attr, Document, DocumentFragment or ShadowRoot node, or part of a SVG |
| 1104 // or if refNode is a Document, DocumentFragment, ShadowRoot, Attr, Entity, or
Notation node. | 1124 // shadow DOM tree, or if refNode is a Document, DocumentFragment, ShadowRoot, |
| 1125 // Attr, Entity, or Notation node. |
| 1105 | 1126 |
| 1106 if (!n->parentNode()) { | 1127 if (!n->parentNode()) { |
| 1107 exceptionState.throwDOMException(InvalidNodeTypeError, | 1128 exceptionState.throwDOMException(InvalidNodeTypeError, |
| 1108 "the given Node has no parent."); | 1129 "the given Node has no parent."); |
| 1109 return; | 1130 return; |
| 1110 } | 1131 } |
| 1111 | 1132 |
| 1112 switch (n->getNodeType()) { | 1133 switch (n->getNodeType()) { |
| 1113 case Node::kAttributeNode: | 1134 case Node::kAttributeNode: |
| 1114 case Node::kDocumentFragmentNode: | 1135 case Node::kDocumentFragmentNode: |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1172 void Range::setEndAfter(Node* refNode, ExceptionState& exceptionState) { | 1193 void Range::setEndAfter(Node* refNode, ExceptionState& exceptionState) { |
| 1173 checkNodeBA(refNode, exceptionState); | 1194 checkNodeBA(refNode, exceptionState); |
| 1174 if (exceptionState.hadException()) | 1195 if (exceptionState.hadException()) |
| 1175 return; | 1196 return; |
| 1176 | 1197 |
| 1177 setEnd(refNode->parentNode(), refNode->nodeIndex() + 1, exceptionState); | 1198 setEnd(refNode->parentNode(), refNode->nodeIndex() + 1, exceptionState); |
| 1178 } | 1199 } |
| 1179 | 1200 |
| 1180 void Range::selectNode(Node* refNode, ExceptionState& exceptionState) { | 1201 void Range::selectNode(Node* refNode, ExceptionState& exceptionState) { |
| 1181 if (!refNode) { | 1202 if (!refNode) { |
| 1182 // FIXME: Generated bindings code never calls with null, and neither should
other callers! | 1203 // FIXME: Generated bindings code never calls with null, and neither should |
| 1204 // other callers! |
| 1183 exceptionState.throwTypeError("The node provided is null."); | 1205 exceptionState.throwTypeError("The node provided is null."); |
| 1184 return; | 1206 return; |
| 1185 } | 1207 } |
| 1186 | 1208 |
| 1187 if (!refNode->parentNode()) { | 1209 if (!refNode->parentNode()) { |
| 1188 exceptionState.throwDOMException(InvalidNodeTypeError, | 1210 exceptionState.throwDOMException(InvalidNodeTypeError, |
| 1189 "the given Node has no parent."); | 1211 "the given Node has no parent."); |
| 1190 return; | 1212 return; |
| 1191 } | 1213 } |
| 1192 | 1214 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1209 | 1231 |
| 1210 if (m_ownerDocument != refNode->document()) | 1232 if (m_ownerDocument != refNode->document()) |
| 1211 setDocument(refNode->document()); | 1233 setDocument(refNode->document()); |
| 1212 | 1234 |
| 1213 setStartBefore(refNode); | 1235 setStartBefore(refNode); |
| 1214 setEndAfter(refNode); | 1236 setEndAfter(refNode); |
| 1215 } | 1237 } |
| 1216 | 1238 |
| 1217 void Range::selectNodeContents(Node* refNode, ExceptionState& exceptionState) { | 1239 void Range::selectNodeContents(Node* refNode, ExceptionState& exceptionState) { |
| 1218 if (!refNode) { | 1240 if (!refNode) { |
| 1219 // FIXME: Generated bindings code never calls with null, and neither should
other callers! | 1241 // FIXME: Generated bindings code never calls with null, and neither should |
| 1242 // other callers! |
| 1220 exceptionState.throwTypeError("The node provided is null."); | 1243 exceptionState.throwTypeError("The node provided is null."); |
| 1221 return; | 1244 return; |
| 1222 } | 1245 } |
| 1223 | 1246 |
| 1224 // InvalidNodeTypeError: Raised if refNode or an ancestor of refNode is an Ent
ity, Notation | 1247 // InvalidNodeTypeError: Raised if refNode or an ancestor of refNode is an |
| 1248 // Entity, Notation |
| 1225 // or DocumentType node. | 1249 // or DocumentType node. |
| 1226 for (Node* n = refNode; n; n = n->parentNode()) { | 1250 for (Node* n = refNode; n; n = n->parentNode()) { |
| 1227 switch (n->getNodeType()) { | 1251 switch (n->getNodeType()) { |
| 1228 case Node::kAttributeNode: | 1252 case Node::kAttributeNode: |
| 1229 case Node::kCdataSectionNode: | 1253 case Node::kCdataSectionNode: |
| 1230 case Node::kCommentNode: | 1254 case Node::kCommentNode: |
| 1231 case Node::kDocumentFragmentNode: | 1255 case Node::kDocumentFragmentNode: |
| 1232 case Node::kDocumentNode: | 1256 case Node::kDocumentNode: |
| 1233 case Node::kElementNode: | 1257 case Node::kElementNode: |
| 1234 case Node::kProcessingInstructionNode: | 1258 case Node::kProcessingInstructionNode: |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1274 startBoundaryPoint.setToStartOfNode(*refNode); | 1298 startBoundaryPoint.setToStartOfNode(*refNode); |
| 1275 start = startBoundaryPoint.toPosition(); | 1299 start = startBoundaryPoint.toPosition(); |
| 1276 RangeBoundaryPoint endBoundaryPoint(refNode); | 1300 RangeBoundaryPoint endBoundaryPoint(refNode); |
| 1277 endBoundaryPoint.setToEndOfNode(*refNode); | 1301 endBoundaryPoint.setToEndOfNode(*refNode); |
| 1278 end = endBoundaryPoint.toPosition(); | 1302 end = endBoundaryPoint.toPosition(); |
| 1279 return true; | 1303 return true; |
| 1280 } | 1304 } |
| 1281 | 1305 |
| 1282 void Range::surroundContents(Node* newParent, ExceptionState& exceptionState) { | 1306 void Range::surroundContents(Node* newParent, ExceptionState& exceptionState) { |
| 1283 if (!newParent) { | 1307 if (!newParent) { |
| 1284 // FIXME: Generated bindings code never calls with null, and neither should
other callers! | 1308 // FIXME: Generated bindings code never calls with null, and neither should |
| 1309 // other callers! |
| 1285 exceptionState.throwTypeError("The node provided is null."); | 1310 exceptionState.throwTypeError("The node provided is null."); |
| 1286 return; | 1311 return; |
| 1287 } | 1312 } |
| 1288 | 1313 |
| 1289 // InvalidStateError: Raised if the Range partially selects a non-Text node. | 1314 // InvalidStateError: Raised if the Range partially selects a non-Text node. |
| 1290 Node* startNonTextContainer = m_start.container(); | 1315 Node* startNonTextContainer = m_start.container(); |
| 1291 if (startNonTextContainer->getNodeType() == Node::kTextNode) | 1316 if (startNonTextContainer->getNodeType() == Node::kTextNode) |
| 1292 startNonTextContainer = startNonTextContainer->parentNode(); | 1317 startNonTextContainer = startNonTextContainer->parentNode(); |
| 1293 Node* endNonTextContainer = m_end.container(); | 1318 Node* endNonTextContainer = m_end.container(); |
| 1294 if (endNonTextContainer->getNodeType() == Node::kTextNode) | 1319 if (endNonTextContainer->getNodeType() == Node::kTextNode) |
| 1295 endNonTextContainer = endNonTextContainer->parentNode(); | 1320 endNonTextContainer = endNonTextContainer->parentNode(); |
| 1296 if (startNonTextContainer != endNonTextContainer) { | 1321 if (startNonTextContainer != endNonTextContainer) { |
| 1297 exceptionState.throwDOMException( | 1322 exceptionState.throwDOMException( |
| 1298 InvalidStateError, "The Range has partially selected a non-Text node."); | 1323 InvalidStateError, "The Range has partially selected a non-Text node."); |
| 1299 return; | 1324 return; |
| 1300 } | 1325 } |
| 1301 | 1326 |
| 1302 // InvalidNodeTypeError: Raised if node is an Attr, Entity, DocumentType, Nota
tion, | 1327 // InvalidNodeTypeError: Raised if node is an Attr, Entity, DocumentType, |
| 1328 // Notation, |
| 1303 // Document, or DocumentFragment node. | 1329 // Document, or DocumentFragment node. |
| 1304 switch (newParent->getNodeType()) { | 1330 switch (newParent->getNodeType()) { |
| 1305 case Node::kAttributeNode: | 1331 case Node::kAttributeNode: |
| 1306 case Node::kDocumentFragmentNode: | 1332 case Node::kDocumentFragmentNode: |
| 1307 case Node::kDocumentNode: | 1333 case Node::kDocumentNode: |
| 1308 case Node::kDocumentTypeNode: | 1334 case Node::kDocumentTypeNode: |
| 1309 exceptionState.throwDOMException( | 1335 exceptionState.throwDOMException( |
| 1310 InvalidNodeTypeError, | 1336 InvalidNodeTypeError, |
| 1311 "The node provided is of type '" + newParent->nodeName() + "'."); | 1337 "The node provided is of type '" + newParent->nodeName() + "'."); |
| 1312 return; | 1338 return; |
| 1313 case Node::kCdataSectionNode: | 1339 case Node::kCdataSectionNode: |
| 1314 case Node::kCommentNode: | 1340 case Node::kCommentNode: |
| 1315 case Node::kElementNode: | 1341 case Node::kElementNode: |
| 1316 case Node::kProcessingInstructionNode: | 1342 case Node::kProcessingInstructionNode: |
| 1317 case Node::kTextNode: | 1343 case Node::kTextNode: |
| 1318 break; | 1344 break; |
| 1319 } | 1345 } |
| 1320 | 1346 |
| 1321 // Raise a HierarchyRequestError if m_start.container() doesn't accept childre
n like newParent. | 1347 // Raise a HierarchyRequestError if m_start.container() doesn't accept |
| 1348 // children like newParent. |
| 1322 Node* parentOfNewParent = m_start.container(); | 1349 Node* parentOfNewParent = m_start.container(); |
| 1323 | 1350 |
| 1324 // If m_start.container() is a character data node, it will be split and it wi
ll be its parent that will | 1351 // If m_start.container() is a character data node, it will be split and it |
| 1325 // need to accept newParent (or in the case of a comment, it logically "would"
be inserted into the parent, | 1352 // will be its parent that will need to accept newParent (or in the case of a |
| 1326 // although this will fail below for another reason). | 1353 // comment, it logically "would" be inserted into the parent, although this |
| 1354 // will fail below for another reason). |
| 1327 if (parentOfNewParent->isCharacterDataNode()) | 1355 if (parentOfNewParent->isCharacterDataNode()) |
| 1328 parentOfNewParent = parentOfNewParent->parentNode(); | 1356 parentOfNewParent = parentOfNewParent->parentNode(); |
| 1329 | 1357 |
| 1330 if (!parentOfNewParent) { | 1358 if (!parentOfNewParent) { |
| 1331 exceptionState.throwDOMException(HierarchyRequestError, | 1359 exceptionState.throwDOMException(HierarchyRequestError, |
| 1332 "The container node is a detached " | 1360 "The container node is a detached " |
| 1333 "character data node; no parent node is " | 1361 "character data node; no parent node is " |
| 1334 "available for insertion."); | 1362 "available for insertion."); |
| 1335 return; | 1363 return; |
| 1336 } | 1364 } |
| 1337 | 1365 |
| 1338 if (!parentOfNewParent->childTypeAllowed(newParent->getNodeType())) { | 1366 if (!parentOfNewParent->childTypeAllowed(newParent->getNodeType())) { |
| 1339 exceptionState.throwDOMException(HierarchyRequestError, | 1367 exceptionState.throwDOMException(HierarchyRequestError, |
| 1340 "The node provided is of type '" + | 1368 "The node provided is of type '" + |
| 1341 newParent->nodeName() + | 1369 newParent->nodeName() + |
| 1342 "', which may not be inserted here."); | 1370 "', which may not be inserted here."); |
| 1343 return; | 1371 return; |
| 1344 } | 1372 } |
| 1345 | 1373 |
| 1346 if (newParent->isShadowIncludingInclusiveAncestorOf(m_start.container())) { | 1374 if (newParent->isShadowIncludingInclusiveAncestorOf(m_start.container())) { |
| 1347 exceptionState.throwDOMException(HierarchyRequestError, | 1375 exceptionState.throwDOMException(HierarchyRequestError, |
| 1348 "The node provided contains the insertion " | 1376 "The node provided contains the insertion " |
| 1349 "point; it may not be inserted into " | 1377 "point; it may not be inserted into " |
| 1350 "itself."); | 1378 "itself."); |
| 1351 return; | 1379 return; |
| 1352 } | 1380 } |
| 1353 | 1381 |
| 1354 // FIXME: Do we need a check if the node would end up with a child node of a t
ype not | 1382 // FIXME: Do we need a check if the node would end up with a child node of a |
| 1355 // allowed by the type of node? | 1383 // type not allowed by the type of node? |
| 1356 | 1384 |
| 1357 while (Node* n = newParent->firstChild()) { | 1385 while (Node* n = newParent->firstChild()) { |
| 1358 toContainerNode(newParent)->removeChild(n, exceptionState); | 1386 toContainerNode(newParent)->removeChild(n, exceptionState); |
| 1359 if (exceptionState.hadException()) | 1387 if (exceptionState.hadException()) |
| 1360 return; | 1388 return; |
| 1361 } | 1389 } |
| 1362 DocumentFragment* fragment = extractContents(exceptionState); | 1390 DocumentFragment* fragment = extractContents(exceptionState); |
| 1363 if (exceptionState.hadException()) | 1391 if (exceptionState.hadException()) |
| 1364 return; | 1392 return; |
| 1365 insertNode(newParent, exceptionState); | 1393 insertNode(newParent, exceptionState); |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1743 .data() | 1771 .data() |
| 1744 << "start offset: " << range->startOffset() | 1772 << "start offset: " << range->startOffset() |
| 1745 << ", end offset: " << range->endOffset(); | 1773 << ", end offset: " << range->endOffset(); |
| 1746 } else { | 1774 } else { |
| 1747 LOG(INFO) << "Cannot show tree if range is null, or if boundary points are " | 1775 LOG(INFO) << "Cannot show tree if range is null, or if boundary points are " |
| 1748 "invalid."; | 1776 "invalid."; |
| 1749 } | 1777 } |
| 1750 } | 1778 } |
| 1751 | 1779 |
| 1752 #endif | 1780 #endif |
| OLD | NEW |