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 { | |
yosin_UTC9
2015/04/17 04:24:50
Is it better to move XXXStrategy to another file?
mfomitchev
2015/04/17 14:41:49
It's your call. The upside is reducing the file si
yosin_UTC9
2015/04/20 01:25:55
We've moved classes to their own files for TextIte
| |
97 public: | |
98 virtual ~GranularityStrategy() { }; | |
99 virtual SelectionStrategy GetType() const; | |
yosin_UTC9
2015/04/17 04:24:50
As of link error, we want to put "= 0".
mfomitchev
2015/04/17 14:41:49
Done.
| |
100 virtual void Clear(); | |
yosin_UTC9
2015/04/17 04:24:50
ditto
mfomitchev
2015/04/17 14:41:49
Done.
| |
101 | |
102 // Calculates and returns the new selection based on the updated user select ion extent |extentPosition| and the granularity strategy. | |
103 virtual VisibleSelection updateExtent(const VisiblePosition& extentPosition, const VisibleSelection&); | |
yosin_UTC9
2015/04/17 04:24:50
ditto
mfomitchev
2015/04/17 14:41:49
Done.
| |
104 protected: | |
105 GranularityStrategy() { }; | |
106 }; | |
107 | |
108 // Always uses character granularity. | |
109 class CharacterGranularityStrategy : public GranularityStrategy { | |
yosin_UTC9
2015/04/17 04:24:50
nit: "final"
mfomitchev
2015/04/17 14:41:49
Done.
| |
110 public: | |
111 CharacterGranularityStrategy() { }; | |
112 ~CharacterGranularityStrategy() override { }; | |
113 | |
114 SelectionStrategy GetType() const override { return StrategyCharacter; } | |
115 void Clear() override { }; | |
116 VisibleSelection updateExtent(const VisiblePosition& extentPosition, const V isibleSelection& selection) override | |
117 { | |
118 return VisibleSelection(selection.visibleBase(), extentPosition); | |
119 }; | |
120 }; | |
121 | |
122 // "Expand by word, shrink by character" selection strategy. | |
123 // Uses character granularity when selection is shrinking. If the selection is e xpanding, | |
124 // granularity doesn't change until a word boundary is passed, after which the g ranularity | |
125 // switches to "word". | |
126 class DirectionGranularityStrategy : public GranularityStrategy { | |
yosin_UTC9
2015/04/17 04:24:50
nit: final
mfomitchev
2015/04/17 14:41:49
Done.
| |
127 public: | |
128 DirectionGranularityStrategy(); | |
129 ~DirectionGranularityStrategy() override { }; | |
130 | |
131 SelectionStrategy GetType() const override { return StrategyDirection; } | |
132 void Clear() override; | |
133 VisibleSelection updateExtent(const VisiblePosition&, const VisibleSelection &) override; | |
134 private: | |
135 enum EWordBoundAdjust {CurrentPosIfOnBound = false, NextBoundIfOnBound = tru e}; | |
yosin_UTC9
2015/04/17 04:24:51
nit: we don't need to assign value for enum fields
yosin_UTC9
2015/04/17 04:24:51
nit: better to use |enum class|.
mfomitchev
2015/04/17 14:41:49
Done.
mfomitchev
2015/04/17 14:41:49
Neat! Thanks for the tip!
| |
136 enum ESearchDirection {SearchBackwards = 0, SearchForward = 1}; | |
yosin_UTC9
2015/04/17 04:24:50
nit: we don't need to assign value for enum fields
yosin_UTC9
2015/04/17 04:24:50
nit: better to use |enum class|.
mfomitchev
2015/04/17 14:41:49
Done.
mfomitchev
2015/04/17 14:41:49
Done.
| |
137 | |
138 // Returns the next word boundary starting from |pos|. |direction| specifies the direction | |
139 // in which to search for the next bound. nextIfOnBound controls whether |po s| or the next boundary | |
140 // is returned when |pos| is located exactly on word boundary. | |
141 VisiblePosition nextWordBound(const VisiblePosition& /*pos*/, ESearchDirecti on /*direction*/, EWordBoundAdjust /*nextIfOnBound*/); | |
142 | |
143 // Current selection granularity being used | |
144 TextGranularity m_granularity; | |
145 // Set to true if the selection was shrunk (without changing relative base/e xtent order) | |
146 // as a result of the most recent updateExtent call. | |
147 bool m_lastMoveShrunkSelection; | |
148 }; | |
149 | |
150 DirectionGranularityStrategy::DirectionGranularityStrategy() | |
151 : m_granularity(CharacterGranularity) | |
152 , m_lastMoveShrunkSelection(false) { } | |
153 | |
154 void DirectionGranularityStrategy::Clear() | |
155 { | |
156 m_granularity = CharacterGranularity; | |
157 m_lastMoveShrunkSelection = false; | |
158 } | |
159 | |
160 VisiblePosition DirectionGranularityStrategy::nextWordBound( | |
161 const VisiblePosition& pos, | |
162 ESearchDirection direction, | |
163 EWordBoundAdjust wordBoundAdjust) | |
164 { | |
165 if (direction == SearchForward) | |
166 return endOfWord(pos, wordBoundAdjust == CurrentPosIfOnBound ? LeftWord IfOnBoundary : RightWordIfOnBoundary); | |
167 return startOfWord(pos, wordBoundAdjust == CurrentPosIfOnBound ? RightWordI fOnBoundary : LeftWordIfOnBoundary); | |
168 } | |
169 | |
170 VisibleSelection DirectionGranularityStrategy::updateExtent(const VisiblePositio n& extentPosition, const VisibleSelection& selection) | |
171 { | |
172 if (extentPosition == selection.visibleExtent()) | |
173 return selection; | |
174 | |
175 const VisiblePosition base = selection.visibleBase(); | |
176 const VisiblePosition oldExtentWithGranularity = selection.isBaseFirst() ? s election.visibleEnd() : selection.visibleStart(); | |
177 | |
178 int extentBaseOrder = comparePositions(extentPosition, base); | |
179 int oldExtentBaseOrder = comparePositions(oldExtentWithGranularity, base); | |
180 | |
181 bool extentBaseOrderSwitched = (extentBaseOrder > 0 && oldExtentBaseOrder < 0) | |
182 || (extentBaseOrder < 0 && oldExtentBaseOrder > 0); | |
183 | |
184 // Determine the boundary of the 'current word', i.e. the boundary extending beyond which | |
185 // should change the granularity to WordGranularity. | |
186 // If the last move has shrunk the selection and is now exactly on the word boundary - | |
187 // we need to take the next bound as the bound of the "current word". | |
188 VisiblePosition currentWordBoundary = nextWordBound( | |
189 oldExtentWithGranularity, | |
190 oldExtentBaseOrder > 0 ? SearchForward : SearchBackwards, | |
191 m_lastMoveShrunkSelection ? NextBoundIfOnBound : CurrentPosIfOnBound); | |
192 | |
193 bool thisMoveShrunkSelection = (extentBaseOrder > 0 && comparePositions(exte ntPosition, selection.visibleExtent()) < 0) | |
194 || (extentBaseOrder < 0 && comparePositions(extentPosition, selection.vi sibleExtent()) > 0); | |
195 // If the extent-base order was switched, then the selection is now expandin g in a different | |
196 // direction than before. Therefore we need to calculate the boundary of the 'current word' | |
197 // in this new direction in order to be able to tell if the selection expand ed beyond it. | |
198 if (extentBaseOrderSwitched) { | |
199 currentWordBoundary = nextWordBound(base, extentBaseOrder > 0 ? SearchFo rward : SearchBackwards, NextBoundIfOnBound); | |
200 m_granularity = CharacterGranularity; | |
201 // When the base/extent order switches it doesn't count as shrinking sel ection. | |
202 thisMoveShrunkSelection = false; | |
203 } | |
204 | |
205 bool expandedBeyondWordBoundary; | |
206 if (extentBaseOrder > 0) | |
207 expandedBeyondWordBoundary = comparePositions(extentPosition, currentWor dBoundary) > 0; | |
208 else | |
209 expandedBeyondWordBoundary = comparePositions(extentPosition, currentWor dBoundary) < 0; | |
210 if (expandedBeyondWordBoundary) { | |
211 m_granularity = WordGranularity; | |
212 } else if (thisMoveShrunkSelection) { | |
213 m_granularity = CharacterGranularity; | |
214 m_lastMoveShrunkSelection = true; | |
215 } | |
216 | |
217 m_lastMoveShrunkSelection = thisMoveShrunkSelection; | |
218 VisibleSelection newSelection = selection; | |
219 newSelection.setExtent(extentPosition); | |
220 if (m_granularity == WordGranularity) { | |
221 if (extentBaseOrder > 0) | |
222 newSelection.setEndRespectingGranularity(m_granularity, LeftWordIfOn Boundary); | |
223 else | |
224 newSelection.setStartRespectingGranularity(m_granularity, RightWordI fOnBoundary); | |
225 } | |
226 | |
227 return newSelection; | |
228 } | |
229 | |
96 FrameSelection::FrameSelection(LocalFrame* frame) | 230 FrameSelection::FrameSelection(LocalFrame* frame) |
97 : m_frame(frame) | 231 : m_frame(frame) |
98 , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation()) | 232 , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation()) |
99 , m_observingVisibleSelection(false) | 233 , m_observingVisibleSelection(false) |
100 , m_granularity(CharacterGranularity) | 234 , m_granularity(CharacterGranularity) |
101 , m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired) | 235 , m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired) |
102 , m_caretRectDirty(true) | 236 , m_caretRectDirty(true) |
103 , m_shouldPaintCaret(true) | 237 , m_shouldPaintCaret(true) |
104 , m_isCaretBlinkingSuspended(false) | 238 , m_isCaretBlinkingSuspended(false) |
105 , m_focused(frame && frame->page() && frame->page()->focusController().focus edFrame() == frame) | 239 , 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 | 349 |
216 newSelection.setIsDirectional(isDirectional); // Adjusting base and extent w ill make newSelection always directional | 350 newSelection.setIsDirectional(isDirectional); // Adjusting base and extent w ill make newSelection always directional |
217 if (m_selection == newSelection) | 351 if (m_selection == newSelection) |
218 return; | 352 return; |
219 | 353 |
220 setSelection(newSelection, granularity); | 354 setSelection(newSelection, granularity); |
221 } | 355 } |
222 | 356 |
223 void FrameSelection::setSelection(const VisibleSelection& newSelection, SetSelec tionOptions options, CursorAlignOnScroll align, TextGranularity granularity) | 357 void FrameSelection::setSelection(const VisibleSelection& newSelection, SetSelec tionOptions options, CursorAlignOnScroll align, TextGranularity granularity) |
224 { | 358 { |
359 if (m_granularityStrategy && (options & FrameSelection::DoNotClearStrategy) == 0) { | |
360 m_granularityStrategy->Clear(); | |
361 } | |
225 bool closeTyping = options & CloseTyping; | 362 bool closeTyping = options & CloseTyping; |
226 bool shouldClearTypingStyle = options & ClearTypingStyle; | 363 bool shouldClearTypingStyle = options & ClearTypingStyle; |
227 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); | 364 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); |
228 | 365 |
229 VisibleSelection s = validateSelection(newSelection); | 366 VisibleSelection s = validateSelection(newSelection); |
367 | |
230 if (shouldAlwaysUseDirectionalSelection(m_frame)) | 368 if (shouldAlwaysUseDirectionalSelection(m_frame)) |
231 s.setIsDirectional(true); | 369 s.setIsDirectional(true); |
232 | 370 |
233 if (!m_frame) { | 371 if (!m_frame) { |
234 m_selection = s; | 372 m_selection = s; |
235 return; | 373 return; |
236 } | 374 } |
237 | 375 |
238 // <http://bugs.webkit.org/show_bug.cgi?id=23464>: Infinite recursion at Fra meSelection::setSelection | 376 // <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 | 377 // 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; | 1304 m_xPosForVerticalArrowNavigation = x; |
1167 } else | 1305 } else |
1168 x = m_xPosForVerticalArrowNavigation; | 1306 x = m_xPosForVerticalArrowNavigation; |
1169 | 1307 |
1170 return x; | 1308 return x; |
1171 } | 1309 } |
1172 | 1310 |
1173 void FrameSelection::clear() | 1311 void FrameSelection::clear() |
1174 { | 1312 { |
1175 m_granularity = CharacterGranularity; | 1313 m_granularity = CharacterGranularity; |
1314 if (m_granularityStrategy) | |
1315 m_granularityStrategy->Clear(); | |
1176 setSelection(VisibleSelection()); | 1316 setSelection(VisibleSelection()); |
1177 } | 1317 } |
1178 | 1318 |
1179 void FrameSelection::prepareForDestruction() | 1319 void FrameSelection::prepareForDestruction() |
1180 { | 1320 { |
1181 m_granularity = CharacterGranularity; | 1321 m_granularity = CharacterGranularity; |
1182 | 1322 |
1183 m_caretBlinkTimer.stop(); | 1323 m_caretBlinkTimer.stop(); |
1184 | 1324 |
1185 LayoutView* view = m_frame->contentRenderer(); | 1325 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()); | 2046 String text = plainText(start.deepEquivalent(), end.deepEquivalent()); |
1907 if (!text.isEmpty() && !isSeparator(text.characterStartingAt(0))) { | 2047 if (!text.isEmpty() && !isSeparator(text.characterStartingAt(0))) { |
1908 setSelection(VisibleSelection(start, end), WordGranularity); | 2048 setSelection(VisibleSelection(start, end), WordGranularity); |
1909 return true; | 2049 return true; |
1910 } | 2050 } |
1911 } | 2051 } |
1912 | 2052 |
1913 return false; | 2053 return false; |
1914 } | 2054 } |
1915 | 2055 |
1916 void FrameSelection::moveRangeSelectionExtent(const VisiblePosition& extentPosit ion, TextGranularity granularity) | 2056 GranularityStrategy* FrameSelection::granularityStrategy() |
1917 { | 2057 { |
1918 if (isNone()) | 2058 // We do lazy initalization for m_granularityStrategy, because if we initial ize it |
2059 // right in the constructor - the correct settings may not be set yet. | |
2060 SelectionStrategy strategyType = StrategyCharacter; | |
2061 Settings* settings = m_frame ? m_frame->settings() : 0; | |
2062 if (settings && settings->selectionStrategy() == StrategyDirection) | |
2063 strategyType = StrategyDirection; | |
2064 | |
2065 if (m_granularityStrategy && m_granularityStrategy->GetType() == strategyTyp e) | |
2066 return m_granularityStrategy.get(); | |
2067 | |
2068 if (strategyType == StrategyDirection) | |
2069 m_granularityStrategy = adoptPtr(new DirectionGranularityStrategy()); | |
2070 else | |
2071 m_granularityStrategy = adoptPtr(new CharacterGranularityStrategy()); | |
2072 return m_granularityStrategy.get(); | |
2073 } | |
2074 | |
2075 void FrameSelection::moveRangeSelectionExtent(const VisiblePosition& extentPosit ion) | |
2076 { | |
2077 const VisiblePosition base = m_selection.visibleBase(); | |
2078 | |
2079 if (isNone() || base == extentPosition) | |
1919 return; | 2080 return; |
1920 | 2081 |
1921 const VisiblePosition basePosition = m_selection.isBaseFirst() ? m_selection .visibleStart() : m_selection.visibleEnd(); | 2082 VisibleSelection newSelection = granularityStrategy()->updateExtent(extentPo sition, selection()); |
1922 VisibleSelection newSelection(basePosition, extentPosition); | 2083 setSelection( |
1923 if (newSelection.isBaseFirst()) | 2084 newSelection, |
1924 newSelection.setEndRespectingGranularity(granularity); | 2085 FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | FrameSe lection::DoNotClearStrategy | UserTriggered, |
1925 else | 2086 FrameSelection::AlignCursorOnScrollIfNeeded, |
1926 newSelection.setStartRespectingGranularity(granularity); | 2087 CharacterGranularity); |
1927 if (!newSelection.isRange()) | |
1928 return; | |
1929 | |
1930 setSelection(newSelection, FrameSelection::CloseTyping | FrameSelection::Cle arTypingStyle | UserTriggered, FrameSelection::AlignCursorOnScrollIfNeeded, gran ularity); | |
1931 } | 2088 } |
1932 | 2089 |
1933 void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition, con st VisiblePosition& extentPosition, TextGranularity granularity) | 2090 void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition, con st VisiblePosition& extentPosition, TextGranularity granularity) |
1934 { | 2091 { |
1935 VisibleSelection newSelection(basePosition, extentPosition); | 2092 VisibleSelection newSelection(basePosition, extentPosition); |
1936 newSelection.expandUsingGranularity(granularity); | 2093 newSelection.expandUsingGranularity(granularity); |
1937 | 2094 |
1938 if (newSelection.isNone()) | 2095 if (newSelection.isNone()) |
1939 return; | 2096 return; |
1940 | 2097 |
1941 setSelection(newSelection, granularity); | 2098 setSelection(newSelection, granularity); |
1942 } | 2099 } |
1943 | 2100 |
1944 } | 2101 } |
1945 | 2102 |
1946 #ifndef NDEBUG | 2103 #ifndef NDEBUG |
1947 | 2104 |
1948 void showTree(const blink::FrameSelection& sel) | 2105 void showTree(const blink::FrameSelection& sel) |
1949 { | 2106 { |
1950 sel.showTreeForThis(); | 2107 sel.showTreeForThis(); |
1951 } | 2108 } |
1952 | 2109 |
1953 void showTree(const blink::FrameSelection* sel) | 2110 void showTree(const blink::FrameSelection* sel) |
1954 { | 2111 { |
1955 if (sel) | 2112 if (sel) |
1956 sel->showTreeForThis(); | 2113 sel->showTreeForThis(); |
1957 } | 2114 } |
1958 | 2115 |
1959 #endif | 2116 #endif |
OLD | NEW |