diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/core')
17 files changed, 215 insertions, 149 deletions
diff --git a/chromium/third_party/blink/renderer/core/dom/document.cc b/chromium/third_party/blink/renderer/core/dom/document.cc index 71bf6c19867..6a969b812da 100644 --- a/chromium/third_party/blink/renderer/core/dom/document.cc +++ b/chromium/third_party/blink/renderer/core/dom/document.cc @@ -2927,6 +2927,46 @@ void Document::UpdateStyleAndLayoutTreeForNode(const Node* node) { UpdateStyleAndLayoutTree(); } +void Document::ApplyScrollRestorationLogic() { + // If we're restoring a scroll position from history, that takes precedence + // over scrolling to the anchor in the URL. + View()->InvokeFragmentAnchor(); + auto& frame_loader = GetFrame()->Loader(); + auto& document_loader = *frame_loader.GetDocumentLoader(); + if (frame_->IsLoading() && + !FrameLoader::NeedsHistoryItemRestore(document_loader.LoadType())) + return; + auto* history_item = frame_loader.GetDocumentLoader()->GetHistoryItem(); + if (!history_item || !history_item->GetViewState()) + return; + bool should_restore_scroll = + history_item->ScrollRestorationType() != kScrollRestorationManual; + auto& scroll_offset = history_item->GetViewState()->scroll_offset_; + // This tries to balance: + // 1. restoring as soon as possible. + // 2. not overriding user scroll (TODO(majidvp): also respect user scale). + // 3. detecting clamping to avoid repeatedly popping the scroll position down + // as the page height increases. + // 4. ignoring clamp detection if scroll state is not being restored, if load + // is complete, or if the navigation is same-document (as the new page may + // be smaller than the previous page). + bool can_restore_without_clamping = + View()->LayoutViewport()->ClampScrollOffset(scroll_offset) == + scroll_offset; + bool can_restore_without_annoying_user = + !document_loader.GetInitialScrollState().was_scrolled_by_user && + (can_restore_without_clamping || !frame_->IsLoading() || + !should_restore_scroll); + if (!can_restore_without_annoying_user) + return; + frame_loader.RestoreScrollPositionAndViewState(); + if (View()->GetScrollableArea()->ApplyPendingHistoryRestoreScrollOffset()) { + if (ScrollingCoordinator* scrolling_coordinator = + View()->GetFrame().GetPage()->GetScrollingCoordinator()) + scrolling_coordinator->FrameViewRootLayerDidChange(View()); + } +} + void Document::UpdateStyleAndLayoutTreeForSubtree(const Node* node) { DCHECK(node); if (!node->InActiveDocument()) { @@ -2979,6 +3019,8 @@ void Document::UpdateStyleAndLayout(ForcedLayoutStatus status) { if (Lifecycle().GetState() < DocumentLifecycle::kLayoutClean) Lifecycle().AdvanceTo(DocumentLifecycle::kLayoutClean); + ApplyScrollRestorationLogic(); + if (LocalFrameView* frame_view_anchored = View()) frame_view_anchored->PerformScrollAnchoringAdjustments(); @@ -2993,11 +3035,6 @@ void Document::LayoutUpdated() { DCHECK(GetFrame()); DCHECK(View()); - // If we're restoring a scroll position from history, that takes precedence - // over scrolling to the anchor in the URL. - View()->InvokeFragmentAnchor(); - GetFrame()->Loader().RestoreScrollPositionAndViewState(); - // Plugins can run script inside layout which can detach the page. // TODO(dcheng): Does it make sense to do any of this work if detached? if (GetFrame()) { @@ -4101,6 +4138,16 @@ bool Document::CheckCompletedInternal() { } } + if (auto* view = View()) { + if (view->GetFragmentAnchor()) { + // Schedule an animation frame to process fragment anchors. The frame + // can't be scheduled when the fragment anchor is set because, per spec, + // we must wait for the document to be loaded before invoking fragment + // anchors. + View()->ScheduleAnimation(); + } + } + return true; } diff --git a/chromium/third_party/blink/renderer/core/dom/document.h b/chromium/third_party/blink/renderer/core/dom/document.h index ee2f8012b78..b36d9bf62b3 100644 --- a/chromium/third_party/blink/renderer/core/dom/document.h +++ b/chromium/third_party/blink/renderer/core/dom/document.h @@ -1630,6 +1630,8 @@ class CORE_EXPORT Document : public ContainerNode, return use_count_fragment_directive_; } + void ApplyScrollRestorationLogic(); + protected: void ClearXMLVersion() { xml_version_ = String(); } diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc b/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc index b48fd035e1e..6b02303b31e 100644 --- a/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc @@ -455,6 +455,13 @@ void LocalFrameView::FrameRectsChanged(const IntRect& old_rect) { if (frame_->IsMainFrame()) frame_->GetPage()->GetVisualViewport().MainFrameDidChangeSize(); GetFrame().Loader().RestoreScrollPositionAndViewState(); + if (GetScrollableArea()) { + if (GetScrollableArea()->ApplyPendingHistoryRestoreScrollOffset()) { + if (ScrollingCoordinator* scrolling_coordinator = + GetFrame().GetPage()->GetScrollingCoordinator()) + scrolling_coordinator->FrameViewRootLayerDidChange(this); + } + } } } @@ -1368,11 +1375,11 @@ void LocalFrameView::ProcessUrlFragment(const KURL& url, if (anchor) { fragment_anchor_ = anchor; fragment_anchor_->Installed(); - - // Layout needs to be clean for scrolling but if layout is needed, we'll - // invoke after layout is completed so no need to do it here. - if (!NeedsLayout()) - InvokeFragmentAnchor(); + // Post-load, same-document navigations need to schedule a frame in which + // the fragment anchor will be invoked. It will be done after layout as + // part of the lifecycle. + if (same_document_navigation) + ScheduleAnimation(); } } @@ -1458,9 +1465,6 @@ void LocalFrameView::HandleLoadCompleted() { // reduce the size of the frame. if (auto_size_info_) auto_size_info_->AutoSizeIfNeeded(); - - if (fragment_anchor_) - fragment_anchor_->DidCompleteLoad(); } void LocalFrameView::ClearLayoutSubtreeRoot(const LayoutObject& root) { @@ -2895,6 +2899,10 @@ void LocalFrameView::UpdateStyleAndLayoutIfNeededRecursive() { if (Lifecycle().GetState() < DocumentLifecycle::kLayoutClean) Lifecycle().AdvanceTo(DocumentLifecycle::kLayoutClean); + // If we're restoring a scroll position from history, that takes precedence + // over scrolling to the anchor in the URL. + frame_->GetDocument()->ApplyScrollRestorationLogic(); + if (AXObjectCache* cache = GetFrame().GetDocument()->ExistingAXObjectCache()) cache->ProcessUpdatesAfterLayout(*GetFrame().GetDocument()); diff --git a/chromium/third_party/blink/renderer/core/frame/root_frame_viewport.cc b/chromium/third_party/blink/renderer/core/frame/root_frame_viewport.cc index 20c0849668e..af7fd711c54 100644 --- a/chromium/third_party/blink/renderer/core/frame/root_frame_viewport.cc +++ b/chromium/third_party/blink/renderer/core/frame/root_frame_viewport.cc @@ -8,6 +8,7 @@ #include "cc/input/snap_selection_strategy.h" #include "third_party/blink/public/platform/web_scroll_into_view_params.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" +#include "third_party/blink/renderer/core/frame/visual_viewport.h" #include "third_party/blink/renderer/core/layout/layout_box.h" #include "third_party/blink/renderer/core/layout/scroll_anchor.h" #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h" @@ -48,7 +49,7 @@ FloatRect GetUserScrollableRect(const ScrollableArea& area) { } // namespace RootFrameViewport::RootFrameViewport(ScrollableArea& visual_viewport, ScrollableArea& layout_viewport) - : visual_viewport_(visual_viewport) { + : visual_viewport_(visual_viewport), should_restore_scroll_(false) { SetLayoutViewport(layout_viewport); } @@ -94,15 +95,15 @@ PhysicalRect RootFrameViewport::RootContentsToLayoutViewportContents( void RootFrameViewport::RestoreToAnchor(const ScrollOffset& target_offset) { // Clamp the scroll offset of each viewport now so that we force any invalid // offsets to become valid so we can compute the correct deltas. - VisualViewport().SetScrollOffset(VisualViewport().GetScrollOffset(), + GetVisualViewport().SetScrollOffset(GetVisualViewport().GetScrollOffset(), kProgrammaticScroll); LayoutViewport().SetScrollOffset(LayoutViewport().GetScrollOffset(), kProgrammaticScroll); ScrollOffset delta = target_offset - GetScrollOffset(); - VisualViewport().SetScrollOffset(VisualViewport().GetScrollOffset() + delta, - kProgrammaticScroll); + GetVisualViewport().SetScrollOffset( + GetVisualViewport().GetScrollOffset() + delta, kProgrammaticScroll); delta = target_offset - GetScrollOffset(); @@ -120,8 +121,8 @@ void RootFrameViewport::RestoreToAnchor(const ScrollOffset& target_offset) { kProgrammaticScroll); delta = target_offset - GetScrollOffset(); - VisualViewport().SetScrollOffset(VisualViewport().GetScrollOffset() + delta, - kProgrammaticScroll); + GetVisualViewport().SetScrollOffset( + GetVisualViewport().GetScrollOffset() + delta, kProgrammaticScroll); } void RootFrameViewport::DidUpdateVisualViewport() { @@ -168,7 +169,7 @@ void RootFrameViewport::UpdateScrollAnimator() { } ScrollOffset RootFrameViewport::ScrollOffsetFromScrollAnimators() const { - return VisualViewport().GetScrollAnimator().CurrentOffset() + + return GetVisualViewport().GetScrollAnimator().CurrentOffset() + LayoutViewport().GetScrollAnimator().CurrentOffset(); } @@ -176,7 +177,7 @@ IntRect RootFrameViewport::VisibleContentRect( IncludeScrollbarsInRect scrollbar_inclusion) const { return IntRect( IntPoint(ScrollOffsetInt()), - VisualViewport().VisibleContentRect(scrollbar_inclusion).Size()); + GetVisualViewport().VisibleContentRect(scrollbar_inclusion).Size()); } PhysicalRect RootFrameViewport::VisibleScrollSnapportRect( @@ -190,9 +191,9 @@ PhysicalRect RootFrameViewport::VisibleScrollSnapportRect( PhysicalRect visual_rect_in_content( PhysicalOffset::FromFloatSizeRound( LayoutViewport().GetScrollOffset() + - VisualViewport().GetScrollAnimator().CurrentOffset()), + GetVisualViewport().GetScrollAnimator().CurrentOffset()), PhysicalSize( - VisualViewport().VisibleContentRect(scrollbar_inclusion).Size())); + GetVisualViewport().VisibleContentRect(scrollbar_inclusion).Size())); PhysicalRect visible_scroll_snapport = Intersection(visual_rect_in_content, frame_rect_in_content); @@ -241,6 +242,50 @@ IntRect RootFrameViewport::ScrollCornerRect() const { return LayoutViewport().ScrollCornerRect(); } +bool RootFrameViewport::ApplyPendingHistoryRestoreScrollOffset() { + if (!pending_view_state_) + return false; + bool should_restore_scale = pending_view_state_->page_scale_factor_; + if (should_restore_scroll_) { + // TODO(pnoland): attempt to restore the anchor in more places than this. + // Anchor-based restore should allow for earlier restoration. + bool did_restore = LayoutViewport().RestoreScrollAnchor( + {pending_view_state_->scroll_anchor_data_.selector_, + LayoutPoint(pending_view_state_->scroll_anchor_data_.offset_.x, + pending_view_state_->scroll_anchor_data_.offset_.y), + pending_view_state_->scroll_anchor_data_.simhash_}); + if (!did_restore) { + LayoutViewport().SetScrollOffset(pending_view_state_->scroll_offset_, + kProgrammaticScroll); + } + } + // For main frame restore scale and visual viewport position + ScrollOffset visual_viewport_offset( + pending_view_state_->visual_viewport_scroll_offset_); + // If the visual viewport's offset is (-1, -1) it means the history item + // is an old version of HistoryItem so distribute the scroll between + // the main frame and the visual viewport as best as we can. + if (visual_viewport_offset.Width() == -1 && + visual_viewport_offset.Height() == -1) { + visual_viewport_offset = pending_view_state_->scroll_offset_ - + LayoutViewport().GetScrollOffset(); + } + auto* visual_viewport = static_cast<VisualViewport*>(&GetVisualViewport()); + if (should_restore_scale && should_restore_scroll_) { + visual_viewport->SetScaleAndLocation( + pending_view_state_->page_scale_factor_, + visual_viewport->IsPinchGestureActive(), + FloatPoint(visual_viewport_offset)); + } else if (should_restore_scale) { + visual_viewport->SetScale(pending_view_state_->page_scale_factor_); + } else if (should_restore_scroll_) { + visual_viewport->SetLocation(FloatPoint(visual_viewport_offset)); + } + should_restore_scroll_ = false; + pending_view_state_.reset(); + return true; +} + void RootFrameViewport::SetScrollOffset(const ScrollOffset& offset, ScrollType scroll_type, ScrollBehavior scroll_behavior, @@ -279,7 +324,7 @@ ScrollOffset RootFrameViewport::ClampToUserScrollableOffset( const ScrollOffset& offset) const { ScrollOffset scroll_offset = offset; FloatRect user_scrollable = GetUserScrollableRect(LayoutViewport()) + - GetUserScrollableRect(VisualViewport()); + GetUserScrollableRect(GetVisualViewport()); scroll_offset.SetWidth(clampTo(scroll_offset.Width(), user_scrollable.X(), user_scrollable.MaxX())); scroll_offset.SetHeight(clampTo(scroll_offset.Height(), user_scrollable.Y(), @@ -367,9 +412,9 @@ void RootFrameViewport::DistributeScrollBetweenViewports( } ScrollableArea& primary = - scroll_first == kVisualViewport ? VisualViewport() : LayoutViewport(); + scroll_first == kVisualViewport ? GetVisualViewport() : LayoutViewport(); ScrollableArea& secondary = - scroll_first == kVisualViewport ? LayoutViewport() : VisualViewport(); + scroll_first == kVisualViewport ? LayoutViewport() : GetVisualViewport(); ScrollOffset target_offset = primary.ClampScrollOffset( primary.GetScrollAnimator().CurrentOffset() + delta); @@ -407,22 +452,22 @@ IntSize RootFrameViewport::ScrollOffsetInt() const { ScrollOffset RootFrameViewport::GetScrollOffset() const { return LayoutViewport().GetScrollOffset() + - VisualViewport().GetScrollOffset(); + GetVisualViewport().GetScrollOffset(); } IntSize RootFrameViewport::MinimumScrollOffsetInt() const { return IntSize(LayoutViewport().MinimumScrollOffsetInt() + - VisualViewport().MinimumScrollOffsetInt()); + GetVisualViewport().MinimumScrollOffsetInt()); } IntSize RootFrameViewport::MaximumScrollOffsetInt() const { return LayoutViewport().MaximumScrollOffsetInt() + - VisualViewport().MaximumScrollOffsetInt(); + GetVisualViewport().MaximumScrollOffsetInt(); } ScrollOffset RootFrameViewport::MaximumScrollOffset() const { return LayoutViewport().MaximumScrollOffset() + - VisualViewport().MaximumScrollOffset(); + GetVisualViewport().MaximumScrollOffset(); } IntSize RootFrameViewport::ClampScrollOffset( @@ -447,7 +492,7 @@ bool RootFrameViewport::ScrollbarsCanBeActive() const { bool RootFrameViewport::UserInputScrollable( ScrollbarOrientation orientation) const { - return VisualViewport().UserInputScrollable(orientation) || + return GetVisualViewport().UserInputScrollable(orientation) || LayoutViewport().UserInputScrollable(orientation); } @@ -500,7 +545,8 @@ ScrollResult RootFrameViewport::UserScroll( // scroll delta, regardless of how much will actually scroll, but we need to // know how much to leave for the layout viewport. FloatSize visual_consumed_delta = - VisualViewport().GetScrollAnimator().ComputeDeltaToConsume(pixel_delta); + GetVisualViewport().GetScrollAnimator().ComputeDeltaToConsume( + pixel_delta); // Split the remaining delta between scrollable and unscrollable axes of the // layout viewport. We only pass a delta to the scrollable axes and remember @@ -530,7 +576,7 @@ ScrollResult RootFrameViewport::UserScroll( // not through the ScrollableAreas? if (visual_consumed_delta == pixel_delta) { ScrollResult visual_result = - VisualViewport().GetScrollAnimator().UserScroll( + GetVisualViewport().GetScrollAnimator().UserScroll( granularity, visual_consumed_delta, run_on_return.Release()); return visual_result; } @@ -538,8 +584,9 @@ ScrollResult RootFrameViewport::UserScroll( ScrollableArea::ScrollCallback callback = run_on_return.Release(); auto all_done = callback ? base::BarrierClosure(2, std::move(callback)) : base::RepeatingClosure(); - ScrollResult visual_result = VisualViewport().GetScrollAnimator().UserScroll( - granularity, visual_consumed_delta, all_done); + ScrollResult visual_result = + GetVisualViewport().GetScrollAnimator().UserScroll( + granularity, visual_consumed_delta, all_done); ScrollResult layout_result = LayoutViewport().GetScrollAnimator().UserScroll( granularity, scrollable_axis_delta, all_done); @@ -565,8 +612,8 @@ CompositorElementId RootFrameViewport::GetCompositorElementId() const { CompositorElementId RootFrameViewport::GetScrollbarElementId( ScrollbarOrientation orientation) { - return VisualViewport().VisualViewportSuppliesScrollbars() - ? VisualViewport().GetScrollbarElementId(orientation) + return GetVisualViewport().VisualViewportSuppliesScrollbars() + ? GetVisualViewport().GetScrollbarElementId(orientation) : LayoutViewport().GetScrollbarElementId(orientation); } @@ -581,25 +628,25 @@ SmoothScrollSequencer* RootFrameViewport::GetSmoothScrollSequencer() const { void RootFrameViewport::ServiceScrollAnimations(double monotonic_time) { ScrollableArea::ServiceScrollAnimations(monotonic_time); LayoutViewport().ServiceScrollAnimations(monotonic_time); - VisualViewport().ServiceScrollAnimations(monotonic_time); + GetVisualViewport().ServiceScrollAnimations(monotonic_time); } void RootFrameViewport::UpdateCompositorScrollAnimations() { ScrollableArea::UpdateCompositorScrollAnimations(); LayoutViewport().UpdateCompositorScrollAnimations(); - VisualViewport().UpdateCompositorScrollAnimations(); + GetVisualViewport().UpdateCompositorScrollAnimations(); } void RootFrameViewport::CancelProgrammaticScrollAnimation() { ScrollableArea::CancelProgrammaticScrollAnimation(); LayoutViewport().CancelProgrammaticScrollAnimation(); - VisualViewport().CancelProgrammaticScrollAnimation(); + GetVisualViewport().CancelProgrammaticScrollAnimation(); } void RootFrameViewport::ClearScrollableArea() { ScrollableArea::ClearScrollableArea(); LayoutViewport().ClearScrollableArea(); - VisualViewport().ClearScrollableArea(); + GetVisualViewport().ClearScrollableArea(); } ScrollbarTheme& RootFrameViewport::GetPageScrollbarTheme() const { diff --git a/chromium/third_party/blink/renderer/core/frame/root_frame_viewport.h b/chromium/third_party/blink/renderer/core/frame/root_frame_viewport.h index 9622a32ddf3..67449d770b1 100644 --- a/chromium/third_party/blink/renderer/core/frame/root_frame_viewport.h +++ b/chromium/third_party/blink/renderer/core/frame/root_frame_viewport.h @@ -121,6 +121,15 @@ class CORE_EXPORT RootFrameViewport final unsigned = 0) const final; scoped_refptr<base::SingleThreadTaskRunner> GetTimerTaskRunner() const final; ScrollbarTheme& GetPageScrollbarTheme() const override; + + void SetPendingHistoryRestoreScrollOffset( + const HistoryItem::ViewState& view_state, + bool should_restore_scroll) override { + pending_view_state_ = view_state; + should_restore_scroll_ = should_restore_scroll; + } + bool ApplyPendingHistoryRestoreScrollOffset() override; + const cc::SnapContainerData* GetSnapContainerData() const override; void SetSnapContainerData(base::Optional<cc::SnapContainerData>) override; @@ -143,7 +152,7 @@ class CORE_EXPORT RootFrameViewport final // class' animator so use this method to pull updated values when necessary. void UpdateScrollAnimator(); - ScrollableArea& VisualViewport() const { + ScrollableArea& GetVisualViewport() const { DCHECK(visual_viewport_); return *visual_viewport_; } @@ -152,6 +161,8 @@ class CORE_EXPORT RootFrameViewport final Member<ScrollableArea> visual_viewport_; Member<ScrollableArea> layout_viewport_; + base::Optional<HistoryItem::ViewState> pending_view_state_; + bool should_restore_scroll_; }; template <> diff --git a/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc b/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc index 1b4e8c96869..e31db459bf9 100644 --- a/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc +++ b/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc @@ -767,6 +767,12 @@ void VisualViewport::SetScrollOffset(const ScrollOffset& offset, scroll_behavior, std::move(on_finish)); } +void VisualViewport::SetScrollOffset(const ScrollOffset& offset, + ScrollType scroll_type, + ScrollBehavior scroll_behavior) { + SetScrollOffset(offset, scroll_type, scroll_behavior, ScrollCallback()); +} + PhysicalRect VisualViewport::ScrollIntoView( const PhysicalRect& rect_in_absolute, const WebScrollIntoViewParams& params) { diff --git a/chromium/third_party/blink/renderer/core/frame/visual_viewport.h b/chromium/third_party/blink/renderer/core/frame/visual_viewport.h index b675a62d691..2dff56c642b 100644 --- a/chromium/third_party/blink/renderer/core/frame/visual_viewport.h +++ b/chromium/third_party/blink/renderer/core/frame/visual_viewport.h @@ -97,10 +97,9 @@ struct PaintPropertyTreeBuilderFragmentContext; // +- horizontal_scrollbar_effect_node_ // +- vertical_scrollbar_effect_node_ // -class CORE_EXPORT VisualViewport final - : public GarbageCollected<VisualViewport>, - public GraphicsLayerClient, - public ScrollableArea { +class CORE_EXPORT VisualViewport : public GarbageCollected<VisualViewport>, + public GraphicsLayerClient, + public ScrollableArea { USING_GARBAGE_COLLECTED_MIXIN(VisualViewport); public: @@ -190,6 +189,9 @@ class CORE_EXPORT VisualViewport final ScrollType, ScrollBehavior, ScrollCallback on_finish) override; + void SetScrollOffset(const ScrollOffset&, + ScrollType, + ScrollBehavior = kScrollBehaviorInstant) override; PhysicalRect ScrollIntoView(const PhysicalRect&, const WebScrollIntoViewParams&) override; bool IsThrottled() const override { @@ -225,7 +227,8 @@ class CORE_EXPORT VisualViewport final CompositorAnimationTimeline* GetCompositorAnimationTimeline() const override; IntRect VisibleContentRect( IncludeScrollbarsInRect = kExcludeScrollbars) const override; - scoped_refptr<base::SingleThreadTaskRunner> GetTimerTaskRunner() const final; + scoped_refptr<base::SingleThreadTaskRunner> GetTimerTaskRunner() + const override; WebColorScheme UsedColorScheme() const override; // VisualViewport scrolling may involve pinch zoom and gets routed through diff --git a/chromium/third_party/blink/renderer/core/loader/frame_loader.cc b/chromium/third_party/blink/renderer/core/loader/frame_loader.cc index e60598f9c8c..da3caa9fa14 100644 --- a/chromium/third_party/blink/renderer/core/loader/frame_loader.cc +++ b/chromium/third_party/blink/renderer/core/loader/frame_loader.cc @@ -134,7 +134,7 @@ bool IsReloadLoadType(WebFrameLoadType type) { type == WebFrameLoadType::kReloadBypassingCache; } -static bool NeedsHistoryItemRestore(WebFrameLoadType type) { +bool FrameLoader::NeedsHistoryItemRestore(WebFrameLoadType type) { return type == WebFrameLoadType::kBackForward || IsReloadLoadType(type); } @@ -1153,79 +1153,9 @@ void FrameLoader::RestoreScrollPositionAndViewState( if (!NeedsHistoryItemRestore(load_type)) return; - bool should_restore_scroll = - scroll_restoration_type != kScrollRestorationManual; - bool should_restore_scale = view_state.page_scale_factor_; - - // This tries to balance: - // 1. restoring as soon as possible. - // 2. not overriding user scroll (TODO(majidvp): also respect user scale). - // 3. detecting clamping to avoid repeatedly popping the scroll position down - // as the page height increases. - // 4. forcing a layout if necessary to avoid clamping. - // 5. ignoring clamp detection if scroll state is not being restored, if load - // is complete, or if the navigation is same-document (as the new page may - // be smaller than the previous page). - bool can_restore_without_clamping = - view->LayoutViewport()->ClampScrollOffset(view_state.scroll_offset_) == - view_state.scroll_offset_; - - bool should_force_clamping = !frame_->IsLoading() || is_same_document; - // Here |can_restore_without_clamping| is false, but layout might be necessary - // to ensure correct content size. - if (!can_restore_without_clamping && should_force_clamping) - frame_->GetDocument()->UpdateStyleAndLayout(); - - bool can_restore_without_annoying_user = - !GetDocumentLoader()->GetInitialScrollState().was_scrolled_by_user && - (can_restore_without_clamping || should_force_clamping || - !should_restore_scroll); - if (!can_restore_without_annoying_user) - return; - - if (should_restore_scroll) { - // TODO(pnoland): attempt to restore the anchor in more places than this. - // Anchor-based restore should allow for earlier restoration. - bool did_restore = view->LayoutViewport()->RestoreScrollAnchor( - {view_state.scroll_anchor_data_.selector_, - LayoutPoint(view_state.scroll_anchor_data_.offset_.x, - view_state.scroll_anchor_data_.offset_.y), - view_state.scroll_anchor_data_.simhash_}); - if (!did_restore) { - view->LayoutViewport()->SetScrollOffset(view_state.scroll_offset_, - kProgrammaticScroll); - } - } - - // For main frame restore scale and visual viewport position - if (frame_->IsMainFrame()) { - ScrollOffset visual_viewport_offset( - view_state.visual_viewport_scroll_offset_); - - // If the visual viewport's offset is (-1, -1) it means the history item - // is an old version of HistoryItem so distribute the scroll between - // the main frame and the visual viewport as best as we can. - if (visual_viewport_offset.Width() == -1 && - visual_viewport_offset.Height() == -1) { - visual_viewport_offset = - view_state.scroll_offset_ - view->LayoutViewport()->GetScrollOffset(); - } - - VisualViewport& visual_viewport = frame_->GetPage()->GetVisualViewport(); - if (should_restore_scale && should_restore_scroll) { - visual_viewport.SetScaleAndLocation( - view_state.page_scale_factor_, visual_viewport.IsPinchGestureActive(), - FloatPoint(visual_viewport_offset)); - } else if (should_restore_scale) { - visual_viewport.SetScale(view_state.page_scale_factor_); - } else if (should_restore_scroll) { - visual_viewport.SetLocation(FloatPoint(visual_viewport_offset)); - } - - if (ScrollingCoordinator* scrolling_coordinator = - frame_->GetPage()->GetScrollingCoordinator()) - scrolling_coordinator->FrameViewRootLayerDidChange(view); - } + view->GetScrollableArea()->SetPendingHistoryRestoreScrollOffset( + view_state, scroll_restoration_type != kScrollRestorationManual); + view->ScheduleAnimation(); GetDocumentLoader()->GetInitialScrollState().did_restore_from_history = true; } diff --git a/chromium/third_party/blink/renderer/core/loader/frame_loader.h b/chromium/third_party/blink/renderer/core/loader/frame_loader.h index c16d98c82a5..44731f0ed2f 100644 --- a/chromium/third_party/blink/renderer/core/loader/frame_loader.h +++ b/chromium/third_party/blink/renderer/core/loader/frame_loader.h @@ -231,6 +231,8 @@ class CORE_EXPORT FrameLoader final { bool IsClientNavigationInitialHistoryLoad(); + static bool NeedsHistoryItemRestore(WebFrameLoadType type); + private: bool AllowRequestForThisFrame(const FrameLoadRequest&); WebFrameLoadType DetermineFrameLoadType(const KURL& url, diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc b/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc index 28b4377bb51..b6b885b848c 100644 --- a/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc +++ b/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc @@ -167,16 +167,6 @@ void ElementFragmentAnchor::DidScroll(ScrollType type) { needs_invoke_ = false; } -void ElementFragmentAnchor::DidCompleteLoad() { - DCHECK(frame_); - DCHECK(frame_->View()); - - // If there is a pending layout, the fragment anchor will be cleared when it - // finishes. - if (!frame_->View()->NeedsLayout()) - needs_invoke_ = false; -} - void ElementFragmentAnchor::Trace(blink::Visitor* visitor) { visitor->Trace(anchor_node_); visitor->Trace(frame_); diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h b/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h index f51ce60afd2..4b5c885323f 100644 --- a/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h +++ b/chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h @@ -52,9 +52,6 @@ class CORE_EXPORT ElementFragmentAnchor final : public FragmentAnchor { // so we can't do it in Invoke. void PerformPreRafActions() override; - // We can dispose of the fragment once load has been completed. - void DidCompleteLoad() override; - // Does nothing as an element anchor does not have any dismissal work. bool Dismiss() override; diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h b/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h index 7550d5674a9..5127fff25dd 100644 --- a/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h +++ b/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h @@ -51,7 +51,6 @@ class CORE_EXPORT FragmentAnchor : public GarbageCollected<FragmentAnchor> { virtual void DidScroll(ScrollType type) = 0; virtual void PerformPreRafActions() = 0; - virtual void DidCompleteLoad() = 0; // Dismissing the fragment anchor removes indicators of the anchor, such as // text highlighting on a text fragment anchor. If true, the anchor has been diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc index 3d8b5cceabf..38ac2dd9f13 100644 --- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc +++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc @@ -176,15 +176,6 @@ void TextFragmentAnchor::PerformPreRafActions() { } } -void TextFragmentAnchor::DidCompleteLoad() { - if (search_finished_) - return; - - // If there is a pending layout we'll finish the search from Invoke. - if (!frame_->View()->NeedsLayout()) - DidFinishSearch(); -} - void TextFragmentAnchor::Trace(blink::Visitor* visitor) { visitor->Trace(frame_); visitor->Trace(element_fragment_anchor_); diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h index 27d3da57a9a..9bcbfb58637 100644 --- a/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h +++ b/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h @@ -53,8 +53,6 @@ class CORE_EXPORT TextFragmentAnchor final : public FragmentAnchor, void PerformPreRafActions() override; - void DidCompleteLoad() override; - // Removes text match highlights if any highlight is in view. bool Dismiss() override; 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 399087fa006..b458c7cee0d 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 @@ -217,6 +217,23 @@ void PaintLayerScrollableArea::DisposeImpl() { layer_ = nullptr; } +bool PaintLayerScrollableArea::ApplyPendingHistoryRestoreScrollOffset() { + if (!pending_view_state_) + return false; + // TODO(pnoland): attempt to restore the anchor in more places than this. + // Anchor-based restore should allow for earlier restoration. + bool did_restore = RestoreScrollAnchor( + {pending_view_state_->scroll_anchor_data_.selector_, + LayoutPoint(pending_view_state_->scroll_anchor_data_.offset_.x, + pending_view_state_->scroll_anchor_data_.offset_.y), + pending_view_state_->scroll_anchor_data_.simhash_}); + if (!did_restore) { + SetScrollOffset(pending_view_state_->scroll_offset_, kProgrammaticScroll); + } + pending_view_state_.reset(); + return true; +} + void PaintLayerScrollableArea::Trace(blink::Visitor* visitor) { visitor->Trace(scrollbar_manager_); visitor->Trace(scroll_anchor_); diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h index dc9895c9284..540c8e7fe60 100644 --- a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h +++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h @@ -556,6 +556,16 @@ class CORE_EXPORT PaintLayerScrollableArea final void DisposeImpl() override; + void SetPendingHistoryRestoreScrollOffset( + const HistoryItem::ViewState& view_state, + bool should_restore_scroll) override { + if (!should_restore_scroll) + return; + pending_view_state_ = view_state; + } + + bool ApplyPendingHistoryRestoreScrollOffset() override; + private: bool NeedsScrollbarReconstruction() const; @@ -722,6 +732,7 @@ class CORE_EXPORT PaintLayerScrollableArea final ScrollingBackgroundDisplayItemClient scrolling_background_display_item_client_; + base::Optional<HistoryItem::ViewState> pending_view_state_; }; DEFINE_TYPE_CASTS(PaintLayerScrollableArea, diff --git a/chromium/third_party/blink/renderer/core/scroll/scrollable_area.h b/chromium/third_party/blink/renderer/core/scroll/scrollable_area.h index b3066ee7056..7af64264d17 100644 --- a/chromium/third_party/blink/renderer/core/scroll/scrollable_area.h +++ b/chromium/third_party/blink/renderer/core/scroll/scrollable_area.h @@ -30,6 +30,7 @@ #include "third_party/blink/public/platform/web_color_scheme.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h" +#include "third_party/blink/renderer/core/loader/history_item.h" #include "third_party/blink/renderer/core/scroll/scrollbar.h" #include "third_party/blink/renderer/platform/geometry/float_quad.h" #include "third_party/blink/renderer/platform/graphics/color.h" @@ -102,9 +103,9 @@ class CORE_EXPORT ScrollableArea : public GarbageCollectedMixin { ScrollType, ScrollBehavior, ScrollCallback on_finish); - void SetScrollOffset(const ScrollOffset&, - ScrollType, - ScrollBehavior = kScrollBehaviorInstant); + virtual void SetScrollOffset(const ScrollOffset&, + ScrollType, + ScrollBehavior = kScrollBehaviorInstant); void ScrollBy(const ScrollOffset&, ScrollType, ScrollBehavior = kScrollBehaviorInstant); @@ -113,6 +114,12 @@ class CORE_EXPORT ScrollableArea : public GarbageCollectedMixin { ScrollType, ScrollBehavior = kScrollBehaviorInstant); + virtual void SetPendingHistoryRestoreScrollOffset( + const HistoryItem::ViewState& view_state, + bool should_restore_scroll) {} + // Returns true if it applied anything. + virtual bool ApplyPendingHistoryRestoreScrollOffset() { return false; } + // Scrolls the area so that the given rect, given in absolute coordinates, // such that it's visible in the area. Returns the new location of the input // rect in absolute coordinates. |