Bug 1519013 - Shrink the content to display size if user has never changed the site resolution. r=botond a=pascalc
☠☠ backed out by 78075f5bf04a ☠ ☠
authorNarcis Beleuzu <nbeleuzu@mozilla.com>
Sun, 07 Apr 2019 16:50:20 +0300
changeset 526002 ee00e620926a5bf8af78b41d91fd8b670af57634
parent 526001 353c9e1559f09f75eafcb6f7897b21a75777e64a
child 526003 e8d66492c9631daf52758892782d864762d3ccc7
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond, pascalc
bugs1519013
milestone67.0
Bug 1519013 - Shrink the content to display size if user has never changed the site resolution. r=botond a=pascalc Summary: elementFromPoint-002.html, elementFromPoint-003.html and dialog-showModal.html use document.elementFromPoint with a given point which is calculated from the value returned by getBoundingClientRect() for a 100% width element. Before this change, the given point is outside of view because there is no viewport meta tag in the documents so that elementFromPoint fails. After this change, the documents fit to the visual viewport so that elementFromPoint works as expected. Reviewers: botond Reviewed By: botond Subscribers: botond Bug #: 1519013 Differential Revision: https://phabricator.services.mozilla.com/D16155
layout/base/MobileViewportManager.cpp
layout/base/MobileViewportManager.h
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/reftests/meta-viewport/dynamic-grow-width-and-height.html
layout/reftests/meta-viewport/dynamic-grow-width.html
layout/reftests/meta-viewport/overflow-hidden-region-dynamic-width-change.html
layout/reftests/meta-viewport/reftest.list
layout/reftests/meta-viewport/remove-overflow-hidden-region-ref.html
layout/reftests/meta-viewport/remove-overflow-hidden-region.html
testing/web-platform/meta/css/cssom-view/elementFromPoint-002.html.ini
testing/web-platform/meta/css/cssom-view/elementFromPoint-003.html.ini
testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html.ini
--- a/layout/base/MobileViewportManager.cpp
+++ b/layout/base/MobileViewportManager.cpp
@@ -320,19 +320,19 @@ void MobileViewportManager::UpdateResolu
                                       viewportSize, mMobileViewportSize));
       }
     }
   } else {  // aType == UpdateType::ContentSize
     MOZ_ASSERT(aType == UpdateType::ContentSize);
     MOZ_ASSERT(aDisplayWidthChangeRatio.isNothing());
 
     // We try to scale down the contents only IF the document has no
-    // initial-scale AND IF it's the initial paint AND IF it's not restored
-    // documents.
-    if (mIsFirstPaint && !mRestoreResolution &&
+    // initial-scale AND IF it's not restored documents AND IF the resolution
+    // has never been changed by APZ.
+    if (!mRestoreResolution && !mPresShell->IsResolutionUpdatedByApz() &&
         !aViewportInfo.IsDefaultZoomValid()) {
       if (zoom != intrinsicScale) {
         newZoom = Some(intrinsicScale);
       }
     } else {
       // Even in other scenarios, we want to ensure that zoom level is
       // not _smaller_ than the intrinsic scale, otherwise we might be
       // trying to show regions where there is no content to show.
--- a/layout/base/MobileViewportManager.h
+++ b/layout/base/MobileViewportManager.h
@@ -70,16 +70,23 @@ class MobileViewportManager final : publ
    * whichever happens first. Also called directly if we are created after the
    * presShell is initialized. */
   void SetInitialViewport();
 
   const mozilla::LayoutDeviceIntSize& DisplaySize() const {
     return mDisplaySize;
   };
 
+  /*
+   * Shrink the content to fit it to the display width if no initial-scale is
+   * specified and if the content is still wider than the display width.
+   */
+  void ShrinkToDisplaySizeIfNeeded(nsViewportInfo& aViewportInfo,
+                                   const mozilla::ScreenIntSize& aDisplaySize);
+
  private:
   ~MobileViewportManager();
 
   /* Main helper method to update the CSS viewport and any other properties that
    * need updating. */
   void RefreshViewportSize(bool aForceAdjustResolution);
 
   /* Secondary main helper method to update just the visual viewport size. */
@@ -128,23 +135,16 @@ class MobileViewportManager final : publ
       const mozilla::CSSSize& aViewportOrContentSize) const;
 
   /*
    * Returns the screen size subtracted the scrollbar sizes from |aDisplaySize|.
    */
   mozilla::ScreenIntSize GetCompositionSize(
       const mozilla::ScreenIntSize& aDisplaySize) const;
 
-  /*
-   * Shrink the content to fit it to the display width if no initial-scale is
-   * specified and if the content is still wider than the display width.
-   */
-  void ShrinkToDisplaySizeIfNeeded(nsViewportInfo& aViewportInfo,
-                                   const mozilla::ScreenIntSize& aDisplaySize);
-
   RefPtr<mozilla::dom::Document> mDocument;
   // raw ref since the presShell owns this
   nsIPresShell* MOZ_NON_OWNING_REF mPresShell;
   nsCOMPtr<mozilla::dom::EventTarget> mEventTarget;
   bool mIsFirstPaint;
   bool mPainted;
   mozilla::LayoutDeviceIntSize mDisplaySize;
   mozilla::CSSSize mMobileViewportSize;
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2038,16 +2038,17 @@ ScrollFrameHelper::ScrollFrameHelper(nsC
       mHasBeenScrolled(false),
       mIgnoreMomentumScroll(false),
       mTransformingByAPZ(false),
       mScrollableByAPZ(false),
       mZoomableByAPZ(false),
       mHasOutOfFlowContentInsideFilter(false),
       mSuppressScrollbarRepaints(false),
       mIsUsingMinimumScaleSize(false),
+      mMinimumScaleSizeChanged(false),
       mVelocityQueue(aOuter->PresContext()) {
   if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
     mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter));
   }
 
   EnsureFrameVisPrefsCached();
 
   if (IsAlwaysActive() && gfxPrefs::LayersTilesEnabled() &&
@@ -5609,20 +5610,48 @@ void ScrollFrameHelper::FinishReflowForS
   // Scrollbars assume zero is the minimum position, so translate for them.
   SetCoordAttribute(aElement, nsGkAtoms::curpos, aCurPosXY - aMinXY);
   SetScrollbarEnabled(aElement, aMaxXY - aMinXY);
   SetCoordAttribute(aElement, nsGkAtoms::maxpos, aMaxXY - aMinXY);
   SetCoordAttribute(aElement, nsGkAtoms::pageincrement, aPageIncrement);
   SetCoordAttribute(aElement, nsGkAtoms::increment, aIncrement);
 }
 
+class MOZ_RAII AutoMinimumScaleSizeChangeDetector final {
+ public:
+  explicit AutoMinimumScaleSizeChangeDetector(
+      ScrollFrameHelper* aScrollFrameHelper)
+      : mHelper(aScrollFrameHelper) {
+    MOZ_ASSERT(mHelper);
+    MOZ_ASSERT(mHelper->mIsRoot);
+
+    mPreviousMinimumScaleSize = aScrollFrameHelper->mMinimumScaleSize;
+    mPreviousIsUsingMinimumScaleSize =
+        aScrollFrameHelper->mIsUsingMinimumScaleSize;
+  }
+  ~AutoMinimumScaleSizeChangeDetector() {
+    if (mPreviousMinimumScaleSize != mHelper->mMinimumScaleSize ||
+        mPreviousIsUsingMinimumScaleSize != mHelper->mIsUsingMinimumScaleSize) {
+      mHelper->mMinimumScaleSizeChanged = true;
+    }
+  }
+
+ private:
+  ScrollFrameHelper* mHelper;
+
+  nsSize mPreviousMinimumScaleSize;
+  bool mPreviousIsUsingMinimumScaleSize;
+};
+
 void ScrollFrameHelper::UpdateMinimumScaleSize(
     const nsRect& aScrollableOverflow, const nsSize& aICBSize) {
   MOZ_ASSERT(mIsRoot);
 
+  AutoMinimumScaleSizeChangeDetector minimumScaleSizeChangeDetector(this);
+
   mIsUsingMinimumScaleSize = false;
 
   if (!mOuter->PresShell()->GetIsViewportOverridden()) {
     return;
   }
 
   nsPresContext* pc = mOuter->PresContext();
   MOZ_ASSERT(pc->IsRootContentDocument(),
@@ -5681,16 +5710,35 @@ void ScrollFrameHelper::UpdateMinimumSca
   mMinimumScaleSize = Max(aICBSize, mMinimumScaleSize);
 
   mIsUsingMinimumScaleSize = true;
 }
 
 bool ScrollFrameHelper::ReflowFinished() {
   mPostedReflowCallback = false;
 
+  if (mIsRoot && mMinimumScaleSizeChanged &&
+      mOuter->PresShell()->GetIsViewportOverridden() &&
+      !mOuter->PresShell()->IsResolutionUpdatedByApz()) {
+    nsIPresShell* presShell = mOuter->PresShell();
+    RefPtr<MobileViewportManager> manager =
+        presShell->GetMobileViewportManager();
+    MOZ_ASSERT(manager);
+
+    ScreenIntSize displaySize = ViewAs<ScreenPixel>(
+        manager->DisplaySize(),
+        PixelCastJustification::LayoutDeviceIsScreenForBounds);
+
+    Document* doc = presShell->GetDocument();
+    MOZ_ASSERT(doc, "The document should be valid");
+    nsViewportInfo viewportInfo = doc->GetViewportInfo(displaySize);
+    manager->ShrinkToDisplaySizeIfNeeded(viewportInfo, displaySize);
+    mMinimumScaleSizeChanged = false;
+  }
+
   bool doScroll = true;
   if (NS_SUBTREE_DIRTY(mOuter)) {
     // We will get another call after the next reflow and scrolling
     // later is less janky.
     doScroll = false;
   }
 
   nsAutoScriptBlocker scriptBlocker;
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -707,16 +707,19 @@ class ScrollFrameHelper : public nsIRefl
   bool mHasOutOfFlowContentInsideFilter : 1;
 
   // True if we don't want the scrollbar to repaint itself right now.
   bool mSuppressScrollbarRepaints : 1;
 
   // True if we are using the minimum scale size instead of ICB for scroll port.
   bool mIsUsingMinimumScaleSize : 1;
 
+  // True if the minimum scale size has been changed since the last reflow.
+  bool mMinimumScaleSizeChanged : 1;
+
   mozilla::layout::ScrollVelocityQueue mVelocityQueue;
 
  protected:
   class AutoScrollbarRepaintSuppression;
   friend class AutoScrollbarRepaintSuppression;
   class AutoScrollbarRepaintSuppression {
    public:
     AutoScrollbarRepaintSuppression(ScrollFrameHelper* aHelper, bool aSuppress)
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/dynamic-grow-width-and-height.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<!--
+  `reftest-snapshot-all` is necessary to take the screenshot for whole canvas
+  when zoom level is changed.
+  This is the same as what we do in the case where reftest-async-zoom is
+  specified.
+ -->
+<html class="reftest-wait reftest-snapshot-all">
+<meta name="viewport" content="width=device-width, minimum-scale=0.5">
+<style>
+html {
+  overflow-x: hidden;
+  scrollbar-width: none;
+}
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+}
+div {
+  position: absolute;
+}
+</style>
+<div id="green" style="background: green; width: 100%; height: 100%;"></div>
+<div style="background: blue; width: 100%; height: 100%;"></div>
+<script>
+document.addEventListener('MozReftestInvalidate', () => {
+  green.style.width = '200%';
+  requestAnimationFrame(() => {
+    // At this moment we don't scale down the contents due to bug 1508177.
+
+    green.style.height = '200%';
+    requestAnimationFrame(() => {
+      // Growing height should make the overflow-x:hidden area visible.
+      document.documentElement.classList.remove('reftest-wait');
+    });
+  });
+});
+</script>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/dynamic-grow-width.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta name="viewport" content="width=device-width, minimum-scale=0.5">
+<style>
+html {
+  overflow-x: hidden;
+}
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+}
+div {
+  height: 100%;
+  position: absolute;
+}
+</style>
+<div id="green" style="background: green; width: 100%;"></div>
+<div style="background: blue; width: 100%;"></div>
+<script>
+document.addEventListener('MozReftestInvalidate', () => {
+  // Grow width to generate overflow-x:hidden area but the content height is
+  // 100vh so that we don't scale down the contents (bug 1508177).
+  green.style.width = '200%';
+  requestAnimationFrame(() => {
+    document.documentElement.classList.remove('reftest-wait');
+  });
+});
+</script>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/overflow-hidden-region-dynamic-width-change.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<!--
+  `reftest-snapshot-all` is necessary to take the screenshot for whole canvas
+  when zoom level is changed.
+  This is the same as what we do in the case where reftest-async-zoom is
+  specified.
+ -->
+<html class="reftest-wait reftest-snapshot-all">
+<meta name="viewport" content="width=device-width, minimum-scale=0.5">
+<style>
+html {
+  overflow: hidden;
+}
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+}
+div {
+  position: absolute;
+}
+</style>
+<div id="red" style="background: red; width: 100%; height: 300%;"></div>
+<div id="green" style="background: green; width: 100%; height: 200%;"></div>
+<div style="background: blue; width: 100%; height: 100%;"></div>
+<script>
+document.addEventListener('MozReftestInvalidate', () => {
+  green.style.width = '200%';
+  red.style.width = '300%';
+  requestAnimationFrame(() => {
+    document.documentElement.classList.remove('reftest-wait');
+  });
+});
+</script>
+</html>
--- a/layout/reftests/meta-viewport/reftest.list
+++ b/layout/reftests/meta-viewport/reftest.list
@@ -17,10 +17,14 @@ skip-if(!Android) == position-fixed-on-m
 # Skip below tests on Windows (bug 1516322) on Webrender (bug 1520096)
 skip-if(winWidget||webrender) == overflow-region.html overflow-region-ref.html
 skip-if(winWidget||webrender) == overflow-hidden-region.html overflow-region-ref.html
 skip-if(winWidget||webrender) == overflow-hidden-region-with-negative-left-positioned-element.html overflow-region-ref.html
 skip-if(winWidget||webrender) fails == horizontal-overflow-hidden-region.html horizontal-overflow-hidden-region-ref.html # bug 1508177
 skip-if(winWidget||webrender) == vertical-overflow-hidden-region.html about:blank
 skip-if(winWidget||webrender) == scroll-to-unreachable-area.html scroll-to-unreachable-area-ref.html
 skip-if(winWidget||webrender) == wrapped-text-at-icb.html wrapped-text-at-icb-ref.html
+skip-if(winWidget||webrender) == overflow-hidden-region-dynamic-width-change.html overflow-region-ref.html
+skip-if(winWidget||webrender) == remove-overflow-hidden-region.html remove-overflow-hidden-region-ref.html
+skip-if(winWidget||webrender) fails == dynamic-grow-width.html horizontal-overflow-hidden-region-ref.html # bug 1508177
+skip-if(winWidget||webrender) == dynamic-grow-width-and-height.html overflow-region-ref.html
 skip-if(winWidget||webrender) == not-able-to-scrollTo.html about:blank
 skip-if(winWidget||webrender) == min-scale-aspect-ratio.html about:blank
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/remove-overflow-hidden-region-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+html {
+  overflow: hidden;
+}
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+}
+div {
+  position: absolute;
+}
+</style>
+<div style="background: blue; width: 100%; height: 100%;"></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/remove-overflow-hidden-region.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta name="viewport" content="width=device-width, minimum-scale=0.5">
+<style>
+html {
+  overflow: hidden;
+}
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+}
+div {
+  position: absolute;
+}
+</style>
+<div id="green" style="background: green; width: 200%; height: 200%;"></div>
+<div style="background: blue; width: 100%; height: 100%; height: 100%;"></div>
+<script>
+document.addEventListener('MozReftestInvalidate', () => {
+  green.style.width = '100%';
+  document.documentElement.classList.remove('reftest-wait');
+});
+</script>
+</html>
deleted file mode 100644
--- a/testing/web-platform/meta/css/cssom-view/elementFromPoint-002.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[elementFromPoint-002.html]
-  [Checking whether dynamic changes to visibility interact correctly with\n  table anonymous boxes]
-    expected:
-      if (os == "android"): FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/cssom-view/elementFromPoint-003.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[elementFromPoint-003.html]
-  [Checking whether dynamic changes to visibility interact correctly with\n  table anonymous boxes]
-    expected:
-      if (os == "android"): FAIL
--- a/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html.ini
+++ b/testing/web-platform/meta/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html.ini
@@ -7,12 +7,8 @@
     expected: FAIL
 
   [opening dialog with multiple focusable children]
     expected: FAIL
 
   [opening dialog with multiple focusable children, one having the autofocus attribute]
     expected: FAIL
 
-  [when opening multiple dialogs, the most recently opened is rendered on top]
-    expected:
-      if (os == "android"): FAIL
-