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