Chromium Code Reviews| Index: Source/core/editing/FrameSelection.cpp |
| diff --git a/Source/core/editing/FrameSelection.cpp b/Source/core/editing/FrameSelection.cpp |
| index 8fbfe7e993caa533506be2cf5dc1eb312796dfc9..d5e77c92fa92b54ee095c724a822989f51b00ede 100644 |
| --- a/Source/core/editing/FrameSelection.cpp |
| +++ b/Source/core/editing/FrameSelection.cpp |
| @@ -92,6 +92,126 @@ static inline bool shouldAlwaysUseDirectionalSelection(LocalFrame* frame) |
| return !frame || frame->editor().behavior().shouldConsiderSelectionAsDirectional(); |
| } |
| +class GranularityStrategy { |
| +public: |
| + virtual ~GranularityStrategy() { }; |
| + virtual void Clear(); |
| + // Returns the selection extent based on the strategy. |
| + virtual VisiblePosition moveRangeSelectionExtent(const VisiblePosition&, FrameSelection*); |
| +protected: |
| + GranularityStrategy() { }; |
| +}; |
| + |
| +class DefaultGranularityStrategy : public GranularityStrategy { |
| +public: |
| + DefaultGranularityStrategy() { }; |
| + ~DefaultGranularityStrategy() override { }; |
| + |
| + void Clear() override { }; |
| + VisiblePosition moveRangeSelectionExtent(const VisiblePosition&, FrameSelection*) override |
| + { |
| + return extentPosition; |
| + }; |
| +}; |
| + |
| +// Uses word granularity when selection is expanding. Uses character granularity when selection is shrinking. |
| +class DirectionGranularityStrategy : public GranularityStrategy { |
| +public: |
| + DirectionGranularityStrategy(); |
| + ~DirectionGranularityStrategy() override { }; |
| + |
| + void Clear() override; |
| + VisiblePosition moveRangeSelectionExtent(const VisiblePosition&, FrameSelection*) override; |
| +private: |
| + // Returns the next word boundary starting from |pos|. |direction| specifies the direction |
| + // in which to search for the next bound. nextIfOnBound controls whether |pos| or the next boundary |
| + // is returned when |pos| is located exactly on word boundary. |
| + VisiblePosition nextWordBound(const VisiblePosition& /*pos*/, int /*direction*/, bool /*nextIfOnBound*/); |
| + |
| + // Current selection granularity being used |
| + TextGranularity m_granularity; |
| + // If the selection extent is extended beyond this threshold - the granularity will be changed to WordGranularity |
| + VisiblePosition m_wordBoundary; |
| + // Cached extentPosition passed in moveRangeSelectionExtent |
| + VisiblePosition m_extentPosition; |
| +}; |
| + |
| +DirectionGranularityStrategy::DirectionGranularityStrategy() |
| + : m_granularity(CharacterGranularity) { } |
| + |
| +void DirectionGranularityStrategy::Clear() |
| +{ |
| + m_wordBoundary.clear(); |
| + m_extentPosition.clear(); |
| + m_granularity = CharacterGranularity; |
| +} |
| + |
| +VisiblePosition DirectionGranularityStrategy::nextWordBound( |
| + const VisiblePosition& pos, |
| + int direction, |
| + bool nextIfOnBound) |
| +{ |
| + return direction > 0 ? endOfWord(pos, nextIfOnBound ? RightWordIfOnBoundary : LeftWordIfOnBoundary) |
| + : startOfWord(pos, nextIfOnBound ? LeftWordIfOnBoundary : RightWordIfOnBoundary); |
| +} |
| + |
| +VisiblePosition DirectionGranularityStrategy::moveRangeSelectionExtent(const VisiblePosition& extentPosition, FrameSelection* fs) |
| +{ |
| + fprintf(stderr, "DirectionGranularityStrategy::moveRangeSelectionExtent, extentPosition offset=%d, characterBefore=%c, characterAfter=%c\n", |
| + extentPosition.deepEquivalent().offsetInContainerNode(), extentPosition.characterBefore(), extentPosition.characterAfter()); |
| + |
| + const VisibleSelection& oldSel = fs->selection(); |
| + const VisiblePosition& base = oldSel.isBaseFirst() ? oldSel.visibleStart() : oldSel.visibleEnd(); |
|
yosin_UTC9
2015/03/10 01:37:03
nit: Just use |visibleBase()|.
|
| + const VisiblePosition& oldExtent = oldSel.isBaseFirst() ? oldSel.visibleEnd() : oldSel.visibleStart(); |
|
yosin_UTC9
2015/03/10 01:37:03
nit: Just use |visibleExtent()|.
|
| + |
| + int extentBaseOrder = comparePositions(extentPosition, base); |
| + int oldExtentBaseOrder = comparePositions(oldExtent, base); |
| + ASSERT(extentBaseOrder != 0); |
| + |
| + bool extentBaseOrderChanged = extentBaseOrder * oldExtentBaseOrder < 0; |
| + |
| + if (m_wordBoundary.isNull()) { |
| + fprintf(stderr, "m_ThresholdEnd.isNull()\n"); |
| + ASSERT(m_extentPosition.isNull()); |
| + ASSERT(m_granularity == CharacterGranularity); |
| + m_wordBoundary = nextWordBound(oldExtent, extentBaseOrder, false); |
| + m_extentPosition = extentPosition; |
| + } |
| + if (extentBaseOrderChanged) { |
| + fprintf(stderr, "extentBaseOrderSwitched, old m_wordBoundary=%d\n", |
| + m_wordBoundary.deepEquivalent().offsetInContainerNode()); |
| + m_wordBoundary = nextWordBound(base, extentBaseOrder, true); |
| + m_granularity = CharacterGranularity; |
| + fprintf(stderr, "new m_wordBoundary=%d\n", |
| + m_wordBoundary.deepEquivalent().offsetInContainerNode()); |
| + } |
| + bool beyondWordBoundary = extentBaseOrder > 0 ? comparePositions(extentPosition, m_wordBoundary) > 0 |
| + : comparePositions(extentPosition, m_wordBoundary) < 0; |
| + fprintf(stderr, "m_wordBoundary=%d, beyondWordBoundary=%d, order=%d\n", |
| + m_wordBoundary.deepEquivalent().offsetInContainerNode(), beyondWordBoundary, extentBaseOrder); |
| + if (beyondWordBoundary) { |
| + if (m_granularity == CharacterGranularity) |
| + m_granularity = WordGranularity; |
| + // The value passed for |nextIfOnBound| doesn't matter here. |
| + m_wordBoundary = nextWordBound(extentPosition, extentBaseOrder, true); |
| + } else if (!extentBaseOrderChanged) { |
| + // If selection was shrunk - switch to character granularity |
| + if (extentBaseOrder * comparePositions(extentPosition, m_extentPosition) < 0) { |
| + m_granularity = CharacterGranularity; |
| + m_wordBoundary = nextWordBound(extentPosition, extentBaseOrder, true); |
| + } |
| + } |
| + m_extentPosition = extentPosition; |
| + |
| + VisiblePosition visibleExtent = extentPosition; |
| + if (m_granularity == WordGranularity) { |
| + fprintf(stderr, "m_extendGranularity == WordGranularity\n"); |
| + visibleExtent = nextWordBound(extentPosition, extentBaseOrder, false); |
| + } |
| + |
| + return visibleExtent; |
| +} |
| + |
| FrameSelection::FrameSelection(LocalFrame* frame) |
| : m_frame(frame) |
| , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation()) |
| @@ -106,6 +226,7 @@ FrameSelection::FrameSelection(LocalFrame* frame) |
| { |
| if (shouldAlwaysUseDirectionalSelection(m_frame)) |
| m_selection.setIsDirectional(true); |
| + m_granularityStrategy = adoptPtr(new DirectionGranularityStrategy()); |
| } |
| FrameSelection::~FrameSelection() |
| @@ -135,12 +256,14 @@ ContainerNode* FrameSelection::rootEditableElementOrTreeScopeRootNode() const |
| void FrameSelection::moveTo(const VisiblePosition &pos, EUserTriggered userTriggered, CursorAlignOnScroll align) |
| { |
| + fprintf(stderr, "FrameSelection::moveTo 1"); |
| SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered; |
| setSelection(VisibleSelection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity(), m_selection.isDirectional()), options, align); |
| } |
| void FrameSelection::moveTo(const VisiblePosition &base, const VisiblePosition &extent, EUserTriggered userTriggered) |
| { |
| + fprintf(stderr, "FrameSelection::moveTo 2"); |
| const bool selectionHasDirection = true; |
| SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered; |
| setSelection(VisibleSelection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity(), selectionHasDirection), options); |
| @@ -148,6 +271,7 @@ void FrameSelection::moveTo(const VisiblePosition &base, const VisiblePosition & |
| void FrameSelection::moveTo(const Position &pos, EAffinity affinity, EUserTriggered userTriggered) |
| { |
| + fprintf(stderr, "FrameSelection::moveTo 3"); |
| SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered; |
| setSelection(VisibleSelection(pos, affinity, m_selection.isDirectional()), options); |
| } |
| @@ -216,11 +340,14 @@ void FrameSelection::setNonDirectionalSelectionIfNeeded(const VisibleSelection& |
| if (m_selection == newSelection) |
| return; |
| + fprintf(stderr, "FrameSelection::setNonDirectionalSelectionIfNeeded"); |
| setSelection(newSelection, granularity); |
| } |
| void FrameSelection::setSelection(const VisibleSelection& newSelection, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity) |
| { |
| + if ((options & FrameSelection::ApplyStrategy) == 0) |
| + m_granularityStrategy->Clear(); |
| bool closeTyping = options & CloseTyping; |
| bool shouldClearTypingStyle = options & ClearTypingStyle; |
| EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); |
| @@ -479,6 +606,7 @@ void FrameSelection::updateSelectionIfNeeded(const Position& base, const Positio |
| newSelection.setWithoutValidation(start, end); |
| else |
| newSelection.setWithoutValidation(end, start); |
| + fprintf(stderr, "FrameSelection::updateSelectionIfNeeded"); |
| setSelection(newSelection, DoNotSetFocus); |
| } |
| @@ -946,6 +1074,7 @@ bool FrameSelection::modify(EAlteration alter, SelectionDirection direction, Tex |
| { |
| if (userTriggered == UserTriggered) { |
| OwnPtrWillBeRawPtr<FrameSelection> trialFrameSelection = FrameSelection::create(); |
| + fprintf(stderr, "FrameSelection::modify 4"); |
| trialFrameSelection->setSelection(m_selection); |
| trialFrameSelection->modify(alter, direction, granularity, NotUserTriggered); |
| @@ -1060,6 +1189,7 @@ bool FrameSelection::modify(EAlteration alter, unsigned verticalDistance, Vertic |
| if (userTriggered == UserTriggered) { |
| OwnPtrWillBeRawPtr<FrameSelection> trialFrameSelection = FrameSelection::create(); |
| + fprintf(stderr, "FrameSelection::modify 5"); |
| trialFrameSelection->setSelection(m_selection); |
| trialFrameSelection->modify(alter, verticalDistance, direction, NotUserTriggered); |
| } |
| @@ -1173,6 +1303,8 @@ LayoutUnit FrameSelection::lineDirectionPointForBlockDirectionNavigation(EPositi |
| void FrameSelection::clear() |
| { |
| m_granularity = CharacterGranularity; |
| + fprintf(stderr, "FrameSelection::clear"); |
| + m_granularityStrategy->Clear(); |
| setSelection(VisibleSelection()); |
| } |
| @@ -1186,6 +1318,7 @@ void FrameSelection::prepareForDestruction() |
| if (view) |
| view->clearSelection(); |
| + fprintf(stderr, "FrameSelection::prepareForDestruction"); |
| setSelection(VisibleSelection(), CloseTyping | ClearTypingStyle | DoNotUpdateAppearance); |
| m_previousCaretNode.clear(); |
| } |
| @@ -1209,12 +1342,14 @@ void FrameSelection::setEnd(const VisiblePosition &pos, EUserTriggered trigger) |
| void FrameSelection::setBase(const VisiblePosition &pos, EUserTriggered userTriggered) |
| { |
| const bool selectionHasDirection = true; |
| + fprintf(stderr, "FrameSelection::setBase"); |
| setSelection(VisibleSelection(pos.deepEquivalent(), m_selection.extent(), pos.affinity(), selectionHasDirection), CloseTyping | ClearTypingStyle | userTriggered); |
| } |
| void FrameSelection::setExtent(const VisiblePosition &pos, EUserTriggered userTriggered) |
| { |
| const bool selectionHasDirection = true; |
| + fprintf(stderr, "FrameSelection::setExtent"); |
| setSelection(VisibleSelection(m_selection.base(), pos.deepEquivalent(), pos.affinity(), selectionHasDirection), CloseTyping | ClearTypingStyle | userTriggered); |
| } |
| @@ -1367,6 +1502,7 @@ void FrameSelection::selectFrameElementInParentIfFullySelected() |
| // Focus on the parent frame, and then select from before this element to after. |
| VisibleSelection newSelection(beforeOwnerElement, afterOwnerElement); |
| page->focusController().setFocusedFrame(parent); |
| + fprintf(stderr, "FrameSelection::selectFrameElementInParentIfFullySelected"); |
| toLocalFrame(parent)->selection().setSelection(newSelection); |
| } |
| @@ -1406,6 +1542,7 @@ void FrameSelection::selectAll() |
| return; |
| VisibleSelection newSelection(VisibleSelection::selectionFromContentsOfNode(root.get())); |
| + fprintf(stderr, "FrameSelection::selectAll"); |
| setSelection(newSelection); |
| selectFrameElementInParentIfFullySelected(); |
| notifyRendererOfSelectionChange(UserTriggered); |
| @@ -1777,6 +1914,7 @@ void FrameSelection::revealSelection(const ScrollAlignment& alignment, RevealExt |
| void FrameSelection::setSelectionFromNone() |
| { |
| + fprintf(stderr, "FrameSelection::setSelectionFromNone"); |
| // Put a caret inside the body if the entire frame is editable (either the |
| // entire WebView is editable or designMode is on for this document). |
| @@ -1912,31 +2050,26 @@ bool FrameSelection::selectWordAroundPosition(const VisiblePosition& position) |
| return false; |
| } |
| -void FrameSelection::moveRangeSelectionExtent(const VisiblePosition& extentPosition, TextGranularity granularity) |
| +void FrameSelection::moveRangeSelectionExtent(const VisiblePosition& extentPosition) |
| { |
| - if (isNone()) |
| - return; |
| - |
| - const VisiblePosition basePosition = m_selection.isBaseFirst() ? |
| + const VisiblePosition base = m_selection.isBaseFirst() ? |
|
yosin_UTC9
2015/03/10 01:37:03
nit: Just use |visibleBase()|.
|
| m_selection.visibleStart() : m_selection.visibleEnd(); |
| - int order = comparePositions(basePosition, extentPosition); |
| - if (!order) |
| + if (isNone() || comparePositions(base, extentPosition) == 0) |
| return; |
| - // Currently we support only CharaterGranularity and WordGranurarity. |
| - // If |granurarity| is not of them, we fall back it to |
| - // CharacterGranularity. |
| - VisiblePosition newExtentPosition = extentPosition; |
| - if (granularity == WordGranularity) |
| - newExtentPosition = order < 0 ? endOfWord(extentPosition) : startOfWord(extentPosition); |
| - |
| - VisibleSelection newSelection = VisibleSelection(basePosition, newExtentPosition); |
| - setSelection(newSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | UserTriggered, FrameSelection::AlignCursorOnScrollIfNeeded, granularity); |
| + VisiblePosition newExtentPosition = m_granularityStrategy->moveRangeSelectionExtent(extentPosition, this); |
| + VisibleSelection newSelection(base, newExtentPosition); |
| + setSelection( |
| + newSelection, |
| + FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | FrameSelection::ApplyStrategy | UserTriggered, |
| + FrameSelection::AlignCursorOnScrollIfNeeded, |
| + CharacterGranularity); |
| } |
| void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition, const VisiblePosition& extentPosition, TextGranularity granularity) |
| { |
| + fprintf(stderr, "moveRangeSelection"); |
| VisibleSelection newSelection(basePosition, extentPosition); |
| newSelection.expandUsingGranularity(granularity); |