#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/content_capture/content_capture_manager.h"
+#include "third_party/blink/renderer/core/css/color_scheme_flags.h"
#include "third_party/blink/renderer/core/css/style_request.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
#include "third_party/blink/renderer/core/layout/custom_scrollbar.h"
#include "third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
-#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/paint/paint_layer_fragment.h"
#include "third_party/blink/renderer/core/scroll/scroll_alignment.h"
#include "third_party/blink/renderer/core/scroll/scroll_animator_base.h"
+#include "third_party/blink/renderer/core/scroll/scrollable_area.h"
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
#include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
+#include "third_party/blink/renderer/core/view_transition/view_transition.h"
+#include "third_party/blink/renderer/core/view_transition/view_transition_utils.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "ui/base/ui_base_features.h"
namespace blink {
-namespace {
-
-// Default value is set to 15 as the default
-// minimum size used by firefox is 15x15.
-static const int kDefaultMinimumWidthForResizing = 15;
-static const int kDefaultMinimumHeightForResizing = 15;
-
-} // namespace
-
PaintLayerScrollableAreaRareData::PaintLayerScrollableAreaRareData() = default;
void PaintLayerScrollableAreaRareData::Trace(Visitor* visitor) const {
visitor->Trace(sticky_layers_);
- visitor->Trace(anchor_positioned_layers_);
}
const int kResizerControlExpandRatioForTouch = 2;
layer_(&layer),
in_resize_mode_(false),
scrolls_overflow_(false),
- in_overflow_relayout_(false),
- allow_second_overflow_relayout_(false),
- needs_composited_scrolling_(false),
needs_scroll_offset_clamp_(false),
needs_relayout_(false),
had_horizontal_scrollbar_before_relayout_(false),
is_scrollbar_freeze_root_(false),
is_horizontal_scrollbar_frozen_(false),
is_vertical_scrollbar_frozen_(false),
+ should_scroll_on_main_thread_(true),
scrollbar_manager_(*this),
has_last_committed_scroll_offset_(false),
scroll_corner_(nullptr),
resizer_(nullptr),
- scroll_anchor_(this),
- non_composited_main_thread_scrolling_reasons_(0) {
+ scroll_anchor_(this) {
if (auto* element = DynamicTo<Element>(GetLayoutBox()->GetNode())) {
// We save and restore only the scrollOffset as the other scroll values are
// recalculated.
element->SetSavedLayerScrollOffset(ScrollOffset());
}
- GetLayoutBox()->GetDocument().GetSnapCoordinator().AddSnapContainer(
- *GetLayoutBox());
+ if (!RuntimeEnabledFeatures::LayoutNewSnapLogicEnabled()) {
+ GetLayoutBox()->GetDocument().GetSnapCoordinator().AddSnapContainer(
+ *GetLayoutBox());
+ }
}
PaintLayerScrollableArea::~PaintLayerScrollableArea() {
void PaintLayerScrollableArea::DisposeImpl() {
rare_data_.Clear();
- GetLayoutBox()->GetDocument().GetSnapCoordinator().RemoveSnapContainer(
- *GetLayoutBox());
+ if (!RuntimeEnabledFeatures::LayoutNewSnapLogicEnabled()) {
+ GetLayoutBox()->GetDocument().GetSnapCoordinator().RemoveSnapContainer(
+ *GetLayoutBox());
+ }
if (InResizeMode() && !GetLayoutBox()->DocumentBeingDestroyed()) {
if (LocalFrame* frame = GetLayoutBox()->GetFrame())
frame_view->RemoveScrollAnchoringScrollableArea(this);
frame_view->RemoveUserScrollableArea(this);
frame_view->RemoveAnimatingScrollableArea(this);
+ if (RuntimeEnabledFeatures::LayoutNewSnapLogicEnabled()) {
+ frame_view->RemovePendingSnapUpdate(this);
+ }
}
}
- non_composited_main_thread_scrolling_reasons_ = 0;
-
if (!GetLayoutBox()->DocumentBeingDestroyed()) {
if (auto* element = DynamicTo<Element>(GetLayoutBox()->GetNode()))
element->SetSavedLayerScrollOffset(scroll_offset_);
if (SmoothScrollSequencer* sequencer = GetSmoothScrollSequencer())
sequencer->DidDisposeScrollableArea(*this);
- RunScrollCompleteCallbacks();
- InvalidateScrollTimeline();
+ RunScrollCompleteCallbacks(ScrollableArea::ScrollCompletionMode::kFinished);
layer_ = nullptr;
}
if (HasBeenDisposed())
return nullptr;
- return &GetLayoutBox()->GetFrame()->GetSmoothScrollSequencer();
+ return GetLayoutBox()->GetFrame()->GetSmoothScrollSequencer();
}
bool PaintLayerScrollableArea::IsActive() const {
TRACE_EVENT_INSTANT1("blink", "Type", TRACE_EVENT_SCOPE_THREAD, "type",
scroll_type);
+ LocalFrameView* frame_view = GetLayoutBox()->GetFrameView();
+ CHECK(frame_view);
+
+ // The ScrollOffsetTranslation paint property depends on the scroll offset.
+ // (see: PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation).
+ // Intersection observation cached rects affected by the scroll are not
+ // invalidated because it's hard to find all of them. Validity of cached
+ // rects is checked in IntersectionGeometry::PrepareComputeGeometry().
+ GetLayoutBox()->SetNeedsPaintPropertyUpdatePreservingCachedRects();
+ frame_view->UpdateIntersectionObservationStateOnScroll(new_offset -
+ scroll_offset_);
+
scroll_offset_ = new_offset;
LocalFrame* frame = GetLayoutBox()->GetFrame();
DCHECK(frame);
- LocalFrameView* frame_view = GetLayoutBox()->GetFrameView();
bool is_root_layer = Layer()->IsRootLayer();
DEVTOOLS_TIMELINE_TRACE_EVENT(
if (auto* scrolling_coordinator = GetScrollingCoordinator()) {
if (!scrolling_coordinator->UpdateCompositorScrollOffset(*frame, *this)) {
- GetLayoutBox()->GetFrameView()->SetPaintArtifactCompositorNeedsUpdate(
- PaintArtifactCompositorUpdateReason::
- kPaintLayerScrollableAreaUpdateScrollOffset);
+ GetLayoutBox()->GetFrameView()->SetPaintArtifactCompositorNeedsUpdate();
}
}
- // The ScrollOffsetTranslation paint property depends on the scroll offset.
- // (see: PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation).
- GetLayoutBox()->SetNeedsPaintPropertyUpdatePreservingCachedRects();
- InvalidateScrollTimeline();
-
if (scroll_type == mojom::blink::ScrollType::kUser ||
scroll_type == mojom::blink::ScrollType::kCompositor) {
Page* page = frame->GetPage();
if (FragmentAnchor* anchor = frame_view->GetFragmentAnchor())
anchor->DidScroll(scroll_type);
- if (IsExplicitScrollType(scroll_type)) {
- if (scroll_type != mojom::blink::ScrollType::kCompositor)
- ShowNonMacOverlayScrollbars();
+ if (IsExplicitScrollType(scroll_type) ||
+ scroll_type == mojom::blink::ScrollType::kScrollStart) {
+ ShowNonMacOverlayScrollbars();
GetScrollAnchor()->Clear();
}
if (ContentCaptureManager* manager = frame_view->GetFrame()
void PaintLayerScrollableArea::InvalidatePaintForScrollOffsetChange() {
InvalidatePaintForStickyDescendants();
- InvalidatePaintForAnchorPositionedLayers();
auto* box = GetLayoutBox();
auto* frame_view = box->GetFrameView();
frame_view->InvalidateBackgroundAttachmentFixedDescendantsOnScroll(*box);
+ if (!box->BackgroundNeedsFullPaintInvalidation() &&
+ BackgroundNeedsRepaintOnScroll()) {
+ box->SetBackgroundNeedsFullPaintInvalidation();
+ }
- // TODO(chrishtr): remove this slow path once crbug.com/906885 is fixed.
- // See also https://bugs.chromium.org/p/chromium/issues/detail?id=903287#c10.
- if (Layer()->EnclosingPaginationLayer())
- box->SetSubtreeShouldCheckForPaintInvalidation();
-
- if (!box->BackgroundNeedsFullPaintInvalidation()) {
- auto background_paint_location = box->GetBackgroundPaintLocation();
- bool background_paint_in_border_box =
- background_paint_location & kBackgroundPaintInBorderBoxSpace;
- bool background_paint_in_scrolling_contents =
- background_paint_location & kBackgroundPaintInContentsSpace;
-
- // Invalidate background on scroll if needed.
- // Fixed attachment background has been dealt with in
- // frame_view->InvalidateBackgroundAttachmentFixedDescendantsOnScroll().
- const auto& background_layers = box->StyleRef().BackgroundLayers();
- if (background_layers.AnyLayerHasLocalAttachmentImage() &&
- background_paint_in_border_box) {
- // Local-attachment background image scrolls, so needs invalidation if it
- // paints in non-scrolling space.
- box->SetBackgroundNeedsFullPaintInvalidation();
- } else if (background_layers.AnyLayerHasDefaultAttachmentImage() &&
- background_paint_in_scrolling_contents) {
- // Normal attachment background image doesn't scroll, so needs
- // invalidation if it paints in scrolling contents.
- box->SetBackgroundNeedsFullPaintInvalidation();
- } else if (background_layers.AnyLayerHasLocalAttachment() &&
- background_layers.AnyLayerUsesContentBox() &&
- background_paint_in_border_box &&
- (box->PaddingLeft() || box->PaddingTop() ||
- box->PaddingRight() || box->PaddingBottom())) {
- // Local attachment content box background needs invalidation if there is
- // padding because the content area can change on scroll (e.g. the top
- // padding can disappear when the box scrolls to the bottom).
- box->SetBackgroundNeedsFullPaintInvalidation();
+ if (auto* compositor = frame_view->GetPaintArtifactCompositor()) {
+ if (compositor->ShouldAlwaysUpdateOnScroll()) {
+ compositor->SetNeedsUpdate();
}
}
}
+// See the comment in .h about background-attachment:fixed.
+bool PaintLayerScrollableArea::BackgroundNeedsRepaintOnScroll() const {
+ const auto* box = GetLayoutBox();
+ auto background_paint_location = box->GetBackgroundPaintLocation();
+ bool background_paint_in_border_box =
+ background_paint_location & kBackgroundPaintInBorderBoxSpace;
+ bool background_paint_in_scrolling_contents =
+ background_paint_location & kBackgroundPaintInContentsSpace;
+
+ const auto& background_layers = box->StyleRef().BackgroundLayers();
+ if (background_layers.AnyLayerHasLocalAttachmentImage() &&
+ background_paint_in_border_box) {
+ // Local-attachment background image scrolls, so needs invalidation if it
+ // paints in non-scrolling space.
+ return true;
+ }
+ if (background_layers.AnyLayerHasDefaultAttachmentImage() &&
+ background_paint_in_scrolling_contents) {
+ // Normal attachment background image doesn't scroll, so needs
+ // invalidation if it paints in scrolling contents.
+ return true;
+ }
+ if (background_layers.AnyLayerHasLocalAttachment() &&
+ background_layers.AnyLayerUsesContentBox() &&
+ background_paint_in_border_box &&
+ (box->PaddingLeft() || box->PaddingTop() || box->PaddingRight() ||
+ box->PaddingBottom())) {
+ // Local attachment content box background needs invalidation if there is
+ // padding because the content area can change on scroll (e.g. the top
+ // padding can disappear when the box scrolls to the bottom).
+ return true;
+ }
+ return false;
+}
+
gfx::Vector2d PaintLayerScrollableArea::ScrollOffsetInt() const {
return gfx::ToFlooredVector2d(scroll_offset_);
}
if (this == controller.RootScrollerArea()) {
visible_size = controller.RootScrollerVisibleArea();
} else {
- visible_size = ToPixelSnappedRect(GetLayoutBox()->OverflowClipRect(
- GetLayoutBox()->Location(),
- kIgnoreOverlayScrollbarSize))
- .size();
+ visible_size = ToRoundedSize(
+ GetLayoutBox()
+ ->OverflowClipRect(PhysicalOffset(), kIgnoreOverlayScrollbarSize)
+ .size);
}
// TODO(skobes): We should really ASSERT that contentSize >= visibleSize
}
void PaintLayerScrollableArea::VisibleSizeChanged() {
- InvalidateScrollTimeline();
ShowNonMacOverlayScrollbars();
}
PhysicalRect PaintLayerScrollableArea::LayoutContentRect(
IncludeScrollbarsInRect scrollbar_inclusion) const {
// LayoutContentRect is conceptually the same as the box's client rect.
- LayoutSize layer_size(Layer()->Size());
+ PhysicalSize layer_size = Size();
LayoutUnit border_width = GetLayoutBox()->BorderWidth();
LayoutUnit border_height = GetLayoutBox()->BorderHeight();
- NGPhysicalBoxStrut scrollbars;
+ PhysicalBoxStrut scrollbars;
if (scrollbar_inclusion == kExcludeScrollbars)
scrollbars = GetLayoutBox()->ComputeScrollbars();
PhysicalSize size(
- layer_size.Width() - border_width - scrollbars.HorizontalSum(),
- layer_size.Height() - border_height - scrollbars.VerticalSum());
+ layer_size.width - border_width - scrollbars.HorizontalSum(),
+ layer_size.height - border_height - scrollbars.VerticalSum());
size.ClampNegativeToZero();
return PhysicalRect(PhysicalOffset::FromPointFRound(ScrollPosition()), size);
}
PhysicalRect layout_content_rect(LayoutContentRect(scrollbar_inclusion));
// TODO(szager): It's not clear that Floor() is the right thing to do here;
// what is the correct behavior for fractional scroll offsets?
- return gfx::Rect(ToFlooredPoint(layout_content_rect.offset),
- ToPixelSnappedSize(layout_content_rect.size.ToLayoutSize(),
- GetLayoutBox()->Location()));
+ gfx::Size size = ToRoundedSize(layout_content_rect.size);
+ return gfx::Rect(ToFlooredPoint(layout_content_rect.offset), size);
}
PhysicalRect PaintLayerScrollableArea::VisibleScrollSnapportRect(
const ComputedStyle* style = GetLayoutBox()->Style();
PhysicalRect layout_content_rect(LayoutContentRect(scrollbar_inclusion));
layout_content_rect.Move(PhysicalOffset(-ScrollOrigin().OffsetFromOrigin()));
- 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()));
+ PhysicalBoxStrut padding(MinimumValueForLength(style->ScrollPaddingTop(),
+ layout_content_rect.Height()),
+ MinimumValueForLength(style->ScrollPaddingRight(),
+ layout_content_rect.Width()),
+ MinimumValueForLength(style->ScrollPaddingBottom(),
+ layout_content_rect.Height()),
+ MinimumValueForLength(style->ScrollPaddingLeft(),
+ layout_content_rect.Width()));
layout_content_rect.Contract(padding);
return layout_content_rect;
}
gfx::Size PaintLayerScrollableArea::ContentsSize() const {
- LayoutPoint location = GetLayoutBox()->Location();
- PhysicalOffset offset(GetLayoutBox()->ClientLeft() + location.X(),
- GetLayoutBox()->ClientTop() + location.Y());
+ // We need to take into account of ClientLeft and ClientTop for
+ // PaintLayerScrollableAreaTest.NotScrollsOverflowWithScrollableScrollbar.
+ PhysicalOffset offset(GetLayoutBox()->ClientLeft(),
+ GetLayoutBox()->ClientTop());
// TODO(crbug.com/962299): The pixel snapping is incorrect in some cases.
return PixelSnappedContentsSize(offset);
}
gfx::Size PaintLayerScrollableArea::PixelSnappedContentsSize(
const PhysicalOffset& paint_offset) const {
- return ToPixelSnappedRect(PhysicalRect(paint_offset, overflow_rect_.size))
- .size();
+ PhysicalSize size = overflow_rect_.size;
+
+ // If we're capturing a transition snapshot, ensure the content size is
+ // considered at least as large as the container. Otherwise, the snapshot
+ // will be clipped by PendingLayer to the content size.
+ if (IsA<LayoutView>(GetLayoutBox())) {
+ if (auto* transition =
+ ViewTransitionUtils::GetTransition(GetLayoutBox()->GetDocument());
+ transition && transition->IsRootTransitioning()) {
+ PhysicalSize container_size(transition->GetSnapshotRootSize());
+ size.width = std::max(container_size.width, size.width);
+ size.height = std::max(container_size.height, size.height);
+ }
+ }
+
+ return ToPixelSnappedRect(PhysicalRect(paint_offset, size)).size();
}
void PaintLayerScrollableArea::ContentsResized() {
// Need to update the bounds of the scroll property.
GetLayoutBox()->SetNeedsPaintPropertyUpdate();
Layer()->SetNeedsCompositingInputsUpdate();
- InvalidateScrollTimeline();
}
gfx::Point PaintLayerScrollableArea::LastKnownMousePosition() const {
}
void PaintLayerScrollableArea::ScrollbarFrameRectChanged() {
+ // TODO(crbug.com/1020913): This should be called only from layout once the
+ // bug is fixed.
+
// Size of non-overlay scrollbar affects overflow clip rect. size of overlay
// scrollbar effects hit testing rect excluding overlay scrollbars.
+ if (GetDocument()->Lifecycle().GetState() == DocumentLifecycle::kInPrePaint) {
+ // In pre-paint we avoid marking the ancestor chain as this might cause
+ // problems, see https://crbug.com/1377634. Note that we do not have
+ // automated test case for this, so if you when modifying this code, please
+ // verify that the test cases on the bug do not crash.
+ GetLayoutBox()
+ ->GetMutableForPainting()
+ .SetOnlyThisNeedsPaintPropertyUpdate();
+ return;
+ }
+
GetLayoutBox()->SetNeedsPaintPropertyUpdate();
}
}
PaintLayer* PaintLayerScrollableArea::Layer() const {
- return layer_;
+ return layer_.Get();
+}
+
+PhysicalSize PaintLayerScrollableArea::Size() const {
+ return layer_->IsRootLayer()
+ ? PhysicalSize(GetLayoutBox()->GetFrameView()->Size())
+ : GetLayoutBox()->Size();
}
LayoutUnit PaintLayerScrollableArea::ScrollWidth() const {
void PaintLayerScrollableArea::UpdateAfterLayout() {
InvalidateAllStickyConstraints();
- InvalidateAllAnchorPositionedLayers();
- bool is_horizontal_scrollbar_frozen;
- bool is_vertical_scrollbar_frozen;
- if (in_overflow_relayout_ && !allow_second_overflow_relayout_) {
- is_horizontal_scrollbar_frozen = is_vertical_scrollbar_frozen = true;
- } else {
- is_horizontal_scrollbar_frozen = IsHorizontalScrollbarFrozen();
- is_vertical_scrollbar_frozen = IsVerticalScrollbarFrozen();
- }
- allow_second_overflow_relayout_ = false;
+ bool is_horizontal_scrollbar_frozen = IsHorizontalScrollbarFrozen();
+ bool is_vertical_scrollbar_frozen = IsVerticalScrollbarFrozen();
if (NeedsScrollbarReconstruction()) {
RemoveScrollbarsForReconstruction();
ComputeScrollbarExistence(needs_horizontal_scrollbar,
needs_vertical_scrollbar);
- // Removing auto scrollbars is a heuristic and can be incorrect if the content
- // size depends on the scrollbar size (e.g., sized with percentages). Removing
- // scrollbars can require two additional layout passes so this is only done on
- // the first layout (!in_overflow_layout).
- if (!in_overflow_relayout_ && !is_horizontal_scrollbar_frozen &&
- !is_vertical_scrollbar_frozen &&
+ if (!is_horizontal_scrollbar_frozen && !is_vertical_scrollbar_frozen &&
TryRemovingAutoScrollbars(needs_horizontal_scrollbar,
needs_vertical_scrollbar)) {
needs_horizontal_scrollbar = needs_vertical_scrollbar = false;
- allow_second_overflow_relayout_ = true;
}
bool horizontal_scrollbar_should_change =
!GetLayoutBox()->IsHorizontalWritingMode())) {
GetLayoutBox()->SetIntrinsicLogicalWidthsDirty();
}
- if (IsManagedByLayoutNG(*GetLayoutBox())) {
- // If the box is managed by LayoutNG, don't go here. We don't want to
- // re-enter the NG layout algorithm for this box from here. Just update
- // the rectangles, in case scrollbars were added or removed. LayoutNG
- // has its own scrollbar change detection mechanism.
- UpdateScrollDimensions();
- } else {
- if (PreventRelayoutScope::RelayoutIsPrevented()) {
- // We're not doing re-layout right now, but we still want to
- // add the scrollbar to the logical width now, to facilitate parent
- // layout.
- GetLayoutBox()->UpdateLogicalWidth();
- PreventRelayoutScope::SetBoxNeedsLayout(
- *this, had_horizontal_scrollbar, had_vertical_scrollbar);
- } else {
- in_overflow_relayout_ = true;
- SubtreeLayoutScope layout_scope(*GetLayoutBox());
- layout_scope.SetNeedsLayout(
- GetLayoutBox(), layout_invalidation_reason::kScrollbarChanged);
- if (auto* block = DynamicTo<LayoutBlock>(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()) {
- To<LayoutFlexibleBox>(parent)->ClearCachedMainSizeForChild(
- *GetLayoutBox());
- }
- }
+ // Just update the rectangles, in case scrollbars were added or
+ // removed. The calling code on the layout side has its own scrollbar
+ // change detection mechanism.
+ UpdateScrollDimensions();
}
} else if (!HasScrollbar() && resizer_will_change) {
Layer()->DirtyStackingContextZOrderLists();
}
- // The snap container data will be updated at the end of the layout update. If
- // the data changes, then this will try to re-snap.
- SetSnapContainerDataNeedsUpdate(true);
+
+ if (RuntimeEnabledFeatures::LayoutNewSnapLogicEnabled()) {
+ EnqueueForSnapUpdateIfNeeded();
+ } else {
+ // The snap container data will be updated at the end of the layout update.
+ // If the data changes, then this will try to re-snap.
+ SetSnapContainerDataNeedsUpdate(true);
+ }
+
{
UpdateScrollbarEnabledState(is_horizontal_scrollbar_frozen,
is_vertical_scrollbar_frozen);
UpdateScrollbarProportions();
}
+ hypothetical_horizontal_scrollbar_thickness_ = 0;
+ if (NeedsHypotheticalScrollbarThickness(kHorizontalScrollbar)) {
+ hypothetical_horizontal_scrollbar_thickness_ =
+ ComputeHypotheticalScrollbarThickness(kHorizontalScrollbar, true);
+ }
+ hypothetical_vertical_scrollbar_thickness_ = 0;
+ if (NeedsHypotheticalScrollbarThickness(kVerticalScrollbar)) {
+ hypothetical_vertical_scrollbar_thickness_ =
+ ComputeHypotheticalScrollbarThickness(kVerticalScrollbar, true);
+ }
+
DelayableClampScrollOffsetAfterOverflowChange();
if (!is_horizontal_scrollbar_frozen || !is_vertical_scrollbar_frozen)
UpdateScrollableAreaSet();
PositionOverflowControls();
+
+ if (RuntimeEnabledFeatures::CSSScrollStartEnabled()) {
+ if (IsApplyingScrollStart()) {
+ ApplyScrollStart();
+ }
+ }
+}
+
+Element* PaintLayerScrollableArea::GetElementForScrollStart() const {
+ if (!GetLayoutBox()) {
+ return nullptr;
+ }
+
+ const LayoutBox* box = GetLayoutBox();
+ if (auto* element = DynamicTo<Element>(box->GetNode())) {
+ return element;
+ }
+
+ Node* node = box->GetNode();
+ if (!node && box->Parent() && box->Parent()->IsFieldset()) {
+ return DynamicTo<Element>(box->Parent()->GetNode());
+ }
+
+ if (node && node->IsDocumentNode()) {
+ return GetLayoutBox()->GetDocument().documentElement();
+ }
+
+ return nullptr;
+}
+
+void PaintLayerScrollableArea::SetShouldCheckForPaintInvalidation() {
+ LayoutBox& box = *GetLayoutBox();
+ // This function may be called during pre-paint, and in such cases we cannot
+ // mark the ancestry for paint invalidation checking, since we may already be
+ // done with those objects, and never get to visit them again.
+ if (GetLayoutBox()->GetDocument().Lifecycle().GetState() ==
+ DocumentLifecycle::DocumentLifecycle::kInPrePaint) {
+ box.GetMutableForPainting().SetShouldCheckForPaintInvalidation();
+ } else {
+ box.SetShouldCheckForPaintInvalidation();
+ }
+}
+
+bool PaintLayerScrollableArea::IsApplyingScrollStart() const {
+ if (Element* element = GetElementForScrollStart()) {
+ if (element->HasBeenExplicitlyScrolled()) {
+ return false;
+ }
+ if (GetScrollStartTargets()) {
+ return true;
+ }
+ return !ScrollStartIsDefault();
+ }
+ return false;
+}
+
+void PaintLayerScrollableArea::StopApplyingScrollStart() {
+ if (Element* element = GetElementForScrollStart()) {
+ element->SetHasBeenExplicitlyScrolled();
+ }
}
void PaintLayerScrollableArea::DelayableClampScrollOffsetAfterOverflowChange() {
}
void PaintLayerScrollableArea::ClampScrollOffsetAfterOverflowChange() {
- if (!RuntimeEnabledFeatures::LayoutNGDelayScrollOffsetClampingEnabled()) {
- DelayableClampScrollOffsetAfterOverflowChange();
- return;
- }
ClampScrollOffsetAfterOverflowChangeInternal();
}
// Recalculate the snap container data since the scrolling behaviour for this
// layout box changed (i.e. it either became the layout viewport or it
// is no longer the layout viewport).
- SetSnapContainerDataNeedsUpdate(true);
+ if (RuntimeEnabledFeatures::LayoutNewSnapLogicEnabled()) {
+ if (!GetLayoutBox()->NeedsLayout()) {
+ EnqueueForSnapUpdateIfNeeded();
+ }
+ } else {
+ SetSnapContainerDataNeedsUpdate(true);
+ }
}
bool PaintLayerScrollableArea::ShouldPerformScrollAnchoring() const {
return GetLayoutBox()->StyleRef().GetScrollBehavior();
}
-mojom::blink::ColorScheme PaintLayerScrollableArea::UsedColorScheme() const {
+mojom::blink::ColorScheme PaintLayerScrollableArea::UsedColorSchemeScrollbars()
+ const {
+ if (RuntimeEnabledFeatures::UsedColorSchemeRootScrollbarsEnabled() &&
+ GetLayoutBox()->IsGlobalRootScroller() &&
+ !GetPageScrollbarTheme().UsesOverlayScrollbars()) {
+ const Document& document = GetLayoutBox()->GetDocument();
+ if (document.documentElement() &&
+ document.documentElement()->GetComputedStyle() &&
+ document.documentElement()->GetComputedStyle()->ColorScheme().empty() &&
+ document.GetStyleEngine().GetPageColorSchemes() ==
+ static_cast<ColorSchemeFlags>(ColorSchemeFlag::kNormal) &&
+ document.GetPreferredColorScheme() ==
+ mojom::blink::PreferredColorScheme::kDark) {
+ return mojom::blink::ColorScheme::kDark;
+ }
+ }
+
return GetLayoutBox()->StyleRef().UsedColorScheme();
}
VerticalScrollbarWidth(kIgnoreOverlayScrollbarSize);
if (NeedsRelayout() && !HadVerticalScrollbarBeforeRelayout())
client_width += VerticalScrollbarWidth();
- LayoutUnit scroll_width(ScrollWidth());
- LayoutUnit box_x = GetLayoutBox()->Location().X();
- return SnapSizeToPixel(scroll_width, box_x) >
- SnapSizeToPixel(client_width, box_x);
+ return ScrollWidth().Round() > client_width.Round();
}
bool PaintLayerScrollableArea::HasVerticalOverflow() const {
LayoutUnit client_height =
LayoutContentRect(kIncludeScrollbars).Height() -
HorizontalScrollbarHeight(kIgnoreOverlayScrollbarSize);
- LayoutUnit scroll_height(ScrollHeight());
- LayoutUnit box_y = GetLayoutBox()->Location().Y();
- return SnapSizeToPixel(scroll_height, box_y) >
- SnapSizeToPixel(client_height, box_y);
+ return ScrollHeight().Round() > client_height.Round();
+}
+
+#if BUILDFLAG(IS_TIZEN_TV)
+void PaintLayerScrollableArea::ThumbPartFocusChanged(
+ ScrollbarOrientation orientation,
+ bool focused) {
+ if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
+ if (frame->GetSettings() &&
+ frame->GetSettings()->GetUseScrollbarThumbFocusNotifications())
+ frame->Client()->ThumbPartFocusChanged(orientation, focused);
+ }
}
+#endif
// This function returns true if the given box requires overflow scrollbars (as
// opposed to the viewport scrollbars managed by VisualViewport).
!needs_vertical_scrollbar)
return;
- bool horizontal_scrollbar_changed =
- SetHasHorizontalScrollbar(needs_horizontal_scrollbar);
- bool vertical_scrollbar_changed =
- SetHasVerticalScrollbar(needs_vertical_scrollbar);
-
- auto* layout_block = DynamicTo<LayoutBlock>(GetLayoutBox());
- if (layout_block &&
- (horizontal_scrollbar_changed || vertical_scrollbar_changed)) {
- layout_block->ScrollbarsChanged(
- horizontal_scrollbar_changed, vertical_scrollbar_changed,
- LayoutBlock::ScrollbarChangeContext::kStyleChange);
- }
+ SetHasHorizontalScrollbar(needs_horizontal_scrollbar);
+ SetHasVerticalScrollbar(needs_vertical_scrollbar);
if (HorizontalScrollbar())
HorizontalScrollbar()->StyleChanged();
UpdateScrollCornerStyle();
- if (!old_style || old_style->UsedColorScheme() != UsedColorScheme() ||
- old_style->ScrollbarWidth() !=
- GetLayoutBox()->StyleRef().ScrollbarWidth()) {
+ if (!old_style ||
+ old_style->UsedColorScheme() != UsedColorSchemeScrollbars() ||
+ old_style->ScrollbarThumbColorResolved() !=
+ GetLayoutBox()->StyleRef().ScrollbarThumbColorResolved() ||
+ old_style->ScrollbarTrackColorResolved() !=
+ GetLayoutBox()->StyleRef().ScrollbarTrackColorResolved()) {
SetScrollControlsNeedFullPaintInvalidation();
}
}
if (IsA<LayoutView>(layout_box)) {
Document& doc = layout_box.GetDocument();
- // If scrollbar properties have been set on the root element, they will be
- // propagated to the viewport.
- Element* doc_element = doc.documentElement();
- if (doc_element && doc_element->GetLayoutObject() &&
- doc_element->GetLayoutObject()->StyleRef().ScrollbarWidth() !=
- EScrollbarWidth::kAuto)
- return *doc_element->GetLayoutObject();
+ // If the layout box uses standard scrollbar styles use it as the style
+ // source.
+ if (layout_box.StyleRef().UsesStandardScrollbarStyle()) {
+ return layout_box;
+ }
+ // Legacy custom scrollbar styles on the document element or the <body> may
+ // apply to the viewport scrollbars. We don't propagate these styles to
+ // LayoutView in StyleResolver like we do for the standard CSS scrollbar
+ // styles because some conditions can only be checked here.
if (Settings* settings = doc.GetSettings()) {
LocalFrame* frame = layout_box.GetFrame();
DCHECK(frame);
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()->StyleRef().HasCustomScrollbarStyle())
+ doc_element->GetLayoutObject()->StyleRef().HasCustomScrollbarStyle() &&
+ !layout_box.StyleRef().UsesStandardScrollbarStyle()) {
return *doc_element->GetLayoutObject();
+ }
} else if (!layout_box.GetNode() && layout_box.Parent()) {
return *layout_box.Parent();
}
int PaintLayerScrollableArea::HypotheticalScrollbarThickness(
ScrollbarOrientation orientation,
bool should_include_overlay_thickness) const {
+ DCHECK(NeedsHypotheticalScrollbarThickness(orientation));
+ // The cached values are updated after layout, use them if we're layout clean.
+ if (should_include_overlay_thickness &&
+ GetLayoutBox()->GetDocument().Lifecycle().GetState() >=
+ DocumentLifecycle::kLayoutClean) {
+ return orientation == kHorizontalScrollbar
+ ? hypothetical_horizontal_scrollbar_thickness_
+ : hypothetical_vertical_scrollbar_thickness_;
+ }
+ return ComputeHypotheticalScrollbarThickness(
+ orientation, should_include_overlay_thickness);
+}
+
+// Hypothetical scrollbar thickness is computed and cached during layout, but
+// only as needed to avoid a performance penalty. It is needed for every
+// LayoutView, to support frame view auto-sizing; and it's needed whenever CSS
+// scrollbar-gutter requires it.
+bool PaintLayerScrollableArea::NeedsHypotheticalScrollbarThickness(
+ ScrollbarOrientation orientation) const {
+ return GetLayoutBox()->IsLayoutView() ||
+ GetLayoutBox()->HasScrollbarGutters(orientation);
+}
+
+int PaintLayerScrollableArea::ComputeHypotheticalScrollbarThickness(
+ ScrollbarOrientation orientation,
+ bool should_include_overlay_thickness) const {
Scrollbar* scrollbar = orientation == kHorizontalScrollbar
? HorizontalScrollbar()
: VerticalScrollbar();
const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
if (style_source.StyleRef().HasCustomScrollbarStyle()) {
- return CustomScrollbar::HypotheticalScrollbarThickness(
- this, orientation, To<Element>(style_source.GetNode()));
+ return CustomScrollbar::HypotheticalScrollbarThickness(this, orientation,
+ &style_source);
}
ScrollbarTheme& theme = GetPageScrollbarTheme();
return true;
// We have a scrollbar with a stale style source.
- if (scrollbar->StyleSource() &&
- scrollbar->StyleSource()->GetLayoutObject() != style_source) {
+ if (scrollbar->StyleSource() != style_source) {
return true;
}
if (current_theme != &scrollbar->GetTheme())
return true;
+
+ EScrollbarWidth current_width = scrollbar->CSSScrollbarWidth();
+ if (current_width != style_source.StyleRef().ScrollbarWidth()) {
+ return true;
+ }
}
return false;
}
if (VisualViewportSuppliesScrollbars() ||
!CanHaveOverflowScrollbars(*GetLayoutBox()) ||
GetLayoutBox()->GetFrame()->GetSettings()->GetHideScrollbars() ||
- GetLayoutBox()->IsLayoutNGFieldset() ||
- GetLayoutBox()->IsLayoutNGFrameSet() ||
+ GetLayoutBox()->IsFieldset() || GetLayoutBox()->IsFrameSet() ||
GetLayoutBox()->StyleRef().ScrollbarWidth() == EScrollbarWidth::kNone) {
needs_horizontal_scrollbar = false;
needs_vertical_scrollbar = false;
// If this is being performed before layout, we want to only update scrollbar
// existence if its based on purely style based reasons.
- if (option == kOverflowIndependent)
+ if (option == kOverflowIndependent) {
return;
+ }
// If we have clean layout, we can make a decision on any scrollbars that
// depend on overflow.
bool PaintLayerScrollableArea::TryRemovingAutoScrollbars(
const bool& needs_horizontal_scrollbar,
const bool& needs_vertical_scrollbar) {
- // If scrollbars are removed but the content size depends on the scrollbars,
- // additional layouts will be required to size the content. Therefore, only
- // remove auto scrollbars for the initial layout pass.
- DCHECK(!in_overflow_relayout_);
-
if (!needs_horizontal_scrollbar && !needs_vertical_scrollbar)
return false;
GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);
}
-bool PaintLayerScrollableArea::SetHasHorizontalScrollbar(bool has_scrollbar) {
+CompositorElementId PaintLayerScrollableArea::GetScrollCornerElementId() const {
+ CompositorElementId scrollable_element_id = GetScrollElementId();
+ DCHECK(scrollable_element_id);
+ return CompositorElementIdWithNamespace(
+ scrollable_element_id, CompositorElementIdNamespace::kScrollCorner);
+}
+
+void PaintLayerScrollableArea::SetHasHorizontalScrollbar(bool has_scrollbar) {
if (IsHorizontalScrollbarFrozen())
- return false;
+ return;
if (has_scrollbar == HasHorizontalScrollbar())
- return false;
-
- // when scrollbar-width is "none", the scrollbar will not be displayed
- if (GetLayoutBox()->StyleRef().ScrollbarWidth() == EScrollbarWidth::kNone)
- return false;
+ return;
SetScrollbarNeedsPaintInvalidation(kHorizontalScrollbar);
// Force an update since we know the scrollbars have changed things.
if (GetLayoutBox()->GetDocument().HasAnnotatedRegions())
GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);
- return true;
}
-bool PaintLayerScrollableArea::SetHasVerticalScrollbar(bool has_scrollbar) {
+void PaintLayerScrollableArea::SetHasVerticalScrollbar(bool has_scrollbar) {
if (IsVerticalScrollbarFrozen())
- return false;
+ return;
if (GetLayoutBox()->GetDocument().IsVerticalScrollEnforced()) {
// When the policy is enforced the contents of document cannot be scrolled.
// This would make rendering a scrollbar look strange
// (https://crbug.com/898151).
- return false;
+ return;
}
if (has_scrollbar == HasVerticalScrollbar())
- return false;
-
- // when scrollbar-width is "none", the scrollbar will not be displayed
- if (GetLayoutBox()->StyleRef().ScrollbarWidth() == EScrollbarWidth::kNone)
- return false;
+ return;
SetScrollbarNeedsPaintInvalidation(kVerticalScrollbar);
// Force an update since we know the scrollbars have changed things.
if (GetLayoutBox()->GetDocument().HasAnnotatedRegions())
GetLayoutBox()->GetDocument().SetAnnotatedRegionsDirty(true);
- return true;
}
int PaintLayerScrollableArea::VerticalScrollbarWidth(
void PaintLayerScrollableArea::SetSnapContainerDataNeedsUpdate(
bool needs_update) {
+ DCHECK(!RuntimeEnabledFeatures::LayoutNewSnapLogicEnabled());
EnsureRareData().snap_container_data_needs_update_ = needs_update;
if (!needs_update)
return;
.SetAnySnapContainerDataNeedsUpdate(true);
}
-bool PaintLayerScrollableArea::NeedsResnap() const {
- return RareData() ? RareData()->needs_resnap_ : false;
-}
-
-void PaintLayerScrollableArea::SetNeedsResnap(bool needs_resnap) {
- EnsureRareData().needs_resnap_ = needs_resnap;
-}
-
absl::optional<gfx::PointF>
PaintLayerScrollableArea::GetSnapPositionAndSetTarget(
const cc::SnapSelectionStrategy& strategy) {
CompositorElementId active_element_id = CompositorElementId();
if (auto* active_element = GetDocument()->ActiveElement()) {
active_element_id =
- CompositorElementIdFromDOMNodeId(DOMNodeIds::IdForNode(active_element));
+ CompositorElementIdFromDOMNodeId(active_element->GetDomNodeId());
}
- cc::TargetSnapAreaElementIds snap_targets;
- gfx::PointF snap_position;
absl::optional<gfx::PointF> snap_point;
- if (data.FindSnapPosition(strategy, &snap_position, &snap_targets,
- active_element_id)) {
- snap_point = gfx::PointF(snap_position.x(), snap_position.y());
+ cc::SnapPositionData snap =
+ data.FindSnapPosition(strategy, active_element_id);
+ if (snap.type != cc::SnapPositionData::Type::kNone) {
+ snap_point = gfx::PointF(snap.position.x(), snap.position.y());
}
- if (data.SetTargetSnapAreaElementIds(snap_targets))
+ if (data.SetTargetSnapAreaElementIds(snap.target_element_ids)) {
GetLayoutBox()->SetNeedsPaintPropertyUpdate();
+ }
return snap_point;
}
if (HasOverlayOverflowControls())
return true;
- // The global root scrollbars and corner also paint as overlay so that they
- // appear on top of all content within the viewport. This is important since
- // these scrollbar's transform state is
+ // Frame and global root scroller (which can be a non-frame) scrollbars and
+ // corner also paint as overlay so that they appear on top of all content
+ // within their viewport. This is important for global root scrollers since
+ // these scrollbars' transform state is
// VisualViewport::TransformNodeForViewportScrollbars().
- return GetLayoutBox() && GetLayoutBox()->IsGlobalRootScroller();
+ return layer_->IsRootLayer() ||
+ (GetLayoutBox() && GetLayoutBox()->IsGlobalRootScroller());
}
void PaintLayerScrollableArea::PositionOverflowControls() {
}
if (scroll_corner_) {
- LayoutRect rect(ScrollCornerRect());
- scroll_corner_->SetFrameRect(rect);
+ PhysicalRect rect(ScrollCornerRect());
+ scroll_corner_->SetOverriddenSize(rect.size);
// TODO(crbug.com/1020913): This should be part of PaintPropertyTreeBuilder
// when we support subpixel layout of overflow controls.
scroll_corner_->GetMutableForPainting().FirstFragment().SetPaintOffset(
- PhysicalOffset(rect.Location()));
+ rect.offset);
}
if (resizer_) {
- LayoutRect rect(ResizerCornerRect(kResizerForPointer));
- resizer_->SetFrameRect(rect);
+ PhysicalRect rect(ResizerCornerRect(kResizerForPointer));
+ resizer_->SetOverriddenSize(rect.size);
// TODO(crbug.com/1020913): This should be part of PaintPropertyTreeBuilder
// when we support subpixel layout of overflow controls.
resizer_->GetMutableForPainting().FirstFragment().SetPaintOffset(
- PhysicalOffset(rect.Location()));
+ rect.offset);
}
}
return;
}
const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
- scoped_refptr<ComputedStyle> corner =
- GetLayoutBox()->IsScrollContainer()
+ bool uses_standard_scrollbar_style =
+ style_source.StyleRef().UsesStandardScrollbarStyle();
+ const ComputedStyle* corner =
+ (GetLayoutBox()->IsScrollContainer() && !uses_standard_scrollbar_style)
? style_source.GetUncachedPseudoElementStyle(
StyleRequest(kPseudoIdScrollbarCorner, style_source.Style()))
- : scoped_refptr<ComputedStyle>(nullptr);
+ : nullptr;
if (corner) {
if (!scroll_corner_) {
scroll_corner_ = LayoutCustomScrollbarPart::CreateAnonymous(
gfx::Rect resize_control_rect;
if (GetLayoutBox()->CanResize()) {
resize_control_rect = ResizerCornerRect(kResizerForPointer);
- if (resize_control_rect.Contains(local_point))
+ if (resize_control_rect.Contains(local_point)) {
+ result.SetIsOverResizer(true);
return true;
+ }
}
int resize_control_size = max(resize_control_rect.height(), 0);
if (HasVerticalScrollbar() &&
VerticalScrollbar()->ShouldParticipateInHitTesting()) {
- LayoutRect v_bar_rect(VerticalScrollbarStart(),
- GetLayoutBox()->BorderTop().ToInt(),
- VerticalScrollbar()->ScrollbarThickness(),
- visible_rect.height() -
- (HasHorizontalScrollbar()
- ? HorizontalScrollbar()->ScrollbarThickness()
- : resize_control_size));
- if (v_bar_rect.Contains(LayoutPoint(local_point))) {
+ gfx::Rect v_bar_rect(VerticalScrollbarStart(),
+ GetLayoutBox()->BorderTop().ToInt(),
+ VerticalScrollbar()->ScrollbarThickness(),
+ visible_rect.height() -
+ (HasHorizontalScrollbar()
+ ? HorizontalScrollbar()->ScrollbarThickness()
+ : resize_control_size));
+ if (v_bar_rect.Contains(local_point)) {
result.SetScrollbar(VerticalScrollbar());
return true;
}
HorizontalScrollbar()->ShouldParticipateInHitTesting()) {
// TODO(crbug.com/638981): Are the conversions to int intentional?
int h_scrollbar_thickness = HorizontalScrollbar()->ScrollbarThickness();
- LayoutRect h_bar_rect(
+ gfx::Rect h_bar_rect(
HorizontalScrollbarStart(),
GetLayoutBox()->BorderTop().ToInt() + visible_rect.height() -
h_scrollbar_thickness,
? VerticalScrollbar()->ScrollbarThickness()
: resize_control_size),
h_scrollbar_thickness);
- if (h_bar_rect.Contains(LayoutPoint(local_point))) {
+ if (h_bar_rect.Contains(local_point)) {
result.SetScrollbar(HorizontalScrollbar());
return true;
}
// Update custom resizer style.
const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
- scoped_refptr<ComputedStyle> resizer =
+ const ComputedStyle* resizer =
GetLayoutBox()->IsScrollContainer()
? style_source.GetUncachedPseudoElementStyle(
StyleRequest(kPseudoIdResizer, style_source.Style()))
- : scoped_refptr<ComputedStyle>(nullptr);
+ : nullptr;
if (resizer) {
if (!resizer_) {
resizer_ = LayoutCustomScrollbarPart::CreateAnonymous(
}
}
+void PaintLayerScrollableArea::EnqueueForSnapUpdateIfNeeded() {
+ auto* box = GetLayoutBox();
+ // Not all PLSAs are scroll containers!
+ if (!box->IsScrollContainer()) {
+ return;
+ }
+
+ // Enqueue ourselves for a snap update if we have any snap-areas, or if we
+ // currently have snap-data (and it needs to be cleared).
+ for (const auto& fragment : box->PhysicalFragments()) {
+ if (fragment.SnapAreas() || GetSnapContainerData()) {
+ box->GetFrameView()->AddPendingSnapUpdate(this);
+ break;
+ }
+ }
+}
+
void PaintLayerScrollableArea::AddStickyLayer(PaintLayer* layer) {
UseCounter::Count(GetLayoutBox()->GetDocument(), WebFeature::kPositionSticky);
EnsureRareData().sticky_layers_.insert(layer);
}
-void PaintLayerScrollableArea::RemoveStickyLayer(PaintLayer* layer) {
- if (rare_data_)
- rare_data_->sticky_layers_.erase(layer);
+void PaintLayerScrollableArea::UpdateAllStickyConstraints() {
+ // TODO(ikilpatrick): Change `UpdateStickyPositionConstraints` return the
+ // sticky constraints object instead of performing a mutation.
+ for (const auto& fragment : GetLayoutBox()->PhysicalFragments()) {
+ if (auto* sticky_descendants = fragment.StickyDescendants()) {
+ for (auto& sticky_descendant : *sticky_descendants) {
+ sticky_descendant->UpdateStickyPositionConstraints();
+ }
+ }
+ }
}
void PaintLayerScrollableArea::InvalidateAllStickyConstraints() {
// StickyConstraints() to see if its sticky constraints need update.
if (rare_data_)
rare_data_->sticky_layers_.clear();
+
+ if (!RuntimeEnabledFeatures::LayoutNewStickyLogicEnabled()) {
+ return;
+ }
+
+ // Enqueue ourselves for a sticky update if we have any sticky descendants.
+ auto* box = GetLayoutBox();
+ for (const auto& fragment : box->PhysicalFragments()) {
+ if (fragment.StickyDescendants()) {
+ box->GetFrameView()->AddPendingStickyUpdate(this);
+ break;
+ }
+ }
}
void PaintLayerScrollableArea::InvalidatePaintForStickyDescendants() {
}
}
-bool PaintLayerScrollableArea::AddAnchorPositionedLayer(PaintLayer* layer) {
- auto add_result = EnsureRareData().anchor_positioned_layers_.insert(layer);
- return add_result.is_new_entry;
-}
-
-void PaintLayerScrollableArea::InvalidateAllAnchorPositionedLayers() {
- if (rare_data_)
- rare_data_->anchor_positioned_layers_.clear();
-}
-
-void PaintLayerScrollableArea::InvalidatePaintForAnchorPositionedLayers() {
- // If this is called during layout, anchor_positioned_layers_ may contain
- // stale pointers. Return because we'll InvalidateAllAnchorPositionedLayers(),
- // and we'll SetNeedsPaintPropertyUpdate() when updating anchor positioned
- // layers.
- if (GetLayoutBox()->NeedsLayout())
- return;
-
- if (PaintLayerScrollableAreaRareData* d = RareData()) {
- for (PaintLayer* anchor_positioned_layer : d->anchor_positioned_layers_)
- anchor_positioned_layer->GetLayoutObject().SetNeedsPaintPropertyUpdate();
- }
-}
-
gfx::Vector2d PaintLayerScrollableArea::OffsetFromResizeCorner(
const gfx::Point& absolute_point) const {
// Currently the resize corner is either the bottom right corner or the bottom
local_point.y() - element_size.height());
}
-LayoutSize PaintLayerScrollableArea::MinimumSizeForResizing(float zoom_factor) {
- LayoutUnit min_width =
- MinimumValueForLength(GetLayoutBox()->StyleRef().MinWidth(),
- GetLayoutBox()->ContainingBlock()->Size().Width());
- LayoutUnit min_height =
- MinimumValueForLength(GetLayoutBox()->StyleRef().MinHeight(),
- GetLayoutBox()->ContainingBlock()->Size().Height());
- min_width = std::max(LayoutUnit(min_width / zoom_factor),
- LayoutUnit(kDefaultMinimumWidthForResizing));
- min_height = std::max(LayoutUnit(min_height / zoom_factor),
- LayoutUnit(kDefaultMinimumHeightForResizing));
- return LayoutSize(min_width, min_height);
-}
-
void PaintLayerScrollableArea::Resize(const gfx::Point& pos,
- const LayoutSize& old_offset) {
+ const gfx::Vector2d& old_offset) {
// FIXME: This should be possible on generated content but is not right now.
if (!InResizeMode() || !GetLayoutBox()->CanResize() ||
!GetLayoutBox()->GetNode())
new_offset.set_x(new_offset.x() / zoom_factor);
new_offset.set_y(new_offset.y() / zoom_factor);
- LayoutSize current_size = GetLayoutBox()->Size();
+ PhysicalSize current_size = GetLayoutBox()->Size();
current_size.Scale(1 / zoom_factor);
- LayoutSize adjusted_old_offset = old_offset * (1.f / zoom_factor);
+ PhysicalOffset adjusted_old_offset(old_offset);
+ adjusted_old_offset.Scale(1.f / zoom_factor);
if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
new_offset.set_x(-new_offset.x());
- adjusted_old_offset.SetWidth(-adjusted_old_offset.Width());
+ adjusted_old_offset.left = -adjusted_old_offset.left;
}
- LayoutSize difference(
- (current_size + LayoutSize(new_offset) - adjusted_old_offset)
- .ExpandedTo(MinimumSizeForResizing(zoom_factor)) -
- current_size);
+ PhysicalOffset offset = PhysicalOffset(new_offset) - adjusted_old_offset;
+ PhysicalSize new_size(current_size.width + offset.left,
+ current_size.height + offset.top);
+
+ // Ensure the new size is at least as large as the resize corner.
+ gfx::SizeF corner_rect(CornerRect().size());
+ corner_rect.InvScale(zoom_factor);
+ new_size.width = std::max(new_size.width, LayoutUnit(corner_rect.width()));
+ new_size.height = std::max(new_size.height, LayoutUnit(corner_rect.height()));
+
+ PhysicalSize difference(new_size - current_size);
bool is_box_sizing_border =
GetLayoutBox()->StyleRef().BoxSizing() == EBoxSizing::kBorderBox;
- EResize resize = GetLayoutBox()->StyleRef().Resize(
- GetLayoutBox()->ContainingBlock()->StyleRef());
- if (resize != EResize::kVertical && difference.Width()) {
+ EResize resize = GetLayoutBox()->StyleRef().UsedResize();
+ if (resize != EResize::kVertical && difference.width) {
LayoutUnit base_width =
- GetLayoutBox()->Size().Width() -
+ GetLayoutBox()->Size().width -
(is_box_sizing_border ? LayoutUnit()
: GetLayoutBox()->BorderAndPaddingWidth());
base_width = LayoutUnit(base_width / zoom_factor);
element->SetInlineStyleProperty(CSSPropertyID::kWidth,
- RoundToInt(base_width + difference.Width()),
+ RoundToInt(base_width + difference.width),
CSSPrimitiveValue::UnitType::kPixels);
}
- if (resize != EResize::kHorizontal && difference.Height()) {
+ if (resize != EResize::kHorizontal && difference.height) {
LayoutUnit base_height =
- GetLayoutBox()->Size().Height() -
+ GetLayoutBox()->Size().height -
(is_box_sizing_border ? LayoutUnit()
: GetLayoutBox()->BorderAndPaddingHeight());
base_height = LayoutUnit(base_height / zoom_factor);
- element->SetInlineStyleProperty(
- CSSPropertyID::kHeight, RoundToInt(base_height + difference.Height()),
- CSSPrimitiveValue::UnitType::kPixels);
+ element->SetInlineStyleProperty(CSSPropertyID::kHeight,
+ RoundToInt(base_height + difference.height),
+ CSSPrimitiveValue::UnitType::kPixels);
}
document.UpdateStyleAndLayout(DocumentUpdateReason::kSizeChange);
new_scroll_offset = ScrollPositionToOffset(end_point);
if (params->is_for_scroll_sequence) {
+ CHECK(GetSmoothScrollSequencer());
DCHECK(params->type == mojom::blink::ScrollType::kProgrammatic ||
params->type == mojom::blink::ScrollType::kUser);
mojom::blink::ScrollBehavior behavior = DetermineScrollBehavior(
frame_view->RemoveScrollAnchoringScrollableArea(this);
}
- bool is_visible_to_hit_test =
- GetLayoutBox()->StyleRef().VisibleToHitTesting();
+ bool is_visible =
+ GetLayoutBox()->StyleRef().Visibility() == EVisibility::kVisible;
bool did_scroll_overflow = scrolls_overflow_;
if (auto* layout_view = DynamicTo<LayoutView>(GetLayoutBox())) {
mojom::blink::ScrollbarMode h_mode;
has_overflow = false;
}
- scrolls_overflow_ = has_overflow && is_visible_to_hit_test;
+ scrolls_overflow_ = has_overflow && is_visible;
if (did_scroll_overflow == ScrollsOverflow())
return;
}
bool PaintLayerScrollableArea::ShouldScrollOnMainThread() const {
- if (HasBeenDisposed())
- return true;
-
- // TODO(crbug.com/985127, crbug.com/1015833): We should just use the main
- // thread scrolling reasons on the scroll node which should have all required
- // reasons. If it was not, we would have inconsistent results here and
- // ScrollNode::GetMainThreadScrollingReasons().
- if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
- if (frame->View()->GetMainThreadScrollingReasons())
- return true;
- }
-
- // Property tree state is not available until the PrePaint lifecycle stage.
- // PaintPropertyTreeBuilder needs to get the old status during PrePaint.
DCHECK_GE(GetDocument()->Lifecycle().GetState(),
- DocumentLifecycle::kInPrePaint);
- const auto* properties = GetLayoutBox()->FirstFragment().PaintProperties();
- if (!properties || !properties->Scroll() ||
- properties->Scroll()->GetMainThreadScrollingReasons())
- return true;
-
- DCHECK(properties->ScrollTranslation());
- return !properties->ScrollTranslation()->HasDirectCompositingReasons();
+ DocumentLifecycle::kPaintClean);
+ return HasBeenDisposed() || should_scroll_on_main_thread_;
}
-static bool LayerNodeMayNeedCompositedScrolling(const PaintLayer* layer) {
- // Don't force composite scroll for select or text input elements.
- if (Node* node = layer->GetLayoutObject().GetNode()) {
- if (IsA<HTMLSelectElement>(node))
- return false;
- if (TextControlElement* text_control = EnclosingTextControl(node)) {
- if (IsA<HTMLInputElement>(text_control)) {
- return false;
- }
- }
+void PaintLayerScrollableArea::SetShouldScrollOnMainThread(
+ bool scroll_on_main_thread) {
+ DCHECK_EQ(GetDocument()->Lifecycle().GetState(),
+ DocumentLifecycle::kPaintClean);
+ if (scroll_on_main_thread != should_scroll_on_main_thread_) {
+ should_scroll_on_main_thread_ = scroll_on_main_thread;
+ MainThreadScrollingDidChange();
}
- return true;
}
-bool PaintLayerScrollableArea::ComputeNeedsCompositedScrolling(
- bool force_prefer_compositing_to_lcd_text) {
- const auto* box = GetLayoutBox();
- non_composited_main_thread_scrolling_reasons_ = 0;
- auto new_background_paint_location =
- box->ComputeBackgroundPaintLocationIfComposited();
- bool needs_composited_scrolling = ComputeNeedsCompositedScrollingInternal(
- new_background_paint_location, force_prefer_compositing_to_lcd_text);
- if (!needs_composited_scrolling)
- new_background_paint_location = kBackgroundPaintInBorderBoxSpace;
- box->GetMutableForPainting().SetBackgroundPaintLocation(
- new_background_paint_location);
-
- return needs_composited_scrolling;
-}
-
-bool PaintLayerScrollableArea::ComputeNeedsCompositedScrollingInternal(
- BackgroundPaintLocation background_paint_location_if_composited,
- bool force_prefer_compositing_to_lcd_text) {
- DCHECK_EQ(background_paint_location_if_composited,
- GetLayoutBox()->ComputeBackgroundPaintLocationIfComposited());
-
- if (!Layer()->GetLayoutObject().GetFrameView()->IsVisible())
- return false;
-
- if (CompositingReasonFinder::RequiresCompositingForRootScroller(*layer_))
- return true;
-
- if (!layer_->ScrollsOverflow())
- return false;
-
- if (layer_->Size().IsEmpty())
- return false;
-
- const auto* box = GetLayoutBox();
-
- // Although trivial 3D transforms are not always a direct compositing reason
- // (see CompositingReasonFinder::RequiresCompositingFor3DTransform), we treat
- // them as one for composited scrolling. This is because of the amount of
- // content that depends on this optimization, and because of the long-term
- // desire to use composited scrolling whenever possible.
- if (box->HasTransformRelatedProperty() &&
- box->StyleRef().Has3DTransformOperation()) {
+bool PaintLayerScrollableArea::PrefersNonCompositedScrolling() const {
+ if (RuntimeEnabledFeatures::PreferNonCompositedScrollingEnabled()) {
return true;
}
-
- if (!force_prefer_compositing_to_lcd_text &&
- (RuntimeEnabledFeatures::PreferNonCompositedScrollingEnabled() ||
- !LayerNodeMayNeedCompositedScrolling(layer_))) {
- return false;
- }
-
- bool needs_composited_scrolling = true;
-
- if (!force_prefer_compositing_to_lcd_text &&
- !box->GetDocument()
- .GetSettings()
- ->GetPreferCompositingToLCDTextEnabled()) {
- if (!box->TextIsKnownToBeOnOpaqueBackground()) {
- non_composited_main_thread_scrolling_reasons_ |=
- cc::MainThreadScrollingReason::kNotOpaqueForTextAndLCDText;
- needs_composited_scrolling = false;
+ if (Node* node = GetLayoutBox()->GetNode()) {
+ if (IsA<HTMLSelectElement>(node)) {
+ return true;
}
- if (!(background_paint_location_if_composited &
- kBackgroundPaintInContentsSpace) &&
- box->StyleRef().HasBackground()) {
- non_composited_main_thread_scrolling_reasons_ |= cc::
- MainThreadScrollingReason::kCantPaintScrollingBackgroundAndLCDText;
- needs_composited_scrolling = false;
+ if (TextControlElement* text_control = EnclosingTextControl(node)) {
+ if (IsA<HTMLInputElement>(text_control)) {
+ return true;
+ }
}
}
-
- DCHECK(!(non_composited_main_thread_scrolling_reasons_ &
- ~cc::MainThreadScrollingReason::kNonCompositedReasons));
-
- if (!box->GetFrame()->Client()->GetWebFrame()) {
- // If there's no WebFrame, then there's no WebFrameWidget, and we can't do
- // threaded scrolling. This currently only happens in a WebPagePopup.
- // (However, we still allow needs_composited_scrolling to be true in this
- // case, so that the scroller gets layerized.)
- non_composited_main_thread_scrolling_reasons_ |=
- cc::MainThreadScrollingReason::kPopupNoThreadedInput;
- }
-
- return needs_composited_scrolling;
+ return false;
}
bool PaintLayerScrollableArea::UsesCompositedScrolling() const {
return GetLayoutBox()->UsesCompositedScrolling();
}
-void PaintLayerScrollableArea::UpdateNeedsCompositedScrolling(
- bool force_prefer_compositing_to_lcd_text) {
- DCHECK_EQ(DocumentLifecycle::kInPrePaint,
- GetDocument()->Lifecycle().GetState());
-
- bool new_needs_composited_scrolling =
- ComputeNeedsCompositedScrolling(force_prefer_compositing_to_lcd_text);
- if (new_needs_composited_scrolling == needs_composited_scrolling_)
- return;
-
- needs_composited_scrolling_ = new_needs_composited_scrolling;
- GetLayoutBox()->SetShouldCheckForPaintInvalidation();
-}
-
bool PaintLayerScrollableArea::VisualViewportSuppliesScrollbars() const {
LocalFrame* frame = GetLayoutBox()->GetFrame();
if (!frame || !frame->GetSettings())
if (style_source.StyleRef().HasCustomScrollbarStyle()) {
DCHECK(style_source.GetNode() && style_source.GetNode()->IsElementNode());
scrollbar = MakeGarbageCollected<CustomScrollbar>(
- ScrollableArea(), orientation, To<Element>(style_source.GetNode()));
+ ScrollableArea(), orientation, &style_source);
} else {
- Element* style_source_element = nullptr;
- style_source_element = DynamicTo<Element>(style_source.GetNode());
scrollbar = MakeGarbageCollected<Scrollbar>(ScrollableArea(), orientation,
- style_source_element);
+ &style_source);
}
ScrollableArea()->GetLayoutBox()->GetDocument().View()->AddScrollbar(
scrollbar);
visitor->Trace(v_bar_);
}
-int PaintLayerScrollableArea::PreventRelayoutScope::count_ = 0;
-SubtreeLayoutScope*
- PaintLayerScrollableArea::PreventRelayoutScope::layout_scope_ = nullptr;
-bool PaintLayerScrollableArea::PreventRelayoutScope::relayout_needed_ = false;
-
-PaintLayerScrollableArea::PreventRelayoutScope::PreventRelayoutScope(
- SubtreeLayoutScope& layout_scope) {
- if (!count_) {
- DCHECK(!layout_scope_);
- DCHECK(NeedsRelayoutList().empty());
- layout_scope_ = &layout_scope;
- }
- count_++;
-}
-
-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 (auto* layout_block = DynamicTo<LayoutBlock>(box)) {
- 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) {
- layout_block->ScrollbarsChanged(horizontal_scrollbar_changed,
- vertical_scrollbar_changed);
- }
- }
- scrollable_area->SetNeedsRelayout(false);
- }
-
- NeedsRelayoutList().clear();
- }
- layout_scope_ = nullptr;
- }
-}
-
-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);
-}
-
-void PaintLayerScrollableArea::PreventRelayoutScope::ResetRelayoutNeeded() {
- DCHECK_EQ(count_, 0);
- DCHECK(NeedsRelayoutList().empty());
- relayout_needed_ = false;
-}
-
-HeapVector<Member<PaintLayerScrollableArea>>&
-PaintLayerScrollableArea::PreventRelayoutScope::NeedsRelayoutList() {
- DEFINE_STATIC_LOCAL(
- Persistent<HeapVector<Member<PaintLayerScrollableArea>>>,
- needs_relayout_list,
- (MakeGarbageCollected<HeapVector<Member<PaintLayerScrollableArea>>>()));
- return *needs_relayout_list;
-}
-
int PaintLayerScrollableArea::FreezeScrollbarsScope::count_ = 0;
PaintLayerScrollableArea::FreezeScrollbarsRootScope::FreezeScrollbarsRootScope(
bool PaintLayerScrollableArea::ShouldDirectlyCompositeScrollbar(
const Scrollbar& scrollbar) const {
// Don't composite non-scrollable scrollbars.
- if (!scrollbar.Maximum())
+ // TODO(crbug.com/1020913): !ScrollsOverflow() should imply
+ // !scrollbar.Maximum(), but currently that isn't always true due to
+ // different or incorrect rounding methods for scroll geometries.
+ if (!ScrollsOverflow() || !scrollbar.Maximum()) {
return false;
- if (scrollbar.IsCustomScrollbar())
+ }
+ if (scrollbar.IsCustomScrollbar()) {
return false;
-
- return NeedsCompositedScrolling();
+ }
+ // Compositing of scrollbar is decided in PaintArtifactCompositor. We assume
+ // compositing here so that paint invalidation will be skipped here. We'll
+ // invalidate raster if needed after paint, without paint invalidation.
+ return true;
}
void PaintLayerScrollableArea::EstablishScrollbarRoot(bool freeze_horizontal,
context.painting_layer->SetNeedsRepaint();
const auto& box = *GetLayoutBox();
ObjectPaintInvalidator(box).InvalidateDisplayItemClient(
- box, PaintInvalidationReason::kGeometry);
+ box, PaintInvalidationReason::kLayout);
}
previously_was_overlay = is_overlay;
context.painting_layer->SetNeedsRepaint();
ObjectPaintInvalidator(*GetLayoutBox())
.InvalidateDisplayItemClient(GetScrollCornerDisplayItemClient(),
- PaintInvalidationReason::kGeometry);
+ PaintInvalidationReason::kLayout);
}
ClearNeedsPaintInvalidationForScrollControls();
}
void PaintLayerScrollableArea::ScrollControlWasSetNeedsPaintInvalidation() {
- GetLayoutBox()->SetShouldCheckForPaintInvalidation();
+ SetShouldCheckForPaintInvalidation();
}
void PaintLayerScrollableArea::DidScrollWithScrollbar(
UseCounter::Count(
GetLayoutBox()->GetDocument(),
WebFeature::kScrollbarUseScrollbarButtonReversedDirection);
- U_FALLTHROUGH;
+ [[fallthrough]];
case kBackButtonStartPart:
case kForwardButtonEndPart:
scrollbar_use_uma =