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

Side by Side Diff: third_party/WebKit/Source/core/page/scrolling/StickyPositionScrollingConstraints.h

Issue 2961613002: Slightly refactor StickyPositionScrollingConstraints API and add documentation (Closed)
Patch Set: remove accidental file Created 3 years, 5 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 #ifndef StickyPositionScrollingConstraints_h 5 #ifndef StickyPositionScrollingConstraints_h
6 #define StickyPositionScrollingConstraints_h 6 #define StickyPositionScrollingConstraints_h
7 7
8 #include "platform/geometry/FloatRect.h" 8 #include "platform/geometry/FloatRect.h"
9 #include "platform/geometry/FloatSize.h" 9 #include "platform/geometry/FloatSize.h"
10 #include "platform/wtf/HashMap.h" 10 #include "platform/wtf/HashMap.h"
11 11
12 namespace blink { 12 namespace blink {
13 13
14 class LayoutBoxModelObject;
15 class PaintLayer; 14 class PaintLayer;
16 class StickyPositionScrollingConstraints; 15 class StickyPositionScrollingConstraints;
17 16
18 typedef WTF::HashMap<PaintLayer*, StickyPositionScrollingConstraints> 17 typedef WTF::HashMap<PaintLayer*, StickyPositionScrollingConstraints>
19 StickyConstraintsMap; 18 StickyConstraintsMap;
20 19
21 // TODO(smcgruer): Add detailed comment explaining how 20 // Encapsulates the constraint information for a position: sticky element and
22 // StickyPositionScrollingConstraints works. 21 // does calculation of the sticky offset for a given overflow clip rectangle.
22 //
23 // To avoid slowing down scrolling we cannot make the offset calculation a
24 // layout-inducing event. Instead constraint information is cached during layout
25 // and used as the scroll position changes to determine the current offset. In
26 // most cases the only information that is needed is the sticky element's layout
27 // rectangle and it's containing block rectangle (both respective to the nearest
28 // ancestor scroller which the element is sticking to), and the set of sticky
29 // edge constraints (i.e. the distance from each edge the element should stick).
30 //
31 // For a given (non-cached) overflow clip rectangle, calculating the current
32 // offset in most cases just requires sliding the (cached) sticky element
33 // rectangle until it satisfies the (cached) sticky edge constraints for the
34 // overflow clip rectangle, whilst not letting the sticky element rectangle
35 // escape it's (cached) containing block rect.
36 //
37 // Unfortunately this approach breaks down in the presence of nested sticky
38 // elements. For those we apply more complicated logic, which is explained in
39 // the implementation of |ComputeStickyOffset|.
23 class StickyPositionScrollingConstraints final { 40 class StickyPositionScrollingConstraints final {
24 public: 41 public:
25 enum AnchorEdgeFlags { 42 enum AnchorEdgeFlags {
26 kAnchorEdgeLeft = 1 << 0, 43 kAnchorEdgeLeft = 1 << 0,
27 kAnchorEdgeRight = 1 << 1, 44 kAnchorEdgeRight = 1 << 1,
28 kAnchorEdgeTop = 1 << 2, 45 kAnchorEdgeTop = 1 << 2,
29 kAnchorEdgeBottom = 1 << 3 46 kAnchorEdgeBottom = 1 << 3
30 }; 47 };
31 typedef unsigned AnchorEdges; 48 typedef unsigned AnchorEdges;
32 49
33 StickyPositionScrollingConstraints() 50 StickyPositionScrollingConstraints()
34 : anchor_edges_(0), 51 : anchor_edges_(0),
35 left_offset_(0), 52 left_offset_(0),
36 right_offset_(0), 53 right_offset_(0),
37 top_offset_(0), 54 top_offset_(0),
38 bottom_offset_(0), 55 bottom_offset_(0),
39 nearest_sticky_box_shifting_sticky_box_(nullptr), 56 nearest_sticky_layer_shifting_sticky_box_(nullptr),
40 nearest_sticky_box_shifting_containing_block_(nullptr) {} 57 nearest_sticky_layer_shifting_containing_block_(nullptr) {}
41 58
42 StickyPositionScrollingConstraints( 59 StickyPositionScrollingConstraints(
43 const StickyPositionScrollingConstraints& other) 60 const StickyPositionScrollingConstraints& other)
44 : anchor_edges_(other.anchor_edges_), 61 : anchor_edges_(other.anchor_edges_),
45 left_offset_(other.left_offset_), 62 left_offset_(other.left_offset_),
46 right_offset_(other.right_offset_), 63 right_offset_(other.right_offset_),
47 top_offset_(other.top_offset_), 64 top_offset_(other.top_offset_),
48 bottom_offset_(other.bottom_offset_), 65 bottom_offset_(other.bottom_offset_),
49 scroll_container_relative_containing_block_rect_( 66 scroll_container_relative_containing_block_rect_(
50 other.scroll_container_relative_containing_block_rect_), 67 other.scroll_container_relative_containing_block_rect_),
51 scroll_container_relative_sticky_box_rect_( 68 scroll_container_relative_sticky_box_rect_(
52 other.scroll_container_relative_sticky_box_rect_), 69 other.scroll_container_relative_sticky_box_rect_),
53 nearest_sticky_box_shifting_sticky_box_( 70 nearest_sticky_layer_shifting_sticky_box_(
54 other.nearest_sticky_box_shifting_sticky_box_), 71 other.nearest_sticky_layer_shifting_sticky_box_),
55 nearest_sticky_box_shifting_containing_block_( 72 nearest_sticky_layer_shifting_containing_block_(
56 other.nearest_sticky_box_shifting_containing_block_), 73 other.nearest_sticky_layer_shifting_containing_block_),
57 total_sticky_box_sticky_offset_(other.total_sticky_box_sticky_offset_), 74 total_sticky_box_sticky_offset_(other.total_sticky_box_sticky_offset_),
58 total_containing_block_sticky_offset_( 75 total_containing_block_sticky_offset_(
59 other.total_containing_block_sticky_offset_) {} 76 other.total_containing_block_sticky_offset_) {}
60 77
61 FloatSize ComputeStickyOffset( 78 // Computes the sticky offset for a given overflow clip rect.
62 const FloatRect& viewport_rect, 79 //
63 const StickyPositionScrollingConstraints* ancestor_sticky_box_constraints, 80 // This method is non-const as we cache internal state for performance; see
64 const StickyPositionScrollingConstraints* 81 // documentation in the implementation for details.
65 ancestor_containing_block_constraints); 82 FloatSize ComputeStickyOffset(const FloatRect& overflow_clip_rect,
83 const StickyConstraintsMap&);
84
85 // Returns the last-computed offset of the sticky box from its original
86 // position before scroll.
87 //
88 // This method exists for performance (to avoid recomputing the sticky offset)
89 // and must only be called when compositing inputs are clean for the sticky
90 // element. (Or after prepaint for SlimmingPaintV2).
yigu 2017/07/05 19:13:56 Do you need to mention that this method should be
smcgruer 2017/07/06 14:25:37 In patchset 2, flackr asked me to relate this to l
flackr 2017/07/06 14:35:06 That's correct, because the lifecycle is a global
91 FloatSize GetOffsetForStickyPosition(const StickyConstraintsMap&) const;
66 92
67 bool HasAncestorStickyElement() const { 93 bool HasAncestorStickyElement() const {
68 return nearest_sticky_box_shifting_sticky_box_ || 94 return nearest_sticky_layer_shifting_sticky_box_ ||
69 nearest_sticky_box_shifting_containing_block_; 95 nearest_sticky_layer_shifting_containing_block_;
70 } 96 }
71 97
72 AnchorEdges GetAnchorEdges() const { return anchor_edges_; } 98 AnchorEdges GetAnchorEdges() const { return anchor_edges_; }
73 bool HasAnchorEdge(AnchorEdgeFlags flag) const { 99 bool HasAnchorEdge(AnchorEdgeFlags flag) const {
74 return anchor_edges_ & flag; 100 return anchor_edges_ & flag;
75 } 101 }
76 void AddAnchorEdge(AnchorEdgeFlags edge_flag) { anchor_edges_ |= edge_flag; } 102 void AddAnchorEdge(AnchorEdgeFlags edge_flag) { anchor_edges_ |= edge_flag; }
77 void SetAnchorEdges(AnchorEdges edges) { anchor_edges_ = edges; }
78 103
79 float LeftOffset() const { return left_offset_; } 104 float LeftOffset() const { return left_offset_; }
80 float RightOffset() const { return right_offset_; } 105 float RightOffset() const { return right_offset_; }
81 float TopOffset() const { return top_offset_; } 106 float TopOffset() const { return top_offset_; }
82 float BottomOffset() const { return bottom_offset_; } 107 float BottomOffset() const { return bottom_offset_; }
83 108
84 void SetLeftOffset(float offset) { left_offset_ = offset; } 109 void SetLeftOffset(float offset) { left_offset_ = offset; }
85 void SetRightOffset(float offset) { right_offset_ = offset; } 110 void SetRightOffset(float offset) { right_offset_ = offset; }
86 void SetTopOffset(float offset) { top_offset_ = offset; } 111 void SetTopOffset(float offset) { top_offset_ = offset; }
87 void SetBottomOffset(float offset) { bottom_offset_ = offset; } 112 void SetBottomOffset(float offset) { bottom_offset_ = offset; }
88 113
89 void SetScrollContainerRelativeContainingBlockRect(const FloatRect& rect) { 114 void SetScrollContainerRelativeContainingBlockRect(const FloatRect& rect) {
90 scroll_container_relative_containing_block_rect_ = rect; 115 scroll_container_relative_containing_block_rect_ = rect;
91 } 116 }
92 const FloatRect& ScrollContainerRelativeContainingBlockRect() const { 117 const FloatRect& ScrollContainerRelativeContainingBlockRect() const {
93 return scroll_container_relative_containing_block_rect_; 118 return scroll_container_relative_containing_block_rect_;
94 } 119 }
95 120
96 void SetScrollContainerRelativeStickyBoxRect(const FloatRect& rect) { 121 void SetScrollContainerRelativeStickyBoxRect(const FloatRect& rect) {
97 scroll_container_relative_sticky_box_rect_ = rect; 122 scroll_container_relative_sticky_box_rect_ = rect;
98 } 123 }
99 const FloatRect& ScrollContainerRelativeStickyBoxRect() const { 124 const FloatRect& ScrollContainerRelativeStickyBoxRect() const {
100 return scroll_container_relative_sticky_box_rect_; 125 return scroll_container_relative_sticky_box_rect_;
101 } 126 }
102 127
103 void SetNearestStickyBoxShiftingStickyBox(LayoutBoxModelObject* layer) { 128 void SetNearestStickyLayerShiftingStickyBox(PaintLayer* layer) {
104 nearest_sticky_box_shifting_sticky_box_ = layer; 129 nearest_sticky_layer_shifting_sticky_box_ = layer;
105 } 130 }
106 LayoutBoxModelObject* NearestStickyBoxShiftingStickyBox() const { 131 PaintLayer* NearestStickyLayerShiftingStickyBox() const {
107 return nearest_sticky_box_shifting_sticky_box_; 132 return nearest_sticky_layer_shifting_sticky_box_;
108 } 133 }
109 134
110 void SetNearestStickyBoxShiftingContainingBlock(LayoutBoxModelObject* layer) { 135 void SetNearestStickyLayerShiftingContainingBlock(PaintLayer* layer) {
111 nearest_sticky_box_shifting_containing_block_ = layer; 136 nearest_sticky_layer_shifting_containing_block_ = layer;
112 } 137 }
113 LayoutBoxModelObject* NearestStickyBoxShiftingContainingBlock() const { 138 PaintLayer* NearestStickyLayerShiftingContainingBlock() const {
114 return nearest_sticky_box_shifting_containing_block_; 139 return nearest_sticky_layer_shifting_containing_block_;
115 }
116
117 const FloatSize& GetTotalStickyBoxStickyOffset() const {
118 return total_sticky_box_sticky_offset_;
119 }
120 const FloatSize& GetTotalContainingBlockStickyOffset() const {
121 return total_containing_block_sticky_offset_;
122 }
123
124 // Returns the relative position of the sticky box and its original position
125 // before scroll. This method is only safe to call if ComputeStickyOffset has
126 // been invoked.
127 FloatSize GetOffsetForStickyPosition(const StickyConstraintsMap&) const;
128
129 const LayoutBoxModelObject* NearestStickyAncestor() const {
130 // If we have one or more sticky ancestor elements between ourselves and our
131 // containing block, |m_nearestStickyBoxShiftingStickyBox| points to the
132 // closest. Otherwise, |m_nearestStickyBoxShiftingContainingBlock| points
133 // to the the first sticky ancestor between our containing block (inclusive)
134 // and our scroll ancestor (exclusive). Therefore our nearest sticky
135 // ancestor is the former if it exists, or the latter otherwise.
136 //
137 // If both are null, then we have no sticky ancestors before our scroll
138 // ancestor, so the correct action is to return null.
139 return nearest_sticky_box_shifting_sticky_box_
140 ? nearest_sticky_box_shifting_sticky_box_
141 : nearest_sticky_box_shifting_containing_block_;
142 } 140 }
143 141
144 bool operator==(const StickyPositionScrollingConstraints& other) const { 142 bool operator==(const StickyPositionScrollingConstraints& other) const {
145 return left_offset_ == other.left_offset_ && 143 return left_offset_ == other.left_offset_ &&
146 right_offset_ == other.right_offset_ && 144 right_offset_ == other.right_offset_ &&
147 top_offset_ == other.top_offset_ && 145 top_offset_ == other.top_offset_ &&
148 bottom_offset_ == other.bottom_offset_ && 146 bottom_offset_ == other.bottom_offset_ &&
149 scroll_container_relative_containing_block_rect_ == 147 scroll_container_relative_containing_block_rect_ ==
150 other.scroll_container_relative_containing_block_rect_ && 148 other.scroll_container_relative_containing_block_rect_ &&
151 scroll_container_relative_sticky_box_rect_ == 149 scroll_container_relative_sticky_box_rect_ ==
152 other.scroll_container_relative_sticky_box_rect_ && 150 other.scroll_container_relative_sticky_box_rect_ &&
153 nearest_sticky_box_shifting_sticky_box_ == 151 nearest_sticky_layer_shifting_sticky_box_ ==
154 other.nearest_sticky_box_shifting_sticky_box_ && 152 other.nearest_sticky_layer_shifting_sticky_box_ &&
155 nearest_sticky_box_shifting_containing_block_ == 153 nearest_sticky_layer_shifting_containing_block_ ==
156 other.nearest_sticky_box_shifting_containing_block_ && 154 other.nearest_sticky_layer_shifting_containing_block_ &&
157 total_sticky_box_sticky_offset_ == 155 total_sticky_box_sticky_offset_ ==
158 other.total_sticky_box_sticky_offset_ && 156 other.total_sticky_box_sticky_offset_ &&
159 total_containing_block_sticky_offset_ == 157 total_containing_block_sticky_offset_ ==
160 other.total_containing_block_sticky_offset_; 158 other.total_containing_block_sticky_offset_;
161 } 159 }
162 160
163 bool operator!=(const StickyPositionScrollingConstraints& other) const { 161 bool operator!=(const StickyPositionScrollingConstraints& other) const {
164 return !(*this == other); 162 return !(*this == other);
165 } 163 }
166 164
167 private: 165 private:
166 FloatSize AncestorStickyBoxOffset(const StickyConstraintsMap&);
167 FloatSize AncestorContainingBlockOffset(const StickyConstraintsMap&);
168
168 AnchorEdges anchor_edges_; 169 AnchorEdges anchor_edges_;
169 float left_offset_; 170 float left_offset_;
170 float right_offset_; 171 float right_offset_;
171 float top_offset_; 172 float top_offset_;
172 float bottom_offset_; 173 float bottom_offset_;
174
175 // The layout position of the sticky element's containing block rectangle,
176 // relative to the scroll container. When calculating the sticky offset it is
177 // used to ensure the sticky element stays bounded by it's containing block.
173 FloatRect scroll_container_relative_containing_block_rect_; 178 FloatRect scroll_container_relative_containing_block_rect_;
179
180 // The layout position of the sticky element. When calculating the sticky
181 // offset it is used to determine how large the offset needs to be to satisfy
182 // the sticky constraints.
174 FloatRect scroll_container_relative_sticky_box_rect_; 183 FloatRect scroll_container_relative_sticky_box_rect_;
175 184
176 // In order to properly compute the stickyOffset, we need to know if we have 185 // In the case of nested sticky elements the layout position of the sticky
177 // any sticky ancestors both between ourselves and our containing block and 186 // element and it's containing block are not accurate (as they are affected by
178 // between our containing block and the viewport. These ancestors are needed 187 // ancestor sticky offsets). To ensure a correct sticky offset calculation in
179 // to properly shift our constraining rects with regards to the containing 188 // that case we must track any sticky ancestors between the sticky element and
180 // block and viewport. 189 // it's containing block, and between it's containing block and the overflow
181 LayoutBoxModelObject* nearest_sticky_box_shifting_sticky_box_; 190 // clip ancestor.
182 LayoutBoxModelObject* nearest_sticky_box_shifting_containing_block_; 191 //
192 // See the implementation of |ComputeStickyOffset| for documentation on how
193 // these ancestors are used to correct the offset calculation.
194 PaintLayer* nearest_sticky_layer_shifting_sticky_box_;
195 PaintLayer* nearest_sticky_layer_shifting_containing_block_;
183 196
184 // For performance we cache our accumulated sticky offset to allow descendant 197 // For performance we cache our accumulated sticky offset to allow descendant
185 // sticky elements to offset their constraint rects. Because we can either 198 // sticky elements to offset their constraint rects. Because we can either
186 // affect the sticky box constraint rect or the containing block constraint 199 // affect the sticky box constraint rect or the containing block constraint
187 // rect, we need to accumulate both. 200 // rect, we need to accumulate both.
188 // 201 //
189 // The case where we can affect both the sticky box constraint rect and the 202 // The case where we can affect both the sticky box constraint rect and the
190 // constraining block constriant rect for different sticky descendants is 203 // constraining block constriant rect for different sticky descendants is
191 // quite complex. See the StickyPositionComplexTableNesting test in 204 // quite complex. See the StickyPositionComplexTableNesting test in
192 // LayoutBoxModelObjectTest.cpp. 205 // LayoutBoxModelObjectTest.cpp.
193 FloatSize total_sticky_box_sticky_offset_; 206 FloatSize total_sticky_box_sticky_offset_;
194 FloatSize total_containing_block_sticky_offset_; 207 FloatSize total_containing_block_sticky_offset_;
195 }; 208 };
196 209
197 } // namespace blink 210 } // namespace blink
198 211
199 #endif // StickyPositionScrollingConstraints_h 212 #endif // StickyPositionScrollingConstraints_h
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698