Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |