summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTamas Zakor <ztamas@inf.u-szeged.hu>2020-02-10 15:52:16 +0100
committerTamas Zakor <ztamas@inf.u-szeged.hu>2020-02-11 13:13:34 +0000
commit7c8b94f2916779c7e0eebd1c2dc6b8c713acb3a2 (patch)
tree39b13ee0323a52a2cf4c306a90dea7bf78a45d00
parent1d119e1884d6ee26f1122136867c75fb50091d4f (diff)
downloadqtwebengine-chromium-7c8b94f2916779c7e0eebd1c2dc6b8c713acb3a2.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.h13
-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, 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.