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 |