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
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/core/frame/root_frame_viewport.h"
6
7 #include "base/barrier_closure.h"
8 #include "cc/input/snap_selection_strategy.h"
9 #include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h"
10 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
11 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
12 #include "third_party/blink/renderer/core/layout/layout_box.h"
13 #include "third_party/blink/renderer/core/layout/scroll_anchor.h"
14 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
15 #include "third_party/blink/renderer/core/scroll/scroll_alignment.h"
16 #include "third_party/blink/renderer/core/scroll/scroll_animator_base.h"
17 #include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
18 #include "third_party/blink/renderer/platform/geometry/double_rect.h"
19 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
20 #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
21
22 namespace blink {
23 namespace {
24 // Computes the rect of valid scroll offsets reachable by user scrolls for the
25 // scrollable area.
GetUserScrollableRect(const ScrollableArea & area)26 FloatRect GetUserScrollableRect(const ScrollableArea& area) {
27 FloatRect user_scrollable_rect;
28 FloatSize scrollable_size =
29 area.MaximumScrollOffset() - area.MinimumScrollOffset();
30 if (area.UserInputScrollable(kHorizontalScrollbar)) {
31 user_scrollable_rect.SetX(area.MinimumScrollOffset().Width());
32 user_scrollable_rect.SetWidth(scrollable_size.Width());
33 } else {
34 user_scrollable_rect.SetX(area.GetScrollOffset().Width());
35 user_scrollable_rect.SetWidth(0);
36 }
37
38 if (area.UserInputScrollable(kVerticalScrollbar)) {
39 user_scrollable_rect.SetY(area.MinimumScrollOffset().Height());
40 user_scrollable_rect.SetHeight(scrollable_size.Height());
41 } else {
42 user_scrollable_rect.SetY(area.GetScrollOffset().Height());
43 user_scrollable_rect.SetHeight(0);
44 }
45 return user_scrollable_rect;
46 }
47
48 } // namespace
RootFrameViewport(ScrollableArea & visual_viewport,ScrollableArea & layout_viewport)49 RootFrameViewport::RootFrameViewport(ScrollableArea& visual_viewport,
50 ScrollableArea& layout_viewport)
51 : visual_viewport_(visual_viewport), should_restore_scroll_(false) {
52 SetLayoutViewport(layout_viewport);
53 }
54
SetLayoutViewport(ScrollableArea & new_layout_viewport)55 void RootFrameViewport::SetLayoutViewport(ScrollableArea& new_layout_viewport) {
56 if (layout_viewport_.Get() == &new_layout_viewport)
57 return;
58
59 if (layout_viewport_ && layout_viewport_->GetScrollAnchor())
60 layout_viewport_->GetScrollAnchor()->SetScroller(layout_viewport_.Get());
61
62 layout_viewport_ = &new_layout_viewport;
63
64 if (layout_viewport_->GetScrollAnchor())
65 layout_viewport_->GetScrollAnchor()->SetScroller(this);
66 }
67
LayoutViewport() const68 ScrollableArea& RootFrameViewport::LayoutViewport() const {
69 DCHECK(layout_viewport_);
70 return *layout_viewport_;
71 }
72
RootContentsToLayoutViewportContents(LocalFrameView & root_frame_view,const PhysicalRect & rect) const73 PhysicalRect RootFrameViewport::RootContentsToLayoutViewportContents(
74 LocalFrameView& root_frame_view,
75 const PhysicalRect& rect) const {
76 PhysicalRect ret = rect;
77
78 // If the root LocalFrameView is the layout viewport then coordinates in the
79 // root LocalFrameView's content space are already in the layout viewport's
80 // content space.
81 if (root_frame_view.LayoutViewport() == &LayoutViewport())
82 return ret;
83
84 // Make the given rect relative to the top of the layout viewport's content
85 // by adding the scroll position.
86 // TODO(bokan): This will have to be revisited if we ever remove the
87 // restriction that a root scroller must be exactly screen filling.
88 ret.Move(
89 PhysicalOffset::FromFloatSizeRound(LayoutViewport().GetScrollOffset()));
90
91 return ret;
92 }
93
RestoreToAnchor(const ScrollOffset & target_offset)94 void RootFrameViewport::RestoreToAnchor(const ScrollOffset& target_offset) {
95 // Clamp the scroll offset of each viewport now so that we force any invalid
96 // offsets to become valid so we can compute the correct deltas.
97 GetVisualViewport().SetScrollOffset(GetVisualViewport().GetScrollOffset(),
98 mojom::blink::ScrollType::kProgrammatic);
99 LayoutViewport().SetScrollOffset(LayoutViewport().GetScrollOffset(),
100 mojom::blink::ScrollType::kProgrammatic);
101
102 ScrollOffset delta = target_offset - GetScrollOffset();
103
104 GetVisualViewport().SetScrollOffset(
105 GetVisualViewport().GetScrollOffset() + delta,
106 mojom::blink::ScrollType::kProgrammatic);
107
108 delta = target_offset - GetScrollOffset();
109
110 // Since the main thread LocalFrameView has integer scroll offsets, scroll it
111 // to the next pixel and then we'll scroll the visual viewport again to
112 // compensate for the sub-pixel offset. We need this "overscroll" to ensure
113 // the pixel of which we want to be partially in appears fully inside the
114 // LocalFrameView since the VisualViewport is bounded by the LocalFrameView.
115 IntSize layout_delta = IntSize(
116 delta.Width() < 0 ? floor(delta.Width()) : ceil(delta.Width()),
117 delta.Height() < 0 ? floor(delta.Height()) : ceil(delta.Height()));
118
119 LayoutViewport().SetScrollOffset(
120 ScrollOffset(LayoutViewport().ScrollOffsetInt() + layout_delta),
121 mojom::blink::ScrollType::kProgrammatic);
122
123 delta = target_offset - GetScrollOffset();
124 GetVisualViewport().SetScrollOffset(
125 GetVisualViewport().GetScrollOffset() + delta,
126 mojom::blink::ScrollType::kProgrammatic);
127 }
128
DidUpdateVisualViewport()129 void RootFrameViewport::DidUpdateVisualViewport() {
130 if (ScrollAnchor* anchor = LayoutViewport().GetScrollAnchor())
131 anchor->Clear();
132 }
133
GetLayoutBox() const134 LayoutBox* RootFrameViewport::GetLayoutBox() const {
135 return LayoutViewport().GetLayoutBox();
136 }
137
LocalToVisibleContentQuad(const FloatQuad & quad,const LayoutObject * local_object,unsigned flags) const138 FloatQuad RootFrameViewport::LocalToVisibleContentQuad(
139 const FloatQuad& quad,
140 const LayoutObject* local_object,
141 unsigned flags) const {
142 if (!layout_viewport_)
143 return quad;
144 FloatQuad viewport_quad =
145 layout_viewport_->LocalToVisibleContentQuad(quad, local_object, flags);
146 if (visual_viewport_) {
147 viewport_quad = visual_viewport_->LocalToVisibleContentQuad(
148 viewport_quad, local_object, flags);
149 }
150 return viewport_quad;
151 }
152
153 scoped_refptr<base::SingleThreadTaskRunner>
GetTimerTaskRunner() const154 RootFrameViewport::GetTimerTaskRunner() const {
155 return LayoutViewport().GetTimerTaskRunner();
156 }
157
HorizontalScrollbarHeight(OverlayScrollbarClipBehavior behavior) const158 int RootFrameViewport::HorizontalScrollbarHeight(
159 OverlayScrollbarClipBehavior behavior) const {
160 return LayoutViewport().HorizontalScrollbarHeight(behavior);
161 }
162
VerticalScrollbarWidth(OverlayScrollbarClipBehavior behavior) const163 int RootFrameViewport::VerticalScrollbarWidth(
164 OverlayScrollbarClipBehavior behavior) const {
165 return LayoutViewport().VerticalScrollbarWidth(behavior);
166 }
167
UpdateScrollAnimator()168 void RootFrameViewport::UpdateScrollAnimator() {
169 GetScrollAnimator().SetCurrentOffset(ScrollOffsetFromScrollAnimators());
170 }
171
ScrollOffsetFromScrollAnimators() const172 ScrollOffset RootFrameViewport::ScrollOffsetFromScrollAnimators() const {
173 return GetVisualViewport().GetScrollAnimator().CurrentOffset() +
174 LayoutViewport().GetScrollAnimator().CurrentOffset();
175 }
176
VisibleContentRect(IncludeScrollbarsInRect scrollbar_inclusion) const177 IntRect RootFrameViewport::VisibleContentRect(
178 IncludeScrollbarsInRect scrollbar_inclusion) const {
179 return IntRect(
180 IntPoint(ScrollOffsetInt()),
181 GetVisualViewport().VisibleContentRect(scrollbar_inclusion).Size());
182 }
183
VisibleScrollSnapportRect(IncludeScrollbarsInRect scrollbar_inclusion) const184 PhysicalRect RootFrameViewport::VisibleScrollSnapportRect(
185 IncludeScrollbarsInRect scrollbar_inclusion) const {
186 // The effective viewport is the intersection of the visual viewport with the
187 // layout viewport.
188 PhysicalRect frame_rect_in_content(
189 PhysicalOffset::FromFloatSizeRound(LayoutViewport().GetScrollOffset()),
190 PhysicalSize(
191 LayoutViewport().VisibleContentRect(scrollbar_inclusion).Size()));
192 PhysicalRect visual_rect_in_content(
193 PhysicalOffset::FromFloatSizeRound(
194 LayoutViewport().GetScrollOffset() +
195 GetVisualViewport().GetScrollAnimator().CurrentOffset()),
196 PhysicalSize(
197 GetVisualViewport().VisibleContentRect(scrollbar_inclusion).Size()));
198
199 PhysicalRect visible_scroll_snapport =
200 Intersection(visual_rect_in_content, frame_rect_in_content);
201 if (!LayoutViewport().GetLayoutBox())
202 return visible_scroll_snapport;
203
204 const ComputedStyle* style = LayoutViewport().GetLayoutBox()->Style();
205 LayoutRectOutsets padding(
206 MinimumValueForLength(style->ScrollPaddingTop(),
207 visible_scroll_snapport.Height()),
208 MinimumValueForLength(style->ScrollPaddingRight(),
209 visible_scroll_snapport.Width()),
210 MinimumValueForLength(style->ScrollPaddingBottom(),
211 visible_scroll_snapport.Height()),
212 MinimumValueForLength(style->ScrollPaddingLeft(),
213 visible_scroll_snapport.Width()));
214 visible_scroll_snapport.Contract(padding);
215
216 return visible_scroll_snapport;
217 }
218
ShouldUseIntegerScrollOffset() const219 bool RootFrameViewport::ShouldUseIntegerScrollOffset() const {
220 // Fractionals are floored in the ScrollAnimatorBase but it's important that
221 // the ScrollAnimators of the visual and layout viewports get the precise
222 // fractional number so never use integer scrolling for RootFrameViewport,
223 // we'll let the truncation happen in the subviewports.
224 return false;
225 }
226
IsActive() const227 bool RootFrameViewport::IsActive() const {
228 return LayoutViewport().IsActive();
229 }
230
ScrollSize(ScrollbarOrientation orientation) const231 int RootFrameViewport::ScrollSize(ScrollbarOrientation orientation) const {
232 IntSize scroll_dimensions =
233 MaximumScrollOffsetInt() - MinimumScrollOffsetInt();
234 return (orientation == kHorizontalScrollbar) ? scroll_dimensions.Width()
235 : scroll_dimensions.Height();
236 }
237
IsScrollCornerVisible() const238 bool RootFrameViewport::IsScrollCornerVisible() const {
239 return LayoutViewport().IsScrollCornerVisible();
240 }
241
ScrollCornerRect() const242 IntRect RootFrameViewport::ScrollCornerRect() const {
243 return LayoutViewport().ScrollCornerRect();
244 }
245
ApplyPendingHistoryRestoreScrollOffset()246 void RootFrameViewport::ApplyPendingHistoryRestoreScrollOffset() {
247 if (!pending_view_state_)
248 return;
249
250 bool should_restore_scale = pending_view_state_->page_scale_factor_;
251
252 // For main frame restore scale and visual viewport position
253 ScrollOffset visual_viewport_offset(
254 pending_view_state_->visual_viewport_scroll_offset_);
255
256 // If the visual viewport's offset is (-1, -1) it means the history item
257 // is an old version of HistoryItem so distribute the scroll between
258 // the main frame and the visual viewport as best as we can.
259 if (visual_viewport_offset.Width() == -1 &&
260 visual_viewport_offset.Height() == -1) {
261 visual_viewport_offset = pending_view_state_->scroll_offset_ -
262 LayoutViewport().GetScrollOffset();
263 }
264
265 auto* visual_viewport = static_cast<VisualViewport*>(&GetVisualViewport());
266 if (should_restore_scale && should_restore_scroll_) {
267 visual_viewport->SetScaleAndLocation(
268 pending_view_state_->page_scale_factor_,
269 visual_viewport->IsPinchGestureActive(),
270 FloatPoint(visual_viewport_offset));
271 } else if (should_restore_scale) {
272 visual_viewport->SetScale(pending_view_state_->page_scale_factor_);
273 } else if (should_restore_scroll_) {
274 visual_viewport->SetLocation(FloatPoint(visual_viewport_offset));
275 }
276
277 should_restore_scroll_ = false;
278
279 pending_view_state_.reset();
280 }
281
SetScrollOffset(const ScrollOffset & offset,mojom::blink::ScrollType scroll_type,mojom::blink::ScrollBehavior scroll_behavior,ScrollCallback on_finish)282 void RootFrameViewport::SetScrollOffset(
283 const ScrollOffset& offset,
284 mojom::blink::ScrollType scroll_type,
285 mojom::blink::ScrollBehavior scroll_behavior,
286 ScrollCallback on_finish) {
287 UpdateScrollAnimator();
288
289 if (scroll_behavior == mojom::blink::ScrollBehavior::kAuto)
290 scroll_behavior = ScrollBehaviorStyle();
291
292 if (scroll_type == mojom::blink::ScrollType::kAnchoring) {
293 DistributeScrollBetweenViewports(offset, scroll_type, scroll_behavior,
294 kLayoutViewport, std::move(on_finish));
295 return;
296 }
297
298 if (scroll_behavior == mojom::blink::ScrollBehavior::kSmooth) {
299 DistributeScrollBetweenViewports(offset, scroll_type, scroll_behavior,
300 kVisualViewport, std::move(on_finish));
301 return;
302 }
303
304 ScrollOffset clamped_offset = ClampScrollOffset(offset);
305 ScrollableArea::SetScrollOffset(clamped_offset, scroll_type, scroll_behavior,
306 std::move(on_finish));
307 }
308
ScrollBehaviorStyle() const309 mojom::blink::ScrollBehavior RootFrameViewport::ScrollBehaviorStyle() const {
310 return LayoutViewport().ScrollBehaviorStyle();
311 }
312
UsedColorScheme() const313 mojom::blink::ColorScheme RootFrameViewport::UsedColorScheme() const {
314 return LayoutViewport().UsedColorScheme();
315 }
316
ClampToUserScrollableOffset(const ScrollOffset & offset) const317 ScrollOffset RootFrameViewport::ClampToUserScrollableOffset(
318 const ScrollOffset& offset) const {
319 ScrollOffset scroll_offset = offset;
320 FloatRect user_scrollable = GetUserScrollableRect(LayoutViewport()) +
321 GetUserScrollableRect(GetVisualViewport());
322 scroll_offset.SetWidth(clampTo(scroll_offset.Width(), user_scrollable.X(),
323 user_scrollable.MaxX()));
324 scroll_offset.SetHeight(clampTo(scroll_offset.Height(), user_scrollable.Y(),
325 user_scrollable.MaxY()));
326 return scroll_offset;
327 }
328
ScrollIntoView(const PhysicalRect & rect_in_absolute,const mojom::blink::ScrollIntoViewParamsPtr & params)329 PhysicalRect RootFrameViewport::ScrollIntoView(
330 const PhysicalRect& rect_in_absolute,
331 const mojom::blink::ScrollIntoViewParamsPtr& params) {
332 PhysicalRect scroll_snapport_rect = VisibleScrollSnapportRect();
333
334 PhysicalRect rect_in_document = rect_in_absolute;
335 rect_in_document.Move(
336 PhysicalOffset::FromFloatSizeFloor(LayoutViewport().GetScrollOffset()));
337
338 ScrollOffset new_scroll_offset =
339 ClampScrollOffset(ScrollAlignment::GetScrollOffsetToExpose(
340 scroll_snapport_rect, rect_in_document, *params->align_x.get(),
341 *params->align_y.get(), GetScrollOffset()));
342 if (params->type == mojom::blink::ScrollType::kUser)
343 new_scroll_offset = ClampToUserScrollableOffset(new_scroll_offset);
344
345 FloatPoint end_point = ScrollOffsetToPosition(new_scroll_offset);
346 std::unique_ptr<cc::SnapSelectionStrategy> strategy =
347 cc::SnapSelectionStrategy::CreateForEndPosition(
348 gfx::ScrollOffset(end_point), true, true);
349 if (GetLayoutBox()) {
350 end_point = GetSnapPositionAndSetTarget(*strategy).value_or(end_point);
351 new_scroll_offset = ScrollPositionToOffset(end_point);
352 }
353
354 if (new_scroll_offset != GetScrollOffset()) {
355 if (params->is_for_scroll_sequence) {
356 DCHECK(params->type == mojom::blink::ScrollType::kProgrammatic ||
357 params->type == mojom::blink::ScrollType::kUser);
358 mojom::blink::ScrollBehavior behavior = DetermineScrollBehavior(
359 params->behavior, GetLayoutBox()->StyleRef().GetScrollBehavior());
360 GetSmoothScrollSequencer()->QueueAnimation(this, new_scroll_offset,
361 behavior);
362 } else {
363 ScrollableArea::SetScrollOffset(new_scroll_offset, params->type);
364 }
365 }
366
367 // Return the newly moved rect to absolute coordinates.
368 // TODO(szager): PaintLayerScrollableArea::ScrollIntoView clips the return
369 // value to the visible content rect, but this does not.
370 rect_in_document.Move(
371 -PhysicalOffset::FromFloatSizeRound(LayoutViewport().GetScrollOffset()));
372 return rect_in_document;
373 }
374
UpdateScrollOffset(const ScrollOffset & offset,mojom::blink::ScrollType scroll_type)375 void RootFrameViewport::UpdateScrollOffset(
376 const ScrollOffset& offset,
377 mojom::blink::ScrollType scroll_type) {
378 DistributeScrollBetweenViewports(offset, scroll_type,
379 mojom::blink::ScrollBehavior::kInstant,
380 kVisualViewport);
381 }
382
DistributeScrollBetweenViewports(const ScrollOffset & offset,mojom::blink::ScrollType scroll_type,mojom::blink::ScrollBehavior behavior,ViewportToScrollFirst scroll_first,ScrollCallback on_finish)383 void RootFrameViewport::DistributeScrollBetweenViewports(
384 const ScrollOffset& offset,
385 mojom::blink::ScrollType scroll_type,
386 mojom::blink::ScrollBehavior behavior,
387 ViewportToScrollFirst scroll_first,
388 ScrollCallback on_finish) {
389 // Make sure we use the scroll offsets as reported by each viewport's
390 // ScrollAnimatorBase, since its ScrollableArea's offset may have the
391 // fractional part truncated off.
392 // TODO(szager): Now that scroll offsets are stored as floats, can we take the
393 // scroll offset directly from the ScrollableArea's rather than the animators?
394 ScrollOffset old_offset = ScrollOffsetFromScrollAnimators();
395
396 ScrollOffset delta = offset - old_offset;
397
398 if (delta.IsZero()) {
399 if (on_finish)
400 std::move(on_finish).Run();
401 return;
402 }
403
404 ScrollableArea& primary =
405 scroll_first == kVisualViewport ? GetVisualViewport() : LayoutViewport();
406 ScrollableArea& secondary =
407 scroll_first == kVisualViewport ? LayoutViewport() : GetVisualViewport();
408
409 ScrollOffset target_offset = primary.ClampScrollOffset(
410 primary.GetScrollAnimator().CurrentOffset() + delta);
411
412 auto all_done = on_finish ? base::BarrierClosure(2, std::move(on_finish))
413 : base::RepeatingClosure();
414
415 // DistributeScrollBetweenViewports can be called from SetScrollOffset,
416 // so we assume that aborting sequenced smooth scrolls has been handled.
417 // It can also be called from inside an animation to set the offset in
418 // each frame. In that case, we shouldn't abort sequenced smooth scrolls.
419 primary.SetScrollOffset(target_offset, scroll_type, behavior, all_done);
420
421 // Scroll the secondary viewport if all of the scroll was not applied to the
422 // primary viewport.
423 ScrollOffset updated_offset =
424 secondary.GetScrollAnimator().CurrentOffset() + FloatSize(target_offset);
425 ScrollOffset applied = updated_offset - old_offset;
426 delta -= applied;
427
428 if (delta.IsZero()) {
429 if (all_done)
430 all_done.Run();
431 return;
432 }
433
434 target_offset = secondary.ClampScrollOffset(
435 secondary.GetScrollAnimator().CurrentOffset() + delta);
436 secondary.SetScrollOffset(target_offset, scroll_type, behavior, all_done);
437 }
438
ScrollOffsetInt() const439 IntSize RootFrameViewport::ScrollOffsetInt() const {
440 return FlooredIntSize(GetScrollOffset());
441 }
442
GetScrollOffset() const443 ScrollOffset RootFrameViewport::GetScrollOffset() const {
444 return LayoutViewport().GetScrollOffset() +
445 GetVisualViewport().GetScrollOffset();
446 }
447
MinimumScrollOffsetInt() const448 IntSize RootFrameViewport::MinimumScrollOffsetInt() const {
449 return IntSize(LayoutViewport().MinimumScrollOffsetInt() +
450 GetVisualViewport().MinimumScrollOffsetInt());
451 }
452
MaximumScrollOffsetInt() const453 IntSize RootFrameViewport::MaximumScrollOffsetInt() const {
454 return LayoutViewport().MaximumScrollOffsetInt() +
455 GetVisualViewport().MaximumScrollOffsetInt();
456 }
457
MaximumScrollOffset() const458 ScrollOffset RootFrameViewport::MaximumScrollOffset() const {
459 return LayoutViewport().MaximumScrollOffset() +
460 GetVisualViewport().MaximumScrollOffset();
461 }
462
ClampScrollOffset(const IntSize & scroll_offset) const463 IntSize RootFrameViewport::ClampScrollOffset(
464 const IntSize& scroll_offset) const {
465 return scroll_offset.ShrunkTo(MaximumScrollOffsetInt())
466 .ExpandedTo(MinimumScrollOffsetInt());
467 }
468
ClampScrollOffset(const ScrollOffset & scroll_offset) const469 ScrollOffset RootFrameViewport::ClampScrollOffset(
470 const ScrollOffset& scroll_offset) const {
471 return scroll_offset.ShrunkTo(MaximumScrollOffset())
472 .ExpandedTo(MinimumScrollOffset());
473 }
474
ContentsSize() const475 IntSize RootFrameViewport::ContentsSize() const {
476 return LayoutViewport().ContentsSize();
477 }
478
ShouldScrollOnMainThread() const479 bool RootFrameViewport::ShouldScrollOnMainThread() const {
480 return LayoutViewport().ShouldScrollOnMainThread();
481 }
482
ScrollbarsCanBeActive() const483 bool RootFrameViewport::ScrollbarsCanBeActive() const {
484 return LayoutViewport().ScrollbarsCanBeActive();
485 }
486
UserInputScrollable(ScrollbarOrientation orientation) const487 bool RootFrameViewport::UserInputScrollable(
488 ScrollbarOrientation orientation) const {
489 return GetVisualViewport().UserInputScrollable(orientation) ||
490 LayoutViewport().UserInputScrollable(orientation);
491 }
492
ShouldPlaceVerticalScrollbarOnLeft() const493 bool RootFrameViewport::ShouldPlaceVerticalScrollbarOnLeft() const {
494 return LayoutViewport().ShouldPlaceVerticalScrollbarOnLeft();
495 }
496
ScrollControlWasSetNeedsPaintInvalidation()497 void RootFrameViewport::ScrollControlWasSetNeedsPaintInvalidation() {
498 LayoutViewport().ScrollControlWasSetNeedsPaintInvalidation();
499 }
500
LayerForScrolling() const501 cc::Layer* RootFrameViewport::LayerForScrolling() const {
502 return LayoutViewport().LayerForScrolling();
503 }
504
LayerForHorizontalScrollbar() const505 cc::Layer* RootFrameViewport::LayerForHorizontalScrollbar() const {
506 return LayoutViewport().LayerForHorizontalScrollbar();
507 }
508
LayerForVerticalScrollbar() const509 cc::Layer* RootFrameViewport::LayerForVerticalScrollbar() const {
510 return LayoutViewport().LayerForVerticalScrollbar();
511 }
512
LayerForScrollCorner() const513 cc::Layer* RootFrameViewport::LayerForScrollCorner() const {
514 return LayoutViewport().LayerForScrollCorner();
515 }
516
517 // This method distributes the scroll between the visual and layout viewport.
UserScroll(ScrollGranularity granularity,const FloatSize & delta,ScrollableArea::ScrollCallback on_finish)518 ScrollResult RootFrameViewport::UserScroll(
519 ScrollGranularity granularity,
520 const FloatSize& delta,
521 ScrollableArea::ScrollCallback on_finish) {
522 base::ScopedClosureRunner run_on_return(std::move(on_finish));
523
524 // TODO(bokan/ymalik): Once smooth scrolling is permanently enabled we
525 // should be able to remove this method override and use the base class
526 // version: ScrollableArea::userScroll.
527
528 UpdateScrollAnimator();
529
530 FloatSize pixel_delta = ResolveScrollDelta(granularity, delta);
531
532 // Precompute the amount of possible scrolling since, when animated,
533 // ScrollAnimator::userScroll will report having consumed the total given
534 // scroll delta, regardless of how much will actually scroll, but we need to
535 // know how much to leave for the layout viewport.
536 FloatSize visual_consumed_delta =
537 GetVisualViewport().GetScrollAnimator().ComputeDeltaToConsume(
538 pixel_delta);
539
540 // Split the remaining delta between scrollable and unscrollable axes of the
541 // layout viewport. We only pass a delta to the scrollable axes and remember
542 // how much was held back so we can add it to the unused delta in the
543 // result.
544 FloatSize layout_delta = pixel_delta - visual_consumed_delta;
545 FloatSize scrollable_axis_delta(
546 LayoutViewport().UserInputScrollable(kHorizontalScrollbar)
547 ? layout_delta.Width()
548 : 0,
549 LayoutViewport().UserInputScrollable(kVerticalScrollbar)
550 ? layout_delta.Height()
551 : 0);
552
553 // If there won't be any scrolling, bail early so we don't produce any side
554 // effects like cancelling existing animations.
555 if (visual_consumed_delta.IsZero() && scrollable_axis_delta.IsZero()) {
556 return ScrollResult(false, false, pixel_delta.Width(),
557 pixel_delta.Height());
558 }
559
560 CancelProgrammaticScrollAnimation();
561 if (SmoothScrollSequencer* sequencer = GetSmoothScrollSequencer())
562 sequencer->AbortAnimations();
563
564 // TODO(bokan): Why do we call userScroll on the animators directly and
565 // not through the ScrollableAreas?
566 if (visual_consumed_delta == pixel_delta) {
567 ScrollResult visual_result =
568 GetVisualViewport().GetScrollAnimator().UserScroll(
569 granularity, visual_consumed_delta, run_on_return.Release());
570 return visual_result;
571 }
572
573 ScrollableArea::ScrollCallback callback = run_on_return.Release();
574 auto all_done = callback ? base::BarrierClosure(2, std::move(callback))
575 : base::RepeatingClosure();
576 ScrollResult visual_result =
577 GetVisualViewport().GetScrollAnimator().UserScroll(
578 granularity, visual_consumed_delta, all_done);
579
580 ScrollResult layout_result = LayoutViewport().GetScrollAnimator().UserScroll(
581 granularity, scrollable_axis_delta, all_done);
582
583 // Remember to add any delta not used because of !userInputScrollable to the
584 // unusedScrollDelta in the result.
585 FloatSize unscrollable_axis_delta = layout_delta - scrollable_axis_delta;
586
587 return ScrollResult(
588 visual_result.did_scroll_x || layout_result.did_scroll_x,
589 visual_result.did_scroll_y || layout_result.did_scroll_y,
590 layout_result.unused_scroll_delta_x + unscrollable_axis_delta.Width(),
591 layout_result.unused_scroll_delta_y + unscrollable_axis_delta.Height());
592 }
593
ScrollAnimatorEnabled() const594 bool RootFrameViewport::ScrollAnimatorEnabled() const {
595 return LayoutViewport().ScrollAnimatorEnabled();
596 }
597
GetScrollElementId() const598 CompositorElementId RootFrameViewport::GetScrollElementId() const {
599 return LayoutViewport().GetScrollElementId();
600 }
601
GetScrollbarElementId(ScrollbarOrientation orientation)602 CompositorElementId RootFrameViewport::GetScrollbarElementId(
603 ScrollbarOrientation orientation) {
604 return GetVisualViewport().VisualViewportSuppliesScrollbars()
605 ? GetVisualViewport().GetScrollbarElementId(orientation)
606 : LayoutViewport().GetScrollbarElementId(orientation);
607 }
608
GetChromeClient() const609 ChromeClient* RootFrameViewport::GetChromeClient() const {
610 return LayoutViewport().GetChromeClient();
611 }
612
GetSmoothScrollSequencer() const613 SmoothScrollSequencer* RootFrameViewport::GetSmoothScrollSequencer() const {
614 return LayoutViewport().GetSmoothScrollSequencer();
615 }
616
ServiceScrollAnimations(double monotonic_time)617 void RootFrameViewport::ServiceScrollAnimations(double monotonic_time) {
618 ScrollableArea::ServiceScrollAnimations(monotonic_time);
619 LayoutViewport().ServiceScrollAnimations(monotonic_time);
620 GetVisualViewport().ServiceScrollAnimations(monotonic_time);
621 }
622
UpdateCompositorScrollAnimations()623 void RootFrameViewport::UpdateCompositorScrollAnimations() {
624 ScrollableArea::UpdateCompositorScrollAnimations();
625 LayoutViewport().UpdateCompositorScrollAnimations();
626 GetVisualViewport().UpdateCompositorScrollAnimations();
627 }
628
CancelProgrammaticScrollAnimation()629 void RootFrameViewport::CancelProgrammaticScrollAnimation() {
630 ScrollableArea::CancelProgrammaticScrollAnimation();
631 LayoutViewport().CancelProgrammaticScrollAnimation();
632 GetVisualViewport().CancelProgrammaticScrollAnimation();
633 }
634
ClearScrollableArea()635 void RootFrameViewport::ClearScrollableArea() {
636 ScrollableArea::ClearScrollableArea();
637 LayoutViewport().ClearScrollableArea();
638 GetVisualViewport().ClearScrollableArea();
639 }
640
GetPageScrollbarTheme() const641 ScrollbarTheme& RootFrameViewport::GetPageScrollbarTheme() const {
642 return LayoutViewport().GetPageScrollbarTheme();
643 }
644
GetSnapContainerData() const645 const cc::SnapContainerData* RootFrameViewport::GetSnapContainerData() const {
646 return LayoutViewport().GetSnapContainerData();
647 }
648
SetSnapContainerData(base::Optional<cc::SnapContainerData> data)649 void RootFrameViewport::SetSnapContainerData(
650 base::Optional<cc::SnapContainerData> data) {
651 LayoutViewport().SetSnapContainerData(data);
652 }
653
SetTargetSnapAreaElementIds(cc::TargetSnapAreaElementIds snap_target_ids)654 bool RootFrameViewport::SetTargetSnapAreaElementIds(
655 cc::TargetSnapAreaElementIds snap_target_ids) {
656 return LayoutViewport().SetTargetSnapAreaElementIds(snap_target_ids);
657 }
658
SnapContainerDataNeedsUpdate() const659 bool RootFrameViewport::SnapContainerDataNeedsUpdate() const {
660 return LayoutViewport().SnapContainerDataNeedsUpdate();
661 }
662
SetSnapContainerDataNeedsUpdate(bool needs_update)663 void RootFrameViewport::SetSnapContainerDataNeedsUpdate(bool needs_update) {
664 LayoutViewport().SetSnapContainerDataNeedsUpdate(needs_update);
665 }
666
NeedsResnap() const667 bool RootFrameViewport::NeedsResnap() const {
668 return LayoutViewport().NeedsResnap();
669 }
670
SetNeedsResnap(bool needs_resnap)671 void RootFrameViewport::SetNeedsResnap(bool needs_resnap) {
672 LayoutViewport().SetNeedsResnap(needs_resnap);
673 }
674
GetSnapPositionAndSetTarget(const cc::SnapSelectionStrategy & strategy)675 base::Optional<FloatPoint> RootFrameViewport::GetSnapPositionAndSetTarget(
676 const cc::SnapSelectionStrategy& strategy) {
677 return LayoutViewport().GetSnapPositionAndSetTarget(strategy);
678 }
679
Trace(Visitor * visitor) const680 void RootFrameViewport::Trace(Visitor* visitor) const {
681 visitor->Trace(visual_viewport_);
682 visitor->Trace(layout_viewport_);
683 ScrollableArea::Trace(visitor);
684 }
685
686 } // namespace blink
687