Commit message: None
CVE: CVE-2016-5147
CWE: CWE-79
Vulnerability description: Blink, as used in Google Chrome before 53.0.2785.89 on Windows and OS X and before 53.0.2785.92 on Linux, mishandles deferred page loads, which allows remote attackers to inject arbitrary web script or HTML via a crafted web site, aka "Universal XSS (UXSS)."

Project: Chrome

static LayoutRect AbsoluteToLocal(const LayoutBox& box, LayoutRect rect) {
  return LayoutRect(
      box.AbsoluteToLocalQuad(FloatQuad(FloatRect(rect)), kUseTransforms)
          .BoundingBox());
}

Project: Chrome

static bool CanHaveOverflowScrollbars(const LayoutBox& box) {
  return box.GetDocument().ViewportDefiningElement() != box.GetNode();
}

Project: Chrome

void PaintLayerScrollableArea::ClampScrollOffsetAfterOverflowChange() {
  if (HasBeenDisposed())
    return;


  if (DelayScrollOffsetClampScope::ClampingIsDelayed()) {
    DelayScrollOffsetClampScope::SetNeedsClamp(this);
    return;
  }

  UpdateScrollDimensions();
  if (ScrollOriginChanged())
    SetScrollOffsetUnconditionally(ClampScrollOffset(GetScrollOffset()));
  else
    ScrollableArea::SetScrollOffset(GetScrollOffset(), kClampingScroll);

  SetNeedsScrollOffsetClamp(false);
  ResetScrollOriginChanged();
  scrollbar_manager_.DestroyDetachedScrollbars();
}

Project: Chrome

    ClampScrollableAreas() {
  for (auto& scrollable_area : NeedsClampList())
    scrollable_area->ClampScrollOffsetAfterOverflowChange();
  NeedsClampList().clear();
}

Project: Chrome

void PaintLayerScrollableArea::ClearPreviousVisualRects() {
  SetHorizontalScrollbarVisualRect(LayoutRect());
  SetVerticalScrollbarVisualRect(LayoutRect());
  SetScrollCornerAndResizerVisualRect(LayoutRect());
}

Project: Chrome

bool PaintLayerScrollableArea::ComputeNeedsCompositedScrolling(
    const bool layer_has_been_composited,
    const PaintLayer* layer) {
  non_composited_main_thread_scrolling_reasons_ = 0;

  if (CompositingReasonFinder::RequiresCompositingForRootScroller(*layer))
    return true;

  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;

  bool background_supports_lcd_text =
      GetLayoutBox()->StyleRef().IsStackingContext() &&
      GetLayoutBox()->GetBackgroundPaintLocation(
          &non_composited_main_thread_scrolling_reasons_) &
          kBackgroundPaintInScrollingContents &&
      layer->BackgroundIsKnownToBeOpaqueInRect(
          ToLayoutBox(layer->GetLayoutObject()).PhysicalPaddingBoxRect(),
          true) &&
      !layer->CompositesWithTransform() && !layer->CompositesWithOpacity();

  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()).PhysicalPaddingBoxRect(),
            true)) {
      non_composited_main_thread_scrolling_reasons_ |=
          MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText;
    }
    if (!layer->GetLayoutObject().StyleRef().IsStackingContext()) {
      non_composited_main_thread_scrolling_reasons_ |=
          MainThreadScrollingReason::kIsNotStackingContextAndLCDText;
    }

    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;
}

Project: Chrome

void PaintLayerScrollableArea::ComputeScrollbarExistence(
    bool& needs_horizontal_scrollbar,
    bool& needs_vertical_scrollbar,
    ComputeScrollbarExistenceOption option) const {
  DCHECK(GetLayoutBox()->GetFrame()->GetSettings());
  if (VisualViewportSuppliesScrollbars() ||
      !CanHaveOverflowScrollbars(*GetLayoutBox()) ||
      GetLayoutBox()->GetFrame()->GetSettings()->GetHideScrollbars()) {
    needs_horizontal_scrollbar = false;
    needs_vertical_scrollbar = false;
    return;
  }

  needs_horizontal_scrollbar = GetLayoutBox()->ScrollsOverflowX();
  needs_vertical_scrollbar = GetLayoutBox()->ScrollsOverflowY();

  if (GetLayoutBox()->HasAutoHorizontalScrollbar()) {
    if (option == kForbidAddingAutoBars)
      needs_horizontal_scrollbar &= HasHorizontalScrollbar();
    needs_horizontal_scrollbar &=
        GetLayoutBox()->IsRooted() && HasHorizontalOverflow() &&
        VisibleContentRect(kIncludeScrollbars).Height();
  }

  if (GetLayoutBox()->HasAutoVerticalScrollbar()) {
    if (option == kForbidAddingAutoBars)
      needs_vertical_scrollbar &= HasVerticalScrollbar();
    needs_vertical_scrollbar &= GetLayoutBox()->IsRooted() &&
                                HasVerticalOverflow() &&
                                VisibleContentRect(kIncludeScrollbars).Width();
  }

  if (GetLayoutBox()->IsLayoutView()) {
    ScrollbarMode h_mode;
    ScrollbarMode v_mode;
    ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);

    if (h_mode == kScrollbarAlwaysOn)
      needs_horizontal_scrollbar = true;
    else if (h_mode == kScrollbarAlwaysOff)
      needs_horizontal_scrollbar = false;
    if (v_mode == kScrollbarAlwaysOn)
      needs_vertical_scrollbar = true;
    else if (v_mode == kScrollbarAlwaysOff)
      needs_vertical_scrollbar = false;
  }
}

Project: Chrome

void PaintLayerScrollableArea::ContentsResized() {
  ScrollableArea::ContentsResized();
  GetLayoutBox()->SetNeedsPaintPropertyUpdate();
  Layer()->SetNeedsCompositingInputsUpdate();
}

Project: Chrome

IntSize PaintLayerScrollableArea::ContentsSize() const {
  LayoutPoint offset(
      GetLayoutBox()->ClientLeft() + GetLayoutBox()->Location().X(),
      GetLayoutBox()->ClientTop() + GetLayoutBox()->Location().Y());
  return PixelSnappedContentsSize(offset);
}

Project: Chrome

PaintLayerScrollableArea::ConvertFromContainingEmbeddedContentViewToScrollbar(
    const Scrollbar& scrollbar,
    const IntPoint& parent_point) const {
  LayoutView* view = GetLayoutBox()->View();
  if (!view)
    return parent_point;

  IntPoint point = view->GetFrameView()->ConvertToLayoutObject(*GetLayoutBox(),
                                                               parent_point);

  point.Move(-ScrollbarOffset(scrollbar));
  return point;
}

Project: Chrome

PaintLayerScrollableArea::ConvertFromScrollbarToContainingEmbeddedContentView(
    const Scrollbar& scrollbar,
    const IntRect& 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);
}

Project: Chrome

PaintLayerScrollableArea::ConvertFromScrollbarToContainingEmbeddedContentView(
    const Scrollbar& scrollbar,
    const IntPoint& 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);
}

Project: Chrome

IntRect PaintLayerScrollableArea::PaintLayerScrollableArea::CornerRect(
    const IntRect& bounds) const {
  int horizontal_thickness;
  int vertical_thickness;
  if (!VerticalScrollbar() && !HorizontalScrollbar()) {
    horizontal_thickness = GetPageScrollbarTheme().ScrollbarThickness();
    vertical_thickness = horizontal_thickness;
  } else if (VerticalScrollbar() && !HorizontalScrollbar()) {
    horizontal_thickness = VerticalScrollbar()->ScrollbarThickness();
    vertical_thickness = horizontal_thickness;
  } else if (HorizontalScrollbar() && !VerticalScrollbar()) {
    vertical_thickness = HorizontalScrollbar()->ScrollbarThickness();
    horizontal_thickness = vertical_thickness;
  } else {
    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);
}

Project: Chrome

static int CornerStart(const LayoutBox& box,
                       int min_x,
                       int max_x,
                       int thickness) {
  if (box.ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
    return min_x + box.StyleRef().BorderLeftWidth();
  return max_x - thickness - box.StyleRef().BorderRightWidth();
}

Project: Chrome

Scrollbar* PaintLayerScrollableArea::ScrollbarManager::CreateScrollbar(
    ScrollbarOrientation orientation) {
  DCHECK(orientation == kHorizontalScrollbar ? !h_bar_is_attached_
                                             : !v_bar_is_attached_);
  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) {
    DCHECK(style_source.GetNode() && style_source.GetNode()->IsElementNode());
    scrollbar = LayoutScrollbar::CreateCustomScrollbar(
        ScrollableArea(), orientation, ToElement(style_source.GetNode()));
  } 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());
  }
  ScrollableArea()->GetLayoutBox()->GetDocument().View()->AddScrollbar(
      scrollbar);
  return scrollbar;
}

Project: Chrome

    DelayScrollOffsetClampScope() {
  DCHECK(count_ > 0 || NeedsClampList().IsEmpty());
  count_++;
}

Project: Chrome

void PaintLayerScrollableArea::DeregisterForAnimation() {
  if (HasBeenDisposed())
    return;
  if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
    if (LocalFrameView* frame_view = frame->View())
      frame_view->RemoveAnimatingScrollableArea(this);
  }
}

Project: Chrome

void PaintLayerScrollableArea::ScrollbarManager::DestroyDetachedScrollbars() {
  DCHECK(!h_bar_is_attached_ || h_bar_);
  DCHECK(!v_bar_is_attached_ || v_bar_);
  if (h_bar_ && !h_bar_is_attached_)
    DestroyScrollbar(kHorizontalScrollbar);
  if (v_bar_ && !v_bar_is_attached_)
    DestroyScrollbar(kVerticalScrollbar);
}

Project: Chrome

void PaintLayerScrollableArea::ScrollbarManager::DestroyScrollbar(
    ScrollbarOrientation orientation) {
  Member<Scrollbar>& scrollbar =
      orientation == kHorizontalScrollbar ? h_bar_ : v_bar_;
  DCHECK(orientation == kHorizontalScrollbar ? !h_bar_is_attached_
                                             : !v_bar_is_attached_);
  if (!scrollbar)
    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);

  ScrollableArea()->GetLayoutBox()->GetDocument().View()->RemoveScrollbar(
      scrollbar);
  scrollbar->DisconnectFromScrollableArea();
  scrollbar = nullptr;
}

Project: Chrome

void PaintLayerScrollableArea::DidChangeGlobalRootScroller() {
  if (GetLayoutBox()->GetNode()->IsElementNode()) {
    ToElement(GetLayoutBox()->GetNode())->SetNeedsCompositingUpdate();
    GetLayoutBox()->SetNeedsPaintPropertyUpdate();
  }

  if (GetLayoutBox()->GetFrame()->GetSettings() &&
      GetLayoutBox()->GetFrame()->GetSettings()->GetViewportEnabled()) {
    bool needs_horizontal_scrollbar;
    bool needs_vertical_scrollbar;
    ComputeScrollbarExistence(needs_horizontal_scrollbar,
                              needs_vertical_scrollbar);
    SetHasHorizontalScrollbar(needs_horizontal_scrollbar);
    SetHasVerticalScrollbar(needs_vertical_scrollbar);
  }
}

Project: Chrome

void PaintLayerScrollableArea::DidScroll(const FloatPoint& position) {
  ScrollableArea::DidScroll(position);
  CHECK(!HasBeenDisposed());
}

Project: Chrome

void PaintLayerScrollableArea::DidScrollWithScrollbar(
    ScrollbarPart part,
    ScrollbarOrientation orientation) {
  WebFeature scrollbar_use_uma;
  switch (part) {
    case kBackButtonStartPart:
    case kForwardButtonStartPart:
    case kBackButtonEndPart:
    case kForwardButtonEndPart:
      scrollbar_use_uma =
          (orientation == kVerticalScrollbar
               ? WebFeature::kScrollbarUseVerticalScrollbarButton
               : WebFeature::kScrollbarUseHorizontalScrollbarButton);
      break;
    case kThumbPart:
      scrollbar_use_uma =
          (orientation == kVerticalScrollbar
               ? WebFeature::kScrollbarUseVerticalScrollbarThumb
               : WebFeature::kScrollbarUseHorizontalScrollbarThumb);
      break;
    case kBackTrackPart:
    case kForwardTrackPart:
      scrollbar_use_uma =
          (orientation == kVerticalScrollbar
               ? WebFeature::kScrollbarUseVerticalScrollbarTrack
               : WebFeature::kScrollbarUseHorizontalScrollbarTrack);
      break;
    default:
      return;
  }

  UseCounter::Count(GetLayoutBox()->GetDocument(), scrollbar_use_uma);
}

Project: Chrome

void PaintLayerScrollableArea::Dispose() {
  if (InResizeMode() && !GetLayoutBox()->DocumentBeingDestroyed()) {
    if (LocalFrame* frame = GetLayoutBox()->GetFrame())
      frame->GetEventHandler().ResizeScrollableAreaDestroyed();
  }

  if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
    if (LocalFrameView* frame_view = frame->View()) {
      frame_view->RemoveScrollableArea(this);
      frame_view->RemoveAnimatingScrollableArea(this);
    }
  }

  non_composited_main_thread_scrolling_reasons_ = 0;

  if (ScrollingCoordinator* scrolling_coordinator = GetScrollingCoordinator())
    scrolling_coordinator->WillDestroyScrollableArea(this);

  if (!GetLayoutBox()->DocumentBeingDestroyed()) {
    Node* node = GetLayoutBox()->GetNode();
    if (node && node->IsElementNode())
      ToElement(node)->SetSavedLayerScrollOffset(scroll_offset_);
  }

  if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
    if (LocalFrameView* frame_view = frame->View())
      frame_view->RemoveResizerArea(*GetLayoutBox());
  }

  scroll_anchor_.Dispose();

  GetLayoutBox()
      ->GetDocument()
      .GetPage()
      ->GlobalRootScrollerController()
      .DidDisposeScrollableArea(*this);

  scrollbar_manager_.Dispose();

  if (scroll_corner_)
    scroll_corner_->Destroy();
  if (resizer_)
    resizer_->Destroy();

  ClearScrollableArea();

  if (SmoothScrollSequencer* sequencer = GetSmoothScrollSequencer())
    sequencer->DidDisposeScrollableArea(*this);

  layer_ = nullptr;
}

Project: Chrome

void PaintLayerScrollableArea::ScrollbarManager::Dispose() {
  h_bar_is_attached_ = v_bar_is_attached_ = 0;
  DestroyScrollbar(kHorizontalScrollbar);
  DestroyScrollbar(kVerticalScrollbar);
}

Project: Chrome

ChromeClient* PaintLayerScrollableArea::GetChromeClient() const {
  if (HasBeenDisposed())
    return nullptr;
  if (Page* page = GetLayoutBox()->GetFrame()->GetPage())
    return &page->GetChromeClient();
  return nullptr;
}

Project: Chrome

PaintLayerScrollableArea::GetCompositorAnimationTimeline() const {
  return layer_->GetLayoutObject()
      .GetFrameView()
      ->GetCompositorAnimationTimeline();
}

Project: Chrome

CompositorElementId PaintLayerScrollableArea::GetCompositorElementId() const {
  return CompositorElementIdFromUniqueObjectId(
      GetLayoutBox()->UniqueId(), CompositorElementIdNamespace::kScroll);
}

Project: Chrome

LayoutBox* PaintLayerScrollableArea::GetLayoutBox() const {
  return layer_ ? layer_->GetLayoutBox() : nullptr;
}

Project: Chrome

ScrollbarTheme& PaintLayerScrollableArea::GetPageScrollbarTheme() const {
  DCHECK(!HasBeenDisposed());

  Page* page = GetLayoutBox()->GetFrame()->GetPage();
  DCHECK(page);

  return page->GetScrollbarTheme();
}

Project: Chrome

ScrollOffset PaintLayerScrollableArea::GetScrollOffset() const {
  return scroll_offset_;
}

Project: Chrome

ScrollingCoordinator* PaintLayerScrollableArea::GetScrollingCoordinator()
    const {
  LocalFrame* frame = GetLayoutBox()->GetFrame();
  if (!frame)
    return nullptr;

  Page* page = frame->GetPage();
  if (!page)
    return nullptr;

  return page->GetScrollingCoordinator();
}

Project: Chrome

SmoothScrollSequencer* PaintLayerScrollableArea::GetSmoothScrollSequencer()
    const {
  if (HasBeenDisposed())
    return nullptr;

  return &GetLayoutBox()->GetFrame()->GetSmoothScrollSequencer();
}

Project: Chrome

PaintLayerScrollableArea::GetTimerTaskRunner() const {
  return GetLayoutBox()->GetFrame()->GetTaskRunner(TaskType::kInternalDefault);
}

Project: Chrome

bool PaintLayerScrollableArea::HasBeenDisposed() const {
  return !layer_;
}

Project: Chrome

bool PaintLayerScrollableArea::HasHorizontalOverflow() const {
  LayoutUnit client_width =
      LayoutContentRect(kIncludeScrollbars).Width() -
      VerticalScrollbarWidth(kIgnorePlatformAndCSSOverlayScrollbarSize);
  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);
}

Project: Chrome

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;
    }
  }
  return false;
}

Project: Chrome

bool PaintLayerScrollableArea::HasStickyDescendants() const {
  if (const PaintLayerScrollableAreaRareData* d = RareData())
    return !d->sticky_constraints_map_.IsEmpty();
  return false;
}

Project: Chrome

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);
}

Project: Chrome

bool PaintLayerScrollableArea::HitTestResizerInFragments(
    const PaintLayerFragments& layer_fragments,
    const HitTestLocation& hit_test_location) const {
  if (!GetLayoutBox()->CanResize())
    return false;

  if (layer_fragments.IsEmpty())
    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;
}

Project: Chrome

int PaintLayerScrollableArea::HorizontalScrollbarHeight(
    OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
  if (!HasHorizontalScrollbar())
    return 0;
  if (overlay_scrollbar_clip_behavior ==
          kIgnorePlatformAndCSSOverlayScrollbarSize &&
      GetLayoutBox()->StyleRef().OverflowX() == EOverflow::kOverlay) {
    return 0;
  }
  if ((overlay_scrollbar_clip_behavior == kIgnorePlatformOverlayScrollbarSize ||
       overlay_scrollbar_clip_behavior ==
           kIgnorePlatformAndCSSOverlayScrollbarSize ||
       !HorizontalScrollbar()->ShouldParticipateInHitTesting()) &&
      HorizontalScrollbar()->IsOverlayScrollbar()) {
    return 0;
  }
  return HorizontalScrollbar()->ScrollbarThickness();
}

Project: Chrome

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();
  return x;
}

Project: Chrome

int PaintLayerScrollableArea::HypotheticalScrollbarThickness(
    ScrollbarOrientation orientation) const {
  Scrollbar* scrollbar = orientation == kHorizontalScrollbar
                             ? HorizontalScrollbar()
                             : VerticalScrollbar();
  if (scrollbar)
    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);
  }

  ScrollbarControlSize scrollbar_size = kRegularScrollbar;
  if (style_source.StyleRef().HasAppearance()) {
    scrollbar_size = LayoutTheme::GetTheme().ScrollbarControlSizeForPart(
        style_source.StyleRef().Appearance());
  }
  ScrollbarTheme& theme = GetPageScrollbarTheme();
  if (theme.UsesOverlayScrollbars())
    return 0;
  int thickness = theme.ScrollbarThickness(scrollbar_size);
  return GetLayoutBox()
      ->GetDocument()
      .GetPage()
      ->GetChromeClient()
      .WindowToViewportScalar(thickness);
}

Project: Chrome

uint64_t PaintLayerScrollableArea::Id() const {
  return DOMNodeIds::IdForNode(GetLayoutBox()->GetNode());
}

Project: Chrome

void PaintLayerScrollableArea::InvalidateAllStickyConstraints() {
  if (PaintLayerScrollableAreaRareData* d = RareData()) {
    for (PaintLayer* sticky_layer : d->sticky_constraints_map_.Keys()) {
      if (sticky_layer->GetLayoutObject().StyleRef().GetPosition() ==
          EPosition::kSticky) {
        sticky_layer->SetNeedsCompositingInputsUpdate();
        sticky_layer->GetLayoutObject().SetNeedsPaintPropertyUpdate();
      }
    }
    d->sticky_constraints_map_.clear();
  }
}

Project: Chrome

void PaintLayerScrollableArea::InvalidatePaintForScrollOffsetChange() {
  InvalidatePaintForStickyDescendants();

  auto* box = GetLayoutBox();
  auto* frame_view = box->GetFrameView();
  frame_view->InvalidateBackgroundAttachmentFixedDescendantsOnScroll(*box);

  if (box->IsLayoutView() && frame_view->HasViewportConstrainedObjects() &&
      !frame_view->InvalidateViewportConstrainedObjects()) {
    box->SetShouldDoFullPaintInvalidation();
    box->SetSubtreeShouldCheckForPaintInvalidation();
  }

  if (Layer()->EnclosingPaginationLayer())
    box->SetSubtreeShouldCheckForPaintInvalidation();

  bool background_paint_in_graphics_layer = true;
  bool background_paint_in_scrolling_contents = false;
  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
      UsesCompositedScrolling()) {
    auto background_paint_location = box->GetBackgroundPaintLocation();
    background_paint_in_graphics_layer =
        background_paint_location & kBackgroundPaintInGraphicsLayer;
    background_paint_in_scrolling_contents =
        background_paint_location & kBackgroundPaintInScrollingContents;
  }

  auto background_layers = box->StyleRef().BackgroundLayers();
  if ((background_layers.AnyLayerHasLocalAttachmentImage() &&
       background_paint_in_graphics_layer) ||
      (background_layers.AnyLayerHasDefaultAttachmentImage() &&
       background_paint_in_scrolling_contents))
    box->SetBackgroundNeedsFullPaintInvalidation();

  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
      !UsesCompositedScrolling())
    Layer()->SetNeedsRepaint();
}

Project: Chrome

void PaintLayerScrollableArea::InvalidatePaintForStickyDescendants() {
  if (PaintLayerScrollableAreaRareData* d = RareData()) {
    for (PaintLayer* sticky_layer : d->sticky_constraints_map_.Keys())
      sticky_layer->GetLayoutObject().SetNeedsPaintPropertyUpdate();
  }
}

Project: Chrome

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()) {
    DCHECK(new_visual_rect.IsEmpty());
    should_invalidate_new_rect = false;
  }

  return should_invalidate_new_rect;
}

Project: Chrome

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(),
      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,
          scroll_corner_and_resizer_visual_rect_,
          ScrollCornerNeedsPaintInvalidation(), box,
          paint_invalidation_container)) {
    SetScrollCornerAndResizerVisualRect(scroll_corner_and_resizer_visual_rect);
    if (LayoutScrollbarPart* scroll_corner = ScrollCorner()) {
      ObjectPaintInvalidator(*scroll_corner)
          .InvalidateDisplayItemClientsIncludingNonCompositingDescendants(
              PaintInvalidationReason::kScrollControl);
    }
    if (LayoutScrollbarPart* resizer = Resizer()) {
      ObjectPaintInvalidator(*resizer)
          .InvalidateDisplayItemClientsIncludingNonCompositingDescendants(
              PaintInvalidationReason::kScrollControl);
    }
  }

  ClearNeedsPaintInvalidationForScrollControls();
}

Project: Chrome

static LayoutRect InvalidatePaintOfScrollbarIfNeeded(
    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 is_overlay = scrollbar && scrollbar->IsOverlayScrollbar();

  LayoutRect new_visual_rect;
  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) {
    needs_paint_invalidation = false;
    DCHECK(!graphics_layer->PaintsContentOrHitTest() ||
           graphics_layer->GetPaintController().GetPaintArtifact().IsEmpty());
  }

  const LayoutBoxModelObject& paint_invalidation_container =
      *context.paint_invalidation_container;
  LayoutSize 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;
  if (!previously_was_overlay)
    previous_scrollbar_used_space_in_box = previous_visual_rect.Size();

  if (!(new_scrollbar_used_space_in_box.IsEmpty() &&
        previous_scrollbar_used_space_in_box.IsEmpty()) &&
      new_scrollbar_used_space_in_box != previous_scrollbar_used_space_in_box) {
    context.painting_layer->SetNeedsRepaint();
    ObjectPaintInvalidator(box).InvalidateDisplayItemClient(
        box, PaintInvalidationReason::kGeometry);
  }

  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;

  context.painting_layer->SetNeedsRepaint();
  ObjectPaintInvalidator(box).InvalidateDisplayItemClient(
      *scrollbar, PaintInvalidationReason::kScrollControl);
  if (scrollbar->IsCustomScrollbar()) {
    ToLayoutScrollbar(scrollbar)
        ->InvalidateDisplayItemClientsOfScrollbarParts();
  }

  return new_visual_rect;
}

Project: Chrome

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().StyleRef().HasStickyConstrainedPosition()) {
      layer->SetNeedsCompositingInputsUpdate();
      layer->GetLayoutObject().SetNeedsPaintPropertyUpdate();
    }
  }
}

Project: Chrome

bool PaintLayerScrollableArea::IsActive() const {
  Page* page = GetLayoutBox()->GetFrame()->GetPage();
  return page && page->GetFocusController().IsActive();
}

Project: Chrome

bool PaintLayerScrollableArea::IsPointInResizeControl(
    const IntPoint& absolute_point,
    ResizerHitTestType resizer_hit_test_type) const {
  if (!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);
}

Project: Chrome

bool PaintLayerScrollableArea::IsScrollCornerVisible() const {
  return !ScrollCornerRect().IsEmpty();
}

Project: Chrome

bool PaintLayerScrollableArea::IsThrottled() const {
  return GetLayoutBox()->GetFrame()->ShouldThrottleRendering();
}

Project: Chrome

IntPoint PaintLayerScrollableArea::LastKnownMousePosition() const {
  return GetLayoutBox()->GetFrame() ? GetLayoutBox()
                                          ->GetFrame()
                                          ->GetEventHandler()
                                          .LastKnownMousePositionInRootFrame()
                                    : IntPoint();
}

Project: Chrome

PaintLayer* PaintLayerScrollableArea::Layer() const {
  return layer_;
}

Project: Chrome

GraphicsLayer* PaintLayerScrollableArea::LayerForHorizontalScrollbar() const {
  DisableCompositingQueryAsserts disabler;

  return Layer()->HasCompositedLayerMapping()
             ? Layer()
                   ->GetCompositedLayerMapping()
                   ->LayerForHorizontalScrollbar()
             : nullptr;
}

Project: Chrome

GraphicsLayer* PaintLayerScrollableArea::LayerForScrollCorner() const {
  DisableCompositingQueryAsserts disabler;

  return Layer()->HasCompositedLayerMapping()
             ? Layer()->GetCompositedLayerMapping()->LayerForScrollCorner()
             : nullptr;
}

Project: Chrome

GraphicsLayer* PaintLayerScrollableArea::LayerForVerticalScrollbar() const {
  DisableCompositingQueryAsserts disabler;

  return Layer()->HasCompositedLayerMapping()
             ? Layer()->GetCompositedLayerMapping()->LayerForVerticalScrollbar()
             : nullptr;
}

Project: Chrome

static bool LayerNodeMayNeedCompositedScrolling(const PaintLayer* layer) {
  if (Node* node = layer->GetLayoutObject().GetNode()) {
    if (IsHTMLSelectElement(node))
      return false;
    if (TextControlElement* text_control = EnclosingTextControl(node)) {
      if (IsHTMLInputElement(text_control)) {
        return false;
      }
    }
  }
  return true;
}

Project: Chrome

LayoutRect PaintLayerScrollableArea::LayoutContentRect(
    IncludeScrollbarsInRect scrollbar_inclusion) const {
  LayoutSize layer_size(Layer()->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()));
}

Project: Chrome

static LayoutRect LocalToAbsolute(const LayoutBox& box, LayoutRect rect) {
  return LayoutRect(
      box.LocalToAbsoluteQuad(FloatQuad(FloatRect(rect)), kUseTransforms)
          .BoundingBox());
}

Project: Chrome

FloatQuad PaintLayerScrollableArea::LocalToVisibleContentQuad(
    const FloatQuad& quad,
    const LayoutObject* local_object,
    MapCoordinatesFlags flags) const {
  LayoutBox* box = GetLayoutBox();
  if (!box)
    return quad;
  DCHECK(local_object);
  return local_object->LocalToAncestorQuad(quad, box, flags);
}

Project: Chrome

IntSize PaintLayerScrollableArea::MinimumScrollOffsetInt() const {
  return ToIntSize(-ScrollOrigin());
}

Project: Chrome

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);
}

Project: Chrome

PaintLayerScrollableArea::DelayScrollOffsetClampScope::NeedsClampList() {
  DEFINE_STATIC_LOCAL(
      Persistent<HeapVector<Member<PaintLayerScrollableArea>>>,
      needs_clamp_list,
      (MakeGarbageCollected<HeapVector<Member<PaintLayerScrollableArea>>>()));
  return *needs_clamp_list;
}

Project: Chrome

IntSize PaintLayerScrollableArea::OffsetFromResizeCorner(
    const IntPoint& absolute_point) const {
  IntSize element_size = Layer()->PixelSnappedSize();
  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;
}

Project: Chrome

PaintLayerScrollableArea::ScrollingBackgroundDisplayItemClient::OwnerNodeId()
    const {
  return static_cast<const DisplayItemClient*>(scrollable_area_->GetLayoutBox())
      ->OwnerNodeId();
}

Project: Chrome

int PaintLayerScrollableArea::PageStep(ScrollbarOrientation orientation) const {
  IntSize 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);
}

Project: Chrome

PaintLayerScrollableArea::PaintLayerScrollableArea(PaintLayer& layer)
    : 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),
      scroll_origin_changed_(false),
      scrollbar_manager_(*this),
      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),
      scrolling_background_display_item_client_(*this) {
  Node* node = GetLayoutBox()->GetNode();
  if (node && node->IsElementNode()) {
    Element* element = ToElement(node);
    scroll_offset_ = element->SavedLayerScrollOffset();
    if (!scroll_offset_.IsZero())
      GetScrollAnimator().SetCurrentOffset(scroll_offset_);
    element->SetSavedLayerScrollOffset(ScrollOffset());
  }
  UpdateResizerAreaSet();
}

Project: Chrome

    PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
  return scrollable_area_->GetLayoutBox()
      ->PaintedOutputOfObjectHasNoEffectRegardlessOfSize();
}

Project: Chrome

IntSize PaintLayerScrollableArea::PixelSnappedContentsSize(
    const LayoutPoint& paint_offset) const {
  return PixelSnappedIntSize(overflow_rect_.Size(), paint_offset);
}

Project: Chrome

void PaintLayerScrollableArea::PositionOverflowControls() {
  if (!HasScrollbar() && !GetLayoutBox()->CanResize())
    return;

  const IntRect border_box =
      GetLayoutBox()->PixelSnappedBorderBoxRect(layer_->SubpixelAccumulation());

  if (Scrollbar* vertical_scrollbar = VerticalScrollbar())
    vertical_scrollbar->SetFrameRect(RectForVerticalScrollbar(border_box));

  if (Scrollbar* horizontal_scrollbar = HorizontalScrollbar())
    horizontal_scrollbar->SetFrameRect(RectForHorizontalScrollbar(border_box));

  const IntRect& scroll_corner = ScrollCornerRect();
  if (scroll_corner_)
    scroll_corner_->SetFrameRect(LayoutRect(scroll_corner));

  if (resizer_)
    resizer_->SetFrameRect(
        LayoutRect(ResizerCornerRect(border_box, kResizerForPointer)));

  if (Layer()->HasCompositedLayerMapping())
    Layer()->GetCompositedLayerMapping()->PositionOverflowControlsLayers();
}

Project: Chrome

PaintLayerScrollableArea::PreventRelayoutScope::PreventRelayoutScope(
    SubtreeLayoutScope& layout_scope) {
  if (!count_) {
    DCHECK(!layout_scope_);
    DCHECK(NeedsRelayoutList().IsEmpty());
    layout_scope_ = &layout_scope;
  }
  count_++;
}

Project: Chrome

IntRect PaintLayerScrollableArea::RectForHorizontalScrollbar(
    const IntRect& border_box_rect) const {
  if (!HasHorizontalScrollbar())
    return IntRect();

  const IntRect& scroll_corner = ScrollCornerRect();

  return IntRect(
      HorizontalScrollbarStart(border_box_rect.X()),
      border_box_rect.MaxY() - GetLayoutBox()->BorderBottom().ToInt() -
          HorizontalScrollbar()->ScrollbarThickness(),
      border_box_rect.Width() -
          (GetLayoutBox()->BorderLeft() + GetLayoutBox()->BorderRight())
              .ToInt() -
          scroll_corner.Width(),
      HorizontalScrollbar()->ScrollbarThickness());
}

Project: Chrome

IntRect PaintLayerScrollableArea::RectForVerticalScrollbar(
    const IntRect& border_box_rect) const {
  if (!HasVerticalScrollbar())
    return IntRect();

  const IntRect& scroll_corner = ScrollCornerRect();

  return IntRect(
      VerticalScrollbarStart(border_box_rect.X(), border_box_rect.MaxX()),
      border_box_rect.Y() + GetLayoutBox()->BorderTop().ToInt(),
      VerticalScrollbar()->ScrollbarThickness(),
      border_box_rect.Height() -
          (GetLayoutBox()->BorderTop() + GetLayoutBox()->BorderBottom())
              .ToInt() -
          scroll_corner.Height());
}

Project: Chrome

void PaintLayerScrollableArea::RegisterForAnimation() {
  if (HasBeenDisposed())
    return;
  if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
    if (LocalFrameView* frame_view = frame->View())
      frame_view->AddAnimatingScrollableArea(this);
  }
}

Project: Chrome

void PaintLayerScrollableArea::ResetRebuildScrollbarLayerFlags() {
  rebuild_horizontal_scrollbar_layer_ = false;
  rebuild_vertical_scrollbar_layer_ = false;
}

Project: Chrome

void PaintLayerScrollableArea::PreventRelayoutScope::ResetRelayoutNeeded() {
  DCHECK_EQ(count_, 0);
  DCHECK(NeedsRelayoutList().IsEmpty());
  relayout_needed_ = false;
}

Project: Chrome

void PaintLayerScrollableArea::Resize(const IntPoint& pos,
                                      const LayoutSize& old_offset) {
  if (!InResizeMode() || !GetLayoutBox()->CanResize() ||
      !GetLayoutBox()->GetNode())
    return;

  DCHECK(GetLayoutBox()->GetNode()->IsElementNode());
  Element* element = ToElement(GetLayoutBox()->GetNode());

  Document& document = element->GetDocument();

  float zoom_factor = GetLayoutBox()->StyleRef().EffectiveZoom();

  IntSize new_offset =
      OffsetFromResizeCorner(document.View()->ConvertFromRootFrame(pos));
  new_offset.SetWidth(new_offset.Width() / zoom_factor);
  new_offset.SetHeight(new_offset.Height() / zoom_factor);

  LayoutSize 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);
  if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
    new_offset.SetWidth(-new_offset.Width());
    adjusted_old_offset.SetWidth(-adjusted_old_offset.Width());
  }

  LayoutSize difference((current_size + new_offset - adjusted_old_offset)
                            .ExpandedTo(MinimumSizeForResizing(zoom_factor)) -
                        current_size);

  bool is_box_sizing_border =
      GetLayoutBox()->StyleRef().BoxSizing() == EBoxSizing::kBorderBox;

  EResize resize =
      ResolvedResize(GetLayoutBox()->StyleRef(),
                     GetLayoutBox()->ContainingBlock()->StyleRef());
  if (resize != EResize::kVertical && difference.Width()) {
    if (element->IsFormControlElement()) {
      element->SetInlineStyleProperty(
          CSSPropertyMarginLeft, GetLayoutBox()->MarginLeft() / zoom_factor,
          CSSPrimitiveValue::UnitType::kPixels);
      element->SetInlineStyleProperty(
          CSSPropertyMarginRight, GetLayoutBox()->MarginRight() / zoom_factor,
          CSSPrimitiveValue::UnitType::kPixels);
    }
    LayoutUnit base_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()),
                                    CSSPrimitiveValue::UnitType::kPixels);
  }

  if (resize != EResize::kHorizontal && difference.Height()) {
    if (element->IsFormControlElement()) {
      element->SetInlineStyleProperty(CSSPropertyMarginTop,
                                      GetLayoutBox()->MarginTop() / zoom_factor,
                                      CSSPrimitiveValue::UnitType::kPixels);
      element->SetInlineStyleProperty(
          CSSPropertyMarginBottom, GetLayoutBox()->MarginBottom() / zoom_factor,
          CSSPrimitiveValue::UnitType::kPixels);
    }
    LayoutUnit base_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);
  }

  document.UpdateStyleAndLayout();

}

Project: Chrome

IntRect PaintLayerScrollableArea::ResizerCornerRect(
    const IntRect& bounds,
    ResizerHitTestType resizer_hit_test_type) const {
  if (GetLayoutBox()->StyleRef().Resize() == EResize::kNone)
    return IntRect();
  IntRect corner = CornerRect(bounds);

  if (resizer_hit_test_type == kResizerForTouch) {
    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);
  }

  return corner;
}

Project: Chrome

bool PaintLayerScrollableArea::ScheduleAnimation() {
  if (ChromeClient* client = GetChromeClient()) {
    client->ScheduleAnimation(GetLayoutBox()->GetFrame()->View());
    return true;
  }
  return false;
}

Project: Chrome

bool PaintLayerScrollableArea::ScrollAnimatorEnabled() const {
  if (HasBeenDisposed())
    return false;
  if (Settings* settings = GetLayoutBox()->GetFrame()->GetSettings())
    return settings->GetScrollAnimatorEnabled();
  return false;
}

Project: Chrome

ScrollBehavior PaintLayerScrollableArea::ScrollBehaviorStyle() const {
  return GetLayoutBox()->StyleRef().GetScrollBehavior();
}

Project: Chrome

void PaintLayerScrollableArea::ScrollControlWasSetNeedsPaintInvalidation() {
  GetLayoutBox()->SetShouldCheckForPaintInvalidation();
}

Project: Chrome

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);
  }
  return scroll_corner_and_resizer;
}

Project: Chrome

IntRect PaintLayerScrollableArea::ScrollCornerRect() const {
  bool has_horizontal_bar = HorizontalScrollbar();
  bool has_vertical_bar = VerticalScrollbar();
  bool has_resizer = GetLayoutBox()->StyleRef().Resize() != EResize::kNone;
  if ((has_horizontal_bar && has_vertical_bar) ||
      (has_resizer && (has_horizontal_bar || has_vertical_bar))) {
    return CornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
        Layer()->SubpixelAccumulation()));
  }
  return IntRect();
}

Project: Chrome

LayoutUnit PaintLayerScrollableArea::ScrollHeight() const {
  return overflow_rect_.Height();
}

Project: Chrome

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());
  local_expose_rect.Move(border_origin_to_scroll_origin);
  LayoutRect scroll_snapport_rect = VisibleScrollSnapportRect();

  ScrollOffset target_offset = ScrollAlignment::GetScrollOffsetToExpose(
      scroll_snapport_rect, local_expose_rect, params.GetScrollAlignmentX(),
      params.GetScrollAlignmentY(), GetScrollOffset());
  ScrollOffset new_scroll_offset(
      ClampScrollOffset(RoundedIntSize(target_offset)));

  ScrollOffset old_scroll_offset = GetScrollOffset();
  if (params.GetScrollType() == kUserScroll) {
    if (!UserInputScrollable(kHorizontalScrollbar))
      new_scroll_offset.SetWidth(old_scroll_offset.Width());
    if (!UserInputScrollable(kVerticalScrollbar))
      new_scroll_offset.SetHeight(old_scroll_offset.Height());
  }

  FloatPoint end_point = ScrollOffsetToPosition(new_scroll_offset);
  std::unique_ptr<SnapSelectionStrategy> strategy =
      SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(end_point),
                                                  true, true);
  end_point = GetLayoutBox()
                  ->GetDocument()
                  .GetSnapCoordinator()
                  ->GetSnapPosition(*GetLayoutBox(), *strategy)
                  .value_or(end_point);
  new_scroll_offset = ScrollPositionToOffset(end_point);

  if (params.is_for_scroll_sequence) {
    DCHECK(params.GetScrollType() == kProgrammaticScroll ||
           params.GetScrollType() == kUserScroll);
    ScrollBehavior behavior =
        DetermineScrollBehavior(params.GetScrollBehavior(),
                                GetLayoutBox()->StyleRef().GetScrollBehavior());
    GetSmoothScrollSequencer()->QueueAnimation(this, new_scroll_offset,
                                               behavior);
  } else {
    SetScrollOffset(new_scroll_offset, params.GetScrollType(),
                    kScrollBehaviorInstant);
  }

  ScrollOffset scroll_offset_difference = new_scroll_offset - old_scroll_offset;
  local_expose_rect.Move(-LayoutSize(scroll_offset_difference));

  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);

  if (intersect.IsEmpty() && !scroll_snapport_rect.IsEmpty() &&
      !local_expose_rect.IsEmpty()) {
    return LocalToAbsolute(*GetLayoutBox(), local_expose_rect);
  }
  intersect = LocalToAbsolute(*GetLayoutBox(), intersect);
  return intersect;
}

Project: Chrome

IntSize PaintLayerScrollableArea::ScrollOffsetInt() const {
  return FlooredIntSize(scroll_offset_);
}

Project: Chrome

int PaintLayerScrollableArea::ScrollSize(
    ScrollbarOrientation orientation) const {
  IntSize scroll_dimensions =
      MaximumScrollOffsetInt() - MinimumScrollOffsetInt();
  return (orientation == kHorizontalScrollbar) ? scroll_dimensions.Width()
                                               : scroll_dimensions.Height();
}

Project: Chrome

LayoutUnit PaintLayerScrollableArea::ScrollWidth() const {
  return overflow_rect_.Width();
}

Project: Chrome

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();
}

Project: Chrome

void PaintLayerScrollableArea::ScrollbarFrameRectChanged() {
  if (!HasOverlayScrollbars())
    GetLayoutBox()->SetNeedsPaintPropertyUpdate();
}

Project: Chrome

IntSize PaintLayerScrollableArea::ScrollbarOffset(
    const Scrollbar& scrollbar) const {
  if (&scrollbar == VerticalScrollbar()) {
    return IntSize(
        VerticalScrollbarStart(0, Layer()->PixelSnappedSize().Width()),
        GetLayoutBox()->BorderTop().ToInt());
  }

  if (&scrollbar == HorizontalScrollbar()) {
    return IntSize(HorizontalScrollbarStart(0),
                   GetLayoutBox()->BorderTop().ToInt() +
                       VisibleContentRect(kIncludeScrollbars).Height() -
                       HorizontalScrollbar()->ScrollbarThickness());
  }

  NOTREACHED();
  return IntSize();
}

Project: Chrome

static inline const LayoutObject& ScrollbarStyleSource(
    const LayoutBox& layout_box) {
  if (layout_box.IsLayoutView()) {
    Document& doc = layout_box.GetDocument();
    if (Settings* settings = doc.GetSettings()) {
      if (!settings->GetAllowCustomScrollbarInMainFrame() &&
          layout_box.GetFrame() && layout_box.GetFrame()->IsMainFrame())
        return layout_box;
    }

    Element* body = doc.body();
    if (body && body->GetLayoutObject() && body->GetLayoutObject()->IsBox() &&
        body->GetLayoutObject()->StyleRef().HasPseudoStyle(kPseudoIdScrollbar))
      return *body->GetLayoutObject();

    Element* doc_element = doc.documentElement();
    if (doc_element && doc_element->GetLayoutObject() &&
        doc_element->GetLayoutObject()->StyleRef().HasPseudoStyle(
            kPseudoIdScrollbar))
      return *doc_element->GetLayoutObject();
  }

  return layout_box;
}

Project: Chrome

bool PaintLayerScrollableArea::ScrollbarsCanBeActive() const {
  LayoutView* view = GetLayoutBox()->View();
  if (!view)
    return false;

  LocalFrameView* frame_view = view->GetFrameView();
  if (frame_view != frame_view->GetFrame().View())
    return false;

  return !!frame_view->GetFrame().GetDocument();
}

Project: Chrome

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;
  NeedsRelayoutList().push_back(&scrollable_area);
}

Project: Chrome

bool PaintLayerScrollableArea::SetHasHorizontalScrollbar(bool has_scrollbar) {
  if (FreezeScrollbarsScope::ScrollbarsAreFrozen())
    return false;

  if (has_scrollbar == HasHorizontalScrollbar())
    return false;

  SetScrollbarNeedsPaintInvalidation(kHorizontalScrollbar);

  scrollbar_manager_.SetHasHorizontalScrollbar(has_scrollbar);

  UpdateScrollOrigin();

  if (HasHorizontalScrollbar())
    HorizontalScrollbar()->StyleChanged();
  if (HasVerticalScrollbar())
    VerticalScrollbar()->StyleChanged();

  SetScrollCornerNeedsPaintInvalidation();

  if (GetLayoutBox()->GetDocument().HasAnnotatedRegions())
    GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);
  return true;
}

Project: Chrome

void PaintLayerScrollableArea::ScrollbarManager::SetHasHorizontalScrollbar(
    bool has_scrollbar) {
  if (has_scrollbar) {
    DisableCompositingQueryAsserts disabler;
    if (!h_bar_) {
      h_bar_ = CreateScrollbar(kHorizontalScrollbar);
      h_bar_is_attached_ = 1;
      if (!h_bar_->IsCustomScrollbar())
        ScrollableArea()->DidAddScrollbar(*h_bar_, kHorizontalScrollbar);
    } else {
      h_bar_is_attached_ = 1;
    }
  } else {
    h_bar_is_attached_ = 0;
    if (!DelayScrollOffsetClampScope::ClampingIsDelayed())
      DestroyScrollbar(kHorizontalScrollbar);
  }
}

Project: Chrome

bool PaintLayerScrollableArea::SetHasVerticalScrollbar(bool has_scrollbar) {
  if (FreezeScrollbarsScope::ScrollbarsAreFrozen())
    return false;

  if (GetLayoutBox()->GetDocument().IsVerticalScrollEnforced()) {
    return false;
  }

  if (has_scrollbar == HasVerticalScrollbar())
    return false;

  SetScrollbarNeedsPaintInvalidation(kVerticalScrollbar);

  scrollbar_manager_.SetHasVerticalScrollbar(has_scrollbar);

  UpdateScrollOrigin();

  if (HasHorizontalScrollbar())
    HorizontalScrollbar()->StyleChanged();
  if (HasVerticalScrollbar())
    VerticalScrollbar()->StyleChanged();

  SetScrollCornerNeedsPaintInvalidation();

  if (GetLayoutBox()->GetDocument().HasAnnotatedRegions())
    GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);
  return true;
}

Project: Chrome

void PaintLayerScrollableArea::ScrollbarManager::SetHasVerticalScrollbar(
    bool has_scrollbar) {
  if (has_scrollbar) {
    DisableCompositingQueryAsserts disabler;
    if (!v_bar_) {
      v_bar_ = CreateScrollbar(kVerticalScrollbar);
      v_bar_is_attached_ = 1;
      if (!v_bar_->IsCustomScrollbar())
        ScrollableArea()->DidAddScrollbar(*v_bar_, kVerticalScrollbar);
    } else {
      v_bar_is_attached_ = 1;
    }
  } else {
    v_bar_is_attached_ = 0;
    if (!DelayScrollOffsetClampScope::ClampingIsDelayed())
      DestroyScrollbar(kVerticalScrollbar);
  }
}

Project: Chrome

void PaintLayerScrollableArea::DelayScrollOffsetClampScope::SetNeedsClamp(
    PaintLayerScrollableArea* scrollable_area) {
  if (!scrollable_area->NeedsScrollOffsetClamp()) {
    scrollable_area->SetNeedsScrollOffsetClamp(true);
    NeedsClampList().push_back(scrollable_area);
  }
}

Project: Chrome

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);
}

Project: Chrome

void PaintLayerScrollableArea::SetScrollOffsetUnconditionally(
    const ScrollOffset& offset,
    ScrollType scroll_type) {
  CancelScrollAnimation();
  ScrollOffsetChanged(offset, scroll_type);
}

Project: Chrome

void PaintLayerScrollableArea::SetVerticalScrollbarVisualRect(
    const LayoutRect& rect) {
  vertical_scrollbar_visual_rect_ = rect;
  if (Scrollbar* scrollbar = VerticalScrollbar())
    scrollbar->SetVisualRect(rect);
}

Project: Chrome

bool PaintLayerScrollableArea::ShouldPerformScrollAnchoring() const {
  return scroll_anchor_.HasScroller() && GetLayoutBox() &&
         GetLayoutBox()->StyleRef().OverflowAnchor() !=
             EOverflowAnchor::kNone &&
         !GetLayoutBox()->GetDocument().FinishingOrIsPrinting();
}

Project: Chrome

bool PaintLayerScrollableArea::ShouldPlaceVerticalScrollbarOnLeft() const {
  return GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft();
}

Project: Chrome

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();
}

Project: Chrome

bool PaintLayerScrollableArea::ShouldSuspendScrollAnimations() const {
  if (HasBeenDisposed())
    return true;
  LayoutView* view = GetLayoutBox()->View();
  if (!view)
    return true;
  return !GetLayoutBox()->GetDocument().LoadEventFinished();
}

Project: Chrome

void PaintLayerScrollableArea::SnapAfterScrollbarScrolling(
    ScrollbarOrientation orientation) {
  SnapCoordinator* snap_coordinator =
      GetLayoutBox()->GetDocument().GetSnapCoordinator();
  if (!snap_coordinator)
    return;

  snap_coordinator->SnapAtCurrentPosition(*GetLayoutBox(),
                                          orientation == kHorizontalScrollbar,
                                          orientation == kVerticalScrollbar);
}

Project: Chrome

void PaintLayerScrollableArea::Trace(blink::Visitor* visitor) {
  visitor->Trace(scrollbar_manager_);
  visitor->Trace(scroll_anchor_);
  visitor->Trace(scrolling_background_display_item_client_);
  ScrollableArea::Trace(visitor);
}

Project: Chrome

void PaintLayerScrollableArea::ScrollbarManager::Trace(
    blink::Visitor* visitor) {
  visitor->Trace(scrollable_area_);
  visitor->Trace(h_bar_);
  visitor->Trace(v_bar_);
}

Project: Chrome

bool PaintLayerScrollableArea::TryRemovingAutoScrollbars(
    const bool& needs_horizontal_scrollbar,
    const bool& needs_vertical_scrollbar) {
  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)
      return false;

    IntSize visible_size_with_scrollbars =
        VisibleContentRect(kIncludeScrollbars).Size();
    if (ScrollWidth() <= visible_size_with_scrollbars.Width() &&
        ScrollHeight() <= visible_size_with_scrollbars.Height()) {
      return true;
    }
  } else {
    if (!GetLayoutBox()->HasAutoVerticalScrollbar() ||
        !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()) {
      return true;
    }
  }

  return false;
}

Project: Chrome

void PaintLayerScrollableArea::UpdateAfterLayout() {
  bool scrollbars_are_frozen =
      (in_overflow_relayout_ && !allow_second_overflow_relayout_) ||
      FreezeScrollbarsScope::ScrollbarsAreFrozen();
  allow_second_overflow_relayout_ = false;

  if (NeedsScrollbarReconstruction()) {
    SetHasHorizontalScrollbar(false);
    SetHasVerticalScrollbar(false);
  }

  UpdateScrollDimensions();

  bool had_horizontal_scrollbar = HasHorizontalScrollbar();
  bool had_vertical_scrollbar = HasVerticalScrollbar();

  bool needs_horizontal_scrollbar;
  bool needs_vertical_scrollbar;
  ComputeScrollbarExistence(needs_horizontal_scrollbar,
                            needs_vertical_scrollbar);

  if (!in_overflow_relayout_ && !scrollbars_are_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 =
      needs_horizontal_scrollbar != had_horizontal_scrollbar;
  bool vertical_scrollbar_should_change =
      needs_vertical_scrollbar != had_vertical_scrollbar;

  bool scrollbars_will_change =
      !scrollbars_are_frozen &&
      (horizontal_scrollbar_should_change || vertical_scrollbar_should_change);
  if (scrollbars_will_change) {
    SetHasHorizontalScrollbar(needs_horizontal_scrollbar);
    SetHasVerticalScrollbar(needs_vertical_scrollbar);

    if (LocalFrameView* frame_view = GetLayoutBox()->GetFrameView()) {
      if (this == frame_view->LayoutViewport()) {
        GetLayoutBox()
            ->GetFrame()
            ->GetPage()
            ->GetVisualViewport()
            .SetNeedsPaintPropertyUpdate();
      }
    }

    if (HasScrollbar())
      UpdateScrollCornerStyle();

    Layer()->UpdateSelfPaintingLayer();

    if (GetLayoutBox()->GetDocument().HasAnnotatedRegions())
      GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);

    if (((horizontal_scrollbar_should_change &&
          GetLayoutBox()->StyleRef().OverflowX() != EOverflow::kOverlay) ||
         (vertical_scrollbar_should_change &&
          GetLayoutBox()->StyleRef().OverflowY() != EOverflow::kOverlay))) {
      if ((vertical_scrollbar_should_change &&
           GetLayoutBox()->IsHorizontalWritingMode()) ||
          (horizontal_scrollbar_should_change &&
           !GetLayoutBox()->IsHorizontalWritingMode())) {
        GetLayoutBox()->SetPreferredLogicalWidthsDirty();
      }
      if (IsManagedByLayoutNG(*GetLayoutBox())) {
        UpdateScrollDimensions();
      } else {
        if (PreventRelayoutScope::RelayoutIsPrevented()) {
          GetLayoutBox()->UpdateLogicalWidth();
          PreventRelayoutScope::SetBoxNeedsLayout(
              *this, had_horizontal_scrollbar, had_vertical_scrollbar);
        } else {
          in_overflow_relayout_ = true;
          SubtreeLayoutScope layout_scope(*GetLayoutBox());
          layout_scope.SetNeedsLayout(
              GetLayoutBox(), layout_invalidation_reason::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());
        }
      }
    }
  }

  {
    DisableCompositingQueryAsserts disabler;

    UpdateScrollbarEnabledState();

    UpdateScrollbarProportions();
  }

  if (!scrollbars_are_frozen && HasOverlayScrollbars()) {
    if (!ScrollSize(kHorizontalScrollbar))
      SetHasHorizontalScrollbar(false);
    if (!ScrollSize(kVerticalScrollbar))
      SetHasVerticalScrollbar(false);
  }

  ClampScrollOffsetAfterOverflowChange();

  if (!scrollbars_are_frozen) {
    UpdateScrollableAreaSet();
  }

  DisableCompositingQueryAsserts disabler;
  PositionOverflowControls();
}

Project: Chrome

void PaintLayerScrollableArea::UpdateAfterOverflowRecalc() {
  UpdateScrollDimensions();
  UpdateScrollbarProportions();

  bool needs_horizontal_scrollbar;
  bool needs_vertical_scrollbar;
  ComputeScrollbarExistence(needs_horizontal_scrollbar,
                            needs_vertical_scrollbar);

  bool horizontal_scrollbar_should_change =
      needs_horizontal_scrollbar != HasHorizontalScrollbar();
  bool vertical_scrollbar_should_change =
      needs_vertical_scrollbar != HasVerticalScrollbar();

  if ((GetLayoutBox()->HasAutoHorizontalScrollbar() &&
       horizontal_scrollbar_should_change) ||
      (GetLayoutBox()->HasAutoVerticalScrollbar() &&
       vertical_scrollbar_should_change)) {
    GetLayoutBox()->SetNeedsLayoutAndFullPaintInvalidation(
        layout_invalidation_reason::kUnknown);
  }

  ClampScrollOffsetAfterOverflowChange();
}

Project: Chrome

void PaintLayerScrollableArea::UpdateAfterStyleChange(
    const ComputedStyle* old_style) {
  if (!OverflowRect().Size().IsZero()) {
    UpdateScrollableAreaSet();
  }

  Color old_background;
  if (old_style) {
    old_background =
        old_style->VisitedDependentColor(GetCSSPropertyBackgroundColor());
  }
  Color new_background = GetLayoutBox()->StyleRef().VisitedDependentColor(
      GetCSSPropertyBackgroundColor());

  if (new_background != old_background) {
    RecalculateScrollbarOverlayColorTheme(new_background);
  }

  bool needs_horizontal_scrollbar;
  bool needs_vertical_scrollbar;
  ComputeScrollbarExistence(needs_horizontal_scrollbar,
                            needs_vertical_scrollbar, kForbidAddingAutoBars);

  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);

  if (GetLayoutBox()->IsLayoutBlock() &&
      (horizontal_scrollbar_changed || vertical_scrollbar_changed)) {
    ToLayoutBlock(GetLayoutBox())
        ->ScrollbarsChanged(horizontal_scrollbar_changed,
                            vertical_scrollbar_changed,
                            LayoutBlock::ScrollbarChangeContext::kStyleChange);
  }

  if (HasHorizontalScrollbar() && old_style &&
      old_style->OverflowX() == EOverflow::kScroll &&
      GetLayoutBox()->StyleRef().OverflowX() != EOverflow::kScroll) {
    HorizontalScrollbar()->SetEnabled(true);
  }

  if (HasVerticalScrollbar() && old_style &&
      old_style->OverflowY() == EOverflow::kScroll &&
      GetLayoutBox()->StyleRef().OverflowY() != EOverflow::kScroll) {
    VerticalScrollbar()->SetEnabled(true);
  }

  if (HorizontalScrollbar())
    HorizontalScrollbar()->StyleChanged();
  if (VerticalScrollbar())
    VerticalScrollbar()->StyleChanged();

  UpdateScrollCornerStyle();
  UpdateResizerAreaSet();
  UpdateResizerStyle(old_style);
}

Project: Chrome

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;
  }
}

Project: Chrome

void PaintLayerScrollableArea::UpdateResizerStyle(
    const ComputedStyle* old_style) {
  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && old_style &&
      old_style->Resize() != GetLayoutBox()->StyleRef().Resize()) {
    if (auto* graphics_layer = LayerForScrollCorner())
      graphics_layer->SetNeedsDisplay();
  }

  if (!resizer_ && !GetLayoutBox()->CanResize())
    return;

  const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
  scoped_refptr<ComputedStyle> resizer =
      GetLayoutBox()->HasOverflowClip()
          ? style_source.GetUncachedPseudoStyle(
                PseudoStyleRequest(kPseudoIdResizer), style_source.Style())
          : scoped_refptr<ComputedStyle>(nullptr);
  if (resizer) {
    if (!resizer_) {
      resizer_ = LayoutScrollbarPart::CreateAnonymous(
          &GetLayoutBox()->GetDocument(), this);
      resizer_->SetDangerousOneWayParent(GetLayoutBox());
    }
    resizer_->SetStyleWithWritingModeOfParent(std::move(resizer));
  } else if (resizer_) {
    resizer_->Destroy();
    resizer_ = nullptr;
  }
}

Project: Chrome

void PaintLayerScrollableArea::UpdateScrollCornerStyle() {
  if (!scroll_corner_ && !HasScrollbar())
    return;
  if (!scroll_corner_ && HasOverlayScrollbars())
    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);
  if (corner) {
    if (!scroll_corner_) {
      scroll_corner_ = LayoutScrollbarPart::CreateAnonymous(
          &GetLayoutBox()->GetDocument(), this);
      scroll_corner_->SetDangerousOneWayParent(GetLayoutBox());
    }
    scroll_corner_->SetStyleWithWritingModeOfParent(std::move(corner));
  } else if (scroll_corner_) {
    scroll_corner_->Destroy();
    scroll_corner_ = nullptr;
  }
}

Project: Chrome

void PaintLayerScrollableArea::UpdateScrollDimensions() {
  LayoutRect new_overflow_rect = GetLayoutBox()->LayoutOverflowRect();
  GetLayoutBox()->FlipForWritingMode(new_overflow_rect);

  new_overflow_rect.Unite(
      LayoutRect(new_overflow_rect.Location(),
                 LayoutContentRect(kExcludeScrollbars).Size()));

  if (overflow_rect_.Size() != new_overflow_rect.Size())
    ContentsResized();
  overflow_rect_ = new_overflow_rect;
  UpdateScrollOrigin();
}

Project: Chrome

void PaintLayerScrollableArea::UpdateScrollableAreaSet() {
  LocalFrame* frame = GetLayoutBox()->GetFrame();
  if (!frame)
    return;

  LocalFrameView* frame_view = frame->View();
  if (!frame_view)
    return;

  bool has_overflow =
      !GetLayoutBox()->Size().IsZero() &&
      ((HasHorizontalOverflow() && GetLayoutBox()->ScrollsOverflowX()) ||
       (HasVerticalOverflow() && GetLayoutBox()->ScrollsOverflowY()));

  bool is_visible_to_hit_test =
      GetLayoutBox()->StyleRef().VisibleToHitTesting();
  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)
      has_overflow = false;
  }
  scrolls_overflow_ = has_overflow && is_visible_to_hit_test;
  if (did_scroll_overflow == ScrollsOverflow())
    return;

  if (RuntimeEnabledFeatures::ImplicitRootScrollerEnabled() &&
      scrolls_overflow_) {
    if (GetLayoutBox()->IsLayoutView()) {
      if (Element* owner = GetLayoutBox()->GetDocument().LocalOwner()) {
        owner->GetDocument().GetRootScrollerController().ConsiderForImplicit(
            *owner);
      }
    } else {
      GetLayoutBox()
          ->GetDocument()
          .GetRootScrollerController()
          .ConsiderForImplicit(*GetLayoutBox()->GetNode());
    }
  }

  GetLayoutBox()->SetNeedsPaintPropertyUpdate();

  if (scrolls_overflow_) {
    DCHECK(CanHaveOverflowScrollbars(*GetLayoutBox()));
    frame_view->AddScrollableArea(this);
  } else {
    frame_view->RemoveScrollableArea(this);
  }

  layer_->DidUpdateScrollsOverflow();
}

Project: Chrome

void PaintLayerScrollableArea::UpdateScrollbarEnabledState() {
  bool force_disable =
      GetPageScrollbarTheme().ShouldDisableInvisibleScrollbars() &&
      ScrollbarsHiddenIfOverlay();

  if (HorizontalScrollbar())
    HorizontalScrollbar()->SetEnabled(HasHorizontalOverflow() &&
                                      !force_disable);
  if (VerticalScrollbar())
    VerticalScrollbar()->SetEnabled(HasVerticalOverflow() && !force_disable);
}

Project: Chrome

bool PaintLayerScrollableArea::UserInputScrollable(
    ScrollbarOrientation orientation) const {
  if (orientation == kVerticalScrollbar &&
      GetLayoutBox()->GetDocument().IsVerticalScrollEnforced()) {
    return false;
  }

  if (GetLayoutBox()->IsIntrinsicallyScrollable(orientation))
    return true;

  if (GetLayoutBox()->IsLayoutView()) {
    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 =
        (orientation == kHorizontalScrollbar) ? h_mode : v_mode;
    return mode == kScrollbarAuto || mode == kScrollbarAlwaysOn;
  }

  EOverflow overflow_style = (orientation == kHorizontalScrollbar)
                                 ? GetLayoutBox()->StyleRef().OverflowX()
                                 : GetLayoutBox()->StyleRef().OverflowY();
  return (overflow_style == EOverflow::kScroll ||
          overflow_style == EOverflow::kAuto ||
          overflow_style == EOverflow::kOverlay);
}

Project: Chrome

int PaintLayerScrollableArea::VerticalScrollbarStart(int min_x,
                                                     int max_x) const {
  if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
    return min_x + GetLayoutBox()->BorderLeft().ToInt();
  return max_x - GetLayoutBox()->BorderRight().ToInt() -
         VerticalScrollbar()->ScrollbarThickness();
}

Project: Chrome

int PaintLayerScrollableArea::VerticalScrollbarWidth(
    OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
  if (!HasVerticalScrollbar())
    return 0;
  if (overlay_scrollbar_clip_behavior ==
          kIgnorePlatformAndCSSOverlayScrollbarSize &&
      GetLayoutBox()->StyleRef().OverflowY() == EOverflow::kOverlay) {
    return 0;
  }
  if ((overlay_scrollbar_clip_behavior == kIgnorePlatformOverlayScrollbarSize ||
       overlay_scrollbar_clip_behavior ==
           kIgnorePlatformAndCSSOverlayScrollbarSize ||
       !VerticalScrollbar()->ShouldParticipateInHitTesting()) &&
      VerticalScrollbar()->IsOverlayScrollbar()) {
    return 0;
  }
  return VerticalScrollbar()->ScrollbarThickness();
}

Project: Chrome

IntRect PaintLayerScrollableArea::VisibleContentRect(
    IncludeScrollbarsInRect scrollbar_inclusion) const {
  LayoutRect layout_content_rect(LayoutContentRect(scrollbar_inclusion));
  return IntRect(FlooredIntPoint(layout_content_rect.Location()),
                 PixelSnappedIntSize(layout_content_rect.Size(),
                                     GetLayoutBox()->Location()));
}

Project: Chrome

LayoutRect 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()));
  layout_content_rect.Contract(padding);
  return layout_content_rect;
}

Project: Chrome

void PaintLayerScrollableArea::VisibleSizeChanged() {
  ShowOverlayScrollbars();
}

Project: Chrome

PaintLayerScrollableArea::ScrollingBackgroundDisplayItemClient::VisualRect()
    const {
  const auto* box = scrollable_area_->GetLayoutBox();
  const auto& paint_offset = box->FirstFragment().PaintOffset();
  auto overflow_clip_rect =
      PixelSnappedIntRect(box->OverflowClipRect(paint_offset));
  auto scroll_size = scrollable_area_->PixelSnappedContentsSize(paint_offset);
  scroll_size = scroll_size.ExpandedTo(overflow_clip_rect.Size());
  LayoutRect result(overflow_clip_rect.Location(), scroll_size);
#if DCHECK_IS_ON()
  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
    DCHECK_EQ(result,
              scrollable_area_->layer_->GraphicsLayerBacking()->VisualRect());
  }
#endif
  return result;
}

Project: Chrome

bool PaintLayerScrollableArea::VisualViewportSuppliesScrollbars() const {
  LocalFrame* frame = GetLayoutBox()->GetFrame();
  if (!frame || !frame->GetSettings())
    return false;

  if (!frame->GetSettings()->GetViewportEnabled())
    return false;

  const TopDocumentRootScrollerController& controller =
      GetLayoutBox()->GetDocument().GetPage()->GlobalRootScrollerController();
  return controller.RootScrollerArea() == this;
}

Project: Chrome

PaintLayerScrollableArea::~PaintLayerScrollableArea() {
  CHECK(HasBeenDisposed());
}

Project: Chrome

PaintLayerScrollableArea::PreventRelayoutScope::~PreventRelayoutScope() {
  if (--count_ == 0) {
    if (relayout_needed_) {
      for (auto scrollable_area : NeedsRelayoutList()) {
        DCHECK(scrollable_area->NeedsRelayout());
        LayoutBox* box = scrollable_area->GetLayoutBox();
        layout_scope_->SetNeedsLayout(
            box, layout_invalidation_reason::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);
      }

      NeedsRelayoutList().clear();
    }
    layout_scope_ = nullptr;
  }
}