Bug 1423013 - Expand the layout viewport to the minimum scale size for overflow:hidden pages. r=botond,tnikkel
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Tue, 15 Jan 2019 09:48:18 +0000
changeset 453908 895cc0297ce2e47092dc5736cd444a573ba03ed2
parent 453907 9d1c137922e113fda75af1aa8eea0859b6fadb69
child 453909 da8b6bcd0deb5c1235d743e136ce240951eb2b8b
push id35378
push userbtara@mozilla.com
push dateTue, 15 Jan 2019 16:08:45 +0000
treeherdermozilla-central@5090d461e169 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond, tnikkel
bugs1423013
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 1423013 - Expand the layout viewport to the minimum scale size for overflow:hidden pages. r=botond,tnikkel Depends on D15345 Differential Revision: https://phabricator.services.mozilla.com/D15347
layout/base/MobileViewportManager.h
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/painting/nsDisplayList.cpp
layout/reftests/meta-viewport/horizontal-overflow-hidden-region-ref.html
layout/reftests/meta-viewport/horizontal-overflow-hidden-region.html
layout/reftests/meta-viewport/overflow-hidden-region-with-negative-left-positioned-element.html
layout/reftests/meta-viewport/overflow-hidden-region.html
layout/reftests/meta-viewport/overflow-region-ref.html
layout/reftests/meta-viewport/overflow-region.html
layout/reftests/meta-viewport/reftest.list
layout/reftests/meta-viewport/scroll-to-unreachable-area-ref.html
layout/reftests/meta-viewport/scroll-to-unreachable-area.html
layout/reftests/meta-viewport/vertical-overflow-hidden-region.html
layout/reftests/meta-viewport/wrapped-text-at-icb-ref.html
layout/reftests/meta-viewport/wrapped-text-at-icb.html
--- a/layout/base/MobileViewportManager.h
+++ b/layout/base/MobileViewportManager.h
@@ -66,16 +66,20 @@ class MobileViewportManager final : publ
    * updated, and the visual viewport size needs to be updated. */
   void ResolutionUpdated();
 
   /* Called to compute the initial viewport on page load or before-first-paint,
    * whichever happens first. Also called directly if we are created after the
    * presShell is initialized. */
   void SetInitialViewport();
 
+  const mozilla::LayoutDeviceIntSize& DisplaySize() const {
+    return mDisplaySize;
+  };
+
  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. */
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -10,16 +10,17 @@
 
 #include "ActiveLayerTracker.h"
 #include "base/compiler_specific.h"
 #include "DisplayItemClip.h"
 #include "nsCOMPtr.h"
 #include "nsIContentViewer.h"
 #include "nsPresContext.h"
 #include "nsView.h"
+#include "nsViewportInfo.h"
 #include "nsIScrollable.h"
 #include "nsContainerFrame.h"
 #include "nsGkAtoms.h"
 #include "nsNameSpaceManager.h"
 #include "mozilla/dom/DocumentInlines.h"
 #include "nsFontMetrics.h"
 #include "nsBoxLayoutState.h"
 #include "mozilla/dom/NodeInfo.h"
@@ -367,19 +368,24 @@ bool nsHTMLScrollFrame::TryLayout(Scroll
   desiredInsideBorderSize.width =
       vScrollbarDesiredWidth +
       std::max(aKidMetrics->Width(), hScrollbarMinWidth);
   desiredInsideBorderSize.height =
       hScrollbarDesiredHeight +
       std::max(aKidMetrics->Height(), vScrollbarMinHeight);
   aState->mInsideBorderSize =
       ComputeInsideBorderSize(aState, desiredInsideBorderSize);
-  nsSize scrollPortSize = nsSize(
-      std::max(0, aState->mInsideBorderSize.width - vScrollbarDesiredWidth),
-      std::max(0, aState->mInsideBorderSize.height - hScrollbarDesiredHeight));
+
+  nsSize layoutSize = mHelper.mIsUsingMinimumScaleSize
+                          ? mHelper.mMinimumScaleSize
+                          : aState->mInsideBorderSize;
+
+  nsSize scrollPortSize =
+      nsSize(std::max(0, layoutSize.width - vScrollbarDesiredWidth),
+             std::max(0, layoutSize.height - hScrollbarDesiredHeight));
 
   nsSize visualViewportSize = scrollPortSize;
   nsIPresShell* presShell = PresShell();
   if (mHelper.mIsRoot && presShell->IsVisualViewportSizeSet()) {
     nsSize compositionSize =
         nsLayoutUtils::CalculateCompositionSizeForFrame(this, false);
     float resolution = presShell->GetResolution();
     compositionSize.width /= resolution;
@@ -442,18 +448,17 @@ bool nsHTMLScrollFrame::TryLayout(Scroll
     doc->UpdateViewportOverflowType(scrolledWidth, scrollPortSize.width);
   } while (false);
 
   aState->mShowHScrollbar = aAssumeHScroll;
   aState->mShowVScrollbar = aAssumeVScroll;
   nsPoint scrollPortOrigin(aState->mComputedBorder.left,
                            aState->mComputedBorder.top);
   if (!IsScrollbarOnRight()) {
-    nscoord vScrollbarActualWidth =
-        aState->mInsideBorderSize.width - scrollPortSize.width;
+    nscoord vScrollbarActualWidth = layoutSize.width - scrollPortSize.width;
     scrollPortOrigin.x += vScrollbarActualWidth;
   }
   mHelper.mScrollPort = nsRect(scrollPortOrigin, scrollPortSize);
   return true;
 }
 
 // XXX Height/BSize mismatch needs to be addressed here; check the caller!
 // Currently this will only behave as expected for horizontal writing modes.
@@ -712,16 +717,22 @@ void nsHTMLScrollFrame::ReflowContents(S
         kidDesiredSize.ScrollableOverflow(), insideBorderSize);
     if (nsRect(nsPoint(0, 0), insideBorderSize).Contains(scrolledRect)) {
       // Let's pretend we had no scrollbars coming in here
       kidDesiredSize.mOverflowAreas.Clear();
       ReflowScrolledFrame(aState, false, false, &kidDesiredSize);
     }
   }
 
+  if (IsRootScrollFrameOfDocument()) {
+    mHelper.UpdateMinimumScaleSize(
+        aState->mContentsOverflowAreas.ScrollableOverflow(),
+        kidDesiredSize.PhysicalSize());
+  }
+
   // Try vertical scrollbar settings that leave the vertical scrollbar
   // unchanged. Do this first because changing the vertical scrollbar setting is
   // expensive, forcing a reflow always.
 
   // Try leaving the horizontal scrollbar unchanged first. This will be more
   // efficient.
   if (TryLayout(aState, &kidDesiredSize,
                 aState->mReflowedContentsWithHScrollbar,
@@ -1043,20 +1054,21 @@ void nsHTMLScrollFrame::Reflow(nsPresCon
       mHelper.mScrolledFrame->GetScrollableOverflowRectRelativeToParent();
   nsPoint oldScrollPosition = mHelper.GetScrollPosition();
 
   state.mComputedBorder = aReflowInput.ComputedPhysicalBorderPadding() -
                           aReflowInput.ComputedPhysicalPadding();
 
   ReflowContents(&state, aDesiredSize);
 
-  aDesiredSize.Width() =
-      state.mInsideBorderSize.width + state.mComputedBorder.LeftRight();
-  aDesiredSize.Height() =
-      state.mInsideBorderSize.height + state.mComputedBorder.TopBottom();
+  nsSize layoutSize = mHelper.mIsUsingMinimumScaleSize
+                          ? mHelper.mMinimumScaleSize
+                          : state.mInsideBorderSize;
+  aDesiredSize.Width() = layoutSize.width + state.mComputedBorder.LeftRight();
+  aDesiredSize.Height() = layoutSize.height + state.mComputedBorder.TopBottom();
 
   // Set the size of the frame now since computing the perspective-correct
   // overflow (within PlaceScrollArea) can rely on it.
   SetSize(aDesiredSize.GetWritingMode(),
           aDesiredSize.Size(aDesiredSize.GetWritingMode()));
 
   // Restore the old scroll position, for now, even if that's not valid anymore
   // because we changed size. We'll fix it up in a post-reflow callback, because
@@ -1086,17 +1098,17 @@ void nsHTMLScrollFrame::Reflow(nsPresCon
       mHelper.mSkippedScrollbarLayout = false;
       ScrollFrameHelper::SetScrollbarVisibility(mHelper.mHScrollbarBox,
                                                 state.mShowHScrollbar);
       ScrollFrameHelper::SetScrollbarVisibility(mHelper.mVScrollbarBox,
                                                 state.mShowVScrollbar);
       // place and reflow scrollbars
       nsRect insideBorderArea =
           nsRect(nsPoint(state.mComputedBorder.left, state.mComputedBorder.top),
-                 state.mInsideBorderSize);
+                 layoutSize);
       mHelper.LayoutScrollbars(state.mBoxState, insideBorderArea,
                                oldScrollAreaBounds);
     } else {
       mHelper.mSkippedScrollbarLayout = true;
     }
   }
 
   aDesiredSize.SetOverflowAreasToDesiredBounds();
@@ -1993,16 +2005,17 @@ ScrollFrameHelper::ScrollFrameHelper(nsC
       mAddClipRectToLayer(false),
       mHasBeenScrolled(false),
       mIgnoreMomentumScroll(false),
       mTransformingByAPZ(false),
       mScrollableByAPZ(false),
       mZoomableByAPZ(false),
       mHasOutOfFlowContentInsideFilter(false),
       mSuppressScrollbarRepaints(false),
+      mIsUsingMinimumScaleSize(false),
       mVelocityQueue(aOuter->PresContext()) {
   if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
     mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter));
   }
 
   EnsureFrameVisPrefsCached();
 
   if (IsAlwaysActive() && gfxPrefs::LayersTilesEnabled() &&
@@ -5440,16 +5453,75 @@ 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);
 }
 
+void ScrollFrameHelper::UpdateMinimumScaleSize(
+    const nsRect& aScrollableOverflow, const nsSize& aICBSize) {
+  MOZ_ASSERT(mIsRoot);
+
+  mIsUsingMinimumScaleSize = false;
+
+  if (!mOuter->PresShell()->GetIsViewportOverridden()) {
+    return;
+  }
+
+  nsPresContext* pc = mOuter->PresContext();
+  MOZ_ASSERT(pc->IsRootContentDocument(),
+             "The pres context should be for the root content document");
+
+  const ScrollStyles& styles = pc->GetViewportScrollStylesOverride();
+  // FIXME: Bug 1520077 - Drop this check. We should use the minimum-scale size
+  // even if no overflow:hidden is specified.
+  if (styles.mHorizontal != StyleOverflow::Hidden) {
+    return;
+  }
+
+  RefPtr<MobileViewportManager> manager =
+      mOuter->PresShell()->GetMobileViewportManager();
+  MOZ_ASSERT(manager);
+
+  ScreenIntSize displaySize = ViewAs<ScreenPixel>(
+      manager->DisplaySize(),
+      PixelCastJustification::LayoutDeviceIsScreenForBounds);
+  if (displaySize.width == 0 || displaySize.height == 0) {
+    return;
+  }
+
+  Document* doc = pc->Document();
+  MOZ_ASSERT(doc, "The document should be valid");
+  nsViewportInfo viewportInfo = doc->GetViewportInfo(displaySize);
+  // FIXME: Bug 1520081 - Drop this check. We should use the minimum-scale size
+  // even if the minimum-scale size is greater than 1.0.
+  if (viewportInfo.GetMinZoom() >=
+      pc->CSSToDevPixelScale() * LayoutDeviceToScreenScale(1.0f)) {
+    return;
+  }
+
+  nsSize maximumPossibleSize =
+      CSSSize::ToAppUnits(ScreenSize(displaySize) / viewportInfo.GetMinZoom());
+
+  mMinimumScaleSize =
+      Min(maximumPossibleSize,
+          nsSize(aScrollableOverflow.XMost(), aScrollableOverflow.YMost()));
+  mMinimumScaleSize = Max(aICBSize, mMinimumScaleSize);
+
+  // Chrome doesn't allow overflow-y:hidden region reachable if there is no
+  // overflow-x:hidden region.
+  // TODO: Bug 1508177: We can drop this condition once after we shrink the
+  // content even if no content area gets visible.
+  if (mMinimumScaleSize.width != aICBSize.width) {
+    mIsUsingMinimumScaleSize = true;
+  }
+}
+
 bool ScrollFrameHelper::ReflowFinished() {
   mPostedReflowCallback = 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;
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -513,16 +513,21 @@ class ScrollFrameHelper : public nsIRefl
   bool DragScroll(WidgetEvent* aEvent);
 
   void AsyncScrollbarDragInitiated(uint64_t aDragBlockId,
                                    mozilla::layers::ScrollDirection aDirection);
   void AsyncScrollbarDragRejected();
 
   bool IsRootScrollFrameOfDocument() const { return mIsRoot; }
 
+  // Update minimum-scale size.  The minimum-scale size will be set/used only
+  // if there is overflow-x:hidden region.
+  void UpdateMinimumScaleSize(const nsRect& aScrollableOverflow,
+                              const nsSize& aICBSize);
+
   // owning references to the nsIAnonymousContentCreator-built content
   nsCOMPtr<mozilla::dom::Element> mHScrollbarContent;
   nsCOMPtr<mozilla::dom::Element> mVScrollbarContent;
   nsCOMPtr<mozilla::dom::Element> mScrollCornerContent;
   nsCOMPtr<mozilla::dom::Element> mResizerContent;
 
   RefPtr<ScrollEvent> mScrollEvent;
   RefPtr<ScrollEndEvent> mScrollEndEvent;
@@ -538,17 +543,21 @@ class ScrollFrameHelper : public nsIRefl
   RefPtr<AsyncScroll> mAsyncScroll;
   RefPtr<AsyncSmoothMSDScroll> mAsyncSmoothMSDScroll;
   RefPtr<ScrollbarActivity> mScrollbarActivity;
   nsTArray<nsIScrollPositionListener*> mListeners;
   nsAtom* mLastScrollOrigin;
   nsAtom* mLastSmoothScrollOrigin;
   Maybe<nsPoint> mApzSmoothScrollDestination;
   uint32_t mScrollGeneration;
+  // NOTE: On mobile this value might be factoring into overflow:hidden region
+  // in the case of the top level document.
   nsRect mScrollPort;
+  nsSize mMinimumScaleSize;
+
   // Where we're currently scrolling to, if we're scrolling asynchronously.
   // If we're not in the middle of an asynchronous scroll then this is
   // just the current scroll position. ScrollBy will choose its
   // destination based on this value.
   nsPoint mDestination;
 
   // A goal position to try to scroll to as content loads. As long as mLastPos
   // matches the current logical scroll position, we try to scroll to
@@ -665,16 +674,19 @@ class ScrollFrameHelper : public nsIRefl
 
   // True if the scroll frame contains out-of-flow content and is inside
   // a CSS filter.
   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;
+
   mozilla::layout::ScrollVelocityQueue mVelocityQueue;
 
  protected:
   class AutoScrollbarRepaintSuppression;
   friend class AutoScrollbarRepaintSuppression;
   class AutoScrollbarRepaintSuppression {
    public:
     AutoScrollbarRepaintSuppression(ScrollFrameHelper* aHelper, bool aSuppress)
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -6449,22 +6449,26 @@ UniquePtr<ScrollMetadata> nsDisplaySubDo
   ContainerLayerParameters params(
       aContainerParameters.mXScale * presShell->GetResolution(),
       aContainerParameters.mYScale * presShell->GetResolution(), nsIntPoint(),
       aContainerParameters);
 
   nsRect viewport = mFrame->GetRect() - mFrame->GetPosition() +
                     mFrame->GetOffsetToCrossDoc(ReferenceFrame());
 
+  nsIScrollableFrame* scrollableFrame = rootScrollFrame->GetScrollTargetFrame();
+  if (isRootContentDocument) {
+    viewport.SizeTo(scrollableFrame->GetScrollPortRect().Size());
+  }
+
   UniquePtr<ScrollMetadata> metadata =
       MakeUnique<ScrollMetadata>(nsLayoutUtils::ComputeScrollMetadata(
           mFrame, rootScrollFrame, rootScrollFrame->GetContent(),
           ReferenceFrame(), aLayerManager, mScrollParentId, viewport, Nothing(),
           isRootContentDocument, Some(params)));
-  nsIScrollableFrame* scrollableFrame = rootScrollFrame->GetScrollTargetFrame();
   if (scrollableFrame) {
     scrollableFrame->NotifyApzTransaction();
   }
 
   return metadata;
 }
 
 static bool UseDisplayPortForViewport(nsDisplayListBuilder* aBuilder,
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/horizontal-overflow-hidden-region-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+}
+div {
+  height: 50%;
+  position: absolute;
+}
+</style>
+<div style="background: green; width: 100%;"></div>
+<div style="background: blue; width: 50%;"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/horizontal-overflow-hidden-region.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<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 style="background: red; width: 300%;"></div>
+<div style="background: green; width: 200%;"></div>
+<div style="background: blue; width: 100%;"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/overflow-hidden-region-with-negative-left-positioned-element.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, minimum-scale=0.25">
+<style>
+html {
+  overflow: hidden;
+}
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+}
+div {
+  position: absolute;
+}
+</style>
+<!--
+  Even if minimum-scale=0.25 is specified, the widest element in this content is
+  below div element whose *real* width is 200% because of `margin-left: -500%`,
+  so this content should be scaled to 0.5x.
+  -->
+<div style="background: green; width: 700%; height: 500%; margin-left: -500%;"></div>
+<div style="background: blue; width: 100%; height: 100%;"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/overflow-hidden-region.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<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 style="background: red; width: 300%; height: 300%;"></div>
+<div style="background: green; width: 200%; height: 200%;"></div>
+<div style="background: blue; width: 100%; height: 100%;"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/overflow-region-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width,initial-scale=1">
+<style>
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+}
+div {
+  position: absolute;
+}
+</style>
+<div style="background: green; width: 100%; height: 100%;"></div>
+<div style="background: blue; width: 50%; height: 50%;"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/overflow-region.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, minimum-scale=0.5">
+<style>
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+  scrollbar-width: none;
+}
+div {
+  position: absolute;
+}
+</style>
+<div style="background: red; width: 300%; height: 300%;"></div>
+<div style="background: green; width: 200%; height: 200%;"></div>
+<div style="background: blue; width: 100%; height: 100%"></div>
--- a/layout/reftests/meta-viewport/reftest.list
+++ b/layout/reftests/meta-viewport/reftest.list
@@ -4,8 +4,17 @@ default-preferences pref(dom.meta-viewpo
 == box-shadow.html initial-scale-0_5-ref.html
 == initial-scale-0.html initial-scale-0_5-ref.html
 == initial-scale-100.html initial-scale-0_5-ref.html
 == no-viewport.html initial-scale-0_5-ref.html
 == viewport-width.html initial-scale-0_5-ref.html
 == initial-scale-1.html no-zoom-ref.html
 == minimum-scale.html no-zoom-ref.html
 == clamped-by-default-minimum-scale.html initial-scale-0_25-ref.html
+
+# 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
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/scroll-to-unreachable-area-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width,initial-scale=1">
+<style>
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+}
+div {
+  position: absolute;
+}
+</style>
+<div style="background: red; width: 100%; height: 100%;"></div>
+<div style="background: green; width: 50%; height: 50%;"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/scroll-to-unreachable-area.html
@@ -0,0 +1,27 @@
+<!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 style="background: red; width: 300%; height: 300%;"></div>
+<div id="green" style="background: green; width: 200%; height: 200%;"></div>
+<div style="background: blue; width: 100%; height: 100%;"></div>
+<script>
+document.addEventListener('MozReftestInvalidate', () => {
+  const rect = green.getBoundingClientRect();
+  window.scrollTo(rect.right, rect.bottom);
+  document.documentElement.classList.remove('reftest-wait');
+});
+</script>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/vertical-overflow-hidden-region.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, minimum-scale=0.5">
+<style>
+html {
+  overflow-y: hidden;
+}
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+}
+div {
+  width: 100%;
+  position: absolute;
+}
+</style>
+<div style="background: red; height: 300%;"></div>
+<div style="background: green; height: 200%;"></div>
+<div style="background: white; height: 100%;"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/wrapped-text-at-icb-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, initial-scale=0.5">
+<style>
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+  font-size: 20px;
+  scrollbar-width: none;
+}
+p {
+  line-height: 1rem;
+  width: 50%;
+}
+</style>
+<p>
+  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/meta-viewport/wrapped-text-at-icb.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, minimum-scale=0.5">
+<style>
+html {
+  overflow: hidden;
+  font-size: 20px;
+}
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+}
+div {
+  position: absolute;
+}
+p {
+  line-height: 1rem;
+}
+</style>
+</head><body><p>
+  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+</p>
+<div style="width: 200%; height: 200%;"></div>