Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 #include "core/page/scrolling/StickyPositionScrollingConstraints.h" | 5 #include "core/page/scrolling/StickyPositionScrollingConstraints.h" |
| 6 #include "core/paint/PaintLayer.h" | 6 #include "core/paint/PaintLayer.h" |
| 7 | 7 |
| 8 namespace blink { | 8 namespace blink { |
| 9 | 9 |
| 10 FloatSize StickyPositionScrollingConstraints::ComputeStickyOffset( | 10 FloatSize StickyPositionScrollingConstraints::ComputeStickyOffset( |
| 11 const FloatRect& viewport_rect, | 11 const FloatRect& overflow_clip_rect, |
| 12 const StickyPositionScrollingConstraints* ancestor_sticky_box_constraints, | 12 const StickyConstraintsMap& constraints_map) { |
| 13 const StickyPositionScrollingConstraints* | |
| 14 ancestor_containing_block_constraints) { | |
| 15 // Adjust the constraint rect locations based on our ancestor sticky elements | |
| 16 // These adjustments are necessary to avoid double offsetting in the case of | |
| 17 // nested sticky elements. | |
| 18 FloatSize ancestor_sticky_box_offset = | |
| 19 ancestor_sticky_box_constraints | |
| 20 ? ancestor_sticky_box_constraints->GetTotalStickyBoxStickyOffset() | |
| 21 : FloatSize(); | |
| 22 FloatSize ancestor_containing_block_offset = | |
| 23 ancestor_containing_block_constraints | |
| 24 ? ancestor_containing_block_constraints | |
| 25 ->GetTotalContainingBlockStickyOffset() | |
| 26 : FloatSize(); | |
| 27 FloatRect sticky_box_rect = scroll_container_relative_sticky_box_rect_; | 13 FloatRect sticky_box_rect = scroll_container_relative_sticky_box_rect_; |
| 28 FloatRect containing_block_rect = | 14 FloatRect containing_block_rect = |
| 29 scroll_container_relative_containing_block_rect_; | 15 scroll_container_relative_containing_block_rect_; |
| 16 FloatSize ancestor_sticky_box_offset = | |
| 17 AncestorStickyBoxOffset(constraints_map); | |
| 18 FloatSize ancestor_containing_block_offset = | |
| 19 AncestorContainingBlockOffset(constraints_map); | |
| 20 | |
| 21 // Adjust the cached rect locations for any sticky ancestor elements. The | |
| 22 // sticky offset applied to those ancestors affects us as follows: | |
| 23 // | |
| 24 // 1. |nearest_sticky_layer_shifting_sticky_box_| is a sticky layer between | |
| 25 // ourselves and our containing block, e.g. an inline parent. As such, | |
| 26 // it shifts only the sticky_box_rect, and not the containing_block_rect. | |
| 27 // 2. |nearest_sticky_layer_shifting_containing_block_| is a sticky layer | |
| 28 // between our containing block (inclusive) and our scroll ancestor | |
| 29 // (exclusive). As such, it shifts both the sticky_box_rect and the | |
| 30 // containing_block_rect. | |
| 31 // | |
| 32 // Note that this calculation assumes that |ComputeStickyOffset| is being | |
| 33 // called top down, e.g. it has been called on any ancestors we have before | |
| 34 // being called on us. | |
| 30 sticky_box_rect.Move(ancestor_sticky_box_offset + | 35 sticky_box_rect.Move(ancestor_sticky_box_offset + |
| 31 ancestor_containing_block_offset); | 36 ancestor_containing_block_offset); |
| 32 containing_block_rect.Move(ancestor_containing_block_offset); | 37 containing_block_rect.Move(ancestor_containing_block_offset); |
| 33 | 38 |
| 39 // We now attempt to shift sticky_box_rect to obey the specified sticky | |
| 40 // constraints, whilst always staying within our containing block. This | |
| 41 // shifting produces the final sticky offset below. | |
| 42 // | |
| 43 // As per the spec, 'left' overrides 'right' and 'top' overrides 'bottom'. | |
| 34 FloatRect box_rect = sticky_box_rect; | 44 FloatRect box_rect = sticky_box_rect; |
| 35 | 45 |
| 36 if (HasAnchorEdge(kAnchorEdgeRight)) { | 46 if (HasAnchorEdge(kAnchorEdgeRight)) { |
| 37 float right_limit = viewport_rect.MaxX() - right_offset_; | 47 float right_limit = overflow_clip_rect.MaxX() - right_offset_; |
| 38 float right_delta = | 48 float right_delta = |
| 39 std::min<float>(0, right_limit - sticky_box_rect.MaxX()); | 49 std::min<float>(0, right_limit - sticky_box_rect.MaxX()); |
| 40 float available_space = | 50 float available_space = |
| 41 std::min<float>(0, containing_block_rect.X() - sticky_box_rect.X()); | 51 std::min<float>(0, containing_block_rect.X() - sticky_box_rect.X()); |
| 42 if (right_delta < available_space) | 52 if (right_delta < available_space) |
| 43 right_delta = available_space; | 53 right_delta = available_space; |
| 44 | 54 |
| 45 box_rect.Move(right_delta, 0); | 55 box_rect.Move(right_delta, 0); |
| 46 } | 56 } |
| 47 | 57 |
| 48 if (HasAnchorEdge(kAnchorEdgeLeft)) { | 58 if (HasAnchorEdge(kAnchorEdgeLeft)) { |
| 49 float left_limit = viewport_rect.X() + left_offset_; | 59 float left_limit = overflow_clip_rect.X() + left_offset_; |
| 50 float left_delta = std::max<float>(0, left_limit - sticky_box_rect.X()); | 60 float left_delta = std::max<float>(0, left_limit - sticky_box_rect.X()); |
| 51 float available_space = std::max<float>( | 61 float available_space = std::max<float>( |
| 52 0, containing_block_rect.MaxX() - sticky_box_rect.MaxX()); | 62 0, containing_block_rect.MaxX() - sticky_box_rect.MaxX()); |
| 53 if (left_delta > available_space) | 63 if (left_delta > available_space) |
| 54 left_delta = available_space; | 64 left_delta = available_space; |
| 55 | 65 |
| 56 box_rect.Move(left_delta, 0); | 66 box_rect.Move(left_delta, 0); |
| 57 } | 67 } |
| 58 | 68 |
| 59 if (HasAnchorEdge(kAnchorEdgeBottom)) { | 69 if (HasAnchorEdge(kAnchorEdgeBottom)) { |
| 60 float bottom_limit = viewport_rect.MaxY() - bottom_offset_; | 70 float bottom_limit = overflow_clip_rect.MaxY() - bottom_offset_; |
| 61 float bottom_delta = | 71 float bottom_delta = |
| 62 std::min<float>(0, bottom_limit - sticky_box_rect.MaxY()); | 72 std::min<float>(0, bottom_limit - sticky_box_rect.MaxY()); |
| 63 float available_space = | 73 float available_space = |
| 64 std::min<float>(0, containing_block_rect.Y() - sticky_box_rect.Y()); | 74 std::min<float>(0, containing_block_rect.Y() - sticky_box_rect.Y()); |
| 65 if (bottom_delta < available_space) | 75 if (bottom_delta < available_space) |
| 66 bottom_delta = available_space; | 76 bottom_delta = available_space; |
| 67 | 77 |
| 68 box_rect.Move(0, bottom_delta); | 78 box_rect.Move(0, bottom_delta); |
| 69 } | 79 } |
| 70 | 80 |
| 71 if (HasAnchorEdge(kAnchorEdgeTop)) { | 81 if (HasAnchorEdge(kAnchorEdgeTop)) { |
| 72 float top_limit = viewport_rect.Y() + top_offset_; | 82 float top_limit = overflow_clip_rect.Y() + top_offset_; |
| 73 float top_delta = std::max<float>(0, top_limit - sticky_box_rect.Y()); | 83 float top_delta = std::max<float>(0, top_limit - sticky_box_rect.Y()); |
| 74 float available_space = std::max<float>( | 84 float available_space = std::max<float>( |
| 75 0, containing_block_rect.MaxY() - sticky_box_rect.MaxY()); | 85 0, containing_block_rect.MaxY() - sticky_box_rect.MaxY()); |
| 76 if (top_delta > available_space) | 86 if (top_delta > available_space) |
| 77 top_delta = available_space; | 87 top_delta = available_space; |
| 78 | 88 |
| 79 box_rect.Move(0, top_delta); | 89 box_rect.Move(0, top_delta); |
| 80 } | 90 } |
| 81 | 91 |
| 82 FloatSize sticky_offset = box_rect.Location() - sticky_box_rect.Location(); | 92 FloatSize sticky_offset = box_rect.Location() - sticky_box_rect.Location(); |
| 83 | 93 |
| 94 // For performance, we cache our accumulated sticky offsets for any descendant | |
| 95 // sticky to use in it's own |ComputeStickyOffset| call. If these were not | |
| 96 // cached, one would instead need to call |ComputeStickyOffset| on every | |
| 97 // sticky ancestor in turn, accumulating the results. | |
| 98 | |
| 99 // TODO(smcgruer): Document why these are calculated like this and why the two | |
| 100 // different members are necessary. | |
|
flackr
2017/06/30 02:48:35
There's some comments in the header file for these
smcgruer
2017/07/07 13:51:58
Done.
flackr
2017/07/19 17:13:34
Sorry, to be specific I meant augment the document
smcgruer
2017/07/20 19:25:08
Done.
| |
| 84 total_sticky_box_sticky_offset_ = ancestor_sticky_box_offset + sticky_offset; | 101 total_sticky_box_sticky_offset_ = ancestor_sticky_box_offset + sticky_offset; |
| 85 total_containing_block_sticky_offset_ = ancestor_sticky_box_offset + | 102 total_containing_block_sticky_offset_ = ancestor_sticky_box_offset + |
| 86 ancestor_containing_block_offset + | 103 ancestor_containing_block_offset + |
| 87 sticky_offset; | 104 sticky_offset; |
| 88 | 105 |
| 89 return sticky_offset; | 106 return sticky_offset; |
| 90 } | 107 } |
| 91 | 108 |
| 92 FloatSize StickyPositionScrollingConstraints::GetOffsetForStickyPosition( | 109 FloatSize StickyPositionScrollingConstraints::GetOffsetForStickyPosition( |
| 93 const StickyConstraintsMap& constraints_map) const { | 110 const StickyConstraintsMap& constraints_map) const { |
| 94 FloatSize nearest_sticky_box_shifting_sticky_box_constraints_offset; | 111 FloatSize nearest_sticky_layer_shifting_sticky_box_constraints_offset; |
| 95 if (nearest_sticky_box_shifting_sticky_box_) { | 112 if (nearest_sticky_layer_shifting_sticky_box_) { |
| 96 nearest_sticky_box_shifting_sticky_box_constraints_offset = | 113 nearest_sticky_layer_shifting_sticky_box_constraints_offset = |
| 97 constraints_map.at(nearest_sticky_box_shifting_sticky_box_->Layer()) | 114 constraints_map.at(nearest_sticky_layer_shifting_sticky_box_) |
| 98 .GetTotalStickyBoxStickyOffset(); | 115 .total_sticky_box_sticky_offset_; |
| 99 } | 116 } |
| 100 return total_sticky_box_sticky_offset_ - | 117 return total_sticky_box_sticky_offset_ - |
| 101 nearest_sticky_box_shifting_sticky_box_constraints_offset; | 118 nearest_sticky_layer_shifting_sticky_box_constraints_offset; |
| 119 } | |
| 120 | |
| 121 FloatSize StickyPositionScrollingConstraints::AncestorStickyBoxOffset( | |
| 122 const StickyConstraintsMap& constraints_map) { | |
| 123 if (!nearest_sticky_layer_shifting_sticky_box_) | |
| 124 return FloatSize(); | |
| 125 DCHECK(constraints_map.Contains(nearest_sticky_layer_shifting_sticky_box_)); | |
| 126 return constraints_map.at(nearest_sticky_layer_shifting_sticky_box_) | |
| 127 .total_sticky_box_sticky_offset_; | |
| 128 } | |
| 129 | |
| 130 FloatSize StickyPositionScrollingConstraints::AncestorContainingBlockOffset( | |
| 131 const StickyConstraintsMap& constraints_map) { | |
| 132 if (!nearest_sticky_layer_shifting_containing_block_) { | |
| 133 return FloatSize(); | |
| 134 } | |
| 135 DCHECK(constraints_map.Contains( | |
| 136 nearest_sticky_layer_shifting_containing_block_)); | |
| 137 return constraints_map.at(nearest_sticky_layer_shifting_containing_block_) | |
| 138 .total_containing_block_sticky_offset_; | |
| 102 } | 139 } |
| 103 | 140 |
| 104 } // namespace blink | 141 } // namespace blink |
| OLD | NEW |