Chromium Code Reviews| 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&, con st VisibleSelection&); | |
|
yosin_UTC9
2015/03/18 03:44:54
Since, |moveRangeSelectionExtent()| returns positi
mfomitchev
2015/03/19 01:24:39
Renamed and expanded on the comment. I wanted to c
| |
| 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, const VisibleSelection&) 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&, const Visib leSelection&) 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 // Marks the boundary of the "current word". If the selection extent is exte nded | |
| 137 // beyond this threshold - the granularity will be changed to WordGranularit y. | |
| 138 VisiblePosition m_wordBoundary; | |
|
yosin_UTC9
2015/03/18 03:44:54
|VisiblePosition| isn't update at DOM mutation or
mfomitchev
2015/03/19 01:24:39
Ok. I really only need m_wordBoundary to determine
yosin_UTC9
2015/03/23 07:20:39
Saving |Position|, |VisibleSelection|, |VisiblePos
| |
| 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, const VisibleSelection& selection) | |
| 163 { | |
| 164 const VisiblePosition& base = selection.visibleBase(); | |
| 165 const VisiblePosition& oldExtent = selection.visibleExtent(); | |
| 166 | |
| 167 int extentBaseOrder = comparePositions(extentPosition, base); | |
|
yoichio
2015/03/17 05:54:41
I wonder why this function looks procedural.
It is
mfomitchev
2015/03/17 17:01:16
Ok, lets enumerate your cases one to four from top
yosin_UTC9
2015/03/18 03:44:54
It is better to ask |VisibleSelection| for DOM ord
| |
| 168 int oldExtentBaseOrder = comparePositions(oldExtent, base); | |
| 169 ASSERT(extentBaseOrder != 0); | |
| 170 | |
| 171 bool extentBaseOrderSwitched = extentBaseOrder * oldExtentBaseOrder < 0; | |
| 172 VisiblePosition prevWordBoundary = m_wordBoundary; | |
| 173 | |
| 174 // If the previous word boundary is empty, this must be the first call to mo veRangeSelectionExtent() | |
| 175 // after a Clear(). Initialize prevWordBoundary based on the current selecti on. | |
| 176 if (prevWordBoundary.isNull()) { | |
|
yoichio
2015/03/17 05:54:41
We can early return in this case.
mfomitchev
2015/03/17 17:01:16
We can't actually. extentPosition can still be any
| |
| 177 ASSERT(m_extentPosition.isNull()); | |
| 178 ASSERT(m_granularity == CharacterGranularity); | |
| 179 prevWordBoundary = nextWordBound(oldExtent, extentBaseOrder, false); | |
|
yosin_UTC9
2015/03/18 03:44:54
How about factor out |FrameSelection::modifyXXX()|
| |
| 180 } | |
| 181 // If the extent-base order was switched, then the selection is now expandin g in a different | |
| 182 // direction than before. Therefore we need to calculate the boundary of the 'current word' | |
| 183 // in this new direction in order to be able to tell if the selection expand ed beyond it. | |
| 184 if (extentBaseOrderSwitched) { | |
| 185 prevWordBoundary = nextWordBound(base, extentBaseOrder, true); | |
| 186 m_granularity = CharacterGranularity; | |
| 187 } | |
| 188 | |
| 189 VisiblePosition newWordBoundary = prevWordBoundary; | |
| 190 bool expandedBeyondWordBoundary = extentBaseOrder > 0 ? comparePositions(ext entPosition, prevWordBoundary) > 0 | |
| 191 : comparePositions(extentPosition, prevWordBoundary) < 0; | |
| 192 // If the selection expanded beyond the word boundary - switch to word granu larity and calculate | |
| 193 // the boundary of the new 'current word'. | |
| 194 if (expandedBeyondWordBoundary) { | |
| 195 if (m_granularity == CharacterGranularity) | |
| 196 m_granularity = WordGranularity; | |
| 197 newWordBoundary = nextWordBound(extentPosition, extentBaseOrder, true); | |
| 198 } else if (!extentBaseOrderSwitched) { | |
| 199 // If selection was shrunk - switch to character granularity and recalcu late the boundary | |
| 200 // of the 'current word' in case the selection was shrunk beyond the old 'current word'. | |
| 201 if (!m_extentPosition.isNull() && extentBaseOrder * comparePositions(ext entPosition, m_extentPosition) < 0) { | |
| 202 m_granularity = CharacterGranularity; | |
| 203 newWordBoundary = nextWordBound(extentPosition, extentBaseOrder, tru e); | |
| 204 } | |
| 205 } | |
| 206 m_wordBoundary = newWordBoundary; | |
| 207 m_extentPosition = extentPosition; | |
| 208 | |
| 209 VisiblePosition visibleExtent = extentPosition; | |
| 210 if (m_granularity == WordGranularity) | |
| 211 visibleExtent = nextWordBound(extentPosition, extentBaseOrder, false); | |
| 212 | |
| 213 return visibleExtent; | |
| 214 } | |
| 215 | |
| 95 FrameSelection::FrameSelection(LocalFrame* frame) | 216 FrameSelection::FrameSelection(LocalFrame* frame) |
| 96 : m_frame(frame) | 217 : m_frame(frame) |
| 97 , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation()) | 218 , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation()) |
| 98 , m_observingVisibleSelection(false) | 219 , m_observingVisibleSelection(false) |
| 99 , m_granularity(CharacterGranularity) | 220 , m_granularity(CharacterGranularity) |
| 100 , m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired) | 221 , m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired) |
| 101 , m_caretRectDirty(true) | 222 , m_caretRectDirty(true) |
| 102 , m_shouldPaintCaret(true) | 223 , m_shouldPaintCaret(true) |
| 103 , m_isCaretBlinkingSuspended(false) | 224 , m_isCaretBlinkingSuspended(false) |
| 104 , 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... | |
| 214 | 335 |
| 215 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 |
| 216 if (m_selection == newSelection) | 337 if (m_selection == newSelection) |
| 217 return; | 338 return; |
| 218 | 339 |
| 219 setSelection(newSelection, granularity); | 340 setSelection(newSelection, granularity); |
| 220 } | 341 } |
| 221 | 342 |
| 222 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) |
| 223 { | 344 { |
| 345 if ((options & FrameSelection::DoNotClearStrategy) == 0) | |
| 346 granularityStrategy().Clear(); | |
| 224 bool closeTyping = options & CloseTyping; | 347 bool closeTyping = options & CloseTyping; |
| 225 bool shouldClearTypingStyle = options & ClearTypingStyle; | 348 bool shouldClearTypingStyle = options & ClearTypingStyle; |
| 226 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); | 349 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); |
| 227 | 350 |
| 228 VisibleSelection s = validateSelection(newSelection); | 351 VisibleSelection s = validateSelection(newSelection); |
| 229 if (shouldAlwaysUseDirectionalSelection(m_frame)) | 352 if (shouldAlwaysUseDirectionalSelection(m_frame)) |
| 230 s.setIsDirectional(true); | 353 s.setIsDirectional(true); |
| 231 | 354 |
| 232 if (!m_frame) { | 355 if (!m_frame) { |
| 233 m_selection = s; | 356 m_selection = s; |
| (...skipping 932 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 719 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1905 String text = plainText(start.deepEquivalent(), end.deepEquivalent()); | 2029 String text = plainText(start.deepEquivalent(), end.deepEquivalent()); |
| 1906 if (!text.isEmpty() && !isSeparator(text.characterStartingAt(0))) { | 2030 if (!text.isEmpty() && !isSeparator(text.characterStartingAt(0))) { |
| 1907 setSelection(VisibleSelection(start, end), WordGranularity); | 2031 setSelection(VisibleSelection(start, end), WordGranularity); |
| 1908 return true; | 2032 return true; |
| 1909 } | 2033 } |
| 1910 } | 2034 } |
| 1911 | 2035 |
| 1912 return false; | 2036 return false; |
| 1913 } | 2037 } |
| 1914 | 2038 |
| 1915 void FrameSelection::moveRangeSelectionExtent(const VisiblePosition& extentPosit ion, TextGranularity granularity) | 2039 GranularityStrategy& FrameSelection::granularityStrategy() |
| 1916 { | 2040 { |
| 1917 if (isNone()) | 2041 if (m_granularityStrategy) |
| 2042 return *m_granularityStrategy; | |
| 2043 // We do lazy initalization for m_granularityStrategy, because if we initial ize it | |
| 2044 // right in the constructor - the correct settings may not be set yet. | |
| 2045 Settings* settings = m_frame ? m_frame->settings() : 0; | |
| 2046 if (settings && settings->selectionStrategy() == StrategyDirection) | |
| 2047 m_granularityStrategy = adoptPtr(new DirectionGranularityStrategy()); | |
| 2048 else | |
| 2049 m_granularityStrategy = adoptPtr(new DefaultGranularityStrategy()); | |
| 2050 return *m_granularityStrategy; | |
| 2051 } | |
| 2052 | |
| 2053 void FrameSelection::moveRangeSelectionExtent(const VisiblePosition& extentPosit ion) | |
| 2054 { | |
| 2055 const VisiblePosition base = m_selection.visibleBase(); | |
| 2056 | |
| 2057 if (isNone() || comparePositions(base, extentPosition) == 0) | |
|
yosin_UTC9
2015/03/18 03:44:54
nit: |base == extentPosision|
mfomitchev
2015/03/19 01:24:39
Done.
| |
| 1918 return; | 2058 return; |
| 1919 | 2059 |
| 1920 const VisiblePosition basePosition = m_selection.isBaseFirst() ? | 2060 VisiblePosition newExtentPosition = granularityStrategy().moveRangeSelection Extent(extentPosition, selection()); |
| 1921 m_selection.visibleStart() : m_selection.visibleEnd(); | 2061 VisibleSelection newSelection(base, newExtentPosition); |
| 1922 | 2062 setSelection( |
| 1923 int order = comparePositions(basePosition, extentPosition); | 2063 newSelection, |
| 1924 if (!order) | 2064 FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | FrameSe lection::DoNotClearStrategy | UserTriggered, |
| 1925 return; | 2065 FrameSelection::AlignCursorOnScrollIfNeeded, |
| 1926 | 2066 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 } | 2067 } |
| 1937 | 2068 |
| 1938 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) |
| 1939 { | 2070 { |
| 1940 VisibleSelection newSelection(basePosition, extentPosition); | 2071 VisibleSelection newSelection(basePosition, extentPosition); |
| 1941 newSelection.expandUsingGranularity(granularity); | 2072 newSelection.expandUsingGranularity(granularity); |
| 1942 | 2073 |
| 1943 if (newSelection.isNone()) | 2074 if (newSelection.isNone()) |
| 1944 return; | 2075 return; |
| 1945 | 2076 |
| 1946 setSelection(newSelection, granularity); | 2077 setSelection(newSelection, granularity); |
| 1947 } | 2078 } |
| 1948 | 2079 |
| 1949 } | 2080 } |
| 1950 | 2081 |
| 1951 #ifndef NDEBUG | 2082 #ifndef NDEBUG |
| 1952 | 2083 |
| 1953 void showTree(const blink::FrameSelection& sel) | 2084 void showTree(const blink::FrameSelection& sel) |
| 1954 { | 2085 { |
| 1955 sel.showTreeForThis(); | 2086 sel.showTreeForThis(); |
| 1956 } | 2087 } |
| 1957 | 2088 |
| 1958 void showTree(const blink::FrameSelection* sel) | 2089 void showTree(const blink::FrameSelection* sel) |
| 1959 { | 2090 { |
| 1960 if (sel) | 2091 if (sel) |
| 1961 sel->showTreeForThis(); | 2092 sel->showTreeForThis(); |
| 1962 } | 2093 } |
| 1963 | 2094 |
| 1964 #endif | 2095 #endif |
| OLD | NEW |