diff --git a/layout/base/MobileViewportManager.h b/layout/base/MobileViewportManager.h index 4781aeb0050d..d2ac5973f757 100644 --- a/layout/base/MobileViewportManager.h +++ b/layout/base/MobileViewportManager.h @@ -71,6 +71,10 @@ class MobileViewportManager final : public nsIDOMEventListener, * presShell is initialized. */ void SetInitialViewport(); + const mozilla::LayoutDeviceIntSize& DisplaySize() const { + return mDisplaySize; + }; + private: ~MobileViewportManager(); diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 59e477a776d0..6277cddc5276 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -15,6 +15,7 @@ #include "nsIContentViewer.h" #include "nsPresContext.h" #include "nsView.h" +#include "nsViewportInfo.h" #include "nsIScrollable.h" #include "nsContainerFrame.h" #include "nsGkAtoms.h" @@ -372,9 +373,14 @@ bool nsHTMLScrollFrame::TryLayout(ScrollReflowInput* aState, 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(); @@ -447,8 +453,7 @@ bool nsHTMLScrollFrame::TryLayout(ScrollReflowInput* aState, 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); @@ -717,6 +722,12 @@ void nsHTMLScrollFrame::ReflowContents(ScrollReflowInput* aState, } } + 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. @@ -1048,10 +1059,11 @@ void nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext, 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. @@ -1091,7 +1103,7 @@ void nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext, // place and reflow scrollbars nsRect insideBorderArea = nsRect(nsPoint(state.mComputedBorder.left, state.mComputedBorder.top), - state.mInsideBorderSize); + layoutSize); mHelper.LayoutScrollbars(state.mBoxState, insideBorderArea, oldScrollAreaBounds); } else { @@ -1998,6 +2010,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, bool aIsRoot) mZoomableByAPZ(false), mHasOutOfFlowContentInsideFilter(false), mSuppressScrollbarRepaints(false), + mIsUsingMinimumScaleSize(false), mVelocityQueue(aOuter->PresContext()) { if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) { mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter)); @@ -5445,6 +5458,65 @@ void ScrollFrameHelper::FinishReflowForScrollbar(Element* aElement, 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 manager = + mOuter->PresShell()->GetMobileViewportManager(); + MOZ_ASSERT(manager); + + ScreenIntSize displaySize = ViewAs( + 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; diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 683f8d1cb06a..b1951a8e4292 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -518,6 +518,11 @@ class ScrollFrameHelper : public nsIReflowCallback { 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 mHScrollbarContent; nsCOMPtr mVScrollbarContent; @@ -543,7 +548,11 @@ class ScrollFrameHelper : public nsIReflowCallback { nsAtom* mLastSmoothScrollOrigin; Maybe 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 @@ -670,6 +679,9 @@ class ScrollFrameHelper : public nsIReflowCallback { // 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: diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 0a333112d3c5..a3209c0ac732 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -6454,12 +6454,16 @@ UniquePtr nsDisplaySubDocument::ComputeScrollMetadata( nsRect viewport = mFrame->GetRect() - mFrame->GetPosition() + mFrame->GetOffsetToCrossDoc(ReferenceFrame()); + nsIScrollableFrame* scrollableFrame = rootScrollFrame->GetScrollTargetFrame(); + if (isRootContentDocument) { + viewport.SizeTo(scrollableFrame->GetScrollPortRect().Size()); + } + UniquePtr metadata = MakeUnique(nsLayoutUtils::ComputeScrollMetadata( mFrame, rootScrollFrame, rootScrollFrame->GetContent(), ReferenceFrame(), aLayerManager, mScrollParentId, viewport, Nothing(), isRootContentDocument, Some(params))); - nsIScrollableFrame* scrollableFrame = rootScrollFrame->GetScrollTargetFrame(); if (scrollableFrame) { scrollableFrame->NotifyApzTransaction(); } diff --git a/layout/reftests/meta-viewport/horizontal-overflow-hidden-region-ref.html b/layout/reftests/meta-viewport/horizontal-overflow-hidden-region-ref.html new file mode 100644 index 000000000000..758aafcb7e83 --- /dev/null +++ b/layout/reftests/meta-viewport/horizontal-overflow-hidden-region-ref.html @@ -0,0 +1,15 @@ + + + +
+
diff --git a/layout/reftests/meta-viewport/horizontal-overflow-hidden-region.html b/layout/reftests/meta-viewport/horizontal-overflow-hidden-region.html new file mode 100644 index 000000000000..79b323295499 --- /dev/null +++ b/layout/reftests/meta-viewport/horizontal-overflow-hidden-region.html @@ -0,0 +1,19 @@ + + + +
+
+
diff --git a/layout/reftests/meta-viewport/overflow-hidden-region-with-negative-left-positioned-element.html b/layout/reftests/meta-viewport/overflow-hidden-region-with-negative-left-positioned-element.html new file mode 100644 index 000000000000..aa7d9c690269 --- /dev/null +++ b/layout/reftests/meta-viewport/overflow-hidden-region-with-negative-left-positioned-element.html @@ -0,0 +1,22 @@ + + + + +
+
diff --git a/layout/reftests/meta-viewport/overflow-hidden-region.html b/layout/reftests/meta-viewport/overflow-hidden-region.html new file mode 100644 index 000000000000..d9c61cc21c6b --- /dev/null +++ b/layout/reftests/meta-viewport/overflow-hidden-region.html @@ -0,0 +1,18 @@ + + + +
+
+
diff --git a/layout/reftests/meta-viewport/overflow-region-ref.html b/layout/reftests/meta-viewport/overflow-region-ref.html new file mode 100644 index 000000000000..899bc559072f --- /dev/null +++ b/layout/reftests/meta-viewport/overflow-region-ref.html @@ -0,0 +1,14 @@ + + + +
+
diff --git a/layout/reftests/meta-viewport/overflow-region.html b/layout/reftests/meta-viewport/overflow-region.html new file mode 100644 index 000000000000..f18ac6182297 --- /dev/null +++ b/layout/reftests/meta-viewport/overflow-region.html @@ -0,0 +1,16 @@ + + + +
+
+
diff --git a/layout/reftests/meta-viewport/reftest.list b/layout/reftests/meta-viewport/reftest.list index 061b472e761b..c2a028d417d1 100644 --- a/layout/reftests/meta-viewport/reftest.list +++ b/layout/reftests/meta-viewport/reftest.list @@ -9,3 +9,12 @@ default-preferences pref(dom.meta-viewport.enabled,true) pref(apz.allow_zooming, == 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 diff --git a/layout/reftests/meta-viewport/scroll-to-unreachable-area-ref.html b/layout/reftests/meta-viewport/scroll-to-unreachable-area-ref.html new file mode 100644 index 000000000000..8c840a06d823 --- /dev/null +++ b/layout/reftests/meta-viewport/scroll-to-unreachable-area-ref.html @@ -0,0 +1,14 @@ + + + +
+
diff --git a/layout/reftests/meta-viewport/scroll-to-unreachable-area.html b/layout/reftests/meta-viewport/scroll-to-unreachable-area.html new file mode 100644 index 000000000000..e0f6016208ff --- /dev/null +++ b/layout/reftests/meta-viewport/scroll-to-unreachable-area.html @@ -0,0 +1,27 @@ + + + + +
+
+
+ + diff --git a/layout/reftests/meta-viewport/vertical-overflow-hidden-region.html b/layout/reftests/meta-viewport/vertical-overflow-hidden-region.html new file mode 100644 index 000000000000..90de29c2e5f3 --- /dev/null +++ b/layout/reftests/meta-viewport/vertical-overflow-hidden-region.html @@ -0,0 +1,19 @@ + + + +
+
+
diff --git a/layout/reftests/meta-viewport/wrapped-text-at-icb-ref.html b/layout/reftests/meta-viewport/wrapped-text-at-icb-ref.html new file mode 100644 index 000000000000..e4b8787f83c6 --- /dev/null +++ b/layout/reftests/meta-viewport/wrapped-text-at-icb-ref.html @@ -0,0 +1,18 @@ + + + +

+ 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. +

diff --git a/layout/reftests/meta-viewport/wrapped-text-at-icb.html b/layout/reftests/meta-viewport/wrapped-text-at-icb.html new file mode 100644 index 000000000000..44b5857fbedf --- /dev/null +++ b/layout/reftests/meta-viewport/wrapped-text-at-icb.html @@ -0,0 +1,23 @@ + + + +

+ 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. +

+