Chromium Code Reviews| 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 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 setDocument(refNode->document()); | 177 setDocument(refNode->document()); |
| 176 didMoveDocument = true; | 178 didMoveDocument = true; |
| 177 } | 179 } |
| 178 | 180 |
| 179 Node* childNode = checkNodeWOffset(refNode, offset, exceptionState); | 181 Node* childNode = checkNodeWOffset(refNode, offset, exceptionState); |
| 180 if (exceptionState.hadException()) | 182 if (exceptionState.hadException()) |
| 181 return; | 183 return; |
| 182 | 184 |
| 183 m_start.set(refNode, offset, childNode); | 185 m_start.set(refNode, offset, childNode); |
| 184 | 186 |
| 185 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) | 187 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) |
|
yosin_UTC9
2017/02/10 10:26:27
nit: Can we use early-return style?
if (didMoveDo
tkent
2017/02/13 04:04:13
Good point. I'll investigate Firefox/Edge behavio
tkent
2017/02/13 05:45:29
Both of Firefox and Edge keep Selection.getRangeAt
tkent
2017/02/13 07:31:40
We discussed offline, and agreed that we should un
| |
| 186 collapse(true); | 188 collapse(true); |
| 189 else | |
| 190 updateSelectionIfAddedToSelection(); | |
| 187 } | 191 } |
| 188 | 192 |
| 189 void Range::setEnd(Node* refNode, int offset, ExceptionState& exceptionState) { | 193 void Range::setEnd(Node* refNode, int offset, ExceptionState& exceptionState) { |
| 190 if (!refNode) { | 194 if (!refNode) { |
| 191 // FIXME: Generated bindings code never calls with null, and neither should | 195 // FIXME: Generated bindings code never calls with null, and neither should |
| 192 // other callers! | 196 // other callers! |
| 193 exceptionState.throwTypeError("The node provided is null."); | 197 exceptionState.throwTypeError("The node provided is null."); |
| 194 return; | 198 return; |
| 195 } | 199 } |
| 196 | 200 |
| 197 bool didMoveDocument = false; | 201 bool didMoveDocument = false; |
| 198 if (refNode->document() != m_ownerDocument) { | 202 if (refNode->document() != m_ownerDocument) { |
| 199 setDocument(refNode->document()); | 203 setDocument(refNode->document()); |
| 200 didMoveDocument = true; | 204 didMoveDocument = true; |
| 201 } | 205 } |
| 202 | 206 |
| 203 Node* childNode = checkNodeWOffset(refNode, offset, exceptionState); | 207 Node* childNode = checkNodeWOffset(refNode, offset, exceptionState); |
| 204 if (exceptionState.hadException()) | 208 if (exceptionState.hadException()) |
| 205 return; | 209 return; |
| 206 | 210 |
| 207 m_end.set(refNode, offset, childNode); | 211 m_end.set(refNode, offset, childNode); |
| 208 | 212 |
| 209 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) | 213 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) |
|
yosin_UTC9
2017/02/10 10:26:27
Similar to L187 in Range::setStart()
tkent
2017/02/13 07:31:40
Done.
| |
| 210 collapse(false); | 214 collapse(false); |
| 215 else | |
| 216 updateSelectionIfAddedToSelection(); | |
| 211 } | 217 } |
| 212 | 218 |
| 213 void Range::setStart(const Position& start, ExceptionState& exceptionState) { | 219 void Range::setStart(const Position& start, ExceptionState& exceptionState) { |
| 214 Position parentAnchored = start.parentAnchoredEquivalent(); | 220 Position parentAnchored = start.parentAnchoredEquivalent(); |
| 215 setStart(parentAnchored.computeContainerNode(), | 221 setStart(parentAnchored.computeContainerNode(), |
| 216 parentAnchored.offsetInContainerNode(), exceptionState); | 222 parentAnchored.offsetInContainerNode(), exceptionState); |
| 217 } | 223 } |
| 218 | 224 |
| 219 void Range::setEnd(const Position& end, ExceptionState& exceptionState) { | 225 void Range::setEnd(const Position& end, ExceptionState& exceptionState) { |
| 220 Position parentAnchored = end.parentAnchoredEquivalent(); | 226 Position parentAnchored = end.parentAnchoredEquivalent(); |
| 221 setEnd(parentAnchored.computeContainerNode(), | 227 setEnd(parentAnchored.computeContainerNode(), |
| 222 parentAnchored.offsetInContainerNode(), exceptionState); | 228 parentAnchored.offsetInContainerNode(), exceptionState); |
| 223 } | 229 } |
| 224 | 230 |
| 225 void Range::collapse(bool toStart) { | 231 void Range::collapse(bool toStart) { |
| 226 if (toStart) | 232 if (toStart) |
| 227 m_end = m_start; | 233 m_end = m_start; |
| 228 else | 234 else |
| 229 m_start = m_end; | 235 m_start = m_end; |
| 236 updateSelectionIfAddedToSelection(); | |
| 230 } | 237 } |
| 231 | 238 |
| 232 bool Range::isNodeFullyContained(Node& node) const { | 239 bool Range::isNodeFullyContained(Node& node) const { |
| 233 ContainerNode* parentNode = node.parentNode(); | 240 ContainerNode* parentNode = node.parentNode(); |
| 234 int nodeIndex = node.nodeIndex(); | 241 int nodeIndex = node.nodeIndex(); |
| 235 return isPointInRange( | 242 return isPointInRange( |
| 236 parentNode, nodeIndex, | 243 parentNode, nodeIndex, |
| 237 IGNORE_EXCEPTION_FOR_TESTING) // starts in the middle of this | 244 IGNORE_EXCEPTION_FOR_TESTING) // starts in the middle of this |
| 238 // range, or on the boundary points. | 245 // range, or on the boundary points. |
| 239 && isPointInRange( | 246 && isPointInRange( |
| (...skipping 971 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1211 "The node provided is of type '" + refNode->nodeName() + "'."); | 1218 "The node provided is of type '" + refNode->nodeName() + "'."); |
| 1212 return; | 1219 return; |
| 1213 } | 1220 } |
| 1214 } | 1221 } |
| 1215 | 1222 |
| 1216 if (m_ownerDocument != refNode->document()) | 1223 if (m_ownerDocument != refNode->document()) |
| 1217 setDocument(refNode->document()); | 1224 setDocument(refNode->document()); |
| 1218 | 1225 |
| 1219 m_start.setToStartOfNode(*refNode); | 1226 m_start.setToStartOfNode(*refNode); |
| 1220 m_end.setToEndOfNode(*refNode); | 1227 m_end.setToEndOfNode(*refNode); |
| 1228 updateSelectionIfAddedToSelection(); | |
| 1221 } | 1229 } |
| 1222 | 1230 |
| 1223 bool Range::selectNodeContents(Node* refNode, Position& start, Position& end) { | 1231 bool Range::selectNodeContents(Node* refNode, Position& start, Position& end) { |
| 1224 if (!refNode) { | 1232 if (!refNode) { |
| 1225 return false; | 1233 return false; |
| 1226 } | 1234 } |
| 1227 | 1235 |
| 1228 for (Node* n = refNode; n; n = n->parentNode()) { | 1236 for (Node* n = refNode; n; n = n->parentNode()) { |
| 1229 switch (n->getNodeType()) { | 1237 switch (n->getNodeType()) { |
| 1230 case Node::kAttributeNode: | 1238 case Node::kAttributeNode: |
| (...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1693 for (const FloatQuad& quad : quads) | 1701 for (const FloatQuad& quad : quads) |
| 1694 result.unite(quad.boundingBox()); // Skips empty rects. | 1702 result.unite(quad.boundingBox()); // Skips empty rects. |
| 1695 | 1703 |
| 1696 // If all rects are empty, return the first rect. | 1704 // If all rects are empty, return the first rect. |
| 1697 if (result.isEmpty() && !quads.isEmpty()) | 1705 if (result.isEmpty() && !quads.isEmpty()) |
| 1698 return quads.front().boundingBox(); | 1706 return quads.front().boundingBox(); |
| 1699 | 1707 |
| 1700 return result; | 1708 return result; |
| 1701 } | 1709 } |
| 1702 | 1710 |
| 1711 void Range::updateSelectionIfAddedToSelection() { | |
| 1712 if (!ownerDocument().frame()) | |
| 1713 return; | |
| 1714 FrameSelection& selection = ownerDocument().frame()->selection(); | |
| 1715 if (this != selection.documentCachedRange()) | |
| 1716 return; | |
| 1717 selection.setSelectedRange(EphemeralRange(this), VP_DEFAULT_AFFINITY); | |
| 1718 selection.cacheRangeOfDocument(this); | |
| 1719 } | |
| 1720 | |
| 1703 DEFINE_TRACE(Range) { | 1721 DEFINE_TRACE(Range) { |
| 1704 visitor->trace(m_ownerDocument); | 1722 visitor->trace(m_ownerDocument); |
| 1705 visitor->trace(m_start); | 1723 visitor->trace(m_start); |
| 1706 visitor->trace(m_end); | 1724 visitor->trace(m_end); |
| 1707 } | 1725 } |
| 1708 | 1726 |
| 1709 } // namespace blink | 1727 } // namespace blink |
| 1710 | 1728 |
| 1711 #ifndef NDEBUG | 1729 #ifndef NDEBUG |
| 1712 | 1730 |
| 1713 void showTree(const blink::Range* range) { | 1731 void showTree(const blink::Range* range) { |
| 1714 if (range && range->boundaryPointsValid()) { | 1732 if (range && range->boundaryPointsValid()) { |
| 1715 LOG(INFO) << "\n" | 1733 LOG(INFO) << "\n" |
| 1716 << range->startContainer() | 1734 << range->startContainer() |
| 1717 ->toMarkedTreeString(range->startContainer(), "S", | 1735 ->toMarkedTreeString(range->startContainer(), "S", |
| 1718 range->endContainer(), "E") | 1736 range->endContainer(), "E") |
| 1719 .utf8() | 1737 .utf8() |
| 1720 .data() | 1738 .data() |
| 1721 << "start offset: " << range->startOffset() | 1739 << "start offset: " << range->startOffset() |
| 1722 << ", end offset: " << range->endOffset(); | 1740 << ", end offset: " << range->endOffset(); |
| 1723 } else { | 1741 } else { |
| 1724 LOG(INFO) << "Cannot show tree if range is null, or if boundary points are " | 1742 LOG(INFO) << "Cannot show tree if range is null, or if boundary points are " |
| 1725 "invalid."; | 1743 "invalid."; |
| 1726 } | 1744 } |
| 1727 } | 1745 } |
| 1728 | 1746 |
| 1729 #endif | 1747 #endif |
| OLD | NEW |