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