Bug 1518640 - Use the visual viewport for anchor node selection. r=botond
authorRyan Hunt <rhunt@eqrion.net>
Tue, 22 Jan 2019 13:37:16 -0600
changeset 515121 38398e4011d7959ea97998d6df34f15519201a0d
parent 515096 f052949e151b1f2cfd9203a507a94ddd42392ec4
child 515122 551abefb4933ba447468a385bd9f7f9478592173
child 515132 4f1ff0e34dd59539c8c0d133ecdff5660ec4e263
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1518640
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1518640 - Use the visual viewport for anchor node selection. r=botond
layout/base/PresShell.cpp
layout/generic/ScrollAnchorContainer.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -10110,31 +10110,43 @@ void nsIPresShell::SetVisualViewportSize
             GetRootScrollFrameAsScrollable()) {
       rootScrollFrame->MarkScrollbarsDirtyForReflow();
     }
     MarkFixedFramesForReflow(nsIPresShell::eResize);
 
     if (auto* window = nsGlobalWindowInner::Cast(mDocument->GetInnerWindow())) {
       window->VisualViewport()->PostResizeEvent();
     }
+
+    if (nsIScrollableFrame* rootScrollFrame =
+            GetRootScrollFrameAsScrollable()) {
+      ScrollAnchorContainer* container = rootScrollFrame->GetAnchor();
+      container->UserScrolled();
+    }
   }
 }
 
 bool nsIPresShell::SetVisualViewportOffset(
     const nsPoint& aScrollOffset, const nsPoint& aPrevLayoutScrollPos) {
   bool didChange = false;
   if (GetVisualViewportOffset() != aScrollOffset) {
     nsPoint prevOffset = GetVisualViewportOffset();
     mVisualViewportOffset = Some(aScrollOffset);
     didChange = true;
 
     if (auto* window = nsGlobalWindowInner::Cast(mDocument->GetInnerWindow())) {
       window->VisualViewport()->PostScrollEvent(prevOffset,
                                                 aPrevLayoutScrollPos);
     }
+
+    if (nsIScrollableFrame* rootScrollFrame =
+            GetRootScrollFrameAsScrollable()) {
+      ScrollAnchorContainer* container = rootScrollFrame->GetAnchor();
+      container->UserScrolled();
+    }
   }
   return didChange;
 }
 
 nsPoint nsIPresShell::GetVisualViewportOffsetRelativeToLayoutViewport() const {
   return GetVisualViewportOffset() - GetLayoutViewportOffset();
 }
 
--- a/layout/generic/ScrollAnchorContainer.cpp
+++ b/layout/generic/ScrollAnchorContainer.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ScrollAnchorContainer.h"
 
 #include "GeckoProfiler.h"
 #include "mozilla/dom/Text.h"
 #include "mozilla/StaticPrefs.h"
+#include "mozilla/ToString.h"
 #include "nsGfxScrollFrame.h"
 #include "nsLayoutUtils.h"
 
 #define ANCHOR_LOG(...)
 // #define ANCHOR_LOG(...) printf_stderr("ANCHOR: " __VA_ARGS__)
 
 namespace mozilla {
 namespace layout {
@@ -158,19 +159,19 @@ void ScrollAnchorContainer::SelectAnchor
   MOZ_ASSERT(mScrollFrame->mScrolledFrame);
   MOZ_ASSERT(mAnchorNodeIsDirty);
 
   if (!StaticPrefs::layout_css_scroll_anchoring_enabled()) {
     return;
   }
 
   AUTO_PROFILER_LABEL("ScrollAnchorContainer::SelectAnchor", LAYOUT);
-  ANCHOR_LOG("Selecting anchor for %p with scroll-port [%d %d x %d %d].\n",
-             this, mScrollFrame->mScrollPort.x, mScrollFrame->mScrollPort.y,
-             mScrollFrame->mScrollPort.width, mScrollFrame->mScrollPort.height);
+  ANCHOR_LOG(
+      "Selecting anchor for %p with scroll-port=%s.\n", this,
+      mozilla::ToString(mScrollFrame->GetVisualOptimalViewingRect()).c_str());
 
   const nsStyleDisplay* disp = Frame()->StyleDisplay();
 
   // Don't select a scroll anchor if the scroll frame has `overflow-anchor:
   // none`.
   bool overflowAnchor =
       disp->mOverflowAnchor == mozilla::StyleOverflowAnchor::Auto;
 
@@ -431,17 +432,18 @@ ScrollAnchorContainer::ExamineAnchorCand
              rect.height);
 
   // Check if this frame is visible in the scroll port. This will exclude rects
   // with zero sized area. The specification is ambiguous about this [1], but
   // this matches Blink's implementation.
   //
   // [1] https://github.com/w3c/csswg-drafts/issues/3483
   nsRect visibleRect;
-  if (!visibleRect.IntersectRect(rect, mScrollFrame->mScrollPort)) {
+  if (!visibleRect.IntersectRect(rect,
+                                 mScrollFrame->GetVisualOptimalViewingRect())) {
     return ExamineResult::Exclude;
   }
 
   // At this point, if canDescend is true, we should only have visible
   // non-anonymous frames that are either:
   //   1. block-outside
   //   2. text nodes
   //
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3978,16 +3978,27 @@ nsSize ScrollFrameHelper::GetVisualViewp
 nsPoint ScrollFrameHelper::GetVisualViewportOffset() const {
   nsIPresShell* presShell = mOuter->PresShell();
   if (mIsRoot && presShell->IsVisualViewportSizeSet()) {
     return presShell->GetVisualViewportOffset();
   }
   return GetScrollPosition();
 }
 
+nsRect ScrollFrameHelper::GetVisualOptimalViewingRect() const {
+  nsIPresShell* presShell = mOuter->PresShell();
+
+  if (mIsRoot && presShell->IsVisualViewportSizeSet() &&
+      presShell->IsVisualViewportOffsetSet()) {
+    return nsRect(presShell->GetVisualViewportOffset(),
+                  presShell->GetVisualViewportSize());
+  }
+  return mScrollPort;
+}
+
 static void AdjustForWholeDelta(int32_t aDelta, nscoord* aCoord) {
   if (aDelta < 0) {
     *aCoord = nscoord_MIN;
   } else if (aDelta > 0) {
     *aCoord = nscoord_MAX;
   }
 }
 
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -215,16 +215,25 @@ class ScrollFrameHelper : public nsIRefl
     return pt;
   }
   nsPoint GetApzScrollPosition() const { return mApzScrollPos; }
   nsRect GetScrollRange() const;
   // Get the scroll range assuming the viewport has size (aWidth, aHeight).
   nsRect GetScrollRange(nscoord aWidth, nscoord aHeight) const;
   nsSize GetVisualViewportSize() const;
   nsPoint GetVisualViewportOffset() const;
+
+  /**
+   * Return the 'optimal viewing region' [1] as a rect suitable for use by
+   * scroll anchoring.
+   *
+   * [1] https://drafts.csswg.org/css-scroll-snap-1/#optimal-viewing-region
+   */
+  nsRect GetVisualOptimalViewingRect() const;
+
   /**
    * For LTR frames, this is the same as GetVisualViewportOffset().
    * For RTL frames, we take the offset from the top right corner of the frame
    * to the top right corner of the visual viewport.
    */
   nsPoint GetLogicalVisualViewportOffset() const {
     nsPoint pt = GetVisualViewportOffset();
     if (!IsPhysicalLTR()) {