Upload upstream chromium 73.0.3683.0
[platform/framework/web/chromium-efl.git] / third_party / blink / renderer / core / paint / paint_layer_scrollable_area.cc
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights
3  * reserved.
4  *
5  * Portions are Copyright (C) 1998 Netscape Communications Corporation.
6  *
7  * Other contributors:
8  *   Robert O'Callahan <roc+@cs.cmu.edu>
9  *   David Baron <dbaron@fas.harvard.edu>
10  *   Christian Biesinger <cbiesinger@gmail.com>
11  *   Randall Jesup <rjesup@wgate.com>
12  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
13  *   Josh Soref <timeless@mac.com>
14  *   Boris Zbarsky <bzbarsky@mit.edu>
15  *
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  *
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
29  *
30  * Alternatively, the contents of this file may be used under the terms
31  * of either the Mozilla Public License Version 1.1, found at
32  * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
33  * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
34  * (the "GPL"), in which case the provisions of the MPL or the GPL are
35  * applicable instead of those above.  If you wish to allow use of your
36  * version of this file only under the terms of one of those two
37  * licenses (the MPL or the GPL) and not to allow others to use your
38  * version of this file under the LGPL, indicate your decision by
39  * deletingthe provisions above and replace them with the notice and
40  * other provisions required by the MPL or the GPL, as the case may be.
41  * If you do not delete the provisions above, a recipient may use your
42  * version of this file under any of the LGPL, the MPL or the GPL.
43  */
44
45 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
46
47 #include "base/numerics/checked_math.h"
48 #include "base/single_thread_task_runner.h"
49 #include "third_party/blink/public/platform/platform.h"
50 #include "third_party/blink/public/platform/task_type.h"
51 #include "third_party/blink/public/platform/web_scroll_into_view_params.h"
52 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
53 #include "third_party/blink/renderer/core/animation/scroll_timeline.h"
54 #include "third_party/blink/renderer/core/css/pseudo_style_request.h"
55 #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
56 #include "third_party/blink/renderer/core/dom/node.h"
57 #include "third_party/blink/renderer/core/dom/shadow_root.h"
58 #include "third_party/blink/renderer/core/editing/frame_selection.h"
59 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
60 #include "third_party/blink/renderer/core/frame/local_frame.h"
61 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
62 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
63 #include "third_party/blink/renderer/core/frame/page_scale_constraints_set.h"
64 #include "third_party/blink/renderer/core/frame/root_frame_viewport.h"
65 #include "third_party/blink/renderer/core/frame/settings.h"
66 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
67 #include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
68 #include "third_party/blink/renderer/core/html/forms/text_control_element.h"
69 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
70 #include "third_party/blink/renderer/core/input/event_handler.h"
71 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
72 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
73 #include "third_party/blink/renderer/core/layout/layout_scrollbar.h"
74 #include "third_party/blink/renderer/core/layout/layout_scrollbar_part.h"
75 #include "third_party/blink/renderer/core/layout/layout_theme.h"
76 #include "third_party/blink/renderer/core/layout/layout_view.h"
77 #include "third_party/blink/renderer/core/layout/logical_values.h"
78 #include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
79 #include "third_party/blink/renderer/core/loader/document_loader.h"
80 #include "third_party/blink/renderer/core/page/chrome_client.h"
81 #include "third_party/blink/renderer/core/page/focus_controller.h"
82 #include "third_party/blink/renderer/core/page/page.h"
83 #include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
84 #include "third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h"
85 #include "third_party/blink/renderer/core/page/scrolling/root_scroller_util.h"
86 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
87 #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
88 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
89 #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
90 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
91 #include "third_party/blink/renderer/core/paint/find_paint_offset_and_visual_rect_needing_update.h"
92 #include "third_party/blink/renderer/core/paint/paint_invalidator.h"
93 #include "third_party/blink/renderer/core/paint/paint_layer_fragment.h"
94 #include "third_party/blink/renderer/core/scroll/scroll_animator_base.h"
95 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
96 #include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
97 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
98 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
99 #include "third_party/blink/renderer/platform/scroll/scroll_alignment.h"
100
101 namespace blink {
102
103 namespace {
104
105 // Default value is set to 15 as the default
106 // minimum size used by firefox is 15x15.
107 static const int kDefaultMinimumWidthForResizing = 15;
108 static const int kDefaultMinimumHeightForResizing = 15;
109
110 }  // namespace
111
112 static LayoutRect LocalToAbsolute(const LayoutBox& box, LayoutRect rect) {
113   return LayoutRect(
114       box.LocalToAbsoluteQuad(FloatQuad(FloatRect(rect)), kUseTransforms)
115           .BoundingBox());
116 }
117
118 static LayoutRect AbsoluteToLocal(const LayoutBox& box, LayoutRect rect) {
119   return LayoutRect(
120       box.AbsoluteToLocalQuad(FloatQuad(FloatRect(rect)), kUseTransforms)
121           .BoundingBox());
122 }
123
124 PaintLayerScrollableAreaRareData::PaintLayerScrollableAreaRareData() = default;
125
126 const int kResizerControlExpandRatioForTouch = 2;
127
128 PaintLayerScrollableArea::PaintLayerScrollableArea(PaintLayer& layer)
129     : layer_(&layer),
130       in_resize_mode_(false),
131       scrolls_overflow_(false),
132       in_overflow_relayout_(false),
133       allow_second_overflow_relayout_(false),
134       needs_composited_scrolling_(false),
135       rebuild_horizontal_scrollbar_layer_(false),
136       rebuild_vertical_scrollbar_layer_(false),
137       needs_scroll_offset_clamp_(false),
138       needs_relayout_(false),
139       had_horizontal_scrollbar_before_relayout_(false),
140       had_vertical_scrollbar_before_relayout_(false),
141       scroll_origin_changed_(false),
142       scrollbar_manager_(*this),
143       scroll_corner_(nullptr),
144       resizer_(nullptr),
145       scroll_anchor_(this),
146       non_composited_main_thread_scrolling_reasons_(0),
147       horizontal_scrollbar_previously_was_overlay_(false),
148       vertical_scrollbar_previously_was_overlay_(false),
149       scrolling_background_display_item_client_(*this) {
150   Node* node = GetLayoutBox()->GetNode();
151   if (node && node->IsElementNode()) {
152     // We save and restore only the scrollOffset as the other scroll values are
153     // recalculated.
154     Element* element = ToElement(node);
155     scroll_offset_ = element->SavedLayerScrollOffset();
156     if (!scroll_offset_.IsZero())
157       GetScrollAnimator().SetCurrentOffset(scroll_offset_);
158     element->SetSavedLayerScrollOffset(ScrollOffset());
159   }
160   UpdateResizerAreaSet();
161 }
162
163 PaintLayerScrollableArea::~PaintLayerScrollableArea() {
164   CHECK(HasBeenDisposed());
165 }
166
167 void PaintLayerScrollableArea::DidScroll(const FloatPoint& position) {
168   ScrollableArea::DidScroll(position);
169   // This should be alive if it receives composited scroll callbacks.
170   CHECK(!HasBeenDisposed());
171 }
172
173 void PaintLayerScrollableArea::Dispose() {
174   if (InResizeMode() && !GetLayoutBox()->DocumentBeingDestroyed()) {
175     if (LocalFrame* frame = GetLayoutBox()->GetFrame())
176       frame->GetEventHandler().ResizeScrollableAreaDestroyed();
177   }
178
179   if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
180     if (LocalFrameView* frame_view = frame->View()) {
181       frame_view->RemoveScrollableArea(this);
182       frame_view->RemoveAnimatingScrollableArea(this);
183     }
184   }
185
186   non_composited_main_thread_scrolling_reasons_ = 0;
187
188   if (ScrollingCoordinator* scrolling_coordinator = GetScrollingCoordinator())
189     scrolling_coordinator->WillDestroyScrollableArea(this);
190
191   if (!GetLayoutBox()->DocumentBeingDestroyed()) {
192     Node* node = GetLayoutBox()->GetNode();
193     // FIXME: Make setSavedLayerScrollOffset take DoubleSize. crbug.com/414283.
194     if (node && node->IsElementNode())
195       ToElement(node)->SetSavedLayerScrollOffset(scroll_offset_);
196   }
197
198   if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
199     if (LocalFrameView* frame_view = frame->View())
200       frame_view->RemoveResizerArea(*GetLayoutBox());
201   }
202
203   // Note: it is not safe to call ScrollAnchor::clear if the document is being
204   // destroyed, because LayoutObjectChildList::removeChildNode skips the call to
205   // willBeRemovedFromTree,
206   // leaving the ScrollAnchor with a stale LayoutObject pointer.
207   scroll_anchor_.Dispose();
208
209   GetLayoutBox()
210       ->GetDocument()
211       .GetPage()
212       ->GlobalRootScrollerController()
213       .DidDisposeScrollableArea(*this);
214
215   scrollbar_manager_.Dispose();
216
217   if (scroll_corner_)
218     scroll_corner_->Destroy();
219   if (resizer_)
220     resizer_->Destroy();
221
222   ClearScrollableArea();
223
224   if (SmoothScrollSequencer* sequencer = GetSmoothScrollSequencer())
225     sequencer->DidDisposeScrollableArea(*this);
226
227   layer_ = nullptr;
228 }
229
230 bool PaintLayerScrollableArea::HasBeenDisposed() const {
231   return !layer_;
232 }
233
234 void PaintLayerScrollableArea::Trace(blink::Visitor* visitor) {
235   visitor->Trace(scrollbar_manager_);
236   visitor->Trace(scroll_anchor_);
237   visitor->Trace(scrolling_background_display_item_client_);
238   ScrollableArea::Trace(visitor);
239 }
240
241 bool PaintLayerScrollableArea::IsThrottled() const {
242   return GetLayoutBox()->GetFrame()->ShouldThrottleRendering();
243 }
244
245 ChromeClient* PaintLayerScrollableArea::GetChromeClient() const {
246   if (HasBeenDisposed())
247     return nullptr;
248   if (Page* page = GetLayoutBox()->GetFrame()->GetPage())
249     return &page->GetChromeClient();
250   return nullptr;
251 }
252
253 SmoothScrollSequencer* PaintLayerScrollableArea::GetSmoothScrollSequencer()
254     const {
255   if (HasBeenDisposed())
256     return nullptr;
257
258   return &GetLayoutBox()->GetFrame()->GetSmoothScrollSequencer();
259 }
260
261 GraphicsLayer* PaintLayerScrollableArea::LayerForScrolling() const {
262   return Layer()->HasCompositedLayerMapping()
263              ? Layer()->GetCompositedLayerMapping()->ScrollingContentsLayer()
264              : nullptr;
265 }
266
267 GraphicsLayer* PaintLayerScrollableArea::LayerForHorizontalScrollbar() const {
268   // See crbug.com/343132.
269   DisableCompositingQueryAsserts disabler;
270
271   return Layer()->HasCompositedLayerMapping()
272              ? Layer()
273                    ->GetCompositedLayerMapping()
274                    ->LayerForHorizontalScrollbar()
275              : nullptr;
276 }
277
278 GraphicsLayer* PaintLayerScrollableArea::LayerForVerticalScrollbar() const {
279   // See crbug.com/343132.
280   DisableCompositingQueryAsserts disabler;
281
282   return Layer()->HasCompositedLayerMapping()
283              ? Layer()->GetCompositedLayerMapping()->LayerForVerticalScrollbar()
284              : nullptr;
285 }
286
287 GraphicsLayer* PaintLayerScrollableArea::LayerForScrollCorner() const {
288   // See crbug.com/343132.
289   DisableCompositingQueryAsserts disabler;
290
291   return Layer()->HasCompositedLayerMapping()
292              ? Layer()->GetCompositedLayerMapping()->LayerForScrollCorner()
293              : nullptr;
294 }
295
296 bool PaintLayerScrollableArea::IsActive() const {
297   Page* page = GetLayoutBox()->GetFrame()->GetPage();
298   return page && page->GetFocusController().IsActive();
299 }
300
301 bool PaintLayerScrollableArea::IsScrollCornerVisible() const {
302   return !ScrollCornerRect().IsEmpty();
303 }
304
305 static int CornerStart(const LayoutBox& box,
306                        int min_x,
307                        int max_x,
308                        int thickness) {
309   if (box.ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
310     return min_x + box.StyleRef().BorderLeftWidth();
311   return max_x - thickness - box.StyleRef().BorderRightWidth();
312 }
313
314 IntRect PaintLayerScrollableArea::PaintLayerScrollableArea::CornerRect(
315     const IntRect& bounds) const {
316   int horizontal_thickness;
317   int vertical_thickness;
318   if (!VerticalScrollbar() && !HorizontalScrollbar()) {
319     // FIXME: This isn't right. We need to know the thickness of custom
320     // scrollbars even when they don't exist in order to set the resizer square
321     // size properly.
322     horizontal_thickness = GetPageScrollbarTheme().ScrollbarThickness();
323     vertical_thickness = horizontal_thickness;
324   } else if (VerticalScrollbar() && !HorizontalScrollbar()) {
325     horizontal_thickness = VerticalScrollbar()->ScrollbarThickness();
326     vertical_thickness = horizontal_thickness;
327   } else if (HorizontalScrollbar() && !VerticalScrollbar()) {
328     vertical_thickness = HorizontalScrollbar()->ScrollbarThickness();
329     horizontal_thickness = vertical_thickness;
330   } else {
331     horizontal_thickness = VerticalScrollbar()->ScrollbarThickness();
332     vertical_thickness = HorizontalScrollbar()->ScrollbarThickness();
333   }
334   return IntRect(CornerStart(*GetLayoutBox(), bounds.X(), bounds.MaxX(),
335                              horizontal_thickness),
336                  bounds.MaxY() - vertical_thickness -
337                      GetLayoutBox()->StyleRef().BorderBottomWidth(),
338                  horizontal_thickness, vertical_thickness);
339 }
340
341 IntRect PaintLayerScrollableArea::ScrollCornerRect() const {
342   // We have a scrollbar corner when a scrollbar is visible and not filling the
343   // entire length of the box.
344   // This happens when:
345   // (a) A resizer is present and at least one scrollbar is present
346   // (b) Both scrollbars are present.
347   bool has_horizontal_bar = HorizontalScrollbar();
348   bool has_vertical_bar = VerticalScrollbar();
349   bool has_resizer = GetLayoutBox()->StyleRef().Resize() != EResize::kNone;
350   if ((has_horizontal_bar && has_vertical_bar) ||
351       (has_resizer && (has_horizontal_bar || has_vertical_bar))) {
352     return CornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
353         Layer()->SubpixelAccumulation()));
354   }
355   return IntRect();
356 }
357
358 IntRect
359 PaintLayerScrollableArea::ConvertFromScrollbarToContainingEmbeddedContentView(
360     const Scrollbar& scrollbar,
361     const IntRect& scrollbar_rect) const {
362   LayoutView* view = GetLayoutBox()->View();
363   if (!view)
364     return scrollbar_rect;
365
366   IntRect rect = scrollbar_rect;
367   rect.Move(ScrollbarOffset(scrollbar));
368
369   return view->GetFrameView()->ConvertFromLayoutObject(*GetLayoutBox(), rect);
370 }
371
372 IntPoint
373 PaintLayerScrollableArea::ConvertFromScrollbarToContainingEmbeddedContentView(
374     const Scrollbar& scrollbar,
375     const IntPoint& scrollbar_point) const {
376   LayoutView* view = GetLayoutBox()->View();
377   if (!view)
378     return scrollbar_point;
379
380   IntPoint point = scrollbar_point;
381   point.Move(ScrollbarOffset(scrollbar));
382   return view->GetFrameView()->ConvertFromLayoutObject(*GetLayoutBox(), point);
383 }
384
385 IntPoint
386 PaintLayerScrollableArea::ConvertFromContainingEmbeddedContentViewToScrollbar(
387     const Scrollbar& scrollbar,
388     const IntPoint& parent_point) const {
389   LayoutView* view = GetLayoutBox()->View();
390   if (!view)
391     return parent_point;
392
393   IntPoint point = view->GetFrameView()->ConvertToLayoutObject(*GetLayoutBox(),
394                                                                parent_point);
395
396   point.Move(-ScrollbarOffset(scrollbar));
397   return point;
398 }
399
400 IntPoint PaintLayerScrollableArea::ConvertFromRootFrame(
401     const IntPoint& point_in_root_frame) const {
402   LayoutView* view = GetLayoutBox()->View();
403   if (!view)
404     return point_in_root_frame;
405
406   return view->GetFrameView()->ConvertFromRootFrame(point_in_root_frame);
407 }
408
409 int PaintLayerScrollableArea::ScrollSize(
410     ScrollbarOrientation orientation) const {
411   IntSize scroll_dimensions =
412       MaximumScrollOffsetInt() - MinimumScrollOffsetInt();
413   return (orientation == kHorizontalScrollbar) ? scroll_dimensions.Width()
414                                                : scroll_dimensions.Height();
415 }
416
417 void PaintLayerScrollableArea::UpdateScrollOffset(
418     const ScrollOffset& new_offset,
419     ScrollType scroll_type) {
420   if (HasBeenDisposed() || GetScrollOffset() == new_offset)
421     return;
422
423   scroll_offset_ = new_offset;
424
425   LocalFrame* frame = GetLayoutBox()->GetFrame();
426   DCHECK(frame);
427
428   LocalFrameView* frame_view = GetLayoutBox()->GetFrameView();
429   bool is_root_layer = Layer()->IsRootLayer();
430
431   TRACE_EVENT1("devtools.timeline", "ScrollLayer", "data",
432                inspector_scroll_layer_event::Data(GetLayoutBox()));
433
434   // FIXME(420741): Resolve circular dependency between scroll offset and
435   // compositing state, and remove this disabler.
436   DisableCompositingQueryAsserts disabler;
437
438   // Update the positions of our child layers (if needed as only fixed layers
439   // should be impacted by a scroll).
440   if (!frame_view->IsInPerformLayout()) {
441     // If we're in the middle of layout, we'll just update layers once layout
442     // has finished.
443     Layer()->UpdateLayerPositionsAfterOverflowScroll();
444     // Update regions, scrolling may change the clip of a particular region.
445     frame_view->UpdateDocumentAnnotatedRegions();
446
447     // As a performance optimization, the scroll offset of the root layer is
448     // not included in EmbeddedContentView's stored frame rect, so there is no
449     // reason to mark the FrameView as needing a geometry update here.
450     if (is_root_layer)
451       frame_view->SetRootLayerDidScroll();
452     else
453       frame_view->SetNeedsUpdateGeometries();
454   }
455   UpdateCompositingLayersAfterScroll();
456
457   GetLayoutBox()->MayUpdateHoverWhenContentUnderMouseChanged(
458       frame->GetEventHandler());
459
460   if (scroll_type == kUserScroll || scroll_type == kCompositorScroll) {
461     Page* page = frame->GetPage();
462     if (page)
463       page->GetChromeClient().ClearToolTip(*frame);
464   }
465
466   InvalidatePaintForScrollOffsetChange();
467
468   // The scrollOffsetTranslation paint property depends on the scroll offset.
469   // (see: PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation).
470   GetLayoutBox()->SetNeedsPaintPropertyUpdate();
471
472   // Schedule the scroll DOM event.
473   if (GetLayoutBox()->GetNode()) {
474     GetLayoutBox()->GetNode()->GetDocument().EnqueueScrollEventForNode(
475         GetLayoutBox()->GetNode());
476   }
477
478   GetLayoutBox()->View()->ClearHitTestCache();
479
480   // Inform the FrameLoader of the new scroll position, so it can be restored
481   // when navigating back.
482   if (is_root_layer) {
483     frame_view->GetFrame().Loader().SaveScrollState();
484     frame_view->DidChangeScrollOffset();
485     if (scroll_type == kCompositorScroll || scroll_type == kUserScroll) {
486       if (DocumentLoader* document_loader = frame->Loader().GetDocumentLoader())
487         document_loader->GetInitialScrollState().was_scrolled_by_user = true;
488     }
489   }
490
491   if (FragmentAnchor* anchor = frame_view->GetFragmentAnchor())
492     anchor->DidScroll(scroll_type);
493
494   if (IsExplicitScrollType(scroll_type)) {
495     if (scroll_type != kCompositorScroll)
496       ShowOverlayScrollbars();
497     GetScrollAnchor()->Clear();
498   }
499
500   if (AXObjectCache* cache =
501           GetLayoutBox()->GetDocument().ExistingAXObjectCache())
502     cache->HandleScrollPositionChanged(GetLayoutBox());
503 }
504
505 void PaintLayerScrollableArea::InvalidatePaintForScrollOffsetChange() {
506   InvalidatePaintForStickyDescendants();
507
508   auto* box = GetLayoutBox();
509   auto* frame_view = box->GetFrameView();
510   frame_view->InvalidateBackgroundAttachmentFixedDescendantsOnScroll(*box);
511
512   if (box->IsLayoutView() && frame_view->HasViewportConstrainedObjects() &&
513       !frame_view->InvalidateViewportConstrainedObjects()) {
514     box->SetShouldDoFullPaintInvalidation();
515     box->SetSubtreeShouldCheckForPaintInvalidation();
516   }
517
518   // TODO(chrishtr): remove this slow path once crbug.com/906885 is fixed.
519   // See also https://bugs.chromium.org/p/chromium/issues/detail?id=903287#c10.
520   if (Layer()->EnclosingPaginationLayer())
521     box->SetSubtreeShouldCheckForPaintInvalidation();
522
523   // If not composited, background always paints into the main graphics layer.
524   bool background_paint_in_graphics_layer = true;
525   bool background_paint_in_scrolling_contents = false;
526   if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
527       UsesCompositedScrolling()) {
528     auto background_paint_location = box->GetBackgroundPaintLocation();
529     background_paint_in_graphics_layer =
530         background_paint_location & kBackgroundPaintInGraphicsLayer;
531     background_paint_in_scrolling_contents =
532         background_paint_location & kBackgroundPaintInScrollingContents;
533   }
534
535   // Both local attachment background painted in graphics layer and normal
536   // attachment background painted in scrolling contents require paint
537   // invalidation. Fixed attachment background has been dealt with in
538   // frame_view->InvalidateBackgroundAttachmentFixedDescendantsOnScroll().
539   auto background_layers = box->StyleRef().BackgroundLayers();
540   if ((background_layers.AnyLayerHasLocalAttachmentImage() &&
541        background_paint_in_graphics_layer) ||
542       (background_layers.AnyLayerHasDefaultAttachmentImage() &&
543        background_paint_in_scrolling_contents))
544     box->SetBackgroundNeedsFullPaintInvalidation();
545
546   // If any scrolling content might have been clipped by a cull rect, then
547   // that cull rect could be affected by scroll offset. For composited
548   // scrollers, this will be taken care of by the interest rect computation
549   // in CompositedLayerMapping.
550   // TODO(wangxianzhu): replace this shortcut with interest rects.
551   if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
552       !UsesCompositedScrolling())
553     Layer()->SetNeedsRepaint();
554 }
555
556 IntSize PaintLayerScrollableArea::ScrollOffsetInt() const {
557   return FlooredIntSize(scroll_offset_);
558 }
559
560 ScrollOffset PaintLayerScrollableArea::GetScrollOffset() const {
561   return scroll_offset_;
562 }
563
564 IntSize PaintLayerScrollableArea::MinimumScrollOffsetInt() const {
565   return ToIntSize(-ScrollOrigin());
566 }
567
568 IntSize PaintLayerScrollableArea::MaximumScrollOffsetInt() const {
569   if (!GetLayoutBox() || !GetLayoutBox()->HasOverflowClip())
570     return ToIntSize(-ScrollOrigin());
571
572   IntSize content_size = ContentsSize();
573
574   Page* page = GetLayoutBox()->GetDocument().GetPage();
575   DCHECK(page);
576   TopDocumentRootScrollerController& controller =
577       page->GlobalRootScrollerController();
578
579   // The global root scroller should be clipped by the top LocalFrameView rather
580   // than it's overflow clipping box. This is to ensure that content exposed by
581   // hiding the URL bar at the bottom of the screen is visible.
582   IntSize visible_size;
583   if (this == controller.RootScrollerArea()) {
584     visible_size = controller.RootScrollerVisibleArea();
585   } else {
586     visible_size =
587         PixelSnappedIntRect(GetLayoutBox()->OverflowClipRect(
588                                 GetLayoutBox()->Location(),
589                                 kIgnorePlatformAndCSSOverlayScrollbarSize))
590             .Size();
591   }
592
593   // TODO(skobes): We should really ASSERT that contentSize >= visibleSize
594   // when we are not the root layer, but we can't because contentSize is
595   // based on stale layout overflow data (http://crbug.com/576933).
596   content_size = content_size.ExpandedTo(visible_size);
597
598   return ToIntSize(-ScrollOrigin() + (content_size - visible_size));
599 }
600
601 void PaintLayerScrollableArea::VisibleSizeChanged() {
602   ShowOverlayScrollbars();
603 }
604
605 LayoutRect PaintLayerScrollableArea::LayoutContentRect(
606     IncludeScrollbarsInRect scrollbar_inclusion) const {
607   // LayoutContentRect is conceptually the same as the box's client rect.
608   LayoutSize layer_size(Layer()->Size());
609   LayoutUnit border_width = GetLayoutBox()->BorderWidth();
610   LayoutUnit border_height = GetLayoutBox()->BorderHeight();
611   LayoutUnit horizontal_scrollbar_height, vertical_scrollbar_width;
612   if (scrollbar_inclusion == kExcludeScrollbars) {
613     horizontal_scrollbar_height = LayoutUnit(
614         HorizontalScrollbar() && !HorizontalScrollbar()->IsOverlayScrollbar()
615             ? HorizontalScrollbar()->ScrollbarThickness()
616             : 0);
617     vertical_scrollbar_width = LayoutUnit(
618         VerticalScrollbar() && !VerticalScrollbar()->IsOverlayScrollbar()
619             ? VerticalScrollbar()->ScrollbarThickness()
620             : 0);
621   }
622
623   return LayoutRect(
624       LayoutPoint(ScrollPosition()),
625       LayoutSize(
626           layer_size.Width() - border_width - vertical_scrollbar_width,
627           layer_size.Height() - border_height - horizontal_scrollbar_height)
628           .ExpandedTo(LayoutSize()));
629 }
630
631 IntRect PaintLayerScrollableArea::VisibleContentRect(
632     IncludeScrollbarsInRect scrollbar_inclusion) const {
633   LayoutRect layout_content_rect(LayoutContentRect(scrollbar_inclusion));
634   // TODO(szager): It's not clear that Floor() is the right thing to do here;
635   // what is the correct behavior for fractional scroll offsets?
636   return IntRect(FlooredIntPoint(layout_content_rect.Location()),
637                  PixelSnappedIntSize(layout_content_rect.Size(),
638                                      GetLayoutBox()->Location()));
639 }
640
641 LayoutRect PaintLayerScrollableArea::VisibleScrollSnapportRect(
642     IncludeScrollbarsInRect scrollbar_inclusion) const {
643   const ComputedStyle* style = GetLayoutBox()->Style();
644   LayoutRect layout_content_rect(LayoutContentRect(scrollbar_inclusion));
645   layout_content_rect.MoveBy(LayoutPoint(-ScrollOrigin()));
646   LayoutRectOutsets padding(MinimumValueForLength(style->ScrollPaddingTop(),
647                                                   layout_content_rect.Height()),
648                             MinimumValueForLength(style->ScrollPaddingRight(),
649                                                   layout_content_rect.Width()),
650                             MinimumValueForLength(style->ScrollPaddingBottom(),
651                                                   layout_content_rect.Height()),
652                             MinimumValueForLength(style->ScrollPaddingLeft(),
653                                                   layout_content_rect.Width()));
654   layout_content_rect.Contract(padding);
655   return layout_content_rect;
656 }
657
658 IntSize PaintLayerScrollableArea::ContentsSize() const {
659   LayoutPoint offset(
660       GetLayoutBox()->ClientLeft() + GetLayoutBox()->Location().X(),
661       GetLayoutBox()->ClientTop() + GetLayoutBox()->Location().Y());
662   return PixelSnappedContentsSize(offset);
663 }
664
665 IntSize PaintLayerScrollableArea::PixelSnappedContentsSize(
666     const LayoutPoint& paint_offset) const {
667   return PixelSnappedIntSize(overflow_rect_.Size(), paint_offset);
668 }
669
670 void PaintLayerScrollableArea::ContentsResized() {
671   ScrollableArea::ContentsResized();
672   // Need to update the bounds of the scroll property.
673   GetLayoutBox()->SetNeedsPaintPropertyUpdate();
674   Layer()->SetNeedsCompositingInputsUpdate();
675 }
676
677 IntPoint PaintLayerScrollableArea::LastKnownMousePosition() const {
678   return GetLayoutBox()->GetFrame() ? GetLayoutBox()
679                                           ->GetFrame()
680                                           ->GetEventHandler()
681                                           .LastKnownMousePositionInRootFrame()
682                                     : IntPoint();
683 }
684
685 bool PaintLayerScrollableArea::ScrollAnimatorEnabled() const {
686   if (HasBeenDisposed())
687     return false;
688   if (Settings* settings = GetLayoutBox()->GetFrame()->GetSettings())
689     return settings->GetScrollAnimatorEnabled();
690   return false;
691 }
692
693 bool PaintLayerScrollableArea::ShouldSuspendScrollAnimations() const {
694   if (HasBeenDisposed())
695     return true;
696   LayoutView* view = GetLayoutBox()->View();
697   if (!view)
698     return true;
699   return !GetLayoutBox()->GetDocument().LoadEventFinished();
700 }
701
702 void PaintLayerScrollableArea::ScrollbarVisibilityChanged() {
703   UpdateScrollbarEnabledState();
704
705   // Paint properties need to be updated, because clip rects
706   // are affected by overlay scrollbars.
707   layer_->GetLayoutObject().SetNeedsPaintPropertyUpdate();
708
709   // TODO(chrishr): this should be able to be removed.
710   layer_->ClearClipRects();
711
712   if (LayoutView* view = GetLayoutBox()->View())
713     view->ClearHitTestCache();
714 }
715
716 void PaintLayerScrollableArea::ScrollbarFrameRectChanged() {
717   // Size of non-overlay scrollbar affects overflow clip rect.
718   if (!HasOverlayScrollbars())
719     GetLayoutBox()->SetNeedsPaintPropertyUpdate();
720 }
721
722 bool PaintLayerScrollableArea::ScrollbarsCanBeActive() const {
723   LayoutView* view = GetLayoutBox()->View();
724   if (!view)
725     return false;
726
727   // TODO(szager): This conditional is weird and likely obsolete. Originally
728   // added in commit eb0d49caaee2b275ff524d3945a74e8d9180eb7d.
729   LocalFrameView* frame_view = view->GetFrameView();
730   if (frame_view != frame_view->GetFrame().View())
731     return false;
732
733   return !!frame_view->GetFrame().GetDocument();
734 }
735
736 IntRect PaintLayerScrollableArea::ScrollableAreaBoundingBox() const {
737   if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
738     if (LocalFrameView* local_root = frame->LocalFrameRoot().View()) {
739       return local_root->RootFrameToDocument(frame->View()->ConvertToRootFrame(
740           GetLayoutBox()->AbsoluteBoundingBoxRect(0)));
741     }
742   }
743   return IntRect();
744 }
745
746 void PaintLayerScrollableArea::RegisterForAnimation() {
747   if (HasBeenDisposed())
748     return;
749   if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
750     if (LocalFrameView* frame_view = frame->View())
751       frame_view->AddAnimatingScrollableArea(this);
752   }
753 }
754
755 void PaintLayerScrollableArea::DeregisterForAnimation() {
756   if (HasBeenDisposed())
757     return;
758   if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
759     if (LocalFrameView* frame_view = frame->View())
760       frame_view->RemoveAnimatingScrollableArea(this);
761   }
762 }
763
764 bool PaintLayerScrollableArea::UserInputScrollable(
765     ScrollbarOrientation orientation) const {
766   if (orientation == kVerticalScrollbar &&
767       GetLayoutBox()->GetDocument().IsVerticalScrollEnforced()) {
768     return false;
769   }
770
771   if (GetLayoutBox()->IsIntrinsicallyScrollable(orientation))
772     return true;
773
774   if (GetLayoutBox()->IsLayoutView()) {
775     Document& document = GetLayoutBox()->GetDocument();
776     Element* fullscreen_element = Fullscreen::FullscreenElementFrom(document);
777     if (fullscreen_element && fullscreen_element != document.documentElement())
778       return false;
779
780     ScrollbarMode h_mode;
781     ScrollbarMode v_mode;
782     ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
783     ScrollbarMode mode =
784         (orientation == kHorizontalScrollbar) ? h_mode : v_mode;
785     return mode == kScrollbarAuto || mode == kScrollbarAlwaysOn;
786   }
787
788   EOverflow overflow_style = (orientation == kHorizontalScrollbar)
789                                  ? GetLayoutBox()->StyleRef().OverflowX()
790                                  : GetLayoutBox()->StyleRef().OverflowY();
791   return (overflow_style == EOverflow::kScroll ||
792           overflow_style == EOverflow::kAuto ||
793           overflow_style == EOverflow::kOverlay);
794 }
795
796 bool PaintLayerScrollableArea::ShouldPlaceVerticalScrollbarOnLeft() const {
797   return GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft();
798 }
799
800 int PaintLayerScrollableArea::PageStep(ScrollbarOrientation orientation) const {
801   // Paging scroll operations should take scroll-padding into account [1]. So we
802   // use the snapport rect to calculate the page step instead of the visible
803   // rect.
804   // [1] https://drafts.csswg.org/css-scroll-snap/#scroll-padding
805   IntSize snapport_size = VisibleScrollSnapportRect().PixelSnappedSize();
806   int length = (orientation == kHorizontalScrollbar) ? snapport_size.Width()
807                                                      : snapport_size.Height();
808   int min_page_step = static_cast<float>(length) *
809                       ScrollableArea::MinFractionToStepWhenPaging();
810   int page_step = max(min_page_step, length - MaxOverlapBetweenPages());
811   return max(page_step, 1);
812 }
813
814 LayoutBox* PaintLayerScrollableArea::GetLayoutBox() const {
815   return layer_ ? layer_->GetLayoutBox() : nullptr;
816 }
817
818 PaintLayer* PaintLayerScrollableArea::Layer() const {
819   return layer_;
820 }
821
822 LayoutUnit PaintLayerScrollableArea::ScrollWidth() const {
823   return overflow_rect_.Width();
824 }
825
826 LayoutUnit PaintLayerScrollableArea::ScrollHeight() const {
827   return overflow_rect_.Height();
828 }
829
830 void PaintLayerScrollableArea::UpdateScrollOrigin() {
831   // This should do nothing prior to first layout; the if-clause will catch
832   // that.
833   if (OverflowRect().IsEmpty())
834     return;
835   LayoutRect scrollable_overflow(overflow_rect_);
836   scrollable_overflow.Move(-GetLayoutBox()->BorderLeft(),
837                            -GetLayoutBox()->BorderTop());
838   IntPoint new_origin(FlooredIntPoint(-scrollable_overflow.Location()) +
839                       GetLayoutBox()->OriginAdjustmentForScrollbars());
840   if (new_origin != scroll_origin_)
841     scroll_origin_changed_ = true;
842   scroll_origin_ = new_origin;
843 }
844
845 void PaintLayerScrollableArea::UpdateScrollDimensions() {
846   LayoutRect new_overflow_rect = GetLayoutBox()->LayoutOverflowRect();
847   GetLayoutBox()->FlipForWritingMode(new_overflow_rect);
848
849   // The layout viewport can be larger than the document's layout overflow when
850   // top controls are hidden.  Expand the overflow here to ensure that our
851   // contents size >= visible size.
852   new_overflow_rect.Unite(
853       LayoutRect(new_overflow_rect.Location(),
854                  LayoutContentRect(kExcludeScrollbars).Size()));
855
856   if (overflow_rect_.Size() != new_overflow_rect.Size())
857     ContentsResized();
858   overflow_rect_ = new_overflow_rect;
859   UpdateScrollOrigin();
860 }
861
862 void PaintLayerScrollableArea::UpdateScrollbarEnabledState() {
863   bool force_disable =
864       GetPageScrollbarTheme().ShouldDisableInvisibleScrollbars() &&
865       ScrollbarsHiddenIfOverlay();
866
867   if (HorizontalScrollbar())
868     HorizontalScrollbar()->SetEnabled(HasHorizontalOverflow() &&
869                                       !force_disable);
870   if (VerticalScrollbar())
871     VerticalScrollbar()->SetEnabled(HasVerticalOverflow() && !force_disable);
872 }
873
874 void PaintLayerScrollableArea::UpdateScrollbarProportions() {
875   if (Scrollbar* horizontal_scrollbar = HorizontalScrollbar())
876     horizontal_scrollbar->SetProportion(VisibleWidth(), ContentsSize().Width());
877   if (Scrollbar* vertical_scrollbar = VerticalScrollbar())
878     vertical_scrollbar->SetProportion(VisibleHeight(), ContentsSize().Height());
879 }
880
881 void PaintLayerScrollableArea::SetScrollOffsetUnconditionally(
882     const ScrollOffset& offset,
883     ScrollType scroll_type) {
884   CancelScrollAnimation();
885   ScrollOffsetChanged(offset, scroll_type);
886 }
887
888 void PaintLayerScrollableArea::UpdateAfterLayout() {
889   bool scrollbars_are_frozen =
890       (in_overflow_relayout_ && !allow_second_overflow_relayout_) ||
891       FreezeScrollbarsScope::ScrollbarsAreFrozen();
892   allow_second_overflow_relayout_ = false;
893
894   if (NeedsScrollbarReconstruction()) {
895     SetHasHorizontalScrollbar(false);
896     SetHasVerticalScrollbar(false);
897   }
898
899   UpdateScrollDimensions();
900
901   bool had_horizontal_scrollbar = HasHorizontalScrollbar();
902   bool had_vertical_scrollbar = HasVerticalScrollbar();
903
904   bool needs_horizontal_scrollbar;
905   bool needs_vertical_scrollbar;
906   ComputeScrollbarExistence(needs_horizontal_scrollbar,
907                             needs_vertical_scrollbar);
908
909   // Removing auto scrollbars is a heuristic and can be incorrect if the content
910   // size depends on the scrollbar size (e.g., sized with percentages). Removing
911   // scrollbars can require two additional layout passes so this is only done on
912   // the first layout (!in_overflow_layout).
913   if (!in_overflow_relayout_ && !scrollbars_are_frozen &&
914       TryRemovingAutoScrollbars(needs_horizontal_scrollbar,
915                                 needs_vertical_scrollbar)) {
916     needs_horizontal_scrollbar = needs_vertical_scrollbar = false;
917     allow_second_overflow_relayout_ = true;
918   }
919
920   bool horizontal_scrollbar_should_change =
921       needs_horizontal_scrollbar != had_horizontal_scrollbar;
922   bool vertical_scrollbar_should_change =
923       needs_vertical_scrollbar != had_vertical_scrollbar;
924
925   bool scrollbars_will_change =
926       !scrollbars_are_frozen &&
927       (horizontal_scrollbar_should_change || vertical_scrollbar_should_change);
928   if (scrollbars_will_change) {
929     SetHasHorizontalScrollbar(needs_horizontal_scrollbar);
930     SetHasVerticalScrollbar(needs_vertical_scrollbar);
931
932     // If we change scrollbars on the layout viewport, the visual viewport
933     // needs to update paint properties to account for the correct
934     // scrollbounds.
935     if (LocalFrameView* frame_view = GetLayoutBox()->GetFrameView()) {
936       if (this == frame_view->LayoutViewport()) {
937         GetLayoutBox()
938             ->GetFrame()
939             ->GetPage()
940             ->GetVisualViewport()
941             .SetNeedsPaintPropertyUpdate();
942       }
943     }
944
945     if (HasScrollbar())
946       UpdateScrollCornerStyle();
947
948     Layer()->UpdateSelfPaintingLayer();
949
950     // Force an update since we know the scrollbars have changed things.
951     if (GetLayoutBox()->GetDocument().HasAnnotatedRegions())
952       GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);
953
954     // Our proprietary overflow: overlay value doesn't trigger a layout.
955     if (((horizontal_scrollbar_should_change &&
956           GetLayoutBox()->StyleRef().OverflowX() != EOverflow::kOverlay) ||
957          (vertical_scrollbar_should_change &&
958           GetLayoutBox()->StyleRef().OverflowY() != EOverflow::kOverlay))) {
959       if ((vertical_scrollbar_should_change &&
960            GetLayoutBox()->IsHorizontalWritingMode()) ||
961           (horizontal_scrollbar_should_change &&
962            !GetLayoutBox()->IsHorizontalWritingMode())) {
963         GetLayoutBox()->SetPreferredLogicalWidthsDirty();
964       }
965       if (IsManagedByLayoutNG(*GetLayoutBox())) {
966         // If the box is managed by LayoutNG, don't go here. We don't want to
967         // re-enter the NG layout algorithm for this box from here. Just update
968         // the rectangles, in case scrollbars were added or removed. LayoutNG
969         // has its own scrollbar change detection mechanism.
970         UpdateScrollDimensions();
971       } else {
972         if (PreventRelayoutScope::RelayoutIsPrevented()) {
973           // We're not doing re-layout right now, but we still want to
974           // add the scrollbar to the logical width now, to facilitate parent
975           // layout.
976           GetLayoutBox()->UpdateLogicalWidth();
977           PreventRelayoutScope::SetBoxNeedsLayout(
978               *this, had_horizontal_scrollbar, had_vertical_scrollbar);
979         } else {
980           in_overflow_relayout_ = true;
981           SubtreeLayoutScope layout_scope(*GetLayoutBox());
982           layout_scope.SetNeedsLayout(
983               GetLayoutBox(), layout_invalidation_reason::kScrollbarChanged);
984           if (GetLayoutBox()->IsLayoutBlock()) {
985             LayoutBlock* block = ToLayoutBlock(GetLayoutBox());
986             block->ScrollbarsChanged(horizontal_scrollbar_should_change,
987                                      vertical_scrollbar_should_change);
988             block->UpdateBlockLayout(true);
989           } else {
990             GetLayoutBox()->UpdateLayout();
991           }
992           in_overflow_relayout_ = false;
993           scrollbar_manager_.DestroyDetachedScrollbars();
994         }
995         LayoutObject* parent = GetLayoutBox()->Parent();
996         if (parent && parent->IsFlexibleBox()) {
997           ToLayoutFlexibleBox(parent)->ClearCachedMainSizeForChild(
998               *GetLayoutBox());
999         }
1000       }
1001     }
1002   }
1003
1004   {
1005     // Hits in
1006     // compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html.
1007     DisableCompositingQueryAsserts disabler;
1008
1009     UpdateScrollbarEnabledState();
1010
1011     UpdateScrollbarProportions();
1012   }
1013
1014   if (!scrollbars_are_frozen && HasOverlayScrollbars()) {
1015     if (!ScrollSize(kHorizontalScrollbar))
1016       SetHasHorizontalScrollbar(false);
1017     if (!ScrollSize(kVerticalScrollbar))
1018       SetHasVerticalScrollbar(false);
1019   }
1020
1021   ClampScrollOffsetAfterOverflowChange();
1022
1023   if (!scrollbars_are_frozen) {
1024     UpdateScrollableAreaSet();
1025   }
1026
1027   DisableCompositingQueryAsserts disabler;
1028   PositionOverflowControls();
1029 }
1030
1031 void PaintLayerScrollableArea::ClampScrollOffsetAfterOverflowChange() {
1032   if (HasBeenDisposed())
1033     return;
1034
1035   // If a vertical scrollbar was removed, the min/max scroll offsets may have
1036   // changed, so the scroll offsets needs to be clamped.  If the scroll offset
1037   // did not change, but the scroll origin *did* change, we still need to notify
1038   // the scrollbars to update their dimensions.
1039
1040   if (DelayScrollOffsetClampScope::ClampingIsDelayed()) {
1041     DelayScrollOffsetClampScope::SetNeedsClamp(this);
1042     return;
1043   }
1044
1045   UpdateScrollDimensions();
1046   if (ScrollOriginChanged())
1047     SetScrollOffsetUnconditionally(ClampScrollOffset(GetScrollOffset()));
1048   else
1049     ScrollableArea::SetScrollOffset(GetScrollOffset(), kClampingScroll);
1050
1051   SetNeedsScrollOffsetClamp(false);
1052   ResetScrollOriginChanged();
1053   scrollbar_manager_.DestroyDetachedScrollbars();
1054 }
1055
1056 void PaintLayerScrollableArea::DidChangeGlobalRootScroller() {
1057   // Being the global root scroller will affect clipping size due to browser
1058   // controls behavior so we need to update compositing based on updated clip
1059   // geometry.
1060   if (GetLayoutBox()->GetNode()->IsElementNode()) {
1061     ToElement(GetLayoutBox()->GetNode())->SetNeedsCompositingUpdate();
1062     GetLayoutBox()->SetNeedsPaintPropertyUpdate();
1063   }
1064
1065   // On Android, where the VisualViewport supplies scrollbars, we need to
1066   // remove the PLSA's scrollbars if we become the global root scroller.
1067   // In general, this would be problematic as that can cause layout but this
1068   // should only ever apply with overlay scrollbars.
1069   if (GetLayoutBox()->GetFrame()->GetSettings() &&
1070       GetLayoutBox()->GetFrame()->GetSettings()->GetViewportEnabled()) {
1071     bool needs_horizontal_scrollbar;
1072     bool needs_vertical_scrollbar;
1073     ComputeScrollbarExistence(needs_horizontal_scrollbar,
1074                               needs_vertical_scrollbar);
1075     SetHasHorizontalScrollbar(needs_horizontal_scrollbar);
1076     SetHasVerticalScrollbar(needs_vertical_scrollbar);
1077   }
1078 }
1079
1080 bool PaintLayerScrollableArea::ShouldPerformScrollAnchoring() const {
1081   return scroll_anchor_.HasScroller() && GetLayoutBox() &&
1082          GetLayoutBox()->StyleRef().OverflowAnchor() !=
1083              EOverflowAnchor::kNone &&
1084          !GetLayoutBox()->GetDocument().FinishingOrIsPrinting();
1085 }
1086
1087 bool PaintLayerScrollableArea::RestoreScrollAnchor(
1088     const SerializedAnchor& serialized_anchor) {
1089   return ShouldPerformScrollAnchoring() &&
1090          scroll_anchor_.RestoreAnchor(serialized_anchor);
1091 }
1092
1093 FloatQuad PaintLayerScrollableArea::LocalToVisibleContentQuad(
1094     const FloatQuad& quad,
1095     const LayoutObject* local_object,
1096     MapCoordinatesFlags flags) const {
1097   LayoutBox* box = GetLayoutBox();
1098   if (!box)
1099     return quad;
1100   DCHECK(local_object);
1101   return local_object->LocalToAncestorQuad(quad, box, flags);
1102 }
1103
1104 scoped_refptr<base::SingleThreadTaskRunner>
1105 PaintLayerScrollableArea::GetTimerTaskRunner() const {
1106   return GetLayoutBox()->GetFrame()->GetTaskRunner(TaskType::kInternalDefault);
1107 }
1108
1109 ScrollBehavior PaintLayerScrollableArea::ScrollBehaviorStyle() const {
1110   return GetLayoutBox()->StyleRef().GetScrollBehavior();
1111 }
1112
1113 bool PaintLayerScrollableArea::HasHorizontalOverflow() const {
1114   // TODO(szager): Make the algorithm for adding/subtracting overflow:auto
1115   // scrollbars memoryless (crbug.com/625300).  This client_width hack will
1116   // prevent the spurious horizontal scrollbar, but it can cause a converse
1117   // problem: it can leave a sliver of horizontal overflow hidden behind the
1118   // vertical scrollbar without creating a horizontal scrollbar.  This
1119   // converse problem seems to happen much less frequently in practice, so we
1120   // bias the logic towards preventing unwanted horizontal scrollbars, which
1121   // are more common and annoying.
1122   LayoutUnit client_width =
1123       LayoutContentRect(kIncludeScrollbars).Width() -
1124       VerticalScrollbarWidth(kIgnorePlatformAndCSSOverlayScrollbarSize);
1125   if (NeedsRelayout() && !HadVerticalScrollbarBeforeRelayout())
1126     client_width += VerticalScrollbarWidth();
1127   LayoutUnit scroll_width(ScrollWidth());
1128   LayoutUnit box_x = GetLayoutBox()->Location().X();
1129   return SnapSizeToPixel(scroll_width, box_x) >
1130          SnapSizeToPixel(client_width, box_x);
1131 }
1132
1133 bool PaintLayerScrollableArea::HasVerticalOverflow() const {
1134   LayoutUnit client_height =
1135       LayoutContentRect(kIncludeScrollbars).Height() -
1136       HorizontalScrollbarHeight(kIgnorePlatformAndCSSOverlayScrollbarSize);
1137   LayoutUnit scroll_height(ScrollHeight());
1138   LayoutUnit box_y = GetLayoutBox()->Location().Y();
1139   return SnapSizeToPixel(scroll_height, box_y) >
1140          SnapSizeToPixel(client_height, box_y);
1141 }
1142
1143 // This function returns true if the given box requires overflow scrollbars (as
1144 // opposed to the 'viewport' scrollbars managed by the PaintLayerCompositor).
1145 // FIXME: we should use the same scrolling machinery for both the viewport and
1146 // overflow. Currently, we need to avoid producing scrollbars here if they'll be
1147 // handled externally in the RLC.
1148 static bool CanHaveOverflowScrollbars(const LayoutBox& box) {
1149   return box.GetDocument().ViewportDefiningElement() != box.GetNode();
1150 }
1151
1152 void PaintLayerScrollableArea::UpdateAfterStyleChange(
1153     const ComputedStyle* old_style) {
1154   // Don't do this on first style recalc, before layout has ever happened.
1155   if (!OverflowRect().Size().IsZero()) {
1156     UpdateScrollableAreaSet();
1157   }
1158
1159   // Whenever background changes on the scrollable element, the scroll bar
1160   // overlay style might need to be changed to have contrast against the
1161   // background.
1162   // Skip the need scrollbar check, because we dont know do we need a scrollbar
1163   // when this method get called.
1164   Color old_background;
1165   if (old_style) {
1166     old_background =
1167         old_style->VisitedDependentColor(GetCSSPropertyBackgroundColor());
1168   }
1169   Color new_background = GetLayoutBox()->StyleRef().VisitedDependentColor(
1170       GetCSSPropertyBackgroundColor());
1171
1172   if (new_background != old_background) {
1173     RecalculateScrollbarOverlayColorTheme(new_background);
1174   }
1175
1176   bool needs_horizontal_scrollbar;
1177   bool needs_vertical_scrollbar;
1178   // We add auto scrollbars only during layout to prevent spurious activations.
1179   ComputeScrollbarExistence(needs_horizontal_scrollbar,
1180                             needs_vertical_scrollbar, kForbidAddingAutoBars);
1181
1182   // Avoid some unnecessary computation if there were and will be no scrollbars.
1183   if (!HasScrollbar() && !needs_horizontal_scrollbar &&
1184       !needs_vertical_scrollbar)
1185     return;
1186
1187   bool horizontal_scrollbar_changed =
1188       SetHasHorizontalScrollbar(needs_horizontal_scrollbar);
1189   bool vertical_scrollbar_changed =
1190       SetHasVerticalScrollbar(needs_vertical_scrollbar);
1191
1192   if (GetLayoutBox()->IsLayoutBlock() &&
1193       (horizontal_scrollbar_changed || vertical_scrollbar_changed)) {
1194     ToLayoutBlock(GetLayoutBox())
1195         ->ScrollbarsChanged(horizontal_scrollbar_changed,
1196                             vertical_scrollbar_changed,
1197                             LayoutBlock::ScrollbarChangeContext::kStyleChange);
1198   }
1199
1200   // With overflow: scroll, scrollbars are always visible but may be disabled.
1201   // When switching to another value, we need to re-enable them (see bug 11985).
1202   if (HasHorizontalScrollbar() && old_style &&
1203       old_style->OverflowX() == EOverflow::kScroll &&
1204       GetLayoutBox()->StyleRef().OverflowX() != EOverflow::kScroll) {
1205     HorizontalScrollbar()->SetEnabled(true);
1206   }
1207
1208   if (HasVerticalScrollbar() && old_style &&
1209       old_style->OverflowY() == EOverflow::kScroll &&
1210       GetLayoutBox()->StyleRef().OverflowY() != EOverflow::kScroll) {
1211     VerticalScrollbar()->SetEnabled(true);
1212   }
1213
1214   // FIXME: Need to detect a swap from custom to native scrollbars (and vice
1215   // versa).
1216   if (HorizontalScrollbar())
1217     HorizontalScrollbar()->StyleChanged();
1218   if (VerticalScrollbar())
1219     VerticalScrollbar()->StyleChanged();
1220
1221   UpdateScrollCornerStyle();
1222   UpdateResizerAreaSet();
1223   UpdateResizerStyle(old_style);
1224 }
1225
1226 void PaintLayerScrollableArea::UpdateAfterOverflowRecalc() {
1227   UpdateScrollDimensions();
1228   UpdateScrollbarProportions();
1229
1230   bool needs_horizontal_scrollbar;
1231   bool needs_vertical_scrollbar;
1232   ComputeScrollbarExistence(needs_horizontal_scrollbar,
1233                             needs_vertical_scrollbar);
1234
1235   bool horizontal_scrollbar_should_change =
1236       needs_horizontal_scrollbar != HasHorizontalScrollbar();
1237   bool vertical_scrollbar_should_change =
1238       needs_vertical_scrollbar != HasVerticalScrollbar();
1239
1240   if ((GetLayoutBox()->HasAutoHorizontalScrollbar() &&
1241        horizontal_scrollbar_should_change) ||
1242       (GetLayoutBox()->HasAutoVerticalScrollbar() &&
1243        vertical_scrollbar_should_change)) {
1244     GetLayoutBox()->SetNeedsLayoutAndFullPaintInvalidation(
1245         layout_invalidation_reason::kUnknown);
1246   }
1247
1248   ClampScrollOffsetAfterOverflowChange();
1249 }
1250
1251 IntRect PaintLayerScrollableArea::RectForHorizontalScrollbar(
1252     const IntRect& border_box_rect) const {
1253   if (!HasHorizontalScrollbar())
1254     return IntRect();
1255
1256   const IntRect& scroll_corner = ScrollCornerRect();
1257
1258   return IntRect(
1259       HorizontalScrollbarStart(border_box_rect.X()),
1260       border_box_rect.MaxY() - GetLayoutBox()->BorderBottom().ToInt() -
1261           HorizontalScrollbar()->ScrollbarThickness(),
1262       border_box_rect.Width() -
1263           (GetLayoutBox()->BorderLeft() + GetLayoutBox()->BorderRight())
1264               .ToInt() -
1265           scroll_corner.Width(),
1266       HorizontalScrollbar()->ScrollbarThickness());
1267 }
1268
1269 IntRect PaintLayerScrollableArea::RectForVerticalScrollbar(
1270     const IntRect& border_box_rect) const {
1271   if (!HasVerticalScrollbar())
1272     return IntRect();
1273
1274   const IntRect& scroll_corner = ScrollCornerRect();
1275
1276   return IntRect(
1277       VerticalScrollbarStart(border_box_rect.X(), border_box_rect.MaxX()),
1278       border_box_rect.Y() + GetLayoutBox()->BorderTop().ToInt(),
1279       VerticalScrollbar()->ScrollbarThickness(),
1280       border_box_rect.Height() -
1281           (GetLayoutBox()->BorderTop() + GetLayoutBox()->BorderBottom())
1282               .ToInt() -
1283           scroll_corner.Height());
1284 }
1285
1286 int PaintLayerScrollableArea::VerticalScrollbarStart(int min_x,
1287                                                      int max_x) const {
1288   if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1289     return min_x + GetLayoutBox()->BorderLeft().ToInt();
1290   return max_x - GetLayoutBox()->BorderRight().ToInt() -
1291          VerticalScrollbar()->ScrollbarThickness();
1292 }
1293
1294 int PaintLayerScrollableArea::HorizontalScrollbarStart(int min_x) const {
1295   int x = min_x + GetLayoutBox()->BorderLeft().ToInt();
1296   if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1297     x += HasVerticalScrollbar()
1298              ? VerticalScrollbar()->ScrollbarThickness()
1299              : ResizerCornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
1300                                      Layer()->SubpixelAccumulation()),
1301                                  kResizerForPointer)
1302                    .Width();
1303   return x;
1304 }
1305
1306 IntSize PaintLayerScrollableArea::ScrollbarOffset(
1307     const Scrollbar& scrollbar) const {
1308   // TODO(szager): Factor out vertical offset calculation into other methods,
1309   // for symmetry with *ScrollbarStart methods for horizontal offset.
1310   if (&scrollbar == VerticalScrollbar()) {
1311     return IntSize(
1312         VerticalScrollbarStart(0, Layer()->PixelSnappedSize().Width()),
1313         GetLayoutBox()->BorderTop().ToInt());
1314   }
1315
1316   if (&scrollbar == HorizontalScrollbar()) {
1317     return IntSize(HorizontalScrollbarStart(0),
1318                    GetLayoutBox()->BorderTop().ToInt() +
1319                        VisibleContentRect(kIncludeScrollbars).Height() -
1320                        HorizontalScrollbar()->ScrollbarThickness());
1321   }
1322
1323   NOTREACHED();
1324   return IntSize();
1325 }
1326
1327 static inline const LayoutObject& ScrollbarStyleSource(
1328     const LayoutBox& layout_box) {
1329   if (layout_box.IsLayoutView()) {
1330     Document& doc = layout_box.GetDocument();
1331     if (Settings* settings = doc.GetSettings()) {
1332       if (!settings->GetAllowCustomScrollbarInMainFrame() &&
1333           layout_box.GetFrame() && layout_box.GetFrame()->IsMainFrame())
1334         return layout_box;
1335     }
1336
1337     // Try the <body> element first as a scrollbar source, but only if the body
1338     // can scroll.
1339     Element* body = doc.body();
1340     if (body && body->GetLayoutObject() && body->GetLayoutObject()->IsBox() &&
1341         body->GetLayoutObject()->StyleRef().HasPseudoStyle(kPseudoIdScrollbar))
1342       return *body->GetLayoutObject();
1343
1344     // If the <body> didn't have a custom style, then the root element might.
1345     Element* doc_element = doc.documentElement();
1346     if (doc_element && doc_element->GetLayoutObject() &&
1347         doc_element->GetLayoutObject()->StyleRef().HasPseudoStyle(
1348             kPseudoIdScrollbar))
1349       return *doc_element->GetLayoutObject();
1350   }
1351
1352   return layout_box;
1353 }
1354
1355 int PaintLayerScrollableArea::HypotheticalScrollbarThickness(
1356     ScrollbarOrientation orientation) const {
1357   Scrollbar* scrollbar = orientation == kHorizontalScrollbar
1358                              ? HorizontalScrollbar()
1359                              : VerticalScrollbar();
1360   if (scrollbar)
1361     return scrollbar->ScrollbarThickness();
1362
1363   const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
1364   bool has_custom_scrollbar_style =
1365       style_source.StyleRef().HasPseudoStyle(kPseudoIdScrollbar);
1366   if (has_custom_scrollbar_style) {
1367     return LayoutScrollbar::HypotheticalScrollbarThickness(
1368         orientation, *GetLayoutBox(), style_source);
1369   }
1370
1371   ScrollbarControlSize scrollbar_size = kRegularScrollbar;
1372   if (style_source.StyleRef().HasAppearance()) {
1373     scrollbar_size = LayoutTheme::GetTheme().ScrollbarControlSizeForPart(
1374         style_source.StyleRef().Appearance());
1375   }
1376   ScrollbarTheme& theme = GetPageScrollbarTheme();
1377   if (theme.UsesOverlayScrollbars())
1378     return 0;
1379   int thickness = theme.ScrollbarThickness(scrollbar_size);
1380   return GetLayoutBox()
1381       ->GetDocument()
1382       .GetPage()
1383       ->GetChromeClient()
1384       .WindowToViewportScalar(thickness);
1385 }
1386
1387 bool PaintLayerScrollableArea::NeedsScrollbarReconstruction() const {
1388   if (!HasScrollbar())
1389     return false;
1390
1391   const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
1392   bool needs_custom =
1393       style_source.IsBox() &&
1394       style_source.StyleRef().HasPseudoStyle(kPseudoIdScrollbar);
1395
1396   Scrollbar* scrollbars[] = {HorizontalScrollbar(), VerticalScrollbar()};
1397
1398   for (Scrollbar* scrollbar : scrollbars) {
1399     if (!scrollbar)
1400       continue;
1401
1402     // We have a native scrollbar that should be custom, or vice versa.
1403     if (scrollbar->IsCustomScrollbar() != needs_custom)
1404       return true;
1405
1406     if (needs_custom) {
1407       DCHECK(scrollbar->IsCustomScrollbar());
1408       // We have a custom scrollbar with a stale m_owner.
1409       if (ToLayoutScrollbar(scrollbar)->StyleSource()->GetLayoutObject() !=
1410           style_source) {
1411         return true;
1412       }
1413
1414       // Should use custom scrollbar and nothing should change.
1415       continue;
1416     }
1417
1418     // Check if native scrollbar should change.
1419     Page* page = GetLayoutBox()->GetFrame()->LocalFrameRoot().GetPage();
1420     DCHECK(page);
1421     ScrollbarTheme* current_theme = &page->GetScrollbarTheme();
1422
1423     if (current_theme != &scrollbar->GetTheme())
1424       return true;
1425   }
1426   return false;
1427 }
1428
1429 void PaintLayerScrollableArea::ComputeScrollbarExistence(
1430     bool& needs_horizontal_scrollbar,
1431     bool& needs_vertical_scrollbar,
1432     ComputeScrollbarExistenceOption option) const {
1433   // Scrollbars may be hidden or provided by visual viewport or frame instead.
1434   DCHECK(GetLayoutBox()->GetFrame()->GetSettings());
1435   if (VisualViewportSuppliesScrollbars() ||
1436       !CanHaveOverflowScrollbars(*GetLayoutBox()) ||
1437       GetLayoutBox()->GetFrame()->GetSettings()->GetHideScrollbars()) {
1438     needs_horizontal_scrollbar = false;
1439     needs_vertical_scrollbar = false;
1440     return;
1441   }
1442
1443   needs_horizontal_scrollbar = GetLayoutBox()->ScrollsOverflowX();
1444   needs_vertical_scrollbar = GetLayoutBox()->ScrollsOverflowY();
1445
1446   // Don't add auto scrollbars if the box contents aren't visible.
1447   if (GetLayoutBox()->HasAutoHorizontalScrollbar()) {
1448     if (option == kForbidAddingAutoBars)
1449       needs_horizontal_scrollbar &= HasHorizontalScrollbar();
1450     needs_horizontal_scrollbar &=
1451         GetLayoutBox()->IsRooted() && HasHorizontalOverflow() &&
1452         VisibleContentRect(kIncludeScrollbars).Height();
1453   }
1454
1455   if (GetLayoutBox()->HasAutoVerticalScrollbar()) {
1456     if (option == kForbidAddingAutoBars)
1457       needs_vertical_scrollbar &= HasVerticalScrollbar();
1458     needs_vertical_scrollbar &= GetLayoutBox()->IsRooted() &&
1459                                 HasVerticalOverflow() &&
1460                                 VisibleContentRect(kIncludeScrollbars).Width();
1461   }
1462
1463   if (GetLayoutBox()->IsLayoutView()) {
1464     ScrollbarMode h_mode;
1465     ScrollbarMode v_mode;
1466     ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
1467
1468     // Look for the scrollbarModes and reset the needs Horizontal & vertical
1469     // Scrollbar values based on scrollbarModes, as during force style change
1470     // StyleResolver::styleForDocument returns documentStyle with no overflow
1471     // values, due to which we are destroying the scrollbars that were already
1472     // present.
1473     if (h_mode == kScrollbarAlwaysOn)
1474       needs_horizontal_scrollbar = true;
1475     else if (h_mode == kScrollbarAlwaysOff)
1476       needs_horizontal_scrollbar = false;
1477     if (v_mode == kScrollbarAlwaysOn)
1478       needs_vertical_scrollbar = true;
1479     else if (v_mode == kScrollbarAlwaysOff)
1480       needs_vertical_scrollbar = false;
1481   }
1482 }
1483
1484 bool PaintLayerScrollableArea::TryRemovingAutoScrollbars(
1485     const bool& needs_horizontal_scrollbar,
1486     const bool& needs_vertical_scrollbar) {
1487   // If scrollbars are removed but the content size depends on the scrollbars,
1488   // additional layouts will be required to size the content. Therefore, only
1489   // remove auto scrollbars for the initial layout pass.
1490   DCHECK(!in_overflow_relayout_);
1491
1492   if (!needs_horizontal_scrollbar && !needs_vertical_scrollbar)
1493     return false;
1494
1495   if (GetLayoutBox()->IsLayoutView()) {
1496     ScrollbarMode h_mode;
1497     ScrollbarMode v_mode;
1498     ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
1499     if (h_mode != kScrollbarAuto || v_mode != kScrollbarAuto)
1500       return false;
1501
1502     IntSize visible_size_with_scrollbars =
1503         VisibleContentRect(kIncludeScrollbars).Size();
1504     if (ScrollWidth() <= visible_size_with_scrollbars.Width() &&
1505         ScrollHeight() <= visible_size_with_scrollbars.Height()) {
1506       return true;
1507     }
1508   } else {
1509     if (!GetLayoutBox()->HasAutoVerticalScrollbar() ||
1510         !GetLayoutBox()->HasAutoHorizontalScrollbar())
1511       return false;
1512
1513     LayoutSize client_size_with_scrollbars =
1514         LayoutContentRect(kIncludeScrollbars).Size();
1515     if (ScrollWidth() <= client_size_with_scrollbars.Width() &&
1516         ScrollHeight() <= client_size_with_scrollbars.Height()) {
1517       return true;
1518     }
1519   }
1520
1521   return false;
1522 }
1523
1524 bool PaintLayerScrollableArea::SetHasHorizontalScrollbar(bool has_scrollbar) {
1525   if (FreezeScrollbarsScope::ScrollbarsAreFrozen())
1526     return false;
1527
1528   if (has_scrollbar == HasHorizontalScrollbar())
1529     return false;
1530
1531   SetScrollbarNeedsPaintInvalidation(kHorizontalScrollbar);
1532
1533   scrollbar_manager_.SetHasHorizontalScrollbar(has_scrollbar);
1534
1535   UpdateScrollOrigin();
1536
1537   // Destroying or creating one bar can cause our scrollbar corner to come and
1538   // go. We need to update the opposite scrollbar's style.
1539   if (HasHorizontalScrollbar())
1540     HorizontalScrollbar()->StyleChanged();
1541   if (HasVerticalScrollbar())
1542     VerticalScrollbar()->StyleChanged();
1543
1544   SetScrollCornerNeedsPaintInvalidation();
1545
1546   // Force an update since we know the scrollbars have changed things.
1547   if (GetLayoutBox()->GetDocument().HasAnnotatedRegions())
1548     GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);
1549   return true;
1550 }
1551
1552 bool PaintLayerScrollableArea::SetHasVerticalScrollbar(bool has_scrollbar) {
1553   if (FreezeScrollbarsScope::ScrollbarsAreFrozen())
1554     return false;
1555
1556   if (GetLayoutBox()->GetDocument().IsVerticalScrollEnforced()) {
1557     // When the policy is enforced the contents of document cannot be scrolled.
1558     // This would make rendering a scrollbar look strange
1559     // (https://crbug.com/898151).
1560     return false;
1561   }
1562
1563   if (has_scrollbar == HasVerticalScrollbar())
1564     return false;
1565
1566   SetScrollbarNeedsPaintInvalidation(kVerticalScrollbar);
1567
1568   scrollbar_manager_.SetHasVerticalScrollbar(has_scrollbar);
1569
1570   UpdateScrollOrigin();
1571
1572   // Destroying or creating one bar can cause our scrollbar corner to come and
1573   // go. We need to update the opposite scrollbar's style.
1574   if (HasHorizontalScrollbar())
1575     HorizontalScrollbar()->StyleChanged();
1576   if (HasVerticalScrollbar())
1577     VerticalScrollbar()->StyleChanged();
1578
1579   SetScrollCornerNeedsPaintInvalidation();
1580
1581   // Force an update since we know the scrollbars have changed things.
1582   if (GetLayoutBox()->GetDocument().HasAnnotatedRegions())
1583     GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);
1584   return true;
1585 }
1586
1587 int PaintLayerScrollableArea::VerticalScrollbarWidth(
1588     OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
1589   if (!HasVerticalScrollbar())
1590     return 0;
1591   if (overlay_scrollbar_clip_behavior ==
1592           kIgnorePlatformAndCSSOverlayScrollbarSize &&
1593       GetLayoutBox()->StyleRef().OverflowY() == EOverflow::kOverlay) {
1594     return 0;
1595   }
1596   if ((overlay_scrollbar_clip_behavior == kIgnorePlatformOverlayScrollbarSize ||
1597        overlay_scrollbar_clip_behavior ==
1598            kIgnorePlatformAndCSSOverlayScrollbarSize ||
1599        !VerticalScrollbar()->ShouldParticipateInHitTesting()) &&
1600       VerticalScrollbar()->IsOverlayScrollbar()) {
1601     return 0;
1602   }
1603   return VerticalScrollbar()->ScrollbarThickness();
1604 }
1605
1606 int PaintLayerScrollableArea::HorizontalScrollbarHeight(
1607     OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
1608   if (!HasHorizontalScrollbar())
1609     return 0;
1610   if (overlay_scrollbar_clip_behavior ==
1611           kIgnorePlatformAndCSSOverlayScrollbarSize &&
1612       GetLayoutBox()->StyleRef().OverflowX() == EOverflow::kOverlay) {
1613     return 0;
1614   }
1615   if ((overlay_scrollbar_clip_behavior == kIgnorePlatformOverlayScrollbarSize ||
1616        overlay_scrollbar_clip_behavior ==
1617            kIgnorePlatformAndCSSOverlayScrollbarSize ||
1618        !HorizontalScrollbar()->ShouldParticipateInHitTesting()) &&
1619       HorizontalScrollbar()->IsOverlayScrollbar()) {
1620     return 0;
1621   }
1622   return HorizontalScrollbar()->ScrollbarThickness();
1623 }
1624
1625 void PaintLayerScrollableArea::SnapAfterScrollbarScrolling(
1626     ScrollbarOrientation orientation) {
1627   SnapCoordinator* snap_coordinator =
1628       GetLayoutBox()->GetDocument().GetSnapCoordinator();
1629   if (!snap_coordinator)
1630     return;
1631
1632   snap_coordinator->SnapAtCurrentPosition(*GetLayoutBox(),
1633                                           orientation == kHorizontalScrollbar,
1634                                           orientation == kVerticalScrollbar);
1635 }
1636
1637 void PaintLayerScrollableArea::PositionOverflowControls() {
1638   if (!HasScrollbar() && !GetLayoutBox()->CanResize())
1639     return;
1640
1641   const IntRect border_box =
1642       GetLayoutBox()->PixelSnappedBorderBoxRect(layer_->SubpixelAccumulation());
1643
1644   if (Scrollbar* vertical_scrollbar = VerticalScrollbar())
1645     vertical_scrollbar->SetFrameRect(RectForVerticalScrollbar(border_box));
1646
1647   if (Scrollbar* horizontal_scrollbar = HorizontalScrollbar())
1648     horizontal_scrollbar->SetFrameRect(RectForHorizontalScrollbar(border_box));
1649
1650   const IntRect& scroll_corner = ScrollCornerRect();
1651   if (scroll_corner_)
1652     scroll_corner_->SetFrameRect(LayoutRect(scroll_corner));
1653
1654   if (resizer_)
1655     resizer_->SetFrameRect(
1656         LayoutRect(ResizerCornerRect(border_box, kResizerForPointer)));
1657
1658   // FIXME, this should eventually be removed, once we are certain that
1659   // composited controls get correctly positioned on a compositor update. For
1660   // now, conservatively leaving this unchanged.
1661   if (Layer()->HasCompositedLayerMapping())
1662     Layer()->GetCompositedLayerMapping()->PositionOverflowControlsLayers();
1663 }
1664
1665 void PaintLayerScrollableArea::UpdateScrollCornerStyle() {
1666   if (!scroll_corner_ && !HasScrollbar())
1667     return;
1668   if (!scroll_corner_ && HasOverlayScrollbars())
1669     return;
1670
1671   const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
1672   scoped_refptr<ComputedStyle> corner =
1673       GetLayoutBox()->HasOverflowClip()
1674           ? style_source.GetUncachedPseudoStyle(
1675                 PseudoStyleRequest(kPseudoIdScrollbarCorner),
1676                 style_source.Style())
1677           : scoped_refptr<ComputedStyle>(nullptr);
1678   if (corner) {
1679     if (!scroll_corner_) {
1680       scroll_corner_ = LayoutScrollbarPart::CreateAnonymous(
1681           &GetLayoutBox()->GetDocument(), this);
1682       scroll_corner_->SetDangerousOneWayParent(GetLayoutBox());
1683     }
1684     scroll_corner_->SetStyleWithWritingModeOfParent(std::move(corner));
1685   } else if (scroll_corner_) {
1686     scroll_corner_->Destroy();
1687     scroll_corner_ = nullptr;
1688   }
1689 }
1690
1691 bool PaintLayerScrollableArea::HitTestOverflowControls(
1692     HitTestResult& result,
1693     const IntPoint& local_point) {
1694   if (!HasScrollbar() && !GetLayoutBox()->CanResize())
1695     return false;
1696
1697   IntRect resize_control_rect;
1698   if (GetLayoutBox()->StyleRef().Resize() != EResize::kNone) {
1699     resize_control_rect =
1700         ResizerCornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
1701                               Layer()->SubpixelAccumulation()),
1702                           kResizerForPointer);
1703     if (resize_control_rect.Contains(local_point))
1704       return true;
1705   }
1706   int resize_control_size = max(resize_control_rect.Height(), 0);
1707
1708   IntRect visible_rect = VisibleContentRect(kIncludeScrollbars);
1709
1710   if (HasVerticalScrollbar() &&
1711       VerticalScrollbar()->ShouldParticipateInHitTesting()) {
1712     LayoutRect v_bar_rect(
1713         VerticalScrollbarStart(0, Layer()->PixelSnappedSize().Width()),
1714         GetLayoutBox()->BorderTop().ToInt(),
1715         VerticalScrollbar()->ScrollbarThickness(),
1716         visible_rect.Height() -
1717             (HasHorizontalScrollbar()
1718                  ? HorizontalScrollbar()->ScrollbarThickness()
1719                  : resize_control_size));
1720     if (v_bar_rect.Contains(local_point)) {
1721       result.SetScrollbar(VerticalScrollbar());
1722       return true;
1723     }
1724   }
1725
1726   resize_control_size = max(resize_control_rect.Width(), 0);
1727   if (HasHorizontalScrollbar() &&
1728       HorizontalScrollbar()->ShouldParticipateInHitTesting()) {
1729     // TODO(crbug.com/638981): Are the conversions to int intentional?
1730     int h_scrollbar_thickness = HorizontalScrollbar()->ScrollbarThickness();
1731     LayoutRect h_bar_rect(
1732         HorizontalScrollbarStart(0),
1733         GetLayoutBox()->BorderTop().ToInt() + visible_rect.Height() -
1734             h_scrollbar_thickness,
1735         visible_rect.Width() - (HasVerticalScrollbar()
1736                                     ? VerticalScrollbar()->ScrollbarThickness()
1737                                     : resize_control_size),
1738         h_scrollbar_thickness);
1739     if (h_bar_rect.Contains(local_point)) {
1740       result.SetScrollbar(HorizontalScrollbar());
1741       return true;
1742     }
1743   }
1744
1745   // FIXME: We should hit test the m_scrollCorner and pass it back through the
1746   // result.
1747
1748   return false;
1749 }
1750
1751 IntRect PaintLayerScrollableArea::ResizerCornerRect(
1752     const IntRect& bounds,
1753     ResizerHitTestType resizer_hit_test_type) const {
1754   if (GetLayoutBox()->StyleRef().Resize() == EResize::kNone)
1755     return IntRect();
1756   IntRect corner = CornerRect(bounds);
1757
1758   if (resizer_hit_test_type == kResizerForTouch) {
1759     // We make the resizer virtually larger for touch hit testing. With the
1760     // expanding ratio k = ResizerControlExpandRatioForTouch, we first move
1761     // the resizer rect (of width w & height h), by (-w * (k-1), -h * (k-1)),
1762     // then expand the rect by new_w/h = w/h * k.
1763     int expand_ratio = kResizerControlExpandRatioForTouch - 1;
1764     corner.Move(-corner.Width() * expand_ratio,
1765                 -corner.Height() * expand_ratio);
1766     corner.Expand(corner.Width() * expand_ratio,
1767                   corner.Height() * expand_ratio);
1768   }
1769
1770   return corner;
1771 }
1772
1773 IntRect PaintLayerScrollableArea::ScrollCornerAndResizerRect() const {
1774   IntRect scroll_corner_and_resizer = ScrollCornerRect();
1775   if (scroll_corner_and_resizer.IsEmpty()) {
1776     scroll_corner_and_resizer =
1777         ResizerCornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
1778                               Layer()->SubpixelAccumulation()),
1779                           kResizerForPointer);
1780   }
1781   return scroll_corner_and_resizer;
1782 }
1783
1784 bool PaintLayerScrollableArea::IsPointInResizeControl(
1785     const IntPoint& absolute_point,
1786     ResizerHitTestType resizer_hit_test_type) const {
1787   if (!GetLayoutBox()->CanResize())
1788     return false;
1789
1790   IntPoint local_point = RoundedIntPoint(GetLayoutBox()->AbsoluteToLocal(
1791       FloatPoint(absolute_point), kUseTransforms));
1792   IntRect local_bounds(IntPoint(), Layer()->PixelSnappedSize());
1793   return ResizerCornerRect(local_bounds, resizer_hit_test_type)
1794       .Contains(local_point);
1795 }
1796
1797 bool PaintLayerScrollableArea::HitTestResizerInFragments(
1798     const PaintLayerFragments& layer_fragments,
1799     const HitTestLocation& hit_test_location) const {
1800   if (!GetLayoutBox()->CanResize())
1801     return false;
1802
1803   if (layer_fragments.IsEmpty())
1804     return false;
1805
1806   for (int i = layer_fragments.size() - 1; i >= 0; --i) {
1807     const PaintLayerFragment& fragment = layer_fragments.at(i);
1808     if (fragment.background_rect.Intersects(hit_test_location) &&
1809         ResizerCornerRect(PixelSnappedIntRect(fragment.layer_bounds),
1810                           kResizerForPointer)
1811             .Contains(hit_test_location.RoundedPoint()))
1812       return true;
1813   }
1814
1815   return false;
1816 }
1817
1818 void PaintLayerScrollableArea::UpdateResizerAreaSet() {
1819   LocalFrame* frame = GetLayoutBox()->GetFrame();
1820   if (!frame)
1821     return;
1822   LocalFrameView* frame_view = frame->View();
1823   if (!frame_view)
1824     return;
1825   if (GetLayoutBox()->CanResize())
1826     frame_view->AddResizerArea(*GetLayoutBox());
1827   else
1828     frame_view->RemoveResizerArea(*GetLayoutBox());
1829 }
1830
1831 void PaintLayerScrollableArea::UpdateResizerStyle(
1832     const ComputedStyle* old_style) {
1833   if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && old_style &&
1834       old_style->Resize() != GetLayoutBox()->StyleRef().Resize()) {
1835     // Invalidate the composited scroll corner layer on resize style change.
1836     if (auto* graphics_layer = LayerForScrollCorner())
1837       graphics_layer->SetNeedsDisplay();
1838   }
1839
1840   if (!resizer_ && !GetLayoutBox()->CanResize())
1841     return;
1842
1843   const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
1844   scoped_refptr<ComputedStyle> resizer =
1845       GetLayoutBox()->HasOverflowClip()
1846           ? style_source.GetUncachedPseudoStyle(
1847                 PseudoStyleRequest(kPseudoIdResizer), style_source.Style())
1848           : scoped_refptr<ComputedStyle>(nullptr);
1849   if (resizer) {
1850     if (!resizer_) {
1851       resizer_ = LayoutScrollbarPart::CreateAnonymous(
1852           &GetLayoutBox()->GetDocument(), this);
1853       resizer_->SetDangerousOneWayParent(GetLayoutBox());
1854     }
1855     resizer_->SetStyleWithWritingModeOfParent(std::move(resizer));
1856   } else if (resizer_) {
1857     resizer_->Destroy();
1858     resizer_ = nullptr;
1859   }
1860 }
1861
1862 void PaintLayerScrollableArea::InvalidateAllStickyConstraints() {
1863   if (PaintLayerScrollableAreaRareData* d = RareData()) {
1864     for (PaintLayer* sticky_layer : d->sticky_constraints_map_.Keys()) {
1865       if (sticky_layer->GetLayoutObject().StyleRef().GetPosition() ==
1866           EPosition::kSticky) {
1867         sticky_layer->SetNeedsCompositingInputsUpdate();
1868         sticky_layer->GetLayoutObject().SetNeedsPaintPropertyUpdate();
1869       }
1870     }
1871     d->sticky_constraints_map_.clear();
1872   }
1873 }
1874
1875 void PaintLayerScrollableArea::InvalidateStickyConstraintsFor(
1876     PaintLayer* layer,
1877     bool needs_compositing_update) {
1878   if (PaintLayerScrollableAreaRareData* d = RareData()) {
1879     d->sticky_constraints_map_.erase(layer);
1880     if (needs_compositing_update &&
1881         layer->GetLayoutObject().StyleRef().HasStickyConstrainedPosition()) {
1882       layer->SetNeedsCompositingInputsUpdate();
1883       layer->GetLayoutObject().SetNeedsPaintPropertyUpdate();
1884     }
1885   }
1886 }
1887
1888 bool PaintLayerScrollableArea::HasStickyDescendants() const {
1889   if (const PaintLayerScrollableAreaRareData* d = RareData())
1890     return !d->sticky_constraints_map_.IsEmpty();
1891   return false;
1892 }
1893
1894 bool PaintLayerScrollableArea::HasNonCompositedStickyDescendants() const {
1895   if (const PaintLayerScrollableAreaRareData* d = RareData()) {
1896     for (const PaintLayer* sticky_layer : d->sticky_constraints_map_.Keys()) {
1897       if (sticky_layer->GetLayoutObject().IsSlowRepaintConstrainedObject())
1898         return true;
1899     }
1900   }
1901   return false;
1902 }
1903
1904 void PaintLayerScrollableArea::InvalidatePaintForStickyDescendants() {
1905   if (PaintLayerScrollableAreaRareData* d = RareData()) {
1906     for (PaintLayer* sticky_layer : d->sticky_constraints_map_.Keys())
1907       sticky_layer->GetLayoutObject().SetNeedsPaintPropertyUpdate();
1908   }
1909 }
1910
1911 IntSize PaintLayerScrollableArea::OffsetFromResizeCorner(
1912     const IntPoint& absolute_point) const {
1913   // Currently the resize corner is either the bottom right corner or the bottom
1914   // left corner.
1915   // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be
1916   // the case?
1917   IntSize element_size = Layer()->PixelSnappedSize();
1918   if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1919     element_size.SetWidth(0);
1920   IntPoint resizer_point = IntPoint(element_size);
1921   IntPoint local_point = RoundedIntPoint(GetLayoutBox()->AbsoluteToLocal(
1922       FloatPoint(absolute_point), kUseTransforms));
1923   return local_point - resizer_point;
1924 }
1925
1926 LayoutSize PaintLayerScrollableArea::MinimumSizeForResizing(float zoom_factor) {
1927   LayoutUnit min_width =
1928       MinimumValueForLength(GetLayoutBox()->StyleRef().MinWidth(),
1929                             GetLayoutBox()->ContainingBlock()->Size().Width());
1930   LayoutUnit min_height =
1931       MinimumValueForLength(GetLayoutBox()->StyleRef().MinHeight(),
1932                             GetLayoutBox()->ContainingBlock()->Size().Height());
1933   min_width = std::max(LayoutUnit(min_width / zoom_factor),
1934                        LayoutUnit(kDefaultMinimumWidthForResizing));
1935   min_height = std::max(LayoutUnit(min_height / zoom_factor),
1936                         LayoutUnit(kDefaultMinimumHeightForResizing));
1937   return LayoutSize(min_width, min_height);
1938 }
1939
1940 void PaintLayerScrollableArea::Resize(const IntPoint& pos,
1941                                       const LayoutSize& old_offset) {
1942   // FIXME: This should be possible on generated content but is not right now.
1943   if (!InResizeMode() || !GetLayoutBox()->CanResize() ||
1944       !GetLayoutBox()->GetNode())
1945     return;
1946
1947   DCHECK(GetLayoutBox()->GetNode()->IsElementNode());
1948   Element* element = ToElement(GetLayoutBox()->GetNode());
1949
1950   Document& document = element->GetDocument();
1951
1952   float zoom_factor = GetLayoutBox()->StyleRef().EffectiveZoom();
1953
1954   IntSize new_offset =
1955       OffsetFromResizeCorner(document.View()->ConvertFromRootFrame(pos));
1956   new_offset.SetWidth(new_offset.Width() / zoom_factor);
1957   new_offset.SetHeight(new_offset.Height() / zoom_factor);
1958
1959   LayoutSize current_size = GetLayoutBox()->Size();
1960   current_size.Scale(1 / zoom_factor);
1961
1962   LayoutSize adjusted_old_offset = LayoutSize(
1963       old_offset.Width() / zoom_factor, old_offset.Height() / zoom_factor);
1964   if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
1965     new_offset.SetWidth(-new_offset.Width());
1966     adjusted_old_offset.SetWidth(-adjusted_old_offset.Width());
1967   }
1968
1969   LayoutSize difference((current_size + new_offset - adjusted_old_offset)
1970                             .ExpandedTo(MinimumSizeForResizing(zoom_factor)) -
1971                         current_size);
1972
1973   bool is_box_sizing_border =
1974       GetLayoutBox()->StyleRef().BoxSizing() == EBoxSizing::kBorderBox;
1975
1976   EResize resize =
1977       ResolvedResize(GetLayoutBox()->StyleRef(),
1978                      GetLayoutBox()->ContainingBlock()->StyleRef());
1979   if (resize != EResize::kVertical && difference.Width()) {
1980     if (element->IsFormControlElement()) {
1981       // Make implicit margins from the theme explicit (see
1982       // <http://bugs.webkit.org/show_bug.cgi?id=9547>).
1983       element->SetInlineStyleProperty(
1984           CSSPropertyMarginLeft, GetLayoutBox()->MarginLeft() / zoom_factor,
1985           CSSPrimitiveValue::UnitType::kPixels);
1986       element->SetInlineStyleProperty(
1987           CSSPropertyMarginRight, GetLayoutBox()->MarginRight() / zoom_factor,
1988           CSSPrimitiveValue::UnitType::kPixels);
1989     }
1990     LayoutUnit base_width =
1991         GetLayoutBox()->Size().Width() -
1992         (is_box_sizing_border ? LayoutUnit()
1993                               : GetLayoutBox()->BorderAndPaddingWidth());
1994     base_width = LayoutUnit(base_width / zoom_factor);
1995     element->SetInlineStyleProperty(CSSPropertyWidth,
1996                                     RoundToInt(base_width + difference.Width()),
1997                                     CSSPrimitiveValue::UnitType::kPixels);
1998   }
1999
2000   if (resize != EResize::kHorizontal && difference.Height()) {
2001     if (element->IsFormControlElement()) {
2002       // Make implicit margins from the theme explicit (see
2003       // <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2004       element->SetInlineStyleProperty(CSSPropertyMarginTop,
2005                                       GetLayoutBox()->MarginTop() / zoom_factor,
2006                                       CSSPrimitiveValue::UnitType::kPixels);
2007       element->SetInlineStyleProperty(
2008           CSSPropertyMarginBottom, GetLayoutBox()->MarginBottom() / zoom_factor,
2009           CSSPrimitiveValue::UnitType::kPixels);
2010     }
2011     LayoutUnit base_height =
2012         GetLayoutBox()->Size().Height() -
2013         (is_box_sizing_border ? LayoutUnit()
2014                               : GetLayoutBox()->BorderAndPaddingHeight());
2015     base_height = LayoutUnit(base_height / zoom_factor);
2016     element->SetInlineStyleProperty(
2017         CSSPropertyHeight, RoundToInt(base_height + difference.Height()),
2018         CSSPrimitiveValue::UnitType::kPixels);
2019   }
2020
2021   document.UpdateStyleAndLayout();
2022
2023   // FIXME (Radar 4118564): We should also autoscroll the window as necessary to
2024   // keep the point under the cursor in view.
2025 }
2026
2027 LayoutRect PaintLayerScrollableArea::ScrollIntoView(
2028     const LayoutRect& absolute_rect,
2029     const WebScrollIntoViewParams& params) {
2030   LayoutRect local_expose_rect =
2031       AbsoluteToLocal(*GetLayoutBox(), absolute_rect);
2032   LayoutSize border_origin_to_scroll_origin =
2033       LayoutSize(-GetLayoutBox()->BorderLeft(), -GetLayoutBox()->BorderTop()) +
2034       LayoutSize(GetScrollOffset());
2035   // Represent the rect in the container's scroll-origin coordinate.
2036   local_expose_rect.Move(border_origin_to_scroll_origin);
2037   LayoutRect scroll_snapport_rect = VisibleScrollSnapportRect();
2038
2039   ScrollOffset target_offset = ScrollAlignment::GetScrollOffsetToExpose(
2040       scroll_snapport_rect, local_expose_rect, params.GetScrollAlignmentX(),
2041       params.GetScrollAlignmentY(), GetScrollOffset());
2042   ScrollOffset new_scroll_offset(
2043       ClampScrollOffset(RoundedIntSize(target_offset)));
2044
2045   ScrollOffset old_scroll_offset = GetScrollOffset();
2046   if (params.GetScrollType() == kUserScroll) {
2047     if (!UserInputScrollable(kHorizontalScrollbar))
2048       new_scroll_offset.SetWidth(old_scroll_offset.Width());
2049     if (!UserInputScrollable(kVerticalScrollbar))
2050       new_scroll_offset.SetHeight(old_scroll_offset.Height());
2051   }
2052
2053   FloatPoint end_point = ScrollOffsetToPosition(new_scroll_offset);
2054   std::unique_ptr<SnapSelectionStrategy> strategy =
2055       SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(end_point),
2056                                                   true, true);
2057   end_point = GetLayoutBox()
2058                   ->GetDocument()
2059                   .GetSnapCoordinator()
2060                   ->GetSnapPosition(*GetLayoutBox(), *strategy)
2061                   .value_or(end_point);
2062   new_scroll_offset = ScrollPositionToOffset(end_point);
2063
2064   if (params.is_for_scroll_sequence) {
2065     DCHECK(params.GetScrollType() == kProgrammaticScroll ||
2066            params.GetScrollType() == kUserScroll);
2067     ScrollBehavior behavior =
2068         DetermineScrollBehavior(params.GetScrollBehavior(),
2069                                 GetLayoutBox()->StyleRef().GetScrollBehavior());
2070     GetSmoothScrollSequencer()->QueueAnimation(this, new_scroll_offset,
2071                                                behavior);
2072   } else {
2073     SetScrollOffset(new_scroll_offset, params.GetScrollType(),
2074                     kScrollBehaviorInstant);
2075   }
2076
2077   ScrollOffset scroll_offset_difference = new_scroll_offset - old_scroll_offset;
2078   // The container hasn't performed the scroll yet if it's for scroll sequence.
2079   // To calculate the result from the scroll, we move the |local_expose_rect| to
2080   // the will-be-scrolled location.
2081   local_expose_rect.Move(-LayoutSize(scroll_offset_difference));
2082
2083   // Represent the rects in the container's border-box coordinate.
2084   local_expose_rect.Move(-border_origin_to_scroll_origin);
2085   scroll_snapport_rect.Move(-border_origin_to_scroll_origin);
2086   LayoutRect intersect = Intersection(scroll_snapport_rect, local_expose_rect);
2087
2088   if (intersect.IsEmpty() && !scroll_snapport_rect.IsEmpty() &&
2089       !local_expose_rect.IsEmpty()) {
2090     return LocalToAbsolute(*GetLayoutBox(), local_expose_rect);
2091   }
2092   intersect = LocalToAbsolute(*GetLayoutBox(), intersect);
2093   return intersect;
2094 }
2095
2096 void PaintLayerScrollableArea::UpdateScrollableAreaSet() {
2097   LocalFrame* frame = GetLayoutBox()->GetFrame();
2098   if (!frame)
2099     return;
2100
2101   LocalFrameView* frame_view = frame->View();
2102   if (!frame_view)
2103     return;
2104
2105   bool has_overflow =
2106       !GetLayoutBox()->Size().IsZero() &&
2107       ((HasHorizontalOverflow() && GetLayoutBox()->ScrollsOverflowX()) ||
2108        (HasVerticalOverflow() && GetLayoutBox()->ScrollsOverflowY()));
2109
2110   bool is_visible_to_hit_test =
2111       GetLayoutBox()->StyleRef().VisibleToHitTesting();
2112   bool did_scroll_overflow = scrolls_overflow_;
2113   if (GetLayoutBox()->IsLayoutView()) {
2114     ScrollbarMode h_mode;
2115     ScrollbarMode v_mode;
2116     ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
2117     if (h_mode == kScrollbarAlwaysOff && v_mode == kScrollbarAlwaysOff)
2118       has_overflow = false;
2119   }
2120   scrolls_overflow_ = has_overflow && is_visible_to_hit_test;
2121   if (did_scroll_overflow == ScrollsOverflow())
2122     return;
2123
2124   if (RuntimeEnabledFeatures::ImplicitRootScrollerEnabled() &&
2125       scrolls_overflow_) {
2126     if (GetLayoutBox()->IsLayoutView()) {
2127       if (Element* owner = GetLayoutBox()->GetDocument().LocalOwner()) {
2128         owner->GetDocument().GetRootScrollerController().ConsiderForImplicit(
2129             *owner);
2130       }
2131     } else {
2132       GetLayoutBox()
2133           ->GetDocument()
2134           .GetRootScrollerController()
2135           .ConsiderForImplicit(*GetLayoutBox()->GetNode());
2136     }
2137   }
2138
2139   // The scroll and scroll offset properties depend on |scrollsOverflow| (see:
2140   // PaintPropertyTreeBuilder::updateScrollAndScrollTranslation).
2141   GetLayoutBox()->SetNeedsPaintPropertyUpdate();
2142
2143   if (scrolls_overflow_) {
2144     DCHECK(CanHaveOverflowScrollbars(*GetLayoutBox()));
2145     frame_view->AddScrollableArea(this);
2146   } else {
2147     frame_view->RemoveScrollableArea(this);
2148   }
2149
2150   layer_->DidUpdateScrollsOverflow();
2151 }
2152
2153 void PaintLayerScrollableArea::UpdateCompositingLayersAfterScroll() {
2154   PaintLayerCompositor* compositor = GetLayoutBox()->View()->Compositor();
2155   if (!compositor->InCompositingMode())
2156     return;
2157
2158   if (UsesCompositedScrolling()) {
2159     DCHECK(Layer()->HasCompositedLayerMapping());
2160     ScrollingCoordinator* scrolling_coordinator = GetScrollingCoordinator();
2161     bool handled_scroll =
2162         Layer()->IsRootLayer() && scrolling_coordinator &&
2163         scrolling_coordinator->UpdateCompositedScrollOffset(this);
2164
2165     if (!handled_scroll) {
2166       if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
2167         // In non-BGPT mode, we need to do a full sub-tree update here, because
2168         // we need to update the position property to compute
2169         // offset_to_transform_parent. For more context, see the comment from
2170         // chrishtr@ here:
2171         // https://chromium-review.googlesource.com/c/chromium/src/+/1403639/6/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
2172         Layer()->GetCompositedLayerMapping()->SetNeedsGraphicsLayerUpdate(
2173             kGraphicsLayerUpdateSubtree);
2174       }
2175       compositor->SetNeedsCompositingUpdate(
2176           kCompositingUpdateAfterGeometryChange);
2177     }
2178
2179     // If we have fixed elements and we scroll the root layer we might
2180     // change compositing since the fixed elements might now overlap a
2181     // composited layer.
2182     if (Layer()->IsRootLayer()) {
2183       LocalFrame* frame = GetLayoutBox()->GetFrame();
2184       if (frame && frame->View() &&
2185           frame->View()->HasViewportConstrainedObjects()) {
2186         Layer()->SetNeedsCompositingInputsUpdate();
2187       }
2188     }
2189   } else {
2190     Layer()->SetNeedsCompositingInputsUpdate();
2191   }
2192 }
2193
2194 ScrollingCoordinator* PaintLayerScrollableArea::GetScrollingCoordinator()
2195     const {
2196   LocalFrame* frame = GetLayoutBox()->GetFrame();
2197   if (!frame)
2198     return nullptr;
2199
2200   Page* page = frame->GetPage();
2201   if (!page)
2202     return nullptr;
2203
2204   return page->GetScrollingCoordinator();
2205 }
2206
2207 bool PaintLayerScrollableArea::ShouldScrollOnMainThread() const {
2208   if (HasBeenDisposed())
2209     return true;
2210   if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
2211     if (frame->View()->GetMainThreadScrollingReasons())
2212       return true;
2213   }
2214   if (HasNonCompositedStickyDescendants())
2215     return true;
2216   return ScrollableArea::ShouldScrollOnMainThread();
2217 }
2218
2219 static bool LayerNodeMayNeedCompositedScrolling(const PaintLayer* layer) {
2220   // Don't force composite scroll for select or text input elements.
2221   if (Node* node = layer->GetLayoutObject().GetNode()) {
2222     if (IsHTMLSelectElement(node))
2223       return false;
2224     if (TextControlElement* text_control = EnclosingTextControl(node)) {
2225       if (IsHTMLInputElement(text_control)) {
2226         return false;
2227       }
2228     }
2229   }
2230   return true;
2231 }
2232
2233 bool PaintLayerScrollableArea::ComputeNeedsCompositedScrolling(
2234     const bool layer_has_been_composited,
2235     const PaintLayer* layer) {
2236   non_composited_main_thread_scrolling_reasons_ = 0;
2237
2238   if (CompositingReasonFinder::RequiresCompositingForRootScroller(*layer))
2239     return true;
2240
2241   // TODO(crbug.com/839341): Remove ScrollTimeline check once we support
2242   // main-thread AnimationWorklet and don't need to promote the scroll-source.
2243   Node* node = layer->GetLayoutObject().GetNode();
2244   if (!layer->ScrollsOverflow() &&
2245       !ScrollTimeline::HasActiveScrollTimeline(node)) {
2246     return false;
2247   }
2248
2249   if (layer->Size().IsEmpty())
2250     return false;
2251
2252   if (!layer_has_been_composited &&
2253       !LayerNodeMayNeedCompositedScrolling(layer)) {
2254     return false;
2255   }
2256
2257   bool needs_composited_scrolling = true;
2258
2259   // TODO(flackr): Allow integer transforms as long as all of the ancestor
2260   // transforms are also integer.
2261   bool background_supports_lcd_text =
2262       GetLayoutBox()->StyleRef().IsStackingContext() &&
2263       GetLayoutBox()->GetBackgroundPaintLocation(
2264           &non_composited_main_thread_scrolling_reasons_) &
2265           kBackgroundPaintInScrollingContents &&
2266       layer->BackgroundIsKnownToBeOpaqueInRect(
2267           ToLayoutBox(layer->GetLayoutObject()).PhysicalPaddingBoxRect(),
2268           true) &&
2269       !layer->CompositesWithTransform() && !layer->CompositesWithOpacity();
2270
2271   // TODO(crbug.com/839341): Remove ScrollTimeline check once we support
2272   // main-thread AnimationWorklet and don't need to promote the scroll-source.
2273   if (!ScrollTimeline::HasActiveScrollTimeline(node) &&
2274       !layer_has_been_composited &&
2275       !layer->Compositor()->PreferCompositingToLCDTextEnabled() &&
2276       !background_supports_lcd_text) {
2277     if (layer->CompositesWithOpacity()) {
2278       non_composited_main_thread_scrolling_reasons_ |=
2279           MainThreadScrollingReason::kHasOpacityAndLCDText;
2280     }
2281     if (layer->CompositesWithTransform()) {
2282       non_composited_main_thread_scrolling_reasons_ |=
2283           MainThreadScrollingReason::kHasTransformAndLCDText;
2284     }
2285     if (!layer->BackgroundIsKnownToBeOpaqueInRect(
2286             ToLayoutBox(layer->GetLayoutObject()).PhysicalPaddingBoxRect(),
2287             true)) {
2288       non_composited_main_thread_scrolling_reasons_ |=
2289           MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText;
2290     }
2291     if (!layer->GetLayoutObject().StyleRef().IsStackingContext()) {
2292       non_composited_main_thread_scrolling_reasons_ |=
2293           MainThreadScrollingReason::kIsNotStackingContextAndLCDText;
2294     }
2295
2296     needs_composited_scrolling = false;
2297   }
2298
2299   if (layer->GetLayoutObject().HasClip() ||
2300       layer->HasDescendantWithClipPath() || !!layer->ClipPathAncestor()) {
2301     non_composited_main_thread_scrolling_reasons_ |=
2302         MainThreadScrollingReason::kHasClipRelatedProperty;
2303     needs_composited_scrolling = false;
2304   }
2305
2306   DCHECK(!(non_composited_main_thread_scrolling_reasons_ &
2307            ~MainThreadScrollingReason::kNonCompositedReasons));
2308   return needs_composited_scrolling;
2309 }
2310
2311 void PaintLayerScrollableArea::UpdateNeedsCompositedScrolling(
2312     bool layer_has_been_composited) {
2313   const bool needs_composited_scrolling =
2314       ComputeNeedsCompositedScrolling(layer_has_been_composited, Layer());
2315
2316   if (static_cast<bool>(needs_composited_scrolling_) !=
2317       needs_composited_scrolling) {
2318     needs_composited_scrolling_ = needs_composited_scrolling;
2319   }
2320 }
2321
2322 bool PaintLayerScrollableArea::VisualViewportSuppliesScrollbars() const {
2323   LocalFrame* frame = GetLayoutBox()->GetFrame();
2324   if (!frame || !frame->GetSettings())
2325     return false;
2326
2327   // On desktop, we always use the layout viewport's scrollbars.
2328   if (!frame->GetSettings()->GetViewportEnabled())
2329     return false;
2330
2331   const TopDocumentRootScrollerController& controller =
2332       GetLayoutBox()->GetDocument().GetPage()->GlobalRootScrollerController();
2333   return controller.RootScrollerArea() == this;
2334 }
2335
2336 bool PaintLayerScrollableArea::ScheduleAnimation() {
2337   if (ChromeClient* client = GetChromeClient()) {
2338     client->ScheduleAnimation(GetLayoutBox()->GetFrame()->View());
2339     return true;
2340   }
2341   return false;
2342 }
2343
2344 void PaintLayerScrollableArea::ResetRebuildScrollbarLayerFlags() {
2345   rebuild_horizontal_scrollbar_layer_ = false;
2346   rebuild_vertical_scrollbar_layer_ = false;
2347 }
2348
2349 CompositorAnimationHost* PaintLayerScrollableArea::GetCompositorAnimationHost()
2350     const {
2351   return layer_->GetLayoutObject().GetFrameView()->GetCompositorAnimationHost();
2352 }
2353
2354 CompositorAnimationTimeline*
2355 PaintLayerScrollableArea::GetCompositorAnimationTimeline() const {
2356   return layer_->GetLayoutObject()
2357       .GetFrameView()
2358       ->GetCompositorAnimationTimeline();
2359 }
2360
2361 void PaintLayerScrollableArea::GetTickmarks(Vector<IntRect>& tickmarks) const {
2362   if (layer_->IsRootLayer())
2363     tickmarks = ToLayoutView(GetLayoutBox())->GetTickmarks();
2364 }
2365
2366 void PaintLayerScrollableArea::ScrollbarManager::SetHasHorizontalScrollbar(
2367     bool has_scrollbar) {
2368   if (has_scrollbar) {
2369     // This doesn't hit in any tests, but since the equivalent code in
2370     // setHasVerticalScrollbar does, presumably this code does as well.
2371     DisableCompositingQueryAsserts disabler;
2372     if (!h_bar_) {
2373       h_bar_ = CreateScrollbar(kHorizontalScrollbar);
2374       h_bar_is_attached_ = 1;
2375       if (!h_bar_->IsCustomScrollbar())
2376         ScrollableArea()->DidAddScrollbar(*h_bar_, kHorizontalScrollbar);
2377     } else {
2378       h_bar_is_attached_ = 1;
2379     }
2380   } else {
2381     h_bar_is_attached_ = 0;
2382     if (!DelayScrollOffsetClampScope::ClampingIsDelayed())
2383       DestroyScrollbar(kHorizontalScrollbar);
2384   }
2385 }
2386
2387 void PaintLayerScrollableArea::ScrollbarManager::SetHasVerticalScrollbar(
2388     bool has_scrollbar) {
2389   if (has_scrollbar) {
2390     DisableCompositingQueryAsserts disabler;
2391     if (!v_bar_) {
2392       v_bar_ = CreateScrollbar(kVerticalScrollbar);
2393       v_bar_is_attached_ = 1;
2394       if (!v_bar_->IsCustomScrollbar())
2395         ScrollableArea()->DidAddScrollbar(*v_bar_, kVerticalScrollbar);
2396     } else {
2397       v_bar_is_attached_ = 1;
2398     }
2399   } else {
2400     v_bar_is_attached_ = 0;
2401     if (!DelayScrollOffsetClampScope::ClampingIsDelayed())
2402       DestroyScrollbar(kVerticalScrollbar);
2403   }
2404 }
2405
2406 Scrollbar* PaintLayerScrollableArea::ScrollbarManager::CreateScrollbar(
2407     ScrollbarOrientation orientation) {
2408   DCHECK(orientation == kHorizontalScrollbar ? !h_bar_is_attached_
2409                                              : !v_bar_is_attached_);
2410   Scrollbar* scrollbar = nullptr;
2411   const LayoutObject& style_source =
2412       ScrollbarStyleSource(*ScrollableArea()->GetLayoutBox());
2413   bool has_custom_scrollbar_style =
2414       style_source.StyleRef().HasPseudoStyle(kPseudoIdScrollbar);
2415   if (has_custom_scrollbar_style) {
2416     DCHECK(style_source.GetNode() && style_source.GetNode()->IsElementNode());
2417     scrollbar = LayoutScrollbar::CreateCustomScrollbar(
2418         ScrollableArea(), orientation, ToElement(style_source.GetNode()));
2419   } else {
2420     ScrollbarControlSize scrollbar_size = kRegularScrollbar;
2421     if (style_source.StyleRef().HasAppearance()) {
2422       scrollbar_size = LayoutTheme::GetTheme().ScrollbarControlSizeForPart(
2423           style_source.StyleRef().Appearance());
2424     }
2425     scrollbar = Scrollbar::Create(ScrollableArea(), orientation, scrollbar_size,
2426                                   &ScrollableArea()
2427                                        ->GetLayoutBox()
2428                                        ->GetFrame()
2429                                        ->GetPage()
2430                                        ->GetChromeClient());
2431   }
2432   ScrollableArea()->GetLayoutBox()->GetDocument().View()->AddScrollbar(
2433       scrollbar);
2434   return scrollbar;
2435 }
2436
2437 void PaintLayerScrollableArea::ScrollbarManager::DestroyScrollbar(
2438     ScrollbarOrientation orientation) {
2439   Member<Scrollbar>& scrollbar =
2440       orientation == kHorizontalScrollbar ? h_bar_ : v_bar_;
2441   DCHECK(orientation == kHorizontalScrollbar ? !h_bar_is_attached_
2442                                              : !v_bar_is_attached_);
2443   if (!scrollbar)
2444     return;
2445
2446   ScrollableArea()->SetScrollbarNeedsPaintInvalidation(orientation);
2447   if (orientation == kHorizontalScrollbar)
2448     ScrollableArea()->rebuild_horizontal_scrollbar_layer_ = true;
2449   else
2450     ScrollableArea()->rebuild_vertical_scrollbar_layer_ = true;
2451
2452   if (!scrollbar->IsCustomScrollbar())
2453     ScrollableArea()->WillRemoveScrollbar(*scrollbar, orientation);
2454
2455   ScrollableArea()->GetLayoutBox()->GetDocument().View()->RemoveScrollbar(
2456       scrollbar);
2457   scrollbar->DisconnectFromScrollableArea();
2458   scrollbar = nullptr;
2459 }
2460
2461 void PaintLayerScrollableArea::ScrollbarManager::DestroyDetachedScrollbars() {
2462   DCHECK(!h_bar_is_attached_ || h_bar_);
2463   DCHECK(!v_bar_is_attached_ || v_bar_);
2464   if (h_bar_ && !h_bar_is_attached_)
2465     DestroyScrollbar(kHorizontalScrollbar);
2466   if (v_bar_ && !v_bar_is_attached_)
2467     DestroyScrollbar(kVerticalScrollbar);
2468 }
2469
2470 void PaintLayerScrollableArea::ScrollbarManager::Dispose() {
2471   h_bar_is_attached_ = v_bar_is_attached_ = 0;
2472   DestroyScrollbar(kHorizontalScrollbar);
2473   DestroyScrollbar(kVerticalScrollbar);
2474 }
2475
2476 void PaintLayerScrollableArea::ScrollbarManager::Trace(
2477     blink::Visitor* visitor) {
2478   visitor->Trace(scrollable_area_);
2479   visitor->Trace(h_bar_);
2480   visitor->Trace(v_bar_);
2481 }
2482
2483 uint64_t PaintLayerScrollableArea::Id() const {
2484   return DOMNodeIds::IdForNode(GetLayoutBox()->GetNode());
2485 }
2486
2487 int PaintLayerScrollableArea::PreventRelayoutScope::count_ = 0;
2488 SubtreeLayoutScope*
2489     PaintLayerScrollableArea::PreventRelayoutScope::layout_scope_ = nullptr;
2490 bool PaintLayerScrollableArea::PreventRelayoutScope::relayout_needed_ = false;
2491
2492 PaintLayerScrollableArea::PreventRelayoutScope::PreventRelayoutScope(
2493     SubtreeLayoutScope& layout_scope) {
2494   if (!count_) {
2495     DCHECK(!layout_scope_);
2496     DCHECK(NeedsRelayoutList().IsEmpty());
2497     layout_scope_ = &layout_scope;
2498   }
2499   count_++;
2500 }
2501
2502 PaintLayerScrollableArea::PreventRelayoutScope::~PreventRelayoutScope() {
2503   if (--count_ == 0) {
2504     if (relayout_needed_) {
2505       for (auto scrollable_area : NeedsRelayoutList()) {
2506         DCHECK(scrollable_area->NeedsRelayout());
2507         LayoutBox* box = scrollable_area->GetLayoutBox();
2508         layout_scope_->SetNeedsLayout(
2509             box, layout_invalidation_reason::kScrollbarChanged);
2510         if (box->IsLayoutBlock()) {
2511           bool horizontal_scrollbar_changed =
2512               scrollable_area->HasHorizontalScrollbar() !=
2513               scrollable_area->HadHorizontalScrollbarBeforeRelayout();
2514           bool vertical_scrollbar_changed =
2515               scrollable_area->HasVerticalScrollbar() !=
2516               scrollable_area->HadVerticalScrollbarBeforeRelayout();
2517           if (horizontal_scrollbar_changed || vertical_scrollbar_changed) {
2518             ToLayoutBlock(box)->ScrollbarsChanged(horizontal_scrollbar_changed,
2519                                                   vertical_scrollbar_changed);
2520           }
2521         }
2522         scrollable_area->SetNeedsRelayout(false);
2523       }
2524
2525       NeedsRelayoutList().clear();
2526     }
2527     layout_scope_ = nullptr;
2528   }
2529 }
2530
2531 void PaintLayerScrollableArea::PreventRelayoutScope::SetBoxNeedsLayout(
2532     PaintLayerScrollableArea& scrollable_area,
2533     bool had_horizontal_scrollbar,
2534     bool had_vertical_scrollbar) {
2535   DCHECK(count_);
2536   DCHECK(layout_scope_);
2537   if (scrollable_area.NeedsRelayout())
2538     return;
2539   scrollable_area.SetNeedsRelayout(true);
2540   scrollable_area.SetHadHorizontalScrollbarBeforeRelayout(
2541       had_horizontal_scrollbar);
2542   scrollable_area.SetHadVerticalScrollbarBeforeRelayout(had_vertical_scrollbar);
2543
2544   relayout_needed_ = true;
2545   NeedsRelayoutList().push_back(&scrollable_area);
2546 }
2547
2548 void PaintLayerScrollableArea::PreventRelayoutScope::ResetRelayoutNeeded() {
2549   DCHECK_EQ(count_, 0);
2550   DCHECK(NeedsRelayoutList().IsEmpty());
2551   relayout_needed_ = false;
2552 }
2553
2554 HeapVector<Member<PaintLayerScrollableArea>>&
2555 PaintLayerScrollableArea::PreventRelayoutScope::NeedsRelayoutList() {
2556   DEFINE_STATIC_LOCAL(
2557       Persistent<HeapVector<Member<PaintLayerScrollableArea>>>,
2558       needs_relayout_list,
2559       (MakeGarbageCollected<HeapVector<Member<PaintLayerScrollableArea>>>()));
2560   return *needs_relayout_list;
2561 }
2562
2563 int PaintLayerScrollableArea::FreezeScrollbarsScope::count_ = 0;
2564
2565 int PaintLayerScrollableArea::DelayScrollOffsetClampScope::count_ = 0;
2566
2567 PaintLayerScrollableArea::DelayScrollOffsetClampScope::
2568     DelayScrollOffsetClampScope() {
2569   DCHECK(count_ > 0 || NeedsClampList().IsEmpty());
2570   count_++;
2571 }
2572
2573 PaintLayerScrollableArea::DelayScrollOffsetClampScope::
2574     ~DelayScrollOffsetClampScope() {
2575   if (--count_ == 0)
2576     DelayScrollOffsetClampScope::ClampScrollableAreas();
2577 }
2578
2579 void PaintLayerScrollableArea::DelayScrollOffsetClampScope::SetNeedsClamp(
2580     PaintLayerScrollableArea* scrollable_area) {
2581   if (!scrollable_area->NeedsScrollOffsetClamp()) {
2582     scrollable_area->SetNeedsScrollOffsetClamp(true);
2583     NeedsClampList().push_back(scrollable_area);
2584   }
2585 }
2586
2587 void PaintLayerScrollableArea::DelayScrollOffsetClampScope::
2588     ClampScrollableAreas() {
2589   for (auto& scrollable_area : NeedsClampList())
2590     scrollable_area->ClampScrollOffsetAfterOverflowChange();
2591   NeedsClampList().clear();
2592 }
2593
2594 HeapVector<Member<PaintLayerScrollableArea>>&
2595 PaintLayerScrollableArea::DelayScrollOffsetClampScope::NeedsClampList() {
2596   DEFINE_STATIC_LOCAL(
2597       Persistent<HeapVector<Member<PaintLayerScrollableArea>>>,
2598       needs_clamp_list,
2599       (MakeGarbageCollected<HeapVector<Member<PaintLayerScrollableArea>>>()));
2600   return *needs_clamp_list;
2601 }
2602
2603 ScrollbarTheme& PaintLayerScrollableArea::GetPageScrollbarTheme() const {
2604   // If PaintLayer is destructed before PaintLayerScrollable area, we can not
2605   // get the page scrollbar theme setting.
2606   DCHECK(!HasBeenDisposed());
2607
2608   Page* page = GetLayoutBox()->GetFrame()->GetPage();
2609   DCHECK(page);
2610
2611   return page->GetScrollbarTheme();
2612 }
2613
2614 void PaintLayerScrollableArea::WillRemoveScrollbar(
2615     Scrollbar& scrollbar,
2616     ScrollbarOrientation orientation) {
2617   if (!scrollbar.IsCustomScrollbar() &&
2618       !(orientation == kHorizontalScrollbar ? LayerForHorizontalScrollbar()
2619                                             : LayerForVerticalScrollbar())) {
2620     ObjectPaintInvalidator(*GetLayoutBox())
2621         .SlowSetPaintingLayerNeedsRepaintAndInvalidateDisplayItemClient(
2622             scrollbar, PaintInvalidationReason::kScrollControl);
2623   }
2624
2625   ScrollableArea::WillRemoveScrollbar(scrollbar, orientation);
2626 }
2627
2628 static LayoutRect ScrollControlVisualRect(
2629     const IntRect& scroll_control_rect,
2630     const LayoutBox& box,
2631     const PaintInvalidatorContext& context,
2632     const LayoutRect& previous_visual_rect) {
2633   LayoutRect visual_rect(scroll_control_rect);
2634 #if DCHECK_IS_ON()
2635   FindVisualRectNeedingUpdateScope finder(box, context, previous_visual_rect,
2636                                           visual_rect);
2637 #endif
2638   if (!context.NeedsVisualRectUpdate(box))
2639     return previous_visual_rect;
2640
2641   // No need to apply any paint offset. Scroll controls paint in a different
2642   // transform space than their contained box (the scrollbarPaintOffset
2643   // transform node).
2644   return visual_rect;
2645 }
2646
2647 // Returns true if the scroll control is invalidated.
2648 static bool InvalidatePaintOfScrollControlIfNeeded(
2649     const LayoutRect& new_visual_rect,
2650     const LayoutRect& previous_visual_rect,
2651     bool needs_paint_invalidation,
2652     LayoutBox& box,
2653     const LayoutBoxModelObject& paint_invalidation_container) {
2654   bool should_invalidate_new_rect = needs_paint_invalidation;
2655   if (new_visual_rect != previous_visual_rect) {
2656     should_invalidate_new_rect = true;
2657   } else if (previous_visual_rect.IsEmpty()) {
2658     DCHECK(new_visual_rect.IsEmpty());
2659     // Do not issue an empty invalidation.
2660     should_invalidate_new_rect = false;
2661   }
2662
2663   return should_invalidate_new_rect;
2664 }
2665
2666 static LayoutRect InvalidatePaintOfScrollbarIfNeeded(
2667     Scrollbar* scrollbar,
2668     GraphicsLayer* graphics_layer,
2669     bool& previously_was_overlay,
2670     const LayoutRect& previous_visual_rect,
2671     bool needs_paint_invalidation_arg,
2672     LayoutBox& box,
2673     const PaintInvalidatorContext& context) {
2674   bool is_overlay = scrollbar && scrollbar->IsOverlayScrollbar();
2675
2676   LayoutRect new_visual_rect;
2677   // Calculate visual rect of the scrollbar, except overlay composited
2678   // scrollbars because we invalidate the graphics layer only.
2679   if (scrollbar && !(graphics_layer && is_overlay)) {
2680     new_visual_rect = ScrollControlVisualRect(scrollbar->FrameRect(), box,
2681                                               context, previous_visual_rect);
2682   }
2683
2684   bool needs_paint_invalidation = needs_paint_invalidation_arg;
2685   if (needs_paint_invalidation && graphics_layer) {
2686     // If the scrollbar needs paint invalidation but didn't change location/size
2687     // or the scrollbar is an overlay scrollbar (visual rect is empty),
2688     // invalidating the graphics layer is enough (which has been done in
2689     // ScrollableArea::setScrollbarNeedsPaintInvalidation()).
2690     // Otherwise invalidatePaintOfScrollControlIfNeeded() below will invalidate
2691     // the old and new location of the scrollbar on the box's paint invalidation
2692     // container to ensure newly expanded/shrunk areas of the box to be
2693     // invalidated.
2694     needs_paint_invalidation = false;
2695     DCHECK(!graphics_layer->PaintsContentOrHitTest() ||
2696            graphics_layer->GetPaintController().GetPaintArtifact().IsEmpty());
2697   }
2698
2699   // Invalidate the box's display item client if the box's padding box size is
2700   // affected by change of the non-overlay scrollbar width. We detect change of
2701   // visual rect size instead of change of scrollbar width change, which may
2702   // have some false-positives (e.g. the scrollbar changed length but not width)
2703   // but won't invalidate more than expected because in the false-positive case
2704   // the box must have changed size and have been invalidated.
2705   const LayoutBoxModelObject& paint_invalidation_container =
2706       *context.paint_invalidation_container;
2707   LayoutSize new_scrollbar_used_space_in_box;
2708   if (!is_overlay)
2709     new_scrollbar_used_space_in_box = new_visual_rect.Size();
2710   LayoutSize previous_scrollbar_used_space_in_box;
2711   if (!previously_was_overlay)
2712     previous_scrollbar_used_space_in_box = previous_visual_rect.Size();
2713
2714   // The IsEmpty() check avoids invalidaiton in cases when the visual rect
2715   // changes from (0,0 0x0) to (0,0 0x100).
2716   if (!(new_scrollbar_used_space_in_box.IsEmpty() &&
2717         previous_scrollbar_used_space_in_box.IsEmpty()) &&
2718       new_scrollbar_used_space_in_box != previous_scrollbar_used_space_in_box) {
2719     context.painting_layer->SetNeedsRepaint();
2720     ObjectPaintInvalidator(box).InvalidateDisplayItemClient(
2721         box, PaintInvalidationReason::kGeometry);
2722   }
2723
2724   bool invalidated = InvalidatePaintOfScrollControlIfNeeded(
2725       new_visual_rect, previous_visual_rect, needs_paint_invalidation, box,
2726       paint_invalidation_container);
2727
2728   previously_was_overlay = is_overlay;
2729
2730   if (!invalidated || !scrollbar || graphics_layer)
2731     return new_visual_rect;
2732
2733   context.painting_layer->SetNeedsRepaint();
2734   ObjectPaintInvalidator(box).InvalidateDisplayItemClient(
2735       *scrollbar, PaintInvalidationReason::kScrollControl);
2736   if (scrollbar->IsCustomScrollbar()) {
2737     ToLayoutScrollbar(scrollbar)
2738         ->InvalidateDisplayItemClientsOfScrollbarParts();
2739   }
2740
2741   return new_visual_rect;
2742 }
2743
2744 void PaintLayerScrollableArea::InvalidatePaintOfScrollControlsIfNeeded(
2745     const PaintInvalidatorContext& context) {
2746   LayoutBox& box = *GetLayoutBox();
2747   SetHorizontalScrollbarVisualRect(InvalidatePaintOfScrollbarIfNeeded(
2748       HorizontalScrollbar(), LayerForHorizontalScrollbar(),
2749       horizontal_scrollbar_previously_was_overlay_,
2750       horizontal_scrollbar_visual_rect_,
2751       HorizontalScrollbarNeedsPaintInvalidation(), box, context));
2752   SetVerticalScrollbarVisualRect(InvalidatePaintOfScrollbarIfNeeded(
2753       VerticalScrollbar(), LayerForVerticalScrollbar(),
2754       vertical_scrollbar_previously_was_overlay_,
2755       vertical_scrollbar_visual_rect_,
2756       VerticalScrollbarNeedsPaintInvalidation(), box, context));
2757
2758   LayoutRect scroll_corner_and_resizer_visual_rect =
2759       ScrollControlVisualRect(ScrollCornerAndResizerRect(), box, context,
2760                               scroll_corner_and_resizer_visual_rect_);
2761   const LayoutBoxModelObject& paint_invalidation_container =
2762       *context.paint_invalidation_container;
2763   if (InvalidatePaintOfScrollControlIfNeeded(
2764           scroll_corner_and_resizer_visual_rect,
2765           scroll_corner_and_resizer_visual_rect_,
2766           ScrollCornerNeedsPaintInvalidation(), box,
2767           paint_invalidation_container)) {
2768     SetScrollCornerAndResizerVisualRect(scroll_corner_and_resizer_visual_rect);
2769     if (LayoutScrollbarPart* scroll_corner = ScrollCorner()) {
2770       ObjectPaintInvalidator(*scroll_corner)
2771           .InvalidateDisplayItemClientsIncludingNonCompositingDescendants(
2772               PaintInvalidationReason::kScrollControl);
2773     }
2774     if (LayoutScrollbarPart* resizer = Resizer()) {
2775       ObjectPaintInvalidator(*resizer)
2776           .InvalidateDisplayItemClientsIncludingNonCompositingDescendants(
2777               PaintInvalidationReason::kScrollControl);
2778     }
2779   }
2780
2781   ClearNeedsPaintInvalidationForScrollControls();
2782 }
2783
2784 void PaintLayerScrollableArea::ClearPreviousVisualRects() {
2785   SetHorizontalScrollbarVisualRect(LayoutRect());
2786   SetVerticalScrollbarVisualRect(LayoutRect());
2787   SetScrollCornerAndResizerVisualRect(LayoutRect());
2788 }
2789
2790 void PaintLayerScrollableArea::SetHorizontalScrollbarVisualRect(
2791     const LayoutRect& rect) {
2792   horizontal_scrollbar_visual_rect_ = rect;
2793   if (Scrollbar* scrollbar = HorizontalScrollbar())
2794     scrollbar->SetVisualRect(rect);
2795 }
2796
2797 void PaintLayerScrollableArea::SetVerticalScrollbarVisualRect(
2798     const LayoutRect& rect) {
2799   vertical_scrollbar_visual_rect_ = rect;
2800   if (Scrollbar* scrollbar = VerticalScrollbar())
2801     scrollbar->SetVisualRect(rect);
2802 }
2803
2804 void PaintLayerScrollableArea::SetScrollCornerAndResizerVisualRect(
2805     const LayoutRect& rect) {
2806   scroll_corner_and_resizer_visual_rect_ = rect;
2807   if (LayoutScrollbarPart* scroll_corner = ScrollCorner())
2808     scroll_corner->GetMutableForPainting().FirstFragment().SetVisualRect(rect);
2809   if (LayoutScrollbarPart* resizer = Resizer())
2810     resizer->GetMutableForPainting().FirstFragment().SetVisualRect(rect);
2811 }
2812
2813 void PaintLayerScrollableArea::ScrollControlWasSetNeedsPaintInvalidation() {
2814   GetLayoutBox()->SetShouldCheckForPaintInvalidation();
2815 }
2816
2817 void PaintLayerScrollableArea::DidScrollWithScrollbar(
2818     ScrollbarPart part,
2819     ScrollbarOrientation orientation) {
2820   WebFeature scrollbar_use_uma;
2821   switch (part) {
2822     case kBackButtonStartPart:
2823     case kForwardButtonStartPart:
2824     case kBackButtonEndPart:
2825     case kForwardButtonEndPart:
2826       scrollbar_use_uma =
2827           (orientation == kVerticalScrollbar
2828                ? WebFeature::kScrollbarUseVerticalScrollbarButton
2829                : WebFeature::kScrollbarUseHorizontalScrollbarButton);
2830       break;
2831     case kThumbPart:
2832       scrollbar_use_uma =
2833           (orientation == kVerticalScrollbar
2834                ? WebFeature::kScrollbarUseVerticalScrollbarThumb
2835                : WebFeature::kScrollbarUseHorizontalScrollbarThumb);
2836       break;
2837     case kBackTrackPart:
2838     case kForwardTrackPart:
2839       scrollbar_use_uma =
2840           (orientation == kVerticalScrollbar
2841                ? WebFeature::kScrollbarUseVerticalScrollbarTrack
2842                : WebFeature::kScrollbarUseHorizontalScrollbarTrack);
2843       break;
2844     default:
2845       return;
2846   }
2847
2848   UseCounter::Count(GetLayoutBox()->GetDocument(), scrollbar_use_uma);
2849 }
2850
2851 CompositorElementId PaintLayerScrollableArea::GetCompositorElementId() const {
2852   return CompositorElementIdFromUniqueObjectId(
2853       GetLayoutBox()->UniqueId(), CompositorElementIdNamespace::kScroll);
2854 }
2855
2856 LayoutRect
2857 PaintLayerScrollableArea::ScrollingBackgroundDisplayItemClient::VisualRect()
2858     const {
2859   const auto* box = scrollable_area_->GetLayoutBox();
2860   const auto& paint_offset = box->FirstFragment().PaintOffset();
2861   auto overflow_clip_rect =
2862       PixelSnappedIntRect(box->OverflowClipRect(paint_offset));
2863   auto scroll_size = scrollable_area_->PixelSnappedContentsSize(paint_offset);
2864   // Ensure scrolling contents are at least as large as the scroll clip
2865   scroll_size = scroll_size.ExpandedTo(overflow_clip_rect.Size());
2866   LayoutRect result(overflow_clip_rect.Location(), scroll_size);
2867 #if DCHECK_IS_ON()
2868   if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
2869     DCHECK_EQ(result,
2870               scrollable_area_->layer_->GraphicsLayerBacking()->VisualRect());
2871   }
2872 #endif
2873   return result;
2874 }
2875
2876 String
2877 PaintLayerScrollableArea::ScrollingBackgroundDisplayItemClient::DebugName()
2878     const {
2879   return "Scrolling background of " +
2880          scrollable_area_->GetLayoutBox()->DebugName();
2881 }
2882
2883 bool PaintLayerScrollableArea::ScrollingBackgroundDisplayItemClient::
2884     PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
2885   return scrollable_area_->GetLayoutBox()
2886       ->PaintedOutputOfObjectHasNoEffectRegardlessOfSize();
2887 }
2888
2889 }  // namespace blink