OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2008, 2009, 2010 Apple 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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
86 static inline LayoutUnit NoXPosForVerticalArrowNavigation() | 86 static inline LayoutUnit NoXPosForVerticalArrowNavigation() |
87 { | 87 { |
88 return LayoutUnit::min(); | 88 return LayoutUnit::min(); |
89 } | 89 } |
90 | 90 |
91 static inline bool shouldAlwaysUseDirectionalSelection(LocalFrame* frame) | 91 static inline bool shouldAlwaysUseDirectionalSelection(LocalFrame* frame) |
92 { | 92 { |
93 return !frame || frame->editor().behavior().shouldConsiderSelectionAsDirecti onal(); | 93 return !frame || frame->editor().behavior().shouldConsiderSelectionAsDirecti onal(); |
94 } | 94 } |
95 | 95 |
96 class GranularityStrategy { | |
97 public: | |
98 virtual ~GranularityStrategy() { }; | |
99 virtual void Clear(); | |
100 | |
101 // Calculates and returns the new selection based on the updated user select ion extent |extentPosition| and the granularity strategy. | |
102 virtual VisibleSelection updateExtent(const VisiblePosition& extentPosition, const VisibleSelection&); | |
103 protected: | |
104 GranularityStrategy() { }; | |
105 }; | |
106 | |
107 class DefaultGranularityStrategy : public GranularityStrategy { | |
108 public: | |
109 DefaultGranularityStrategy() { }; | |
110 ~DefaultGranularityStrategy() override { }; | |
111 | |
112 void Clear() override { }; | |
113 VisibleSelection updateExtent(const VisiblePosition& extentPosition, const V isibleSelection& selection) override | |
114 { | |
115 return VisibleSelection(selection.visibleBase(), extentPosition); | |
116 }; | |
117 }; | |
118 | |
119 // "Expand by word, shrink by character" selection strategy. | |
120 // Uses character granularity when selection is shrinking. If the selection is e xpanding, | |
121 // granularity doesn't change until a word boundary is passed, after which the g ranularity | |
122 // switches to "word". | |
123 class DirectionGranularityStrategy : public GranularityStrategy { | |
124 public: | |
125 DirectionGranularityStrategy(); | |
126 ~DirectionGranularityStrategy() override { }; | |
127 | |
128 void Clear() override; | |
129 VisibleSelection updateExtent(const VisiblePosition&, const VisibleSelection &) override; | |
130 private: | |
131 // Returns the next word boundary starting from |pos|. |direction| specifies the direction | |
132 // in which to search for the next bound. nextIfOnBound controls whether |po s| or the next boundary | |
133 // is returned when |pos| is located exactly on word boundary. | |
134 VisiblePosition nextWordBound(const VisiblePosition& /*pos*/, int /*directio n*/, bool /*nextIfOnBound*/); | |
yosin_UTC9
2015/04/16 04:11:26
nit: Could you use enum for |nextIfOnBound|? In Bl
yosin_UTC9
2015/04/16 04:11:26
nit: It is better to use |SelectionDirection|, def
mfomitchev1
2015/04/17 00:13:50
Done.
mfomitchev1
2015/04/17 00:13:51
I created a local ESearchDirection instead. Select
| |
135 | |
136 // Current selection granularity being used | |
137 TextGranularity m_granularity; | |
138 // Set to true if the selection was shrunk (without changing relative base/e xtent order) | |
139 // as a result of the most recent updateExtent call. | |
140 bool m_lastMoveShrunkSelection; | |
141 }; | |
142 | |
143 DirectionGranularityStrategy::DirectionGranularityStrategy() | |
144 : m_granularity(CharacterGranularity) | |
145 , m_lastMoveShrunkSelection(false) { } | |
146 | |
147 void DirectionGranularityStrategy::Clear() | |
148 { | |
149 m_granularity = CharacterGranularity; | |
150 m_lastMoveShrunkSelection = false; | |
151 } | |
152 | |
153 VisiblePosition DirectionGranularityStrategy::nextWordBound( | |
154 const VisiblePosition& pos, | |
155 int direction, | |
156 bool nextIfOnBound) | |
157 { | |
158 return direction > 0 ? endOfWord(pos, nextIfOnBound ? RightWordIfOnBoundary : LeftWordIfOnBoundary) | |
159 : startOfWord(pos, nextIfOnBound ? LeftWordIfOnBoundary : RightWordIfOnB oundary); | |
160 } | |
161 | |
162 VisibleSelection DirectionGranularityStrategy::updateExtent(const VisiblePositio n& extentPosition, const VisibleSelection& selection) | |
163 { | |
164 if (extentPosition == selection.visibleExtent()) | |
165 return selection; | |
166 | |
167 const VisiblePosition& base = selection.visibleBase(); | |
yosin_UTC9
2015/04/16 04:11:26
nit: It is better to use |VisiblePostion| as value
mfomitchev1
2015/04/17 00:13:51
Done.
| |
168 const VisiblePosition& oldExtentWithGranularity = selection.isBaseFirst() ? selection.visibleEnd() : selection.visibleStart(); | |
169 | |
170 int extentBaseOrder = comparePositions(extentPosition, base); | |
171 int oldExtentBaseOrder = comparePositions(oldExtentWithGranularity, base); | |
172 ASSERT(extentBaseOrder != 0); | |
yosin_UTC9
2015/04/16 04:11:26
I'm not sure this assertion is always satisfied.
mfomitchev1
2015/04/17 00:13:51
I think it is - we short-circuit in FrameSelection
| |
173 | |
174 bool extentBaseOrderSwitched = extentBaseOrder * oldExtentBaseOrder < 0; | |
yosin_UTC9
2015/04/16 04:11:26
This is too smart conditional expression. Could yo
mfomitchev1
2015/04/17 00:13:51
Done.
| |
175 | |
176 // Determine the boundary of the 'current word', i.e. the boundary extending beyond which | |
177 // should change the granularity to WordGranularity. | |
178 // If the last move has shrunk the selection and is now exactly on the word boundary - | |
179 // we need to take the next bound as the bound of the "current word". | |
180 VisiblePosition currentWordBoundary = | |
181 nextWordBound(oldExtentWithGranularity, oldExtentBaseOrder, m_lastMoveSh runkSelection); | |
182 | |
183 bool thisMoveShrunkSelection = extentBaseOrder * comparePositions(extentPosi tion, selection.visibleExtent()) < 0; | |
yosin_UTC9
2015/04/16 04:11:26
ditto as L174.
mfomitchev1
2015/04/17 00:13:50
Done.
| |
184 // If the extent-base order was switched, then the selection is now expandin g in a different | |
185 // direction than before. Therefore we need to calculate the boundary of the 'current word' | |
186 // in this new direction in order to be able to tell if the selection expand ed beyond it. | |
187 if (extentBaseOrderSwitched) { | |
188 currentWordBoundary = nextWordBound(base, extentBaseOrder, true); | |
189 m_granularity = CharacterGranularity; | |
190 // When the base/extent order switches it doesn't count as shrinking sel ection. | |
191 thisMoveShrunkSelection = false; | |
192 } | |
193 | |
194 bool expandedBeyondWordBoundary = extentBaseOrder > 0 ? comparePositions(ext entPosition, currentWordBoundary) > 0 | |
yosin_UTC9
2015/04/16 04:11:26
This conditional expression looks complex. It is b
mfomitchev1
2015/04/17 00:13:51
Done.
| |
195 : comparePositions(extentPosition, currentWordBoundary) < 0; | |
196 if (expandedBeyondWordBoundary) { | |
197 m_granularity = WordGranularity; | |
198 } else if (thisMoveShrunkSelection) { | |
199 m_granularity = CharacterGranularity; | |
200 m_lastMoveShrunkSelection = true; | |
201 } | |
202 | |
203 m_lastMoveShrunkSelection = thisMoveShrunkSelection; | |
204 VisibleSelection newSelection = selection; | |
205 newSelection.setExtent(extentPosition); | |
206 if (m_granularity == WordGranularity) { | |
207 if (extentBaseOrder > 0) | |
208 newSelection.setEndRespectingGranularity(m_granularity, LeftWordIfOn Boundary); | |
209 else | |
210 newSelection.setStartRespectingGranularity(m_granularity, RightWordI fOnBoundary); | |
211 } | |
212 | |
213 return newSelection; | |
214 } | |
215 | |
96 FrameSelection::FrameSelection(LocalFrame* frame) | 216 FrameSelection::FrameSelection(LocalFrame* frame) |
97 : m_frame(frame) | 217 : m_frame(frame) |
98 , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation()) | 218 , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation()) |
99 , m_observingVisibleSelection(false) | 219 , m_observingVisibleSelection(false) |
100 , m_granularity(CharacterGranularity) | 220 , m_granularity(CharacterGranularity) |
101 , m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired) | 221 , m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired) |
102 , m_caretRectDirty(true) | 222 , m_caretRectDirty(true) |
103 , m_shouldPaintCaret(true) | 223 , m_shouldPaintCaret(true) |
104 , m_isCaretBlinkingSuspended(false) | 224 , m_isCaretBlinkingSuspended(false) |
105 , m_focused(frame && frame->page() && frame->page()->focusController().focus edFrame() == frame) | 225 , m_focused(frame && frame->page() && frame->page()->focusController().focus edFrame() == frame) |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
215 | 335 |
216 newSelection.setIsDirectional(isDirectional); // Adjusting base and extent w ill make newSelection always directional | 336 newSelection.setIsDirectional(isDirectional); // Adjusting base and extent w ill make newSelection always directional |
217 if (m_selection == newSelection) | 337 if (m_selection == newSelection) |
218 return; | 338 return; |
219 | 339 |
220 setSelection(newSelection, granularity); | 340 setSelection(newSelection, granularity); |
221 } | 341 } |
222 | 342 |
223 void FrameSelection::setSelection(const VisibleSelection& newSelection, SetSelec tionOptions options, CursorAlignOnScroll align, TextGranularity granularity) | 343 void FrameSelection::setSelection(const VisibleSelection& newSelection, SetSelec tionOptions options, CursorAlignOnScroll align, TextGranularity granularity) |
224 { | 344 { |
345 if ((options & FrameSelection::DoNotClearStrategy) == 0) | |
346 granularityStrategy()->Clear(); | |
225 bool closeTyping = options & CloseTyping; | 347 bool closeTyping = options & CloseTyping; |
226 bool shouldClearTypingStyle = options & ClearTypingStyle; | 348 bool shouldClearTypingStyle = options & ClearTypingStyle; |
227 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); | 349 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); |
228 | 350 |
229 VisibleSelection s = validateSelection(newSelection); | 351 VisibleSelection s = validateSelection(newSelection); |
352 | |
230 if (shouldAlwaysUseDirectionalSelection(m_frame)) | 353 if (shouldAlwaysUseDirectionalSelection(m_frame)) |
231 s.setIsDirectional(true); | 354 s.setIsDirectional(true); |
232 | 355 |
233 if (!m_frame) { | 356 if (!m_frame) { |
234 m_selection = s; | 357 m_selection = s; |
235 return; | 358 return; |
236 } | 359 } |
237 | 360 |
238 // <http://bugs.webkit.org/show_bug.cgi?id=23464>: Infinite recursion at Fra meSelection::setSelection | 361 // <http://bugs.webkit.org/show_bug.cgi?id=23464>: Infinite recursion at Fra meSelection::setSelection |
239 // if document->frame() == m_frame we can get into an infinite loop | 362 // if document->frame() == m_frame we can get into an infinite loop |
(...skipping 926 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1166 m_xPosForVerticalArrowNavigation = x; | 1289 m_xPosForVerticalArrowNavigation = x; |
1167 } else | 1290 } else |
1168 x = m_xPosForVerticalArrowNavigation; | 1291 x = m_xPosForVerticalArrowNavigation; |
1169 | 1292 |
1170 return x; | 1293 return x; |
1171 } | 1294 } |
1172 | 1295 |
1173 void FrameSelection::clear() | 1296 void FrameSelection::clear() |
1174 { | 1297 { |
1175 m_granularity = CharacterGranularity; | 1298 m_granularity = CharacterGranularity; |
1299 granularityStrategy()->Clear(); | |
1176 setSelection(VisibleSelection()); | 1300 setSelection(VisibleSelection()); |
1177 } | 1301 } |
1178 | 1302 |
1179 void FrameSelection::prepareForDestruction() | 1303 void FrameSelection::prepareForDestruction() |
1180 { | 1304 { |
1181 m_granularity = CharacterGranularity; | 1305 m_granularity = CharacterGranularity; |
1182 | 1306 |
1183 m_caretBlinkTimer.stop(); | 1307 m_caretBlinkTimer.stop(); |
1184 | 1308 |
1185 LayoutView* view = m_frame->contentRenderer(); | 1309 LayoutView* view = m_frame->contentRenderer(); |
(...skipping 720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1906 String text = plainText(start.deepEquivalent(), end.deepEquivalent()); | 2030 String text = plainText(start.deepEquivalent(), end.deepEquivalent()); |
1907 if (!text.isEmpty() && !isSeparator(text.characterStartingAt(0))) { | 2031 if (!text.isEmpty() && !isSeparator(text.characterStartingAt(0))) { |
1908 setSelection(VisibleSelection(start, end), WordGranularity); | 2032 setSelection(VisibleSelection(start, end), WordGranularity); |
1909 return true; | 2033 return true; |
1910 } | 2034 } |
1911 } | 2035 } |
1912 | 2036 |
1913 return false; | 2037 return false; |
1914 } | 2038 } |
1915 | 2039 |
1916 void FrameSelection::moveRangeSelectionExtent(const VisiblePosition& extentPosit ion, TextGranularity granularity) | 2040 GranularityStrategy* const FrameSelection::granularityStrategy() |
yosin_UTC9
2015/04/16 04:11:26
nit: omit |const|
mfomitchev1
2015/04/17 00:13:51
Done.
| |
1917 { | 2041 { |
1918 if (isNone()) | 2042 if (m_granularityStrategy) |
2043 return m_granularityStrategy.get(); | |
2044 // We do lazy initalization for m_granularityStrategy, because if we initial ize it | |
2045 // right in the constructor - the correct settings may not be set yet. | |
Rick Byers
2015/04/16 19:09:48
and you're sure granularityStrategy won't ever be
mfomitchev1
2015/04/16 19:33:00
Yeah, that's a good point. I don't really understa
Rick Byers
2015/04/16 19:35:10
Sure, sounds good.
mfomitchev1
2015/04/17 00:13:51
Done.
| |
2046 Settings* settings = m_frame ? m_frame->settings() : 0; | |
2047 if (settings && settings->selectionStrategy() == StrategyDirection) | |
2048 m_granularityStrategy = adoptPtr(new DirectionGranularityStrategy()); | |
2049 else | |
2050 m_granularityStrategy = adoptPtr(new DefaultGranularityStrategy()); | |
2051 return m_granularityStrategy.get(); | |
2052 } | |
2053 | |
2054 void FrameSelection::moveRangeSelectionExtent(const VisiblePosition& extentPosit ion) | |
2055 { | |
2056 const VisiblePosition base = m_selection.visibleBase(); | |
2057 | |
2058 if (isNone() || base == extentPosition) | |
1919 return; | 2059 return; |
1920 | 2060 |
1921 const VisiblePosition basePosition = m_selection.isBaseFirst() ? m_selection .visibleStart() : m_selection.visibleEnd(); | 2061 VisibleSelection newSelection = granularityStrategy()->updateExtent(extentPo sition, selection()); |
1922 VisibleSelection newSelection(basePosition, extentPosition); | 2062 setSelection( |
1923 if (newSelection.isBaseFirst()) | 2063 newSelection, |
1924 newSelection.setEndRespectingGranularity(granularity); | 2064 FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | FrameSe lection::DoNotClearStrategy | UserTriggered, |
1925 else | 2065 FrameSelection::AlignCursorOnScrollIfNeeded, |
1926 newSelection.setStartRespectingGranularity(granularity); | 2066 CharacterGranularity); |
1927 if (!newSelection.isRange()) | |
1928 return; | |
1929 | |
1930 setSelection(newSelection, FrameSelection::CloseTyping | FrameSelection::Cle arTypingStyle | UserTriggered, FrameSelection::AlignCursorOnScrollIfNeeded, gran ularity); | |
1931 } | 2067 } |
1932 | 2068 |
1933 void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition, con st VisiblePosition& extentPosition, TextGranularity granularity) | 2069 void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition, con st VisiblePosition& extentPosition, TextGranularity granularity) |
1934 { | 2070 { |
1935 VisibleSelection newSelection(basePosition, extentPosition); | 2071 VisibleSelection newSelection(basePosition, extentPosition); |
1936 newSelection.expandUsingGranularity(granularity); | 2072 newSelection.expandUsingGranularity(granularity); |
1937 | 2073 |
1938 if (newSelection.isNone()) | 2074 if (newSelection.isNone()) |
1939 return; | 2075 return; |
1940 | 2076 |
1941 setSelection(newSelection, granularity); | 2077 setSelection(newSelection, granularity); |
1942 } | 2078 } |
1943 | 2079 |
1944 } | 2080 } |
1945 | 2081 |
1946 #ifndef NDEBUG | 2082 #ifndef NDEBUG |
1947 | 2083 |
1948 void showTree(const blink::FrameSelection& sel) | 2084 void showTree(const blink::FrameSelection& sel) |
1949 { | 2085 { |
1950 sel.showTreeForThis(); | 2086 sel.showTreeForThis(); |
1951 } | 2087 } |
1952 | 2088 |
1953 void showTree(const blink::FrameSelection* sel) | 2089 void showTree(const blink::FrameSelection* sel) |
1954 { | 2090 { |
1955 if (sel) | 2091 if (sel) |
1956 sel->showTreeForThis(); | 2092 sel->showTreeForThis(); |
1957 } | 2093 } |
1958 | 2094 |
1959 #endif | 2095 #endif |
OLD | NEW |