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 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
85 static inline LayoutUnit NoXPosForVerticalArrowNavigation() | 85 static inline LayoutUnit NoXPosForVerticalArrowNavigation() |
86 { | 86 { |
87 return LayoutUnit::min(); | 87 return LayoutUnit::min(); |
88 } | 88 } |
89 | 89 |
90 static inline bool shouldAlwaysUseDirectionalSelection(LocalFrame* frame) | 90 static inline bool shouldAlwaysUseDirectionalSelection(LocalFrame* frame) |
91 { | 91 { |
92 return !frame || frame->editor().behavior().shouldConsiderSelectionAsDirecti onal(); | 92 return !frame || frame->editor().behavior().shouldConsiderSelectionAsDirecti onal(); |
93 } | 93 } |
94 | 94 |
95 class GranularityStrategy { | |
96 public: | |
97 virtual ~GranularityStrategy() { }; | |
98 virtual void Clear(); | |
99 // Returns the selection extent based on the strategy. | |
100 virtual VisiblePosition moveRangeSelectionExtent(const VisiblePosition&, Fra meSelection*); | |
yoichio
2015/03/16 04:49:25
Could you use |const VisibleSelection& currentSele
mfomitchev
2015/03/16 17:14:12
Done.
| |
101 protected: | |
102 GranularityStrategy() { }; | |
103 }; | |
104 | |
105 class DefaultGranularityStrategy : public GranularityStrategy { | |
106 public: | |
107 DefaultGranularityStrategy() { }; | |
108 ~DefaultGranularityStrategy() override { }; | |
109 | |
110 void Clear() override { }; | |
111 VisiblePosition moveRangeSelectionExtent(const VisiblePosition& extentPositi on, FrameSelection*) override | |
112 { | |
113 return extentPosition; | |
114 }; | |
115 }; | |
116 | |
117 // "Expand by word, shrink by character" selection strategy. | |
118 // Uses character granularity when selection is shrinking. If the selection is e xpanding, | |
119 // granularity doesn't change until the word boundary is passed, after which the granularity | |
120 // switches to "word". | |
121 class DirectionGranularityStrategy : public GranularityStrategy { | |
122 public: | |
123 DirectionGranularityStrategy(); | |
124 ~DirectionGranularityStrategy() override { }; | |
125 | |
126 void Clear() override; | |
127 VisiblePosition moveRangeSelectionExtent(const VisiblePosition&, FrameSelect ion*) override; | |
128 private: | |
129 // Returns the next word boundary starting from |pos|. |direction| specifies the direction | |
130 // in which to search for the next bound. nextIfOnBound controls whether |po s| or the next boundary | |
131 // is returned when |pos| is located exactly on word boundary. | |
132 VisiblePosition nextWordBound(const VisiblePosition& /*pos*/, int /*directio n*/, bool /*nextIfOnBound*/); | |
133 | |
134 // Current selection granularity being used | |
135 TextGranularity m_granularity; | |
136 // If the selection extent is extended beyond this threshold - | |
137 // the granularity will be changed to WordGranularity | |
138 VisiblePosition m_wordBoundary; | |
yoichio
2015/03/16 04:49:25
Please initialize these variables.
mfomitchev
2015/03/16 17:14:12
We do initialize m_granularity in the constructor.
| |
139 // Cached extentPosition passed in moveRangeSelectionExtent | |
140 VisiblePosition m_extentPosition; | |
141 }; | |
142 | |
143 DirectionGranularityStrategy::DirectionGranularityStrategy() | |
144 : m_granularity(CharacterGranularity) { } | |
145 | |
146 void DirectionGranularityStrategy::Clear() | |
147 { | |
148 m_wordBoundary.clear(); | |
149 m_extentPosition.clear(); | |
150 m_granularity = CharacterGranularity; | |
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 VisiblePosition DirectionGranularityStrategy::moveRangeSelectionExtent(const Vis iblePosition& extentPosition, FrameSelection* fs) | |
163 { | |
164 const VisibleSelection& oldSel = fs->selection(); | |
165 const VisiblePosition& base = oldSel.visibleBase(); | |
166 const VisiblePosition& oldExtent = oldSel.visibleExtent(); | |
167 | |
168 int extentBaseOrder = comparePositions(extentPosition, base); | |
169 int oldExtentBaseOrder = comparePositions(oldExtent, base); | |
170 ASSERT(extentBaseOrder != 0); | |
171 | |
172 bool extentBaseOrderChanged = extentBaseOrder * oldExtentBaseOrder < 0; | |
173 | |
174 if (m_wordBoundary.isNull()) { | |
175 ASSERT(m_extentPosition.isNull()); | |
176 ASSERT(m_granularity == CharacterGranularity); | |
177 m_wordBoundary = nextWordBound(oldExtent, extentBaseOrder, false); | |
178 m_extentPosition = extentPosition; | |
179 } | |
180 if (extentBaseOrderChanged) { | |
181 m_wordBoundary = nextWordBound(base, extentBaseOrder, true); | |
182 m_granularity = CharacterGranularity; | |
183 } | |
184 bool beyondWordBoundary = extentBaseOrder > 0 ? comparePositions(extentPosit ion, m_wordBoundary) > 0 | |
185 : comparePositions(extentPosition, m_wordBoundary) < 0; | |
186 if (beyondWordBoundary) { | |
187 if (m_granularity == CharacterGranularity) | |
188 m_granularity = WordGranularity; | |
189 // The value passed for |nextIfOnBound| doesn't matter here. | |
190 m_wordBoundary = nextWordBound(extentPosition, extentBaseOrder, true); | |
191 } else if (!extentBaseOrderChanged) { | |
192 // If selection was shrunk - switch to character granularity | |
193 if (extentBaseOrder * comparePositions(extentPosition, m_extentPosition) < 0) { | |
194 m_granularity = CharacterGranularity; | |
195 m_wordBoundary = nextWordBound(extentPosition, extentBaseOrder, true ); | |
196 } | |
197 } | |
198 m_extentPosition = extentPosition; | |
yoichio
2015/03/16 04:49:25
I guess we need to update m_wordBoundary, m_granul
mfomitchev
2015/03/16 17:14:12
Ok, updated the code so that we only do it once. S
| |
199 | |
200 VisiblePosition visibleExtent = extentPosition; | |
201 if (m_granularity == WordGranularity) | |
202 visibleExtent = nextWordBound(extentPosition, extentBaseOrder, false); | |
203 | |
204 return visibleExtent; | |
205 } | |
206 | |
95 FrameSelection::FrameSelection(LocalFrame* frame) | 207 FrameSelection::FrameSelection(LocalFrame* frame) |
96 : m_frame(frame) | 208 : m_frame(frame) |
97 , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation()) | 209 , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation()) |
98 , m_observingVisibleSelection(false) | 210 , m_observingVisibleSelection(false) |
99 , m_granularity(CharacterGranularity) | 211 , m_granularity(CharacterGranularity) |
100 , m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired) | 212 , m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired) |
101 , m_caretRectDirty(true) | 213 , m_caretRectDirty(true) |
102 , m_shouldPaintCaret(true) | 214 , m_shouldPaintCaret(true) |
103 , m_isCaretBlinkingSuspended(false) | 215 , m_isCaretBlinkingSuspended(false) |
104 , m_focused(frame && frame->page() && frame->page()->focusController().focus edFrame() == frame) | 216 , m_focused(frame && frame->page() && frame->page()->focusController().focus edFrame() == frame) |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
214 | 326 |
215 newSelection.setIsDirectional(isDirectional); // Adjusting base and extent w ill make newSelection always directional | 327 newSelection.setIsDirectional(isDirectional); // Adjusting base and extent w ill make newSelection always directional |
216 if (m_selection == newSelection) | 328 if (m_selection == newSelection) |
217 return; | 329 return; |
218 | 330 |
219 setSelection(newSelection, granularity); | 331 setSelection(newSelection, granularity); |
220 } | 332 } |
221 | 333 |
222 void FrameSelection::setSelection(const VisibleSelection& newSelection, SetSelec tionOptions options, CursorAlignOnScroll align, TextGranularity granularity) | 334 void FrameSelection::setSelection(const VisibleSelection& newSelection, SetSelec tionOptions options, CursorAlignOnScroll align, TextGranularity granularity) |
223 { | 335 { |
336 if ((options & FrameSelection::DoNotClearStrategy) == 0) | |
337 granularityStrategy().Clear(); | |
224 bool closeTyping = options & CloseTyping; | 338 bool closeTyping = options & CloseTyping; |
225 bool shouldClearTypingStyle = options & ClearTypingStyle; | 339 bool shouldClearTypingStyle = options & ClearTypingStyle; |
226 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); | 340 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); |
227 | 341 |
228 VisibleSelection s = validateSelection(newSelection); | 342 VisibleSelection s = validateSelection(newSelection); |
229 if (shouldAlwaysUseDirectionalSelection(m_frame)) | 343 if (shouldAlwaysUseDirectionalSelection(m_frame)) |
230 s.setIsDirectional(true); | 344 s.setIsDirectional(true); |
231 | 345 |
232 if (!m_frame) { | 346 if (!m_frame) { |
233 m_selection = s; | 347 m_selection = s; |
(...skipping 932 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1166 m_xPosForVerticalArrowNavigation = x; | 1280 m_xPosForVerticalArrowNavigation = x; |
1167 } else | 1281 } else |
1168 x = m_xPosForVerticalArrowNavigation; | 1282 x = m_xPosForVerticalArrowNavigation; |
1169 | 1283 |
1170 return x; | 1284 return x; |
1171 } | 1285 } |
1172 | 1286 |
1173 void FrameSelection::clear() | 1287 void FrameSelection::clear() |
1174 { | 1288 { |
1175 m_granularity = CharacterGranularity; | 1289 m_granularity = CharacterGranularity; |
1290 granularityStrategy().Clear(); | |
1176 setSelection(VisibleSelection()); | 1291 setSelection(VisibleSelection()); |
1177 } | 1292 } |
1178 | 1293 |
1179 void FrameSelection::prepareForDestruction() | 1294 void FrameSelection::prepareForDestruction() |
1180 { | 1295 { |
1181 m_granularity = CharacterGranularity; | 1296 m_granularity = CharacterGranularity; |
1182 | 1297 |
1183 m_caretBlinkTimer.stop(); | 1298 m_caretBlinkTimer.stop(); |
1184 | 1299 |
1185 LayoutView* view = m_frame->contentRenderer(); | 1300 LayoutView* view = m_frame->contentRenderer(); |
(...skipping 719 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1905 String text = plainText(start.deepEquivalent(), end.deepEquivalent()); | 2020 String text = plainText(start.deepEquivalent(), end.deepEquivalent()); |
1906 if (!text.isEmpty() && !isSeparator(text.characterStartingAt(0))) { | 2021 if (!text.isEmpty() && !isSeparator(text.characterStartingAt(0))) { |
1907 setSelection(VisibleSelection(start, end), WordGranularity); | 2022 setSelection(VisibleSelection(start, end), WordGranularity); |
1908 return true; | 2023 return true; |
1909 } | 2024 } |
1910 } | 2025 } |
1911 | 2026 |
1912 return false; | 2027 return false; |
1913 } | 2028 } |
1914 | 2029 |
1915 void FrameSelection::moveRangeSelectionExtent(const VisiblePosition& extentPosit ion, TextGranularity granularity) | 2030 GranularityStrategy& FrameSelection::granularityStrategy() |
1916 { | 2031 { |
1917 if (isNone()) | 2032 if (m_granularityStrategy) |
2033 return *m_granularityStrategy; | |
2034 // We do lazy initalization for m_granularityStrategy, because if we initial ize it | |
2035 // right in the constructor - the correct settings may not be set yet. | |
2036 Settings* settings = m_frame ? m_frame->settings() : 0; | |
2037 if (settings && settings->selectionStrategy() == StrategyDirection) | |
2038 m_granularityStrategy = adoptPtr(new DirectionGranularityStrategy()); | |
2039 else | |
2040 m_granularityStrategy = adoptPtr(new DefaultGranularityStrategy()); | |
2041 return *m_granularityStrategy; | |
2042 } | |
2043 | |
2044 void FrameSelection::moveRangeSelectionExtent(const VisiblePosition& extentPosit ion) | |
2045 { | |
2046 const VisiblePosition base = m_selection.visibleBase(); | |
2047 | |
2048 if (isNone() || comparePositions(base, extentPosition) == 0) | |
1918 return; | 2049 return; |
1919 | 2050 |
1920 const VisiblePosition basePosition = m_selection.isBaseFirst() ? | 2051 VisiblePosition newExtentPosition = granularityStrategy().moveRangeSelection Extent(extentPosition, this); |
1921 m_selection.visibleStart() : m_selection.visibleEnd(); | 2052 VisibleSelection newSelection(base, newExtentPosition); |
1922 | 2053 setSelection( |
1923 int order = comparePositions(basePosition, extentPosition); | 2054 newSelection, |
1924 if (!order) | 2055 FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | FrameSe lection::DoNotClearStrategy | UserTriggered, |
1925 return; | 2056 FrameSelection::AlignCursorOnScrollIfNeeded, |
1926 | 2057 CharacterGranularity); |
1927 // Currently we support only CharaterGranularity and WordGranurarity. | |
1928 // If |granurarity| is not of them, we fall back it to | |
1929 // CharacterGranularity. | |
1930 VisiblePosition newExtentPosition = extentPosition; | |
1931 if (granularity == WordGranularity) | |
1932 newExtentPosition = order < 0 ? endOfWord(extentPosition) : startOfWord( extentPosition); | |
1933 | |
1934 VisibleSelection newSelection = VisibleSelection(basePosition, newExtentPosi tion); | |
1935 setSelection(newSelection, FrameSelection::CloseTyping | FrameSelection::Cle arTypingStyle | UserTriggered, FrameSelection::AlignCursorOnScrollIfNeeded, gran ularity); | |
1936 } | 2058 } |
1937 | 2059 |
1938 void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition, con st VisiblePosition& extentPosition, TextGranularity granularity) | 2060 void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition, con st VisiblePosition& extentPosition, TextGranularity granularity) |
1939 { | 2061 { |
1940 VisibleSelection newSelection(basePosition, extentPosition); | 2062 VisibleSelection newSelection(basePosition, extentPosition); |
1941 newSelection.expandUsingGranularity(granularity); | 2063 newSelection.expandUsingGranularity(granularity); |
1942 | 2064 |
1943 if (newSelection.isNone()) | 2065 if (newSelection.isNone()) |
1944 return; | 2066 return; |
1945 | 2067 |
1946 setSelection(newSelection, granularity); | 2068 setSelection(newSelection, granularity); |
1947 } | 2069 } |
1948 | 2070 |
1949 } | 2071 } |
1950 | 2072 |
1951 #ifndef NDEBUG | 2073 #ifndef NDEBUG |
1952 | 2074 |
1953 void showTree(const blink::FrameSelection& sel) | 2075 void showTree(const blink::FrameSelection& sel) |
1954 { | 2076 { |
1955 sel.showTreeForThis(); | 2077 sel.showTreeForThis(); |
1956 } | 2078 } |
1957 | 2079 |
1958 void showTree(const blink::FrameSelection* sel) | 2080 void showTree(const blink::FrameSelection* sel) |
1959 { | 2081 { |
1960 if (sel) | 2082 if (sel) |
1961 sel->showTreeForThis(); | 2083 sel->showTreeForThis(); |
1962 } | 2084 } |
1963 | 2085 |
1964 #endif | 2086 #endif |
OLD | NEW |