| 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; | 17 static const int kMaxAdjustments = 20; |
| 18 | 18 |
| 19 ScrollAnchor::ScrollAnchor() | 19 ScrollAnchor::ScrollAnchor() |
| 20 : m_hasBounced(false) | 20 : m_hasBounced(false) |
| 21 , m_adjustmentCount(0) | 21 , m_adjustmentCount(0) |
| 22 , m_anyAncestorChangedPaddingOrMargin(false) |
| 22 { | 23 { |
| 23 } | 24 } |
| 24 | 25 |
| 25 ScrollAnchor::ScrollAnchor(ScrollableArea* scroller) | 26 ScrollAnchor::ScrollAnchor(ScrollableArea* scroller) |
| 26 : ScrollAnchor() | 27 : ScrollAnchor() |
| 27 { | 28 { |
| 28 setScroller(scroller); | 29 setScroller(scroller); |
| 29 } | 30 } |
| 30 | 31 |
| 31 ScrollAnchor::~ScrollAnchor() | 32 ScrollAnchor::~ScrollAnchor() |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 } | 193 } |
| 193 } | 194 } |
| 194 | 195 |
| 195 void ScrollAnchor::save() | 196 void ScrollAnchor::save() |
| 196 { | 197 { |
| 197 DCHECK(m_scroller); | 198 DCHECK(m_scroller); |
| 198 if (m_scroller->scrollPosition() == IntPoint::zero()) { | 199 if (m_scroller->scrollPosition() == IntPoint::zero()) { |
| 199 clear(); | 200 clear(); |
| 200 return; | 201 return; |
| 201 } | 202 } |
| 202 if (m_current) | 203 |
| 204 if (m_current) { |
| 205 m_anyAncestorChangedPaddingOrMargin = paddingOrBorderChanged(); |
| 203 return; | 206 return; |
| 207 } |
| 204 | 208 |
| 205 findAnchor(); | 209 findAnchor(); |
| 206 if (!m_current) | 210 if (!m_current) |
| 207 return; | 211 return; |
| 208 | 212 |
| 213 m_anyAncestorChangedPaddingOrMargin = paddingOrBorderChanged(); |
| 214 |
| 209 m_current.m_anchorObject->setIsScrollAnchorObject(); | 215 m_current.m_anchorObject->setIsScrollAnchorObject(); |
| 210 m_current.m_savedRelativeOffset = computeRelativeOffset( | 216 m_current.m_savedRelativeOffset = computeRelativeOffset( |
| 211 m_current.m_anchorObject, m_scroller, m_current.m_corner); | 217 m_current.m_anchorObject, m_scroller, m_current.m_corner); |
| 212 | 218 |
| 213 if (m_lastAdjusted) { | 219 if (m_lastAdjusted) { |
| 214 // We need to update m_lastAdjusted.m_savedRelativeOffset, since it is | 220 // We need to update m_lastAdjusted.m_savedRelativeOffset, since it is |
| 215 // relative to the visible rect and the user may have scrolled since the | 221 // relative to the visible rect and the user may have scrolled since the |
| 216 // last adjustment. | 222 // last adjustment. |
| 217 if (!candidateMayMoveWithScroller(m_lastAdjusted.m_anchorObject, m_scrol
ler)) { | 223 if (!candidateMayMoveWithScroller(m_lastAdjusted.m_anchorObject, m_scrol
ler)) { |
| 218 m_lastAdjusted.clear(); | 224 m_lastAdjusted.clear(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 233 // visual delta. If we scroll by the delta in LayoutUnits, the snapping of t
he | 239 // visual delta. If we scroll by the delta in LayoutUnits, the snapping of t
he |
| 234 // anchor node may round differently from the snapping of the scroll positio
n. | 240 // anchor node may round differently from the snapping of the scroll positio
n. |
| 235 // (For example, anchor moving from 2.4px -> 2.6px is really 2px -> 3px, so
we | 241 // (For example, anchor moving from 2.4px -> 2.6px is really 2px -> 3px, so
we |
| 236 // should scroll by 1px instead of 0.2px.) This is true regardless of whethe
r | 242 // should scroll by 1px instead of 0.2px.) This is true regardless of whethe
r |
| 237 // the ScrollableArea actually uses fractional scroll positions. | 243 // the ScrollableArea actually uses fractional scroll positions. |
| 238 return roundedIntSize(computeRelativeOffset( | 244 return roundedIntSize(computeRelativeOffset( |
| 239 anchorPoint.m_anchorObject, m_scroller, anchorPoint.m_corner)) - | 245 anchorPoint.m_anchorObject, m_scroller, anchorPoint.m_corner)) - |
| 240 roundedIntSize(anchorPoint.m_savedRelativeOffset); | 246 roundedIntSize(anchorPoint.m_savedRelativeOffset); |
| 241 } | 247 } |
| 242 | 248 |
| 249 bool ScrollAnchor::paddingOrBorderChanged() const |
| 250 { |
| 251 LayoutObject* current = anchorObject(); |
| 252 while (current && current != scrollerLayoutBox(m_scroller)) { |
| 253 if (current->isLayoutBlock() |
| 254 && (toLayoutBlock(current)->heightAvailableToChildrenChanged())) |
| 255 return true; |
| 256 current = current->parent(); |
| 257 } |
| 258 return false; |
| 259 } |
| 260 |
| 243 void ScrollAnchor::restore() | 261 void ScrollAnchor::restore() |
| 244 { | 262 { |
| 245 DCHECK(m_scroller); | 263 DCHECK(m_scroller); |
| 246 if (m_lastAdjusted && m_lastAdjusted.m_anchorObject != m_current.m_anchorObj
ect | 264 if (m_lastAdjusted && m_lastAdjusted.m_anchorObject != m_current.m_anchorObj
ect |
| 247 && !m_hasBounced && computeAdjustment(m_lastAdjusted) == -m_lastAdjustme
nt) { | 265 && !m_hasBounced && computeAdjustment(m_lastAdjusted) == -m_lastAdjustme
nt) { |
| 248 // If previous anchor point has bounced, follow the bounce. | 266 // If previous anchor point has bounced, follow the bounce. |
| 249 clear(); | 267 clear(); |
| 250 adjust(-m_lastAdjustment); | 268 adjust(-m_lastAdjustment); |
| 251 return; | 269 return; |
| 252 } | 270 } |
| 271 |
| 253 if (!m_current) | 272 if (!m_current) |
| 254 return; | 273 return; |
| 274 |
| 275 // Authors often change the padding or margin when trying to simulate |
| 276 // position:sticky on headers. Use this as a heuristic to disable scroll |
| 277 // anchoring so that we don't conflict with JS changes. |
| 278 // TODO(ymalik): Does this change allow us to remove the de-bouncing hack? |
| 279 if (m_anyAncestorChangedPaddingOrMargin) { |
| 280 clear(); |
| 281 return; |
| 282 } |
| 283 |
| 255 IntSize adjustment = computeAdjustment(m_current); | 284 IntSize adjustment = computeAdjustment(m_current); |
| 256 if (adjustment.isZero()) | 285 if (adjustment.isZero()) |
| 257 return; | 286 return; |
| 287 |
| 258 if (adjustment == -m_lastAdjustment && m_hasBounced) { | 288 if (adjustment == -m_lastAdjustment && m_hasBounced) { |
| 259 // Don't bounce more than once. | 289 // Don't bounce more than once. |
| 260 clear(); | 290 clear(); |
| 261 m_hasBounced = false; | 291 m_hasBounced = false; |
| 262 m_lastAdjustment = IntSize(); | 292 m_lastAdjustment = IntSize(); |
| 263 m_lastAdjusted.clear(); | 293 m_lastAdjusted.clear(); |
| 264 return; | 294 return; |
| 265 } | 295 } |
| 266 // We impose a limit on the number of adjustments between user scrolls, to | 296 // We impose a limit on the number of adjustments between user scrolls, to |
| 267 // mitigate the impact of pathological feedback loops with event handlers. | 297 // mitigate the impact of pathological feedback loops with event handlers. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 | 340 |
| 311 void ScrollAnchor::notifyRemoved(LayoutObject* layoutObject) | 341 void ScrollAnchor::notifyRemoved(LayoutObject* layoutObject) |
| 312 { | 342 { |
| 313 if (m_current.m_anchorObject == layoutObject) | 343 if (m_current.m_anchorObject == layoutObject) |
| 314 m_current.clear(); | 344 m_current.clear(); |
| 315 if (m_lastAdjusted.m_anchorObject == layoutObject) | 345 if (m_lastAdjusted.m_anchorObject == layoutObject) |
| 316 m_lastAdjusted.clear(); | 346 m_lastAdjusted.clear(); |
| 317 } | 347 } |
| 318 | 348 |
| 319 } // namespace blink | 349 } // namespace blink |
| OLD | NEW |