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

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

Issue 2416553002: Convert set{End,Start}RespectingGranularity() in VisibleSlection as pure functions (Closed)
Patch Set: 2016-10-12T19:51:30 Created 4 years, 2 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/VisibleSelection.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) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. 2 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 530 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 m_baseIsFirst = true; 541 m_baseIsFirst = true;
542 } else if (m_extent.isNull()) { 542 } else if (m_extent.isNull()) {
543 m_extent = m_base; 543 m_extent = m_base;
544 m_baseIsFirst = true; 544 m_baseIsFirst = true;
545 } else { 545 } else {
546 m_baseIsFirst = m_base.compareTo(m_extent) <= 0; 546 m_baseIsFirst = m_base.compareTo(m_extent) <= 0;
547 } 547 }
548 } 548 }
549 549
550 template <typename Strategy> 550 template <typename Strategy>
551 void VisibleSelectionTemplate<Strategy>::setStartRespectingGranularity( 551 static PositionTemplate<Strategy> computeStartRespectingGranularity(
552 const PositionWithAffinityTemplate<Strategy>& passedStart,
552 TextGranularity granularity) { 553 TextGranularity granularity) {
553 DCHECK(m_base.isNotNull()); 554 DCHECK(passedStart.isNotNull());
554 DCHECK(m_extent.isNotNull());
555
556 m_start = m_baseIsFirst ? m_base : m_extent;
557 555
558 switch (granularity) { 556 switch (granularity) {
559 case CharacterGranularity: 557 case CharacterGranularity:
560 // Don't do any expansion. 558 // Don't do any expansion.
561 break; 559 return passedStart.position();
562 case WordGranularity: { 560 case WordGranularity: {
563 // General case: Select the word the caret is positioned inside of. 561 // General case: Select the word the caret is positioned inside of.
564 // If the caret is on the word boundary, select the word according to 562 // If the caret is on the word boundary, select the word according to
565 // |wordSide|. 563 // |wordSide|.
566 // Edge case: If the caret is after the last word in a soft-wrapped line 564 // Edge case: If the caret is after the last word in a soft-wrapped line
567 // or the last word in the document, select that last word 565 // or the last word in the document, select that last word
568 // (LeftWordIfOnBoundary). 566 // (LeftWordIfOnBoundary).
569 // Edge case: If the caret is after the last word in a paragraph, select 567 // Edge case: If the caret is after the last word in a paragraph, select
570 // from the the end of the last word to the line break (also 568 // from the the end of the last word to the line break (also
571 // RightWordIfOnBoundary); 569 // RightWordIfOnBoundary);
572 const VisiblePositionTemplate<Strategy> visibleStart = 570 const VisiblePositionTemplate<Strategy> visibleStart =
573 createVisiblePosition(m_start, m_affinity); 571 createVisiblePosition(passedStart);
574 EWordSide side = RightWordIfOnBoundary;
575 if (isEndOfEditableOrNonEditableContent(visibleStart) || 572 if (isEndOfEditableOrNonEditableContent(visibleStart) ||
576 (isEndOfLine(visibleStart) && !isStartOfLine(visibleStart) && 573 (isEndOfLine(visibleStart) && !isStartOfLine(visibleStart) &&
577 !isEndOfParagraph(visibleStart))) 574 !isEndOfParagraph(visibleStart))) {
578 side = LeftWordIfOnBoundary; 575 return startOfWord(visibleStart, LeftWordIfOnBoundary).deepEquivalent();
579 m_start = startOfWord(visibleStart, side).deepEquivalent(); 576 }
580 break; 577 return startOfWord(visibleStart, RightWordIfOnBoundary).deepEquivalent();
581 } 578 }
582 case SentenceGranularity: { 579 case SentenceGranularity:
583 m_start = startOfSentence(createVisiblePosition(m_start, m_affinity)) 580 return startOfSentence(createVisiblePosition(passedStart))
584 .deepEquivalent(); 581 .deepEquivalent();
585 break; 582 case LineGranularity:
586 } 583 return startOfLine(createVisiblePosition(passedStart)).deepEquivalent();
587 case LineGranularity: {
588 m_start = startOfLine(createVisiblePosition(m_start, m_affinity))
589 .deepEquivalent();
590 break;
591 }
592 case LineBoundary: 584 case LineBoundary:
593 m_start = startOfLine(createVisiblePosition(m_start, m_affinity)) 585 return startOfLine(createVisiblePosition(passedStart)).deepEquivalent();
594 .deepEquivalent();
595 break;
596 case ParagraphGranularity: { 586 case ParagraphGranularity: {
597 VisiblePositionTemplate<Strategy> pos = 587 const VisiblePositionTemplate<Strategy> pos =
598 createVisiblePosition(m_start, m_affinity); 588 createVisiblePosition(passedStart);
599 if (isStartOfLine(pos) && isEndOfEditableOrNonEditableContent(pos)) 589 if (isStartOfLine(pos) && isEndOfEditableOrNonEditableContent(pos))
600 pos = previousPositionOf(pos); 590 return startOfParagraph(previousPositionOf(pos)).deepEquivalent();
601 m_start = startOfParagraph(pos).deepEquivalent(); 591 return startOfParagraph(pos).deepEquivalent();
602 break;
603 } 592 }
604 case DocumentBoundary: 593 case DocumentBoundary:
605 m_start = startOfDocument(createVisiblePosition(m_start, m_affinity)) 594 return startOfDocument(createVisiblePosition(passedStart))
606 .deepEquivalent(); 595 .deepEquivalent();
607 break;
608 case ParagraphBoundary: 596 case ParagraphBoundary:
609 m_start = startOfParagraph(createVisiblePosition(m_start, m_affinity)) 597 return startOfParagraph(createVisiblePosition(passedStart))
610 .deepEquivalent(); 598 .deepEquivalent();
611 break;
612 case SentenceBoundary: 599 case SentenceBoundary:
613 m_start = startOfSentence(createVisiblePosition(m_start, m_affinity)) 600 return startOfSentence(createVisiblePosition(passedStart))
614 .deepEquivalent(); 601 .deepEquivalent();
615 break;
616 } 602 }
617 603
618 // Make sure we do not have a Null position. 604 NOTREACHED();
619 if (m_start.isNull()) 605 return passedStart.position();
620 m_start = m_baseIsFirst ? m_base : m_extent;
621 } 606 }
622 607
623 template <typename Strategy> 608 template <typename Strategy>
624 void VisibleSelectionTemplate<Strategy>::setEndRespectingGranularity( 609 static PositionTemplate<Strategy> computeEndRespectingGranularity(
610 const PositionTemplate<Strategy>& start,
611 const PositionWithAffinityTemplate<Strategy>& passedEnd,
625 TextGranularity granularity) { 612 TextGranularity granularity) {
626 DCHECK(m_base.isNotNull()); 613 DCHECK(passedEnd.isNotNull());
627 DCHECK(m_extent.isNotNull());
628
629 m_end = m_baseIsFirst ? m_extent : m_base;
630 614
631 switch (granularity) { 615 switch (granularity) {
632 case CharacterGranularity: 616 case CharacterGranularity:
633 // Don't do any expansion. 617 // Don't do any expansion.
634 break; 618 return passedEnd.position();
635 case WordGranularity: { 619 case WordGranularity: {
636 // General case: Select the word the caret is positioned inside of. 620 // General case: Select the word the caret is positioned inside of.
637 // If the caret is on the word boundary, select the word according to 621 // If the caret is on the word boundary, select the word according to
638 // |wordSide|. 622 // |wordSide|.
639 // Edge case: If the caret is after the last word in a soft-wrapped line 623 // Edge case: If the caret is after the last word in a soft-wrapped line
640 // or the last word in the document, select that last word 624 // or the last word in the document, select that last word
641 // (|LeftWordIfOnBoundary|). 625 // (|LeftWordIfOnBoundary|).
642 // Edge case: If the caret is after the last word in a paragraph, select 626 // Edge case: If the caret is after the last word in a paragraph, select
643 // from the the end of the last word to the line break (also 627 // from the the end of the last word to the line break (also
644 // |RightWordIfOnBoundary|); 628 // |RightWordIfOnBoundary|);
645 const VisiblePositionTemplate<Strategy> originalEnd = 629 const VisiblePositionTemplate<Strategy> originalEnd =
646 createVisiblePosition(m_end, m_affinity); 630 createVisiblePosition(passedEnd);
647 EWordSide side = RightWordIfOnBoundary; 631 EWordSide side = RightWordIfOnBoundary;
648 if (isEndOfEditableOrNonEditableContent(originalEnd) || 632 if (isEndOfEditableOrNonEditableContent(originalEnd) ||
649 (isEndOfLine(originalEnd) && !isStartOfLine(originalEnd) && 633 (isEndOfLine(originalEnd) && !isStartOfLine(originalEnd) &&
650 !isEndOfParagraph(originalEnd))) 634 !isEndOfParagraph(originalEnd)))
651 side = LeftWordIfOnBoundary; 635 side = LeftWordIfOnBoundary;
652 636
653 const VisiblePositionTemplate<Strategy> wordEnd = 637 const VisiblePositionTemplate<Strategy> wordEnd =
654 endOfWord(originalEnd, side); 638 endOfWord(originalEnd, side);
655 VisiblePositionTemplate<Strategy> end = wordEnd; 639 if (!isEndOfParagraph(originalEnd))
640 return wordEnd.deepEquivalent();
641 if (isEmptyTableCell(start.anchorNode()))
642 return wordEnd.deepEquivalent();
656 643
657 if (isEndOfParagraph(originalEnd) && 644 // Select the paragraph break (the space from the end of a paragraph
658 !isEmptyTableCell(m_start.anchorNode())) { 645 // to the start of the next one) to match TextEdit.
659 // Select the paragraph break (the space from the end of a paragraph 646 const VisiblePositionTemplate<Strategy> end = nextPositionOf(wordEnd);
660 // to the start of the next one) to match TextEdit. 647 Element* const table = tableElementJustBefore(end);
661 end = nextPositionOf(wordEnd); 648 if (!table) {
662
663 if (Element* table = tableElementJustBefore(end)) {
664 // The paragraph break after the last paragraph in the last cell
665 // of a block table ends at the start of the paragraph after the
666 // table.
667 if (isEnclosingBlock(table))
668 end = nextPositionOf(end, CannotCrossEditingBoundary);
669 else
670 end = wordEnd;
671 }
672
673 if (end.isNull()) 649 if (end.isNull())
674 end = wordEnd; 650 return wordEnd.deepEquivalent();
651 return end.deepEquivalent();
675 } 652 }
676 653
677 m_end = end.deepEquivalent(); 654 if (!isEnclosingBlock(table))
678 break; 655 return wordEnd.deepEquivalent();
656
657 // The paragraph break after the last paragraph in the last cell
658 // of a block table ends at the start of the paragraph after the
659 // table.
660 const VisiblePositionTemplate<Strategy> next =
661 nextPositionOf(end, CannotCrossEditingBoundary);
662 if (next.isNull())
663 return wordEnd.deepEquivalent();
664 return next.deepEquivalent();
679 } 665 }
680 case SentenceGranularity: { 666 case SentenceGranularity:
681 m_end = endOfSentence(createVisiblePosition(m_end, m_affinity)) 667 return endOfSentence(createVisiblePosition(passedEnd)).deepEquivalent();
682 .deepEquivalent();
683 break;
684 }
685 case LineGranularity: { 668 case LineGranularity: {
686 VisiblePositionTemplate<Strategy> end = 669 const VisiblePositionTemplate<Strategy> end =
687 endOfLine(createVisiblePosition(m_end, m_affinity)); 670 endOfLine(createVisiblePosition(passedEnd));
671 if (!isEndOfParagraph(end))
672 return end.deepEquivalent();
688 // If the end of this line is at the end of a paragraph, include the 673 // If the end of this line is at the end of a paragraph, include the
689 // space after the end of the line in the selection. 674 // space after the end of the line in the selection.
690 if (isEndOfParagraph(end)) { 675 const VisiblePositionTemplate<Strategy> next = nextPositionOf(end);
691 VisiblePositionTemplate<Strategy> next = nextPositionOf(end); 676 if (next.isNull())
692 if (next.isNotNull()) 677 return end.deepEquivalent();
693 end = next; 678 return next.deepEquivalent();
694 }
695 m_end = end.deepEquivalent();
696 break;
697 } 679 }
698 case LineBoundary: 680 case LineBoundary:
699 m_end = 681 return endOfLine(createVisiblePosition(passedEnd)).deepEquivalent();
700 endOfLine(createVisiblePosition(m_end, m_affinity)).deepEquivalent();
701 break;
702 case ParagraphGranularity: { 682 case ParagraphGranularity: {
703 const VisiblePositionTemplate<Strategy> visibleParagraphEnd = 683 const VisiblePositionTemplate<Strategy> visibleParagraphEnd =
704 endOfParagraph(createVisiblePosition(m_end, m_affinity)); 684 endOfParagraph(createVisiblePosition(passedEnd));
705 685
706 // Include the "paragraph break" (the space from the end of this 686 // Include the "paragraph break" (the space from the end of this
707 // paragraph to the start of the next one) in the selection. 687 // paragraph to the start of the next one) in the selection.
708 VisiblePositionTemplate<Strategy> end = 688 const VisiblePositionTemplate<Strategy> end =
709 nextPositionOf(visibleParagraphEnd); 689 nextPositionOf(visibleParagraphEnd);
710 690
711 if (Element* table = tableElementJustBefore(end)) { 691 Element* const table = tableElementJustBefore(end);
712 // The paragraph break after the last paragraph in the last cell of 692 if (!table) {
713 // a block table ends at the start of the paragraph after the table, 693 if (end.isNull())
714 // not at the position just after the table. 694 return visibleParagraphEnd.deepEquivalent();
715 if (isEnclosingBlock(table)) { 695 return end.deepEquivalent();
716 end = nextPositionOf(end, CannotCrossEditingBoundary);
717 } else {
718 // There is no parargraph break after the last paragraph in the
719 // last cell of an inline table.
720 end = visibleParagraphEnd;
721 }
722 } 696 }
723 697
724 if (end.isNull()) 698 if (!isEnclosingBlock(table)) {
725 end = visibleParagraphEnd; 699 // There is no paragraph break after the last paragraph in the
700 // last cell of an inline table.
701 return visibleParagraphEnd.deepEquivalent();
702 }
726 703
727 m_end = end.deepEquivalent(); 704 // The paragraph break after the last paragraph in the last cell of
728 break; 705 // a block table ends at the start of the paragraph after the table,
706 // not at the position just after the table.
707 const VisiblePositionTemplate<Strategy> next =
708 nextPositionOf(end, CannotCrossEditingBoundary);
709 if (next.isNull())
710 return visibleParagraphEnd.deepEquivalent();
711 return next.deepEquivalent();
729 } 712 }
730 case DocumentBoundary: 713 case DocumentBoundary:
731 m_end = endOfDocument(createVisiblePosition(m_end, m_affinity)) 714 return endOfDocument(createVisiblePosition(passedEnd)).deepEquivalent();
732 .deepEquivalent();
733 break;
734 case ParagraphBoundary: 715 case ParagraphBoundary:
735 m_end = endOfParagraph(createVisiblePosition(m_end, m_affinity)) 716 return endOfParagraph(createVisiblePosition(passedEnd)).deepEquivalent();
736 .deepEquivalent();
737 break;
738 case SentenceBoundary: 717 case SentenceBoundary:
739 m_end = endOfSentence(createVisiblePosition(m_end, m_affinity)) 718 return endOfSentence(createVisiblePosition(passedEnd)).deepEquivalent();
740 .deepEquivalent();
741 break;
742 } 719 }
743 720 NOTREACHED();
744 // Make sure we do not have a Null position. 721 return passedEnd.position();
745 if (m_end.isNull())
746 m_end = m_baseIsFirst ? m_extent : m_base;
747 } 722 }
748 723
749 template <typename Strategy> 724 template <typename Strategy>
750 void VisibleSelectionTemplate<Strategy>::updateSelectionType() { 725 void VisibleSelectionTemplate<Strategy>::updateSelectionType() {
751 m_selectionType = computeSelectionType(m_start, m_end); 726 m_selectionType = computeSelectionType(m_start, m_end);
752 727
753 // Affinity only makes sense for a caret 728 // Affinity only makes sense for a caret
754 if (m_selectionType != CaretSelection) 729 if (m_selectionType != CaretSelection)
755 m_affinity = TextAffinity::Downstream; 730 m_affinity = TextAffinity::Downstream;
756 } 731 }
757 732
758 template <typename Strategy> 733 template <typename Strategy>
759 void VisibleSelectionTemplate<Strategy>::validate(TextGranularity granularity) { 734 void VisibleSelectionTemplate<Strategy>::validate(TextGranularity granularity) {
760 DCHECK(!needsLayoutTreeUpdate(m_base)); 735 DCHECK(!needsLayoutTreeUpdate(m_base));
761 DCHECK(!needsLayoutTreeUpdate(m_extent)); 736 DCHECK(!needsLayoutTreeUpdate(m_extent));
762 // TODO(xiaochengh): Add a DocumentLifecycle::DisallowTransitionScope here. 737 // TODO(xiaochengh): Add a DocumentLifecycle::DisallowTransitionScope here.
763 738
764 m_granularity = granularity; 739 m_granularity = granularity;
765 m_hasTrailingWhitespace = false; 740 m_hasTrailingWhitespace = false;
766 setBaseAndExtentToDeepEquivalents(); 741 setBaseAndExtentToDeepEquivalents();
767 if (m_base.isNull() || m_extent.isNull()) { 742 if (m_base.isNull() || m_extent.isNull()) {
768 m_base = m_extent = m_start = m_end = PositionTemplate<Strategy>(); 743 m_base = m_extent = m_start = m_end = PositionTemplate<Strategy>();
769 updateSelectionType(); 744 updateSelectionType();
770 return; 745 return;
771 } 746 }
772 747
773 m_start = m_baseIsFirst ? m_base : m_extent; 748 const PositionTemplate<Strategy> start = m_baseIsFirst ? m_base : m_extent;
774 m_end = m_baseIsFirst ? m_extent : m_base; 749 const PositionTemplate<Strategy> newStart = computeStartRespectingGranularity(
775 setStartRespectingGranularity(granularity); 750 PositionWithAffinityTemplate<Strategy>(start, m_affinity), granularity);
776 DCHECK(m_start.isNotNull()); 751 m_start = newStart.isNotNull() ? newStart : start;
777 setEndRespectingGranularity(granularity); 752
778 DCHECK(m_end.isNotNull()); 753 const PositionTemplate<Strategy> end = m_baseIsFirst ? m_extent : m_base;
754 const PositionTemplate<Strategy> newEnd = computeEndRespectingGranularity(
755 m_start, PositionWithAffinityTemplate<Strategy>(end, m_affinity),
756 granularity);
757 m_end = newEnd.isNotNull() ? newEnd : end;
758
779 adjustSelectionToAvoidCrossingShadowBoundaries(); 759 adjustSelectionToAvoidCrossingShadowBoundaries();
780 adjustSelectionToAvoidCrossingEditingBoundaries(); 760 adjustSelectionToAvoidCrossingEditingBoundaries();
781 updateSelectionType(); 761 updateSelectionType();
782 762
783 if (getSelectionType() == RangeSelection) { 763 if (getSelectionType() == RangeSelection) {
784 // "Constrain" the selection to be the smallest equivalent range of 764 // "Constrain" the selection to be the smallest equivalent range of
785 // nodes. This is a somewhat arbitrary choice, but experience shows that 765 // nodes. This is a somewhat arbitrary choice, but experience shows that
786 // it is useful to make to make the selection "canonical" (if only for 766 // it is useful to make to make the selection "canonical" (if only for
787 // purposes of comparing selections). This is an ideal point of the code 767 // purposes of comparing selections). This is an ideal point of the code
788 // to do this operation, since all selection changes that result in a 768 // to do this operation, since all selection changes that result in a
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after
1131 1111
1132 void showTree(const blink::VisibleSelectionInFlatTree& sel) { 1112 void showTree(const blink::VisibleSelectionInFlatTree& sel) {
1133 sel.showTreeForThis(); 1113 sel.showTreeForThis();
1134 } 1114 }
1135 1115
1136 void showTree(const blink::VisibleSelectionInFlatTree* sel) { 1116 void showTree(const blink::VisibleSelectionInFlatTree* sel) {
1137 if (sel) 1117 if (sel)
1138 sel->showTreeForThis(); 1118 sel->showTreeForThis();
1139 } 1119 }
1140 #endif 1120 #endif
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/editing/VisibleSelection.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698