Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(469)

Side by Side Diff: third_party/WebKit/Source/core/layout/ScrollAnchor.cpp

Issue 2404393003: Tie scroll anchoring adjustments to frame lifecycle instead of layout. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/LayoutBlockFlow.h" 9 #include "core/layout/LayoutBlockFlow.h"
10 #include "core/layout/api/LayoutBoxItem.h" 10 #include "core/layout/api/LayoutBoxItem.h"
11 #include "core/layout/line/InlineTextBox.h" 11 #include "core/layout/line/InlineTextBox.h"
12 #include "core/paint/PaintLayer.h" 12 #include "core/paint/PaintLayer.h"
13 #include "core/paint/PaintLayerScrollableArea.h" 13 #include "core/paint/PaintLayerScrollableArea.h"
14 #include "platform/Histogram.h" 14 #include "platform/Histogram.h"
15 15
16 namespace blink { 16 namespace blink {
17 17
18 using Corner = ScrollAnchor::Corner; 18 using Corner = ScrollAnchor::Corner;
19 19
20 ScrollAnchor::ScrollAnchor() 20 ScrollAnchor::ScrollAnchor()
21 : m_anchorObject(nullptr), 21 : m_anchorObject(nullptr),
22 m_corner(Corner::TopLeft), 22 m_corner(Corner::TopLeft),
23 m_scrollAnchorDisablingStyleChanged(false), 23 m_scrollAnchorDisablingStyleChanged(false),
24 m_saved(false) {} 24 m_queued(false) {}
25 25
26 ScrollAnchor::ScrollAnchor(ScrollableArea* scroller) : ScrollAnchor() { 26 ScrollAnchor::ScrollAnchor(ScrollableArea* scroller) : ScrollAnchor() {
27 setScroller(scroller); 27 setScroller(scroller);
28 } 28 }
29 29
30 ScrollAnchor::~ScrollAnchor() {} 30 ScrollAnchor::~ScrollAnchor() {}
31 31
32 void ScrollAnchor::setScroller(ScrollableArea* scroller) { 32 void ScrollAnchor::setScroller(ScrollableArea* scroller) {
33 DCHECK(m_scroller != scroller); 33 DCHECK(m_scroller != scroller);
34 DCHECK(scroller); 34 DCHECK(scroller);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 } 100 }
101 LayoutBox* scrollerBox = scrollerLayoutBox(scroller); 101 LayoutBox* scrollerBox = scrollerLayoutBox(scroller);
102 102
103 LayoutRect relativeBounds = LayoutRect( 103 LayoutRect relativeBounds = LayoutRect(
104 layoutObject->localToAncestorQuad(FloatRect(localBounds), scrollerBox) 104 layoutObject->localToAncestorQuad(FloatRect(localBounds), scrollerBox)
105 .boundingBox()); 105 .boundingBox());
106 // When root layer scrolling is off, the LayoutView will have no scroll 106 // When root layer scrolling is off, the LayoutView will have no scroll
107 // offset (since scrolling is handled by the FrameView) so 107 // offset (since scrolling is handled by the FrameView) so
108 // localToAncestorQuad returns document coords, so we must subtract scroll 108 // localToAncestorQuad returns document coords, so we must subtract scroll
109 // offset to get viewport coords. We discard the fractional part of the 109 // offset to get viewport coords. We discard the fractional part of the
110 // scroll offset so that the rounding in restore() matches the snapping of 110 // scroll offset so that the rounding in adjust() matches the snapping of
111 // the anchor node to the pixel grid of the layer it paints into. For 111 // the anchor node to the pixel grid of the layer it paints into. For
112 // non-FrameView scrollers, we rely on the flooring behavior of 112 // non-FrameView scrollers, we rely on the flooring behavior of
113 // LayoutBox::scrolledContentOffset. 113 // LayoutBox::scrolledContentOffset.
114 if (!RuntimeEnabledFeatures::rootLayerScrollingEnabled() && 114 if (!RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
115 scrollerBox->isLayoutView()) 115 scrollerBox->isLayoutView())
116 relativeBounds.moveBy(IntPoint(-scroller->scrollOffsetInt())); 116 relativeBounds.moveBy(IntPoint(-scroller->scrollOffsetInt()));
117 return relativeBounds; 117 return relativeBounds;
118 } 118 }
119 119
120 static LayoutPoint computeRelativeOffset(const LayoutObject* layoutObject, 120 static LayoutPoint computeRelativeOffset(const LayoutObject* layoutObject,
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 while (true) { 205 while (true) {
206 DCHECK(current); 206 DCHECK(current);
207 if (current->scrollAnchorDisablingStyleChanged()) 207 if (current->scrollAnchorDisablingStyleChanged())
208 return true; 208 return true;
209 if (current == scrollerBox) 209 if (current == scrollerBox)
210 return false; 210 return false;
211 current = current->parent(); 211 current = current->parent();
212 } 212 }
213 } 213 }
214 214
215 void ScrollAnchor::save() { 215 void ScrollAnchor::notifyBeforeLayout() {
216 if (m_saved) 216 if (m_queued) {
217 m_scrollAnchorDisablingStyleChanged |=
218 computeScrollAnchorDisablingStyleChanged();
217 return; 219 return;
218 m_saved = true; 220 }
219 DCHECK(m_scroller); 221 DCHECK(m_scroller);
220 ScrollOffset scrollOffset = m_scroller->scrollOffset(); 222 ScrollOffset scrollOffset = m_scroller->scrollOffset();
221 float blockDirectionScrollOffset = 223 float blockDirectionScrollOffset =
222 scrollerLayoutBox(m_scroller)->isHorizontalWritingMode() 224 scrollerLayoutBox(m_scroller)->isHorizontalWritingMode()
223 ? scrollOffset.height() 225 ? scrollOffset.height()
224 : scrollOffset.width(); 226 : scrollOffset.width();
225 if (blockDirectionScrollOffset == 0) { 227 if (blockDirectionScrollOffset == 0) {
226 clearSelf(); 228 clearSelf();
227 return; 229 return;
228 } 230 }
229 231
230 if (!m_anchorObject) { 232 if (!m_anchorObject) {
231 findAnchor(); 233 findAnchor();
232 if (!m_anchorObject) 234 if (!m_anchorObject)
233 return; 235 return;
234 236
235 m_anchorObject->setIsScrollAnchorObject(); 237 m_anchorObject->setIsScrollAnchorObject();
236 m_savedRelativeOffset = 238 m_savedRelativeOffset =
237 computeRelativeOffset(m_anchorObject, m_scroller, m_corner); 239 computeRelativeOffset(m_anchorObject, m_scroller, m_corner);
238 } 240 }
239 241
240 // Note that we must compute this during save() since the scroller's
241 // descendants have finished layout (and had the bit cleared) by the
242 // time restore() is called.
243 m_scrollAnchorDisablingStyleChanged = 242 m_scrollAnchorDisablingStyleChanged =
244 computeScrollAnchorDisablingStyleChanged(); 243 computeScrollAnchorDisablingStyleChanged();
244
245 FrameView* frameView = scrollerLayoutBox(m_scroller)->frameView();
246 ScrollableArea* owningScroller =
247 m_scroller->isRootFrameViewport()
248 ? &toRootFrameViewport(m_scroller)->layoutViewport()
249 : m_scroller.get();
250 frameView->enqueueScrollAnchoringAdjustment(owningScroller);
ymalik 2016/10/13 13:05:39 I wonder if we should just enqueue m_scroller here
skobes 2016/10/13 17:21:37 I thought about this but it seemed a bit cleaner f
251 m_queued = true;
245 } 252 }
246 253
247 IntSize ScrollAnchor::computeAdjustment() const { 254 IntSize ScrollAnchor::computeAdjustment() const {
248 // The anchor node can report fractional positions, but it is DIP-snapped when 255 // The anchor node can report fractional positions, but it is DIP-snapped when
249 // painting (crbug.com/610805), so we must round the offsets to determine the 256 // painting (crbug.com/610805), so we must round the offsets to determine the
250 // visual delta. If we scroll by the delta in LayoutUnits, the snapping of the 257 // visual delta. If we scroll by the delta in LayoutUnits, the snapping of the
251 // anchor node may round differently from the snapping of the scroll position. 258 // anchor node may round differently from the snapping of the scroll position.
252 // (For example, anchor moving from 2.4px -> 2.6px is really 2px -> 3px, so we 259 // (For example, anchor moving from 2.4px -> 2.6px is really 2px -> 3px, so we
253 // should scroll by 1px instead of 0.2px.) This is true regardless of whether 260 // should scroll by 1px instead of 0.2px.) This is true regardless of whether
254 // the ScrollableArea actually uses fractional scroll positions. 261 // the ScrollableArea actually uses fractional scroll positions.
255 IntSize delta = roundedIntSize(computeRelativeOffset(m_anchorObject, 262 IntSize delta = roundedIntSize(computeRelativeOffset(m_anchorObject,
256 m_scroller, m_corner)) - 263 m_scroller, m_corner)) -
257 roundedIntSize(m_savedRelativeOffset); 264 roundedIntSize(m_savedRelativeOffset);
258 265
259 // Only adjust on the block layout axis. 266 // Only adjust on the block layout axis.
260 if (scrollerLayoutBox(m_scroller)->isHorizontalWritingMode()) 267 if (scrollerLayoutBox(m_scroller)->isHorizontalWritingMode())
261 delta.setWidth(0); 268 delta.setWidth(0);
262 else 269 else
263 delta.setHeight(0); 270 delta.setHeight(0);
264 return delta; 271 return delta;
265 } 272 }
266 273
267 void ScrollAnchor::restore() { 274 void ScrollAnchor::adjust() {
268 if (!m_saved) 275 if (!m_queued)
269 return; 276 return;
270 m_saved = false; 277 m_queued = false;
271 DCHECK(m_scroller); 278 DCHECK(m_scroller);
272 if (!m_anchorObject) 279 if (!m_anchorObject)
273 return; 280 return;
274 IntSize adjustment = computeAdjustment(); 281 IntSize adjustment = computeAdjustment();
275 if (adjustment.isZero()) 282 if (adjustment.isZero())
276 return; 283 return;
277 284
278 if (m_scrollAnchorDisablingStyleChanged) { 285 if (m_scrollAnchorDisablingStyleChanged) {
279 // Note that we only clear if the adjustment would have been non-zero. 286 // Note that we only clear if the adjustment would have been non-zero.
280 // This minimizes redundant calls to findAnchor. 287 // This minimizes redundant calls to findAnchor.
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 bool ScrollAnchor::refersTo(const LayoutObject* layoutObject) const { 341 bool ScrollAnchor::refersTo(const LayoutObject* layoutObject) const {
335 return m_anchorObject == layoutObject; 342 return m_anchorObject == layoutObject;
336 } 343 }
337 344
338 void ScrollAnchor::notifyRemoved(LayoutObject* layoutObject) { 345 void ScrollAnchor::notifyRemoved(LayoutObject* layoutObject) {
339 if (m_anchorObject == layoutObject) 346 if (m_anchorObject == layoutObject)
340 clearSelf(); 347 clearSelf();
341 } 348 }
342 349
343 } // namespace blink 350 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698