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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/core/editing/DOMSelection.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. 2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 8 *
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 return frame()->selection().selection(); 74 return frame()->selection().selection();
75 } 75 }
76 76
77 bool DOMSelection::isBaseFirstInSelection() const { 77 bool DOMSelection::isBaseFirstInSelection() const {
78 DCHECK(frame()); 78 DCHECK(frame());
79 const SelectionInDOMTree& selection = 79 const SelectionInDOMTree& selection =
80 frame()->selection().selectionInDOMTree(); 80 frame()->selection().selectionInDOMTree();
81 return selection.base() <= selection.extent(); 81 return selection.base() <= selection.extent();
82 } 82 }
83 83
84 const Position& DOMSelection::anchorPosition() const {
85 DCHECK(frame());
86 return frame()->selection().selectionInDOMTree().base();
87 }
88
89 // TODO(tkent): Following four functions based on VisibleSelection should be
90 // removed.
84 static Position anchorPosition(const VisibleSelection& selection) { 91 static Position anchorPosition(const VisibleSelection& selection) {
85 Position anchor = 92 Position anchor =
86 selection.isBaseFirst() ? selection.start() : selection.end(); 93 selection.isBaseFirst() ? selection.start() : selection.end();
87 return anchor.parentAnchoredEquivalent(); 94 return anchor.parentAnchoredEquivalent();
88 } 95 }
89 96
90 static Position focusPosition(const VisibleSelection& selection) { 97 static Position focusPosition(const VisibleSelection& selection) {
91 Position focus = 98 Position focus =
92 selection.isBaseFirst() ? selection.end() : selection.start(); 99 selection.isBaseFirst() ? selection.end() : selection.start();
93 return focus.parentAnchoredEquivalent(); 100 return focus.parentAnchoredEquivalent();
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 // needs to be audited. See http://crbug.com/590369 for more details. 405 // needs to be audited. See http://crbug.com/590369 for more details.
399 frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); 406 frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
400 407
401 frame()->selection().modify(alter, direction, granularity); 408 frame()->selection().modify(alter, direction, granularity);
402 } 409 }
403 410
404 void DOMSelection::extend(Node* node, 411 void DOMSelection::extend(Node* node,
405 int offset, 412 int offset,
406 ExceptionState& exceptionState) { 413 ExceptionState& exceptionState) {
407 DCHECK(node); 414 DCHECK(node);
415 // https://www.w3.org/TR/selection-api/#dom-selection-extend
408 416
417 // 2. If the context object is empty, throw an InvalidStateError exception and
418 // abort these steps.
409 if (rangeCount() == 0) { 419 if (rangeCount() == 0) {
410 exceptionState.throwDOMException( 420 exceptionState.throwDOMException(
411 InvalidStateError, "This Selection object doesn't have any Ranges."); 421 InvalidStateError, "This Selection object doesn't have any Ranges.");
412 return; 422 return;
413 } 423 }
414 424
415 if (offset < 0) { 425 if (offset < 0) {
416 exceptionState.throwDOMException( 426 exceptionState.throwDOMException(
417 IndexSizeError, String::number(offset) + " is not a valid offset."); 427 IndexSizeError, String::number(offset) + " is not a valid offset.");
418 return; 428 return;
419 } 429 }
420 Range::checkNodeWOffset(node, offset, exceptionState); 430 Range::checkNodeWOffset(node, offset, exceptionState);
421 if (exceptionState.hadException()) 431 if (exceptionState.hadException())
422 return; 432 return;
423 433
434 // 1. If node's root is not the document associated with the context object,
435 // abort these steps.
424 if (!isValidForPosition(node)) 436 if (!isValidForPosition(node))
425 return; 437 return;
426 438
439 // 3. Let oldAnchor and oldFocus be the context object's anchor and focus, and
440 // let newFocus be the boundary point (node, offset).
441 const Position& oldAnchor = anchorPosition();
442 DCHECK(!oldAnchor.isNull());
443 const Position newFocus(node, offset);
444
427 clearCachedRangeIfSelectionOfDocument(); 445 clearCachedRangeIfSelectionOfDocument();
428 const Position& base = frame()->selection().base(); 446
429 if (base.isNull()) { 447 // 4. Let newRange be a new range.
430 // TODO(editing-dev): We should throw |InvalidStateError| if selection is 448 Range* newRange = Range::create(*frame()->document());
431 // none to follow the spec. 449
432 frame()->selection().setSelection(SelectionInDOMTree::Builder() 450 // 5. If node's root is not the same as the context object's range's root, set
433 .collapse(Position(node, offset)) 451 // newRange's start and end to newFocus.
434 .setIsDirectional(true) 452 // E.g. oldAnchor might point in shadow Text node in TextControlElement.
435 .build()); 453 if (oldAnchor.anchorNode()->treeRoot() != node->treeRoot()) {
436 return; 454 newRange->setStart(node, offset);
455 newRange->setEnd(node, offset);
456
457 } else if (oldAnchor <= newFocus) {
458 // 6. Otherwise, if oldAnchor is before or equal to newFocus, set newRange's
459 // start to oldAnchor, then set its end to newFocus.
460 newRange->setStart(oldAnchor.anchorNode(),
461 oldAnchor.offsetInContainerNode());
462 newRange->setEnd(node, offset);
463
464 } else {
465 // 7. Otherwise, set newRange's start to newFocus, then set its end to
466 // oldAnchor.
467 newRange->setStart(node, offset);
468 newRange->setEnd(oldAnchor.anchorNode(), oldAnchor.offsetInContainerNode());
437 } 469 }
438 frame()->selection().setSelection(SelectionInDOMTree::Builder() 470
439 .collapse(base) 471 // 8. Set the context object's range to newRange.
440 .extend(Position(node, offset)) 472 SelectionInDOMTree::Builder builder;
441 .setIsDirectional(true) 473 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.
442 .build()); 474 builder.collapse(newFocus);
475 else
476 builder.collapse(oldAnchor).extend(newFocus);
477 frame()->selection().setSelection(builder.setIsDirectional(true).build());
478 cacheRangeIfSelectionOfDocument(newRange);
443 } 479 }
444 480
445 Range* DOMSelection::getRangeAt(int index, 481 Range* DOMSelection::getRangeAt(int index,
446 ExceptionState& exceptionState) const { 482 ExceptionState& exceptionState) const {
447 if (!isAvailable()) 483 if (!isAvailable())
448 return nullptr; 484 return nullptr;
449 485
450 if (index < 0 || index >= rangeCount()) { 486 if (index < 0 || index >= rangeCount()) {
451 exceptionState.throwDOMException( 487 exceptionState.throwDOMException(
452 IndexSizeError, String::number(index) + " is not a valid index."); 488 IndexSizeError, String::number(index) + " is not a valid index.");
453 return nullptr; 489 return nullptr;
454 } 490 }
455 491
456 // If you're hitting this, you've added broken multi-range selection support 492 // If you're hitting this, you've added broken multi-range selection support
457 DCHECK_EQ(rangeCount(), 1); 493 DCHECK_EQ(rangeCount(), 1);
458 494
459 if (Range* cachedRange = documentCachedRange()) 495 if (Range* cachedRange = documentCachedRange())
460 return cachedRange; 496 return cachedRange;
461 497
462 Range* range = createRangeFromSelectionEditor(); 498 Range* range = createRangeFromSelectionEditor();
463 cacheRangeIfSelectionOfDocument(range); 499 cacheRangeIfSelectionOfDocument(range);
464 return range; 500 return range;
465 } 501 }
466 502
467 Range* DOMSelection::primaryRangeOrNull() const { 503 Range* DOMSelection::primaryRangeOrNull() const {
468 return rangeCount() > 0 ? getRangeAt(0, ASSERT_NO_EXCEPTION) : nullptr; 504 return rangeCount() > 0 ? getRangeAt(0, ASSERT_NO_EXCEPTION) : nullptr;
469 } 505 }
470 506
471 Range* DOMSelection::createRangeFromSelectionEditor() const { 507 Range* DOMSelection::createRangeFromSelectionEditor() const {
472 Position anchor = anchorPosition(visibleSelection()); 508 Position anchor = blink::anchorPosition(visibleSelection());
473 if (isSelectionOfDocument() && !anchor.anchorNode()->isInShadowTree()) 509 if (isSelectionOfDocument() && !anchor.anchorNode()->isInShadowTree())
474 return frame()->selection().firstRange(); 510 return frame()->selection().firstRange();
475 511
476 Node* node = shadowAdjustedNode(anchor); 512 Node* node = shadowAdjustedNode(anchor);
477 if (!node) // crbug.com/595100 513 if (!node) // crbug.com/595100
478 return nullptr; 514 return nullptr;
479 Position focus = focusPosition(visibleSelection()); 515 Position focus = blink::focusPosition(visibleSelection());
480 if (!visibleSelection().isBaseFirst()) { 516 if (!visibleSelection().isBaseFirst()) {
481 return Range::create(*anchor.document(), shadowAdjustedNode(focus), 517 return Range::create(*anchor.document(), shadowAdjustedNode(focus),
482 shadowAdjustedOffset(focus), node, 518 shadowAdjustedOffset(focus), node,
483 shadowAdjustedOffset(anchor)); 519 shadowAdjustedOffset(anchor));
484 } 520 }
485 return Range::create(*anchor.document(), node, shadowAdjustedOffset(anchor), 521 return Range::create(*anchor.document(), node, shadowAdjustedOffset(anchor),
486 shadowAdjustedNode(focus), shadowAdjustedOffset(focus)); 522 shadowAdjustedNode(focus), shadowAdjustedOffset(focus));
487 } 523 }
488 524
489 bool DOMSelection::isSelectionOfDocument() const { 525 bool DOMSelection::isSelectionOfDocument() const {
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 m_treeScope->document().addConsoleMessage( 789 m_treeScope->document().addConsoleMessage(
754 ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message)); 790 ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message));
755 } 791 }
756 792
757 DEFINE_TRACE(DOMSelection) { 793 DEFINE_TRACE(DOMSelection) {
758 visitor->trace(m_treeScope); 794 visitor->trace(m_treeScope);
759 ContextClient::trace(visitor); 795 ContextClient::trace(visitor);
760 } 796 }
761 797
762 } // namespace blink 798 } // namespace blink
OLDNEW
« 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