summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTamas Zakor <ztamas@inf.u-szeged.hu>2020-02-10 15:52:16 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-03-25 13:45:49 +0100
commit42b3867d6e6530567b22bb960fbd5c391121c36d (patch)
tree2500f5a59c4ead63ffa675ce1c5bdd03727c9ba7
parentf32e6ea26beca53862b2570d29fb1a512286bb71 (diff)
downloadqtwebengine-chromium-42b3867d6e6530567b22bb960fbd5c391121c36d.tar.gz
[Backport] Re-land: Only invoke text and element fragment anchors after layout.
This reverts commit f3d96d04734f1e2d1384d558b72f9e8fcfca265b. The original commit was reverted because it caused flakiness in some browser tests (in particular, HostZoomMapBrowserTest.PageScaleIsOneChanged) The flakiness was caused by a real bug in the CL, which is fixed in the latest patchset. The bug was that the base::Optional pending_view_state_ was not being rest after being applied. See https://chromium-review.googlesource.com/c/chromium/src/+/1981806/1..3 for what has changed from the original CL. Bug: 1018632 Fixes: QTBUG-79369 Change-Id: I86fcdb403678a5890a2e9d1abcab3ea1d5a639d9 Reviewed-by: Philip Rogers <pdr@chromium.org> Commit-Queue: Chris Harrelson <chrishtr@chromium.org> Cr-Commit-Position: refs/heads/master@{#727481} Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document.cc57
-rw-r--r--chromium/third_party/blink/renderer/core/dom/document.h2
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_view.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/frame/root_frame_viewport.cc103
-rw-r--r--chromium/third_party/blink/renderer/core/frame/root_frame_viewport.h13
-rw-r--r--chromium/third_party/blink/renderer/core/frame/visual_viewport.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/frame/visual_viewport.h8
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_loader.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/loader/frame_loader.h2
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h3
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h1
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h11
-rw-r--r--chromium/third_party/blink/renderer/core/scroll/scrollable_area.h13
17 files changed, 213 insertions, 146 deletions
diff --git a/chromium/third_party/blink/renderer/core/dom/document.cc b/chromium/third_party/blink/renderer/core/dom/document.cc
index 2247f71c3c9..a5333977dcd 100644
--- a/chromium/third_party/blink/renderer/core/dom/document.cc
+++ b/chromium/third_party/blink/renderer/core/dom/document.cc
@@ -3008,6 +3008,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()) {
@@ -3060,6 +3100,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();
@@ -3074,11 +3116,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()) {
@@ -4200,6 +4237,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 3d25b6321cb..e5dbe7ea6a0 100644
--- a/chromium/third_party/blink/renderer/core/dom/document.h
+++ b/chromium/third_party/blink/renderer/core/dom/document.h
@@ -1657,6 +1657,8 @@ class CORE_EXPORT Document : public ContainerNode,
}
#endif
+ 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 889b5da440b..9af30d33d15 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
@@ -452,6 +452,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);
+ }
+ }
}
}
@@ -1392,11 +1399,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();
}
}
@@ -1482,9 +1489,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) {
@@ -2982,6 +2986,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 c7b59db75b5..1c9019b2586 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/paint/paint_layer_scrollable_area.h"
@@ -47,7 +48,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);
}
@@ -93,15 +94,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();
@@ -119,8 +120,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() {
@@ -167,7 +168,7 @@ void RootFrameViewport::UpdateScrollAnimator() {
}
ScrollOffset RootFrameViewport::ScrollOffsetFromScrollAnimators() const {
- return VisualViewport().GetScrollAnimator().CurrentOffset() +
+ return GetVisualViewport().GetScrollAnimator().CurrentOffset() +
LayoutViewport().GetScrollAnimator().CurrentOffset();
}
@@ -175,7 +176,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(
@@ -189,9 +190,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);
@@ -240,6 +241,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,
@@ -278,7 +323,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(),
@@ -362,9 +407,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);
@@ -402,22 +447,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(
@@ -446,7 +491,7 @@ bool RootFrameViewport::ScrollbarsCanBeActive() const {
bool RootFrameViewport::UserInputScrollable(
ScrollbarOrientation orientation) const {
- return VisualViewport().UserInputScrollable(orientation) ||
+ return GetVisualViewport().UserInputScrollable(orientation) ||
LayoutViewport().UserInputScrollable(orientation);
}
@@ -499,7 +544,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
@@ -529,7 +575,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;
}
@@ -537,8 +583,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);
@@ -564,8 +611,8 @@ CompositorElementId RootFrameViewport::GetScrollElementId() const {
CompositorElementId RootFrameViewport::GetScrollbarElementId(
ScrollbarOrientation orientation) {
- return VisualViewport().VisualViewportSuppliesScrollbars()
- ? VisualViewport().GetScrollbarElementId(orientation)
+ return GetVisualViewport().VisualViewportSuppliesScrollbars()
+ ? GetVisualViewport().GetScrollbarElementId(orientation)
: LayoutViewport().GetScrollbarElementId(orientation);
}
@@ -580,25 +627,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 2b70633aba1..556aa86b691 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
@@ -122,6 +122,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;
bool SetTargetSnapAreaElementIds(cc::TargetSnapAreaElementIds) override;
@@ -147,7 +156,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_;
}
@@ -156,6 +165,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 e8ba80bad3e..6ba9cb37ca0 100644
--- a/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc
+++ b/chromium/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -707,6 +707,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 eb4cc33d9b3..cbea77d5b89 100644
--- a/chromium/third_party/blink/renderer/core/frame/visual_viewport.h
+++ b/chromium/third_party/blink/renderer/core/frame/visual_viewport.h
@@ -92,7 +92,7 @@ struct PaintPropertyTreeBuilderFragmentContext;
// +- horizontal_scrollbar_effect_node_
// +- vertical_scrollbar_effect_node_
//
-class CORE_EXPORT VisualViewport final
+class CORE_EXPORT VisualViewport
: public GarbageCollected<VisualViewport>,
public ScrollableArea {
USING_GARBAGE_COLLECTED_MIXIN(VisualViewport);
@@ -178,6 +178,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 {
@@ -213,7 +216,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 746c175f527..158ca2f8bac 100644
--- a/chromium/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -132,7 +132,7 @@ bool IsReloadLoadType(WebFrameLoadType type) {
type == WebFrameLoadType::kReloadBypassingCache;
}
-static bool NeedsHistoryItemRestore(WebFrameLoadType type) {
+bool FrameLoader::NeedsHistoryItemRestore(WebFrameLoadType type) {
return type == WebFrameLoadType::kBackForward || IsReloadLoadType(type);
}
@@ -1169,79 +1169,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 73dc75a7693..d884f0cc726 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
@@ -168,16 +168,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 d26d801edb3..2a6feeafa08 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
@@ -187,15 +187,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 c2ff5b6ecf3..269a94b1c88 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
@@ -228,6 +228,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 c5a4495f359..ec73b820893 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
@@ -580,6 +580,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;
@@ -768,6 +778,7 @@ class CORE_EXPORT PaintLayerScrollableArea final
ScrollingBackgroundDisplayItemClient
scrolling_background_display_item_client_{*this};
ScrollCornerDisplayItemClient scroll_corner_display_item_client_{*this};
+ 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 284280d5552..480285b3a03 100644
--- a/chromium/third_party/blink/renderer/core/scroll/scrollable_area.h
+++ b/chromium/third_party/blink/renderer/core/scroll/scrollable_area.h
@@ -31,6 +31,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"
@@ -103,9 +104,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);
@@ -114,6 +115,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.