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/frame/RootFrameViewport.h" | 5 #include "core/frame/RootFrameViewport.h" |
6 | 6 |
7 #include "core/frame/FrameView.h" | 7 #include "core/frame/FrameView.h" |
8 #include "core/layout/ScrollAlignment.h" | 8 #include "core/layout/ScrollAlignment.h" |
9 #include "core/layout/ScrollAnchor.h" | 9 #include "core/layout/ScrollAnchor.h" |
10 #include "platform/geometry/DoubleRect.h" | 10 #include "platform/geometry/DoubleRect.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 // If the root FrameView is the layout viewport then coordinates in the | 42 // If the root FrameView is the layout viewport then coordinates in the |
43 // root FrameView's content space are already in the layout viewport's | 43 // root FrameView's content space are already in the layout viewport's |
44 // content space. | 44 // content space. |
45 if (rootFrameView.layoutViewportScrollableArea() == &layoutViewport()) | 45 if (rootFrameView.layoutViewportScrollableArea() == &layoutViewport()) |
46 return ret; | 46 return ret; |
47 | 47 |
48 // Make the given rect relative to the top of the layout viewport's content | 48 // Make the given rect relative to the top of the layout viewport's content |
49 // by adding the scroll position. | 49 // by adding the scroll position. |
50 // TODO(bokan): This will have to be revisited if we ever remove the | 50 // TODO(bokan): This will have to be revisited if we ever remove the |
51 // restriction that a root scroller must be exactly screen filling. | 51 // restriction that a root scroller must be exactly screen filling. |
52 ret.moveBy(LayoutPoint(layoutViewport().scrollPositionDouble())); | 52 ret.move(LayoutSize(layoutViewport().scrollOffset())); |
53 | 53 |
54 return ret; | 54 return ret; |
55 } | 55 } |
56 | 56 |
57 void RootFrameViewport::restoreToAnchor(const DoublePoint& targetPosition) { | 57 void RootFrameViewport::restoreToAnchor(const ScrollOffset& targetOffset) { |
58 // Clamp the scroll offset of each viewport now so that we force any invalid | 58 // Clamp the scroll offset of each viewport now so that we force any invalid |
59 // offsets to become valid so we can compute the correct deltas. | 59 // offsets to become valid so we can compute the correct deltas. |
60 visualViewport().setScrollPosition(visualViewport().scrollPositionDouble(), | 60 visualViewport().setScrollOffset(visualViewport().scrollOffset(), |
61 ProgrammaticScroll); | 61 ProgrammaticScroll); |
62 layoutViewport().setScrollPosition(layoutViewport().scrollPositionDouble(), | 62 layoutViewport().setScrollOffset(layoutViewport().scrollOffset(), |
63 ProgrammaticScroll); | 63 ProgrammaticScroll); |
64 | 64 |
65 DoubleSize delta = targetPosition - scrollPositionDouble(); | 65 ScrollOffset delta = targetOffset - scrollOffset(); |
66 | 66 |
67 visualViewport().setScrollPosition( | 67 visualViewport().setScrollOffset(visualViewport().scrollOffset() + delta, |
68 visualViewport().scrollPositionDouble() + delta, ProgrammaticScroll); | 68 ProgrammaticScroll); |
69 | 69 |
70 delta = targetPosition - scrollPositionDouble(); | 70 delta = targetOffset - scrollOffset(); |
71 | 71 |
72 // Since the main thread FrameView has integer scroll offsets, scroll it to | 72 // Since the main thread FrameView has integer scroll offsets, scroll it to |
73 // the next pixel and then we'll scroll the visual viewport again to | 73 // the next pixel and then we'll scroll the visual viewport again to |
74 // compensate for the sub-pixel offset. We need this "overscroll" to ensure | 74 // compensate for the sub-pixel offset. We need this "overscroll" to ensure |
75 // the pixel of which we want to be partially in appears fully inside the | 75 // the pixel of which we want to be partially in appears fully inside the |
76 // FrameView since the VisualViewport is bounded by the FrameView. | 76 // FrameView since the VisualViewport is bounded by the FrameView. |
77 IntSize layoutDelta = IntSize( | 77 IntSize layoutDelta = IntSize( |
78 delta.width() < 0 ? floor(delta.width()) : ceil(delta.width()), | 78 delta.width() < 0 ? floor(delta.width()) : ceil(delta.width()), |
79 delta.height() < 0 ? floor(delta.height()) : ceil(delta.height())); | 79 delta.height() < 0 ? floor(delta.height()) : ceil(delta.height())); |
80 | 80 |
81 layoutViewport().setScrollPosition( | 81 layoutViewport().setScrollOffset( |
82 layoutViewport().scrollPosition() + layoutDelta, ProgrammaticScroll); | 82 ScrollOffset(layoutViewport().scrollOffsetInt() + layoutDelta), |
| 83 ProgrammaticScroll); |
83 | 84 |
84 delta = targetPosition - scrollPositionDouble(); | 85 delta = targetOffset - scrollOffset(); |
85 visualViewport().setScrollPosition( | 86 visualViewport().setScrollOffset(visualViewport().scrollOffset() + delta, |
86 visualViewport().scrollPositionDouble() + delta, ProgrammaticScroll); | 87 ProgrammaticScroll); |
87 } | 88 } |
88 | 89 |
89 void RootFrameViewport::didUpdateVisualViewport() { | 90 void RootFrameViewport::didUpdateVisualViewport() { |
90 if (RuntimeEnabledFeatures::scrollAnchoringEnabled()) { | 91 if (RuntimeEnabledFeatures::scrollAnchoringEnabled()) { |
91 if (ScrollAnchor* anchor = layoutViewport().scrollAnchor()) | 92 if (ScrollAnchor* anchor = layoutViewport().scrollAnchor()) |
92 anchor->clear(); | 93 anchor->clear(); |
93 } | 94 } |
94 } | 95 } |
95 | 96 |
96 LayoutBox* RootFrameViewport::layoutBox() const { | 97 LayoutBox* RootFrameViewport::layoutBox() const { |
97 return layoutViewport().layoutBox(); | 98 return layoutViewport().layoutBox(); |
98 } | 99 } |
99 | 100 |
100 void RootFrameViewport::updateScrollAnimator() { | 101 void RootFrameViewport::updateScrollAnimator() { |
101 scrollAnimator().setCurrentPosition( | 102 scrollAnimator().setCurrentOffset( |
102 toFloatPoint(scrollOffsetFromScrollAnimators())); | 103 toFloatSize(scrollOffsetFromScrollAnimators())); |
103 } | 104 } |
104 | 105 |
105 DoublePoint RootFrameViewport::scrollOffsetFromScrollAnimators() const { | 106 ScrollOffset RootFrameViewport::scrollOffsetFromScrollAnimators() const { |
106 return visualViewport().scrollAnimator().currentPosition() + | 107 return visualViewport().scrollAnimator().currentOffset() + |
107 layoutViewport().scrollAnimator().currentPosition(); | 108 layoutViewport().scrollAnimator().currentOffset(); |
108 } | |
109 | |
110 DoubleRect RootFrameViewport::visibleContentRectDouble( | |
111 IncludeScrollbarsInRect scrollbarInclusion) const { | |
112 return DoubleRect( | |
113 scrollPositionDouble(), | |
114 visualViewport().visibleContentRectDouble(scrollbarInclusion).size()); | |
115 } | 109 } |
116 | 110 |
117 IntRect RootFrameViewport::visibleContentRect( | 111 IntRect RootFrameViewport::visibleContentRect( |
118 IncludeScrollbarsInRect scrollbarInclusion) const { | 112 IncludeScrollbarsInRect scrollbarInclusion) const { |
119 return enclosingIntRect(visibleContentRectDouble(scrollbarInclusion)); | 113 return IntRect( |
| 114 IntPoint(scrollOffsetInt()), |
| 115 visualViewport().visibleContentRect(scrollbarInclusion).size()); |
120 } | 116 } |
121 | 117 |
122 bool RootFrameViewport::shouldUseIntegerScrollOffset() const { | 118 bool RootFrameViewport::shouldUseIntegerScrollOffset() const { |
123 // Fractionals are floored in the ScrollAnimatorBase but it's important that | 119 // Fractionals are floored in the ScrollAnimatorBase but it's important that |
124 // the ScrollAnimators of the visual and layout viewports get the precise | 120 // the ScrollAnimators of the visual and layout viewports get the precise |
125 // fractional number so never use integer scrolling for RootFrameViewport, | 121 // fractional number so never use integer scrolling for RootFrameViewport, |
126 // we'll let the truncation happen in the subviewports. | 122 // we'll let the truncation happen in the subviewports. |
127 return false; | 123 return false; |
128 } | 124 } |
129 | 125 |
130 bool RootFrameViewport::isActive() const { | 126 bool RootFrameViewport::isActive() const { |
131 return layoutViewport().isActive(); | 127 return layoutViewport().isActive(); |
132 } | 128 } |
133 | 129 |
134 int RootFrameViewport::scrollSize(ScrollbarOrientation orientation) const { | 130 int RootFrameViewport::scrollSize(ScrollbarOrientation orientation) const { |
135 IntSize scrollDimensions = maximumScrollPosition() - minimumScrollPosition(); | 131 IntSize scrollDimensions = |
| 132 maximumScrollOffsetInt() - minimumScrollOffsetInt(); |
136 return (orientation == HorizontalScrollbar) ? scrollDimensions.width() | 133 return (orientation == HorizontalScrollbar) ? scrollDimensions.width() |
137 : scrollDimensions.height(); | 134 : scrollDimensions.height(); |
138 } | 135 } |
139 | 136 |
140 bool RootFrameViewport::isScrollCornerVisible() const { | 137 bool RootFrameViewport::isScrollCornerVisible() const { |
141 return layoutViewport().isScrollCornerVisible(); | 138 return layoutViewport().isScrollCornerVisible(); |
142 } | 139 } |
143 | 140 |
144 IntRect RootFrameViewport::scrollCornerRect() const { | 141 IntRect RootFrameViewport::scrollCornerRect() const { |
145 return layoutViewport().scrollCornerRect(); | 142 return layoutViewport().scrollCornerRect(); |
146 } | 143 } |
147 | 144 |
148 void RootFrameViewport::setScrollPosition(const DoublePoint& position, | 145 void RootFrameViewport::setScrollOffset(const ScrollOffset& offset, |
149 ScrollType scrollType, | 146 ScrollType scrollType, |
150 ScrollBehavior scrollBehavior) { | 147 ScrollBehavior scrollBehavior) { |
151 updateScrollAnimator(); | 148 updateScrollAnimator(); |
152 | 149 |
153 if (scrollBehavior == ScrollBehaviorAuto) | 150 if (scrollBehavior == ScrollBehaviorAuto) |
154 scrollBehavior = scrollBehaviorStyle(); | 151 scrollBehavior = scrollBehaviorStyle(); |
155 | 152 |
156 if (scrollType == ProgrammaticScroll && | 153 if (scrollType == ProgrammaticScroll && |
157 !layoutViewport().isProgrammaticallyScrollable()) | 154 !layoutViewport().isProgrammaticallyScrollable()) |
158 return; | 155 return; |
159 | 156 |
160 if (scrollType == AnchoringScroll) { | 157 if (scrollType == AnchoringScroll) { |
161 distributeScrollBetweenViewports(position, scrollType, scrollBehavior, | 158 distributeScrollBetweenViewports(offset, scrollType, scrollBehavior, |
162 LayoutViewport); | 159 LayoutViewport); |
163 return; | 160 return; |
164 } | 161 } |
165 | 162 |
166 if (scrollBehavior == ScrollBehaviorSmooth) { | 163 if (scrollBehavior == ScrollBehaviorSmooth) { |
167 distributeScrollBetweenViewports(position, scrollType, scrollBehavior, | 164 distributeScrollBetweenViewports(offset, scrollType, scrollBehavior, |
168 VisualViewport); | 165 VisualViewport); |
169 return; | 166 return; |
170 } | 167 } |
171 | 168 |
172 DoublePoint clampedPosition = clampScrollPosition(position); | 169 ScrollOffset clampedOffset = clampScrollOffset(offset); |
173 ScrollableArea::setScrollPosition(clampedPosition, scrollType, | 170 ScrollableArea::setScrollOffset(clampedOffset, scrollType, scrollBehavior); |
174 scrollBehavior); | |
175 } | 171 } |
176 | 172 |
177 ScrollBehavior RootFrameViewport::scrollBehaviorStyle() const { | 173 ScrollBehavior RootFrameViewport::scrollBehaviorStyle() const { |
178 return layoutViewport().scrollBehaviorStyle(); | 174 return layoutViewport().scrollBehaviorStyle(); |
179 } | 175 } |
180 | 176 |
181 LayoutRect RootFrameViewport::scrollIntoView(const LayoutRect& rectInContent, | 177 LayoutRect RootFrameViewport::scrollIntoView(const LayoutRect& rectInContent, |
182 const ScrollAlignment& alignX, | 178 const ScrollAlignment& alignX, |
183 const ScrollAlignment& alignY, | 179 const ScrollAlignment& alignY, |
184 ScrollType scrollType) { | 180 ScrollType scrollType) { |
185 // We want to move the rect into the viewport that excludes the scrollbars so | 181 // We want to move the rect into the viewport that excludes the scrollbars so |
186 // we intersect the visual viewport with the scrollbar-excluded frameView | 182 // we intersect the visual viewport with the scrollbar-excluded frameView |
187 // content rect. However, we don't use visibleContentRect directly since it | 183 // content rect. However, we don't use visibleContentRect directly since it |
188 // floors the scroll position. Instead, we use | 184 // floors the scroll offset. Instead, we use ScrollAnimatorBase::currentOffset |
189 // ScrollAnimatorBase::currentPosition and construct a LayoutRect from that. | 185 // and construct a LayoutRect from that. |
190 | |
191 LayoutRect frameRectInContent = | 186 LayoutRect frameRectInContent = |
192 LayoutRect(layoutViewport().scrollAnimator().currentPosition(), | 187 LayoutRect(FloatPoint(layoutViewport().scrollAnimator().currentOffset()), |
193 layoutViewport().visibleContentRect().size()); | 188 FloatSize(layoutViewport().visibleContentRect().size())); |
194 LayoutRect visualRectInContent = | 189 LayoutRect visualRectInContent = |
195 LayoutRect(scrollOffsetFromScrollAnimators(), | 190 LayoutRect(FloatPoint(scrollOffsetFromScrollAnimators()), |
196 visualViewport().visibleContentRect().size()); | 191 FloatSize(visualViewport().visibleContentRect().size())); |
197 | 192 |
198 // Intersect layout and visual rects to exclude the scrollbar from the view | 193 // Intersect layout and visual rects to exclude the scrollbar from the view |
199 // rect. | 194 // rect. |
200 LayoutRect viewRectInContent = | 195 LayoutRect viewRectInContent = |
201 intersection(visualRectInContent, frameRectInContent); | 196 intersection(visualRectInContent, frameRectInContent); |
202 LayoutRect targetViewport = ScrollAlignment::getRectToExpose( | 197 LayoutRect targetViewport = ScrollAlignment::getRectToExpose( |
203 viewRectInContent, rectInContent, alignX, alignY); | 198 viewRectInContent, rectInContent, alignX, alignY); |
204 if (targetViewport != viewRectInContent) | 199 if (targetViewport != viewRectInContent) { |
205 setScrollPosition(DoublePoint(targetViewport.x(), targetViewport.y()), | 200 setScrollOffset(ScrollOffset(targetViewport.x(), targetViewport.y()), |
206 scrollType); | 201 scrollType); |
| 202 } |
207 | 203 |
208 // RootFrameViewport only changes the viewport relative to the document so we | 204 // RootFrameViewport only changes the viewport relative to the document so we |
209 // can't change the input rect's location relative to the document origin. | 205 // can't change the input rect's location relative to the document origin. |
210 return rectInContent; | 206 return rectInContent; |
211 } | 207 } |
212 | 208 |
213 void RootFrameViewport::setScrollOffset(const DoublePoint& offset, | 209 void RootFrameViewport::updateScrollOffset(const ScrollOffset& offset, |
214 ScrollType scrollType) { | 210 ScrollType scrollType) { |
215 distributeScrollBetweenViewports(DoublePoint(offset), scrollType, | 211 distributeScrollBetweenViewports(offset, scrollType, ScrollBehaviorInstant, |
216 ScrollBehaviorInstant, VisualViewport); | 212 VisualViewport); |
217 } | 213 } |
218 | 214 |
219 void RootFrameViewport::distributeScrollBetweenViewports( | 215 void RootFrameViewport::distributeScrollBetweenViewports( |
220 const DoublePoint& offset, | 216 const ScrollOffset& offset, |
221 ScrollType scrollType, | 217 ScrollType scrollType, |
222 ScrollBehavior behavior, | 218 ScrollBehavior behavior, |
223 ViewportToScrollFirst scrollFirst) { | 219 ViewportToScrollFirst scrollFirst) { |
224 // Make sure we use the scroll positions as reported by each viewport's | 220 // Make sure we use the scroll offsets as reported by each viewport's |
225 // ScrollAnimatorBase, since its ScrollableArea's position may have the | 221 // ScrollAnimatorBase, since its ScrollableArea's offset may have the |
226 // fractional part truncated off. | 222 // fractional part truncated off. |
227 DoublePoint oldPosition = scrollOffsetFromScrollAnimators(); | 223 // TODO(szager): Now that scroll offsets are stored as floats, can we take the |
| 224 // scroll offset directly from the ScrollableArea's rather than the animators? |
| 225 ScrollOffset oldOffset = scrollOffsetFromScrollAnimators(); |
228 | 226 |
229 DoubleSize delta = offset - oldPosition; | 227 ScrollOffset delta = offset - oldOffset; |
230 | 228 |
231 if (delta.isZero()) | 229 if (delta.isZero()) |
232 return; | 230 return; |
233 | 231 |
234 ScrollableArea& primary = | 232 ScrollableArea& primary = |
235 scrollFirst == VisualViewport ? visualViewport() : layoutViewport(); | 233 scrollFirst == VisualViewport ? visualViewport() : layoutViewport(); |
236 ScrollableArea& secondary = | 234 ScrollableArea& secondary = |
237 scrollFirst == VisualViewport ? layoutViewport() : visualViewport(); | 235 scrollFirst == VisualViewport ? layoutViewport() : visualViewport(); |
238 | 236 |
239 DoublePoint targetPosition = primary.clampScrollPosition( | 237 ScrollOffset targetOffset = primary.clampScrollOffset( |
240 primary.scrollAnimator().currentPosition() + delta); | 238 primary.scrollAnimator().currentOffset() + delta); |
241 | 239 |
242 primary.setScrollPosition(targetPosition, scrollType, behavior); | 240 primary.setScrollOffset(targetOffset, scrollType, behavior); |
243 | 241 |
244 // Scroll the secondary viewport if all of the scroll was not applied to the | 242 // Scroll the secondary viewport if all of the scroll was not applied to the |
245 // primary viewport. | 243 // primary viewport. |
246 DoublePoint updatedPosition = | 244 ScrollOffset updatedOffset = |
247 secondary.scrollAnimator().currentPosition() + FloatPoint(targetPosition); | 245 secondary.scrollAnimator().currentOffset() + FloatSize(targetOffset); |
248 DoubleSize applied = updatedPosition - oldPosition; | 246 ScrollOffset applied = updatedOffset - oldOffset; |
249 delta -= applied; | 247 delta -= applied; |
250 | 248 |
251 if (delta.isZero()) | 249 if (delta.isZero()) |
252 return; | 250 return; |
253 | 251 |
254 targetPosition = secondary.clampScrollPosition( | 252 targetOffset = secondary.clampScrollOffset( |
255 secondary.scrollAnimator().currentPosition() + delta); | 253 secondary.scrollAnimator().currentOffset() + delta); |
256 secondary.setScrollPosition(targetPosition, scrollType, behavior); | 254 secondary.setScrollOffset(targetOffset, scrollType, behavior); |
257 } | 255 } |
258 | 256 |
259 IntPoint RootFrameViewport::scrollPosition() const { | 257 IntSize RootFrameViewport::scrollOffsetInt() const { |
260 return flooredIntPoint(scrollPositionDouble()); | 258 return flooredIntSize(scrollOffset()); |
261 } | 259 } |
262 | 260 |
263 DoublePoint RootFrameViewport::scrollPositionDouble() const { | 261 ScrollOffset RootFrameViewport::scrollOffset() const { |
264 return layoutViewport().scrollPositionDouble() + | 262 return layoutViewport().scrollOffset() + visualViewport().scrollOffset(); |
265 toDoubleSize(visualViewport().scrollPositionDouble()); | |
266 } | 263 } |
267 | 264 |
268 IntPoint RootFrameViewport::minimumScrollPosition() const { | 265 IntSize RootFrameViewport::minimumScrollOffsetInt() const { |
269 return IntPoint(layoutViewport().minimumScrollPosition() + | 266 return IntSize(layoutViewport().minimumScrollOffsetInt() + |
270 visualViewport().minimumScrollPosition()); | 267 visualViewport().minimumScrollOffsetInt()); |
271 } | 268 } |
272 | 269 |
273 IntPoint RootFrameViewport::maximumScrollPosition() const { | 270 IntSize RootFrameViewport::maximumScrollOffsetInt() const { |
274 return layoutViewport().maximumScrollPosition() + | 271 return layoutViewport().maximumScrollOffsetInt() + |
275 visualViewport().maximumScrollPosition(); | 272 visualViewport().maximumScrollOffsetInt(); |
276 } | 273 } |
277 | 274 |
278 DoublePoint RootFrameViewport::maximumScrollPositionDouble() const { | 275 ScrollOffset RootFrameViewport::maximumScrollOffset() const { |
279 return layoutViewport().maximumScrollPositionDouble() + | 276 return layoutViewport().maximumScrollOffset() + |
280 toDoubleSize(visualViewport().maximumScrollPositionDouble()); | 277 visualViewport().maximumScrollOffset(); |
281 } | 278 } |
282 | 279 |
283 IntSize RootFrameViewport::contentsSize() const { | 280 IntSize RootFrameViewport::contentsSize() const { |
284 return layoutViewport().contentsSize(); | 281 return layoutViewport().contentsSize(); |
285 } | 282 } |
286 | 283 |
287 bool RootFrameViewport::scrollbarsCanBeActive() const { | 284 bool RootFrameViewport::scrollbarsCanBeActive() const { |
288 return layoutViewport().scrollbarsCanBeActive(); | 285 return layoutViewport().scrollbarsCanBeActive(); |
289 } | 286 } |
290 | 287 |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 visualViewport().clearScrollAnimators(); | 425 visualViewport().clearScrollAnimators(); |
429 } | 426 } |
430 | 427 |
431 DEFINE_TRACE(RootFrameViewport) { | 428 DEFINE_TRACE(RootFrameViewport) { |
432 visitor->trace(m_visualViewport); | 429 visitor->trace(m_visualViewport); |
433 visitor->trace(m_layoutViewport); | 430 visitor->trace(m_layoutViewport); |
434 ScrollableArea::trace(visitor); | 431 ScrollableArea::trace(visitor); |
435 } | 432 } |
436 | 433 |
437 } // namespace blink | 434 } // namespace blink |
OLD | NEW |