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

Side by Side Diff: third_party/WebKit/Source/core/editing/DOMSelection.cpp

Issue 2704443002: Selection API: extend() should operate DOM Ranges. (Closed)
Patch Set: . 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 const Position& DOMSelection::focusPosition() const {
90 DCHECK(frame());
91 return frame()->selection().selectionInDOMTree().extent();
92 }
93
94 // TODO(tkent): Following four functions based on VisibleSelection should be
95 // removed.
84 static Position anchorPosition(const VisibleSelection& selection) { 96 static Position anchorPosition(const VisibleSelection& selection) {
85 Position anchor = 97 Position anchor =
86 selection.isBaseFirst() ? selection.start() : selection.end(); 98 selection.isBaseFirst() ? selection.start() : selection.end();
87 return anchor.parentAnchoredEquivalent(); 99 return anchor.parentAnchoredEquivalent();
88 } 100 }
89 101
90 static Position focusPosition(const VisibleSelection& selection) { 102 static Position focusPosition(const VisibleSelection& selection) {
91 Position focus = 103 Position focus =
92 selection.isBaseFirst() ? selection.end() : selection.start(); 104 selection.isBaseFirst() ? selection.end() : selection.start();
93 return focus.parentAnchoredEquivalent(); 105 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. 410 // needs to be audited. See http://crbug.com/590369 for more details.
399 frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); 411 frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
400 412
401 frame()->selection().modify(alter, direction, granularity); 413 frame()->selection().modify(alter, direction, granularity);
402 } 414 }
403 415
404 void DOMSelection::extend(Node* node, 416 void DOMSelection::extend(Node* node,
405 int offset, 417 int offset,
406 ExceptionState& exceptionState) { 418 ExceptionState& exceptionState) {
407 DCHECK(node); 419 DCHECK(node);
420 // https://www.w3.org/TR/selection-api/#dom-selection-extend
408 421
422 // 2. If the context object is empty, throw an InvalidStateError exception and
423 // abort these steps.
409 if (rangeCount() == 0) { 424 if (rangeCount() == 0) {
410 exceptionState.throwDOMException( 425 exceptionState.throwDOMException(
411 InvalidStateError, "This Selection object doesn't have any Ranges."); 426 InvalidStateError, "This Selection object doesn't have any Ranges.");
412 return; 427 return;
413 } 428 }
414 429
415 if (offset < 0) { 430 if (offset < 0) {
416 exceptionState.throwDOMException( 431 exceptionState.throwDOMException(
417 IndexSizeError, String::number(offset) + " is not a valid offset."); 432 IndexSizeError, String::number(offset) + " is not a valid offset.");
418 return; 433 return;
419 } 434 }
420 Range::checkNodeWOffset(node, offset, exceptionState); 435 Range::checkNodeWOffset(node, offset, exceptionState);
421 if (exceptionState.hadException()) 436 if (exceptionState.hadException())
422 return; 437 return;
423 438
439 // 1. If node's root is not the document associated with the context object,
440 // abort these steps.
424 if (!isValidForPosition(node)) 441 if (!isValidForPosition(node))
425 return; 442 return;
426 443
444 // 3. Let oldAnchor and oldFocus be the context object's anchor and focus, and
445 // let newFocus be the boundary point (node, offset).
446 const Position& oldAnchor = anchorPosition();
447 DCHECK(!oldAnchor.isNull());
448 Position newFocus(node, offset);
yoichio 2017/02/16 07:26:05 Could you declare |const Position newFocus| ?
tkent 2017/02/16 08:14:38 Yes, done.
449
427 clearCachedRangeIfSelectionOfDocument(); 450 clearCachedRangeIfSelectionOfDocument();
428 const Position& base = frame()->selection().base(); 451
429 if (base.isNull()) { 452 // 4. Let newRange be a new range.
430 // TODO(editing-dev): We should throw |InvalidStateError| if selection is 453 Range* newRange = Range::create(*frame()->document());
431 // none to follow the spec. 454
455 // 5. If node's root is not the same as the context object's range's root, set
456 // newRange's start and end to newFocus.
457 // E.g. oldAnchor might point in shadow Text node in TextControlElement.
458 if (oldAnchor.anchorNode()->treeRoot() != node->treeRoot()) {
459 newRange->setStart(node, offset);
460 newRange->setEnd(node, offset);
461
462 } else if (oldAnchor <= newFocus) {
463 // 6. Otherwise, if oldAnchor is before or equal to newFocus, set newRange's
464 // start to oldAnchor, then set its end to newFocus.
465 newRange->setStart(oldAnchor.anchorNode(),
466 oldAnchor.offsetInContainerNode());
467 newRange->setEnd(node, offset);
468
469 } else {
470 // 7. Otherwise, set newRange's start to newFocus, then set its end to
471 // oldAnchor.
472 newRange->setStart(node, offset);
473 newRange->setEnd(oldAnchor.anchorNode(), oldAnchor.offsetInContainerNode());
474 }
475
476 // 8. Set the context object's range to newRange.
yoichio 2017/02/16 07:26:05 How about following code to share?: SelectionInDO
tkent 2017/02/16 08:14:38 Done.
477 if (newRange->collapsed()) {
432 frame()->selection().setSelection(SelectionInDOMTree::Builder() 478 frame()->selection().setSelection(SelectionInDOMTree::Builder()
433 .collapse(Position(node, offset)) 479 .collapse(newFocus)
434 .setIsDirectional(true) 480 .setIsDirectional(true)
435 .build()); 481 .build());
436 return; 482 } else {
483 frame()->selection().setSelection(SelectionInDOMTree::Builder()
484 .collapse(oldAnchor)
485 .extend(newFocus)
486 .setIsDirectional(true)
487 .build());
437 } 488 }
438 frame()->selection().setSelection(SelectionInDOMTree::Builder() 489 cacheRangeIfSelectionOfDocument(newRange);
439 .collapse(base)
440 .extend(Position(node, offset))
441 .setIsDirectional(true)
442 .build());
443 } 490 }
444 491
445 Range* DOMSelection::getRangeAt(int index, 492 Range* DOMSelection::getRangeAt(int index,
446 ExceptionState& exceptionState) const { 493 ExceptionState& exceptionState) const {
447 if (!isAvailable()) 494 if (!isAvailable())
448 return nullptr; 495 return nullptr;
449 496
450 if (index < 0 || index >= rangeCount()) { 497 if (index < 0 || index >= rangeCount()) {
451 exceptionState.throwDOMException( 498 exceptionState.throwDOMException(
452 IndexSizeError, String::number(index) + " is not a valid index."); 499 IndexSizeError, String::number(index) + " is not a valid index.");
453 return nullptr; 500 return nullptr;
454 } 501 }
455 502
456 // If you're hitting this, you've added broken multi-range selection support 503 // If you're hitting this, you've added broken multi-range selection support
457 DCHECK_EQ(rangeCount(), 1); 504 DCHECK_EQ(rangeCount(), 1);
458 505
459 if (Range* cachedRange = documentCachedRange()) 506 if (Range* cachedRange = documentCachedRange())
460 return cachedRange; 507 return cachedRange;
461 508
462 Range* range = createRangeFromSelectionEditor(); 509 Range* range = createRangeFromSelectionEditor();
463 cacheRangeIfSelectionOfDocument(range); 510 cacheRangeIfSelectionOfDocument(range);
464 return range; 511 return range;
465 } 512 }
466 513
467 Range* DOMSelection::primaryRangeOrNull() const { 514 Range* DOMSelection::primaryRangeOrNull() const {
468 return rangeCount() > 0 ? getRangeAt(0, ASSERT_NO_EXCEPTION) : nullptr; 515 return rangeCount() > 0 ? getRangeAt(0, ASSERT_NO_EXCEPTION) : nullptr;
469 } 516 }
470 517
471 Range* DOMSelection::createRangeFromSelectionEditor() const { 518 Range* DOMSelection::createRangeFromSelectionEditor() const {
472 Position anchor = anchorPosition(visibleSelection()); 519 Position anchor = blink::anchorPosition(visibleSelection());
473 if (isSelectionOfDocument() && !anchor.anchorNode()->isInShadowTree()) 520 if (isSelectionOfDocument() && !anchor.anchorNode()->isInShadowTree())
474 return frame()->selection().firstRange(); 521 return frame()->selection().firstRange();
475 522
476 Node* node = shadowAdjustedNode(anchor); 523 Node* node = shadowAdjustedNode(anchor);
477 if (!node) // crbug.com/595100 524 if (!node) // crbug.com/595100
478 return nullptr; 525 return nullptr;
479 Position focus = focusPosition(visibleSelection()); 526 Position focus = blink::focusPosition(visibleSelection());
480 if (!visibleSelection().isBaseFirst()) { 527 if (!visibleSelection().isBaseFirst()) {
481 return Range::create(*anchor.document(), shadowAdjustedNode(focus), 528 return Range::create(*anchor.document(), shadowAdjustedNode(focus),
482 shadowAdjustedOffset(focus), node, 529 shadowAdjustedOffset(focus), node,
483 shadowAdjustedOffset(anchor)); 530 shadowAdjustedOffset(anchor));
484 } 531 }
485 return Range::create(*anchor.document(), node, shadowAdjustedOffset(anchor), 532 return Range::create(*anchor.document(), node, shadowAdjustedOffset(anchor),
486 shadowAdjustedNode(focus), shadowAdjustedOffset(focus)); 533 shadowAdjustedNode(focus), shadowAdjustedOffset(focus));
487 } 534 }
488 535
489 bool DOMSelection::isSelectionOfDocument() const { 536 bool DOMSelection::isSelectionOfDocument() const {
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 m_treeScope->document().addConsoleMessage( 800 m_treeScope->document().addConsoleMessage(
754 ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message)); 801 ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message));
755 } 802 }
756 803
757 DEFINE_TRACE(DOMSelection) { 804 DEFINE_TRACE(DOMSelection) {
758 visitor->trace(m_treeScope); 805 visitor->trace(m_treeScope);
759 ContextClient::trace(visitor); 806 ContextClient::trace(visitor);
760 } 807 }
761 808
762 } // namespace blink 809 } // 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