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 // 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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |