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

Side by Side Diff: Source/core/editing/GranularityStrategy.cpp

Issue 1123563003: Improving direction-based selection strategy. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Removing unused method. Created 5 years, 7 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "config.h" 5 #include "config.h"
6 #include "core/editing/GranularityStrategy.h" 6 #include "core/editing/GranularityStrategy.h"
7 7
8 #include "core/editing/FrameSelection.h"
8 #include "core/editing/htmlediting.h" 9 #include "core/editing/htmlediting.h"
9 10
10 namespace blink { 11 namespace blink {
11 12
12 GranularityStrategy::GranularityStrategy() { } 13 GranularityStrategy::GranularityStrategy() { }
13 14
14 GranularityStrategy::~GranularityStrategy() { } 15 GranularityStrategy::~GranularityStrategy() { }
15 16
16 CharacterGranularityStrategy::CharacterGranularityStrategy() { } 17 CharacterGranularityStrategy::CharacterGranularityStrategy() { }
17 18
18 CharacterGranularityStrategy::~CharacterGranularityStrategy() { } 19 CharacterGranularityStrategy::~CharacterGranularityStrategy() { }
19 20
20 SelectionStrategy CharacterGranularityStrategy::GetType() const 21 SelectionStrategy CharacterGranularityStrategy::GetType() const
21 { 22 {
22 return SelectionStrategy::Character; 23 return SelectionStrategy::Character;
23 } 24 }
24 25
25 void CharacterGranularityStrategy::Clear() { }; 26 void CharacterGranularityStrategy::Clear() { };
26 27
27 VisibleSelection CharacterGranularityStrategy::updateExtent(const VisiblePositio n& extentPosition, const VisibleSelection& selection) 28 VisibleSelection CharacterGranularityStrategy::updateExtent(const IntPoint& exte ntPoint, LocalFrame* frame)
28 { 29 {
30 const VisiblePosition& extentPosition = visiblePositionForContentsPoint(exte ntPoint, frame);
31 const VisibleSelection& selection = frame->selection().selection();
32 if (selection.visibleBase() == extentPosition)
33 return selection;
29 return VisibleSelection(selection.visibleBase(), extentPosition); 34 return VisibleSelection(selection.visibleBase(), extentPosition);
30 } 35 }
31 36
32 DirectionGranularityStrategy::DirectionGranularityStrategy() 37 DirectionGranularityStrategy::DirectionGranularityStrategy()
33 : m_granularity(CharacterGranularity) 38 : m_granularity(CharacterGranularity)
34 , m_lastMoveShrunkSelection(false) { } 39 , m_lastMoveShrunkSelection(false)
40 , m_offset(0)
41 , m_cleared(true) { }
35 42
36 DirectionGranularityStrategy::~DirectionGranularityStrategy() { } 43 DirectionGranularityStrategy::~DirectionGranularityStrategy() { }
37 44
38 SelectionStrategy DirectionGranularityStrategy::GetType() const 45 SelectionStrategy DirectionGranularityStrategy::GetType() const
39 { 46 {
40 return SelectionStrategy::Direction; 47 return SelectionStrategy::Direction;
41 } 48 }
42 49
43 void DirectionGranularityStrategy::Clear() 50 void DirectionGranularityStrategy::Clear()
44 { 51 {
52 m_cleared = true;
45 m_granularity = CharacterGranularity; 53 m_granularity = CharacterGranularity;
46 m_lastMoveShrunkSelection = false; 54 m_lastMoveShrunkSelection = false;
55 m_offset = 0;
56 m_extentPoint.zero();
47 } 57 }
48 58
59 bool DirectionGranularityStrategy::arePositionsInOrder(
60 const VisiblePosition& pos1,
61 const VisiblePosition& pos2,
62 int order)
63 {
64 int positionOrder = comparePositions(pos1, pos2);
65 if (order == 0)
66 return positionOrder == 0;
67 return order > 0 ? positionOrder > 0 : positionOrder < 0;
68 }
69
70
49 VisiblePosition DirectionGranularityStrategy::nextWordBound( 71 VisiblePosition DirectionGranularityStrategy::nextWordBound(
50 const VisiblePosition& pos, 72 const VisiblePosition& pos,
51 SearchDirection direction, 73 SearchDirection direction,
52 BoundAdjust wordBoundAdjust) 74 BoundAdjust wordBoundAdjust)
53 { 75 {
54 bool nextBoundIfOnBound = wordBoundAdjust == BoundAdjust::NextBoundIfOnBoun d; 76 bool nextBoundIfOnBound = wordBoundAdjust == BoundAdjust::NextBoundIfOnBoun d;
55 if (direction == SearchDirection::SearchForward) { 77 if (direction == SearchDirection::SearchForward) {
56 EWordSide wordSide = nextBoundIfOnBound ? RightWordIfOnBoundary : LeftWo rdIfOnBoundary; 78 EWordSide wordSide = nextBoundIfOnBound ? RightWordIfOnBoundary : LeftWo rdIfOnBoundary;
57 return endOfWord(pos, wordSide); 79 return endOfWord(pos, wordSide);
58 } 80 }
59 EWordSide wordSide = nextBoundIfOnBound ? LeftWordIfOnBoundary : RightWordIf OnBoundary; 81 EWordSide wordSide = nextBoundIfOnBound ? LeftWordIfOnBoundary : RightWordIf OnBoundary;
60 return startOfWord(pos, wordSide); 82 return startOfWord(pos, wordSide);
61 } 83 }
62 84
63 VisibleSelection DirectionGranularityStrategy::updateExtent(const VisiblePositio n& extentPosition, const VisibleSelection& selection) 85 VisibleSelection DirectionGranularityStrategy::updateExtent(const IntPoint& exte ntPoint, LocalFrame* frame)
64 { 86 {
65 if (extentPosition == selection.visibleExtent()) 87 const VisibleSelection& selection = frame->selection().selection();
88 // Initialize m_extentPoint if this is the first update after a clear.
89 if (m_cleared) {
90 VisiblePosition pos = selection.isBaseFirst() ? selection.visibleEnd() : selection.visibleStart();
91 m_extentPoint = IntPoint(pos.absoluteCaretBounds().x(), pos.absoluteCare tBounds().y());
92 m_cleared = false;
93 }
94
95 IntPoint oldOffsetExtentPoint(m_extentPoint.x() + m_offset, m_extentPoint.y( ));
96 VisiblePosition oldOffsetExtentPosition = visiblePositionForContentsPoint(ol dOffsetExtentPoint, frame);
97
98 // Apply the offset.
99 IntPoint offsetExtentPoint = extentPoint;
100 int dx = extentPoint.x() - m_extentPoint.x();
101 if (m_offset != 0) {
102 if (m_offset > 0 && dx > 0)
103 m_offset = std::max(0, m_offset - dx);
104 else if (m_offset < 0 && dx < 0)
105 m_offset = std::min(0, m_offset - dx);
106 offsetExtentPoint.move(m_offset, 0);
107 }
108 m_extentPoint = extentPoint;
109
110 VisiblePosition offsetExtentPosition = visiblePositionForContentsPoint(offse tExtentPoint, frame);
111
112 if (!inSameLine(offsetExtentPosition, oldOffsetExtentPosition)) {
113 m_offset = 0;
114 offsetExtentPoint = extentPoint;
115 offsetExtentPosition = visiblePositionForContentsPoint(extentPoint, fram e);
116 }
117
118 const VisiblePosition base = selection.visibleBase();
119 int extentBaseOrder = comparePositions(offsetExtentPosition, base);
120
121 // Do not allow selection and extent to be at the same position
122 if (extentBaseOrder == 0)
66 return selection; 123 return selection;
67 124
68 const VisiblePosition base = selection.visibleBase(); 125 int oldExtentBaseOrder = comparePositions(selection.visibleExtent(), base);
69 const VisiblePosition oldExtentWithGranularity = selection.isBaseFirst() ? s election.visibleEnd() : selection.visibleStart(); 126 bool extentBaseOrderSwitched = !arePositionsInOrder(offsetExtentPosition, ba se, oldExtentBaseOrder);
70
71 int extentBaseOrder = comparePositions(extentPosition, base);
72 int oldExtentBaseOrder = comparePositions(oldExtentWithGranularity, base);
73
74 bool extentBaseOrderSwitched = (extentBaseOrder > 0 && oldExtentBaseOrder < 0)
75 || (extentBaseOrder < 0 && oldExtentBaseOrder > 0);
76 127
77 // Determine the boundary of the 'current word', i.e. the boundary extending 128 // Determine the boundary of the 'current word', i.e. the boundary extending
78 // beyond which should change the granularity to WordGranularity. 129 // beyond which should change the granularity to WordGranularity.
79 // If the last move has shrunk the selection and is now exactly on the word 130 VisiblePosition currentWordBoundary;
80 // boundary - we need to take the next bound as the bound of the "current
81 // word".
82 VisiblePosition currentWordBoundary = nextWordBound(
83 oldExtentWithGranularity,
84 oldExtentBaseOrder > 0 ? SearchDirection::SearchForward : SearchDirectio n::SearchBackwards,
85 m_lastMoveShrunkSelection ? BoundAdjust::NextBoundIfOnBound : BoundAdjus t::CurrentPosIfOnBound);
86
87 bool thisMoveShrunkSelection = (extentBaseOrder > 0 && comparePositions(exte ntPosition, selection.visibleExtent()) < 0)
88 || (extentBaseOrder < 0 && comparePositions(extentPosition, selection.vi sibleExtent()) > 0);
89 // If the extent-base order was switched, then the selection is now
90 // expanding in a different direction than before. Therefore we need to
91 // calculate the boundary of the 'current word' in this new direction in
92 // order to be able to tell if the selection expanded beyond it.
93 if (extentBaseOrderSwitched) { 131 if (extentBaseOrderSwitched) {
132 // Special case.
133 // If the extent-base order was switched, then the selection is now
134 // expanding in a different direction than before. Therefore we
135 // calculate the current word boundary in this new direction and
136 // based on the |base| position.
94 currentWordBoundary = nextWordBound( 137 currentWordBoundary = nextWordBound(
95 base, 138 base,
96 extentBaseOrder > 0 ? SearchDirection::SearchForward : SearchDirecti on::SearchBackwards, 139 extentBaseOrder > 0 ? SearchDirection::SearchForward : SearchDirecti on::SearchBackwards,
97 BoundAdjust::NextBoundIfOnBound); 140 BoundAdjust::NextBoundIfOnBound);
98 m_granularity = CharacterGranularity; 141 m_granularity = CharacterGranularity;
99 // When the base/extent order switches it doesn't count as shrinking sel ection. 142 } else {
100 thisMoveShrunkSelection = false; 143 // Calculate the current word boundary based on |oldExtentWithGranularit y|.
144 // If the last move has shrunk the selection and is now exactly on the w ord
145 // boundary - we need to take the next bound as the bound of the current word.
146 currentWordBoundary = nextWordBound(
147 oldOffsetExtentPosition,
148 selection.isBaseFirst() ? SearchDirection::SearchForward : SearchDir ection::SearchBackwards,
149 m_lastMoveShrunkSelection ? BoundAdjust::NextBoundIfOnBound : BoundA djust::CurrentPosIfOnBound);
101 } 150 }
102 151
103 bool expandedBeyondWordBoundary; 152 bool expandedBeyondWordBoundary = arePositionsInOrder(offsetExtentPosition, currentWordBoundary, extentBaseOrder);
104 if (extentBaseOrder > 0) 153
105 expandedBeyondWordBoundary = comparePositions(extentPosition, currentWor dBoundary) > 0; 154 // The selection is shrunk if the extent changes position to be closer to
106 else 155 // the base, and the extent/base order wasn't switched.
107 expandedBeyondWordBoundary = comparePositions(extentPosition, currentWor dBoundary) < 0; 156 bool thisMoveShrunkSelection =
108 if (expandedBeyondWordBoundary) { 157 !extentBaseOrderSwitched
158 && oldOffsetExtentPosition != offsetExtentPosition
159 && arePositionsInOrder(oldOffsetExtentPosition, offsetExtentPosition, ex tentBaseOrder);
160
161 if (expandedBeyondWordBoundary)
109 m_granularity = WordGranularity; 162 m_granularity = WordGranularity;
110 } else if (thisMoveShrunkSelection) { 163 else if (thisMoveShrunkSelection)
111 m_granularity = CharacterGranularity; 164 m_granularity = CharacterGranularity;
112 m_lastMoveShrunkSelection = true; 165
166 VisiblePosition newSelectionExtent = offsetExtentPosition;
167 if (m_granularity == WordGranularity) {
168 // Determine the bounds of the word where the extent is located.
169 // Set the selection extent to one of the two bounds depending on
170 // whether the extent is passed the middle of the word.
171 VisiblePosition boundBeforeExtent = nextWordBound(offsetExtentPosition, SearchDirection::SearchBackwards, BoundAdjust::CurrentPosIfOnBound);
172 VisiblePosition boundAfterExtent = nextWordBound(offsetExtentPosition, S earchDirection::SearchForward, BoundAdjust::CurrentPosIfOnBound);
173 int xMiddleBetweenBounds = (boundAfterExtent.absoluteCaretBounds().x() + boundBeforeExtent.absoluteCaretBounds().x()) / 2;
174 bool extentBeforeMiddle = offsetExtentPoint.x() < xMiddleBetweenBounds;
175
176 newSelectionExtent = extentBeforeMiddle ? boundBeforeExtent : boundAfter Extent;
177 // Update the offset if needed.
178 if (!inSameLine(newSelectionExtent, selection.visibleExtent()))
179 m_offset = 0;
180 else if ((extentBaseOrder > 0 && !extentBeforeMiddle) || (extentBaseOrde r < 0 && extentBeforeMiddle))
181 m_offset = newSelectionExtent.absoluteCaretBounds().x() - extentPoin t.x();
113 } 182 }
114 183
115 m_lastMoveShrunkSelection = thisMoveShrunkSelection; 184 // Only update m_lastMoveShrunkSelection if the selection actually changed
185 // as a result of this move.
186 if (newSelectionExtent != selection.visibleExtent())
187 m_lastMoveShrunkSelection = thisMoveShrunkSelection;
188
116 VisibleSelection newSelection = selection; 189 VisibleSelection newSelection = selection;
117 newSelection.setExtent(extentPosition); 190 newSelection.setExtent(newSelectionExtent);
118 if (m_granularity == WordGranularity) {
119 if (extentBaseOrder > 0)
120 newSelection.setEndRespectingGranularity(m_granularity, LeftWordIfOn Boundary);
121 else
122 newSelection.setStartRespectingGranularity(m_granularity, RightWordI fOnBoundary);
123 }
124
125 return newSelection; 191 return newSelection;
126 } 192 }
127 193
128 } // namespace blink 194 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698