| 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 18 matching lines...) Expand all Loading... |
| 29 #include "core/dom/ClientRect.h" | 29 #include "core/dom/ClientRect.h" |
| 30 #include "core/dom/ClientRectList.h" | 30 #include "core/dom/ClientRectList.h" |
| 31 #include "core/dom/DocumentFragment.h" | 31 #include "core/dom/DocumentFragment.h" |
| 32 #include "core/dom/ExceptionCode.h" | 32 #include "core/dom/ExceptionCode.h" |
| 33 #include "core/dom/Node.h" | 33 #include "core/dom/Node.h" |
| 34 #include "core/dom/NodeTraversal.h" | 34 #include "core/dom/NodeTraversal.h" |
| 35 #include "core/dom/NodeWithIndex.h" | 35 #include "core/dom/NodeWithIndex.h" |
| 36 #include "core/dom/ProcessingInstruction.h" | 36 #include "core/dom/ProcessingInstruction.h" |
| 37 #include "core/dom/Text.h" | 37 #include "core/dom/Text.h" |
| 38 #include "core/editing/EditingUtilities.h" | 38 #include "core/editing/EditingUtilities.h" |
| 39 #include "core/editing/EphemeralRange.h" |
| 40 #include "core/editing/FrameSelection.h" |
| 39 #include "core/editing/VisiblePosition.h" | 41 #include "core/editing/VisiblePosition.h" |
| 40 #include "core/editing/VisibleUnits.h" | 42 #include "core/editing/VisibleUnits.h" |
| 41 #include "core/editing/iterators/TextIterator.h" | 43 #include "core/editing/iterators/TextIterator.h" |
| 42 #include "core/editing/serializers/Serialization.h" | 44 #include "core/editing/serializers/Serialization.h" |
| 43 #include "core/events/ScopedEventQueue.h" | 45 #include "core/events/ScopedEventQueue.h" |
| 44 #include "core/html/HTMLBodyElement.h" | 46 #include "core/html/HTMLBodyElement.h" |
| 45 #include "core/html/HTMLElement.h" | 47 #include "core/html/HTMLElement.h" |
| 46 #include "core/layout/LayoutObject.h" | 48 #include "core/layout/LayoutObject.h" |
| 47 #include "core/layout/LayoutText.h" | 49 #include "core/layout/LayoutText.h" |
| 48 #include "core/svg/SVGSVGElement.h" | 50 #include "core/svg/SVGSVGElement.h" |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 void Range::setStart(Node* refNode, | 165 void Range::setStart(Node* refNode, |
| 164 int offset, | 166 int offset, |
| 165 ExceptionState& exceptionState) { | 167 ExceptionState& exceptionState) { |
| 166 if (!refNode) { | 168 if (!refNode) { |
| 167 // FIXME: Generated bindings code never calls with null, and neither should | 169 // FIXME: Generated bindings code never calls with null, and neither should |
| 168 // other callers! | 170 // other callers! |
| 169 exceptionState.throwTypeError("The node provided is null."); | 171 exceptionState.throwTypeError("The node provided is null."); |
| 170 return; | 172 return; |
| 171 } | 173 } |
| 172 | 174 |
| 175 Document& oldDocument = ownerDocument(); |
| 173 bool didMoveDocument = false; | 176 bool didMoveDocument = false; |
| 174 if (refNode->document() != m_ownerDocument) { | 177 if (refNode->document() != m_ownerDocument) { |
| 175 setDocument(refNode->document()); | 178 setDocument(refNode->document()); |
| 176 didMoveDocument = true; | 179 didMoveDocument = true; |
| 177 } | 180 } |
| 178 | 181 |
| 179 Node* childNode = checkNodeWOffset(refNode, offset, exceptionState); | 182 Node* childNode = checkNodeWOffset(refNode, offset, exceptionState); |
| 180 if (exceptionState.hadException()) | 183 if (exceptionState.hadException()) |
| 181 return; | 184 return; |
| 182 | 185 |
| 183 m_start.set(refNode, offset, childNode); | 186 m_start.set(refNode, offset, childNode); |
| 184 | 187 |
| 185 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) | 188 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) { |
| 189 removeFromSelectionIfInDifferentRoot(oldDocument); |
| 186 collapse(true); | 190 collapse(true); |
| 191 return; |
| 192 } |
| 193 updateSelectionIfAddedToSelection(); |
| 187 } | 194 } |
| 188 | 195 |
| 189 void Range::setEnd(Node* refNode, int offset, ExceptionState& exceptionState) { | 196 void Range::setEnd(Node* refNode, int offset, ExceptionState& exceptionState) { |
| 190 if (!refNode) { | 197 if (!refNode) { |
| 191 // FIXME: Generated bindings code never calls with null, and neither should | 198 // FIXME: Generated bindings code never calls with null, and neither should |
| 192 // other callers! | 199 // other callers! |
| 193 exceptionState.throwTypeError("The node provided is null."); | 200 exceptionState.throwTypeError("The node provided is null."); |
| 194 return; | 201 return; |
| 195 } | 202 } |
| 196 | 203 |
| 197 bool didMoveDocument = false; | 204 bool didMoveDocument = false; |
| 205 Document& oldDocument = ownerDocument(); |
| 198 if (refNode->document() != m_ownerDocument) { | 206 if (refNode->document() != m_ownerDocument) { |
| 199 setDocument(refNode->document()); | 207 setDocument(refNode->document()); |
| 200 didMoveDocument = true; | 208 didMoveDocument = true; |
| 201 } | 209 } |
| 202 | 210 |
| 203 Node* childNode = checkNodeWOffset(refNode, offset, exceptionState); | 211 Node* childNode = checkNodeWOffset(refNode, offset, exceptionState); |
| 204 if (exceptionState.hadException()) | 212 if (exceptionState.hadException()) |
| 205 return; | 213 return; |
| 206 | 214 |
| 207 m_end.set(refNode, offset, childNode); | 215 m_end.set(refNode, offset, childNode); |
| 208 | 216 |
| 209 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) | 217 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) { |
| 218 removeFromSelectionIfInDifferentRoot(oldDocument); |
| 210 collapse(false); | 219 collapse(false); |
| 220 return; |
| 221 } |
| 222 updateSelectionIfAddedToSelection(); |
| 211 } | 223 } |
| 212 | 224 |
| 213 void Range::setStart(const Position& start, ExceptionState& exceptionState) { | 225 void Range::setStart(const Position& start, ExceptionState& exceptionState) { |
| 214 Position parentAnchored = start.parentAnchoredEquivalent(); | 226 Position parentAnchored = start.parentAnchoredEquivalent(); |
| 215 setStart(parentAnchored.computeContainerNode(), | 227 setStart(parentAnchored.computeContainerNode(), |
| 216 parentAnchored.offsetInContainerNode(), exceptionState); | 228 parentAnchored.offsetInContainerNode(), exceptionState); |
| 217 } | 229 } |
| 218 | 230 |
| 219 void Range::setEnd(const Position& end, ExceptionState& exceptionState) { | 231 void Range::setEnd(const Position& end, ExceptionState& exceptionState) { |
| 220 Position parentAnchored = end.parentAnchoredEquivalent(); | 232 Position parentAnchored = end.parentAnchoredEquivalent(); |
| 221 setEnd(parentAnchored.computeContainerNode(), | 233 setEnd(parentAnchored.computeContainerNode(), |
| 222 parentAnchored.offsetInContainerNode(), exceptionState); | 234 parentAnchored.offsetInContainerNode(), exceptionState); |
| 223 } | 235 } |
| 224 | 236 |
| 225 void Range::collapse(bool toStart) { | 237 void Range::collapse(bool toStart) { |
| 226 if (toStart) | 238 if (toStart) |
| 227 m_end = m_start; | 239 m_end = m_start; |
| 228 else | 240 else |
| 229 m_start = m_end; | 241 m_start = m_end; |
| 242 updateSelectionIfAddedToSelection(); |
| 230 } | 243 } |
| 231 | 244 |
| 232 bool Range::isNodeFullyContained(Node& node) const { | 245 bool Range::isNodeFullyContained(Node& node) const { |
| 233 ContainerNode* parentNode = node.parentNode(); | 246 ContainerNode* parentNode = node.parentNode(); |
| 234 int nodeIndex = node.nodeIndex(); | 247 int nodeIndex = node.nodeIndex(); |
| 235 return isPointInRange( | 248 return isPointInRange( |
| 236 parentNode, nodeIndex, | 249 parentNode, nodeIndex, |
| 237 IGNORE_EXCEPTION_FOR_TESTING) // starts in the middle of this | 250 IGNORE_EXCEPTION_FOR_TESTING) // starts in the middle of this |
| 238 // range, or on the boundary points. | 251 // range, or on the boundary points. |
| 239 && isPointInRange( | 252 && isPointInRange( |
| (...skipping 929 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1169 break; | 1182 break; |
| 1170 case Node::kAttributeNode: | 1183 case Node::kAttributeNode: |
| 1171 case Node::kDocumentFragmentNode: | 1184 case Node::kDocumentFragmentNode: |
| 1172 case Node::kDocumentNode: | 1185 case Node::kDocumentNode: |
| 1173 exceptionState.throwDOMException( | 1186 exceptionState.throwDOMException( |
| 1174 InvalidNodeTypeError, | 1187 InvalidNodeTypeError, |
| 1175 "The node provided is of type '" + refNode->nodeName() + "'."); | 1188 "The node provided is of type '" + refNode->nodeName() + "'."); |
| 1176 return; | 1189 return; |
| 1177 } | 1190 } |
| 1178 | 1191 |
| 1179 if (m_ownerDocument != refNode->document()) | |
| 1180 setDocument(refNode->document()); | |
| 1181 | |
| 1182 setStartBefore(refNode); | 1192 setStartBefore(refNode); |
| 1183 setEndAfter(refNode); | 1193 setEndAfter(refNode); |
| 1184 } | 1194 } |
| 1185 | 1195 |
| 1186 void Range::selectNodeContents(Node* refNode, ExceptionState& exceptionState) { | 1196 void Range::selectNodeContents(Node* refNode, ExceptionState& exceptionState) { |
| 1187 if (!refNode) { | 1197 if (!refNode) { |
| 1188 // FIXME: Generated bindings code never calls with null, and neither should | 1198 // FIXME: Generated bindings code never calls with null, and neither should |
| 1189 // other callers! | 1199 // other callers! |
| 1190 exceptionState.throwTypeError("The node provided is null."); | 1200 exceptionState.throwTypeError("The node provided is null."); |
| 1191 return; | 1201 return; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1206 case Node::kTextNode: | 1216 case Node::kTextNode: |
| 1207 break; | 1217 break; |
| 1208 case Node::kDocumentTypeNode: | 1218 case Node::kDocumentTypeNode: |
| 1209 exceptionState.throwDOMException( | 1219 exceptionState.throwDOMException( |
| 1210 InvalidNodeTypeError, | 1220 InvalidNodeTypeError, |
| 1211 "The node provided is of type '" + refNode->nodeName() + "'."); | 1221 "The node provided is of type '" + refNode->nodeName() + "'."); |
| 1212 return; | 1222 return; |
| 1213 } | 1223 } |
| 1214 } | 1224 } |
| 1215 | 1225 |
| 1226 Document& oldDocument = ownerDocument(); |
| 1216 if (m_ownerDocument != refNode->document()) | 1227 if (m_ownerDocument != refNode->document()) |
| 1217 setDocument(refNode->document()); | 1228 setDocument(refNode->document()); |
| 1218 | 1229 |
| 1219 m_start.setToStartOfNode(*refNode); | 1230 m_start.setToStartOfNode(*refNode); |
| 1220 m_end.setToEndOfNode(*refNode); | 1231 m_end.setToEndOfNode(*refNode); |
| 1232 removeFromSelectionIfInDifferentRoot(oldDocument); |
| 1233 updateSelectionIfAddedToSelection(); |
| 1221 } | 1234 } |
| 1222 | 1235 |
| 1223 bool Range::selectNodeContents(Node* refNode, Position& start, Position& end) { | 1236 bool Range::selectNodeContents(Node* refNode, Position& start, Position& end) { |
| 1224 if (!refNode) { | 1237 if (!refNode) { |
| 1225 return false; | 1238 return false; |
| 1226 } | 1239 } |
| 1227 | 1240 |
| 1228 for (Node* n = refNode; n; n = n->parentNode()) { | 1241 for (Node* n = refNode; n; n = n->parentNode()) { |
| 1229 switch (n->getNodeType()) { | 1242 switch (n->getNodeType()) { |
| 1230 case Node::kAttributeNode: | 1243 case Node::kAttributeNode: |
| (...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1693 for (const FloatQuad& quad : quads) | 1706 for (const FloatQuad& quad : quads) |
| 1694 result.unite(quad.boundingBox()); // Skips empty rects. | 1707 result.unite(quad.boundingBox()); // Skips empty rects. |
| 1695 | 1708 |
| 1696 // If all rects are empty, return the first rect. | 1709 // If all rects are empty, return the first rect. |
| 1697 if (result.isEmpty() && !quads.isEmpty()) | 1710 if (result.isEmpty() && !quads.isEmpty()) |
| 1698 return quads.front().boundingBox(); | 1711 return quads.front().boundingBox(); |
| 1699 | 1712 |
| 1700 return result; | 1713 return result; |
| 1701 } | 1714 } |
| 1702 | 1715 |
| 1716 void Range::updateSelectionIfAddedToSelection() { |
| 1717 if (!ownerDocument().frame()) |
| 1718 return; |
| 1719 FrameSelection& selection = ownerDocument().frame()->selection(); |
| 1720 if (this != selection.documentCachedRange()) |
| 1721 return; |
| 1722 DCHECK(startContainer()->isConnected()); |
| 1723 DCHECK(startContainer()->document() == ownerDocument()); |
| 1724 DCHECK(endContainer()->isConnected()); |
| 1725 DCHECK(endContainer()->document() == ownerDocument()); |
| 1726 selection.setSelectedRange(EphemeralRange(this), VP_DEFAULT_AFFINITY); |
| 1727 selection.cacheRangeOfDocument(this); |
| 1728 } |
| 1729 |
| 1730 void Range::removeFromSelectionIfInDifferentRoot(Document& oldDocument) { |
| 1731 if (!oldDocument.frame()) |
| 1732 return; |
| 1733 FrameSelection& selection = oldDocument.frame()->selection(); |
| 1734 if (this != selection.documentCachedRange()) |
| 1735 return; |
| 1736 if (ownerDocument() == oldDocument && startContainer()->isConnected() && |
| 1737 endContainer()->isConnected()) |
| 1738 return; |
| 1739 selection.clear(); |
| 1740 selection.clearDocumentCachedRange(); |
| 1741 } |
| 1742 |
| 1703 DEFINE_TRACE(Range) { | 1743 DEFINE_TRACE(Range) { |
| 1704 visitor->trace(m_ownerDocument); | 1744 visitor->trace(m_ownerDocument); |
| 1705 visitor->trace(m_start); | 1745 visitor->trace(m_start); |
| 1706 visitor->trace(m_end); | 1746 visitor->trace(m_end); |
| 1707 } | 1747 } |
| 1708 | 1748 |
| 1709 } // namespace blink | 1749 } // namespace blink |
| 1710 | 1750 |
| 1711 #ifndef NDEBUG | 1751 #ifndef NDEBUG |
| 1712 | 1752 |
| 1713 void showTree(const blink::Range* range) { | 1753 void showTree(const blink::Range* range) { |
| 1714 if (range && range->boundaryPointsValid()) { | 1754 if (range && range->boundaryPointsValid()) { |
| 1715 LOG(INFO) << "\n" | 1755 LOG(INFO) << "\n" |
| 1716 << range->startContainer() | 1756 << range->startContainer() |
| 1717 ->toMarkedTreeString(range->startContainer(), "S", | 1757 ->toMarkedTreeString(range->startContainer(), "S", |
| 1718 range->endContainer(), "E") | 1758 range->endContainer(), "E") |
| 1719 .utf8() | 1759 .utf8() |
| 1720 .data() | 1760 .data() |
| 1721 << "start offset: " << range->startOffset() | 1761 << "start offset: " << range->startOffset() |
| 1722 << ", end offset: " << range->endOffset(); | 1762 << ", end offset: " << range->endOffset(); |
| 1723 } else { | 1763 } else { |
| 1724 LOG(INFO) << "Cannot show tree if range is null, or if boundary points are " | 1764 LOG(INFO) << "Cannot show tree if range is null, or if boundary points are " |
| 1725 "invalid."; | 1765 "invalid."; |
| 1726 } | 1766 } |
| 1727 } | 1767 } |
| 1728 | 1768 |
| 1729 #endif | 1769 #endif |
| OLD | NEW |