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

Unified Diff: Source/core/editing/FrameSelection.cpp

Issue 988023005: Implementing directional selection strategy in Blink. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/editing/FrameSelection.h ('k') | Source/core/editing/FrameSelectionTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « Source/core/editing/FrameSelection.h ('k') | Source/core/editing/FrameSelectionTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698