Bug 1423709 - Adapt initial zoom value to fit the wider contents to screen device width. r=botond
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Tue, 20 Nov 2018 03:56:44 +0000
changeset 503610 9f9d8ca6b972f61f07a1c0ed1a44656b8ded1e58
parent 503609 e41abff7fff927ba9c791a4f9a546b398ce194f0
child 503611 efb925fd7a3c4b47eef949767a6a52002c94e55d
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1423709
milestone65.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 1423709 - Adapt initial zoom value to fit the wider contents to screen device width. r=botond What we need to do here is to scale down the document as if the document was pinched in to fit the contents to screen width when all the following conditions are met. - it's the first paint for the document - no initial-scale is specified in meta viewport tags - no mRestoreResolution hasn't set - the content width is wider than the initial viewport width Depends on D10196 Differential Revision: https://phabricator.services.mozilla.com/D10197
layout/base/MobileViewportManager.cpp
layout/base/MobileViewportManager.h
--- a/layout/base/MobileViewportManager.cpp
+++ b/layout/base/MobileViewportManager.cpp
@@ -228,38 +228,42 @@ MobileViewportManager::UpdateResolution(
                                         const CSSSize& aViewport,
                                         const Maybe<float>& aDisplayWidthChangeRatio)
 {
   CSSToLayoutDeviceScale cssToDev =
       mPresShell->GetPresContext()->CSSToDevPixelScale();
   LayoutDeviceToLayerScale res(mPresShell->GetResolution());
 
   if (mIsFirstPaint) {
+    ScreenIntSize compositionSize = GetCompositionSize(aDisplaySize);
+
     CSSToScreenScale defaultZoom;
     if (mRestoreResolution) {
       LayoutDeviceToLayerScale restoreResolution(mRestoreResolution.value());
       if (mRestoreDisplaySize) {
         CSSSize prevViewport = mDocument->GetViewportInfo(mRestoreDisplaySize.value()).GetSize();
         float restoreDisplayWidthChangeRatio = (mRestoreDisplaySize.value().width > 0)
-          ? (float)aDisplaySize.width / (float)mRestoreDisplaySize.value().width : 1.0f;
+          ? (float)compositionSize.width / (float)mRestoreDisplaySize.value().width : 1.0f;
 
         restoreResolution =
           ScaleResolutionWithDisplayWidth(restoreResolution,
                                           restoreDisplayWidthChangeRatio,
                                           aViewport,
                                           prevViewport);
       }
       defaultZoom = CSSToScreenScale(restoreResolution.scale * cssToDev.scale);
       MVM_LOG("%p: restored zoom is %f\n", this, defaultZoom.scale);
       defaultZoom = ClampZoom(defaultZoom, aViewportInfo);
     } else {
       defaultZoom = aViewportInfo.GetDefaultZoom();
       MVM_LOG("%p: default zoom from viewport is %f\n", this, defaultZoom.scale);
       if (!aViewportInfo.IsDefaultZoomValid()) {
-        defaultZoom = ComputeIntrinsicScale(aViewportInfo, aDisplaySize, aViewport);
+        defaultZoom = ComputeIntrinsicScale(aViewportInfo,
+                                            compositionSize,
+                                            aViewport);
       }
     }
     MOZ_ASSERT(aViewportInfo.GetMinZoom() <= defaultZoom &&
       defaultZoom <= aViewportInfo.GetMaxZoom());
 
     CSSToParentLayerScale zoom = ViewTargetAs<ParentLayerPixel>(defaultZoom,
       PixelCastJustification::ScreenIsParentLayerForRoot);
 
@@ -300,32 +304,42 @@ MobileViewportManager::UpdateResolution(
       aViewport, mMobileViewportSize);
     mPresShell->SetResolutionAndScaleTo(res.scale);
   }
 
   return ViewTargetAs<ScreenPixel>(cssToDev * res / ParentLayerToLayerScale(1),
     PixelCastJustification::ScreenIsParentLayerForRoot);
 }
 
-void
-MobileViewportManager::UpdateVisualViewportSize(const ScreenIntSize& aDisplaySize,
-                                                const CSSToScreenScale& aZoom)
+
+ScreenIntSize
+MobileViewportManager::GetCompositionSize(const ScreenIntSize& aDisplaySize) const
 {
-  ScreenSize compositionSize(aDisplaySize);
+  ScreenIntSize compositionSize(aDisplaySize);
   ScreenMargin scrollbars =
     LayoutDeviceMargin::FromAppUnits(
       nsLayoutUtils::ScrollbarAreaToExcludeFromCompositionBoundsFor(
         mPresShell->GetRootScrollFrame()),
       mPresShell->GetPresContext()->AppUnitsPerDevPixel())
     // Scrollbars are not subject to resolution scaling, so LD pixels =
     // Screen pixels for them.
     * LayoutDeviceToScreenScale(1.0f);
 
   compositionSize.width -= scrollbars.LeftRight();
   compositionSize.height -= scrollbars.TopBottom();
+
+  return compositionSize;
+}
+
+void
+MobileViewportManager::UpdateVisualViewportSize(const ScreenIntSize& aDisplaySize,
+                                                const CSSToScreenScale& aZoom)
+{
+  ScreenSize compositionSize = ScreenSize(GetCompositionSize(aDisplaySize));
+
   CSSSize compSize = compositionSize / aZoom;
   MVM_LOG("%p: Setting VVPS %s\n", this, Stringify(compSize).c_str());
   nsLayoutUtils::SetVisualViewportSize(mPresShell, compSize);
 }
 
 void
 MobileViewportManager::UpdateDisplayPortMargins()
 {
@@ -439,18 +453,57 @@ MobileViewportManager::RefreshViewportSi
   }
   if (gfxPlatform::AsyncPanZoomEnabled()) {
     UpdateDisplayPortMargins();
   }
 
   CSSSize oldSize = mMobileViewportSize;
 
   // Update internal state.
-  mIsFirstPaint = false;
   mMobileViewportSize = viewport;
 
   // Kick off a reflow.
   mPresShell->ResizeReflowIgnoreOverride(
     nsPresContext::CSSPixelsToAppUnits(viewport.width),
     nsPresContext::CSSPixelsToAppUnits(viewport.height),
     nsPresContext::CSSPixelsToAppUnits(oldSize.width),
     nsPresContext::CSSPixelsToAppUnits(oldSize.height));
+
+  // We are going to fit the content to the display width if the initial-scale
+  // is not specied and if the content is still wider than the display width.
+  ShrinkToDisplaySizeIfNeeded(viewportInfo, displaySize);
+
+  mIsFirstPaint = false;
 }
+
+void
+MobileViewportManager::ShrinkToDisplaySizeIfNeeded(
+  nsViewportInfo& aViewportInfo,
+  const ScreenIntSize& aDisplaySize)
+{
+  if (!gfxPrefs::APZAllowZooming()) {
+    // If the APZ is disabled, we don't scale down wider contents to fit them
+    // into device screen because users won't be able to zoom out the tiny
+    // contents.
+    return;
+  }
+
+  // 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 (aViewportInfo.IsDefaultZoomValid() ||
+      !mIsFirstPaint || mRestoreResolution) {
+    return;
+  }
+
+  nsIScrollableFrame* rootScrollableFrame =
+    mPresShell->GetRootScrollFrameAsScrollable();
+  if (rootScrollableFrame) {
+    nsRect scrollableRect =
+      nsLayoutUtils::CalculateScrollableRectForFrame(rootScrollableFrame,
+                                                     nullptr);
+    CSSSize contentSize = CSSSize::FromAppUnits(scrollableRect.Size());
+    CSSToScreenScale zoom =
+      UpdateResolution(aViewportInfo, aDisplaySize, contentSize, Nothing());
+
+    MVM_LOG("%p: Adapted zoom is %f\n", this, zoom.scale);
+    UpdateVisualViewportSize(aDisplaySize, zoom);
+  }
+}
--- a/layout/base/MobileViewportManager.h
+++ b/layout/base/MobileViewportManager.h
@@ -105,16 +105,29 @@ public:
   /* Updates the displayport margins for the presShell's root scrollable frame */
   void UpdateDisplayPortMargins();
 
   /* Helper function for ComputeIntrinsicResolution(). */
   mozilla::CSSToScreenScale ComputeIntrinsicScale(const nsViewportInfo& aViewportInfo,
                                                   const mozilla::ScreenIntSize& aDisplaySize,
                                                   const mozilla::CSSSize& aViewportSize) 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);
+
   nsCOMPtr<nsIDocument> mDocument;
   nsIPresShell* MOZ_NON_OWNING_REF mPresShell; // raw ref since the presShell owns this
   nsCOMPtr<mozilla::dom::EventTarget> mEventTarget;
   bool mIsFirstPaint;
   bool mPainted;
   mozilla::LayoutDeviceIntSize mDisplaySize;
   mozilla::CSSSize mMobileViewportSize;
   mozilla::Maybe<float> mRestoreResolution;