Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(188)

Unified Diff: third_party/WebKit/Source/core/editing/DOMSelection.cpp

Issue 2704443002: Selection API: extend() should operate DOM Ranges. (Closed)
Patch Set: Apply yoichio's comments, remove unused focusPosition(). Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/editing/DOMSelection.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/core/editing/DOMSelection.cpp
diff --git a/third_party/WebKit/Source/core/editing/DOMSelection.cpp b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
index da74aa29d601e9082424cc260e49acffe948b5b7..1fcc3db5fa10badf94a8e889cfa2aadb5ff4dd01 100644
--- a/third_party/WebKit/Source/core/editing/DOMSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
@@ -81,6 +81,13 @@ bool DOMSelection::isBaseFirstInSelection() const {
return selection.base() <= selection.extent();
}
+const Position& DOMSelection::anchorPosition() const {
+ DCHECK(frame());
+ return frame()->selection().selectionInDOMTree().base();
+}
+
+// TODO(tkent): Following four functions based on VisibleSelection should be
+// removed.
static Position anchorPosition(const VisibleSelection& selection) {
Position anchor =
selection.isBaseFirst() ? selection.start() : selection.end();
@@ -405,7 +412,10 @@ void DOMSelection::extend(Node* node,
int offset,
ExceptionState& exceptionState) {
DCHECK(node);
+ // https://www.w3.org/TR/selection-api/#dom-selection-extend
+ // 2. If the context object is empty, throw an InvalidStateError exception and
+ // abort these steps.
if (rangeCount() == 0) {
exceptionState.throwDOMException(
InvalidStateError, "This Selection object doesn't have any Ranges.");
@@ -421,25 +431,51 @@ void DOMSelection::extend(Node* node,
if (exceptionState.hadException())
return;
+ // 1. If node's root is not the document associated with the context object,
+ // abort these steps.
if (!isValidForPosition(node))
return;
+ // 3. Let oldAnchor and oldFocus be the context object's anchor and focus, and
+ // let newFocus be the boundary point (node, offset).
+ const Position& oldAnchor = anchorPosition();
+ DCHECK(!oldAnchor.isNull());
+ const Position newFocus(node, offset);
+
clearCachedRangeIfSelectionOfDocument();
- const Position& base = frame()->selection().base();
- if (base.isNull()) {
- // TODO(editing-dev): We should throw |InvalidStateError| if selection is
- // none to follow the spec.
- frame()->selection().setSelection(SelectionInDOMTree::Builder()
- .collapse(Position(node, offset))
- .setIsDirectional(true)
- .build());
- return;
+
+ // 4. Let newRange be a new range.
+ Range* newRange = Range::create(*frame()->document());
+
+ // 5. If node's root is not the same as the context object's range's root, set
+ // newRange's start and end to newFocus.
+ // E.g. oldAnchor might point in shadow Text node in TextControlElement.
+ if (oldAnchor.anchorNode()->treeRoot() != node->treeRoot()) {
+ newRange->setStart(node, offset);
+ newRange->setEnd(node, offset);
+
+ } else if (oldAnchor <= newFocus) {
+ // 6. Otherwise, if oldAnchor is before or equal to newFocus, set newRange's
+ // start to oldAnchor, then set its end to newFocus.
+ newRange->setStart(oldAnchor.anchorNode(),
+ oldAnchor.offsetInContainerNode());
+ newRange->setEnd(node, offset);
+
+ } else {
+ // 7. Otherwise, set newRange's start to newFocus, then set its end to
+ // oldAnchor.
+ newRange->setStart(node, offset);
+ newRange->setEnd(oldAnchor.anchorNode(), oldAnchor.offsetInContainerNode());
}
- frame()->selection().setSelection(SelectionInDOMTree::Builder()
- .collapse(base)
- .extend(Position(node, offset))
- .setIsDirectional(true)
- .build());
+
+ // 8. Set the context object's range to newRange.
+ SelectionInDOMTree::Builder builder;
+ if (newRange->collapsed())
yosin_UTC9 2017/02/16 10:05:41 How about below? builder.setBaseAndExtent(Ephemer
tkent 2017/02/16 14:44:26 It doesn't work in step 7 case.
+ builder.collapse(newFocus);
+ else
+ builder.collapse(oldAnchor).extend(newFocus);
+ frame()->selection().setSelection(builder.setIsDirectional(true).build());
+ cacheRangeIfSelectionOfDocument(newRange);
}
Range* DOMSelection::getRangeAt(int index,
@@ -469,14 +505,14 @@ Range* DOMSelection::primaryRangeOrNull() const {
}
Range* DOMSelection::createRangeFromSelectionEditor() const {
- Position anchor = anchorPosition(visibleSelection());
+ Position anchor = blink::anchorPosition(visibleSelection());
if (isSelectionOfDocument() && !anchor.anchorNode()->isInShadowTree())
return frame()->selection().firstRange();
Node* node = shadowAdjustedNode(anchor);
if (!node) // crbug.com/595100
return nullptr;
- Position focus = focusPosition(visibleSelection());
+ Position focus = blink::focusPosition(visibleSelection());
if (!visibleSelection().isBaseFirst()) {
return Range::create(*anchor.document(), shadowAdjustedNode(focus),
shadowAdjustedOffset(focus), node,
« no previous file with comments | « third_party/WebKit/Source/core/editing/DOMSelection.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698