OLD | NEW |
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 "core/layout/ScrollAnchor.h" | 5 #include "core/layout/ScrollAnchor.h" |
6 | 6 |
7 #include "core/frame/FrameView.h" | 7 #include "core/frame/FrameView.h" |
8 #include "core/frame/UseCounter.h" | 8 #include "core/frame/UseCounter.h" |
9 #include "core/layout/line/InlineTextBox.h" | 9 #include "core/layout/line/InlineTextBox.h" |
10 #include "core/paint/PaintLayerScrollableArea.h" | 10 #include "core/paint/PaintLayerScrollableArea.h" |
11 #include "platform/Histogram.h" | 11 #include "platform/Histogram.h" |
12 | 12 |
13 namespace blink { | 13 namespace blink { |
14 | 14 |
15 using Corner = ScrollAnchor::Corner; | 15 using Corner = ScrollAnchor::Corner; |
16 | 16 |
| 17 static const int kMaxAdjustments = 20; |
| 18 |
17 ScrollAnchor::ScrollAnchor(ScrollableArea* scroller) | 19 ScrollAnchor::ScrollAnchor(ScrollableArea* scroller) |
18 : m_scroller(scroller) | 20 : m_scroller(scroller) |
19 , m_hasBounced(false) | 21 , m_hasBounced(false) |
| 22 , m_adjustmentCount(0) |
20 { | 23 { |
21 ASSERT(m_scroller); | 24 ASSERT(m_scroller); |
22 ASSERT(m_scroller->isFrameView() || m_scroller->isPaintLayerScrollableArea()
); | 25 ASSERT(m_scroller->isFrameView() || m_scroller->isPaintLayerScrollableArea()
); |
23 } | 26 } |
24 | 27 |
25 ScrollAnchor::~ScrollAnchor() | 28 ScrollAnchor::~ScrollAnchor() |
26 { | 29 { |
27 } | 30 } |
28 | 31 |
29 // TODO(pilgrim) replace all instances of scrollerLayoutBox with scrollerLayoutB
oxItem | 32 // TODO(pilgrim) replace all instances of scrollerLayoutBox with scrollerLayoutB
oxItem |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 if (adjustment.isZero()) | 247 if (adjustment.isZero()) |
245 return; | 248 return; |
246 if (adjustment == -m_lastAdjustment && m_hasBounced) { | 249 if (adjustment == -m_lastAdjustment && m_hasBounced) { |
247 // Don't bounce more than once. | 250 // Don't bounce more than once. |
248 clear(); | 251 clear(); |
249 m_hasBounced = false; | 252 m_hasBounced = false; |
250 m_lastAdjustment = IntSize(); | 253 m_lastAdjustment = IntSize(); |
251 m_lastAdjusted.clear(); | 254 m_lastAdjusted.clear(); |
252 return; | 255 return; |
253 } | 256 } |
254 adjust(adjustment); | 257 // We impose a limit on the number of adjustments between user scrolls, to |
| 258 // mitigate the impact of pathological feedback loops with event handlers. |
| 259 if (++m_adjustmentCount <= kMaxAdjustments) |
| 260 adjust(adjustment); |
255 } | 261 } |
256 | 262 |
257 void ScrollAnchor::adjust(IntSize adjustment) | 263 void ScrollAnchor::adjust(IntSize adjustment) |
258 { | 264 { |
259 m_scroller->scrollAnimator().adjustAnimationAndSetScrollPosition(adjustment,
AnchoringScroll); | 265 m_scroller->scrollAnimator().adjustAnimationAndSetScrollPosition(adjustment,
AnchoringScroll); |
260 | 266 |
261 if (m_current && m_lastAdjusted.m_anchorObject != m_current.m_anchorObject)
{ | 267 if (m_current && m_lastAdjusted.m_anchorObject != m_current.m_anchorObject)
{ |
262 m_lastAdjusted.clear(); | 268 m_lastAdjusted.clear(); |
263 m_lastAdjusted = m_current; | 269 m_lastAdjusted = m_current; |
264 } | 270 } |
265 m_hasBounced = (m_lastAdjustment == -adjustment); | 271 m_hasBounced = (m_lastAdjustment == -adjustment); |
266 m_lastAdjustment = adjustment; | 272 m_lastAdjustment = adjustment; |
267 | 273 |
268 // Update UMA metric. | 274 // Update UMA metric. |
269 DEFINE_STATIC_LOCAL(EnumerationHistogram, adjustedOffsetHistogram, | 275 DEFINE_STATIC_LOCAL(EnumerationHistogram, adjustedOffsetHistogram, |
270 ("Layout.ScrollAnchor.AdjustedScrollOffset", 2)); | 276 ("Layout.ScrollAnchor.AdjustedScrollOffset", 2)); |
271 adjustedOffsetHistogram.count(1); | 277 adjustedOffsetHistogram.count(1); |
272 UseCounter::count(scrollerLayoutBox(m_scroller)->document(), UseCounter::Scr
ollAnchored); | 278 UseCounter::count(scrollerLayoutBox(m_scroller)->document(), UseCounter::Scr
ollAnchored); |
273 } | 279 } |
274 | 280 |
275 void ScrollAnchor::clear() | 281 void ScrollAnchor::clear() |
276 { | 282 { |
| 283 m_adjustmentCount = 0; |
277 m_current.clear(); | 284 m_current.clear(); |
278 } | 285 } |
279 | 286 |
280 void ScrollAnchor::AnchorPoint::clear() | 287 void ScrollAnchor::AnchorPoint::clear() |
281 { | 288 { |
282 LayoutObject* anchorObject = m_anchorObject; | 289 LayoutObject* anchorObject = m_anchorObject; |
283 m_anchorObject = nullptr; | 290 m_anchorObject = nullptr; |
284 | 291 |
285 if (anchorObject) | 292 if (anchorObject) |
286 anchorObject->maybeClearIsScrollAnchorObject(); | 293 anchorObject->maybeClearIsScrollAnchorObject(); |
287 } | 294 } |
288 | 295 |
289 bool ScrollAnchor::refersTo(const LayoutObject* layoutObject) const | 296 bool ScrollAnchor::refersTo(const LayoutObject* layoutObject) const |
290 { | 297 { |
291 return m_current.m_anchorObject == layoutObject | 298 return m_current.m_anchorObject == layoutObject |
292 || m_lastAdjusted.m_anchorObject == layoutObject; | 299 || m_lastAdjusted.m_anchorObject == layoutObject; |
293 } | 300 } |
294 | 301 |
295 void ScrollAnchor::notifyRemoved(LayoutObject* layoutObject) | 302 void ScrollAnchor::notifyRemoved(LayoutObject* layoutObject) |
296 { | 303 { |
297 if (m_current.m_anchorObject == layoutObject) | 304 if (m_current.m_anchorObject == layoutObject) |
298 m_current.clear(); | 305 m_current.clear(); |
299 if (m_lastAdjusted.m_anchorObject == layoutObject) | 306 if (m_lastAdjusted.m_anchorObject == layoutObject) |
300 m_lastAdjusted.clear(); | 307 m_lastAdjusted.clear(); |
301 } | 308 } |
302 | 309 |
303 } // namespace blink | 310 } // namespace blink |
OLD | NEW |