summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc514
1 files changed, 386 insertions, 128 deletions
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index ec6d6ca5d58..ee72a82c200 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -44,12 +44,14 @@
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "base/numerics/checked_math.h"
#include "base/single_thread_task_runner.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/dom/ax_object_cache.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/shadow_root.h"
@@ -84,13 +86,15 @@
#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/paint_invalidator.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/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/wtf/checked_numeric.h"
+#include "third_party/blink/renderer/platform/scroll/smooth_scroll_sequencer.h"
namespace blink {
@@ -121,8 +125,6 @@ const int kResizerControlExpandRatioForTouch = 2;
PaintLayerScrollableArea::PaintLayerScrollableArea(PaintLayer& layer)
: layer_(&layer),
- next_topmost_scroll_child_(nullptr),
- topmost_scroll_child_(nullptr),
in_resize_mode_(false),
scrolls_overflow_(false),
in_overflow_relayout_(false),
@@ -134,11 +136,14 @@ PaintLayerScrollableArea::PaintLayerScrollableArea(PaintLayer& layer)
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) {
+ 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()) {
// We save and restore only the scrollOffset as the other scroll values are
@@ -156,8 +161,8 @@ PaintLayerScrollableArea::~PaintLayerScrollableArea() {
DCHECK(HasBeenDisposed());
}
-void PaintLayerScrollableArea::DidScroll(const gfx::ScrollOffset& offset) {
- ScrollableArea::DidScroll(offset);
+void PaintLayerScrollableArea::DidScroll(const FloatPoint& position) {
+ ScrollableArea::DidScroll(position);
// This should be alive if it receives composited scroll callbacks.
CHECK(!HasBeenDisposed());
}
@@ -216,16 +221,6 @@ void PaintLayerScrollableArea::Dispose() {
if (SmoothScrollSequencer* sequencer = GetSmoothScrollSequencer())
sequencer->DidDisposeScrollableArea(*this);
- {
- // Here using the stale compositing data is in fact what we want to do
- // because the graphics layer which hasn't been removed yet may be used in
- // the meantime to try to deliver scroll related updates.
- DisableCompositingQueryAsserts disabler;
- GraphicsLayer* graphics_layer = LayerForScrolling();
- if (graphics_layer)
- graphics_layer->ScrollableAreaDisposed();
- }
-
layer_ = nullptr;
}
@@ -239,24 +234,11 @@ void PaintLayerScrollableArea::Trace(blink::Visitor* visitor) {
ScrollableArea::Trace(visitor);
}
-void PaintLayerScrollableArea::CalculateScrollbarModes(
- ScrollbarMode& h_mode,
- ScrollbarMode& v_mode) const {
- DCHECK(GetLayoutBox()->IsLayoutView());
-
- // FrameViewAutoSizeInfo manually controls the appearance of the main frame's
- // scrollbars so defer to those if we're in AutoSize mode.
- if (AutosizeVerticalScrollbarMode() != kScrollbarAuto ||
- AutosizeHorizontalScrollbarMode() != kScrollbarAuto) {
- h_mode = AutosizeHorizontalScrollbarMode();
- v_mode = AutosizeVerticalScrollbarMode();
- return;
- }
-
- ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
+bool PaintLayerScrollableArea::IsThrottled() const {
+ return GetLayoutBox()->GetFrame()->ShouldThrottleRendering();
}
-ChromeClient* PaintLayerScrollableArea::GetChromeClient() const {
+PlatformChromeClient* PaintLayerScrollableArea::GetChromeClient() const {
if (HasBeenDisposed())
return nullptr;
if (Page* page = GetLayoutBox()->GetFrame()->GetPage())
@@ -681,9 +663,10 @@ IntRect PaintLayerScrollableArea::VisibleContentRect(
GetLayoutBox()->Location()));
}
-LayoutRect PaintLayerScrollableArea::VisibleScrollSnapportRect() const {
+LayoutRect PaintLayerScrollableArea::VisibleScrollSnapportRect(
+ IncludeScrollbarsInRect scrollbar_inclusion) const {
const ComputedStyle* style = GetLayoutBox()->Style();
- LayoutRect layout_content_rect(LayoutContentRect(kExcludeScrollbars));
+ LayoutRect layout_content_rect(LayoutContentRect(scrollbar_inclusion));
layout_content_rect.MoveBy(LayoutPoint(-ScrollOrigin()));
LayoutRectOutsets padding(MinimumValueForLength(style->ScrollPaddingTop(),
layout_content_rect.Height()),
@@ -707,10 +690,6 @@ void PaintLayerScrollableArea::ContentsResized() {
GetLayoutBox()->SetNeedsPaintPropertyUpdate();
}
-bool PaintLayerScrollableArea::IsScrollable() const {
- return ScrollsOverflow();
-}
-
IntPoint PaintLayerScrollableArea::LastKnownMousePosition() const {
return GetLayoutBox()->GetFrame() ? GetLayoutBox()
->GetFrame()
@@ -733,7 +712,7 @@ bool PaintLayerScrollableArea::ShouldSuspendScrollAnimations() const {
LayoutView* view = GetLayoutBox()->View();
if (!view)
return true;
- return view->GetFrameView()->ShouldSuspendScrollAnimations();
+ return !GetLayoutBox()->GetDocument().LoadEventFinished();
}
void PaintLayerScrollableArea::ScrollbarVisibilityChanged() {
@@ -760,13 +739,20 @@ bool PaintLayerScrollableArea::ScrollbarsCanBeActive() const {
LayoutView* view = GetLayoutBox()->View();
if (!view)
return false;
- return view->GetFrameView()->ScrollbarsCanBeActive();
+
+ // TODO(szager): This conditional is weird and likely obsolete. Originally
+ // added in commit eb0d49caaee2b275ff524d3945a74e8d9180eb7d.
+ LocalFrameView* frame_view = view->GetFrameView();
+ if (frame_view != frame_view->GetFrame().View())
+ return false;
+
+ 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()->AbsoluteToRootFrame(
+ return local_root->RootFrameToDocument(frame->View()->ConvertToRootFrame(
GetLayoutBox()->AbsoluteBoundingBoxRect(0)));
}
}
@@ -804,7 +790,7 @@ bool PaintLayerScrollableArea::UserInputScrollable(
ScrollbarMode h_mode;
ScrollbarMode v_mode;
- CalculateScrollbarModes(h_mode, v_mode);
+ ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
ScrollbarMode mode =
(orientation == kHorizontalScrollbar) ? h_mode : v_mode;
return mode == kScrollbarAuto || mode == kScrollbarAlwaysOn;
@@ -823,12 +809,16 @@ bool PaintLayerScrollableArea::ShouldPlaceVerticalScrollbarOnLeft() const {
}
int PaintLayerScrollableArea::PageStep(ScrollbarOrientation orientation) const {
- int length =
- (orientation == kHorizontalScrollbar) ? VisibleWidth() : VisibleHeight();
+ // Paging scroll operations should take scroll-padding into account [1]. So we
+ // 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();
int min_page_step = static_cast<float>(length) *
ScrollableArea::MinFractionToStepWhenPaging();
int page_step = max(min_page_step, length - MaxOverlapBetweenPages());
-
return max(page_step, 1);
}
@@ -866,8 +856,11 @@ void PaintLayerScrollableArea::UpdateScrollOrigin() {
LayoutRect scrollable_overflow(overflow_rect_);
scrollable_overflow.Move(-GetLayoutBox()->BorderLeft(),
-GetLayoutBox()->BorderTop());
- SetScrollOrigin(-scrollable_overflow.PixelSnappedLocation() +
- GetLayoutBox()->OriginAdjustmentForScrollbars());
+ IntPoint new_origin(-scrollable_overflow.PixelSnappedLocation() +
+ GetLayoutBox()->OriginAdjustmentForScrollbars());
+ if (new_origin != scroll_origin_)
+ scroll_origin_changed_ = true;
+ scroll_origin_ = new_origin;
}
void PaintLayerScrollableArea::UpdateScrollDimensions() {
@@ -1039,6 +1032,9 @@ void PaintLayerScrollableArea::UpdateAfterLayout() {
}
void PaintLayerScrollableArea::ClampScrollOffsetAfterOverflowChange() {
+ if (HasBeenDisposed())
+ return;
+
// If a vertical scrollbar was removed, the min/max scroll offsets may have
// changed, so the scroll offsets needs to be clamped. If the scroll offset
// did not change, but the scroll origin *did* change, we still need to notify
@@ -1229,13 +1225,8 @@ void PaintLayerScrollableArea::UpdateAfterStyleChange(
UpdateResizerStyle(old_style);
}
-bool PaintLayerScrollableArea::UpdateAfterCompositingChange() {
+void PaintLayerScrollableArea::UpdateAfterCompositingChange() {
Layer()->UpdateScrollingStateAfterCompositingChange();
- const bool layers_changed =
- topmost_scroll_child_ != next_topmost_scroll_child_;
- topmost_scroll_child_ = next_topmost_scroll_child_;
- next_topmost_scroll_child_ = nullptr;
- return layers_changed;
}
void PaintLayerScrollableArea::UpdateAfterOverflowRecalc() {
@@ -1340,43 +1331,63 @@ IntSize PaintLayerScrollableArea::ScrollbarOffset(
}
static inline const LayoutObject& ScrollbarStyleSource(
- const LayoutObject& layout_object) {
- if (Node* node = layout_object.GetNode()) {
- if (layout_object.IsLayoutView()) {
- Document& doc = node->GetDocument();
- if (Settings* settings = doc.GetSettings()) {
- if (!settings->GetAllowCustomScrollbarInMainFrame() &&
- layout_object.GetFrame() && layout_object.GetFrame()->IsMainFrame())
- return layout_object;
- }
-
- // Try the <body> element first as a scrollbar source.
- Element* body = doc.body();
- if (body && body->GetLayoutObject() &&
- body->GetLayoutObject()->Style()->HasPseudoStyle(kPseudoIdScrollbar))
- 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))
- return *doc_element->GetLayoutObject();
+ 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;
}
- if (layout_object.StyleRef().HasPseudoStyle(kPseudoIdScrollbar))
- return layout_object;
+ // Try the <body> element first 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))
+ return *body->GetLayoutObject();
- if (ShadowRoot* shadow_root = node->ContainingShadowRoot()) {
- if (shadow_root->IsUserAgent()) {
- if (LayoutObject* host_layout_object =
- shadow_root->host().GetLayoutObject())
- return *host_layout_object;
- }
- }
+ // 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))
+ return *doc_element->GetLayoutObject();
+ }
+
+ return layout_box;
+}
+
+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);
}
- return layout_object;
+ 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);
}
bool PaintLayerScrollableArea::NeedsScrollbarReconstruction() const {
@@ -1401,8 +1412,10 @@ bool PaintLayerScrollableArea::NeedsScrollbarReconstruction() const {
if (needs_custom) {
DCHECK(scrollbar->IsCustomScrollbar());
// We have a custom scrollbar with a stale m_owner.
- if (ToLayoutScrollbar(scrollbar)->StyleSource() != style_source)
+ if (ToLayoutScrollbar(scrollbar)->StyleSource()->GetLayoutObject() !=
+ style_source) {
return true;
+ }
// Should use custom scrollbar and nothing should change.
continue;
@@ -1456,7 +1469,7 @@ void PaintLayerScrollableArea::ComputeScrollbarExistence(
if (GetLayoutBox()->IsLayoutView()) {
ScrollbarMode h_mode;
ScrollbarMode v_mode;
- CalculateScrollbarModes(h_mode, v_mode);
+ ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
// Look for the scrollbarModes and reset the needs Horizontal & vertical
// Scrollbar values based on scrollbarModes, as during force style change
@@ -1488,7 +1501,7 @@ bool PaintLayerScrollableArea::TryRemovingAutoScrollbars(
if (GetLayoutBox()->IsLayoutView()) {
ScrollbarMode h_mode;
ScrollbarMode v_mode;
- CalculateScrollbarModes(h_mode, v_mode);
+ ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
if (h_mode != kScrollbarAuto || v_mode != kScrollbarAuto)
return false;
@@ -1608,7 +1621,7 @@ int PaintLayerScrollableArea::HorizontalScrollbarHeight(
return HorizontalScrollbar()->ScrollbarThickness();
}
-void PaintLayerScrollableArea::SnapAfterScrollbarDragging(
+void PaintLayerScrollableArea::SnapAfterScrollbarScrolling(
ScrollbarOrientation orientation) {
SnapCoordinator* snap_coordinator =
GetLayoutBox()->GetDocument().GetSnapCoordinator();
@@ -1772,8 +1785,8 @@ bool PaintLayerScrollableArea::IsPointInResizeControl(
if (!GetLayoutBox()->CanResize())
return false;
- IntPoint local_point = RoundedIntPoint(
- GetLayoutBox()->AbsoluteToLocal(absolute_point, kUseTransforms));
+ 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);
@@ -1901,8 +1914,8 @@ IntSize PaintLayerScrollableArea::OffsetFromResizeCorner(
if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
element_size.SetWidth(0);
IntPoint resizer_point = IntPoint(element_size);
- IntPoint local_point = RoundedIntPoint(
- GetLayoutBox()->AbsoluteToLocal(absolute_point, kUseTransforms));
+ IntPoint local_point = RoundedIntPoint(GetLayoutBox()->AbsoluteToLocal(
+ FloatPoint(absolute_point), kUseTransforms));
return local_point - resizer_point;
}
@@ -1935,7 +1948,7 @@ void PaintLayerScrollableArea::Resize(const IntPoint& pos,
float zoom_factor = GetLayoutBox()->Style()->EffectiveZoom();
IntSize new_offset =
- OffsetFromResizeCorner(document.View()->RootFrameToContents(pos));
+ OffsetFromResizeCorner(document.View()->ConvertFromRootFrame(pos));
new_offset.SetWidth(new_offset.Width() / zoom_factor);
new_offset.SetHeight(new_offset.Height() / zoom_factor);
@@ -2081,7 +2094,7 @@ void PaintLayerScrollableArea::UpdateScrollableAreaSet() {
if (GetLayoutBox()->IsLayoutView()) {
ScrollbarMode h_mode;
ScrollbarMode v_mode;
- CalculateScrollbarModes(h_mode, v_mode);
+ ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
if (h_mode == kScrollbarAlwaysOff && v_mode == kScrollbarAlwaysOff)
has_overflow = false;
}
@@ -2204,8 +2217,13 @@ bool PaintLayerScrollableArea::ComputeNeedsCompositedScrolling(
if (CompositingReasonFinder::RequiresCompositingForRootScroller(*layer))
return true;
- if (!layer->ScrollsOverflow())
+ // 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;
@@ -2229,7 +2247,10 @@ bool PaintLayerScrollableArea::ComputeNeedsCompositedScrolling(
ToLayoutBox(layer->GetLayoutObject()).PaddingBoxRect()) &&
!layer->CompositesWithTransform() && !layer->CompositesWithOpacity();
- if (!layer_has_been_composited &&
+ // 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()) {
@@ -2276,14 +2297,6 @@ void PaintLayerScrollableArea::UpdateNeedsCompositedScrolling(
}
}
-void PaintLayerScrollableArea::SetTopmostScrollChild(PaintLayer* scroll_child) {
- // We only want to track the topmost scroll child for scrollable areas with
- // overlay scrollbars.
- if (!HasOverlayScrollbars())
- return;
- next_topmost_scroll_child_ = scroll_child;
-}
-
bool PaintLayerScrollableArea::VisualViewportSuppliesScrollbars() const {
LocalFrame* frame = GetLayoutBox()->GetFrame();
if (!frame || !frame->GetSettings())
@@ -2301,7 +2314,7 @@ bool PaintLayerScrollableArea::VisualViewportSuppliesScrollbars() const {
}
bool PaintLayerScrollableArea::ScheduleAnimation() {
- if (ChromeClient* client = GetChromeClient()) {
+ if (ChromeClient* client = ToChromeClient(GetChromeClient())) {
client->ScheduleAnimation(GetLayoutBox()->GetFrame()->View());
return true;
}
@@ -2326,26 +2339,8 @@ PaintLayerScrollableArea::GetCompositorAnimationTimeline() const {
}
void PaintLayerScrollableArea::GetTickmarks(Vector<IntRect>& tickmarks) const {
- if (layer_->IsRootLayer()) {
- tickmarks = GetLayoutBox()
- ->GetDocument()
- .Markers()
- .LayoutRectsForTextMatchMarkers();
- }
-}
-
-PaintLayerScrollableArea*
-PaintLayerScrollableArea::ScrollbarManager::ScrollableArea() {
- return ToPaintLayerScrollableArea(scrollable_area_.Get());
-}
-
-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);
+ if (layer_->IsRootLayer())
+ tickmarks = ToLayoutView(GetLayoutBox())->GetTickmarks();
}
void PaintLayerScrollableArea::ScrollbarManager::SetHasHorizontalScrollbar(
@@ -2396,7 +2391,6 @@ Scrollbar* PaintLayerScrollableArea::ScrollbarManager::CreateScrollbar(
const LayoutObject& style_source =
ScrollbarStyleSource(*ScrollableArea()->GetLayoutBox());
bool has_custom_scrollbar_style =
- style_source.IsBox() &&
style_source.StyleRef().HasPseudoStyle(kPseudoIdScrollbar);
if (has_custom_scrollbar_style) {
DCHECK(style_source.GetNode() && style_source.GetNode()->IsElementNode());
@@ -2444,6 +2438,28 @@ void PaintLayerScrollableArea::ScrollbarManager::DestroyScrollbar(
scrollbar = nullptr;
}
+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);
+}
+
+void PaintLayerScrollableArea::ScrollbarManager::Dispose() {
+ h_bar_is_attached_ = v_bar_is_attached_ = 0;
+ DestroyScrollbar(kHorizontalScrollbar);
+ DestroyScrollbar(kVerticalScrollbar);
+}
+
+void PaintLayerScrollableArea::ScrollbarManager::Trace(
+ blink::Visitor* visitor) {
+ visitor->Trace(scrollable_area_);
+ visitor->Trace(h_bar_);
+ visitor->Trace(v_bar_);
+}
+
uint64_t PaintLayerScrollableArea::Id() const {
return DOMNodeIds::IdForNode(GetLayoutBox()->GetNode());
}
@@ -2568,4 +2584,246 @@ ScrollbarTheme& PaintLayerScrollableArea::GetPageScrollbarTheme() const {
return page->GetScrollbarTheme();
}
+void PaintLayerScrollableArea::WillRemoveScrollbar(
+ Scrollbar& scrollbar,
+ ScrollbarOrientation orientation) {
+ if (!scrollbar.IsCustomScrollbar() &&
+ !(orientation == kHorizontalScrollbar ? LayerForHorizontalScrollbar()
+ : LayerForVerticalScrollbar())) {
+ ObjectPaintInvalidator(*GetLayoutBox())
+ .SlowSetPaintingLayerNeedsRepaintAndInvalidateDisplayItemClient(
+ scrollbar, PaintInvalidationReason::kScrollControl);
+ }
+
+ 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()) {
+ DCHECK(new_visual_rect.IsEmpty());
+ // Do not issue an empty invalidation.
+ should_invalidate_new_rect = false;
+ }
+
+ return should_invalidate_new_rect;
+}
+
+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;
+ // 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());
+ }
+
+ // 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;
+ 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();
+
+ // The IsEmpty() check avoids invalidaiton in cases when the visual rect
+ // changes from (0,0 0x0) to (0,0 0x100).
+ 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;
+}
+
+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();
+}
+
+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();
+}
+
+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);
+}
+
+CompositorElementId PaintLayerScrollableArea::GetCompositorElementId() const {
+ return CompositorElementIdFromUniqueObjectId(
+ GetLayoutBox()->UniqueId(), CompositorElementIdNamespace::kScroll);
+}
+
} // namespace blink