[M120 Migration][VD] Support EWK Scroll API for TV WebBrowser
[platform/framework/web/chromium-efl.git] / third_party / blink / renderer / core / paint / paint_layer_scrollable_area.cc
index ee72a82..5a62520 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Other contributors:
  *   Robert O'Callahan <roc+@cs.cmu.edu>
- *   David Baron <dbaron@fas.harvard.edu>
+ *   David Baron <dbaron@dbaron.org>
  *   Christian Biesinger <cbiesinger@gmail.com>
  *   Randall Jesup <rjesup@wgate.com>
  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
 
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 
+#include <utility>
+
 #include "base/numerics/checked_math.h"
-#include "base/single_thread_task_runner.h"
+#include "base/task/single_thread_task_runner.h"
+#include "cc/animation/animation_timeline.h"
+#include "cc/input/main_thread_scrolling_reason.h"
+#include "cc/input/snap_selection_strategy.h"
+#include "cc/layers/picture_layer.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h"
+#include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
 #include "third_party/blink/renderer/core/animation/scroll_timeline.h"
-#include "third_party/blink/renderer/core/css/pseudo_style_request.h"
+#include "third_party/blink/renderer/core/content_capture/content_capture_manager.h"
+#include "third_party/blink/renderer/core/css/color_scheme_flags.h"
+#include "third_party/blink/renderer/core/css/style_request.h"
 #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
 #include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
 #include "third_party/blink/renderer/core/html/forms/text_control_element.h"
 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
 #include "third_party/blink/renderer/core/input/event_handler.h"
+#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
+#include "third_party/blink/renderer/core/layout/custom_scrollbar.h"
+#include "third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.h"
 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
-#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
-#include "third_party/blink/renderer/core/layout/layout_scrollbar.h"
-#include "third_party/blink/renderer/core/layout/layout_scrollbar_part.h"
 #include "third_party/blink/renderer/core/layout/layout_theme.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/focus_controller.h"
 #include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
 #include "third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h"
-#include "third_party/blink/renderer/core/page/scrolling/root_scroller_util.h"
 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
 #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
+#include "third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h"
 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
-#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
-#include "third_party/blink/renderer/core/paint/find_paint_offset_and_visual_rect_needing_update.h"
+#include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h"
+#include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
 #include "third_party/blink/renderer/core/paint/paint_invalidator.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_fragment.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
+#include "third_party/blink/renderer/core/scroll/scroll_alignment.h"
+#include "third_party/blink/renderer/core/scroll/scroll_animator_base.h"
+#include "third_party/blink/renderer/core/scroll/scrollable_area.h"
+#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
+#include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
+#include "third_party/blink/renderer/core/view_transition/view_transition.h"
+#include "third_party/blink/renderer/core/view_transition/view_transition_utils.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
-#include "third_party/blink/renderer/platform/scroll/scroll_alignment.h"
-#include "third_party/blink/renderer/platform/scroll/scroll_animator_base.h"
-#include "third_party/blink/renderer/platform/scroll/scrollbar_theme.h"
-#include "third_party/blink/renderer/platform/scroll/smooth_scroll_sequencer.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "ui/base/ui_base_features.h"
+#include "ui/gfx/geometry/point_conversions.h"
 
 namespace blink {
 
-namespace {
-
-// Default value is set to 15 as the default
-// minimum size used by firefox is 15x15.
-static const int kDefaultMinimumWidthForResizing = 15;
-static const int kDefaultMinimumHeightForResizing = 15;
-
-}  // namespace
-
-static LayoutRect LocalToAbsolute(const LayoutBox& box, LayoutRect rect) {
-  return LayoutRect(
-      box.LocalToAbsoluteQuad(FloatQuad(FloatRect(rect)), kUseTransforms)
-          .BoundingBox());
-}
+PaintLayerScrollableAreaRareData::PaintLayerScrollableAreaRareData() = default;
 
-static LayoutRect AbsoluteToLocal(const LayoutBox& box, LayoutRect rect) {
-  return LayoutRect(
-      box.AbsoluteToLocalQuad(FloatQuad(FloatRect(rect)), kUseTransforms)
-          .BoundingBox());
+void PaintLayerScrollableAreaRareData::Trace(Visitor* visitor) const {
+  visitor->Trace(sticky_layers_);
 }
 
-PaintLayerScrollableAreaRareData::PaintLayerScrollableAreaRareData() = default;
-
 const int kResizerControlExpandRatioForTouch = 2;
 
 PaintLayerScrollableArea::PaintLayerScrollableArea(PaintLayer& layer)
-    : layer_(&layer),
+    : ScrollableArea(layer.GetLayoutBox()
+                         ->GetDocument()
+                         .GetPage()
+                         ->GetAgentGroupScheduler()
+                         .CompositorTaskRunner()),
+      layer_(&layer),
       in_resize_mode_(false),
       scrolls_overflow_(false),
-      in_overflow_relayout_(false),
-      allow_second_overflow_relayout_(false),
-      needs_composited_scrolling_(false),
-      rebuild_horizontal_scrollbar_layer_(false),
-      rebuild_vertical_scrollbar_layer_(false),
       needs_scroll_offset_clamp_(false),
       needs_relayout_(false),
       had_horizontal_scrollbar_before_relayout_(false),
       had_vertical_scrollbar_before_relayout_(false),
+      had_resizer_before_relayout_(false),
       scroll_origin_changed_(false),
+      is_scrollbar_freeze_root_(false),
+      is_horizontal_scrollbar_frozen_(false),
+      is_vertical_scrollbar_frozen_(false),
+      should_scroll_on_main_thread_(true),
       scrollbar_manager_(*this),
+      has_last_committed_scroll_offset_(false),
       scroll_corner_(nullptr),
       resizer_(nullptr),
-      scroll_anchor_(this),
-      non_composited_main_thread_scrolling_reasons_(0),
-      horizontal_scrollbar_previously_was_overlay_(false),
-      vertical_scrollbar_previously_was_overlay_(false) {
-  Node* node = GetLayoutBox()->GetNode();
-  if (node && node->IsElementNode()) {
+      scroll_anchor_(this) {
+  if (auto* element = DynamicTo<Element>(GetLayoutBox()->GetNode())) {
     // We save and restore only the scrollOffset as the other scroll values are
     // recalculated.
-    Element* element = ToElement(node);
     scroll_offset_ = element->SavedLayerScrollOffset();
     if (!scroll_offset_.IsZero())
       GetScrollAnimator().SetCurrentOffset(scroll_offset_);
     element->SetSavedLayerScrollOffset(ScrollOffset());
   }
-  UpdateResizerAreaSet();
+
+  if (!RuntimeEnabledFeatures::LayoutNewSnapLogicEnabled()) {
+    GetLayoutBox()->GetDocument().GetSnapCoordinator().AddSnapContainer(
+        *GetLayoutBox());
+  }
 }
 
 PaintLayerScrollableArea::~PaintLayerScrollableArea() {
-  DCHECK(HasBeenDisposed());
+  CHECK(HasBeenDisposed());
+}
+
+PaintLayerScrollableArea* PaintLayerScrollableArea::FromNode(const Node& node) {
+  const LayoutBox* box = node.GetLayoutBox();
+  return box ? box->GetScrollableArea() : nullptr;
 }
 
-void PaintLayerScrollableArea::DidScroll(const FloatPoint& position) {
-  ScrollableArea::DidScroll(position);
+void PaintLayerScrollableArea::DidCompositorScroll(
+    const gfx::PointF& position) {
+  ScrollableArea::DidCompositorScroll(position);
   // This should be alive if it receives composited scroll callbacks.
   CHECK(!HasBeenDisposed());
 }
 
-void PaintLayerScrollableArea::Dispose() {
+void PaintLayerScrollableArea::DisposeImpl() {
+  rare_data_.Clear();
+
+  if (!RuntimeEnabledFeatures::LayoutNewSnapLogicEnabled()) {
+    GetLayoutBox()->GetDocument().GetSnapCoordinator().RemoveSnapContainer(
+        *GetLayoutBox());
+  }
+
   if (InResizeMode() && !GetLayoutBox()->DocumentBeingDestroyed()) {
     if (LocalFrame* frame = GetLayoutBox()->GetFrame())
       frame->GetEventHandler().ResizeScrollableAreaDestroyed();
@@ -175,26 +194,18 @@ void PaintLayerScrollableArea::Dispose() {
 
   if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
     if (LocalFrameView* frame_view = frame->View()) {
-      frame_view->RemoveScrollableArea(this);
+      frame_view->RemoveScrollAnchoringScrollableArea(this);
+      frame_view->RemoveUserScrollableArea(this);
       frame_view->RemoveAnimatingScrollableArea(this);
+      if (RuntimeEnabledFeatures::LayoutNewSnapLogicEnabled()) {
+        frame_view->RemovePendingSnapUpdate(this);
+      }
     }
   }
 
-  non_composited_main_thread_scrolling_reasons_ = 0;
-
-  if (ScrollingCoordinator* scrolling_coordinator = GetScrollingCoordinator())
-    scrolling_coordinator->WillDestroyScrollableArea(this);
-
   if (!GetLayoutBox()->DocumentBeingDestroyed()) {
-    Node* node = GetLayoutBox()->GetNode();
-    // FIXME: Make setSavedLayerScrollOffset take DoubleSize. crbug.com/414283.
-    if (node && node->IsElementNode())
-      ToElement(node)->SetSavedLayerScrollOffset(scroll_offset_);
-  }
-
-  if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
-    if (LocalFrameView* frame_view = frame->View())
-      frame_view->RemoveResizerArea(*GetLayoutBox());
+    if (auto* element = DynamicTo<Element>(GetLayoutBox()->GetNode()))
+      element->SetSavedLayerScrollOffset(scroll_offset_);
   }
 
   // Note: it is not safe to call ScrollAnchor::clear if the document is being
@@ -221,16 +232,44 @@ void PaintLayerScrollableArea::Dispose() {
   if (SmoothScrollSequencer* sequencer = GetSmoothScrollSequencer())
     sequencer->DidDisposeScrollableArea(*this);
 
+  RunScrollCompleteCallbacks(ScrollableArea::ScrollCompletionMode::kFinished);
+
   layer_ = nullptr;
 }
 
-bool PaintLayerScrollableArea::HasBeenDisposed() const {
-  return !layer_;
+void PaintLayerScrollableArea::ApplyPendingHistoryRestoreScrollOffset() {
+  if (!pending_view_state_)
+    return;
+
+  // TODO(pnoland): attempt to restore the anchor in more places than this.
+  // Anchor-based restore should allow for earlier restoration.
+  bool did_restore = RestoreScrollAnchor(
+      {pending_view_state_->scroll_anchor_data_.selector_,
+       LayoutPoint(pending_view_state_->scroll_anchor_data_.offset_),
+       pending_view_state_->scroll_anchor_data_.simhash_});
+  if (!did_restore) {
+    SetScrollOffset(pending_view_state_->scroll_offset_,
+                    mojom::blink::ScrollType::kProgrammatic,
+                    mojom::blink::ScrollBehavior::kAuto);
+  }
+
+  pending_view_state_.reset();
+}
+
+void PaintLayerScrollableArea::SetTickmarksOverride(
+    Vector<gfx::Rect> tickmarks) {
+  EnsureRareData().tickmarks_override_ = std::move(tickmarks);
 }
 
-void PaintLayerScrollableArea::Trace(blink::Visitor* visitor) {
+void PaintLayerScrollableArea::Trace(Visitor* visitor) const {
   visitor->Trace(scrollbar_manager_);
+  visitor->Trace(scroll_corner_);
+  visitor->Trace(resizer_);
   visitor->Trace(scroll_anchor_);
+  visitor->Trace(scrolling_background_display_item_client_);
+  visitor->Trace(scroll_corner_display_item_client_);
+  visitor->Trace(layer_);
+  visitor->Trace(rare_data_);
   ScrollableArea::Trace(visitor);
 }
 
@@ -238,7 +277,7 @@ bool PaintLayerScrollableArea::IsThrottled() const {
   return GetLayoutBox()->GetFrame()->ShouldThrottleRendering();
 }
 
-PlatformChromeClient* PaintLayerScrollableArea::GetChromeClient() const {
+ChromeClient* PaintLayerScrollableArea::GetChromeClient() const {
   if (HasBeenDisposed())
     return nullptr;
   if (Page* page = GetLayoutBox()->GetFrame()->GetPage())
@@ -250,55 +289,8 @@ SmoothScrollSequencer* PaintLayerScrollableArea::GetSmoothScrollSequencer()
     const {
   if (HasBeenDisposed())
     return nullptr;
-  if (Page* page = GetLayoutBox()->GetFrame()->GetPage())
-    return page->GetSmoothScrollSequencer();
-  return nullptr;
-}
 
-GraphicsLayer* PaintLayerScrollableArea::LayerForScrolling() const {
-  return Layer()->HasCompositedLayerMapping()
-             ? Layer()->GetCompositedLayerMapping()->ScrollingContentsLayer()
-             : nullptr;
-}
-
-GraphicsLayer* PaintLayerScrollableArea::LayerForHorizontalScrollbar() const {
-  // See crbug.com/343132.
-  DisableCompositingQueryAsserts disabler;
-
-  return Layer()->HasCompositedLayerMapping()
-             ? Layer()
-                   ->GetCompositedLayerMapping()
-                   ->LayerForHorizontalScrollbar()
-             : nullptr;
-}
-
-GraphicsLayer* PaintLayerScrollableArea::LayerForVerticalScrollbar() const {
-  // See crbug.com/343132.
-  DisableCompositingQueryAsserts disabler;
-
-  return Layer()->HasCompositedLayerMapping()
-             ? Layer()->GetCompositedLayerMapping()->LayerForVerticalScrollbar()
-             : nullptr;
-}
-
-GraphicsLayer* PaintLayerScrollableArea::LayerForScrollCorner() const {
-  // See crbug.com/343132.
-  DisableCompositingQueryAsserts disabler;
-
-  return Layer()->HasCompositedLayerMapping()
-             ? Layer()->GetCompositedLayerMapping()->LayerForScrollCorner()
-             : nullptr;
-}
-
-bool PaintLayerScrollableArea::ShouldUseIntegerScrollOffset() const {
-  if (!HasBeenDisposed()) {
-    Frame* frame = GetLayoutBox()->GetFrame();
-    if (frame->GetSettings() &&
-        !frame->GetSettings()->GetPreferCompositingToLCDTextEnabled())
-      return true;
-  }
-
-  return ScrollableArea::ShouldUseIntegerScrollOffset();
+  return GetLayoutBox()->GetFrame()->GetSmoothScrollSequencer();
 }
 
 bool PaintLayerScrollableArea::IsActive() const {
@@ -315,19 +307,18 @@ static int CornerStart(const LayoutBox& box,
                        int max_x,
                        int thickness) {
   if (box.ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
-    return min_x + box.StyleRef().BorderLeftWidth();
-  return max_x - thickness - box.StyleRef().BorderRightWidth();
+    return min_x + box.StyleRef().BorderLeftWidth().ToFloat();
+  return max_x - thickness - box.StyleRef().BorderRightWidth().ToFloat();
 }
 
-IntRect PaintLayerScrollableArea::PaintLayerScrollableArea::CornerRect(
-    const IntRect& bounds) const {
+gfx::Rect PaintLayerScrollableArea::CornerRect() const {
   int horizontal_thickness;
   int vertical_thickness;
   if (!VerticalScrollbar() && !HorizontalScrollbar()) {
-    // FIXME: This isn't right. We need to know the thickness of custom
-    // scrollbars even when they don't exist in order to set the resizer square
-    // size properly.
-    horizontal_thickness = GetPageScrollbarTheme().ScrollbarThickness();
+    // We need to know the thickness of custom scrollbars even when they don't
+    // exist in order to set the resizer square size properly.
+    horizontal_thickness = GetPageScrollbarTheme().ScrollbarThickness(
+        ScaleFromDIP(), EScrollbarWidth::kAuto);
     vertical_thickness = horizontal_thickness;
   } else if (VerticalScrollbar() && !HorizontalScrollbar()) {
     horizontal_thickness = VerticalScrollbar()->ScrollbarThickness();
@@ -339,14 +330,15 @@ IntRect PaintLayerScrollableArea::PaintLayerScrollableArea::CornerRect(
     horizontal_thickness = VerticalScrollbar()->ScrollbarThickness();
     vertical_thickness = HorizontalScrollbar()->ScrollbarThickness();
   }
-  return IntRect(CornerStart(*GetLayoutBox(), bounds.X(), bounds.MaxX(),
-                             horizontal_thickness),
-                 bounds.MaxY() - vertical_thickness -
-                     GetLayoutBox()->StyleRef().BorderBottomWidth(),
-                 horizontal_thickness, vertical_thickness);
+  gfx::Size border_box_size = PixelSnappedBorderBoxSize();
+  return gfx::Rect(CornerStart(*GetLayoutBox(), 0, border_box_size.width(),
+                               horizontal_thickness),
+                   border_box_size.height() - vertical_thickness -
+                       GetLayoutBox()->StyleRef().BorderBottomWidth().ToFloat(),
+                   horizontal_thickness, vertical_thickness);
 }
 
-IntRect PaintLayerScrollableArea::ScrollCornerRect() const {
+gfx::Rect PaintLayerScrollableArea::ScrollCornerRect() const {
   // We have a scrollbar corner when a scrollbar is visible and not filling the
   // entire length of the box.
   // This happens when:
@@ -354,59 +346,61 @@ IntRect PaintLayerScrollableArea::ScrollCornerRect() const {
   // (b) Both scrollbars are present.
   bool has_horizontal_bar = HorizontalScrollbar();
   bool has_vertical_bar = VerticalScrollbar();
-  bool has_resizer = GetLayoutBox()->Style()->Resize() != EResize::kNone;
+  bool has_resizer = GetLayoutBox()->CanResize();
   if ((has_horizontal_bar && has_vertical_bar) ||
       (has_resizer && (has_horizontal_bar || has_vertical_bar))) {
-    return CornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
-        Layer()->SubpixelAccumulation()));
+    return CornerRect();
   }
-  return IntRect();
+  return gfx::Rect();
+}
+
+void PaintLayerScrollableArea::SetScrollCornerNeedsPaintInvalidation() {
+  ScrollableArea::SetScrollCornerNeedsPaintInvalidation();
 }
 
-IntRect
+gfx::Rect
 PaintLayerScrollableArea::ConvertFromScrollbarToContainingEmbeddedContentView(
     const Scrollbar& scrollbar,
-    const IntRect& scrollbar_rect) const {
+    const gfx::Rect& scrollbar_rect) const {
   LayoutView* view = GetLayoutBox()->View();
   if (!view)
     return scrollbar_rect;
 
-  IntRect rect = scrollbar_rect;
-  rect.Move(ScrollbarOffset(scrollbar));
-
-  return view->GetFrameView()->ConvertFromLayoutObject(*GetLayoutBox(), rect);
+  gfx::Rect rect = scrollbar_rect;
+  rect.Offset(ScrollbarOffset(scrollbar));
+  return ToPixelSnappedRect(
+      GetLayoutBox()->LocalToAbsoluteRect(PhysicalRect(rect)));
 }
 
-IntPoint
+gfx::Point
 PaintLayerScrollableArea::ConvertFromScrollbarToContainingEmbeddedContentView(
     const Scrollbar& scrollbar,
-    const IntPoint& scrollbar_point) const {
+    const gfx::Point& scrollbar_point) const {
   LayoutView* view = GetLayoutBox()->View();
   if (!view)
     return scrollbar_point;
 
-  IntPoint point = scrollbar_point;
-  point.Move(ScrollbarOffset(scrollbar));
-  return view->GetFrameView()->ConvertFromLayoutObject(*GetLayoutBox(), point);
+  gfx::Point point = scrollbar_point + ScrollbarOffset(scrollbar);
+  return ToRoundedPoint(
+      GetLayoutBox()->LocalToAbsolutePoint(PhysicalOffset(point)));
 }
 
-IntPoint
+gfx::Point
 PaintLayerScrollableArea::ConvertFromContainingEmbeddedContentViewToScrollbar(
     const Scrollbar& scrollbar,
-    const IntPoint& parent_point) const {
+    const gfx::Point& parent_point) const {
   LayoutView* view = GetLayoutBox()->View();
   if (!view)
     return parent_point;
 
-  IntPoint point = view->GetFrameView()->ConvertToLayoutObject(*GetLayoutBox(),
-                                                               parent_point);
-
-  point.Move(-ScrollbarOffset(scrollbar));
+  gfx::Point point = ToRoundedPoint(
+      GetLayoutBox()->AbsoluteToLocalPoint(PhysicalOffset(parent_point)));
+  point -= ScrollbarOffset(scrollbar);
   return point;
 }
 
-IntPoint PaintLayerScrollableArea::ConvertFromRootFrame(
-    const IntPoint& point_in_root_frame) const {
+gfx::Point PaintLayerScrollableArea::ConvertFromRootFrame(
+    const gfx::Point& point_in_root_frame) const {
   LayoutView* view = GetLayoutBox()->View();
   if (!view)
     return point_in_root_frame;
@@ -414,42 +408,59 @@ IntPoint PaintLayerScrollableArea::ConvertFromRootFrame(
   return view->GetFrameView()->ConvertFromRootFrame(point_in_root_frame);
 }
 
+gfx::Point PaintLayerScrollableArea::ConvertFromRootFrameToVisualViewport(
+    const gfx::Point& point_in_root_frame) const {
+  LocalFrameView* frame_view = GetLayoutBox()->GetFrameView();
+  DCHECK(frame_view);
+  const auto* page = frame_view->GetPage();
+  const auto& viewport = page->GetVisualViewport();
+  return viewport.RootFrameToViewport(point_in_root_frame);
+}
+
 int PaintLayerScrollableArea::ScrollSize(
     ScrollbarOrientation orientation) const {
-  IntSize scroll_dimensions =
+  gfx::Vector2d scroll_dimensions =
       MaximumScrollOffsetInt() - MinimumScrollOffsetInt();
-  return (orientation == kHorizontalScrollbar) ? scroll_dimensions.Width()
-                                               : scroll_dimensions.Height();
+  return (orientation == kHorizontalScrollbar) ? scroll_dimensions.x()
+                                               : scroll_dimensions.y();
 }
 
 void PaintLayerScrollableArea::UpdateScrollOffset(
     const ScrollOffset& new_offset,
-    ScrollType scroll_type) {
+    mojom::blink::ScrollType scroll_type) {
   if (HasBeenDisposed() || GetScrollOffset() == new_offset)
     return;
 
-  bool offset_was_zero = scroll_offset_.IsZero();
+  TRACE_EVENT2("blink", "PaintLayerScrollableArea::UpdateScrollOffset", "x",
+               new_offset.x(), "y", new_offset.y());
+  TRACE_EVENT_INSTANT1("blink", "Type", TRACE_EVENT_SCOPE_THREAD, "type",
+                       scroll_type);
+
+  LocalFrameView* frame_view = GetLayoutBox()->GetFrameView();
+  CHECK(frame_view);
+
+  // The ScrollOffsetTranslation paint property depends on the scroll offset.
+  // (see: PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation).
+  // Intersection observation cached rects affected by the scroll are not
+  // invalidated because it's hard to find all of them. Validity of cached
+  // rects is checked in IntersectionGeometry::PrepareComputeGeometry().
+  GetLayoutBox()->SetNeedsPaintPropertyUpdatePreservingCachedRects();
+  frame_view->UpdateIntersectionObservationStateOnScroll(new_offset -
+                                                         scroll_offset_);
+
   scroll_offset_ = new_offset;
 
   LocalFrame* frame = GetLayoutBox()->GetFrame();
   DCHECK(frame);
 
-  LocalFrameView* frame_view = GetLayoutBox()->GetFrameView();
   bool is_root_layer = Layer()->IsRootLayer();
 
-  TRACE_EVENT1("devtools.timeline", "ScrollLayer", "data",
-               InspectorScrollLayerEvent::Data(GetLayoutBox()));
-
-  // FIXME(420741): Resolve circular dependency between scroll offset and
-  // compositing state, and remove this disabler.
-  DisableCompositingQueryAsserts disabler;
+  DEVTOOLS_TIMELINE_TRACE_EVENT(
+      "ScrollLayer", inspector_scroll_layer_event::Data, GetLayoutBox());
 
   // Update the positions of our child layers (if needed as only fixed layers
   // should be impacted by a scroll).
   if (!frame_view->IsInPerformLayout()) {
-    // If we're in the middle of layout, we'll just update layers once layout
-    // has finished.
-    Layer()->UpdateLayerPositionsAfterOverflowScroll();
     // Update regions, scrolling may change the clip of a particular region.
     frame_view->UpdateDocumentAnnotatedRegions();
 
@@ -461,26 +472,37 @@ void PaintLayerScrollableArea::UpdateScrollOffset(
     else
       frame_view->SetNeedsUpdateGeometries();
   }
-  UpdateCompositingLayersAfterScroll();
 
-  GetLayoutBox()->DispatchFakeMouseMoveEventSoon(frame->GetEventHandler());
+  if (auto* scrolling_coordinator = GetScrollingCoordinator()) {
+    if (!scrolling_coordinator->UpdateCompositorScrollOffset(*frame, *this)) {
+      GetLayoutBox()->GetFrameView()->SetPaintArtifactCompositorNeedsUpdate();
+    }
+  }
 
-  if (scroll_type == kUserScroll || scroll_type == kCompositorScroll) {
+  if (scroll_type == mojom::blink::ScrollType::kUser ||
+      scroll_type == mojom::blink::ScrollType::kCompositor) {
     Page* page = frame->GetPage();
     if (page)
       page->GetChromeClient().ClearToolTip(*frame);
   }
 
-  InvalidatePaintForScrollOffsetChange(offset_was_zero);
-
-  // The scrollOffsetTranslation paint property depends on the scroll offset.
-  // (see: PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation).
-  GetLayoutBox()->SetNeedsPaintPropertyUpdate();
-
-  // Schedule the scroll DOM event.
-  if (GetLayoutBox()->GetNode()) {
-    GetLayoutBox()->GetNode()->GetDocument().EnqueueScrollEventForNode(
-        GetLayoutBox()->GetNode());
+  InvalidatePaintForScrollOffsetChange();
+
+  // Don't enqueue a scroll event yet for scroll reasons that are not about
+  // explicit changes to scroll. Instead, only do so at the time of the next
+  // lifecycle update, to avoid scroll events that are out of date or don't
+  // result in an actual scroll that is visible to the user. These scroll events
+  // will then be dispatched at the *subsequent* animation frame, because
+  // they happen after layout and therefore the next opportunity to fire the
+  // events is at the next lifecycle update (*).
+  //
+  // (*) https://html.spec.whatwg.org/C/#update-the-rendering steps
+  if (scroll_type == mojom::blink::ScrollType::kClamping ||
+      scroll_type == mojom::blink::ScrollType::kAnchoring) {
+    if (GetLayoutBox()->GetNode())
+      frame_view->SetNeedsEnqueueScrollEvent(this);
+  } else {
+    EnqueueScrollEventIfNeeded();
   }
 
   GetLayoutBox()->View()->ClearHitTestCache();
@@ -490,111 +512,114 @@ void PaintLayerScrollableArea::UpdateScrollOffset(
   if (is_root_layer) {
     frame_view->GetFrame().Loader().SaveScrollState();
     frame_view->DidChangeScrollOffset();
-    if (scroll_type == kCompositorScroll || scroll_type == kUserScroll) {
+    if (scroll_type == mojom::blink::ScrollType::kCompositor ||
+        scroll_type == mojom::blink::ScrollType::kUser) {
       if (DocumentLoader* document_loader = frame->Loader().GetDocumentLoader())
         document_loader->GetInitialScrollState().was_scrolled_by_user = true;
     }
   }
 
-  if (IsExplicitScrollType(scroll_type)) {
-    if (scroll_type != kCompositorScroll)
-      ShowOverlayScrollbars();
-    frame_view->ClearFragmentAnchor();
+  if (FragmentAnchor* anchor = frame_view->GetFragmentAnchor())
+    anchor->DidScroll(scroll_type);
+
+  if (IsExplicitScrollType(scroll_type) ||
+      scroll_type == mojom::blink::ScrollType::kScrollStart) {
+    ShowNonMacOverlayScrollbars();
     GetScrollAnchor()->Clear();
   }
-
+  if (ContentCaptureManager* manager = frame_view->GetFrame()
+                                           .LocalFrameRoot()
+                                           .GetOrResetContentCaptureManager()) {
+    manager->OnScrollPositionChanged();
+  }
   if (AXObjectCache* cache =
           GetLayoutBox()->GetDocument().ExistingAXObjectCache())
     cache->HandleScrollPositionChanged(GetLayoutBox());
 }
 
-void PaintLayerScrollableArea::InvalidatePaintForScrollOffsetChange(
-    bool offset_was_zero) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
-    // "background-attachment: local" causes the background of this element to
-    // change position due to scroll so a paint invalidation is needed.
-    // TODO(pdr): This invalidation can be removed if the local background
-    // attachment is painted into the scrolling contents.
-    if (ScrollsOverflow() &&
-        GetLayoutBox()->Style()->BackgroundLayers().Attachment() ==
-            EFillAttachment::kLocal) {
-      GetLayoutBox()->SetShouldDoFullPaintInvalidation();
-      return;
-    }
-
-    // TODO(pdr): If this is the root frame, descendants with fixed background
-    // attachments need to be invalidated.
-
-    // A scroll offset translation is still needed for overflow:hidden and there
-    // is an optimization to only create this translation node when scroll
-    // offset is non-zero (see: NeedsScrollOrScrollTranslation in
-    // PaintPropertyTreeBuilder.cpp). Because of this optimization, gaining or
-    // losing scroll offset can change whether a property exists and we have to
-    // invalidate paint to ensure this property gets picked up in BlockPainter.
-    bool needs_repaint_for_overflow_hidden =
-        !ScrollsOverflow() && (offset_was_zero || GetScrollOffset().IsZero());
-    // An invalidation is needed to ensure the interest rect is recalculated
-    // so newly-scrolled-to items are repainted. We may want to set a flag on
-    // PaintLayer to just check for interest rect changes instead of doing a
-    // full repaint.
-    bool needs_repaint_for_interest_rect = true;
-    if (needs_repaint_for_overflow_hidden || needs_repaint_for_interest_rect) {
-      Layer()->SetNeedsRepaint();
-      return;
-    }
+void PaintLayerScrollableArea::InvalidatePaintForScrollOffsetChange() {
+  InvalidatePaintForStickyDescendants();
 
-    return;
+  auto* box = GetLayoutBox();
+  auto* frame_view = box->GetFrameView();
+  frame_view->InvalidateBackgroundAttachmentFixedDescendantsOnScroll(*box);
+  if (!box->BackgroundNeedsFullPaintInvalidation() &&
+      BackgroundNeedsRepaintOnScroll()) {
+    box->SetBackgroundNeedsFullPaintInvalidation();
   }
 
-  bool requires_paint_invalidation = true;
-
-  LocalFrameView* frame_view = GetLayoutBox()->GetFrameView();
-  bool is_root_layer = Layer()->IsRootLayer();
-  if (GetLayoutBox()->View()->Compositor()->InCompositingMode()) {
-    bool only_scrolled_composited_layers =
-        ScrollsOverflow() && Layer()->IsAllScrollingContentComposited() &&
-        GetLayoutBox()->Style()->BackgroundLayers().Attachment() !=
-            EFillAttachment::kLocal;
-
-    if (UsesCompositedScrolling() || only_scrolled_composited_layers)
-      requires_paint_invalidation = false;
+  if (auto* compositor = frame_view->GetPaintArtifactCompositor()) {
+    if (compositor->ShouldAlwaysUpdateOnScroll()) {
+      compositor->SetNeedsUpdate();
+    }
   }
+}
 
-  if (requires_paint_invalidation || is_root_layer)
-    frame_view->InvalidateBackgroundAttachmentFixedDescendants(*GetLayoutBox());
+// See the comment in .h about background-attachment:fixed.
+bool PaintLayerScrollableArea::BackgroundNeedsRepaintOnScroll() const {
+  const auto* box = GetLayoutBox();
+  auto background_paint_location = box->GetBackgroundPaintLocation();
+  bool background_paint_in_border_box =
+      background_paint_location & kBackgroundPaintInBorderBoxSpace;
+  bool background_paint_in_scrolling_contents =
+      background_paint_location & kBackgroundPaintInContentsSpace;
 
-  if (!requires_paint_invalidation && is_root_layer) {
-    // Some special invalidations for the root layer.
-    if (frame_view->HasViewportConstrainedObjects()) {
-      if (!frame_view->InvalidateViewportConstrainedObjects())
-        requires_paint_invalidation = true;
-    }
-    InvalidatePaintForStickyDescendants();
+  const auto& background_layers = box->StyleRef().BackgroundLayers();
+  if (background_layers.AnyLayerHasLocalAttachmentImage() &&
+      background_paint_in_border_box) {
+    // Local-attachment background image scrolls, so needs invalidation if it
+    // paints in non-scrolling space.
+    return true;
   }
-
-  if (requires_paint_invalidation) {
-    GetLayoutBox()->SetShouldDoFullPaintInvalidation();
-    GetLayoutBox()->SetMayNeedPaintInvalidationSubtree();
+  if (background_layers.AnyLayerHasDefaultAttachmentImage() &&
+      background_paint_in_scrolling_contents) {
+    // Normal attachment background image doesn't scroll, so needs
+    // invalidation if it paints in scrolling contents.
+    return true;
   }
+  if (background_layers.AnyLayerHasLocalAttachment() &&
+      background_layers.AnyLayerUsesContentBox() &&
+      background_paint_in_border_box &&
+      (box->PaddingLeft() || box->PaddingTop() || box->PaddingRight() ||
+       box->PaddingBottom())) {
+    // Local attachment content box background needs invalidation if there is
+    // padding because the content area can change on scroll (e.g. the top
+    // padding can disappear when the box scrolls to the bottom).
+    return true;
+  }
+  return false;
 }
 
-IntSize PaintLayerScrollableArea::ScrollOffsetInt() const {
-  return FlooredIntSize(scroll_offset_);
+gfx::Vector2d PaintLayerScrollableArea::ScrollOffsetInt() const {
+  return gfx::ToFlooredVector2d(scroll_offset_);
 }
 
 ScrollOffset PaintLayerScrollableArea::GetScrollOffset() const {
   return scroll_offset_;
 }
 
-IntSize PaintLayerScrollableArea::MinimumScrollOffsetInt() const {
-  return ToIntSize(-ScrollOrigin());
+void PaintLayerScrollableArea::EnqueueScrollEventIfNeeded() {
+  if (scroll_offset_ == last_committed_scroll_offset_ &&
+      has_last_committed_scroll_offset_)
+    return;
+  last_committed_scroll_offset_ = scroll_offset_;
+  has_last_committed_scroll_offset_ = true;
+  if (HasBeenDisposed())
+    return;
+  // Schedule the scroll DOM event.
+  if (auto* node = EventTargetNode())
+    node->GetDocument().EnqueueScrollEventForNode(node);
+}
+
+gfx::Vector2d PaintLayerScrollableArea::MinimumScrollOffsetInt() const {
+  return -ScrollOrigin().OffsetFromOrigin();
 }
 
-IntSize PaintLayerScrollableArea::MaximumScrollOffsetInt() const {
-  if (!GetLayoutBox()->HasOverflowClip())
-    return ToIntSize(-ScrollOrigin());
+gfx::Vector2d PaintLayerScrollableArea::MaximumScrollOffsetInt() const {
+  if (!GetLayoutBox() || !GetLayoutBox()->IsScrollContainer())
+    return -ScrollOrigin().OffsetFromOrigin();
 
-  IntSize content_size = ContentsSize();
+  gfx::Size content_size = ContentsSize();
 
   Page* page = GetLayoutBox()->GetDocument().GetPage();
   DCHECK(page);
@@ -604,98 +629,116 @@ IntSize PaintLayerScrollableArea::MaximumScrollOffsetInt() const {
   // The global root scroller should be clipped by the top LocalFrameView rather
   // than it's overflow clipping box. This is to ensure that content exposed by
   // hiding the URL bar at the bottom of the screen is visible.
-  IntSize visible_size;
+  gfx::Size visible_size;
   if (this == controller.RootScrollerArea()) {
     visible_size = controller.RootScrollerVisibleArea();
   } else {
-    visible_size =
-        PixelSnappedIntRect(GetLayoutBox()->OverflowClipRect(
-                                GetLayoutBox()->Location(),
-                                kIgnorePlatformAndCSSOverlayScrollbarSize))
-            .Size();
+    visible_size = ToRoundedSize(
+        GetLayoutBox()
+            ->OverflowClipRect(PhysicalOffset(), kIgnoreOverlayScrollbarSize)
+            .size);
   }
 
   // TODO(skobes): We should really ASSERT that contentSize >= visibleSize
   // when we are not the root layer, but we can't because contentSize is
   // based on stale layout overflow data (http://crbug.com/576933).
-  content_size = content_size.ExpandedTo(visible_size);
+  content_size.SetToMax(visible_size);
 
-  return ToIntSize(-ScrollOrigin() + (content_size - visible_size));
+  return -ScrollOrigin().OffsetFromOrigin() +
+         gfx::Vector2d(content_size.width() - visible_size.width(),
+                       content_size.height() - visible_size.height());
 }
 
 void PaintLayerScrollableArea::VisibleSizeChanged() {
-  ShowOverlayScrollbars();
+  ShowNonMacOverlayScrollbars();
 }
 
-LayoutRect PaintLayerScrollableArea::LayoutContentRect(
+PhysicalRect PaintLayerScrollableArea::LayoutContentRect(
     IncludeScrollbarsInRect scrollbar_inclusion) const {
   // LayoutContentRect is conceptually the same as the box's client rect.
-  LayoutSize layer_size(Layer()->Size());
+  PhysicalSize layer_size = Size();
   LayoutUnit border_width = GetLayoutBox()->BorderWidth();
   LayoutUnit border_height = GetLayoutBox()->BorderHeight();
-  LayoutUnit horizontal_scrollbar_height, vertical_scrollbar_width;
-  if (scrollbar_inclusion == kExcludeScrollbars) {
-    horizontal_scrollbar_height = LayoutUnit(
-        HorizontalScrollbar() && !HorizontalScrollbar()->IsOverlayScrollbar()
-            ? HorizontalScrollbar()->ScrollbarThickness()
-            : 0);
-    vertical_scrollbar_width = LayoutUnit(
-        VerticalScrollbar() && !VerticalScrollbar()->IsOverlayScrollbar()
-            ? VerticalScrollbar()->ScrollbarThickness()
-            : 0);
-  }
-
-  return LayoutRect(
-      LayoutPoint(ScrollPosition()),
-      LayoutSize(
-          layer_size.Width() - border_width - vertical_scrollbar_width,
-          layer_size.Height() - border_height - horizontal_scrollbar_height)
-          .ExpandedTo(LayoutSize()));
-}
-
-IntRect PaintLayerScrollableArea::VisibleContentRect(
+  PhysicalBoxStrut scrollbars;
+  if (scrollbar_inclusion == kExcludeScrollbars)
+    scrollbars = GetLayoutBox()->ComputeScrollbars();
+
+  PhysicalSize size(
+      layer_size.width - border_width - scrollbars.HorizontalSum(),
+      layer_size.height - border_height - scrollbars.VerticalSum());
+  size.ClampNegativeToZero();
+  return PhysicalRect(PhysicalOffset::FromPointFRound(ScrollPosition()), size);
+}
+
+gfx::Rect PaintLayerScrollableArea::VisibleContentRect(
     IncludeScrollbarsInRect scrollbar_inclusion) const {
-  LayoutRect layout_content_rect(LayoutContentRect(scrollbar_inclusion));
+  PhysicalRect layout_content_rect(LayoutContentRect(scrollbar_inclusion));
   // TODO(szager): It's not clear that Floor() is the right thing to do here;
   // what is the correct behavior for fractional scroll offsets?
-  return IntRect(FlooredIntPoint(layout_content_rect.Location()),
-                 PixelSnappedIntSize(layout_content_rect.Size(),
-                                     GetLayoutBox()->Location()));
+  gfx::Size size = ToRoundedSize(layout_content_rect.size);
+  return gfx::Rect(ToFlooredPoint(layout_content_rect.offset), size);
 }
 
-LayoutRect PaintLayerScrollableArea::VisibleScrollSnapportRect(
+PhysicalRect PaintLayerScrollableArea::VisibleScrollSnapportRect(
     IncludeScrollbarsInRect scrollbar_inclusion) const {
   const ComputedStyle* style = GetLayoutBox()->Style();
-  LayoutRect layout_content_rect(LayoutContentRect(scrollbar_inclusion));
-  layout_content_rect.MoveBy(LayoutPoint(-ScrollOrigin()));
-  LayoutRectOutsets padding(MinimumValueForLength(style->ScrollPaddingTop(),
-                                                  layout_content_rect.Height()),
-                            MinimumValueForLength(style->ScrollPaddingRight(),
-                                                  layout_content_rect.Width()),
-                            MinimumValueForLength(style->ScrollPaddingBottom(),
-                                                  layout_content_rect.Height()),
-                            MinimumValueForLength(style->ScrollPaddingLeft(),
-                                                  layout_content_rect.Width()));
+  PhysicalRect layout_content_rect(LayoutContentRect(scrollbar_inclusion));
+  layout_content_rect.Move(PhysicalOffset(-ScrollOrigin().OffsetFromOrigin()));
+  PhysicalBoxStrut padding(MinimumValueForLength(style->ScrollPaddingTop(),
+                                                 layout_content_rect.Height()),
+                           MinimumValueForLength(style->ScrollPaddingRight(),
+                                                 layout_content_rect.Width()),
+                           MinimumValueForLength(style->ScrollPaddingBottom(),
+                                                 layout_content_rect.Height()),
+                           MinimumValueForLength(style->ScrollPaddingLeft(),
+                                                 layout_content_rect.Width()));
   layout_content_rect.Contract(padding);
   return layout_content_rect;
 }
 
-IntSize PaintLayerScrollableArea::ContentsSize() const {
-  return IntSize(PixelSnappedScrollWidth(), PixelSnappedScrollHeight());
+gfx::Size PaintLayerScrollableArea::ContentsSize() const {
+  // We need to take into account of ClientLeft and ClientTop  for
+  // PaintLayerScrollableAreaTest.NotScrollsOverflowWithScrollableScrollbar.
+  PhysicalOffset offset(GetLayoutBox()->ClientLeft(),
+                        GetLayoutBox()->ClientTop());
+  // TODO(crbug.com/962299): The pixel snapping is incorrect in some cases.
+  return PixelSnappedContentsSize(offset);
+}
+
+gfx::Size PaintLayerScrollableArea::PixelSnappedContentsSize(
+    const PhysicalOffset& paint_offset) const {
+  PhysicalSize size = overflow_rect_.size;
+
+  // If we're capturing a transition snapshot, ensure the content size is
+  // considered at least as large as the container. Otherwise, the snapshot
+  // will be clipped by PendingLayer to the content size.
+  if (IsA<LayoutView>(GetLayoutBox())) {
+    if (auto* transition =
+            ViewTransitionUtils::GetTransition(GetLayoutBox()->GetDocument());
+        transition && transition->IsRootTransitioning()) {
+      PhysicalSize container_size(transition->GetSnapshotRootSize());
+      size.width = std::max(container_size.width, size.width);
+      size.height = std::max(container_size.height, size.height);
+    }
+  }
+
+  return ToPixelSnappedRect(PhysicalRect(paint_offset, size)).size();
 }
 
 void PaintLayerScrollableArea::ContentsResized() {
   ScrollableArea::ContentsResized();
   // Need to update the bounds of the scroll property.
   GetLayoutBox()->SetNeedsPaintPropertyUpdate();
+  Layer()->SetNeedsCompositingInputsUpdate();
 }
 
-IntPoint PaintLayerScrollableArea::LastKnownMousePosition() const {
-  return GetLayoutBox()->GetFrame() ? GetLayoutBox()
-                                          ->GetFrame()
-                                          ->GetEventHandler()
-                                          .LastKnownMousePositionInRootFrame()
-                                    : IntPoint();
+gfx::Point PaintLayerScrollableArea::LastKnownMousePosition() const {
+  return GetLayoutBox()->GetFrame()
+             ? gfx::ToFlooredPoint(GetLayoutBox()
+                                       ->GetFrame()
+                                       ->GetEventHandler()
+                                       .LastKnownMousePositionInRootFrame())
+             : gfx::Point();
 }
 
 bool PaintLayerScrollableArea::ScrollAnimatorEnabled() const {
@@ -722,17 +765,28 @@ void PaintLayerScrollableArea::ScrollbarVisibilityChanged() {
   // are affected by overlay scrollbars.
   layer_->GetLayoutObject().SetNeedsPaintPropertyUpdate();
 
-  // TODO(chrishr): this should be able to be removed.
-  layer_->ClearClipRects();
-
   if (LayoutView* view = GetLayoutBox()->View())
     view->ClearHitTestCache();
 }
 
 void PaintLayerScrollableArea::ScrollbarFrameRectChanged() {
-  // Size of non-overlay scrollbar affects overflow clip rect.
-  if (!HasOverlayScrollbars())
-    GetLayoutBox()->SetNeedsPaintPropertyUpdate();
+  // TODO(crbug.com/1020913): This should be called only from layout once the
+  // bug is fixed.
+
+  // Size of non-overlay scrollbar affects overflow clip rect. size of overlay
+  // scrollbar effects hit testing rect excluding overlay scrollbars.
+  if (GetDocument()->Lifecycle().GetState() == DocumentLifecycle::kInPrePaint) {
+    // In pre-paint we avoid marking the ancestor chain as this might cause
+    // problems, see https://crbug.com/1377634. Note that we do not have
+    // automated test case for this, so if you when modifying this code, please
+    // verify that the test cases on the bug do not crash.
+    GetLayoutBox()
+        ->GetMutableForPainting()
+        .SetOnlyThisNeedsPaintPropertyUpdate();
+    return;
+  }
+
+  GetLayoutBox()->SetNeedsPaintPropertyUpdate();
 }
 
 bool PaintLayerScrollableArea::ScrollbarsCanBeActive() const {
@@ -749,16 +803,6 @@ bool PaintLayerScrollableArea::ScrollbarsCanBeActive() const {
   return !!frame_view->GetFrame().GetDocument();
 }
 
-IntRect PaintLayerScrollableArea::ScrollableAreaBoundingBox() const {
-  if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
-    if (LocalFrameView* local_root = frame->LocalFrameRoot().View()) {
-      return local_root->RootFrameToDocument(frame->View()->ConvertToRootFrame(
-          GetLayoutBox()->AbsoluteBoundingBoxRect(0)));
-    }
-  }
-  return IntRect();
-}
-
 void PaintLayerScrollableArea::RegisterForAnimation() {
   if (HasBeenDisposed())
     return;
@@ -779,26 +823,32 @@ void PaintLayerScrollableArea::DeregisterForAnimation() {
 
 bool PaintLayerScrollableArea::UserInputScrollable(
     ScrollbarOrientation orientation) const {
+  if (orientation == kVerticalScrollbar &&
+      GetLayoutBox()->GetDocument().IsVerticalScrollEnforced()) {
+    return false;
+  }
+
   if (GetLayoutBox()->IsIntrinsicallyScrollable(orientation))
     return true;
 
-  if (GetLayoutBox()->IsLayoutView()) {
+  if (IsA<LayoutView>(GetLayoutBox())) {
     Document& document = GetLayoutBox()->GetDocument();
     Element* fullscreen_element = Fullscreen::FullscreenElementFrom(document);
     if (fullscreen_element && fullscreen_element != document.documentElement())
       return false;
 
-    ScrollbarMode h_mode;
-    ScrollbarMode v_mode;
-    ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
-    ScrollbarMode mode =
+    mojom::blink::ScrollbarMode h_mode;
+    mojom::blink::ScrollbarMode v_mode;
+    To<LayoutView>(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
+    mojom::blink::ScrollbarMode mode =
         (orientation == kHorizontalScrollbar) ? h_mode : v_mode;
-    return mode == kScrollbarAuto || mode == kScrollbarAlwaysOn;
+    return mode == mojom::blink::ScrollbarMode::kAuto ||
+           mode == mojom::blink::ScrollbarMode::kAlwaysOn;
   }
 
   EOverflow overflow_style = (orientation == kHorizontalScrollbar)
-                                 ? GetLayoutBox()->Style()->OverflowX()
-                                 : GetLayoutBox()->Style()->OverflowY();
+                                 ? GetLayoutBox()->StyleRef().OverflowX()
+                                 : GetLayoutBox()->StyleRef().OverflowY();
   return (overflow_style == EOverflow::kScroll ||
           overflow_style == EOverflow::kAuto ||
           overflow_style == EOverflow::kOverlay);
@@ -813,21 +863,40 @@ int PaintLayerScrollableArea::PageStep(ScrollbarOrientation orientation) const {
   // use the snapport rect to calculate the page step instead of the visible
   // rect.
   // [1] https://drafts.csswg.org/css-scroll-snap/#scroll-padding
-  IntSize snapport_size = VisibleScrollSnapportRect().PixelSnappedSize();
-  int length = (orientation == kHorizontalScrollbar) ? snapport_size.Width()
-                                                     : snapport_size.Height();
+  gfx::Size snapport_size = VisibleScrollSnapportRect().PixelSnappedSize();
+  int length = (orientation == kHorizontalScrollbar) ? snapport_size.width()
+                                                     : snapport_size.height();
   int min_page_step = static_cast<float>(length) *
                       ScrollableArea::MinFractionToStepWhenPaging();
   int page_step = max(min_page_step, length - MaxOverlapBetweenPages());
   return max(page_step, 1);
 }
 
+bool PaintLayerScrollableArea::IsRootFrameLayoutViewport() const {
+  LocalFrame* frame = GetLayoutBox()->GetFrame();
+  if (!frame || !frame->View())
+    return false;
+
+  RootFrameViewport* root_frame_viewport =
+      frame->View()->GetRootFrameViewport();
+  if (!root_frame_viewport)
+    return false;
+
+  return &root_frame_viewport->LayoutViewport() == this;
+}
+
 LayoutBox* PaintLayerScrollableArea::GetLayoutBox() const {
-  return layer_->GetLayoutBox();
+  return layer_ ? layer_->GetLayoutBox() : nullptr;
 }
 
 PaintLayer* PaintLayerScrollableArea::Layer() const {
-  return layer_;
+  return layer_.Get();
+}
+
+PhysicalSize PaintLayerScrollableArea::Size() const {
+  return layer_->IsRootLayer()
+             ? PhysicalSize(GetLayoutBox()->GetFrameView()->Size())
+             : GetLayoutBox()->Size();
 }
 
 LayoutUnit PaintLayerScrollableArea::ScrollWidth() const {
@@ -838,87 +907,100 @@ LayoutUnit PaintLayerScrollableArea::ScrollHeight() const {
   return overflow_rect_.Height();
 }
 
-int PaintLayerScrollableArea::PixelSnappedScrollWidth() const {
-  return SnapSizeToPixel(ScrollWidth(), GetLayoutBox()->ClientLeft() +
-                                            GetLayoutBox()->Location().X());
-}
-
-int PaintLayerScrollableArea::PixelSnappedScrollHeight() const {
-  return SnapSizeToPixel(ScrollHeight(), GetLayoutBox()->ClientTop() +
-                                             GetLayoutBox()->Location().Y());
-}
-
 void PaintLayerScrollableArea::UpdateScrollOrigin() {
   // This should do nothing prior to first layout; the if-clause will catch
   // that.
-  if (OverflowRect().IsEmpty())
+  if (overflow_rect_.IsEmpty())
     return;
-  LayoutRect scrollable_overflow(overflow_rect_);
-  scrollable_overflow.Move(-GetLayoutBox()->BorderLeft(),
-                           -GetLayoutBox()->BorderTop());
-  IntPoint new_origin(-scrollable_overflow.PixelSnappedLocation() +
-                      GetLayoutBox()->OriginAdjustmentForScrollbars());
-  if (new_origin != scroll_origin_)
+  PhysicalRect scrollable_overflow = overflow_rect_;
+  scrollable_overflow.Move(-PhysicalOffset(GetLayoutBox()->BorderLeft(),
+                                           GetLayoutBox()->BorderTop()));
+  gfx::Point new_origin = ToFlooredPoint(-scrollable_overflow.offset) +
+                          GetLayoutBox()->OriginAdjustmentForScrollbars();
+  if (new_origin != scroll_origin_) {
     scroll_origin_changed_ = true;
+    // ScrollOrigin affects paint offsets of the scrolling contents.
+    GetLayoutBox()->SetSubtreeShouldCheckForPaintInvalidation();
+  }
   scroll_origin_ = new_origin;
 }
 
 void PaintLayerScrollableArea::UpdateScrollDimensions() {
-  LayoutRect new_overflow_rect = GetLayoutBox()->LayoutOverflowRect();
-  GetLayoutBox()->FlipForWritingMode(new_overflow_rect);
+  PhysicalRect new_overflow_rect = GetLayoutBox()->PhysicalLayoutOverflowRect();
 
   // The layout viewport can be larger than the document's layout overflow when
   // top controls are hidden.  Expand the overflow here to ensure that our
   // contents size >= visible size.
-  new_overflow_rect.Unite(
-      LayoutRect(new_overflow_rect.Location(),
-                 LayoutContentRect(kExcludeScrollbars).Size()));
+  new_overflow_rect.Unite(PhysicalRect(
+      new_overflow_rect.offset, LayoutContentRect(kExcludeScrollbars).size));
 
-  if (overflow_rect_.Size() != new_overflow_rect.Size())
-    ContentsResized();
+  bool resized = overflow_rect_.size != new_overflow_rect.size;
   overflow_rect_ = new_overflow_rect;
+  if (resized)
+    ContentsResized();
   UpdateScrollOrigin();
 }
 
-void PaintLayerScrollableArea::UpdateScrollbarEnabledState() {
+void PaintLayerScrollableArea::UpdateScrollbarEnabledState(
+    bool is_horizontal_scrollbar_frozen,
+    bool is_vertical_scrollbar_frozen) {
   bool force_disable =
       GetPageScrollbarTheme().ShouldDisableInvisibleScrollbars() &&
       ScrollbarsHiddenIfOverlay();
 
-  if (HorizontalScrollbar())
-    HorizontalScrollbar()->SetEnabled(HasHorizontalOverflow() &&
-                                      !force_disable);
-  if (VerticalScrollbar())
-    VerticalScrollbar()->SetEnabled(HasVerticalOverflow() && !force_disable);
+  // Don't update the enabled state of a custom scrollbar if that scrollbar
+  // is frozen. Otherwise re-running the style cascade with the change in
+  // :disabled pseudo state matching for custom scrollbars can cause infinite
+  // loops in layout.
+  if (Scrollbar* horizontal_scrollbar = HorizontalScrollbar()) {
+    if (!horizontal_scrollbar->IsCustomScrollbar() ||
+        !is_horizontal_scrollbar_frozen) {
+      horizontal_scrollbar->SetEnabled(HasHorizontalOverflow() &&
+                                       !force_disable);
+    }
+  }
+
+  if (Scrollbar* vertical_scrollbar = VerticalScrollbar()) {
+    if (!vertical_scrollbar->IsCustomScrollbar() ||
+        !is_vertical_scrollbar_frozen) {
+      vertical_scrollbar->SetEnabled(HasVerticalOverflow() && !force_disable);
+    }
+  }
 }
 
 void PaintLayerScrollableArea::UpdateScrollbarProportions() {
   if (Scrollbar* horizontal_scrollbar = HorizontalScrollbar())
-    horizontal_scrollbar->SetProportion(VisibleWidth(), ContentsSize().Width());
+    horizontal_scrollbar->SetProportion(VisibleWidth(), ContentsSize().width());
   if (Scrollbar* vertical_scrollbar = VerticalScrollbar())
-    vertical_scrollbar->SetProportion(VisibleHeight(), ContentsSize().Height());
+    vertical_scrollbar->SetProportion(VisibleHeight(), ContentsSize().height());
 }
 
 void PaintLayerScrollableArea::SetScrollOffsetUnconditionally(
     const ScrollOffset& offset,
-    ScrollType scroll_type) {
+    mojom::blink::ScrollType scroll_type) {
   CancelScrollAnimation();
   ScrollOffsetChanged(offset, scroll_type);
 }
 
 void PaintLayerScrollableArea::UpdateAfterLayout() {
-  bool scrollbars_are_frozen =
-      (in_overflow_relayout_ && !allow_second_overflow_relayout_) ||
-      FreezeScrollbarsScope::ScrollbarsAreFrozen();
-  allow_second_overflow_relayout_ = false;
+  InvalidateAllStickyConstraints();
+
+  bool is_horizontal_scrollbar_frozen = IsHorizontalScrollbarFrozen();
+  bool is_vertical_scrollbar_frozen = IsVerticalScrollbarFrozen();
 
   if (NeedsScrollbarReconstruction()) {
-    SetHasHorizontalScrollbar(false);
-    SetHasVerticalScrollbar(false);
+    RemoveScrollbarsForReconstruction();
+    // In case that DelayScrollOffsetClampScope prevented destruction of the
+    // scrollbars.
+    scrollbar_manager_.DestroyDetachedScrollbars();
   }
 
   UpdateScrollDimensions();
 
+  bool has_resizer = GetLayoutBox()->CanResize();
+  bool resizer_will_change = had_resizer_before_relayout_ != has_resizer;
+  had_resizer_before_relayout_ = has_resizer;
+
   bool had_horizontal_scrollbar = HasHorizontalScrollbar();
   bool had_vertical_scrollbar = HasVerticalScrollbar();
 
@@ -927,15 +1009,10 @@ void PaintLayerScrollableArea::UpdateAfterLayout() {
   ComputeScrollbarExistence(needs_horizontal_scrollbar,
                             needs_vertical_scrollbar);
 
-  // Removing auto scrollbars is a heuristic and can be incorrect if the content
-  // size depends on the scrollbar size (e.g., sized with percentages). Removing
-  // scrollbars can require two additional layout passes so this is only done on
-  // the first layout (!in_overflow_layout).
-  if (!in_overflow_relayout_ && !scrollbars_are_frozen &&
+  if (!is_horizontal_scrollbar_frozen && !is_vertical_scrollbar_frozen &&
       TryRemovingAutoScrollbars(needs_horizontal_scrollbar,
                                 needs_vertical_scrollbar)) {
     needs_horizontal_scrollbar = needs_vertical_scrollbar = false;
-    allow_second_overflow_relayout_ = true;
   }
 
   bool horizontal_scrollbar_should_change =
@@ -944,14 +1021,25 @@ void PaintLayerScrollableArea::UpdateAfterLayout() {
       needs_vertical_scrollbar != had_vertical_scrollbar;
 
   bool scrollbars_will_change =
-      !scrollbars_are_frozen &&
-      (horizontal_scrollbar_should_change || vertical_scrollbar_should_change);
+      (horizontal_scrollbar_should_change && !is_horizontal_scrollbar_frozen) ||
+      (vertical_scrollbar_should_change && !is_vertical_scrollbar_frozen);
   if (scrollbars_will_change) {
     SetHasHorizontalScrollbar(needs_horizontal_scrollbar);
     SetHasVerticalScrollbar(needs_vertical_scrollbar);
 
-    if (HasScrollbar())
-      UpdateScrollCornerStyle();
+    // If we change scrollbars on the layout viewport, the visual viewport
+    // needs to update paint properties to account for the correct
+    // scrollbounds.
+    if (LocalFrameView* frame_view = GetLayoutBox()->GetFrameView()) {
+      VisualViewport& visual_viewport =
+          GetLayoutBox()->GetFrame()->GetPage()->GetVisualViewport();
+      if (this == frame_view->LayoutViewport() &&
+          visual_viewport.IsActiveViewport()) {
+        visual_viewport.SetNeedsPaintPropertyUpdate();
+      }
+    }
+
+    UpdateScrollCornerStyle();
 
     Layer()->UpdateSelfPaintingLayer();
 
@@ -960,78 +1048,134 @@ void PaintLayerScrollableArea::UpdateAfterLayout() {
       GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);
 
     // Our proprietary overflow: overlay value doesn't trigger a layout.
-    // If the box is managed by LayoutNG, don't go here. We don't want to
-    // re-enter the NG layout algorithm for this box from here.
     if (((horizontal_scrollbar_should_change &&
-          GetLayoutBox()->Style()->OverflowX() != EOverflow::kOverlay) ||
+          GetLayoutBox()->StyleRef().OverflowX() != EOverflow::kOverlay) ||
          (vertical_scrollbar_should_change &&
-          GetLayoutBox()->Style()->OverflowY() != EOverflow::kOverlay)) &&
-        !IsManagedByLayoutNG(*GetLayoutBox())) {
+          GetLayoutBox()->StyleRef().OverflowY() != EOverflow::kOverlay))) {
       if ((vertical_scrollbar_should_change &&
            GetLayoutBox()->IsHorizontalWritingMode()) ||
           (horizontal_scrollbar_should_change &&
            !GetLayoutBox()->IsHorizontalWritingMode())) {
-        GetLayoutBox()->SetPreferredLogicalWidthsDirty();
-      }
-      if (PreventRelayoutScope::RelayoutIsPrevented()) {
-        // We're not doing re-layout right now, but we still want to
-        // add the scrollbar to the logical width now, to facilitate parent
-        // layout.
-        GetLayoutBox()->UpdateLogicalWidth();
-        PreventRelayoutScope::SetBoxNeedsLayout(*this, had_horizontal_scrollbar,
-                                                had_vertical_scrollbar);
-      } else {
-        in_overflow_relayout_ = true;
-        SubtreeLayoutScope layout_scope(*GetLayoutBox());
-        layout_scope.SetNeedsLayout(
-            GetLayoutBox(), LayoutInvalidationReason::kScrollbarChanged);
-        if (GetLayoutBox()->IsLayoutBlock()) {
-          LayoutBlock* block = ToLayoutBlock(GetLayoutBox());
-          block->ScrollbarsChanged(horizontal_scrollbar_should_change,
-                                   vertical_scrollbar_should_change);
-          block->UpdateBlockLayout(true);
-        } else {
-          GetLayoutBox()->UpdateLayout();
-        }
-        in_overflow_relayout_ = false;
-        scrollbar_manager_.DestroyDetachedScrollbars();
-      }
-      LayoutObject* parent = GetLayoutBox()->Parent();
-      if (parent && parent->IsFlexibleBox()) {
-        ToLayoutFlexibleBox(parent)->ClearCachedMainSizeForChild(
-            *GetLayoutBox());
+        GetLayoutBox()->SetIntrinsicLogicalWidthsDirty();
       }
+      // Just update the rectangles, in case scrollbars were added or
+      // removed. The calling code on the layout side has its own scrollbar
+      // change detection mechanism.
+      UpdateScrollDimensions();
     }
+  } else if (!HasScrollbar() && resizer_will_change) {
+    Layer()->DirtyStackingContextZOrderLists();
   }
 
-  {
-    // Hits in
-    // compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html.
-    DisableCompositingQueryAsserts disabler;
+  if (RuntimeEnabledFeatures::LayoutNewSnapLogicEnabled()) {
+    EnqueueForSnapUpdateIfNeeded();
+  } else {
+    // The snap container data will be updated at the end of the layout update.
+    // If the data changes, then this will try to re-snap.
+    SetSnapContainerDataNeedsUpdate(true);
+  }
 
-    UpdateScrollbarEnabledState();
+  {
+    UpdateScrollbarEnabledState(is_horizontal_scrollbar_frozen,
+                                is_vertical_scrollbar_frozen);
 
     UpdateScrollbarProportions();
   }
 
-  if (!scrollbars_are_frozen && HasOverlayScrollbars()) {
-    if (!ScrollSize(kHorizontalScrollbar))
-      SetHasHorizontalScrollbar(false);
-    if (!ScrollSize(kVerticalScrollbar))
-      SetHasVerticalScrollbar(false);
+  hypothetical_horizontal_scrollbar_thickness_ = 0;
+  if (NeedsHypotheticalScrollbarThickness(kHorizontalScrollbar)) {
+    hypothetical_horizontal_scrollbar_thickness_ =
+        ComputeHypotheticalScrollbarThickness(kHorizontalScrollbar, true);
+  }
+  hypothetical_vertical_scrollbar_thickness_ = 0;
+  if (NeedsHypotheticalScrollbarThickness(kVerticalScrollbar)) {
+    hypothetical_vertical_scrollbar_thickness_ =
+        ComputeHypotheticalScrollbarThickness(kVerticalScrollbar, true);
   }
 
-  ClampScrollOffsetAfterOverflowChange();
+  DelayableClampScrollOffsetAfterOverflowChange();
 
-  if (!scrollbars_are_frozen) {
+  if (!is_horizontal_scrollbar_frozen || !is_vertical_scrollbar_frozen)
     UpdateScrollableAreaSet();
-  }
 
-  DisableCompositingQueryAsserts disabler;
   PositionOverflowControls();
+
+  if (RuntimeEnabledFeatures::CSSScrollStartEnabled()) {
+    if (IsApplyingScrollStart()) {
+      ApplyScrollStart();
+    }
+  }
+}
+
+Element* PaintLayerScrollableArea::GetElementForScrollStart() const {
+  if (!GetLayoutBox()) {
+    return nullptr;
+  }
+
+  const LayoutBox* box = GetLayoutBox();
+  if (auto* element = DynamicTo<Element>(box->GetNode())) {
+    return element;
+  }
+
+  Node* node = box->GetNode();
+  if (!node && box->Parent() && box->Parent()->IsFieldset()) {
+    return DynamicTo<Element>(box->Parent()->GetNode());
+  }
+
+  if (node && node->IsDocumentNode()) {
+    return GetLayoutBox()->GetDocument().documentElement();
+  }
+
+  return nullptr;
+}
+
+void PaintLayerScrollableArea::SetShouldCheckForPaintInvalidation() {
+  LayoutBox& box = *GetLayoutBox();
+  // This function may be called during pre-paint, and in such cases we cannot
+  // mark the ancestry for paint invalidation checking, since we may already be
+  // done with those objects, and never get to visit them again.
+  if (GetLayoutBox()->GetDocument().Lifecycle().GetState() ==
+      DocumentLifecycle::DocumentLifecycle::kInPrePaint) {
+    box.GetMutableForPainting().SetShouldCheckForPaintInvalidation();
+  } else {
+    box.SetShouldCheckForPaintInvalidation();
+  }
+}
+
+bool PaintLayerScrollableArea::IsApplyingScrollStart() const {
+  if (Element* element = GetElementForScrollStart()) {
+    if (element->HasBeenExplicitlyScrolled()) {
+      return false;
+    }
+    if (GetScrollStartTargets()) {
+      return true;
+    }
+    return !ScrollStartIsDefault();
+  }
+  return false;
+}
+
+void PaintLayerScrollableArea::StopApplyingScrollStart() {
+  if (Element* element = GetElementForScrollStart()) {
+    element->SetHasBeenExplicitlyScrolled();
+  }
+}
+
+void PaintLayerScrollableArea::DelayableClampScrollOffsetAfterOverflowChange() {
+  if (HasBeenDisposed())
+    return;
+  if (DelayScrollOffsetClampScope::ClampingIsDelayed()) {
+    DelayScrollOffsetClampScope::SetNeedsClamp(this);
+    return;
+  }
+  ClampScrollOffsetAfterOverflowChangeInternal();
 }
 
 void PaintLayerScrollableArea::ClampScrollOffsetAfterOverflowChange() {
+  ClampScrollOffsetAfterOverflowChangeInternal();
+}
+
+void PaintLayerScrollableArea::ClampScrollOffsetAfterOverflowChangeInternal() {
   if (HasBeenDisposed())
     return;
 
@@ -1040,16 +1184,25 @@ void PaintLayerScrollableArea::ClampScrollOffsetAfterOverflowChange() {
   // did not change, but the scroll origin *did* change, we still need to notify
   // the scrollbars to update their dimensions.
 
-  if (DelayScrollOffsetClampScope::ClampingIsDelayed()) {
-    DelayScrollOffsetClampScope::SetNeedsClamp(this);
-    return;
+  const Document& document = GetLayoutBox()->GetDocument();
+  if (document.IsPrintingOrPaintingPreview()) {
+    // Scrollable elements may change size when generating layout for printing,
+    // which may require them to change the scroll position in order to keep the
+    // same content within view. In vertical-rl writing-mode, even the root
+    // frame may be attempted scrolled, because a viewport size change may
+    // affect scroll origin. Save all scroll offsets before clamping, so that
+    // everything can be restored the way it was after printing.
+    if (Node* node = EventTargetNode())
+      document.GetFrame()->EnsureSaveScrollOffset(*node);
   }
 
   UpdateScrollDimensions();
-  if (ScrollOriginChanged())
+  if (ScrollOriginChanged()) {
     SetScrollOffsetUnconditionally(ClampScrollOffset(GetScrollOffset()));
-  else
-    ScrollableArea::SetScrollOffset(GetScrollOffset(), kClampingScroll);
+  } else {
+    ScrollableArea::SetScrollOffset(GetScrollOffset(),
+                                    mojom::blink::ScrollType::kClamping);
+  }
 
   SetNeedsScrollOffsetClamp(false);
   ResetScrollOriginChanged();
@@ -1060,10 +1213,8 @@ void PaintLayerScrollableArea::DidChangeGlobalRootScroller() {
   // Being the global root scroller will affect clipping size due to browser
   // controls behavior so we need to update compositing based on updated clip
   // geometry.
-  if (GetLayoutBox()->GetNode()->IsElementNode()) {
-    ToElement(GetLayoutBox()->GetNode())->SetNeedsCompositingUpdate();
-    GetLayoutBox()->SetNeedsPaintPropertyUpdate();
-  }
+  Layer()->SetNeedsCompositingInputsUpdate();
+  GetLayoutBox()->SetNeedsPaintPropertyUpdate();
 
   // On Android, where the VisualViewport supplies scrollbars, we need to
   // remove the PLSA's scrollbars if we become the global root scroller.
@@ -1078,11 +1229,23 @@ void PaintLayerScrollableArea::DidChangeGlobalRootScroller() {
     SetHasHorizontalScrollbar(needs_horizontal_scrollbar);
     SetHasVerticalScrollbar(needs_vertical_scrollbar);
   }
+
+  // Recalculate the snap container data since the scrolling behaviour for this
+  // layout box changed (i.e. it either became the layout viewport or it
+  // is no longer the layout viewport).
+  if (RuntimeEnabledFeatures::LayoutNewSnapLogicEnabled()) {
+    if (!GetLayoutBox()->NeedsLayout()) {
+      EnqueueForSnapUpdateIfNeeded();
+    }
+  } else {
+    SetSnapContainerDataNeedsUpdate(true);
+  }
 }
 
 bool PaintLayerScrollableArea::ShouldPerformScrollAnchoring() const {
   return scroll_anchor_.HasScroller() && GetLayoutBox() &&
-         GetLayoutBox()->Style()->OverflowAnchor() != EOverflowAnchor::kNone &&
+         GetLayoutBox()->StyleRef().OverflowAnchor() !=
+             EOverflowAnchor::kNone &&
          !GetLayoutBox()->GetDocument().FinishingOrIsPrinting();
 }
 
@@ -1092,8 +1255,8 @@ bool PaintLayerScrollableArea::RestoreScrollAnchor(
          scroll_anchor_.RestoreAnchor(serialized_anchor);
 }
 
-FloatQuad PaintLayerScrollableArea::LocalToVisibleContentQuad(
-    const FloatQuad& quad,
+gfx::QuadF PaintLayerScrollableArea::LocalToVisibleContentQuad(
+    const gfx::QuadF& quad,
     const LayoutObject* local_object,
     MapCoordinatesFlags flags) const {
   LayoutBox* box = GetLayoutBox();
@@ -1108,8 +1271,29 @@ PaintLayerScrollableArea::GetTimerTaskRunner() const {
   return GetLayoutBox()->GetFrame()->GetTaskRunner(TaskType::kInternalDefault);
 }
 
-ScrollBehavior PaintLayerScrollableArea::ScrollBehaviorStyle() const {
-  return GetLayoutBox()->Style()->GetScrollBehavior();
+mojom::blink::ScrollBehavior PaintLayerScrollableArea::ScrollBehaviorStyle()
+    const {
+  return GetLayoutBox()->StyleRef().GetScrollBehavior();
+}
+
+mojom::blink::ColorScheme PaintLayerScrollableArea::UsedColorSchemeScrollbars()
+    const {
+  if (RuntimeEnabledFeatures::UsedColorSchemeRootScrollbarsEnabled() &&
+      GetLayoutBox()->IsGlobalRootScroller() &&
+      !GetPageScrollbarTheme().UsesOverlayScrollbars()) {
+    const Document& document = GetLayoutBox()->GetDocument();
+    if (document.documentElement() &&
+        document.documentElement()->GetComputedStyle() &&
+        document.documentElement()->GetComputedStyle()->ColorScheme().empty() &&
+        document.GetStyleEngine().GetPageColorSchemes() ==
+            static_cast<ColorSchemeFlags>(ColorSchemeFlag::kNormal) &&
+        document.GetPreferredColorScheme() ==
+            mojom::blink::PreferredColorScheme::kDark) {
+      return mojom::blink::ColorScheme::kDark;
+    }
+  }
+
+  return GetLayoutBox()->StyleRef().UsedColorScheme();
 }
 
 bool PaintLayerScrollableArea::HasHorizontalOverflow() const {
@@ -1121,32 +1305,34 @@ bool PaintLayerScrollableArea::HasHorizontalOverflow() const {
   // converse problem seems to happen much less frequently in practice, so we
   // bias the logic towards preventing unwanted horizontal scrollbars, which
   // are more common and annoying.
-  LayoutUnit client_width =
-      LayoutContentRect(kIncludeScrollbars).Width() -
-      VerticalScrollbarWidth(kIgnorePlatformAndCSSOverlayScrollbarSize);
+  LayoutUnit client_width = LayoutContentRect(kIncludeScrollbars).Width() -
+                            VerticalScrollbarWidth(kIgnoreOverlayScrollbarSize);
   if (NeedsRelayout() && !HadVerticalScrollbarBeforeRelayout())
     client_width += VerticalScrollbarWidth();
-  LayoutUnit scroll_width(ScrollWidth());
-  LayoutUnit box_x = GetLayoutBox()->Location().X();
-  return SnapSizeToPixel(scroll_width, box_x) >
-         SnapSizeToPixel(client_width, box_x);
+  return ScrollWidth().Round() > client_width.Round();
 }
 
 bool PaintLayerScrollableArea::HasVerticalOverflow() const {
   LayoutUnit client_height =
       LayoutContentRect(kIncludeScrollbars).Height() -
-      HorizontalScrollbarHeight(kIgnorePlatformAndCSSOverlayScrollbarSize);
-  LayoutUnit scroll_height(ScrollHeight());
-  LayoutUnit box_y = GetLayoutBox()->Location().Y();
-  return SnapSizeToPixel(scroll_height, box_y) >
-         SnapSizeToPixel(client_height, box_y);
+      HorizontalScrollbarHeight(kIgnoreOverlayScrollbarSize);
+  return ScrollHeight().Round() > client_height.Round();
+}
+
+#if BUILDFLAG(IS_TIZEN_TV)
+void PaintLayerScrollableArea::ThumbPartFocusChanged(
+    ScrollbarOrientation orientation,
+    bool focused) {
+  if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
+    if (frame->GetSettings() &&
+        frame->GetSettings()->GetUseScrollbarThumbFocusNotifications())
+      frame->Client()->ThumbPartFocusChanged(orientation, focused);
+  }
 }
+#endif
 
 // This function returns true if the given box requires overflow scrollbars (as
-// opposed to the 'viewport' scrollbars managed by the PaintLayerCompositor).
-// FIXME: we should use the same scrolling machinery for both the viewport and
-// overflow. Currently, we need to avoid producing scrollbars here if they'll be
-// handled externally in the RLC.
+// opposed to the viewport scrollbars managed by VisualViewport).
 static bool CanHaveOverflowScrollbars(const LayoutBox& box) {
   return box.GetDocument().ViewportDefiningElement() != box.GetNode();
 }
@@ -1154,84 +1340,54 @@ static bool CanHaveOverflowScrollbars(const LayoutBox& box) {
 void PaintLayerScrollableArea::UpdateAfterStyleChange(
     const ComputedStyle* old_style) {
   // Don't do this on first style recalc, before layout has ever happened.
-  if (!OverflowRect().Size().IsZero()) {
+  if (!overflow_rect_.size.IsZero())
     UpdateScrollableAreaSet();
-  }
 
-  // Whenever background changes on the scrollable element, the scroll bar
-  // overlay style might need to be changed to have contrast against the
-  // background.
-  // Skip the need scrollbar check, because we dont know do we need a scrollbar
-  // when this method get called.
-  Color old_background;
-  if (old_style) {
-    old_background =
-        old_style->VisitedDependentColor(GetCSSPropertyBackgroundColor());
-  }
-  Color new_background = GetLayoutBox()->Style()->VisitedDependentColor(
-      GetCSSPropertyBackgroundColor());
+  UpdateResizerStyle(old_style);
+
+  // The scrollbar overlay color theme depends on styles such as the background
+  // color and the used color scheme.
+  RecalculateScrollbarOverlayColorTheme();
 
-  if (new_background != old_background) {
-    RecalculateScrollbarOverlayColorTheme(new_background);
+  if (NeedsScrollbarReconstruction()) {
+    RemoveScrollbarsForReconstruction();
+    return;
   }
 
   bool needs_horizontal_scrollbar;
   bool needs_vertical_scrollbar;
-  // We add auto scrollbars only during layout to prevent spurious activations.
   ComputeScrollbarExistence(needs_horizontal_scrollbar,
-                            needs_vertical_scrollbar, kForbidAddingAutoBars);
+                            needs_vertical_scrollbar, kOverflowIndependent);
 
   // Avoid some unnecessary computation if there were and will be no scrollbars.
   if (!HasScrollbar() && !needs_horizontal_scrollbar &&
       !needs_vertical_scrollbar)
     return;
 
-  bool horizontal_scrollbar_changed =
-      SetHasHorizontalScrollbar(needs_horizontal_scrollbar);
-  bool vertical_scrollbar_changed =
-      SetHasVerticalScrollbar(needs_vertical_scrollbar);
+  SetHasHorizontalScrollbar(needs_horizontal_scrollbar);
+  SetHasVerticalScrollbar(needs_vertical_scrollbar);
 
-  if (GetLayoutBox()->IsLayoutBlock() &&
-      (horizontal_scrollbar_changed || vertical_scrollbar_changed)) {
-    ToLayoutBlock(GetLayoutBox())
-        ->ScrollbarsChanged(horizontal_scrollbar_changed,
-                            vertical_scrollbar_changed,
-                            LayoutBlock::ScrollbarChangeContext::kStyleChange);
-  }
-
-  // With overflow: scroll, scrollbars are always visible but may be disabled.
-  // When switching to another value, we need to re-enable them (see bug 11985).
-  if (HasHorizontalScrollbar() && old_style &&
-      old_style->OverflowX() == EOverflow::kScroll &&
-      GetLayoutBox()->Style()->OverflowX() != EOverflow::kScroll) {
-    HorizontalScrollbar()->SetEnabled(true);
-  }
-
-  if (HasVerticalScrollbar() && old_style &&
-      old_style->OverflowY() == EOverflow::kScroll &&
-      GetLayoutBox()->Style()->OverflowY() != EOverflow::kScroll) {
-    VerticalScrollbar()->SetEnabled(true);
-  }
-
-  // FIXME: Need to detect a swap from custom to native scrollbars (and vice
-  // versa).
   if (HorizontalScrollbar())
     HorizontalScrollbar()->StyleChanged();
   if (VerticalScrollbar())
     VerticalScrollbar()->StyleChanged();
 
   UpdateScrollCornerStyle();
-  UpdateResizerAreaSet();
-  UpdateResizerStyle(old_style);
-}
 
-void PaintLayerScrollableArea::UpdateAfterCompositingChange() {
-  Layer()->UpdateScrollingStateAfterCompositingChange();
+  if (!old_style ||
+      old_style->UsedColorScheme() != UsedColorSchemeScrollbars() ||
+      old_style->ScrollbarThumbColorResolved() !=
+          GetLayoutBox()->StyleRef().ScrollbarThumbColorResolved() ||
+      old_style->ScrollbarTrackColorResolved() !=
+          GetLayoutBox()->StyleRef().ScrollbarTrackColorResolved()) {
+    SetScrollControlsNeedFullPaintInvalidation();
+  }
 }
 
 void PaintLayerScrollableArea::UpdateAfterOverflowRecalc() {
   UpdateScrollDimensions();
   UpdateScrollbarProportions();
+  UpdateScrollbarEnabledState();
 
   bool needs_horizontal_scrollbar;
   bool needs_vertical_scrollbar;
@@ -1248,118 +1404,158 @@ void PaintLayerScrollableArea::UpdateAfterOverflowRecalc() {
       (GetLayoutBox()->HasAutoVerticalScrollbar() &&
        vertical_scrollbar_should_change)) {
     GetLayoutBox()->SetNeedsLayoutAndFullPaintInvalidation(
-        LayoutInvalidationReason::kUnknown);
+        layout_invalidation_reason::kUnknown);
   }
 
   ClampScrollOffsetAfterOverflowChange();
+  UpdateScrollableAreaSet();
 }
 
-IntRect PaintLayerScrollableArea::RectForHorizontalScrollbar(
-    const IntRect& border_box_rect) const {
+gfx::Rect PaintLayerScrollableArea::RectForHorizontalScrollbar() const {
   if (!HasHorizontalScrollbar())
-    return IntRect();
+    return gfx::Rect();
 
-  const IntRect& scroll_corner = ScrollCornerRect();
-
-  return IntRect(
-      HorizontalScrollbarStart(border_box_rect.X()),
-      border_box_rect.MaxY() - GetLayoutBox()->BorderBottom().ToInt() -
+  const gfx::Rect& scroll_corner = ScrollCornerRect();
+  gfx::Size border_box_size = PixelSnappedBorderBoxSize();
+  return gfx::Rect(
+      HorizontalScrollbarStart(),
+      border_box_size.height() - GetLayoutBox()->BorderBottom().ToInt() -
           HorizontalScrollbar()->ScrollbarThickness(),
-      border_box_rect.Width() -
+      border_box_size.width() -
           (GetLayoutBox()->BorderLeft() + GetLayoutBox()->BorderRight())
               .ToInt() -
-          scroll_corner.Width(),
+          scroll_corner.width(),
       HorizontalScrollbar()->ScrollbarThickness());
 }
 
-IntRect PaintLayerScrollableArea::RectForVerticalScrollbar(
-    const IntRect& border_box_rect) const {
+gfx::Rect PaintLayerScrollableArea::RectForVerticalScrollbar() const {
   if (!HasVerticalScrollbar())
-    return IntRect();
-
-  const IntRect& scroll_corner = ScrollCornerRect();
+    return gfx::Rect();
 
-  return IntRect(
-      VerticalScrollbarStart(border_box_rect.X(), border_box_rect.MaxX()),
-      border_box_rect.Y() + GetLayoutBox()->BorderTop().ToInt(),
+  const gfx::Rect& scroll_corner = ScrollCornerRect();
+  return gfx::Rect(
+      VerticalScrollbarStart(), GetLayoutBox()->BorderTop().ToInt(),
       VerticalScrollbar()->ScrollbarThickness(),
-      border_box_rect.Height() -
+      PixelSnappedBorderBoxSize().height() -
           (GetLayoutBox()->BorderTop() + GetLayoutBox()->BorderBottom())
               .ToInt() -
-          scroll_corner.Height());
+          scroll_corner.height());
 }
 
-int PaintLayerScrollableArea::VerticalScrollbarStart(int min_x,
-                                                     int max_x) const {
+int PaintLayerScrollableArea::VerticalScrollbarStart() const {
   if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
-    return min_x + GetLayoutBox()->BorderLeft().ToInt();
-  return max_x - GetLayoutBox()->BorderRight().ToInt() -
+    return GetLayoutBox()->BorderLeft().ToInt();
+  return PixelSnappedBorderBoxSize().width() -
+         GetLayoutBox()->BorderRight().ToInt() -
          VerticalScrollbar()->ScrollbarThickness();
 }
 
-int PaintLayerScrollableArea::HorizontalScrollbarStart(int min_x) const {
-  int x = min_x + GetLayoutBox()->BorderLeft().ToInt();
-  if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
-    x += HasVerticalScrollbar()
-             ? VerticalScrollbar()->ScrollbarThickness()
-             : ResizerCornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
-                                     Layer()->SubpixelAccumulation()),
-                                 kResizerForPointer)
-                   .Width();
+int PaintLayerScrollableArea::HorizontalScrollbarStart() const {
+  int x = GetLayoutBox()->BorderLeft().ToInt();
+  if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
+    x += HasVerticalScrollbar() ? VerticalScrollbar()->ScrollbarThickness()
+                                : ResizerCornerRect(kResizerForPointer).width();
+  }
   return x;
 }
 
-IntSize PaintLayerScrollableArea::ScrollbarOffset(
+gfx::Vector2d PaintLayerScrollableArea::ScrollbarOffset(
     const Scrollbar& scrollbar) const {
   // TODO(szager): Factor out vertical offset calculation into other methods,
   // for symmetry with *ScrollbarStart methods for horizontal offset.
   if (&scrollbar == VerticalScrollbar()) {
-    return IntSize(
-        VerticalScrollbarStart(0, Layer()->PixelSnappedSize().Width()),
-        GetLayoutBox()->BorderTop().ToInt());
+    return gfx::Vector2d(VerticalScrollbarStart(),
+                         GetLayoutBox()->BorderTop().ToInt());
   }
 
   if (&scrollbar == HorizontalScrollbar()) {
-    return IntSize(HorizontalScrollbarStart(0),
-                   GetLayoutBox()->BorderTop().ToInt() +
-                       VisibleContentRect(kIncludeScrollbars).Height() -
-                       HorizontalScrollbar()->ScrollbarThickness());
+    return gfx::Vector2d(HorizontalScrollbarStart(),
+                         GetLayoutBox()->BorderTop().ToInt() +
+                             VisibleContentRect(kIncludeScrollbars).height() -
+                             HorizontalScrollbar()->ScrollbarThickness());
   }
 
   NOTREACHED();
-  return IntSize();
+  return gfx::Vector2d();
 }
 
 static inline const LayoutObject& ScrollbarStyleSource(
     const LayoutBox& layout_box) {
-  if (layout_box.IsLayoutView()) {
+  if (IsA<LayoutView>(layout_box)) {
     Document& doc = layout_box.GetDocument();
+
+    // If the layout box uses standard scrollbar styles use it as the style
+    // source.
+    if (layout_box.StyleRef().UsesStandardScrollbarStyle()) {
+      return layout_box;
+    }
+
+    // Legacy custom scrollbar styles on the document element or the <body> may
+    // apply to the viewport scrollbars. We don't propagate these styles to
+    // LayoutView in StyleResolver like we do for the standard CSS scrollbar
+    // styles because some conditions can only be checked here.
     if (Settings* settings = doc.GetSettings()) {
+      LocalFrame* frame = layout_box.GetFrame();
+      DCHECK(frame);
+      DCHECK(frame->GetPage());
+
+      VisualViewport& viewport = frame->GetPage()->GetVisualViewport();
       if (!settings->GetAllowCustomScrollbarInMainFrame() &&
-          layout_box.GetFrame() && layout_box.GetFrame()->IsMainFrame())
+          frame->IsMainFrame() && viewport.IsActiveViewport()) {
         return layout_box;
+      }
     }
 
-    // Try the <body> element first as a scrollbar source, but only if the body
+    // Try the <body> element as a scrollbar source, but only if the body
     // can scroll.
     Element* body = doc.body();
     if (body && body->GetLayoutObject() && body->GetLayoutObject()->IsBox() &&
-        body->GetLayoutObject()->Style()->HasPseudoStyle(kPseudoIdScrollbar))
+        body->GetLayoutObject()->StyleRef().HasCustomScrollbarStyle())
       return *body->GetLayoutObject();
 
     // If the <body> didn't have a custom style, then the root element might.
     Element* doc_element = doc.documentElement();
     if (doc_element && doc_element->GetLayoutObject() &&
-        doc_element->GetLayoutObject()->Style()->HasPseudoStyle(
-            kPseudoIdScrollbar))
+        doc_element->GetLayoutObject()->StyleRef().HasCustomScrollbarStyle() &&
+        !layout_box.StyleRef().UsesStandardScrollbarStyle()) {
       return *doc_element->GetLayoutObject();
+    }
+  } else if (!layout_box.GetNode() && layout_box.Parent()) {
+    return *layout_box.Parent();
   }
 
   return layout_box;
 }
 
 int PaintLayerScrollableArea::HypotheticalScrollbarThickness(
+    ScrollbarOrientation orientation,
+    bool should_include_overlay_thickness) const {
+  DCHECK(NeedsHypotheticalScrollbarThickness(orientation));
+  // The cached values are updated after layout, use them if we're layout clean.
+  if (should_include_overlay_thickness &&
+      GetLayoutBox()->GetDocument().Lifecycle().GetState() >=
+          DocumentLifecycle::kLayoutClean) {
+    return orientation == kHorizontalScrollbar
+               ? hypothetical_horizontal_scrollbar_thickness_
+               : hypothetical_vertical_scrollbar_thickness_;
+  }
+  return ComputeHypotheticalScrollbarThickness(
+      orientation, should_include_overlay_thickness);
+}
+
+// Hypothetical scrollbar thickness is computed and cached during layout, but
+// only as needed to avoid a performance penalty. It is needed for every
+// LayoutView, to support frame view auto-sizing; and it's needed whenever CSS
+// scrollbar-gutter requires it.
+bool PaintLayerScrollableArea::NeedsHypotheticalScrollbarThickness(
     ScrollbarOrientation orientation) const {
+  return GetLayoutBox()->IsLayoutView() ||
+         GetLayoutBox()->HasScrollbarGutters(orientation);
+}
+
+int PaintLayerScrollableArea::ComputeHypotheticalScrollbarThickness(
+    ScrollbarOrientation orientation,
+    bool should_include_overlay_thickness) const {
   Scrollbar* scrollbar = orientation == kHorizontalScrollbar
                              ? HorizontalScrollbar()
                              : VerticalScrollbar();
@@ -1367,27 +1563,16 @@ int PaintLayerScrollableArea::HypotheticalScrollbarThickness(
     return scrollbar->ScrollbarThickness();
 
   const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
-  bool has_custom_scrollbar_style =
-      style_source.StyleRef().HasPseudoStyle(kPseudoIdScrollbar);
-  if (has_custom_scrollbar_style) {
-    return LayoutScrollbar::HypotheticalScrollbarThickness(
-        orientation, *GetLayoutBox(), style_source);
+  if (style_source.StyleRef().HasCustomScrollbarStyle()) {
+    return CustomScrollbar::HypotheticalScrollbarThickness(this, orientation,
+                                                           &style_source);
   }
 
-  ScrollbarControlSize scrollbar_size = kRegularScrollbar;
-  if (style_source.StyleRef().HasAppearance()) {
-    scrollbar_size = LayoutTheme::GetTheme().ScrollbarControlSizeForPart(
-        style_source.StyleRef().Appearance());
-  }
   ScrollbarTheme& theme = GetPageScrollbarTheme();
-  if (theme.UsesOverlayScrollbars())
+  if (theme.UsesOverlayScrollbars() && !should_include_overlay_thickness)
     return 0;
-  int thickness = theme.ScrollbarThickness(scrollbar_size);
-  return GetLayoutBox()
-      ->GetDocument()
-      .GetPage()
-      ->GetChromeClient()
-      .WindowToViewportScalar(thickness);
+  return theme.ScrollbarThickness(ScaleFromDIP(),
+                                  style_source.StyleRef().ScrollbarWidth());
 }
 
 bool PaintLayerScrollableArea::NeedsScrollbarReconstruction() const {
@@ -1396,8 +1581,7 @@ bool PaintLayerScrollableArea::NeedsScrollbarReconstruction() const {
 
   const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
   bool needs_custom =
-      style_source.IsBox() &&
-      style_source.StyleRef().HasPseudoStyle(kPseudoIdScrollbar);
+      style_source.IsBox() && style_source.StyleRef().HasCustomScrollbarStyle();
 
   Scrollbar* scrollbars[] = {HorizontalScrollbar(), VerticalScrollbar()};
 
@@ -1409,14 +1593,12 @@ bool PaintLayerScrollableArea::NeedsScrollbarReconstruction() const {
     if (scrollbar->IsCustomScrollbar() != needs_custom)
       return true;
 
-    if (needs_custom) {
-      DCHECK(scrollbar->IsCustomScrollbar());
-      // We have a custom scrollbar with a stale m_owner.
-      if (ToLayoutScrollbar(scrollbar)->StyleSource()->GetLayoutObject() !=
-          style_source) {
-        return true;
-      }
+    // We have a scrollbar with a stale style source.
+    if (scrollbar->StyleSource() != style_source) {
+      return true;
+    }
 
+    if (needs_custom) {
       // Should use custom scrollbar and nothing should change.
       continue;
     }
@@ -1428,6 +1610,11 @@ bool PaintLayerScrollableArea::NeedsScrollbarReconstruction() const {
 
     if (current_theme != &scrollbar->GetTheme())
       return true;
+
+    EScrollbarWidth current_width = scrollbar->CSSScrollbarWidth();
+    if (current_width != style_source.StyleRef().ScrollbarWidth()) {
+      return true;
+    }
   }
   return false;
 }
@@ -1440,75 +1627,117 @@ void PaintLayerScrollableArea::ComputeScrollbarExistence(
   DCHECK(GetLayoutBox()->GetFrame()->GetSettings());
   if (VisualViewportSuppliesScrollbars() ||
       !CanHaveOverflowScrollbars(*GetLayoutBox()) ||
-      GetLayoutBox()->GetFrame()->GetSettings()->GetHideScrollbars()) {
+      GetLayoutBox()->GetFrame()->GetSettings()->GetHideScrollbars() ||
+      GetLayoutBox()->IsFieldset() || GetLayoutBox()->IsFrameSet() ||
+      GetLayoutBox()->StyleRef().ScrollbarWidth() == EScrollbarWidth::kNone) {
     needs_horizontal_scrollbar = false;
     needs_vertical_scrollbar = false;
     return;
   }
 
-  needs_horizontal_scrollbar = GetLayoutBox()->ScrollsOverflowX();
-  needs_vertical_scrollbar = GetLayoutBox()->ScrollsOverflowY();
+  mojom::blink::ScrollbarMode h_mode = mojom::blink::ScrollbarMode::kAuto;
+  mojom::blink::ScrollbarMode v_mode = mojom::blink::ScrollbarMode::kAuto;
 
-  // Don't add auto scrollbars if the box contents aren't visible.
-  if (GetLayoutBox()->HasAutoHorizontalScrollbar()) {
-    if (option == kForbidAddingAutoBars)
-      needs_horizontal_scrollbar &= HasHorizontalScrollbar();
-    needs_horizontal_scrollbar &=
-        GetLayoutBox()->IsRooted() && HasHorizontalOverflow() &&
-        VisibleContentRect(kIncludeScrollbars).Height();
-  }
+  // First, determine what behavior the scrollbars say they should have.
+  {
+    if (auto* layout_view = DynamicTo<LayoutView>(GetLayoutBox())) {
+      // LayoutView is special as there's various quirks and settings that
+      // style doesn't account for.
+      layout_view->CalculateScrollbarModes(h_mode, v_mode);
+    } else {
+      auto overflow_x = GetLayoutBox()->StyleRef().OverflowX();
+      if (overflow_x == EOverflow::kScroll) {
+        h_mode = mojom::blink::ScrollbarMode::kAlwaysOn;
+      } else if (overflow_x == EOverflow::kHidden ||
+                 overflow_x == EOverflow::kVisible) {
+        h_mode = mojom::blink::ScrollbarMode::kAlwaysOff;
+      }
+
+      auto overflow_y = GetLayoutBox()->StyleRef().OverflowY();
+      if (overflow_y == EOverflow::kScroll) {
+        v_mode = mojom::blink::ScrollbarMode::kAlwaysOn;
+      } else if (overflow_y == EOverflow::kHidden ||
+                 overflow_y == EOverflow::kVisible) {
+        v_mode = mojom::blink::ScrollbarMode::kAlwaysOff;
+      }
+    }
 
-  if (GetLayoutBox()->HasAutoVerticalScrollbar()) {
-    if (option == kForbidAddingAutoBars)
-      needs_vertical_scrollbar &= HasVerticalScrollbar();
-    needs_vertical_scrollbar &= GetLayoutBox()->IsRooted() &&
-                                HasVerticalOverflow() &&
-                                VisibleContentRect(kIncludeScrollbars).Width();
+    // Since overlay scrollbars (the fade-in/out kind, not overflow: overlay)
+    // only appear when scrolling, we don't create them if there isn't overflow
+    // to scroll. Thus, overlay scrollbars can't be "always on". i.e.
+    // |overlay:scroll| behaves like |overlay:auto|.
+    bool has_custom_scrollbar_style = ScrollbarStyleSource(*GetLayoutBox())
+                                          .StyleRef()
+                                          .HasCustomScrollbarStyle();
+    bool will_be_overlay = GetPageScrollbarTheme().UsesOverlayScrollbars() &&
+                           !has_custom_scrollbar_style;
+    if (will_be_overlay) {
+      if (h_mode == mojom::blink::ScrollbarMode::kAlwaysOn)
+        h_mode = mojom::blink::ScrollbarMode::kAuto;
+      if (v_mode == mojom::blink::ScrollbarMode::kAlwaysOn)
+        v_mode = mojom::blink::ScrollbarMode::kAuto;
+    }
   }
 
-  if (GetLayoutBox()->IsLayoutView()) {
-    ScrollbarMode h_mode;
-    ScrollbarMode v_mode;
-    ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
+  // By default, don't make any changes.
+  needs_horizontal_scrollbar = HasHorizontalScrollbar();
+  needs_vertical_scrollbar = HasVerticalScrollbar();
 
-    // Look for the scrollbarModes and reset the needs Horizontal & vertical
-    // Scrollbar values based on scrollbarModes, as during force style change
-    // StyleResolver::styleForDocument returns documentStyle with no overflow
-    // values, due to which we are destroying the scrollbars that were already
-    // present.
-    if (h_mode == kScrollbarAlwaysOn)
+  // If the behavior doesn't depend on overflow or any other information, we
+  // can set it now.
+  {
+    if (h_mode == mojom::blink::ScrollbarMode::kAlwaysOn)
       needs_horizontal_scrollbar = true;
-    else if (h_mode == kScrollbarAlwaysOff)
+    else if (h_mode == mojom::blink::ScrollbarMode::kAlwaysOff)
       needs_horizontal_scrollbar = false;
-    if (v_mode == kScrollbarAlwaysOn)
+
+    if (v_mode == mojom::blink::ScrollbarMode::kAlwaysOn)
       needs_vertical_scrollbar = true;
-    else if (v_mode == kScrollbarAlwaysOff)
+    else if (v_mode == mojom::blink::ScrollbarMode::kAlwaysOff)
       needs_vertical_scrollbar = false;
   }
+
+  // If this is being performed before layout, we want to only update scrollbar
+  // existence if its based on purely style based reasons.
+  if (option == kOverflowIndependent) {
+    return;
+  }
+
+  // If we have clean layout, we can make a decision on any scrollbars that
+  // depend on overflow.
+  {
+    if (h_mode == mojom::blink::ScrollbarMode::kAuto) {
+      // Don't add auto scrollbars if the box contents aren't visible.
+      needs_horizontal_scrollbar =
+          GetLayoutBox()->IsRooted() && HasHorizontalOverflow() &&
+          VisibleContentRect(kIncludeScrollbars).height();
+    }
+    if (v_mode == mojom::blink::ScrollbarMode::kAuto) {
+      needs_vertical_scrollbar = GetLayoutBox()->IsRooted() &&
+                                 HasVerticalOverflow() &&
+                                 VisibleContentRect(kIncludeScrollbars).width();
+    }
+  }
 }
 
 bool PaintLayerScrollableArea::TryRemovingAutoScrollbars(
     const bool& needs_horizontal_scrollbar,
     const bool& needs_vertical_scrollbar) {
-  // If scrollbars are removed but the content size depends on the scrollbars,
-  // additional layouts will be required to size the content. Therefore, only
-  // remove auto scrollbars for the initial layout pass.
-  DCHECK(!in_overflow_relayout_);
-
   if (!needs_horizontal_scrollbar && !needs_vertical_scrollbar)
     return false;
 
-  if (GetLayoutBox()->IsLayoutView()) {
-    ScrollbarMode h_mode;
-    ScrollbarMode v_mode;
-    ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
-    if (h_mode != kScrollbarAuto || v_mode != kScrollbarAuto)
+  if (auto* layout_view = DynamicTo<LayoutView>(GetLayoutBox())) {
+    mojom::blink::ScrollbarMode h_mode;
+    mojom::blink::ScrollbarMode v_mode;
+    layout_view->CalculateScrollbarModes(h_mode, v_mode);
+    if (h_mode != mojom::blink::ScrollbarMode::kAuto ||
+        v_mode != mojom::blink::ScrollbarMode::kAuto)
       return false;
 
-    IntSize visible_size_with_scrollbars =
-        VisibleContentRect(kIncludeScrollbars).Size();
-    if (ScrollWidth() <= visible_size_with_scrollbars.Width() &&
-        ScrollHeight() <= visible_size_with_scrollbars.Height()) {
+    gfx::Size visible_size_with_scrollbars =
+        VisibleContentRect(kIncludeScrollbars).size();
+    if (ScrollWidth() <= visible_size_with_scrollbars.width() &&
+        ScrollHeight() <= visible_size_with_scrollbars.height()) {
       return true;
     }
   } else {
@@ -1516,10 +1745,10 @@ bool PaintLayerScrollableArea::TryRemovingAutoScrollbars(
         !GetLayoutBox()->HasAutoHorizontalScrollbar())
       return false;
 
-    LayoutSize client_size_with_scrollbars =
-        LayoutContentRect(kIncludeScrollbars).Size();
-    if (ScrollWidth() <= client_size_with_scrollbars.Width() &&
-        ScrollHeight() <= client_size_with_scrollbars.Height()) {
+    PhysicalSize client_size_with_scrollbars =
+        LayoutContentRect(kIncludeScrollbars).size;
+    if (ScrollWidth() <= client_size_with_scrollbars.width &&
+        ScrollHeight() <= client_size_with_scrollbars.height) {
       return true;
     }
   }
@@ -1527,12 +1756,38 @@ bool PaintLayerScrollableArea::TryRemovingAutoScrollbars(
   return false;
 }
 
-bool PaintLayerScrollableArea::SetHasHorizontalScrollbar(bool has_scrollbar) {
-  if (FreezeScrollbarsScope::ScrollbarsAreFrozen())
-    return false;
+void PaintLayerScrollableArea::RemoveScrollbarsForReconstruction() {
+  if (!HasHorizontalScrollbar() && !HasVerticalScrollbar())
+    return;
+  if (HasHorizontalScrollbar()) {
+    SetScrollbarNeedsPaintInvalidation(kHorizontalScrollbar);
+    scrollbar_manager_.SetHasHorizontalScrollbar(false);
+  }
+  if (HasVerticalScrollbar()) {
+    SetScrollbarNeedsPaintInvalidation(kVerticalScrollbar);
+    scrollbar_manager_.SetHasVerticalScrollbar(false);
+  }
+  UpdateScrollCornerStyle();
+  UpdateScrollOrigin();
+
+  // Force an update since we know the scrollbars have changed things.
+  if (GetLayoutBox()->GetDocument().HasAnnotatedRegions())
+    GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);
+}
+
+CompositorElementId PaintLayerScrollableArea::GetScrollCornerElementId() const {
+  CompositorElementId scrollable_element_id = GetScrollElementId();
+  DCHECK(scrollable_element_id);
+  return CompositorElementIdWithNamespace(
+      scrollable_element_id, CompositorElementIdNamespace::kScrollCorner);
+}
+
+void PaintLayerScrollableArea::SetHasHorizontalScrollbar(bool has_scrollbar) {
+  if (IsHorizontalScrollbarFrozen())
+    return;
 
   if (has_scrollbar == HasHorizontalScrollbar())
-    return false;
+    return;
 
   SetScrollbarNeedsPaintInvalidation(kHorizontalScrollbar);
 
@@ -1552,15 +1807,21 @@ bool PaintLayerScrollableArea::SetHasHorizontalScrollbar(bool has_scrollbar) {
   // Force an update since we know the scrollbars have changed things.
   if (GetLayoutBox()->GetDocument().HasAnnotatedRegions())
     GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);
-  return true;
 }
 
-bool PaintLayerScrollableArea::SetHasVerticalScrollbar(bool has_scrollbar) {
-  if (FreezeScrollbarsScope::ScrollbarsAreFrozen())
-    return false;
+void PaintLayerScrollableArea::SetHasVerticalScrollbar(bool has_scrollbar) {
+  if (IsVerticalScrollbarFrozen())
+    return;
+
+  if (GetLayoutBox()->GetDocument().IsVerticalScrollEnforced()) {
+    // When the policy is enforced the contents of document cannot be scrolled.
+    // This would make rendering a scrollbar look strange
+    // (https://crbug.com/898151).
+    return;
+  }
 
   if (has_scrollbar == HasVerticalScrollbar())
-    return false;
+    return;
 
   SetScrollbarNeedsPaintInvalidation(kVerticalScrollbar);
 
@@ -1580,21 +1841,17 @@ bool PaintLayerScrollableArea::SetHasVerticalScrollbar(bool has_scrollbar) {
   // Force an update since we know the scrollbars have changed things.
   if (GetLayoutBox()->GetDocument().HasAnnotatedRegions())
     GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);
-  return true;
 }
 
 int PaintLayerScrollableArea::VerticalScrollbarWidth(
     OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
   if (!HasVerticalScrollbar())
     return 0;
-  if (overlay_scrollbar_clip_behavior ==
-          kIgnorePlatformAndCSSOverlayScrollbarSize &&
-      GetLayoutBox()->Style()->OverflowY() == EOverflow::kOverlay) {
+  if (overlay_scrollbar_clip_behavior == kIgnoreOverlayScrollbarSize &&
+      GetLayoutBox()->StyleRef().OverflowY() == EOverflow::kOverlay) {
     return 0;
   }
-  if ((overlay_scrollbar_clip_behavior == kIgnorePlatformOverlayScrollbarSize ||
-       overlay_scrollbar_clip_behavior ==
-           kIgnorePlatformAndCSSOverlayScrollbarSize ||
+  if ((overlay_scrollbar_clip_behavior == kIgnoreOverlayScrollbarSize ||
        !VerticalScrollbar()->ShouldParticipateInHitTesting()) &&
       VerticalScrollbar()->IsOverlayScrollbar()) {
     return 0;
@@ -1606,14 +1863,11 @@ int PaintLayerScrollableArea::HorizontalScrollbarHeight(
     OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
   if (!HasHorizontalScrollbar())
     return 0;
-  if (overlay_scrollbar_clip_behavior ==
-          kIgnorePlatformAndCSSOverlayScrollbarSize &&
-      GetLayoutBox()->Style()->OverflowX() == EOverflow::kOverlay) {
+  if (overlay_scrollbar_clip_behavior == kIgnoreOverlayScrollbarSize &&
+      GetLayoutBox()->StyleRef().OverflowX() == EOverflow::kOverlay) {
     return 0;
   }
-  if ((overlay_scrollbar_clip_behavior == kIgnorePlatformOverlayScrollbarSize ||
-       overlay_scrollbar_clip_behavior ==
-           kIgnorePlatformAndCSSOverlayScrollbarSize ||
+  if ((overlay_scrollbar_clip_behavior == kIgnoreOverlayScrollbarSize ||
        !HorizontalScrollbar()->ShouldParticipateInHitTesting()) &&
       HorizontalScrollbar()->IsOverlayScrollbar()) {
     return 0;
@@ -1621,65 +1875,178 @@ int PaintLayerScrollableArea::HorizontalScrollbarHeight(
   return HorizontalScrollbar()->ScrollbarThickness();
 }
 
-void PaintLayerScrollableArea::SnapAfterScrollbarScrolling(
-    ScrollbarOrientation orientation) {
-  SnapCoordinator* snap_coordinator =
-      GetLayoutBox()->GetDocument().GetSnapCoordinator();
-  if (!snap_coordinator)
-    return;
-  snap_coordinator->PerformSnapping(*GetLayoutBox(),
-                                    orientation == kHorizontalScrollbar,
-                                    orientation == kVerticalScrollbar);
+const cc::SnapContainerData* PaintLayerScrollableArea::GetSnapContainerData()
+    const {
+  return RareData() && RareData()->snap_container_data_
+             ? &RareData()->snap_container_data_.value()
+             : nullptr;
 }
 
-void PaintLayerScrollableArea::PositionOverflowControls() {
-  if (!HasScrollbar() && !GetLayoutBox()->CanResize())
+void PaintLayerScrollableArea::SetSnapContainerData(
+    absl::optional<cc::SnapContainerData> data) {
+  EnsureRareData().snap_container_data_ = data;
+}
+
+bool PaintLayerScrollableArea::SetTargetSnapAreaElementIds(
+    cc::TargetSnapAreaElementIds snap_target_ids) {
+  if (!RareData() || !RareData()->snap_container_data_)
+    return false;
+  if (RareData()->snap_container_data_.value().SetTargetSnapAreaElementIds(
+          snap_target_ids)) {
+    GetLayoutBox()->SetNeedsPaintPropertyUpdate();
+    return true;
+  }
+  return false;
+}
+
+bool PaintLayerScrollableArea::SnapContainerDataNeedsUpdate() const {
+  return RareData() ? RareData()->snap_container_data_needs_update_ : false;
+}
+
+void PaintLayerScrollableArea::SetSnapContainerDataNeedsUpdate(
+    bool needs_update) {
+  DCHECK(!RuntimeEnabledFeatures::LayoutNewSnapLogicEnabled());
+  EnsureRareData().snap_container_data_needs_update_ = needs_update;
+  if (!needs_update)
     return;
+  GetLayoutBox()
+      ->GetDocument()
+      .GetSnapCoordinator()
+      .SetAnySnapContainerDataNeedsUpdate(true);
+}
 
-  const IntRect border_box =
-      GetLayoutBox()->PixelSnappedBorderBoxRect(layer_->SubpixelAccumulation());
+absl::optional<gfx::PointF>
+PaintLayerScrollableArea::GetSnapPositionAndSetTarget(
+    const cc::SnapSelectionStrategy& strategy) {
+  if (!RareData() || !RareData()->snap_container_data_)
+    return absl::nullopt;
 
-  if (Scrollbar* vertical_scrollbar = VerticalScrollbar())
-    vertical_scrollbar->SetFrameRect(RectForVerticalScrollbar(border_box));
+  cc::SnapContainerData& data = RareData()->snap_container_data_.value();
+  if (!data.size())
+    return absl::nullopt;
 
-  if (Scrollbar* horizontal_scrollbar = HorizontalScrollbar())
-    horizontal_scrollbar->SetFrameRect(RectForHorizontalScrollbar(border_box));
+  // If the document has a focused element that is coincident with the snap
+  // target, update the snap target to point to the focused element. This
+  // ensures that we stay snapped to the focused element after a relayout.
+  // TODO(crbug.com/1199911): If the focused element is not a snap target but
+  // has an ancestor that is, perhaps the rule should be applied for the
+  // ancestor element.
+  CompositorElementId active_element_id = CompositorElementId();
+  if (auto* active_element = GetDocument()->ActiveElement()) {
+    active_element_id =
+        CompositorElementIdFromDOMNodeId(active_element->GetDomNodeId());
+  }
 
-  const IntRect& scroll_corner = ScrollCornerRect();
-  if (scroll_corner_)
-    scroll_corner_->SetFrameRect(LayoutRect(scroll_corner));
+  absl::optional<gfx::PointF> snap_point;
+  cc::SnapPositionData snap =
+      data.FindSnapPosition(strategy, active_element_id);
+  if (snap.type != cc::SnapPositionData::Type::kNone) {
+    snap_point = gfx::PointF(snap.position.x(), snap.position.y());
+  }
 
-  if (resizer_)
-    resizer_->SetFrameRect(
-        LayoutRect(ResizerCornerRect(border_box, kResizerForPointer)));
+  if (data.SetTargetSnapAreaElementIds(snap.target_element_ids)) {
+    GetLayoutBox()->SetNeedsPaintPropertyUpdate();
+  }
 
-  // FIXME, this should eventually be removed, once we are certain that
-  // composited controls get correctly positioned on a compositor update. For
-  // now, conservatively leaving this unchanged.
-  if (Layer()->HasCompositedLayerMapping())
-    Layer()->GetCompositedLayerMapping()->PositionOverflowControlsLayers();
+  return snap_point;
 }
 
-void PaintLayerScrollableArea::UpdateScrollCornerStyle() {
-  if (!scroll_corner_ && !HasScrollbar())
-    return;
-  if (!scroll_corner_ && HasOverlayScrollbars())
+bool PaintLayerScrollableArea::HasOverflowControls() const {
+  // We do not need to check for ScrollCorner because it only exists iff there
+  // are scrollbars, see: |ScrollCornerRect| and |UpdateScrollCornerStyle|.
+  DCHECK(!ScrollCorner() || HasScrollbar());
+  return HasScrollbar() || GetLayoutBox()->CanResize();
+}
+
+bool PaintLayerScrollableArea::HasOverlayOverflowControls() const {
+  if (HasOverlayScrollbars())
+    return true;
+  if (!HasScrollbar() && GetLayoutBox()->CanResize())
+    return true;
+  if (GetLayoutBox()->StyleRef().OverflowX() == EOverflow::kOverlay ||
+      GetLayoutBox()->StyleRef().OverflowY() == EOverflow::kOverlay)
+    return true;
+  return false;
+}
+
+bool PaintLayerScrollableArea::NeedsScrollCorner() const {
+  // This is one of the differences between platform overlay scrollbars and
+  // overflow:overlay scrollbars: the former don't need scroll corner, while
+  // the latter do. HasOverlayScrollbars doesn't include overflow:overlay.
+  return HasScrollbar() && !HasOverlayScrollbars();
+}
+
+bool PaintLayerScrollableArea::ShouldOverflowControlsPaintAsOverlay() const {
+  if (HasOverlayOverflowControls())
+    return true;
+
+  // Frame and global root scroller (which can be a non-frame) scrollbars and
+  // corner also paint as overlay so that they appear on top of all content
+  // within their viewport. This is important for global root scrollers since
+  // these scrollbars' transform state is
+  // VisualViewport::TransformNodeForViewportScrollbars().
+  return layer_->IsRootLayer() ||
+         (GetLayoutBox() && GetLayoutBox()->IsGlobalRootScroller());
+}
+
+void PaintLayerScrollableArea::PositionOverflowControls() {
+  if (!HasOverflowControls())
     return;
 
+  if (Scrollbar* vertical_scrollbar = VerticalScrollbar()) {
+    vertical_scrollbar->SetFrameRect(RectForVerticalScrollbar());
+    if (auto* custom_scrollbar = DynamicTo<CustomScrollbar>(vertical_scrollbar))
+      custom_scrollbar->PositionScrollbarParts();
+  }
+
+  if (Scrollbar* horizontal_scrollbar = HorizontalScrollbar()) {
+    horizontal_scrollbar->SetFrameRect(RectForHorizontalScrollbar());
+    if (auto* custom_scrollbar =
+            DynamicTo<CustomScrollbar>(horizontal_scrollbar))
+      custom_scrollbar->PositionScrollbarParts();
+  }
+
+  if (scroll_corner_) {
+    PhysicalRect rect(ScrollCornerRect());
+    scroll_corner_->SetOverriddenSize(rect.size);
+    // TODO(crbug.com/1020913): This should be part of PaintPropertyTreeBuilder
+    // when we support subpixel layout of overflow controls.
+    scroll_corner_->GetMutableForPainting().FirstFragment().SetPaintOffset(
+        rect.offset);
+  }
+
+  if (resizer_) {
+    PhysicalRect rect(ResizerCornerRect(kResizerForPointer));
+    resizer_->SetOverriddenSize(rect.size);
+    // TODO(crbug.com/1020913): This should be part of PaintPropertyTreeBuilder
+    // when we support subpixel layout of overflow controls.
+    resizer_->GetMutableForPainting().FirstFragment().SetPaintOffset(
+        rect.offset);
+  }
+}
+
+void PaintLayerScrollableArea::UpdateScrollCornerStyle() {
+  if (!NeedsScrollCorner()) {
+    if (scroll_corner_) {
+      scroll_corner_->Destroy();
+      scroll_corner_ = nullptr;
+    }
+    return;
+  }
   const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
-  scoped_refptr<ComputedStyle> corner =
-      GetLayoutBox()->HasOverflowClip()
-          ? style_source.GetUncachedPseudoStyle(
-                PseudoStyleRequest(kPseudoIdScrollbarCorner),
-                style_source.Style())
-          : scoped_refptr<ComputedStyle>(nullptr);
+  bool uses_standard_scrollbar_style =
+      style_source.StyleRef().UsesStandardScrollbarStyle();
+  const ComputedStyle* corner =
+      (GetLayoutBox()->IsScrollContainer() && !uses_standard_scrollbar_style)
+          ? style_source.GetUncachedPseudoElementStyle(
+                StyleRequest(kPseudoIdScrollbarCorner, style_source.Style()))
+          : nullptr;
   if (corner) {
     if (!scroll_corner_) {
-      scroll_corner_ = LayoutScrollbarPart::CreateAnonymous(
+      scroll_corner_ = LayoutCustomScrollbarPart::CreateAnonymous(
           &GetLayoutBox()->GetDocument(), this);
-      scroll_corner_->SetDangerousOneWayParent(GetLayoutBox());
     }
-    scroll_corner_->SetStyleWithWritingModeOfParent(std::move(corner));
+    scroll_corner_->SetStyle(std::move(corner));
   } else if (scroll_corner_) {
     scroll_corner_->Destroy();
     scroll_corner_ = nullptr;
@@ -1688,49 +2055,47 @@ void PaintLayerScrollableArea::UpdateScrollCornerStyle() {
 
 bool PaintLayerScrollableArea::HitTestOverflowControls(
     HitTestResult& result,
-    const IntPoint& local_point) {
-  if (!HasScrollbar() && !GetLayoutBox()->CanResize())
+    const gfx::Point& local_point) {
+  if (!HasOverflowControls())
     return false;
 
-  IntRect resize_control_rect;
-  if (GetLayoutBox()->Style()->Resize() != EResize::kNone) {
-    resize_control_rect =
-        ResizerCornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
-                              Layer()->SubpixelAccumulation()),
-                          kResizerForPointer);
-    if (resize_control_rect.Contains(local_point))
+  gfx::Rect resize_control_rect;
+  if (GetLayoutBox()->CanResize()) {
+    resize_control_rect = ResizerCornerRect(kResizerForPointer);
+    if (resize_control_rect.Contains(local_point)) {
+      result.SetIsOverResizer(true);
       return true;
+    }
   }
-  int resize_control_size = max(resize_control_rect.Height(), 0);
+  int resize_control_size = max(resize_control_rect.height(), 0);
 
-  IntRect visible_rect = VisibleContentRect(kIncludeScrollbars);
+  gfx::Rect visible_rect = VisibleContentRect(kIncludeScrollbars);
 
   if (HasVerticalScrollbar() &&
       VerticalScrollbar()->ShouldParticipateInHitTesting()) {
-    LayoutRect v_bar_rect(
-        VerticalScrollbarStart(0, Layer()->PixelSnappedSize().Width()),
-        GetLayoutBox()->BorderTop().ToInt(),
-        VerticalScrollbar()->ScrollbarThickness(),
-        visible_rect.Height() -
-            (HasHorizontalScrollbar()
-                 ? HorizontalScrollbar()->ScrollbarThickness()
-                 : resize_control_size));
+    gfx::Rect v_bar_rect(VerticalScrollbarStart(),
+                         GetLayoutBox()->BorderTop().ToInt(),
+                         VerticalScrollbar()->ScrollbarThickness(),
+                         visible_rect.height() -
+                             (HasHorizontalScrollbar()
+                                  ? HorizontalScrollbar()->ScrollbarThickness()
+                                  : resize_control_size));
     if (v_bar_rect.Contains(local_point)) {
       result.SetScrollbar(VerticalScrollbar());
       return true;
     }
   }
 
-  resize_control_size = max(resize_control_rect.Width(), 0);
+  resize_control_size = max(resize_control_rect.width(), 0);
   if (HasHorizontalScrollbar() &&
       HorizontalScrollbar()->ShouldParticipateInHitTesting()) {
     // TODO(crbug.com/638981): Are the conversions to int intentional?
     int h_scrollbar_thickness = HorizontalScrollbar()->ScrollbarThickness();
-    LayoutRect h_bar_rect(
-        HorizontalScrollbarStart(0),
-        GetLayoutBox()->BorderTop().ToInt() + visible_rect.Height() -
+    gfx::Rect h_bar_rect(
+        HorizontalScrollbarStart(),
+        GetLayoutBox()->BorderTop().ToInt() + visible_rect.height() -
             h_scrollbar_thickness,
-        visible_rect.Width() - (HasVerticalScrollbar()
+        visible_rect.width() - (HasVerticalScrollbar()
                                     ? VerticalScrollbar()->ScrollbarThickness()
                                     : resize_control_size),
         h_scrollbar_thickness);
@@ -1746,332 +2111,327 @@ bool PaintLayerScrollableArea::HitTestOverflowControls(
   return false;
 }
 
-IntRect PaintLayerScrollableArea::ResizerCornerRect(
-    const IntRect& bounds,
+gfx::Rect PaintLayerScrollableArea::ResizerCornerRect(
     ResizerHitTestType resizer_hit_test_type) const {
-  if (GetLayoutBox()->Style()->Resize() == EResize::kNone)
-    return IntRect();
-  IntRect corner = CornerRect(bounds);
+  if (!GetLayoutBox()->CanResize())
+    return gfx::Rect();
+  gfx::Rect corner = CornerRect();
 
   if (resizer_hit_test_type == kResizerForTouch) {
     // We make the resizer virtually larger for touch hit testing. With the
     // expanding ratio k = ResizerControlExpandRatioForTouch, we first move
     // the resizer rect (of width w & height h), by (-w * (k-1), -h * (k-1)),
     // then expand the rect by new_w/h = w/h * k.
-    int expand_ratio = kResizerControlExpandRatioForTouch - 1;
-    corner.Move(-corner.Width() * expand_ratio,
-                -corner.Height() * expand_ratio);
-    corner.Expand(corner.Width() * expand_ratio,
-                  corner.Height() * expand_ratio);
+    corner.Offset(-corner.width() * (kResizerControlExpandRatioForTouch - 1),
+                  -corner.height() * (kResizerControlExpandRatioForTouch - 1));
+    corner.set_size(
+        gfx::Size(corner.width() * kResizerControlExpandRatioForTouch,
+                  corner.height() * kResizerControlExpandRatioForTouch));
   }
 
   return corner;
 }
 
-IntRect PaintLayerScrollableArea::ScrollCornerAndResizerRect() const {
-  IntRect scroll_corner_and_resizer = ScrollCornerRect();
-  if (scroll_corner_and_resizer.IsEmpty()) {
-    scroll_corner_and_resizer =
-        ResizerCornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
-                              Layer()->SubpixelAccumulation()),
-                          kResizerForPointer);
-  }
+gfx::Rect PaintLayerScrollableArea::ScrollCornerAndResizerRect() const {
+  gfx::Rect scroll_corner_and_resizer = ScrollCornerRect();
+  if (scroll_corner_and_resizer.IsEmpty())
+    return ResizerCornerRect(kResizerForPointer);
   return scroll_corner_and_resizer;
 }
 
-bool PaintLayerScrollableArea::IsPointInResizeControl(
-    const IntPoint& absolute_point,
+bool PaintLayerScrollableArea::IsAbsolutePointInResizeControl(
+    const gfx::Point& absolute_point,
     ResizerHitTestType resizer_hit_test_type) const {
-  if (!GetLayoutBox()->CanResize())
+  if (GetLayoutBox()->StyleRef().Visibility() != EVisibility::kVisible ||
+      !GetLayoutBox()->CanResize())
     return false;
 
-  IntPoint local_point = RoundedIntPoint(GetLayoutBox()->AbsoluteToLocal(
-      FloatPoint(absolute_point), kUseTransforms));
-  IntRect local_bounds(IntPoint(), Layer()->PixelSnappedSize());
-  return ResizerCornerRect(local_bounds, resizer_hit_test_type)
-      .Contains(local_point);
+  gfx::Point local_point = ToRoundedPoint(
+      GetLayoutBox()->AbsoluteToLocalPoint(PhysicalOffset(absolute_point)));
+  return ResizerCornerRect(resizer_hit_test_type).Contains(local_point);
 }
 
-bool PaintLayerScrollableArea::HitTestResizerInFragments(
-    const PaintLayerFragments& layer_fragments,
-    const HitTestLocation& hit_test_location) const {
-  if (!GetLayoutBox()->CanResize())
-    return false;
-
-  if (layer_fragments.IsEmpty())
+bool PaintLayerScrollableArea::IsLocalPointInResizeControl(
+    const gfx::Point& local_point,
+    ResizerHitTestType resizer_hit_test_type) const {
+  if (GetLayoutBox()->StyleRef().Visibility() != EVisibility::kVisible ||
+      !GetLayoutBox()->CanResize())
     return false;
 
-  for (int i = layer_fragments.size() - 1; i >= 0; --i) {
-    const PaintLayerFragment& fragment = layer_fragments.at(i);
-    if (fragment.background_rect.Intersects(hit_test_location) &&
-        ResizerCornerRect(PixelSnappedIntRect(fragment.layer_bounds),
-                          kResizerForPointer)
-            .Contains(hit_test_location.RoundedPoint()))
-      return true;
-  }
-
-  return false;
-}
-
-void PaintLayerScrollableArea::UpdateResizerAreaSet() {
-  LocalFrame* frame = GetLayoutBox()->GetFrame();
-  if (!frame)
-    return;
-  LocalFrameView* frame_view = frame->View();
-  if (!frame_view)
-    return;
-  if (GetLayoutBox()->CanResize())
-    frame_view->AddResizerArea(*GetLayoutBox());
-  else
-    frame_view->RemoveResizerArea(*GetLayoutBox());
+  return ResizerCornerRect(resizer_hit_test_type).Contains(local_point);
 }
 
 void PaintLayerScrollableArea::UpdateResizerStyle(
     const ComputedStyle* old_style) {
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() && old_style &&
-      old_style->Resize() != GetLayoutBox()->StyleRef().Resize()) {
-    // Invalidate the composited scroll corner layer on resize style change.
-    if (auto* graphics_layer = LayerForScrollCorner())
-      graphics_layer->SetNeedsDisplay();
-  }
-
-  if (!resizer_ && !GetLayoutBox()->CanResize())
+  // Change of resizer status affects HasOverlayOverflowControls(). Invalid
+  // z-order lists to refresh overflow control painting order.
+  bool had_resizer = old_style && old_style->HasResize();
+  bool needs_resizer = GetLayoutBox()->CanResize();
+  if (had_resizer != needs_resizer)
+    layer_->DirtyStackingContextZOrderLists();
+
+  if (!resizer_ && !needs_resizer)
     return;
 
+  // Update custom resizer style.
   const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
-  scoped_refptr<ComputedStyle> resizer =
-      GetLayoutBox()->HasOverflowClip()
-          ? style_source.GetUncachedPseudoStyle(
-                PseudoStyleRequest(kPseudoIdResizer), style_source.Style())
-          : scoped_refptr<ComputedStyle>(nullptr);
+  const ComputedStyle* resizer =
+      GetLayoutBox()->IsScrollContainer()
+          ? style_source.GetUncachedPseudoElementStyle(
+                StyleRequest(kPseudoIdResizer, style_source.Style()))
+          : nullptr;
   if (resizer) {
     if (!resizer_) {
-      resizer_ = LayoutScrollbarPart::CreateAnonymous(
+      resizer_ = LayoutCustomScrollbarPart::CreateAnonymous(
           &GetLayoutBox()->GetDocument(), this);
-      resizer_->SetDangerousOneWayParent(GetLayoutBox());
     }
-    resizer_->SetStyleWithWritingModeOfParent(std::move(resizer));
+    resizer_->SetStyle(std::move(resizer));
   } else if (resizer_) {
     resizer_->Destroy();
     resizer_ = nullptr;
   }
 }
 
-void PaintLayerScrollableArea::InvalidateAllStickyConstraints() {
-  if (PaintLayerScrollableAreaRareData* d = RareData()) {
-    for (PaintLayer* sticky_layer : d->sticky_constraints_map_.Keys()) {
-      if (sticky_layer->GetLayoutObject().Style()->GetPosition() ==
-          EPosition::kSticky)
-        sticky_layer->SetNeedsCompositingInputsUpdate();
+void PaintLayerScrollableArea::EnqueueForSnapUpdateIfNeeded() {
+  auto* box = GetLayoutBox();
+  // Not all PLSAs are scroll containers!
+  if (!box->IsScrollContainer()) {
+    return;
+  }
+
+  // Enqueue ourselves for a snap update if we have any snap-areas, or if we
+  // currently have snap-data (and it needs to be cleared).
+  for (const auto& fragment : box->PhysicalFragments()) {
+    if (fragment.SnapAreas() || GetSnapContainerData()) {
+      box->GetFrameView()->AddPendingSnapUpdate(this);
+      break;
     }
-    d->sticky_constraints_map_.clear();
   }
 }
 
-void PaintLayerScrollableArea::InvalidateStickyConstraintsFor(
-    PaintLayer* layer,
-    bool needs_compositing_update) {
-  if (PaintLayerScrollableAreaRareData* d = RareData()) {
-    d->sticky_constraints_map_.erase(layer);
-    if (needs_compositing_update &&
-        layer->GetLayoutObject().Style()->HasStickyConstrainedPosition())
-      layer->SetNeedsCompositingInputsUpdate();
-  }
+void PaintLayerScrollableArea::AddStickyLayer(PaintLayer* layer) {
+  UseCounter::Count(GetLayoutBox()->GetDocument(), WebFeature::kPositionSticky);
+  EnsureRareData().sticky_layers_.insert(layer);
 }
 
-bool PaintLayerScrollableArea::HasStickyDescendants() const {
-  if (const PaintLayerScrollableAreaRareData* d = RareData())
-    return !d->sticky_constraints_map_.IsEmpty();
-  return false;
+void PaintLayerScrollableArea::UpdateAllStickyConstraints() {
+  // TODO(ikilpatrick): Change `UpdateStickyPositionConstraints` return the
+  // sticky constraints object instead of performing a mutation.
+  for (const auto& fragment : GetLayoutBox()->PhysicalFragments()) {
+    if (auto* sticky_descendants = fragment.StickyDescendants()) {
+      for (auto& sticky_descendant : *sticky_descendants) {
+        sticky_descendant->UpdateStickyPositionConstraints();
+      }
+    }
+  }
 }
 
-bool PaintLayerScrollableArea::HasNonCompositedStickyDescendants() const {
-  if (const PaintLayerScrollableAreaRareData* d = RareData()) {
-    for (const PaintLayer* sticky_layer : d->sticky_constraints_map_.Keys()) {
-      if (sticky_layer->GetLayoutObject().IsSlowRepaintConstrainedObject())
-        return true;
+void PaintLayerScrollableArea::InvalidateAllStickyConstraints() {
+  // Don't clear StickyConstraints for each LayoutObject of each layer in
+  // sticky_layers_ because sticky_layers_ may contain stale pointers.
+  // LayoutBoxModelObject::UpdateStickyPositionConstraints() will check both
+  // HasStickyLayer() of its containing scrollable area and its
+  // StickyConstraints() to see if its sticky constraints need update.
+  if (rare_data_)
+    rare_data_->sticky_layers_.clear();
+
+  if (!RuntimeEnabledFeatures::LayoutNewStickyLogicEnabled()) {
+    return;
+  }
+
+  // Enqueue ourselves for a sticky update if we have any sticky descendants.
+  auto* box = GetLayoutBox();
+  for (const auto& fragment : box->PhysicalFragments()) {
+    if (fragment.StickyDescendants()) {
+      box->GetFrameView()->AddPendingStickyUpdate(this);
+      break;
     }
   }
-  return false;
 }
 
 void PaintLayerScrollableArea::InvalidatePaintForStickyDescendants() {
+  // If this is called during layout, sticky_layers_ may contain stale pointers.
+  // Return because we'll InvalidateAllStickyConstraints(), and we'll
+  // SetNeedsPaintPropertyUpdate() when updating sticky constraints.
+  if (GetLayoutBox()->NeedsLayout())
+    return;
+
   if (PaintLayerScrollableAreaRareData* d = RareData()) {
-    for (PaintLayer* sticky_layer : d->sticky_constraints_map_.Keys()) {
-      sticky_layer->GetLayoutObject()
-          .SetShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
+    for (PaintLayer* sticky_layer : d->sticky_layers_) {
+      auto& object = sticky_layer->GetLayoutObject();
+      object.SetNeedsPaintPropertyUpdate();
+      DCHECK(object.StickyConstraints());
+      object.StickyConstraints()->ComputeStickyOffset(ScrollPosition());
     }
   }
 }
 
-IntSize PaintLayerScrollableArea::OffsetFromResizeCorner(
-    const IntPoint& absolute_point) const {
+gfx::Vector2d PaintLayerScrollableArea::OffsetFromResizeCorner(
+    const gfx::Point& absolute_point) const {
   // Currently the resize corner is either the bottom right corner or the bottom
   // left corner.
   // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be
   // the case?
-  IntSize element_size = Layer()->PixelSnappedSize();
+  gfx::Size element_size = PixelSnappedBorderBoxSize();
   if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
-    element_size.SetWidth(0);
-  IntPoint resizer_point = IntPoint(element_size);
-  IntPoint local_point = RoundedIntPoint(GetLayoutBox()->AbsoluteToLocal(
-      FloatPoint(absolute_point), kUseTransforms));
-  return local_point - resizer_point;
-}
-
-LayoutSize PaintLayerScrollableArea::MinimumSizeForResizing(float zoom_factor) {
-  LayoutUnit min_width =
-      MinimumValueForLength(GetLayoutBox()->StyleRef().MinWidth(),
-                            GetLayoutBox()->ContainingBlock()->Size().Width());
-  LayoutUnit min_height =
-      MinimumValueForLength(GetLayoutBox()->StyleRef().MinHeight(),
-                            GetLayoutBox()->ContainingBlock()->Size().Height());
-  min_width = std::max(LayoutUnit(min_width / zoom_factor),
-                       LayoutUnit(kDefaultMinimumWidthForResizing));
-  min_height = std::max(LayoutUnit(min_height / zoom_factor),
-                        LayoutUnit(kDefaultMinimumHeightForResizing));
-  return LayoutSize(min_width, min_height);
-}
-
-void PaintLayerScrollableArea::Resize(const IntPoint& pos,
-                                      const LayoutSize& old_offset) {
+    element_size.set_width(0);
+  gfx::Point local_point = ToRoundedPoint(
+      GetLayoutBox()->AbsoluteToLocalPoint(PhysicalOffset(absolute_point)));
+  return gfx::Vector2d(local_point.x() - element_size.width(),
+                       local_point.y() - element_size.height());
+}
+
+void PaintLayerScrollableArea::Resize(const gfx::Point& pos,
+                                      const gfx::Vector2d& old_offset) {
   // FIXME: This should be possible on generated content but is not right now.
   if (!InResizeMode() || !GetLayoutBox()->CanResize() ||
       !GetLayoutBox()->GetNode())
     return;
 
   DCHECK(GetLayoutBox()->GetNode()->IsElementNode());
-  Element* element = ToElement(GetLayoutBox()->GetNode());
+  auto* element = To<Element>(GetLayoutBox()->GetNode());
 
   Document& document = element->GetDocument();
 
-  float zoom_factor = GetLayoutBox()->Style()->EffectiveZoom();
+  float zoom_factor = GetLayoutBox()->StyleRef().EffectiveZoom();
 
-  IntSize new_offset =
+  gfx::Vector2d new_offset =
       OffsetFromResizeCorner(document.View()->ConvertFromRootFrame(pos));
-  new_offset.SetWidth(new_offset.Width() / zoom_factor);
-  new_offset.SetHeight(new_offset.Height() / zoom_factor);
+  new_offset.set_x(new_offset.x() / zoom_factor);
+  new_offset.set_y(new_offset.y() / zoom_factor);
 
-  LayoutSize current_size = GetLayoutBox()->Size();
+  PhysicalSize current_size = GetLayoutBox()->Size();
   current_size.Scale(1 / zoom_factor);
 
-  LayoutSize adjusted_old_offset = LayoutSize(
-      old_offset.Width() / zoom_factor, old_offset.Height() / zoom_factor);
+  PhysicalOffset adjusted_old_offset(old_offset);
+  adjusted_old_offset.Scale(1.f / zoom_factor);
   if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
-    new_offset.SetWidth(-new_offset.Width());
-    adjusted_old_offset.SetWidth(-adjusted_old_offset.Width());
+    new_offset.set_x(-new_offset.x());
+    adjusted_old_offset.left = -adjusted_old_offset.left;
   }
 
-  LayoutSize difference((current_size + new_offset - adjusted_old_offset)
-                            .ExpandedTo(MinimumSizeForResizing(zoom_factor)) -
-                        current_size);
+  PhysicalOffset offset = PhysicalOffset(new_offset) - adjusted_old_offset;
+  PhysicalSize new_size(current_size.width + offset.left,
+                        current_size.height + offset.top);
+
+  // Ensure the new size is at least as large as the resize corner.
+  gfx::SizeF corner_rect(CornerRect().size());
+  corner_rect.InvScale(zoom_factor);
+  new_size.width = std::max(new_size.width, LayoutUnit(corner_rect.width()));
+  new_size.height = std::max(new_size.height, LayoutUnit(corner_rect.height()));
+
+  PhysicalSize difference(new_size - current_size);
 
   bool is_box_sizing_border =
-      GetLayoutBox()->Style()->BoxSizing() == EBoxSizing::kBorderBox;
-
-  EResize resize = GetLayoutBox()->Style()->Resize();
-  if (resize != EResize::kVertical && difference.Width()) {
-    if (element->IsFormControlElement()) {
-      // Make implicit margins from the theme explicit (see
-      // <http://bugs.webkit.org/show_bug.cgi?id=9547>).
-      element->SetInlineStyleProperty(
-          CSSPropertyMarginLeft, GetLayoutBox()->MarginLeft() / zoom_factor,
-          CSSPrimitiveValue::UnitType::kPixels);
-      element->SetInlineStyleProperty(
-          CSSPropertyMarginRight, GetLayoutBox()->MarginRight() / zoom_factor,
-          CSSPrimitiveValue::UnitType::kPixels);
-    }
+      GetLayoutBox()->StyleRef().BoxSizing() == EBoxSizing::kBorderBox;
+
+  EResize resize = GetLayoutBox()->StyleRef().UsedResize();
+  if (resize != EResize::kVertical && difference.width) {
     LayoutUnit base_width =
-        GetLayoutBox()->Size().Width() -
+        GetLayoutBox()->Size().width -
         (is_box_sizing_border ? LayoutUnit()
                               : GetLayoutBox()->BorderAndPaddingWidth());
     base_width = LayoutUnit(base_width / zoom_factor);
-    element->SetInlineStyleProperty(CSSPropertyWidth,
-                                    RoundToInt(base_width + difference.Width()),
+    element->SetInlineStyleProperty(CSSPropertyID::kWidth,
+                                    RoundToInt(base_width + difference.width),
                                     CSSPrimitiveValue::UnitType::kPixels);
   }
 
-  if (resize != EResize::kHorizontal && difference.Height()) {
-    if (element->IsFormControlElement()) {
-      // Make implicit margins from the theme explicit (see
-      // <http://bugs.webkit.org/show_bug.cgi?id=9547>).
-      element->SetInlineStyleProperty(CSSPropertyMarginTop,
-                                      GetLayoutBox()->MarginTop() / zoom_factor,
-                                      CSSPrimitiveValue::UnitType::kPixels);
-      element->SetInlineStyleProperty(
-          CSSPropertyMarginBottom, GetLayoutBox()->MarginBottom() / zoom_factor,
-          CSSPrimitiveValue::UnitType::kPixels);
-    }
+  if (resize != EResize::kHorizontal && difference.height) {
     LayoutUnit base_height =
-        GetLayoutBox()->Size().Height() -
+        GetLayoutBox()->Size().height -
         (is_box_sizing_border ? LayoutUnit()
                               : GetLayoutBox()->BorderAndPaddingHeight());
     base_height = LayoutUnit(base_height / zoom_factor);
-    element->SetInlineStyleProperty(
-        CSSPropertyHeight, RoundToInt(base_height + difference.Height()),
-        CSSPrimitiveValue::UnitType::kPixels);
+    element->SetInlineStyleProperty(CSSPropertyID::kHeight,
+                                    RoundToInt(base_height + difference.height),
+                                    CSSPrimitiveValue::UnitType::kPixels);
   }
 
-  document.UpdateStyleAndLayout();
+  document.UpdateStyleAndLayout(DocumentUpdateReason::kSizeChange);
 
-  // FIXME (Radar 4118564): We should also autoscroll the window as necessary to
+  // FIXME: We should also autoscroll the window as necessary to
   // keep the point under the cursor in view.
 }
 
-LayoutRect PaintLayerScrollableArea::ScrollIntoView(
-    const LayoutRect& absolute_rect,
-    const WebScrollIntoViewParams& params) {
-  LayoutRect local_expose_rect =
-      AbsoluteToLocal(*GetLayoutBox(), absolute_rect);
-  LayoutSize border_origin_to_scroll_origin =
-      LayoutSize(-GetLayoutBox()->BorderLeft(), -GetLayoutBox()->BorderTop()) +
-      LayoutSize(GetScrollOffset());
+PhysicalRect PaintLayerScrollableArea::ScrollIntoView(
+    const PhysicalRect& absolute_rect,
+    const mojom::blink::ScrollIntoViewParamsPtr& params) {
+  // Ignore sticky position offsets for the purposes of scrolling elements into
+  // view. See https://www.w3.org/TR/css-position-3/#stickypos-scroll for
+  // details
+  const MapCoordinatesFlags flag =
+      (RuntimeEnabledFeatures::CSSPositionStickyStaticScrollPositionEnabled())
+          ? kIgnoreStickyOffset
+          : 0;
+
+  PhysicalRect local_expose_rect =
+      GetLayoutBox()->AbsoluteToLocalRect(absolute_rect, flag);
+  PhysicalOffset border_origin_to_scroll_origin(-GetLayoutBox()->BorderLeft(),
+                                                -GetLayoutBox()->BorderTop());
+  // There might be scroll bar between border_origin and scroll_origin.
+  gfx::Vector2d scroll_bar_adjustment =
+      GetLayoutBox()->OriginAdjustmentForScrollbars();
+  border_origin_to_scroll_origin.left -= scroll_bar_adjustment.x();
+  border_origin_to_scroll_origin.top -= scroll_bar_adjustment.y();
+  border_origin_to_scroll_origin +=
+      PhysicalOffset::FromVector2dFFloor(GetScrollOffset());
   // Represent the rect in the container's scroll-origin coordinate.
   local_expose_rect.Move(border_origin_to_scroll_origin);
-  LayoutRect scroll_snapport_rect = VisibleScrollSnapportRect();
+  PhysicalRect scroll_snapport_rect = VisibleScrollSnapportRect();
 
   ScrollOffset target_offset = ScrollAlignment::GetScrollOffsetToExpose(
-      scroll_snapport_rect, local_expose_rect, params.GetScrollAlignmentX(),
-      params.GetScrollAlignmentY(), GetScrollOffset());
+      scroll_snapport_rect, local_expose_rect, *params->align_x.get(),
+      *params->align_y.get(), GetScrollOffset());
   ScrollOffset new_scroll_offset(
-      ClampScrollOffset(RoundedIntSize(target_offset)));
+      ClampScrollOffset(gfx::ToRoundedVector2d(target_offset)));
 
   ScrollOffset old_scroll_offset = GetScrollOffset();
-  if (params.GetScrollType() == kUserScroll) {
+  if (params->type == mojom::blink::ScrollType::kUser) {
     if (!UserInputScrollable(kHorizontalScrollbar))
-      new_scroll_offset.SetWidth(old_scroll_offset.Width());
+      new_scroll_offset.set_x(old_scroll_offset.x());
     if (!UserInputScrollable(kVerticalScrollbar))
-      new_scroll_offset.SetHeight(old_scroll_offset.Height());
-  }
-  if (params.is_for_scroll_sequence) {
-    DCHECK(params.GetScrollType() == kProgrammaticScroll ||
-           params.GetScrollType() == kUserScroll);
-    ScrollBehavior behavior =
-        DetermineScrollBehavior(params.GetScrollBehavior(),
-                                GetLayoutBox()->Style()->GetScrollBehavior());
+      new_scroll_offset.set_y(old_scroll_offset.y());
+  }
+
+  gfx::PointF end_point = ScrollOffsetToPosition(new_scroll_offset);
+  std::unique_ptr<cc::SnapSelectionStrategy> strategy =
+      cc::SnapSelectionStrategy::CreateForEndPosition(end_point, true, true);
+  end_point = GetSnapPositionAndSetTarget(*strategy).value_or(end_point);
+  new_scroll_offset = ScrollPositionToOffset(end_point);
+
+  if (params->is_for_scroll_sequence) {
+    CHECK(GetSmoothScrollSequencer());
+    DCHECK(params->type == mojom::blink::ScrollType::kProgrammatic ||
+           params->type == mojom::blink::ScrollType::kUser);
+    mojom::blink::ScrollBehavior behavior = DetermineScrollBehavior(
+        params->behavior, GetLayoutBox()->StyleRef().GetScrollBehavior());
     GetSmoothScrollSequencer()->QueueAnimation(this, new_scroll_offset,
                                                behavior);
   } else {
-    SetScrollOffset(new_scroll_offset, params.GetScrollType(),
-                    kScrollBehaviorInstant);
+    SetScrollOffset(new_scroll_offset, params->type,
+                    mojom::blink::ScrollBehavior::kInstant);
   }
 
   ScrollOffset scroll_offset_difference = new_scroll_offset - old_scroll_offset;
   // The container hasn't performed the scroll yet if it's for scroll sequence.
   // To calculate the result from the scroll, we move the |local_expose_rect| to
   // the will-be-scrolled location.
-  local_expose_rect.Move(-LayoutSize(scroll_offset_difference));
+  local_expose_rect.Move(
+      -PhysicalOffset::FromVector2dFRound(scroll_offset_difference));
 
   // Represent the rects in the container's border-box coordinate.
   local_expose_rect.Move(-border_origin_to_scroll_origin);
   scroll_snapport_rect.Move(-border_origin_to_scroll_origin);
-  LayoutRect intersect = Intersection(scroll_snapport_rect, local_expose_rect);
+  PhysicalRect intersect =
+      Intersection(scroll_snapport_rect, local_expose_rect);
 
   if (intersect.IsEmpty() && !scroll_snapport_rect.IsEmpty() &&
       !local_expose_rect.IsEmpty()) {
-    return LocalToAbsolute(*GetLayoutBox(), local_expose_rect);
+    return GetLayoutBox()->LocalToAbsoluteRect(local_expose_rect, flag);
   }
-  intersect = LocalToAbsolute(*GetLayoutBox(), intersect);
+  intersect = GetLayoutBox()->LocalToAbsoluteRect(intersect, flag);
+
   return intersect;
 }
 
@@ -2084,36 +2444,66 @@ void PaintLayerScrollableArea::UpdateScrollableAreaSet() {
   if (!frame_view)
     return;
 
+  const bool has_horizontal_overflow = HasHorizontalOverflow();
+  const bool has_vertical_overflow = HasVerticalOverflow();
   bool has_overflow =
       !GetLayoutBox()->Size().IsZero() &&
-      ((HasHorizontalOverflow() && GetLayoutBox()->ScrollsOverflowX()) ||
-       (HasVerticalOverflow() && GetLayoutBox()->ScrollsOverflowY()));
+      ((has_horizontal_overflow && GetLayoutBox()->ScrollsOverflowX()) ||
+       (has_vertical_overflow && GetLayoutBox()->ScrollsOverflowY()));
+
+  bool overflows_in_block_direction = GetLayoutBox()->IsHorizontalWritingMode()
+                                          ? has_vertical_overflow
+                                          : has_horizontal_overflow;
 
-  bool is_visible_to_hit_test = GetLayoutBox()->Style()->VisibleToHitTesting();
+  if (overflows_in_block_direction) {
+    DCHECK(CanHaveOverflowScrollbars(*GetLayoutBox()));
+    frame_view->AddScrollAnchoringScrollableArea(this);
+  } else {
+    frame_view->RemoveScrollAnchoringScrollableArea(this);
+  }
+
+  bool is_visible =
+      GetLayoutBox()->StyleRef().Visibility() == EVisibility::kVisible;
   bool did_scroll_overflow = scrolls_overflow_;
-  if (GetLayoutBox()->IsLayoutView()) {
-    ScrollbarMode h_mode;
-    ScrollbarMode v_mode;
-    ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
-    if (h_mode == kScrollbarAlwaysOff && v_mode == kScrollbarAlwaysOff)
+  if (auto* layout_view = DynamicTo<LayoutView>(GetLayoutBox())) {
+    mojom::blink::ScrollbarMode h_mode;
+    mojom::blink::ScrollbarMode v_mode;
+    layout_view->CalculateScrollbarModes(h_mode, v_mode);
+    if (h_mode == mojom::blink::ScrollbarMode::kAlwaysOff &&
+        v_mode == mojom::blink::ScrollbarMode::kAlwaysOff)
       has_overflow = false;
   }
-  scrolls_overflow_ = has_overflow && is_visible_to_hit_test;
+
+  scrolls_overflow_ = has_overflow && is_visible;
   if (did_scroll_overflow == ScrollsOverflow())
     return;
 
+  // Change of scrolls_overflow may affect whether we create ScrollTranslation
+  // which is referenced from ScrollDisplayItem. Invalidate scrollbars (but not
+  // their parts) to repaint the display item.
+  if (auto* scrollbar = HorizontalScrollbar())
+    scrollbar->SetNeedsPaintInvalidation(kNoPart);
+  if (auto* scrollbar = VerticalScrollbar())
+    scrollbar->SetNeedsPaintInvalidation(kNoPart);
+
   if (RuntimeEnabledFeatures::ImplicitRootScrollerEnabled() &&
       scrolls_overflow_) {
-    if (GetLayoutBox()->IsLayoutView()) {
+    if (IsA<LayoutView>(GetLayoutBox())) {
       if (Element* owner = GetLayoutBox()->GetDocument().LocalOwner()) {
         owner->GetDocument().GetRootScrollerController().ConsiderForImplicit(
             *owner);
       }
     } else {
-      GetLayoutBox()
-          ->GetDocument()
-          .GetRootScrollerController()
-          .ConsiderForImplicit(*GetLayoutBox()->GetNode());
+      // In some cases, the LayoutBox may not be associated with a Node (e.g.
+      // <input> and <fieldset> can generate anonymous LayoutBoxes for their
+      // scrollers). We don't care about those cases for root scroller so
+      // simply avoid these. https://crbug.com/1125621.
+      if (GetLayoutBox()->GetNode()) {
+        GetLayoutBox()
+            ->GetDocument()
+            .GetRootScrollerController()
+            .ConsiderForImplicit(*GetLayoutBox()->GetNode());
+      }
     }
   }
 
@@ -2121,55 +2511,21 @@ void PaintLayerScrollableArea::UpdateScrollableAreaSet() {
   // PaintPropertyTreeBuilder::updateScrollAndScrollTranslation).
   GetLayoutBox()->SetNeedsPaintPropertyUpdate();
 
+  // Scroll hit test data depend on whether the box scrolls overflow.
+  // They are painted in the background phase
+  // (see: BoxPainter::PaintBoxDecorationBackground).
+  GetLayoutBox()->SetBackgroundNeedsFullPaintInvalidation();
+
   if (scrolls_overflow_) {
     DCHECK(CanHaveOverflowScrollbars(*GetLayoutBox()));
-    frame_view->AddScrollableArea(this);
+    frame_view->AddUserScrollableArea(this);
   } else {
-    frame_view->RemoveScrollableArea(this);
+    frame_view->RemoveUserScrollableArea(this);
   }
 
   layer_->DidUpdateScrollsOverflow();
 }
 
-void PaintLayerScrollableArea::UpdateCompositingLayersAfterScroll() {
-  PaintLayerCompositor* compositor = GetLayoutBox()->View()->Compositor();
-  if (!compositor->InCompositingMode())
-    return;
-
-  if (UsesCompositedScrolling()) {
-    DCHECK(Layer()->HasCompositedLayerMapping());
-    ScrollingCoordinator* scrolling_coordinator = GetScrollingCoordinator();
-    bool handled_scroll =
-        Layer()->IsRootLayer() && scrolling_coordinator &&
-        scrolling_coordinator->UpdateCompositedScrollOffset(this);
-
-    if (!handled_scroll) {
-      Layer()->GetCompositedLayerMapping()->SetNeedsGraphicsLayerUpdate(
-          kGraphicsLayerUpdateSubtree);
-      compositor->SetNeedsCompositingUpdate(
-          kCompositingUpdateAfterGeometryChange);
-    }
-
-    // Sticky constraints and paint property nodes need to be updated
-    // to the new sticky locations.
-    if (HasStickyDescendants())
-      InvalidateAllStickyConstraints();
-
-    // If we have fixed elements and we scroll the root layer we might
-    // change compositing since the fixed elements might now overlap a
-    // composited layer.
-    if (Layer()->IsRootLayer()) {
-      LocalFrame* frame = GetLayoutBox()->GetFrame();
-      if (frame && frame->View() &&
-          frame->View()->HasViewportConstrainedObjects()) {
-        Layer()->SetNeedsCompositingInputsUpdate();
-      }
-    }
-  } else {
-    Layer()->SetNeedsCompositingInputsUpdate();
-  }
-}
-
 ScrollingCoordinator* PaintLayerScrollableArea::GetScrollingCoordinator()
     const {
   LocalFrame* frame = GetLayoutBox()->GetFrame();
@@ -2184,117 +2540,40 @@ ScrollingCoordinator* PaintLayerScrollableArea::GetScrollingCoordinator()
 }
 
 bool PaintLayerScrollableArea::ShouldScrollOnMainThread() const {
-  if (HasBeenDisposed())
-    return true;
-  if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
-    if (frame->View()->GetMainThreadScrollingReasons())
-      return true;
-  }
-  if (HasNonCompositedStickyDescendants())
-    return true;
-  return ScrollableArea::ShouldScrollOnMainThread();
+  DCHECK_GE(GetDocument()->Lifecycle().GetState(),
+            DocumentLifecycle::kPaintClean);
+  return HasBeenDisposed() || should_scroll_on_main_thread_;
 }
 
-static bool LayerNodeMayNeedCompositedScrolling(const PaintLayer* layer) {
-  // Don't force composite scroll for select or text input elements.
-  if (Node* node = layer->GetLayoutObject().GetNode()) {
-    if (IsHTMLSelectElement(node))
-      return false;
-    if (TextControlElement* text_control = EnclosingTextControl(node)) {
-      if (IsHTMLInputElement(text_control)) {
-        return false;
-      }
-    }
+void PaintLayerScrollableArea::SetShouldScrollOnMainThread(
+    bool scroll_on_main_thread) {
+  DCHECK_EQ(GetDocument()->Lifecycle().GetState(),
+            DocumentLifecycle::kPaintClean);
+  if (scroll_on_main_thread != should_scroll_on_main_thread_) {
+    should_scroll_on_main_thread_ = scroll_on_main_thread;
+    MainThreadScrollingDidChange();
   }
-  return true;
 }
 
-bool PaintLayerScrollableArea::ComputeNeedsCompositedScrolling(
-    const bool layer_has_been_composited,
-    const PaintLayer* layer) {
-  non_composited_main_thread_scrolling_reasons_ = 0;
-
-  if (CompositingReasonFinder::RequiresCompositingForRootScroller(*layer))
+bool PaintLayerScrollableArea::PrefersNonCompositedScrolling() const {
+  if (RuntimeEnabledFeatures::PreferNonCompositedScrollingEnabled()) {
     return true;
-
-  // TODO(crbug.com/839341): Remove ScrollTimeline check once we support
-  // main-thread AnimationWorklet and don't need to promote the scroll-source.
-  Node* node = layer->GetLayoutObject().GetNode();
-  if (!layer->ScrollsOverflow() &&
-      !ScrollTimeline::HasActiveScrollTimeline(node)) {
-    return false;
   }
-
-  if (layer->Size().IsEmpty())
-    return false;
-
-  if (!layer_has_been_composited &&
-      !LayerNodeMayNeedCompositedScrolling(layer)) {
-    return false;
-  }
-
-  bool needs_composited_scrolling = true;
-
-  // TODO(flackr): Allow integer transforms as long as all of the ancestor
-  // transforms are also integer.
-  bool background_supports_lcd_text =
-      RuntimeEnabledFeatures::CompositeOpaqueScrollersEnabled() &&
-      layer->GetLayoutObject().Style()->IsStackingContext() &&
-      layer->GetBackgroundPaintLocation(
-          &non_composited_main_thread_scrolling_reasons_) &
-          kBackgroundPaintInScrollingContents &&
-      layer->BackgroundIsKnownToBeOpaqueInRect(
-          ToLayoutBox(layer->GetLayoutObject()).PaddingBoxRect()) &&
-      !layer->CompositesWithTransform() && !layer->CompositesWithOpacity();
-
-  // TODO(crbug.com/839341): Remove ScrollTimeline check once we support
-  // main-thread AnimationWorklet and don't need to promote the scroll-source.
-  if (!ScrollTimeline::HasActiveScrollTimeline(node) &&
-      !layer_has_been_composited &&
-      !layer->Compositor()->PreferCompositingToLCDTextEnabled() &&
-      !background_supports_lcd_text) {
-    if (layer->CompositesWithOpacity()) {
-      non_composited_main_thread_scrolling_reasons_ |=
-          MainThreadScrollingReason::kHasOpacityAndLCDText;
-    }
-    if (layer->CompositesWithTransform()) {
-      non_composited_main_thread_scrolling_reasons_ |=
-          MainThreadScrollingReason::kHasTransformAndLCDText;
-    }
-    if (!layer->BackgroundIsKnownToBeOpaqueInRect(
-            ToLayoutBox(layer->GetLayoutObject()).PaddingBoxRect())) {
-      non_composited_main_thread_scrolling_reasons_ |=
-          MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText;
+  if (Node* node = GetLayoutBox()->GetNode()) {
+    if (IsA<HTMLSelectElement>(node)) {
+      return true;
     }
-    if (!layer->GetLayoutObject().Style()->IsStackingContext()) {
-      non_composited_main_thread_scrolling_reasons_ |=
-          MainThreadScrollingReason::kIsNotStackingContextAndLCDText;
+    if (TextControlElement* text_control = EnclosingTextControl(node)) {
+      if (IsA<HTMLInputElement>(text_control)) {
+        return true;
+      }
     }
-
-    needs_composited_scrolling = false;
   }
-
-  if (layer->GetLayoutObject().HasClip() ||
-      layer->HasDescendantWithClipPath() || !!layer->ClipPathAncestor()) {
-    non_composited_main_thread_scrolling_reasons_ |=
-        MainThreadScrollingReason::kHasClipRelatedProperty;
-    needs_composited_scrolling = false;
-  }
-
-  DCHECK(!(non_composited_main_thread_scrolling_reasons_ &
-           ~MainThreadScrollingReason::kNonCompositedReasons));
-  return needs_composited_scrolling;
+  return false;
 }
 
-void PaintLayerScrollableArea::UpdateNeedsCompositedScrolling(
-    bool layer_has_been_composited) {
-  const bool needs_composited_scrolling =
-      ComputeNeedsCompositedScrolling(layer_has_been_composited, Layer());
-
-  if (static_cast<bool>(needs_composited_scrolling_) !=
-      needs_composited_scrolling) {
-    needs_composited_scrolling_ = needs_composited_scrolling;
-  }
+bool PaintLayerScrollableArea::UsesCompositedScrolling() const {
+  return GetLayoutBox()->UsesCompositedScrolling();
 }
 
 bool PaintLayerScrollableArea::VisualViewportSuppliesScrollbars() const {
@@ -2308,47 +2587,46 @@ bool PaintLayerScrollableArea::VisualViewportSuppliesScrollbars() const {
 
   const TopDocumentRootScrollerController& controller =
       GetLayoutBox()->GetDocument().GetPage()->GlobalRootScrollerController();
-
-  return RootScrollerUtil::ScrollableAreaForRootScroller(
-             controller.GlobalRootScroller()) == this;
+  return controller.RootScrollerArea() == this;
 }
 
 bool PaintLayerScrollableArea::ScheduleAnimation() {
-  if (ChromeClient* client = ToChromeClient(GetChromeClient())) {
-    client->ScheduleAnimation(GetLayoutBox()->GetFrame()->View());
+  if (ChromeClient* client =
+          GetLayoutBox()->GetFrameView()->GetChromeClient()) {
+    client->ScheduleAnimation(GetLayoutBox()->GetFrameView());
     return true;
   }
   return false;
 }
 
-void PaintLayerScrollableArea::ResetRebuildScrollbarLayerFlags() {
-  rebuild_horizontal_scrollbar_layer_ = false;
-  rebuild_vertical_scrollbar_layer_ = false;
-}
-
-CompositorAnimationHost* PaintLayerScrollableArea::GetCompositorAnimationHost()
+cc::AnimationHost* PaintLayerScrollableArea::GetCompositorAnimationHost()
     const {
   return layer_->GetLayoutObject().GetFrameView()->GetCompositorAnimationHost();
 }
 
-CompositorAnimationTimeline*
+cc::AnimationTimeline*
 PaintLayerScrollableArea::GetCompositorAnimationTimeline() const {
-  return layer_->GetLayoutObject()
-      .GetFrameView()
-      ->GetCompositorAnimationTimeline();
+  return layer_->GetLayoutObject().GetFrameView()->GetScrollAnimationTimeline();
 }
 
-void PaintLayerScrollableArea::GetTickmarks(Vector<IntRect>& tickmarks) const {
+bool PaintLayerScrollableArea::HasTickmarks() const {
+  if (RareData() && !RareData()->tickmarks_override_.empty())
+    return true;
+  return layer_->IsRootLayer() &&
+         To<LayoutView>(GetLayoutBox())->HasTickmarks();
+}
+
+Vector<gfx::Rect> PaintLayerScrollableArea::GetTickmarks() const {
+  if (RareData() && !RareData()->tickmarks_override_.empty())
+    return RareData()->tickmarks_override_;
   if (layer_->IsRootLayer())
-    tickmarks = ToLayoutView(GetLayoutBox())->GetTickmarks();
+    return To<LayoutView>(GetLayoutBox())->GetTickmarks();
+  return Vector<gfx::Rect>();
 }
 
 void PaintLayerScrollableArea::ScrollbarManager::SetHasHorizontalScrollbar(
     bool has_scrollbar) {
   if (has_scrollbar) {
-    // This doesn't hit in any tests, but since the equivalent code in
-    // setHasVerticalScrollbar does, presumably this code does as well.
-    DisableCompositingQueryAsserts disabler;
     if (!h_bar_) {
       h_bar_ = CreateScrollbar(kHorizontalScrollbar);
       h_bar_is_attached_ = 1;
@@ -2367,7 +2645,6 @@ void PaintLayerScrollableArea::ScrollbarManager::SetHasHorizontalScrollbar(
 void PaintLayerScrollableArea::ScrollbarManager::SetHasVerticalScrollbar(
     bool has_scrollbar) {
   if (has_scrollbar) {
-    DisableCompositingQueryAsserts disabler;
     if (!v_bar_) {
       v_bar_ = CreateScrollbar(kVerticalScrollbar);
       v_bar_is_attached_ = 1;
@@ -2390,24 +2667,13 @@ Scrollbar* PaintLayerScrollableArea::ScrollbarManager::CreateScrollbar(
   Scrollbar* scrollbar = nullptr;
   const LayoutObject& style_source =
       ScrollbarStyleSource(*ScrollableArea()->GetLayoutBox());
-  bool has_custom_scrollbar_style =
-      style_source.StyleRef().HasPseudoStyle(kPseudoIdScrollbar);
-  if (has_custom_scrollbar_style) {
+  if (style_source.StyleRef().HasCustomScrollbarStyle()) {
     DCHECK(style_source.GetNode() && style_source.GetNode()->IsElementNode());
-    scrollbar = LayoutScrollbar::CreateCustomScrollbar(
-        ScrollableArea(), orientation, ToElement(style_source.GetNode()));
+    scrollbar = MakeGarbageCollected<CustomScrollbar>(
+        ScrollableArea(), orientation, &style_source);
   } else {
-    ScrollbarControlSize scrollbar_size = kRegularScrollbar;
-    if (style_source.StyleRef().HasAppearance()) {
-      scrollbar_size = LayoutTheme::GetTheme().ScrollbarControlSizeForPart(
-          style_source.StyleRef().Appearance());
-    }
-    scrollbar = Scrollbar::Create(ScrollableArea(), orientation, scrollbar_size,
-                                  &ScrollableArea()
-                                       ->GetLayoutBox()
-                                       ->GetFrame()
-                                       ->GetPage()
-                                       ->GetChromeClient());
+    scrollbar = MakeGarbageCollected<Scrollbar>(ScrollableArea(), orientation,
+                                                &style_source);
   }
   ScrollableArea()->GetLayoutBox()->GetDocument().View()->AddScrollbar(
       scrollbar);
@@ -2424,10 +2690,6 @@ void PaintLayerScrollableArea::ScrollbarManager::DestroyScrollbar(
     return;
 
   ScrollableArea()->SetScrollbarNeedsPaintInvalidation(orientation);
-  if (orientation == kHorizontalScrollbar)
-    ScrollableArea()->rebuild_horizontal_scrollbar_layer_ = true;
-  else
-    ScrollableArea()->rebuild_vertical_scrollbar_layer_ = true;
 
   if (!scrollbar->IsCustomScrollbar())
     ScrollableArea()->WillRemoveScrollbar(*scrollbar, orientation);
@@ -2454,100 +2716,38 @@ void PaintLayerScrollableArea::ScrollbarManager::Dispose() {
 }
 
 void PaintLayerScrollableArea::ScrollbarManager::Trace(
-    blink::Visitor* visitor) {
+    blink::Visitor* visitor) const {
   visitor->Trace(scrollable_area_);
   visitor->Trace(h_bar_);
   visitor->Trace(v_bar_);
 }
 
-uint64_t PaintLayerScrollableArea::Id() const {
-  return DOMNodeIds::IdForNode(GetLayoutBox()->GetNode());
-}
-
-int PaintLayerScrollableArea::PreventRelayoutScope::count_ = 0;
-SubtreeLayoutScope*
-    PaintLayerScrollableArea::PreventRelayoutScope::layout_scope_ = nullptr;
-bool PaintLayerScrollableArea::PreventRelayoutScope::relayout_needed_ = false;
-PersistentHeapVector<Member<PaintLayerScrollableArea>>*
-    PaintLayerScrollableArea::PreventRelayoutScope::needs_relayout_ = nullptr;
-
-PaintLayerScrollableArea::PreventRelayoutScope::PreventRelayoutScope(
-    SubtreeLayoutScope& layout_scope) {
-  if (!count_) {
-    DCHECK(!layout_scope_);
-    DCHECK(!needs_relayout_ || needs_relayout_->IsEmpty());
-    layout_scope_ = &layout_scope;
-  }
-  count_++;
-}
-
-PaintLayerScrollableArea::PreventRelayoutScope::~PreventRelayoutScope() {
-  if (--count_ == 0) {
-    if (relayout_needed_) {
-      for (auto scrollable_area : *needs_relayout_) {
-        DCHECK(scrollable_area->NeedsRelayout());
-        LayoutBox* box = scrollable_area->GetLayoutBox();
-        layout_scope_->SetNeedsLayout(
-            box, LayoutInvalidationReason::kScrollbarChanged);
-        if (box->IsLayoutBlock()) {
-          bool horizontal_scrollbar_changed =
-              scrollable_area->HasHorizontalScrollbar() !=
-              scrollable_area->HadHorizontalScrollbarBeforeRelayout();
-          bool vertical_scrollbar_changed =
-              scrollable_area->HasVerticalScrollbar() !=
-              scrollable_area->HadVerticalScrollbarBeforeRelayout();
-          if (horizontal_scrollbar_changed || vertical_scrollbar_changed) {
-            ToLayoutBlock(box)->ScrollbarsChanged(horizontal_scrollbar_changed,
-                                                  vertical_scrollbar_changed);
-          }
-        }
-        scrollable_area->SetNeedsRelayout(false);
-      }
+int PaintLayerScrollableArea::FreezeScrollbarsScope::count_ = 0;
 
-      needs_relayout_->clear();
-    }
-    layout_scope_ = nullptr;
+PaintLayerScrollableArea::FreezeScrollbarsRootScope::FreezeScrollbarsRootScope(
+    const LayoutBox& box,
+    bool freeze_horizontal,
+    bool freeze_vertical)
+    : scrollable_area_(box.GetScrollableArea()) {
+  if (scrollable_area_ && !FreezeScrollbarsScope::ScrollbarsAreFrozen() &&
+      (freeze_horizontal || freeze_vertical)) {
+    scrollable_area_->EstablishScrollbarRoot(freeze_horizontal,
+                                             freeze_vertical);
+    freezer_.emplace();
   }
 }
 
-void PaintLayerScrollableArea::PreventRelayoutScope::SetBoxNeedsLayout(
-    PaintLayerScrollableArea& scrollable_area,
-    bool had_horizontal_scrollbar,
-    bool had_vertical_scrollbar) {
-  DCHECK(count_);
-  DCHECK(layout_scope_);
-  if (scrollable_area.NeedsRelayout())
-    return;
-  scrollable_area.SetNeedsRelayout(true);
-  scrollable_area.SetHadHorizontalScrollbarBeforeRelayout(
-      had_horizontal_scrollbar);
-  scrollable_area.SetHadVerticalScrollbarBeforeRelayout(had_vertical_scrollbar);
-
-  relayout_needed_ = true;
-  if (!needs_relayout_)
-    needs_relayout_ =
-        new PersistentHeapVector<Member<PaintLayerScrollableArea>>();
-  needs_relayout_->push_back(&scrollable_area);
+PaintLayerScrollableArea::FreezeScrollbarsRootScope::
+    ~FreezeScrollbarsRootScope() {
+  if (scrollable_area_)
+    scrollable_area_->ClearScrollbarRoot();
 }
 
-void PaintLayerScrollableArea::PreventRelayoutScope::ResetRelayoutNeeded() {
-  DCHECK_EQ(count_, 0);
-  DCHECK(!needs_relayout_ || needs_relayout_->IsEmpty());
-  relayout_needed_ = false;
-}
-
-int PaintLayerScrollableArea::FreezeScrollbarsScope::count_ = 0;
-
 int PaintLayerScrollableArea::DelayScrollOffsetClampScope::count_ = 0;
-PersistentHeapVector<Member<PaintLayerScrollableArea>>*
-    PaintLayerScrollableArea::DelayScrollOffsetClampScope::needs_clamp_ =
-        nullptr;
 
 PaintLayerScrollableArea::DelayScrollOffsetClampScope::
     DelayScrollOffsetClampScope() {
-  if (!needs_clamp_)
-    needs_clamp_ = new PersistentHeapVector<Member<PaintLayerScrollableArea>>();
-  DCHECK(count_ > 0 || needs_clamp_->IsEmpty());
+  DCHECK(count_ > 0 || NeedsClampList().empty());
   count_++;
 }
 
@@ -2561,16 +2761,24 @@ void PaintLayerScrollableArea::DelayScrollOffsetClampScope::SetNeedsClamp(
     PaintLayerScrollableArea* scrollable_area) {
   if (!scrollable_area->NeedsScrollOffsetClamp()) {
     scrollable_area->SetNeedsScrollOffsetClamp(true);
-    needs_clamp_->push_back(scrollable_area);
+    NeedsClampList().push_back(scrollable_area);
   }
 }
 
 void PaintLayerScrollableArea::DelayScrollOffsetClampScope::
     ClampScrollableAreas() {
-  for (auto& scrollable_area : *needs_clamp_)
+  for (auto& scrollable_area : NeedsClampList())
     scrollable_area->ClampScrollOffsetAfterOverflowChange();
-  delete needs_clamp_;
-  needs_clamp_ = nullptr;
+  NeedsClampList().clear();
+}
+
+HeapVector<Member<PaintLayerScrollableArea>>&
+PaintLayerScrollableArea::DelayScrollOffsetClampScope::NeedsClampList() {
+  DEFINE_STATIC_LOCAL(
+      Persistent<HeapVector<Member<PaintLayerScrollableArea>>>,
+      needs_clamp_list,
+      (MakeGarbageCollected<HeapVector<Member<PaintLayerScrollableArea>>>()));
+  return *needs_clamp_list;
 }
 
 ScrollbarTheme& PaintLayerScrollableArea::GetPageScrollbarTheme() const {
@@ -2584,12 +2792,28 @@ ScrollbarTheme& PaintLayerScrollableArea::GetPageScrollbarTheme() const {
   return page->GetScrollbarTheme();
 }
 
+void PaintLayerScrollableArea::DidAddScrollbar(
+    Scrollbar& scrollbar,
+    ScrollbarOrientation orientation) {
+  if (HasOverlayOverflowControls() ||
+      layer_->NeedsReorderOverlayOverflowControls()) {
+    // Z-order of existing or new recordered overflow controls is updated along
+    // with the z-order lists.
+    layer_->DirtyStackingContextZOrderLists();
+  }
+  ScrollableArea::DidAddScrollbar(scrollbar, orientation);
+}
+
 void PaintLayerScrollableArea::WillRemoveScrollbar(
     Scrollbar& scrollbar,
     ScrollbarOrientation orientation) {
-  if (!scrollbar.IsCustomScrollbar() &&
-      !(orientation == kHorizontalScrollbar ? LayerForHorizontalScrollbar()
-                                            : LayerForVerticalScrollbar())) {
+  if (layer_->NeedsReorderOverlayOverflowControls()) {
+    // Z-order of recordered overflow controls is updated along with the z-order
+    // lists.
+    layer_->DirtyStackingContextZOrderLists();
+  }
+
+  if (!scrollbar.IsCustomScrollbar()) {
     ObjectPaintInvalidator(*GetLayoutBox())
         .SlowSetPaintingLayerNeedsRepaintAndInvalidateDisplayItemClient(
             scrollbar, PaintInvalidationReason::kScrollControl);
@@ -2598,91 +2822,84 @@ void PaintLayerScrollableArea::WillRemoveScrollbar(
   ScrollableArea::WillRemoveScrollbar(scrollbar, orientation);
 }
 
-static LayoutRect ScrollControlVisualRect(
-    const IntRect& scroll_control_rect,
-    const LayoutBox& box,
-    const PaintInvalidatorContext& context,
-    const LayoutRect& previous_visual_rect) {
-  LayoutRect visual_rect(scroll_control_rect);
-#if DCHECK_IS_ON()
-  FindVisualRectNeedingUpdateScope finder(box, context, previous_visual_rect,
-                                          visual_rect);
-#endif
-  if (!context.NeedsVisualRectUpdate(box))
-    return previous_visual_rect;
-
-  // No need to apply any paint offset. Scroll controls paint in a different
-  // transform space than their contained box (the scrollbarPaintOffset
-  // transform node).
-  return visual_rect;
-}
-
 // Returns true if the scroll control is invalidated.
-static bool InvalidatePaintOfScrollControlIfNeeded(
-    const LayoutRect& new_visual_rect,
-    const LayoutRect& previous_visual_rect,
-    bool needs_paint_invalidation,
-    LayoutBox& box,
-    const LayoutBoxModelObject& paint_invalidation_container) {
-  bool should_invalidate_new_rect = needs_paint_invalidation;
-  if (new_visual_rect != previous_visual_rect) {
-    should_invalidate_new_rect = true;
-  } else if (previous_visual_rect.IsEmpty()) {
+static bool ScrollControlNeedsPaintInvalidation(
+    const gfx::Rect& new_visual_rect,
+    const gfx::Rect& previous_visual_rect,
+    bool needs_paint_invalidation) {
+  if (new_visual_rect != previous_visual_rect)
+    return true;
+  if (previous_visual_rect.IsEmpty()) {
     DCHECK(new_visual_rect.IsEmpty());
     // Do not issue an empty invalidation.
-    should_invalidate_new_rect = false;
+    return false;
+  }
+
+  return needs_paint_invalidation;
+}
+
+bool PaintLayerScrollableArea::ShouldDirectlyCompositeScrollbar(
+    const Scrollbar& scrollbar) const {
+  // Don't composite non-scrollable scrollbars.
+  // TODO(crbug.com/1020913): !ScrollsOverflow() should imply
+  // !scrollbar.Maximum(), but currently that isn't always true due to
+  // different or incorrect rounding methods for scroll geometries.
+  if (!ScrollsOverflow() || !scrollbar.Maximum()) {
+    return false;
   }
+  if (scrollbar.IsCustomScrollbar()) {
+    return false;
+  }
+  // Compositing of scrollbar is decided in PaintArtifactCompositor. We assume
+  // compositing here so that paint invalidation will be skipped here. We'll
+  // invalidate raster if needed after paint, without paint invalidation.
+  return true;
+}
+
+void PaintLayerScrollableArea::EstablishScrollbarRoot(bool freeze_horizontal,
+                                                      bool freeze_vertical) {
+  DCHECK(!FreezeScrollbarsScope::ScrollbarsAreFrozen());
+  is_scrollbar_freeze_root_ = true;
+  is_horizontal_scrollbar_frozen_ = freeze_horizontal;
+  is_vertical_scrollbar_frozen_ = freeze_vertical;
+}
 
-  return should_invalidate_new_rect;
+void PaintLayerScrollableArea::ClearScrollbarRoot() {
+  is_scrollbar_freeze_root_ = false;
+  is_horizontal_scrollbar_frozen_ = false;
+  is_vertical_scrollbar_frozen_ = false;
 }
 
-static LayoutRect InvalidatePaintOfScrollbarIfNeeded(
+void PaintLayerScrollableArea::InvalidatePaintOfScrollbarIfNeeded(
+    const PaintInvalidatorContext& context,
+    bool needs_paint_invalidation,
     Scrollbar* scrollbar,
-    GraphicsLayer* graphics_layer,
     bool& previously_was_overlay,
-    const LayoutRect& previous_visual_rect,
-    bool needs_paint_invalidation_arg,
-    LayoutBox& box,
-    const PaintInvalidatorContext& context) {
+    bool& previously_was_directly_composited,
+    gfx::Rect& visual_rect) {
   bool is_overlay = scrollbar && scrollbar->IsOverlayScrollbar();
 
-  LayoutRect new_visual_rect;
-  // Calculate visual rect of the scrollbar, except overlay composited
-  // scrollbars because we invalidate the graphics layer only.
-  if (scrollbar && !(graphics_layer && is_overlay)) {
-    new_visual_rect = ScrollControlVisualRect(scrollbar->FrameRect(), box,
-                                              context, previous_visual_rect);
-  }
-
-  bool needs_paint_invalidation = needs_paint_invalidation_arg;
-  if (needs_paint_invalidation && graphics_layer) {
-    // If the scrollbar needs paint invalidation but didn't change location/size
-    // or the scrollbar is an overlay scrollbar (visual rect is empty),
-    // invalidating the graphics layer is enough (which has been done in
-    // ScrollableArea::setScrollbarNeedsPaintInvalidation()).
-    // Otherwise invalidatePaintOfScrollControlIfNeeded() below will invalidate
-    // the old and new location of the scrollbar on the box's paint invalidation
-    // container to ensure newly expanded/shrunk areas of the box to be
-    // invalidated.
-    needs_paint_invalidation = false;
-    DCHECK(!graphics_layer->DrawsContent() ||
-           graphics_layer->GetPaintController().GetPaintArtifact().IsEmpty());
+  gfx::Rect new_visual_rect;
+  if (scrollbar) {
+    new_visual_rect = scrollbar->FrameRect();
+    // TODO(crbug.com/1020913): We should not round paint_offset but should
+    // consider subpixel accumulation when painting scrollbars.
+    new_visual_rect.Offset(
+        ToRoundedVector2d(context.fragment_data->PaintOffset()));
   }
 
   // Invalidate the box's display item client if the box's padding box size is
   // affected by change of the non-overlay scrollbar width. We detect change of
-  // visual rect size instead of change of scrollbar width change, which may
-  // have some false-positives (e.g. the scrollbar changed length but not width)
-  // but won't invalidate more than expected because in the false-positive case
-  // the box must have changed size and have been invalidated.
-  const LayoutBoxModelObject& paint_invalidation_container =
-      *context.paint_invalidation_container;
-  LayoutSize new_scrollbar_used_space_in_box;
+  // visual rect size instead of change of scrollbar width, which may have some
+  // false-positives (e.g. the scrollbar changed length but not width) but won't
+  // invalidate more than expected because in the false-positive case the box
+  // must have changed size and have been invalidated.
+  gfx::Size new_scrollbar_used_space_in_box;
   if (!is_overlay)
-    new_scrollbar_used_space_in_box = new_visual_rect.Size();
-  LayoutSize previous_scrollbar_used_space_in_box;
+    new_scrollbar_used_space_in_box = new_visual_rect.size();
+  gfx::Size previous_scrollbar_used_space_in_box;
   if (!previously_was_overlay)
-    previous_scrollbar_used_space_in_box = previous_visual_rect.Size();
+    previous_scrollbar_used_space_in_box = visual_rect.size();
 
   // The IsEmpty() check avoids invalidaiton in cases when the visual rect
   // changes from (0,0 0x0) to (0,0 0x100).
@@ -2690,111 +2907,103 @@ static LayoutRect InvalidatePaintOfScrollbarIfNeeded(
         previous_scrollbar_used_space_in_box.IsEmpty()) &&
       new_scrollbar_used_space_in_box != previous_scrollbar_used_space_in_box) {
     context.painting_layer->SetNeedsRepaint();
+    const auto& box = *GetLayoutBox();
     ObjectPaintInvalidator(box).InvalidateDisplayItemClient(
-        box, PaintInvalidationReason::kGeometry);
+        box, PaintInvalidationReason::kLayout);
   }
 
-  bool invalidated = InvalidatePaintOfScrollControlIfNeeded(
-      new_visual_rect, previous_visual_rect, needs_paint_invalidation, box,
-      paint_invalidation_container);
-
   previously_was_overlay = is_overlay;
 
-  if (!invalidated || !scrollbar || graphics_layer)
-    return new_visual_rect;
+  if (scrollbar) {
+    bool directly_composited = ShouldDirectlyCompositeScrollbar(*scrollbar);
+    if (directly_composited != previously_was_directly_composited) {
+      needs_paint_invalidation = true;
+      previously_was_directly_composited = directly_composited;
+    } else if (directly_composited) {
+      // Don't invalidate directly composited scrollbar if the change is only
+      // inside of the scrollbar. ScrollbarDisplayItem will handle such change.
+      needs_paint_invalidation = false;
+    }
+  }
 
-  context.painting_layer->SetNeedsRepaint();
-  ObjectPaintInvalidator(box).InvalidateDisplayItemClient(
-      *scrollbar, PaintInvalidationReason::kScrollControl);
-  if (scrollbar->IsCustomScrollbar()) {
-    ToLayoutScrollbar(scrollbar)
-        ->InvalidateDisplayItemClientsOfScrollbarParts();
+  if (scrollbar &&
+      ScrollControlNeedsPaintInvalidation(new_visual_rect, visual_rect,
+                                          needs_paint_invalidation)) {
+    context.painting_layer->SetNeedsRepaint();
+    scrollbar->Invalidate(PaintInvalidationReason::kScrollControl);
+    if (auto* custom_scrollbar = DynamicTo<CustomScrollbar>(scrollbar))
+      custom_scrollbar->InvalidateDisplayItemClientsOfScrollbarParts();
   }
 
-  return new_visual_rect;
+  visual_rect = new_visual_rect;
 }
 
 void PaintLayerScrollableArea::InvalidatePaintOfScrollControlsIfNeeded(
     const PaintInvalidatorContext& context) {
-  LayoutBox& box = *GetLayoutBox();
-  SetHorizontalScrollbarVisualRect(InvalidatePaintOfScrollbarIfNeeded(
-      HorizontalScrollbar(), LayerForHorizontalScrollbar(),
-      horizontal_scrollbar_previously_was_overlay_,
-      horizontal_scrollbar_visual_rect_,
-      HorizontalScrollbarNeedsPaintInvalidation(), box, context));
-  SetVerticalScrollbarVisualRect(InvalidatePaintOfScrollbarIfNeeded(
-      VerticalScrollbar(), LayerForVerticalScrollbar(),
+  if (context.subtree_flags & PaintInvalidatorContext::kSubtreeFullInvalidation)
+    SetScrollControlsNeedFullPaintInvalidation();
+
+  InvalidatePaintOfScrollbarIfNeeded(
+      context, HorizontalScrollbarNeedsPaintInvalidation(),
+      HorizontalScrollbar(), horizontal_scrollbar_previously_was_overlay_,
+      horizontal_scrollbar_previously_was_directly_composited_,
+      horizontal_scrollbar_visual_rect_);
+  InvalidatePaintOfScrollbarIfNeeded(
+      context, VerticalScrollbarNeedsPaintInvalidation(), VerticalScrollbar(),
       vertical_scrollbar_previously_was_overlay_,
-      vertical_scrollbar_visual_rect_,
-      VerticalScrollbarNeedsPaintInvalidation(), box, context));
-
-  LayoutRect scroll_corner_and_resizer_visual_rect =
-      ScrollControlVisualRect(ScrollCornerAndResizerRect(), box, context,
-                              scroll_corner_and_resizer_visual_rect_);
-  const LayoutBoxModelObject& paint_invalidation_container =
-      *context.paint_invalidation_container;
-  if (InvalidatePaintOfScrollControlIfNeeded(
-          scroll_corner_and_resizer_visual_rect,
+      vertical_scrollbar_previously_was_directly_composited_,
+      vertical_scrollbar_visual_rect_);
+
+  gfx::Rect new_scroll_corner_and_resizer_visual_rect =
+      ScrollCornerAndResizerRect();
+  // TODO(crbug.com/1020913): We should not round paint_offset but should
+  // consider subpixel accumulation when painting scrollbars.
+  new_scroll_corner_and_resizer_visual_rect.Offset(
+      ToRoundedVector2d(context.fragment_data->PaintOffset()));
+  if (ScrollControlNeedsPaintInvalidation(
+          new_scroll_corner_and_resizer_visual_rect,
           scroll_corner_and_resizer_visual_rect_,
-          ScrollCornerNeedsPaintInvalidation(), box,
-          paint_invalidation_container)) {
-    SetScrollCornerAndResizerVisualRect(scroll_corner_and_resizer_visual_rect);
-    if (LayoutScrollbarPart* scroll_corner = ScrollCorner()) {
+          ScrollCornerNeedsPaintInvalidation())) {
+    scroll_corner_and_resizer_visual_rect_ =
+        new_scroll_corner_and_resizer_visual_rect;
+    if (LayoutCustomScrollbarPart* scroll_corner = ScrollCorner()) {
+      DCHECK(!scroll_corner->PaintingLayer());
       ObjectPaintInvalidator(*scroll_corner)
-          .InvalidateDisplayItemClientsIncludingNonCompositingDescendants(
-              PaintInvalidationReason::kScrollControl);
+          .InvalidateDisplayItemClient(*scroll_corner,
+                                       PaintInvalidationReason::kScrollControl);
     }
-    if (LayoutScrollbarPart* resizer = Resizer()) {
-      ObjectPaintInvalidator(*resizer)
-          .InvalidateDisplayItemClientsIncludingNonCompositingDescendants(
-              PaintInvalidationReason::kScrollControl);
+    if (LayoutCustomScrollbarPart* resizer = Resizer()) {
+      DCHECK(!resizer->PaintingLayer());
+      ObjectPaintInvalidator(*resizer).InvalidateDisplayItemClient(
+          *resizer, PaintInvalidationReason::kScrollControl);
     }
+
+    context.painting_layer->SetNeedsRepaint();
+    ObjectPaintInvalidator(*GetLayoutBox())
+        .InvalidateDisplayItemClient(GetScrollCornerDisplayItemClient(),
+                                     PaintInvalidationReason::kLayout);
   }
 
   ClearNeedsPaintInvalidationForScrollControls();
 }
 
-void PaintLayerScrollableArea::ClearPreviousVisualRects() {
-  SetHorizontalScrollbarVisualRect(LayoutRect());
-  SetVerticalScrollbarVisualRect(LayoutRect());
-  SetScrollCornerAndResizerVisualRect(LayoutRect());
-}
-
-void PaintLayerScrollableArea::SetHorizontalScrollbarVisualRect(
-    const LayoutRect& rect) {
-  horizontal_scrollbar_visual_rect_ = rect;
-  if (Scrollbar* scrollbar = HorizontalScrollbar())
-    scrollbar->SetVisualRect(rect);
-}
-
-void PaintLayerScrollableArea::SetVerticalScrollbarVisualRect(
-    const LayoutRect& rect) {
-  vertical_scrollbar_visual_rect_ = rect;
-  if (Scrollbar* scrollbar = VerticalScrollbar())
-    scrollbar->SetVisualRect(rect);
-}
-
-void PaintLayerScrollableArea::SetScrollCornerAndResizerVisualRect(
-    const LayoutRect& rect) {
-  scroll_corner_and_resizer_visual_rect_ = rect;
-  if (LayoutScrollbarPart* scroll_corner = ScrollCorner())
-    scroll_corner->GetMutableForPainting().FirstFragment().SetVisualRect(rect);
-  if (LayoutScrollbarPart* resizer = Resizer())
-    resizer->GetMutableForPainting().FirstFragment().SetVisualRect(rect);
-}
-
 void PaintLayerScrollableArea::ScrollControlWasSetNeedsPaintInvalidation() {
-  GetLayoutBox()->SetMayNeedPaintInvalidation();
+  SetShouldCheckForPaintInvalidation();
 }
 
 void PaintLayerScrollableArea::DidScrollWithScrollbar(
     ScrollbarPart part,
-    ScrollbarOrientation orientation) {
+    ScrollbarOrientation orientation,
+    WebInputEvent::Type type) {
   WebFeature scrollbar_use_uma;
   switch (part) {
-    case kBackButtonStartPart:
-    case kForwardButtonStartPart:
     case kBackButtonEndPart:
+    case kForwardButtonStartPart:
+      UseCounter::Count(
+          GetLayoutBox()->GetDocument(),
+          WebFeature::kScrollbarUseScrollbarButtonReversedDirection);
+      [[fallthrough]];
+    case kBackButtonStartPart:
     case kForwardButtonEndPart:
       scrollbar_use_uma =
           (orientation == kVerticalScrollbar
@@ -2802,10 +3011,17 @@ void PaintLayerScrollableArea::DidScrollWithScrollbar(
                : WebFeature::kScrollbarUseHorizontalScrollbarButton);
       break;
     case kThumbPart:
-      scrollbar_use_uma =
-          (orientation == kVerticalScrollbar
-               ? WebFeature::kScrollbarUseVerticalScrollbarThumb
-               : WebFeature::kScrollbarUseHorizontalScrollbarThumb);
+      if (orientation == kVerticalScrollbar) {
+        scrollbar_use_uma =
+            (WebInputEvent::IsMouseEventType(type)
+                 ? WebFeature::kVerticalScrollbarThumbScrollingWithMouse
+                 : WebFeature::kVerticalScrollbarThumbScrollingWithTouch);
+      } else {
+        scrollbar_use_uma =
+            (WebInputEvent::IsMouseEventType(type)
+                 ? WebFeature::kHorizontalScrollbarThumbScrollingWithMouse
+                 : WebFeature::kHorizontalScrollbarThumbScrollingWithTouch);
+      }
       break;
     case kBackTrackPart:
     case kForwardTrackPart:
@@ -2818,12 +3034,89 @@ void PaintLayerScrollableArea::DidScrollWithScrollbar(
       return;
   }
 
-  UseCounter::Count(GetLayoutBox()->GetDocument(), scrollbar_use_uma);
+  Document& document = GetLayoutBox()->GetDocument();
+
+  UseCounter::Count(document, scrollbar_use_uma);
 }
 
-CompositorElementId PaintLayerScrollableArea::GetCompositorElementId() const {
+CompositorElementId PaintLayerScrollableArea::GetScrollElementId() const {
   return CompositorElementIdFromUniqueObjectId(
       GetLayoutBox()->UniqueId(), CompositorElementIdNamespace::kScroll);
 }
 
+gfx::Size PaintLayerScrollableArea::PixelSnappedBorderBoxSize() const {
+  // TODO(crbug.com/1020913): We use this method during
+  // PositionOverflowControls() even before the paint offset is updated.
+  // This can be fixed only after we support subpixels in overflow control
+  // geometry. For now we ensure correct pixel snapping of overflow controls by
+  // calling PositionOverflowControls() again when paint offset is updated.
+  return GetLayoutBox()->PixelSnappedBorderBoxSize(
+      GetLayoutBox()->FirstFragment().PaintOffset());
+}
+
+gfx::Rect PaintLayerScrollableArea::ScrollingBackgroundVisualRect(
+    const PhysicalOffset& paint_offset) const {
+  const auto* box = GetLayoutBox();
+  auto clip_rect = box->OverflowClipRect(paint_offset);
+  auto overflow_clip_rect = ToPixelSnappedRect(clip_rect);
+  auto scroll_size = PixelSnappedContentsSize(clip_rect.offset);
+  // Ensure scrolling contents are at least as large as the scroll clip
+  scroll_size.SetToMax(overflow_clip_rect.size());
+  gfx::Rect result(overflow_clip_rect.origin(), scroll_size);
+
+  // The HTML element of a document is special, in that it can have a transform,
+  // but the bounds of the painted area of the element still extends beyond
+  // its actual size to encompass the entire viewport canvas. This is
+  // accomplished in ViewPainter by starting with a rect in viewport canvas
+  // space that is equal to the size of the viewport canvas, then mapping it
+  // into the local border box space of the HTML element, and painting a rect
+  // equal to the bounding box of the result. We need to add in that mapped rect
+  // in such cases.
+  const Document& document = box->GetDocument();
+  if (IsA<LayoutView>(box) &&
+      (document.IsXMLDocument() || document.IsHTMLDocument())) {
+    if (const auto* document_element = document.documentElement()) {
+      if (const auto* document_element_object =
+              document_element->GetLayoutObject()) {
+        const auto& document_element_state =
+            document_element_object->FirstFragment().LocalBorderBoxProperties();
+        const auto& view_contents_state =
+            box->FirstFragment().ContentsProperties();
+        gfx::Rect result_in_view = result;
+        GeometryMapper::SourceToDestinationRect(
+            view_contents_state.Transform(), document_element_state.Transform(),
+            result_in_view);
+        result.Union(result_in_view);
+      }
+    }
+  }
+
+  return result;
+}
+
+String
+PaintLayerScrollableArea::ScrollingBackgroundDisplayItemClient::DebugName()
+    const {
+  return "Scrolling background of " +
+         scrollable_area_->GetLayoutBox()->DebugName();
+}
+
+DOMNodeId
+PaintLayerScrollableArea::ScrollingBackgroundDisplayItemClient::OwnerNodeId()
+    const {
+  return static_cast<const DisplayItemClient*>(scrollable_area_->GetLayoutBox())
+      ->OwnerNodeId();
+}
+
+String PaintLayerScrollableArea::ScrollCornerDisplayItemClient::DebugName()
+    const {
+  return "Scroll corner of " + scrollable_area_->GetLayoutBox()->DebugName();
+}
+
+DOMNodeId PaintLayerScrollableArea::ScrollCornerDisplayItemClient::OwnerNodeId()
+    const {
+  return static_cast<const DisplayItemClient*>(scrollable_area_->GetLayoutBox())
+      ->OwnerNodeId();
+}
+
 }  // namespace blink