| 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 | 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All |
| 7 * rights reserved. | 7 * rights reserved. |
| 8 * Copyright (C) 2011 Motorola Mobility. All rights reserved. | 8 * Copyright (C) 2011 Motorola Mobility. All rights reserved. |
| 9 * | 9 * |
| 10 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 m_end(m_ownerDocument) { | 61 m_end(m_ownerDocument) { |
| 62 m_ownerDocument->attachRange(this); | 62 m_ownerDocument->attachRange(this); |
| 63 } | 63 } |
| 64 | 64 |
| 65 Range* Range::create(Document& ownerDocument) { | 65 Range* Range::create(Document& ownerDocument) { |
| 66 return new Range(ownerDocument); | 66 return new Range(ownerDocument); |
| 67 } | 67 } |
| 68 | 68 |
| 69 inline Range::Range(Document& ownerDocument, | 69 inline Range::Range(Document& ownerDocument, |
| 70 Node* startContainer, | 70 Node* startContainer, |
| 71 int startOffset, | 71 unsigned startOffset, |
| 72 Node* endContainer, | 72 Node* endContainer, |
| 73 int endOffset) | 73 unsigned endOffset) |
| 74 : m_ownerDocument(&ownerDocument), | 74 : m_ownerDocument(&ownerDocument), |
| 75 m_start(m_ownerDocument), | 75 m_start(m_ownerDocument), |
| 76 m_end(m_ownerDocument) { | 76 m_end(m_ownerDocument) { |
| 77 m_ownerDocument->attachRange(this); | 77 m_ownerDocument->attachRange(this); |
| 78 | 78 |
| 79 // Simply setting the containers and offsets directly would not do any of the | 79 // Simply setting the containers and offsets directly would not do any of the |
| 80 // checking that setStart and setEnd do, so we call those functions. | 80 // checking that setStart and setEnd do, so we call those functions. |
| 81 setStart(startContainer, startOffset); | 81 setStart(startContainer, startOffset); |
| 82 setEnd(endContainer, endOffset); | 82 setEnd(endContainer, endOffset); |
| 83 } | 83 } |
| 84 | 84 |
| 85 Range* Range::create(Document& ownerDocument, | 85 Range* Range::create(Document& ownerDocument, |
| 86 Node* startContainer, | 86 Node* startContainer, |
| 87 int startOffset, | 87 unsigned startOffset, |
| 88 Node* endContainer, | 88 Node* endContainer, |
| 89 int endOffset) { | 89 unsigned endOffset) { |
| 90 return new Range(ownerDocument, startContainer, startOffset, endContainer, | 90 return new Range(ownerDocument, startContainer, startOffset, endContainer, |
| 91 endOffset); | 91 endOffset); |
| 92 } | 92 } |
| 93 | 93 |
| 94 Range* Range::create(Document& ownerDocument, | 94 Range* Range::create(Document& ownerDocument, |
| 95 const Position& start, | 95 const Position& start, |
| 96 const Position& end) { | 96 const Position& end) { |
| 97 return new Range(ownerDocument, start.computeContainerNode(), | 97 return new Range(ownerDocument, start.computeContainerNode(), |
| 98 start.computeOffsetInContainerNode(), | 98 start.computeOffsetInContainerNode(), |
| 99 end.computeContainerNode(), | 99 end.computeContainerNode(), |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 endRootContainer = endRootContainer->parentNode(); | 154 endRootContainer = endRootContainer->parentNode(); |
| 155 Node* startRootContainer = start.container(); | 155 Node* startRootContainer = start.container(); |
| 156 while (startRootContainer->parentNode()) | 156 while (startRootContainer->parentNode()) |
| 157 startRootContainer = startRootContainer->parentNode(); | 157 startRootContainer = startRootContainer->parentNode(); |
| 158 | 158 |
| 159 return startRootContainer != endRootContainer || | 159 return startRootContainer != endRootContainer || |
| 160 (Range::compareBoundaryPoints(start, end, ASSERT_NO_EXCEPTION) > 0); | 160 (Range::compareBoundaryPoints(start, end, ASSERT_NO_EXCEPTION) > 0); |
| 161 } | 161 } |
| 162 | 162 |
| 163 void Range::setStart(Node* refNode, | 163 void Range::setStart(Node* refNode, |
| 164 int offset, | 164 unsigned offset, |
| 165 ExceptionState& exceptionState) { | 165 ExceptionState& exceptionState) { |
| 166 if (!refNode) { | 166 if (!refNode) { |
| 167 // FIXME: Generated bindings code never calls with null, and neither should | 167 // FIXME: Generated bindings code never calls with null, and neither should |
| 168 // other callers! | 168 // other callers! |
| 169 exceptionState.throwTypeError("The node provided is null."); | 169 exceptionState.throwTypeError("The node provided is null."); |
| 170 return; | 170 return; |
| 171 } | 171 } |
| 172 | 172 |
| 173 bool didMoveDocument = false; | 173 bool didMoveDocument = false; |
| 174 if (refNode->document() != m_ownerDocument) { | 174 if (refNode->document() != m_ownerDocument) { |
| 175 setDocument(refNode->document()); | 175 setDocument(refNode->document()); |
| 176 didMoveDocument = true; | 176 didMoveDocument = true; |
| 177 } | 177 } |
| 178 | 178 |
| 179 Node* childNode = checkNodeWOffset(refNode, offset, exceptionState); | 179 Node* childNode = checkNodeWOffset(refNode, offset, exceptionState); |
| 180 if (exceptionState.hadException()) | 180 if (exceptionState.hadException()) |
| 181 return; | 181 return; |
| 182 | 182 |
| 183 m_start.set(refNode, offset, childNode); | 183 m_start.set(refNode, offset, childNode); |
| 184 | 184 |
| 185 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) | 185 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) |
| 186 collapse(true); | 186 collapse(true); |
| 187 } | 187 } |
| 188 | 188 |
| 189 void Range::setEnd(Node* refNode, int offset, ExceptionState& exceptionState) { | 189 void Range::setEnd(Node* refNode, |
| 190 unsigned offset, |
| 191 ExceptionState& exceptionState) { |
| 190 if (!refNode) { | 192 if (!refNode) { |
| 191 // FIXME: Generated bindings code never calls with null, and neither should | 193 // FIXME: Generated bindings code never calls with null, and neither should |
| 192 // other callers! | 194 // other callers! |
| 193 exceptionState.throwTypeError("The node provided is null."); | 195 exceptionState.throwTypeError("The node provided is null."); |
| 194 return; | 196 return; |
| 195 } | 197 } |
| 196 | 198 |
| 197 bool didMoveDocument = false; | 199 bool didMoveDocument = false; |
| 198 if (refNode->document() != m_ownerDocument) { | 200 if (refNode->document() != m_ownerDocument) { |
| 199 setDocument(refNode->document()); | 201 setDocument(refNode->document()); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 return false; | 250 return false; |
| 249 // commonAncestorContainer() is O(depth). We should avoid to call it in common | 251 // commonAncestorContainer() is O(depth). We should avoid to call it in common |
| 250 // cases. | 252 // cases. |
| 251 if (node.isInTreeScope() && m_start.container()->isInTreeScope() && | 253 if (node.isInTreeScope() && m_start.container()->isInTreeScope() && |
| 252 &node.treeScope() == &m_start.container()->treeScope()) | 254 &node.treeScope() == &m_start.container()->treeScope()) |
| 253 return true; | 255 return true; |
| 254 return node.commonAncestor(*m_start.container(), NodeTraversal::parent); | 256 return node.commonAncestor(*m_start.container(), NodeTraversal::parent); |
| 255 } | 257 } |
| 256 | 258 |
| 257 bool Range::isPointInRange(Node* refNode, | 259 bool Range::isPointInRange(Node* refNode, |
| 258 int offset, | 260 unsigned offset, |
| 259 ExceptionState& exceptionState) const { | 261 ExceptionState& exceptionState) const { |
| 260 if (!refNode) { | 262 if (!refNode) { |
| 261 // FIXME: Generated bindings code never calls with null, and neither should | 263 // FIXME: Generated bindings code never calls with null, and neither should |
| 262 // other callers! | 264 // other callers! |
| 263 exceptionState.throwTypeError("The node provided is null."); | 265 exceptionState.throwTypeError("The node provided is null."); |
| 264 return false; | 266 return false; |
| 265 } | 267 } |
| 266 if (!hasSameRoot(*refNode)) | 268 if (!hasSameRoot(*refNode)) |
| 267 return false; | 269 return false; |
| 268 | 270 |
| 269 checkNodeWOffset(refNode, offset, exceptionState); | 271 checkNodeWOffset(refNode, offset, exceptionState); |
| 270 if (exceptionState.hadException()) | 272 if (exceptionState.hadException()) |
| 271 return false; | 273 return false; |
| 272 | 274 |
| 273 return compareBoundaryPoints(refNode, offset, m_start.container(), | 275 return compareBoundaryPoints(refNode, offset, m_start.container(), |
| 274 m_start.offset(), exceptionState) >= 0 && | 276 m_start.offset(), exceptionState) >= 0 && |
| 275 !exceptionState.hadException() && | 277 !exceptionState.hadException() && |
| 276 compareBoundaryPoints(refNode, offset, m_end.container(), | 278 compareBoundaryPoints(refNode, offset, m_end.container(), |
| 277 m_end.offset(), exceptionState) <= 0 && | 279 m_end.offset(), exceptionState) <= 0 && |
| 278 !exceptionState.hadException(); | 280 !exceptionState.hadException(); |
| 279 } | 281 } |
| 280 | 282 |
| 281 short Range::comparePoint(Node* refNode, | 283 short Range::comparePoint(Node* refNode, |
| 282 int offset, | 284 unsigned offset, |
| 283 ExceptionState& exceptionState) const { | 285 ExceptionState& exceptionState) const { |
| 284 // http://developer.mozilla.org/en/docs/DOM:range.comparePoint | 286 // http://developer.mozilla.org/en/docs/DOM:range.comparePoint |
| 285 // This method returns -1, 0 or 1 depending on if the point described by the | 287 // This method returns -1, 0 or 1 depending on if the point described by the |
| 286 // refNode node and an offset within the node is before, same as, or after the | 288 // refNode node and an offset within the node is before, same as, or after the |
| 287 // range respectively. | 289 // range respectively. |
| 288 | 290 |
| 289 if (!hasSameRoot(*refNode)) { | 291 if (!hasSameRoot(*refNode)) { |
| 290 exceptionState.throwDOMException( | 292 exceptionState.throwDOMException( |
| 291 WrongDocumentError, | 293 WrongDocumentError, |
| 292 "The node provided and the Range are not in the same tree."); | 294 "The node provided and the Range are not in the same tree."); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 359 return compareBoundaryPoints(m_end, sourceRange->m_end, exceptionState); | 361 return compareBoundaryPoints(m_end, sourceRange->m_end, exceptionState); |
| 360 case kEndToStart: | 362 case kEndToStart: |
| 361 return compareBoundaryPoints(m_start, sourceRange->m_end, exceptionState); | 363 return compareBoundaryPoints(m_start, sourceRange->m_end, exceptionState); |
| 362 } | 364 } |
| 363 | 365 |
| 364 NOTREACHED(); | 366 NOTREACHED(); |
| 365 return 0; | 367 return 0; |
| 366 } | 368 } |
| 367 | 369 |
| 368 short Range::compareBoundaryPoints(Node* containerA, | 370 short Range::compareBoundaryPoints(Node* containerA, |
| 369 int offsetA, | 371 unsigned offsetA, |
| 370 Node* containerB, | 372 Node* containerB, |
| 371 int offsetB, | 373 unsigned offsetB, |
| 372 ExceptionState& exceptionState) { | 374 ExceptionState& exceptionState) { |
| 373 bool disconnected = false; | 375 bool disconnected = false; |
| 374 short result = comparePositionsInDOMTree(containerA, offsetA, containerB, | 376 short result = comparePositionsInDOMTree(containerA, offsetA, containerB, |
| 375 offsetB, &disconnected); | 377 offsetB, &disconnected); |
| 376 if (disconnected) { | 378 if (disconnected) { |
| 377 exceptionState.throwDOMException( | 379 exceptionState.throwDOMException( |
| 378 WrongDocumentError, "The two ranges are in separate documents."); | 380 WrongDocumentError, "The two ranges are in separate documents."); |
| 379 return 0; | 381 return 0; |
| 380 } | 382 } |
| 381 return result; | 383 return result; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 exceptionState.throwTypeError("The node provided is null."); | 415 exceptionState.throwTypeError("The node provided is null."); |
| 414 return false; | 416 return false; |
| 415 } | 417 } |
| 416 if (!hasSameRoot(*refNode)) | 418 if (!hasSameRoot(*refNode)) |
| 417 return false; | 419 return false; |
| 418 | 420 |
| 419 ContainerNode* parentNode = refNode->parentNode(); | 421 ContainerNode* parentNode = refNode->parentNode(); |
| 420 if (!parentNode) | 422 if (!parentNode) |
| 421 return true; | 423 return true; |
| 422 | 424 |
| 423 int nodeIndex = refNode->nodeIndex(); | 425 unsigned nodeIndex = refNode->nodeIndex(); |
| 424 | 426 |
| 425 if (comparePoint(parentNode, nodeIndex, exceptionState) < | 427 if (comparePoint(parentNode, nodeIndex, exceptionState) < |
| 426 0 // starts before start | 428 0 // starts before start |
| 427 && | 429 && |
| 428 comparePoint(parentNode, nodeIndex + 1, exceptionState) < | 430 comparePoint(parentNode, nodeIndex + 1, exceptionState) < |
| 429 0) { // ends before start | 431 0) { // ends before start |
| 430 return false; | 432 return false; |
| 431 } | 433 } |
| 432 | 434 |
| 433 if (comparePoint(parentNode, nodeIndex, exceptionState) > | 435 if (comparePoint(parentNode, nodeIndex, exceptionState) > |
| (...skipping 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 933 } | 935 } |
| 934 | 936 |
| 935 String Range::toString() const { | 937 String Range::toString() const { |
| 936 StringBuilder builder; | 938 StringBuilder builder; |
| 937 | 939 |
| 938 Node* pastLast = pastLastNode(); | 940 Node* pastLast = pastLastNode(); |
| 939 for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(*n)) { | 941 for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(*n)) { |
| 940 Node::NodeType type = n->getNodeType(); | 942 Node::NodeType type = n->getNodeType(); |
| 941 if (type == Node::kTextNode || type == Node::kCdataSectionNode) { | 943 if (type == Node::kTextNode || type == Node::kCdataSectionNode) { |
| 942 String data = toCharacterData(n)->data(); | 944 String data = toCharacterData(n)->data(); |
| 943 int length = data.length(); | 945 unsigned length = data.length(); |
| 944 int start = (n == m_start.container()) | 946 unsigned start = |
| 945 ? std::min(std::max(0, m_start.offset()), length) | 947 (n == m_start.container()) ? std::min(m_start.offset(), length) : 0; |
| 946 : 0; | 948 unsigned end = (n == m_end.container()) |
| 947 int end = (n == m_end.container()) | 949 ? std::min(std::max(start, m_end.offset()), length) |
| 948 ? std::min(std::max(start, m_end.offset()), length) | 950 : length; |
| 949 : length; | |
| 950 builder.append(data, start, end - start); | 951 builder.append(data, start, end - start); |
| 951 } | 952 } |
| 952 } | 953 } |
| 953 | 954 |
| 954 return builder.toString(); | 955 return builder.toString(); |
| 955 } | 956 } |
| 956 | 957 |
| 957 String Range::text() const { | 958 String Range::text() const { |
| 958 DCHECK(!m_ownerDocument->needsLayoutTreeUpdate()); | 959 DCHECK(!m_ownerDocument->needsLayoutTreeUpdate()); |
| 959 return plainText(EphemeralRange(this), | 960 return plainText(EphemeralRange(this), |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1001 return blink::createContextualFragment( | 1002 return blink::createContextualFragment( |
| 1002 markup, element, AllowScriptingContentAndDoNotMarkAlreadyStarted, | 1003 markup, element, AllowScriptingContentAndDoNotMarkAlreadyStarted, |
| 1003 exceptionState); | 1004 exceptionState); |
| 1004 } | 1005 } |
| 1005 | 1006 |
| 1006 void Range::detach() { | 1007 void Range::detach() { |
| 1007 // This is now a no-op as per the DOM specification. | 1008 // This is now a no-op as per the DOM specification. |
| 1008 } | 1009 } |
| 1009 | 1010 |
| 1010 Node* Range::checkNodeWOffset(Node* n, | 1011 Node* Range::checkNodeWOffset(Node* n, |
| 1011 int offset, | 1012 unsigned offset, |
| 1012 ExceptionState& exceptionState) { | 1013 ExceptionState& exceptionState) { |
| 1013 switch (n->getNodeType()) { | 1014 switch (n->getNodeType()) { |
| 1014 case Node::kDocumentTypeNode: | 1015 case Node::kDocumentTypeNode: |
| 1015 exceptionState.throwDOMException( | 1016 exceptionState.throwDOMException( |
| 1016 InvalidNodeTypeError, | 1017 InvalidNodeTypeError, |
| 1017 "The node provided is of type '" + n->nodeName() + "'."); | 1018 "The node provided is of type '" + n->nodeName() + "'."); |
| 1018 return nullptr; | 1019 return nullptr; |
| 1019 case Node::kCdataSectionNode: | 1020 case Node::kCdataSectionNode: |
| 1020 case Node::kCommentNode: | 1021 case Node::kCommentNode: |
| 1021 case Node::kTextNode: | 1022 case Node::kTextNode: |
| 1022 if (static_cast<unsigned>(offset) > toCharacterData(n)->length()) | 1023 if (offset > toCharacterData(n)->length()) |
| 1023 exceptionState.throwDOMException( | 1024 exceptionState.throwDOMException( |
| 1024 IndexSizeError, | 1025 IndexSizeError, |
| 1025 "The offset " + String::number(offset) + | 1026 "The offset " + String::number(offset) + |
| 1026 " is larger than or equal to the node's length (" + | 1027 " is larger than or equal to the node's length (" + |
| 1027 String::number(toCharacterData(n)->length()) + ")."); | 1028 String::number(toCharacterData(n)->length()) + ")."); |
| 1028 return nullptr; | 1029 return nullptr; |
| 1029 case Node::kProcessingInstructionNode: | 1030 case Node::kProcessingInstructionNode: |
| 1030 if (static_cast<unsigned>(offset) > | 1031 if (offset > toProcessingInstruction(n)->data().length()) |
| 1031 toProcessingInstruction(n)->data().length()) | |
| 1032 exceptionState.throwDOMException( | 1032 exceptionState.throwDOMException( |
| 1033 IndexSizeError, | 1033 IndexSizeError, |
| 1034 "The offset " + String::number(offset) + | 1034 "The offset " + String::number(offset) + |
| 1035 " is larger than or equal to than the node's length (" + | 1035 " is larger than or equal to than the node's length (" + |
| 1036 String::number(toProcessingInstruction(n)->data().length()) + | 1036 String::number(toProcessingInstruction(n)->data().length()) + |
| 1037 ")."); | 1037 ")."); |
| 1038 return nullptr; | 1038 return nullptr; |
| 1039 case Node::kAttributeNode: | 1039 case Node::kAttributeNode: |
| 1040 case Node::kDocumentFragmentNode: | 1040 case Node::kDocumentFragmentNode: |
| 1041 case Node::kDocumentNode: | 1041 case Node::kDocumentNode: |
| (...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1540 boundaryTextRemoved(m_end, text, offset, length); | 1540 boundaryTextRemoved(m_end, text, offset, length); |
| 1541 } | 1541 } |
| 1542 | 1542 |
| 1543 static inline void boundaryTextNodesMerged(RangeBoundaryPoint& boundary, | 1543 static inline void boundaryTextNodesMerged(RangeBoundaryPoint& boundary, |
| 1544 const NodeWithIndex& oldNode, | 1544 const NodeWithIndex& oldNode, |
| 1545 unsigned offset) { | 1545 unsigned offset) { |
| 1546 if (boundary.container() == oldNode.node()) | 1546 if (boundary.container() == oldNode.node()) |
| 1547 boundary.set(oldNode.node().previousSibling(), boundary.offset() + offset, | 1547 boundary.set(oldNode.node().previousSibling(), boundary.offset() + offset, |
| 1548 0); | 1548 0); |
| 1549 else if (boundary.container() == oldNode.node().parentNode() && | 1549 else if (boundary.container() == oldNode.node().parentNode() && |
| 1550 boundary.offset() == oldNode.index()) | 1550 boundary.offset() == static_cast<unsigned>(oldNode.index())) |
| 1551 boundary.set(oldNode.node().previousSibling(), offset, 0); | 1551 boundary.set(oldNode.node().previousSibling(), offset, 0); |
| 1552 } | 1552 } |
| 1553 | 1553 |
| 1554 void Range::didMergeTextNodes(const NodeWithIndex& oldNode, unsigned offset) { | 1554 void Range::didMergeTextNodes(const NodeWithIndex& oldNode, unsigned offset) { |
| 1555 DCHECK_EQ(oldNode.node().document(), m_ownerDocument); | 1555 DCHECK_EQ(oldNode.node().document(), m_ownerDocument); |
| 1556 DCHECK(oldNode.node().parentNode()); | 1556 DCHECK(oldNode.node().parentNode()); |
| 1557 DCHECK(oldNode.node().isTextNode()); | 1557 DCHECK(oldNode.node().isTextNode()); |
| 1558 DCHECK(oldNode.node().previousSibling()); | 1558 DCHECK(oldNode.node().previousSibling()); |
| 1559 DCHECK(oldNode.node().previousSibling()->isTextNode()); | 1559 DCHECK(oldNode.node().previousSibling()->isTextNode()); |
| 1560 boundaryTextNodesMerged(m_start, oldNode, offset); | 1560 boundaryTextNodesMerged(m_start, oldNode, offset); |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1716 .data() | 1716 .data() |
| 1717 << "start offset: " << range->startOffset() | 1717 << "start offset: " << range->startOffset() |
| 1718 << ", end offset: " << range->endOffset(); | 1718 << ", end offset: " << range->endOffset(); |
| 1719 } else { | 1719 } else { |
| 1720 LOG(INFO) << "Cannot show tree if range is null, or if boundary points are " | 1720 LOG(INFO) << "Cannot show tree if range is null, or if boundary points are " |
| 1721 "invalid."; | 1721 "invalid."; |
| 1722 } | 1722 } |
| 1723 } | 1723 } |
| 1724 | 1724 |
| 1725 #endif | 1725 #endif |
| OLD | NEW |