Cherry-pick: [Android WebView] In non-WideViewport mode, initial-scale < 1 must be ignored

Cherry-pick of chromium http://crrev.com/25353006

Bug: 10566410

Original description:

[Android WebView] In non-WideViewport mode, initial-scale < 1 must be ignored

From my experiments with the existing implementation, it turns out that in the
case when WideViewport is turned off, values of initial-scale < 1 are ignored in
most cases. The layout width is set to device-width (scaled according to
target-densitydpi). This also includes 'auto' initial-scale.

An exception from the rule is the case when width is set to device-width,
in which case the initial-scale is respected.

BUG=303189

Change-Id: I3d7139ce0fe24e0c8f3f45e2209a9fdba0de5555
diff --git a/Source/core/page/PageScaleConstraintsSet.cpp b/Source/core/page/PageScaleConstraintsSet.cpp
index 01ac14e..182c39e 100644
--- a/Source/core/page/PageScaleConstraintsSet.cpp
+++ b/Source/core/page/PageScaleConstraintsSet.cpp
@@ -151,10 +151,17 @@
     }
 
     if (wideViewportQuirkEnabled) {
-        if (useWideViewport && arguments.width == -1 && arguments.zoom != 1.0f)
+        if (useWideViewport && arguments.width == -1 && arguments.zoom != 1.0f) {
             adjustedLayoutSizeWidth = layoutFallbackWidth;
-        else if (!useWideViewport)
-            adjustedLayoutSizeWidth = getLayoutWidthForNonWideViewport(viewSize, initialScale) / targetDensityDPIFactor;
+        } else if (!useWideViewport) {
+            const float nonWideScale = arguments.zoom < 1 && arguments.width != ViewportArguments::ValueDeviceWidth ? -1 : initialScale;
+            adjustedLayoutSizeWidth = getLayoutWidthForNonWideViewport(viewSize, nonWideScale) / targetDensityDPIFactor;
+            if (arguments.zoom < 1) {
+                m_pageDefinedConstraints.initialScale = viewSize.width() / adjustedLayoutSizeWidth;
+                m_pageDefinedConstraints.minimumScale = std::min<float>(m_pageDefinedConstraints.minimumScale, m_pageDefinedConstraints.initialScale);
+                m_pageDefinedConstraints.maximumScale = std::max<float>(m_pageDefinedConstraints.maximumScale, m_pageDefinedConstraints.initialScale);
+            }
+        }
     }
 
     if (adjustedLayoutSizeWidth != m_pageDefinedConstraints.layoutSize.width()) {
diff --git a/Source/web/tests/WebFrameTest.cpp b/Source/web/tests/WebFrameTest.cpp
index bd58af4..0f7bbda 100644
--- a/Source/web/tests/WebFrameTest.cpp
+++ b/Source/web/tests/WebFrameTest.cpp
@@ -1222,6 +1222,51 @@
     }
 }
 
+TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOne) {
+    registerMockedHttpURLLoad("viewport-initial-scale-less-than-1.html");
+
+    FixedLayoutTestWebViewClient client;
+    client.m_screenInfo.deviceScaleFactor = 1.33f;
+    int viewportWidth = 640;
+    int viewportHeight = 480;
+
+    m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "viewport-initial-scale-less-than-1.html", true, 0, &client);
+    m_webView->enableFixedLayoutMode(true);
+    m_webView->settings()->setViewportEnabled(true);
+    m_webView->settings()->setSupportDeprecatedTargetDensityDPI(true);
+    m_webView->settings()->setWideViewportQuirkEnabled(true);
+    m_webView->settings()->setUseWideViewport(true);
+    m_webView->resize(WebSize(viewportWidth, viewportHeight));
+    m_webView->layout();
+
+    EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, m_webView->fixedLayoutSize().width, 1.0f);
+    EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, m_webView->fixedLayoutSize().height, 1.0f);
+    EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, m_webView->pageScaleFactor(), 0.01f);
+}
+
+TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOneWithDeviceWidth) {
+    registerMockedHttpURLLoad("viewport-initial-scale-less-than-1-device-width.html");
+
+    FixedLayoutTestWebViewClient client;
+    client.m_screenInfo.deviceScaleFactor = 1.33f;
+    int viewportWidth = 640;
+    int viewportHeight = 480;
+
+    m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "viewport-initial-scale-less-than-1-device-width.html", true, 0, &client);
+    m_webView->enableFixedLayoutMode(true);
+    m_webView->settings()->setViewportEnabled(true);
+    m_webView->settings()->setSupportDeprecatedTargetDensityDPI(true);
+    m_webView->settings()->setWideViewportQuirkEnabled(true);
+    m_webView->settings()->setUseWideViewport(true);
+    m_webView->resize(WebSize(viewportWidth, viewportHeight));
+    m_webView->layout();
+
+    const float pageZoom = 0.25f;
+    EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor / pageZoom, m_webView->fixedLayoutSize().width, 1.0f);
+    EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor / pageZoom, m_webView->fixedLayoutSize().height, 1.0f);
+    EXPECT_NEAR(pageZoom * 1.0f / client.m_screenInfo.deviceScaleFactor, m_webView->pageScaleFactor(), 0.01f);
+}
+
 class WebFrameResizeTest : public WebFrameTest {
 protected:
 
diff --git a/Source/web/tests/data/viewport-initial-scale-less-than-1-device-width.html b/Source/web/tests/data/viewport-initial-scale-less-than-1-device-width.html
new file mode 100644
index 0000000..990d727
--- /dev/null
+++ b/Source/web/tests/data/viewport-initial-scale-less-than-1-device-width.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <meta name='viewport' content='width=device-width,target-densitydpi=device-dpi,initial-scale=0.25' />
+  </head>
+  <body>
+    A page with a viewport set to device-dpi and device width, scale < 1.
+  </body>
+</html>
diff --git a/Source/web/tests/data/viewport-initial-scale-less-than-1.html b/Source/web/tests/data/viewport-initial-scale-less-than-1.html
new file mode 100644
index 0000000..f4d4d50
--- /dev/null
+++ b/Source/web/tests/data/viewport-initial-scale-less-than-1.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <meta name='viewport' content='width=320,target-densitydpi=device-dpi,initial-scale=0.25' />
+  </head>
+  <body>
+    A page with a viewport set to device-dpi and fixed width, scale < 1.
+  </body>
+</html>