Changing view scale should zoom to initial scale if the page is already at initial...
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Oct 2018 17:36:31 +0000 (17:36 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Oct 2018 17:36:31 +0000 (17:36 +0000)
https://bugs.webkit.org/show_bug.cgi?id=190570
<rdar://problem/45261877>

Reviewed by Tim Horton.

Source/WebCore:

Add a getter for ViewportConfiguration's layout size scale factor.
See Source/WebKit/ChangeLog for more details.

* page/ViewportConfiguration.h:
(WebCore::ViewportConfiguration::layoutSizeScaleFactor const):

Source/WebKit:

r237087 added support for changing the view scale on iOS, by making it possible to let the minimum layout size
be a factor of the view size; this allows internal clients to change page zoom levels on iOS. Currently,
changing the page zoom level automatically zooms to the new initial scale only if the user has not manually
scaled the page before, even if the page is already at initial scale (e.g. after the user double taps to zoom on
a small element, and double taps again to zoom back out to initial scale).

This patch makes some minor adjustments to automatically zoom to the new initial scale after changing the view
scale, as long as the page was at initial scale when changing zoom levels.

Test: fast/viewport/ios/initial-scale-after-changing-view-scale.html

* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::areEssentiallyEqualAsFloat):

Move this function further up in the file, so that we can use it in `setViewportConfigurationViewLayoutSize`.

(WebKit::WebPage::setViewportConfigurationViewLayoutSize):

If the page is near initial scale and the zoom level changes, zoom to the new initial scale.

(WebKit::WebPage::viewportConfigurationChanged):

Make this take a new enum argument that determines whether we want to zoom to initial scale as a result of the
viewport configuration change (`No` by default).

LayoutTests:

* fast/viewport/ios/initial-scale-after-changing-view-scale-expected.txt: Added.
* fast/viewport/ios/initial-scale-after-changing-view-scale.html: Added.

Add a new layout test to verify that:
1.  Changing view scale before the page scale factor is changed by the user zooms to the new initial scale.
2.  Changing view scale after the user changes the page scale to something different than initial scale does not
    cause the page to zoom to the new initial scale.
3.  Changing view scale after the user changes the page scale factor back to initial scale causes the page to
    zoom to the new initial scale.

* resources/basic-gestures.js:

Make a small tweak in `doubleTapToZoomAtPoint` to ensure that both single taps as well as zooming are complete
before invoking UIScriptController completion.

(return.new.Promise):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237127 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/viewport/ios/initial-scale-after-changing-view-scale-expected.txt [new file with mode: 0644]
LayoutTests/fast/viewport/ios/initial-scale-after-changing-view-scale.html [new file with mode: 0644]
LayoutTests/resources/basic-gestures.js
Source/WebCore/ChangeLog
Source/WebCore/page/ViewportConfiguration.h
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

index 0cdbedb..c7da7d2 100644 (file)
@@ -1,3 +1,28 @@
+2018-10-15  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Changing view scale should zoom to initial scale if the page is already at initial scale
+        https://bugs.webkit.org/show_bug.cgi?id=190570
+        <rdar://problem/45261877>
+
+        Reviewed by Tim Horton.
+
+        * fast/viewport/ios/initial-scale-after-changing-view-scale-expected.txt: Added.
+        * fast/viewport/ios/initial-scale-after-changing-view-scale.html: Added.
+
+        Add a new layout test to verify that:
+        1.  Changing view scale before the page scale factor is changed by the user zooms to the new initial scale.
+        2.  Changing view scale after the user changes the page scale to something different than initial scale does not
+            cause the page to zoom to the new initial scale.
+        3.  Changing view scale after the user changes the page scale factor back to initial scale causes the page to
+            zoom to the new initial scale.
+
+        * resources/basic-gestures.js:
+
+        Make a small tweak in `doubleTapToZoomAtPoint` to ensure that both single taps as well as zooming are complete
+        before invoking UIScriptController completion.
+
+        (return.new.Promise):
+
 2018-10-15  Yoshiaki Jitsukawa  <yoshiaki.jitsukawa@sony.com>
 
         [Cairo] Incorrect rendering for 135-deg skews
diff --git a/LayoutTests/fast/viewport/ios/initial-scale-after-changing-view-scale-expected.txt b/LayoutTests/fast/viewport/ios/initial-scale-after-changing-view-scale-expected.txt
new file mode 100644 (file)
index 0000000..a618db8
--- /dev/null
@@ -0,0 +1,16 @@
+Initial page scale factor                   : 1.00
+ - Page scale after setViewScale(1.25)      : 1.25
+ - Page scale after setViewScale(0.75)      : 0.75
+ - Page scale after setViewScale(1)         : 1.00
+
+Page scale after double tapping to zoom in  : 1.60
+ - Page scale after setViewScale(1.25)      : 1.60
+ - Page scale after setViewScale(0.75)      : 1.60
+ - Page scale after setViewScale(1)         : 1.60
+
+Page scale after double tapping to zoom out : 1.00
+ - Page scale after setViewScale(1.25)      : 1.25
+ - Page scale after setViewScale(0.75)      : 0.75
+ - Page scale after setViewScale(1)         : 1.00
+
+This test verifies that changing the view scale zooms the page to initial scale, but only if the page was already at initial scale. To manually test, (1) change the zoom scale without changing the page scale in any way, and check that the page zooms to initial scale; (2) now double tap on the box to zoom in, and check that changing zoom levels does not change the page scale; (3) finally, double tap on the box again to zoom back out to initial scale, and check that changing zoom levels automatically zooms the page to initial scale once again.
diff --git a/LayoutTests/fast/viewport/ios/initial-scale-after-changing-view-scale.html b/LayoutTests/fast/viewport/ios/initial-scale-after-changing-view-scale.html
new file mode 100644 (file)
index 0000000..ad15ad3
--- /dev/null
@@ -0,0 +1,95 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <style>
+    #square {
+        position: absolute;
+        width: 80px;
+        height: 80px;
+        border: 2px solid black;
+        top: 0;
+        left: 0;
+    }
+
+    #output {
+        width: 100%;
+        height: 100%;
+        overflow: scroll;
+    }
+
+    #description {
+        margin-top: 100px;
+    }
+
+    body {
+        margin: 0;
+        width: 100%;
+        height: 100%;
+    }
+    </style>
+    <script src="../../../resources/ui-helper.js"></script>
+    <script src="../../../resources/basic-gestures.js"></script>
+    <script>
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+    }
+
+    function pageScaleAfterSettingViewScale(scale)
+    {
+        return new Promise(async resolve => {
+            await UIHelper.setViewScale(scale);
+            await Promise.all([UIHelper.ensureVisibleContentRectUpdate(), UIHelper.ensurePresentationUpdate()]);
+            resolve(internals.pageScaleFactor().toFixed(2));
+        });
+    }
+
+    function pageScaleAfterDoubleTappingOnSquare()
+    {
+        return new Promise(async resolve => {
+            await doubleTapToZoomAtPoint(40, 40);
+            resolve(internals.pageScaleFactor().toFixed(2));
+        });
+    }
+
+    async function runTest()
+    {
+        const appendOutput = message => {
+            output.appendChild(document.createTextNode(message));
+            output.appendChild(document.createElement("br"));
+        };
+
+        appendOutput(`Initial page scale factor                   : ${internals.pageScaleFactor().toFixed(2)}`);
+        appendOutput(` - Page scale after setViewScale(1.25)      : ${await pageScaleAfterSettingViewScale(1.25)}`);
+        appendOutput(` - Page scale after setViewScale(0.75)      : ${await pageScaleAfterSettingViewScale(0.75)}`);
+        appendOutput(` - Page scale after setViewScale(1)         : ${await pageScaleAfterSettingViewScale(1)}`);
+        appendOutput("");
+        appendOutput(`Page scale after double tapping to zoom in  : ${await pageScaleAfterDoubleTappingOnSquare()}`);
+        appendOutput(` - Page scale after setViewScale(1.25)      : ${await pageScaleAfterSettingViewScale(1.25)}`);
+        appendOutput(` - Page scale after setViewScale(0.75)      : ${await pageScaleAfterSettingViewScale(0.75)}`);
+        appendOutput(` - Page scale after setViewScale(1)         : ${await pageScaleAfterSettingViewScale(1)}`);
+        appendOutput("");
+        appendOutput(`Page scale after double tapping to zoom out : ${await pageScaleAfterDoubleTappingOnSquare()}`);
+        appendOutput(` - Page scale after setViewScale(1.25)      : ${await pageScaleAfterSettingViewScale(1.25)}`);
+        appendOutput(` - Page scale after setViewScale(0.75)      : ${await pageScaleAfterSettingViewScale(0.75)}`);
+        appendOutput(` - Page scale after setViewScale(1)         : ${await pageScaleAfterSettingViewScale(1)}`);
+        appendOutput("");
+
+        testRunner.notifyDone();
+    }
+    </script>
+</head>
+
+<body onload="runTest()">
+    <div id="square"></div>
+    <pre id="output"></pre>
+    <p id="description">This test verifies that changing the view scale zooms the page to initial scale, but only if the
+        page was already at initial scale. To manually test, <strong>(1)</strong> change the zoom scale without changing
+        the page scale in any way, and check that the page zooms to initial scale; <strong>(2)</strong> now double tap
+        on the box to zoom in, and check that changing zoom levels does not change the page scale; <strong>(3)</strong>
+        finally, double tap on the box again to zoom back out to initial scale, and check that changing zoom levels
+        automatically zooms the page to initial scale once again.
+    </p>
+</body>
+</html>
index 5c6b7f0..038fcea 100644 (file)
@@ -15,9 +15,14 @@ function doubleTapToZoomAtPoint(x, y)
     return new Promise(resolve => {
         testRunner.runUIScript(`
             (function() {
-                uiController.didEndZoomingCallback = () => uiController.uiScriptComplete();
-                uiController.singleTapAtPoint(${x}, ${y}, () => { });
-                uiController.singleTapAtPoint(${x}, ${y}, () => { });
+                let completionCount = 0;
+                const checkDone = () => {
+                    if (++completionCount == 3)
+                        uiController.uiScriptComplete();
+                };
+                uiController.didEndZoomingCallback = checkDone;
+                uiController.singleTapAtPoint(${x}, ${y}, checkDone);
+                uiController.singleTapAtPoint(${x}, ${y}, checkDone);
             })();`, resolve);
     });
 }
index 7ecfe2c..bd28acf 100644 (file)
@@ -1,3 +1,17 @@
+2018-10-15  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Changing view scale should zoom to initial scale if the page is already at initial scale
+        https://bugs.webkit.org/show_bug.cgi?id=190570
+        <rdar://problem/45261877>
+
+        Reviewed by Tim Horton.
+
+        Add a getter for ViewportConfiguration's layout size scale factor.
+        See Source/WebKit/ChangeLog for more details.
+
+        * page/ViewportConfiguration.h:
+        (WebCore::ViewportConfiguration::layoutSizeScaleFactor const):
+
 2018-10-15  Charlie Turner  <cturner@igalia.com>
 
         Fix build error with !LOG_DISABLED in Release mode
index 91a9ba1..6a710f5 100644 (file)
@@ -91,6 +91,8 @@ public:
     WEBCORE_EXPORT bool setCanIgnoreScalingConstraints(bool);
     void setForceAlwaysUserScalable(bool forceAlwaysUserScalable) { m_forceAlwaysUserScalable = forceAlwaysUserScalable; }
 
+    double layoutSizeScaleFactor() const { return m_layoutSizeScaleFactor; }
+
     WEBCORE_EXPORT IntSize layoutSize() const;
     WEBCORE_EXPORT double initialScale() const;
     WEBCORE_EXPORT double initialScaleIgnoringContentSize() const;
index 40db008..81147e9 100644 (file)
@@ -1,3 +1,37 @@
+2018-10-15  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Changing view scale should zoom to initial scale if the page is already at initial scale
+        https://bugs.webkit.org/show_bug.cgi?id=190570
+        <rdar://problem/45261877>
+
+        Reviewed by Tim Horton.
+
+        r237087 added support for changing the view scale on iOS, by making it possible to let the minimum layout size
+        be a factor of the view size; this allows internal clients to change page zoom levels on iOS. Currently,
+        changing the page zoom level automatically zooms to the new initial scale only if the user has not manually
+        scaled the page before, even if the page is already at initial scale (e.g. after the user double taps to zoom on
+        a small element, and double taps again to zoom back out to initial scale).
+
+        This patch makes some minor adjustments to automatically zoom to the new initial scale after changing the view
+        scale, as long as the page was at initial scale when changing zoom levels.
+
+        Test: fast/viewport/ios/initial-scale-after-changing-view-scale.html
+
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::areEssentiallyEqualAsFloat):
+
+        Move this function further up in the file, so that we can use it in `setViewportConfigurationViewLayoutSize`.
+
+        (WebKit::WebPage::setViewportConfigurationViewLayoutSize):
+
+        If the page is near initial scale and the zoom level changes, zoom to the new initial scale.
+
+        (WebKit::WebPage::viewportConfigurationChanged):
+
+        Make this take a new enum argument that determines whether we want to zoom to initial scale as a result of the
+        viewport configuration change (`No` by default).
+
 2018-10-15  Chris Dumez  <cdumez@apple.com>
 
         Restrict browsing context lookup by name to frames that are related to one another
index d8cf5d3..fdd3941 100644 (file)
@@ -1123,7 +1123,8 @@ private:
 
 #if PLATFORM(IOS)
     void resetViewportDefaultConfiguration(WebFrame* mainFrame, bool hasMobileDocType = false);
-    void viewportConfigurationChanged();
+    enum class ZoomToInitialScale { No, Yes };
+    void viewportConfigurationChanged(ZoomToInitialScale = ZoomToInitialScale::No);
     void updateViewportSizeForCSSViewportUnits();
 
     static void convertSelectionRectsToRootView(WebCore::FrameView*, Vector<WebCore::SelectionRect>&);
index ab81fdd..c6a91e2 100644 (file)
@@ -2518,11 +2518,23 @@ void WebPage::autofillLoginCredentials(const String& username, const String& pas
     }
 }
 
+// WebCore stores the page scale factor as float instead of double. When we get a scale from WebCore,
+// we need to ignore differences that are within a small rounding error on floats.
+static inline bool areEssentiallyEqualAsFloat(float a, float b)
+{
+    return WTF::areEssentiallyEqual(a, b);
+}
+
 void WebPage::setViewportConfigurationViewLayoutSize(const FloatSize& size, double scaleFactor)
 {
     LOG_WITH_STREAM(VisibleRects, stream << "WebPage " << m_pageID << " setViewportConfigurationViewLayoutSize " << size << " scaleFactor " << scaleFactor);
+
+    ZoomToInitialScale shouldZoomToInitialScale = ZoomToInitialScale::No;
+    if (m_viewportConfiguration.layoutSizeScaleFactor() != scaleFactor && areEssentiallyEqualAsFloat(m_viewportConfiguration.initialScale(), pageScaleFactor()))
+        shouldZoomToInitialScale = ZoomToInitialScale::Yes;
+
     if (m_viewportConfiguration.setViewLayoutSize(size, scaleFactor))
-        viewportConfigurationChanged();
+        viewportConfigurationChanged(shouldZoomToInitialScale);
 }
 
 void WebPage::setMaximumUnobscuredSize(const FloatSize& maximumUnobscuredSize)
@@ -2545,13 +2557,6 @@ void WebPage::setOverrideViewportArguments(const std::optional<WebCore::Viewport
         document->setOverrideViewportArguments(arguments);
 }
 
-// WebCore stores the page scale factor as float instead of double. When we get a scale from WebCore,
-// we need to ignore differences that are within a small rounding error on floats.
-static inline bool areEssentiallyEqualAsFloat(float a, float b)
-{
-    return WTF::areEssentiallyEqual(a, b);
-}
-
 void WebPage::resetTextAutosizing()
 {
     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
@@ -2776,14 +2781,14 @@ void WebPage::resetViewportDefaultConfiguration(WebFrame* frame, bool hasMobileD
         m_viewportConfiguration.setDefaultConfiguration(parametersForStandardFrame());
 }
 
-void WebPage::viewportConfigurationChanged()
+void WebPage::viewportConfigurationChanged(ZoomToInitialScale zoomToInitialScale)
 {
     if (setFixedLayoutSize(m_viewportConfiguration.layoutSize()))
         resetTextAutosizing();
 
     double initialScale = m_viewportConfiguration.initialScale();
     double scale;
-    if (m_userHasChangedPageScaleFactor)
+    if (m_userHasChangedPageScaleFactor && zoomToInitialScale == ZoomToInitialScale::No)
         scale = std::max(std::min(pageScaleFactor(), m_viewportConfiguration.maximumScale()), m_viewportConfiguration.minimumScale());
     else
         scale = initialScale;