Allow WebKit clients to specify a minimum effective width for layout.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 28 Nov 2018 18:50:23 +0000 (18:50 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 28 Nov 2018 18:50:23 +0000 (18:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=191499
<rdar://problem/45362678>

Patch by Yongjun Zhang <yongjun_zhang@apple.com> on 2018-11-28
Reviewed by Wenson Hsieh.

Source/WebCore:

If we ignore the meta viewport (_shouldIgnoreMetaViewport is true), the default layout width will be device
width. For clients that wish to lay out the content with a different width value, we would need to add a way
to specify the effective width for layout.

Tests: fast/viewport/ios/ipad/viewport-overriden-by-minimum-effective-width-if-ignore-meta-viewport.html
       fast/viewport/ios/ipad/viewport-unchanged-by-minimum-effective-width-if-not-ignore-meta-viewport.html

* page/ViewportConfiguration.cpp:
(WebCore::ViewportConfiguration::setViewLayoutSize): Add a new argument effectiveWidth.
(WebCore::ViewportConfiguration::nativeWebpageParameters): Make sure minimumScale for nativeWebpageParameters
    is small enough so that it won't clamp out the initial scale. If content is wider than the viewport, this
    ensures we can still zoom out the page.
(WebCore::ViewportConfiguration::updateConfiguration): update _minimumEffectiveDeviceWidth and apply that to
    the layout size scale computation.
(WebCore::ViewportConfiguration::effectiveLayoutSizeScaleFactor): A helper method to return the effective
    layout scale factor which is also effected by _minimumEffectiveDeviceWidth.
(WebCore::ViewportConfiguration::updateMinimumLayoutSize): Update m_minimumLayoutSize based on effectiveLayoutSizeScaleFactor().
(WebCore::ViewportConfiguration::description const): Also dump m_minimumEffectiveDeviceWidth.
* page/ViewportConfiguration.h: Add a member variable m_minimumEffectiveDeviceWidth.

Source/WebKit:

If we ignore the meta viewport (_shouldIgnoreMetaViewport is true), the default layout width will be device
width. For clients that wish to lay out the content with a different width value, we would need to add a way
to specify the effective width for layout.

* UIProcess/API/Cocoa/WKWebView.mm: Add an iVar _minimumEffectiveDeviceWidth.
(-[WKWebView _dispatchSetViewLayoutSize:]): Call the new setViewportConfigurationViewLayoutSize method.
(-[WKWebView _setViewScale:]): Ditto.
(-[WKWebView _setMinimumEffectiveWidth:]): The setter for _minimumEffectiveDeviceWidth.
(-[WKWebView _minimumEffectiveWidth]): Getter for _minimumEffectiveDeviceWidth
* UIProcess/API/Cocoa/WKWebViewPrivate.h: Add a property _minimumEffectiveDeviceWidth to WKWebView.
* UIProcess/WebPageProxy.h: Change setViewportConfigurationViewLayoutSize to take another argument minimumEffectiveDeviceWidth.
* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::setViewportConfigurationViewLayoutSize): Also send effectiveWidth to WebContent process.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::WebPage): Set the initial effective width to 0 when creating a web page, this tells ViewportConfiguration
     to ignore the minimum effective width value.
* WebProcess/WebPage/WebPage.h: Change setViewportConfigurationViewLayoutSize to take another argument effectiveWidth.
* WebProcess/WebPage/WebPage.messages.in:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::setViewportConfigurationViewLayoutSize): Also pass effectiveWidth value to ViewportConfiguration.

Tools:

Allow UIScriptController to set WKWebView's minimum effective width with a new `setMinimumEffectiveWidth` method.

* DumpRenderTree/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::setMinimumEffectiveWidth):
* DumpRenderTree/mac/UIScriptControllerMac.mm:
(WTR::UIScriptController::setViewScale):
(WTR::UIScriptController::setMinimumEffectiveWidth):
* TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
* TestRunnerShared/UIScriptContext/UIScriptController.cpp:
(WTR::UIScriptController::setMinimumEffectiveWidth):
* TestRunnerShared/UIScriptContext/UIScriptController.h:
* WebKitTestRunner/UIScriptControllerCocoa.mm:
(WTR::UIScriptController::setMinimumEffectiveWidth):
* WebKitTestRunner/cocoa/TestControllerCocoa.mm:
(WTR::TestController::cocoaResetStateToConsistentValues):

LayoutTests:

Add two new tests. The first test verifies if we ignore meta viewport, setting a different effective width value
will change the layout width of the page. The second test verifies if we don't ignore meta viewport, we will always
respect that (980pt) and setting a different effective width value won't change the layout width.

* fast/viewport/ios/ipad/viewport-overriden-by-minimum-effective-width-if-ignore-meta-viewport-expected.txt: Added.
* fast/viewport/ios/ipad/viewport-overriden-by-minimum-effective-width-if-ignore-meta-viewport.html: Added.
* fast/viewport/ios/ipad/viewport-unchanged-by-minimum-effective-width-if-not-ignore-meta-viewport-expected.txt: Added.
* fast/viewport/ios/ipad/viewport-unchanged-by-minimum-effective-width-if-not-ignore-meta-viewport.html: Added.
* resources/ui-helper.js:
(window.UIHelper.setMinimumEffectiveWidth): Add a helper method to set the minimum effective width from a test.
(window.UIHelper):

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

26 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/viewport/ios/ipad/viewport-overriden-by-minimum-effective-width-if-ignore-meta-viewport-expected.txt [new file with mode: 0644]
LayoutTests/fast/viewport/ios/ipad/viewport-overriden-by-minimum-effective-width-if-ignore-meta-viewport.html [new file with mode: 0644]
LayoutTests/fast/viewport/ios/ipad/viewport-unchanged-by-minimum-effective-width-if-not-ignore-meta-viewport-expected.txt [new file with mode: 0644]
LayoutTests/fast/viewport/ios/ipad/viewport-unchanged-by-minimum-effective-width-if-not-ignore-meta-viewport.html [new file with mode: 0644]
LayoutTests/resources/ui-helper.js
Source/WebCore/ChangeLog
Source/WebCore/page/ViewportConfiguration.cpp
Source/WebCore/page/ViewportConfiguration.h
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/WebPage.messages.in
Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm
Tools/ChangeLog
Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm
Tools/DumpRenderTree/mac/UIScriptControllerMac.mm
Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl
Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp
Tools/TestRunnerShared/UIScriptContext/UIScriptController.h
Tools/WebKitTestRunner/UIScriptControllerCocoa.mm
Tools/WebKitTestRunner/cocoa/TestControllerCocoa.mm

index e1622f5..f8dd859 100644 (file)
@@ -1,3 +1,24 @@
+2018-11-28  Yongjun Zhang  <yongjun_zhang@apple.com>
+
+        Allow WebKit clients to specify a minimum effective width for layout.
+        https://bugs.webkit.org/show_bug.cgi?id=191499
+        <rdar://problem/45362678>
+
+        Reviewed by Wenson Hsieh.
+
+        Add two new tests. The first test verifies if we ignore meta viewport, setting a different effective width value
+        will change the layout width of the page. The second test verifies if we don't ignore meta viewport, we will always
+        respect that (980pt) and setting a different effective width value won't change the layout width. 
+
+
+        * fast/viewport/ios/ipad/viewport-overriden-by-minimum-effective-width-if-ignore-meta-viewport-expected.txt: Added.
+        * fast/viewport/ios/ipad/viewport-overriden-by-minimum-effective-width-if-ignore-meta-viewport.html: Added.
+        * fast/viewport/ios/ipad/viewport-unchanged-by-minimum-effective-width-if-not-ignore-meta-viewport-expected.txt: Added.
+        * fast/viewport/ios/ipad/viewport-unchanged-by-minimum-effective-width-if-not-ignore-meta-viewport.html: Added.
+        * resources/ui-helper.js:
+        (window.UIHelper.setMinimumEffectiveWidth): Add a helper method to set the minimum effective width from a test.
+        (window.UIHelper):
+
 2018-11-27  Jiewen Tan  <jiewen_tan@apple.com>
 
         Unreviewed, test gardening
diff --git a/LayoutTests/fast/viewport/ios/ipad/viewport-overriden-by-minimum-effective-width-if-ignore-meta-viewport-expected.txt b/LayoutTests/fast/viewport/ios/ipad/viewport-overriden-by-minimum-effective-width-if-ignore-meta-viewport-expected.txt
new file mode 100644 (file)
index 0000000..2bbe7a4
--- /dev/null
@@ -0,0 +1,41 @@
+setMinimumEffectiveWidth(640.00)
+window size: [768, 1004]
+square size: [77, 100]
+zoom scale: 1.00
+
+setMinimumEffectiveWidth(768.00)
+window size: [768, 1004]
+square size: [77, 100]
+zoom scale: 1.00
+
+setMinimumEffectiveWidth(834.00)
+window size: [834, 1090]
+square size: [83, 109]
+zoom scale: 0.92
+
+setMinimumEffectiveWidth(980.00)
+window size: [980, 1281]
+square size: [98, 128]
+zoom scale: 0.78
+
+setMinimumEffectiveWidth(1024.00)
+window size: [1024, 1339]
+square size: [102, 134]
+zoom scale: 0.75
+
+setMinimumEffectiveWidth(1112.00)
+window size: [1112, 1454]
+square size: [111, 145]
+zoom scale: 0.69
+
+setMinimumEffectiveWidth(1280.00)
+window size: [1280, 1673]
+square size: [128, 167]
+zoom scale: 0.60
+
+setMinimumEffectiveWidth(1336.00)
+window size: [1336, 1747]
+square size: [134, 175]
+zoom scale: 0.57
+
+
diff --git a/LayoutTests/fast/viewport/ios/ipad/viewport-overriden-by-minimum-effective-width-if-ignore-meta-viewport.html b/LayoutTests/fast/viewport/ios/ipad/viewport-overriden-by-minimum-effective-width-if-ignore-meta-viewport.html
new file mode 100644 (file)
index 0000000..15f8585
--- /dev/null
@@ -0,0 +1,57 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ shouldIgnoreMetaViewport=true ] -->
+<html>
+<head>
+    <style>
+        #square {
+            position: absolute;
+            width: 10vw;
+            height: 10vh;
+            border: 2px solid black;
+        }
+
+        #output {
+            width: 100%;
+            height: 100%;
+            overflow: scroll;
+        }
+
+        body {
+            margin: 0;
+            width: 100%;
+            height: 100%;
+        }
+    </style>
+    <script src="../../../../resources/ui-helper.js"></script>
+    <script>
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+    }
+
+    async function runTest() {
+        const appendOutput = message => {
+            output.appendChild(document.createTextNode(message));
+            output.appendChild(document.createElement("br"));
+        };
+
+        for (let targetMinimumEffectiveWidth of [640, 768, 834, 980, 1024, 1112, 1280, 1336]) {
+            appendOutput(`setMinimumEffectiveWidth(${targetMinimumEffectiveWidth.toFixed(2)})`);
+
+            await UIHelper.setMinimumEffectiveWidth(targetMinimumEffectiveWidth);
+            await Promise.all([UIHelper.ensureVisibleContentRectUpdate(), UIHelper.ensurePresentationUpdate()]);
+            appendOutput(`window size: [${innerWidth}, ${innerHeight}]`);
+            appendOutput(`square size: [${square.clientWidth}, ${square.clientHeight}]`);
+            appendOutput(`zoom scale: ${(await UIHelper.zoomScale()).toFixed(2)}`);
+            appendOutput("");
+        }
+
+        testRunner.notifyDone();
+    }
+    </script>
+</head>
+
+<body onload="runTest()">
+    <div id="square"></div>
+    <pre id="output"></pre>
+</body>
+</html>
diff --git a/LayoutTests/fast/viewport/ios/ipad/viewport-unchanged-by-minimum-effective-width-if-not-ignore-meta-viewport-expected.txt b/LayoutTests/fast/viewport/ios/ipad/viewport-unchanged-by-minimum-effective-width-if-not-ignore-meta-viewport-expected.txt
new file mode 100644 (file)
index 0000000..fd36321
--- /dev/null
@@ -0,0 +1,41 @@
+setMinimumEffectiveWidth(640.00)
+window size: [980, 1281]
+square size: [98, 128]
+zoom scale: 0.78
+
+setMinimumEffectiveWidth(768.00)
+window size: [980, 1281]
+square size: [98, 128]
+zoom scale: 0.78
+
+setMinimumEffectiveWidth(834.00)
+window size: [980, 1281]
+square size: [98, 128]
+zoom scale: 0.78
+
+setMinimumEffectiveWidth(980.00)
+window size: [980, 1281]
+square size: [98, 128]
+zoom scale: 0.78
+
+setMinimumEffectiveWidth(1024.00)
+window size: [980, 1281]
+square size: [98, 128]
+zoom scale: 0.78
+
+setMinimumEffectiveWidth(1112.00)
+window size: [980, 1281]
+square size: [98, 128]
+zoom scale: 0.78
+
+setMinimumEffectiveWidth(1280.00)
+window size: [980, 1281]
+square size: [98, 128]
+zoom scale: 0.78
+
+setMinimumEffectiveWidth(1336.00)
+window size: [980, 1281]
+square size: [98, 128]
+zoom scale: 0.78
+
+
diff --git a/LayoutTests/fast/viewport/ios/ipad/viewport-unchanged-by-minimum-effective-width-if-not-ignore-meta-viewport.html b/LayoutTests/fast/viewport/ios/ipad/viewport-unchanged-by-minimum-effective-width-if-not-ignore-meta-viewport.html
new file mode 100644 (file)
index 0000000..20e15a7
--- /dev/null
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+        #square {
+            position: absolute;
+            width: 10vw;
+            height: 10vh;
+            border: 2px solid black;
+        }
+
+        #output {
+            width: 100%;
+            height: 100%;
+            overflow: scroll;
+        }
+
+        body {
+            margin: 0;
+            width: 100%;
+            height: 100%;
+        }
+    </style>
+    <script src="../../../../resources/ui-helper.js"></script>
+    <script>
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+    }
+
+    async function runTest() {
+        const appendOutput = message => {
+            output.appendChild(document.createTextNode(message));
+            output.appendChild(document.createElement("br"));
+        };
+
+        for (let targetMinimumEffectiveWidth of [640, 768, 834, 980, 1024, 1112, 1280, 1336]) {
+            appendOutput(`setMinimumEffectiveWidth(${targetMinimumEffectiveWidth.toFixed(2)})`);
+
+            await UIHelper.setMinimumEffectiveWidth(targetMinimumEffectiveWidth);
+            await Promise.all([UIHelper.ensureVisibleContentRectUpdate(), UIHelper.ensurePresentationUpdate()]);
+            appendOutput(`window size: [${innerWidth}, ${innerHeight}]`);
+            appendOutput(`square size: [${square.clientWidth}, ${square.clientHeight}]`);
+            appendOutput(`zoom scale: ${(await UIHelper.zoomScale()).toFixed(2)}`);
+            appendOutput("");
+        }
+
+        testRunner.notifyDone();
+    }
+    </script>
+</head>
+
+<body onload="runTest()">
+    <div id="square"></div>
+    <pre id="output"></pre>
+</body>
+</html>
index d026ebe..e4df524 100644 (file)
@@ -468,4 +468,12 @@ window.UIHelper = class UIHelper {
             })
         });
     }
+
+    static setMinimumEffectiveWidth(effectiveWidth)
+    {
+        if (!this.isWebKit2())
+            return Promise.resolve();
+
+        return new Promise(resolve => testRunner.runUIScript(`uiController.setMinimumEffectiveWidth(${effectiveWidth})`, resolve));
+    }
 }
index 4a00dec..58c9a47 100644 (file)
@@ -1,3 +1,31 @@
+2018-11-28  Yongjun Zhang  <yongjun_zhang@apple.com>
+
+        Allow WebKit clients to specify a minimum effective width for layout.
+        https://bugs.webkit.org/show_bug.cgi?id=191499
+        <rdar://problem/45362678>
+
+        Reviewed by Wenson Hsieh.
+
+        If we ignore the meta viewport (_shouldIgnoreMetaViewport is true), the default layout width will be device
+        width. For clients that wish to lay out the content with a different width value, we would need to add a way
+        to specify the effective width for layout.
+
+        Tests: fast/viewport/ios/ipad/viewport-overriden-by-minimum-effective-width-if-ignore-meta-viewport.html
+               fast/viewport/ios/ipad/viewport-unchanged-by-minimum-effective-width-if-not-ignore-meta-viewport.html
+
+        * page/ViewportConfiguration.cpp:
+        (WebCore::ViewportConfiguration::setViewLayoutSize): Add a new argument effectiveWidth.
+        (WebCore::ViewportConfiguration::nativeWebpageParameters): Make sure minimumScale for nativeWebpageParameters
+            is small enough so that it won't clamp out the initial scale. If content is wider than the viewport, this
+            ensures we can still zoom out the page.
+        (WebCore::ViewportConfiguration::updateConfiguration): update _minimumEffectiveDeviceWidth and apply that to
+            the layout size scale computation.
+        (WebCore::ViewportConfiguration::effectiveLayoutSizeScaleFactor): A helper method to return the effective
+            layout scale factor which is also effected by _minimumEffectiveDeviceWidth.
+        (WebCore::ViewportConfiguration::updateMinimumLayoutSize): Update m_minimumLayoutSize based on effectiveLayoutSizeScaleFactor().
+        (WebCore::ViewportConfiguration::description const): Also dump m_minimumEffectiveDeviceWidth.
+        * page/ViewportConfiguration.h: Add a member variable m_minimumEffectiveDeviceWidth.
+
 2018-11-28  Stephan Szabo  <stephan.szabo@sony.com>
 
         Make generic EventHandler methods
index a5ebb87..5cc8140 100644 (file)
@@ -114,14 +114,16 @@ bool ViewportConfiguration::setContentsSize(const IntSize& contentSize)
     return true;
 }
 
-bool ViewportConfiguration::setViewLayoutSize(const FloatSize& viewLayoutSize, std::optional<double>&& scaleFactor)
+bool ViewportConfiguration::setViewLayoutSize(const FloatSize& viewLayoutSize, std::optional<double>&& scaleFactor, std::optional<double>&& minimumEffectiveDeviceWidth)
 {
     double newScaleFactor = scaleFactor.value_or(m_layoutSizeScaleFactor);
-    if (m_viewLayoutSize == viewLayoutSize && m_layoutSizeScaleFactor == newScaleFactor)
+    double newEffectiveWidth = minimumEffectiveDeviceWidth.value_or(m_minimumEffectiveDeviceWidth);
+    if (m_viewLayoutSize == viewLayoutSize && m_layoutSizeScaleFactor == newScaleFactor && newEffectiveWidth == m_minimumEffectiveDeviceWidth)
         return false;
 
     m_layoutSizeScaleFactor = newScaleFactor;
     m_viewLayoutSize = viewLayoutSize;
+    m_minimumEffectiveDeviceWidth = newEffectiveWidth;
 
     updateMinimumLayoutSize();
     updateConfiguration();
@@ -448,16 +450,17 @@ void ViewportConfiguration::updateConfiguration()
 
     m_configuration.avoidsUnsafeArea = m_viewportArguments.viewportFit != ViewportFit::Cover;
     m_configuration.initialScaleIgnoringLayoutScaleFactor = m_configuration.initialScale;
-    m_configuration.initialScale *= m_layoutSizeScaleFactor;
-    m_configuration.minimumScale *= m_layoutSizeScaleFactor;
-    m_configuration.maximumScale *= m_layoutSizeScaleFactor;
+    float effectiveLayoutScale = effectiveLayoutSizeScaleFactor();
+    m_configuration.initialScale *= effectiveLayoutScale;
+    m_configuration.minimumScale *= effectiveLayoutScale;
+    m_configuration.maximumScale *= effectiveLayoutScale;
 
     LOG_WITH_STREAM(Viewports, stream << "ViewportConfiguration " << this << " updateConfiguration " << *this << " gives initial scale " << initialScale() << " based on contentSize " << m_contentSize << " and layout size " << layoutWidth() << "x" << layoutHeight());
 }
 
 void ViewportConfiguration::updateMinimumLayoutSize()
 {
-    m_minimumLayoutSize = m_viewLayoutSize / m_layoutSizeScaleFactor;
+    m_minimumLayoutSize = m_viewLayoutSize / effectiveLayoutSizeScaleFactor();
 
     if (!shouldOverrideDeviceWidthAndShrinkToFit())
         return;
@@ -609,6 +612,7 @@ String ViewportConfiguration::description() const
     ts.dumpProperty("ignoring horizontal scaling constraints", shouldIgnoreHorizontalScalingConstraints() ? "true" : "false");
     ts.dumpProperty("ignoring vertical scaling constraints", shouldIgnoreVerticalScalingConstraints() ? "true" : "false");
     ts.dumpProperty("avoids unsafe area", avoidsUnsafeArea() ? "true" : "false");
+    ts.dumpProperty("minimum effective device width", m_minimumEffectiveDeviceWidth);
     
     ts.endGroup();
 
index 1f156d6..4987be2 100644 (file)
@@ -77,7 +77,7 @@ public:
     const FloatSize& viewLayoutSize() const { return m_viewLayoutSize; }
 
     const FloatSize& minimumLayoutSize() const { return m_minimumLayoutSize; }
-    WEBCORE_EXPORT bool setViewLayoutSize(const FloatSize&, std::optional<double>&& scaleFactor = std::nullopt);
+    WEBCORE_EXPORT bool setViewLayoutSize(const FloatSize&, std::optional<double>&& scaleFactor = std::nullopt, std::optional<double>&& effectiveWidth = std::nullopt);
 
     const OptionSet<DisabledAdaptations>& disabledAdaptations() const { return m_disabledAdaptations; }
     WEBCORE_EXPORT bool setDisabledAdaptations(const OptionSet<DisabledAdaptations>&);
@@ -130,13 +130,20 @@ private:
     constexpr double forceAlwaysUserScalableMaximumScale() const
     {
         const double forceAlwaysUserScalableMaximumScaleIgnoringLayoutScaleFactor = 5;
-        return forceAlwaysUserScalableMaximumScaleIgnoringLayoutScaleFactor * m_layoutSizeScaleFactor;
+        return forceAlwaysUserScalableMaximumScaleIgnoringLayoutScaleFactor * effectiveLayoutSizeScaleFactor();
     }
 
     constexpr double forceAlwaysUserScalableMinimumScale() const
     {
         const double forceAlwaysUserScalableMinimumScaleIgnoringLayoutScaleFactor = 1;
-        return forceAlwaysUserScalableMinimumScaleIgnoringLayoutScaleFactor * m_layoutSizeScaleFactor;
+        return forceAlwaysUserScalableMinimumScaleIgnoringLayoutScaleFactor * effectiveLayoutSizeScaleFactor();
+    }
+
+    constexpr double effectiveLayoutSizeScaleFactor() const
+    {
+        if (!m_viewLayoutSize.width() || !m_minimumEffectiveDeviceWidth)
+            return m_layoutSizeScaleFactor;
+        return m_layoutSizeScaleFactor * m_viewLayoutSize.width() / std::max<double>(m_minimumEffectiveDeviceWidth, m_viewLayoutSize.width());
     }
 
     void updateMinimumLayoutSize();
@@ -150,6 +157,7 @@ private:
     OptionSet<DisabledAdaptations> m_disabledAdaptations;
 
     double m_layoutSizeScaleFactor { 1 };
+    double m_minimumEffectiveDeviceWidth { 0 };
     bool m_canIgnoreScalingConstraints;
     bool m_forceAlwaysUserScalable;
 };
index 814ca72..1f33088 100644 (file)
@@ -1,3 +1,32 @@
+2018-11-28  Yongjun Zhang  <yongjun_zhang@apple.com>
+
+        Allow WebKit clients to specify a minimum effective width for layout.
+        https://bugs.webkit.org/show_bug.cgi?id=191499
+        <rdar://problem/45362678>
+
+        Reviewed by Wenson Hsieh.
+
+        If we ignore the meta viewport (_shouldIgnoreMetaViewport is true), the default layout width will be device
+        width. For clients that wish to lay out the content with a different width value, we would need to add a way
+        to specify the effective width for layout.
+
+        * UIProcess/API/Cocoa/WKWebView.mm: Add an iVar _minimumEffectiveDeviceWidth.
+        (-[WKWebView _dispatchSetViewLayoutSize:]): Call the new setViewportConfigurationViewLayoutSize method.
+        (-[WKWebView _setViewScale:]): Ditto.
+        (-[WKWebView _setMinimumEffectiveWidth:]): The setter for _minimumEffectiveDeviceWidth.
+        (-[WKWebView _minimumEffectiveWidth]): Getter for _minimumEffectiveDeviceWidth
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h: Add a property _minimumEffectiveDeviceWidth to WKWebView.
+        * UIProcess/WebPageProxy.h: Change setViewportConfigurationViewLayoutSize to take another argument minimumEffectiveDeviceWidth.
+        * UIProcess/ios/WebPageProxyIOS.mm:
+        (WebKit::WebPageProxy::setViewportConfigurationViewLayoutSize): Also send effectiveWidth to WebContent process.
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::WebPage): Set the initial effective width to 0 when creating a web page, this tells ViewportConfiguration
+             to ignore the minimum effective width value.
+        * WebProcess/WebPage/WebPage.h: Change setViewportConfigurationViewLayoutSize to take another argument effectiveWidth.
+        * WebProcess/WebPage/WebPage.messages.in:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::setViewportConfigurationViewLayoutSize): Also pass effectiveWidth value to ViewportConfiguration.
+
 2018-11-28  Fujii Hironori  <Hironori.Fujii@sony.com>
 
         Remove @no-unify of InjectedBundleRangeHandle.cpp and InjectedBundleNodeHandle.cpp
index 719b409..40a7d41 100644 (file)
@@ -383,6 +383,7 @@ static std::optional<WebCore::ScrollbarOverlayStyle> toCoreScrollbarStyle(_WKOve
     std::unique_ptr<WebKit::WebViewImpl> _impl;
     RetainPtr<WKTextFinderClient> _textFinderClient;
 #endif
+    CGFloat _minimumEffectiveDeviceWidth;
 }
 
 - (instancetype)initWithFrame:(CGRect)frame
@@ -2686,7 +2687,7 @@ static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
         return;
 
     LOG_WITH_STREAM(VisibleRects, stream << "-[WKWebView " << _page->pageID() << " _dispatchSetViewLayoutSize:] " << viewLayoutSize << " contentZoomScale " << contentZoomScale(self));
-    _page->setViewportConfigurationViewLayoutSize(viewLayoutSize, _page->layoutSizeScaleFactor());
+    _page->setViewportConfigurationViewLayoutSize(viewLayoutSize, _page->layoutSizeScaleFactor(), _minimumEffectiveDeviceWidth);
     _lastSentViewLayoutSize = viewLayoutSize;
 }
 
@@ -5347,10 +5348,26 @@ static inline WebKit::FindOptions toFindOptions(_WKFindOptions wkFindOptions)
     if (_page->layoutSizeScaleFactor() == viewScale)
         return;
 
-    _page->setViewportConfigurationViewLayoutSize([self activeViewLayoutSize:self.bounds], viewScale);
+    _page->setViewportConfigurationViewLayoutSize([self activeViewLayoutSize:self.bounds], viewScale, _minimumEffectiveDeviceWidth);
 #endif
 }
 
+- (void)_setMinimumEffectiveDeviceWidth:(CGFloat)minimumEffectiveDeviceWidth
+{
+    if (_minimumEffectiveDeviceWidth == minimumEffectiveDeviceWidth)
+        return;
+
+    _minimumEffectiveDeviceWidth = minimumEffectiveDeviceWidth;
+#if PLATFORM(IOS_FAMILY)
+    _page->setViewportConfigurationViewLayoutSize([self activeViewLayoutSize:self.bounds], _page->layoutSizeScaleFactor(), _minimumEffectiveDeviceWidth);
+#endif
+}
+
+- (CGFloat)_minimumEffectiveDeviceWidth
+{
+    return _minimumEffectiveDeviceWidth;
+}
+
 #pragma mark scrollperf methods
 
 - (void)_setScrollPerformanceDataCollectionEnabled:(BOOL)enabled
index 97228ab..170c2aa 100644 (file)
@@ -181,6 +181,8 @@ typedef NS_OPTIONS(NSUInteger, _WKRectEdge) {
 
 @property (nonatomic, setter=_setViewScale:) CGFloat _viewScale WK_API_AVAILABLE(macosx(10.11), ios(9.0));
 
+@property (nonatomic, setter=_setMinimumEffectiveDeviceWidth:) CGFloat _minimumEffectiveDeviceWidth WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 @property (nonatomic, setter=_setBackgroundExtendsBeyondPage:) BOOL _backgroundExtendsBeyondPage WK_API_AVAILABLE(macosx(10.13.4), ios(8.0));
 
 - (_WKAttachment *)_insertAttachmentWithFilename:(NSString *)filename contentType:(NSString *)contentType data:(NSData *)data options:(_WKAttachmentDisplayOptions *)options completion:(void(^)(BOOL success))completionHandler WK_API_DEPRECATED_WITH_REPLACEMENT("-_insertAttachmentWithFileWrapper:contentType:options:completion:", macosx(10.13.4, WK_MAC_TBA), ios(11.3, WK_IOS_TBA));
index 32e9f5d..32d9126 100644 (file)
@@ -603,7 +603,7 @@ public:
 
     void dynamicViewportSizeUpdate(const WebCore::FloatSize& viewLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const WebCore::FloatRect& targetExposedContentRect, const WebCore::FloatRect& targetUnobscuredRect, const WebCore::FloatRect& targetUnobscuredRectInScrollViewCoordinates, const WebCore::FloatBoxExtent& unobscuredSafeAreaInsets, double targetScale, int32_t deviceOrientation, DynamicViewportSizeUpdateID);
 
-    void setViewportConfigurationViewLayoutSize(const WebCore::FloatSize&, double scaleFactor);
+    void setViewportConfigurationViewLayoutSize(const WebCore::FloatSize&, double scaleFactor, double minimumEffectiveDeviceWidth);
     void setMaximumUnobscuredSize(const WebCore::FloatSize&);
     void setDeviceOrientation(int32_t);
     int32_t deviceOrientation() const { return m_deviceOrientation; }
index 72d8bd5..b473f08 100644 (file)
@@ -318,13 +318,13 @@ void WebPageProxy::dynamicViewportSizeUpdate(const FloatSize& viewLayoutSize, co
         targetScale, deviceOrientation, dynamicViewportSizeUpdateID), m_pageID);
 }
 
-void WebPageProxy::setViewportConfigurationViewLayoutSize(const WebCore::FloatSize& size, double scaleFactor)
+void WebPageProxy::setViewportConfigurationViewLayoutSize(const WebCore::FloatSize& size, double scaleFactor, double minimumEffectiveDeviceWidth)
 {
     m_viewportConfigurationViewLayoutSize = size;
     m_viewportConfigurationLayoutSizeScaleFactor = scaleFactor;
 
     if (isValid())
-        m_process->send(Messages::WebPage::SetViewportConfigurationViewLayoutSize(size, scaleFactor), m_pageID);
+        m_process->send(Messages::WebPage::SetViewportConfigurationViewLayoutSize(size, scaleFactor, minimumEffectiveDeviceWidth), m_pageID);
 }
 
 void WebPageProxy::setForceAlwaysUserScalable(bool userScalable)
index d78e047..5ff2465 100644 (file)
@@ -624,7 +624,7 @@ WebPage::WebPage(uint64_t pageID, WebPageCreationParameters&& parameters)
 #endif
 
 #if PLATFORM(IOS_FAMILY)
-    setViewportConfigurationViewLayoutSize(parameters.viewportConfigurationViewLayoutSize, parameters.viewportConfigurationLayoutSizeScaleFactor);
+    setViewportConfigurationViewLayoutSize(parameters.viewportConfigurationViewLayoutSize, parameters.viewportConfigurationLayoutSizeScaleFactor, 0);
     setMaximumUnobscuredSize(parameters.maximumUnobscuredSize);
 #endif
 }
index f5c5014..b32fc98 100644 (file)
@@ -914,7 +914,7 @@ public:
     void updateVisibilityState(bool isInitialState = false);
 
 #if PLATFORM(IOS_FAMILY)
-    void setViewportConfigurationViewLayoutSize(const WebCore::FloatSize&, double scaleFactor);
+    void setViewportConfigurationViewLayoutSize(const WebCore::FloatSize&, double scaleFactor, double minimumEffectiveDeviceWidth);
     void setMaximumUnobscuredSize(const WebCore::FloatSize&);
     void setDeviceOrientation(int32_t);
     void setOverrideViewportArguments(const std::optional<WebCore::ViewportArguments>&);
index 8ab8437..127d841 100644 (file)
@@ -45,7 +45,7 @@ messages -> WebPage LegacyReceiver {
     KeyEvent(WebKit::WebKeyboardEvent event)
     MouseEvent(WebKit::WebMouseEvent event)
 #if PLATFORM(IOS_FAMILY)
-    SetViewportConfigurationViewLayoutSize(WebCore::FloatSize size, double scaleFactor)
+    SetViewportConfigurationViewLayoutSize(WebCore::FloatSize size, double scaleFactor, double minimumEffectiveDeviceWidth)
     SetMaximumUnobscuredSize(WebCore::FloatSize size)
     SetDeviceOrientation(int32_t deviceOrientation)
     SetOverrideViewportArguments(std::optional<WebCore::ViewportArguments> arguments)
index 35fe9f5..eac4f4f 100644 (file)
@@ -2562,15 +2562,15 @@ static inline bool areEssentiallyEqualAsFloat(float a, float b)
     return WTF::areEssentiallyEqual(a, b);
 }
 
-void WebPage::setViewportConfigurationViewLayoutSize(const FloatSize& size, double scaleFactor)
+void WebPage::setViewportConfigurationViewLayoutSize(const FloatSize& size, double scaleFactor, double minimumEffectiveDeviceWidth)
 {
-    LOG_WITH_STREAM(VisibleRects, stream << "WebPage " << m_pageID << " setViewportConfigurationViewLayoutSize " << size << " scaleFactor " << scaleFactor);
+    LOG_WITH_STREAM(VisibleRects, stream << "WebPage " << m_pageID << " setViewportConfigurationViewLayoutSize " << size << " scaleFactor " << scaleFactor << " minimumEffectiveDeviceWidth " << minimumEffectiveDeviceWidth);
 
     ZoomToInitialScale shouldZoomToInitialScale = ZoomToInitialScale::No;
     if (m_viewportConfiguration.layoutSizeScaleFactor() != scaleFactor && areEssentiallyEqualAsFloat(m_viewportConfiguration.initialScale(), pageScaleFactor()))
         shouldZoomToInitialScale = ZoomToInitialScale::Yes;
 
-    if (m_viewportConfiguration.setViewLayoutSize(size, scaleFactor))
+    if (m_viewportConfiguration.setViewLayoutSize(size, scaleFactor, minimumEffectiveDeviceWidth))
         viewportConfigurationChanged(shouldZoomToInitialScale);
 }
 
index 647df90..69d1f20 100644 (file)
@@ -1,3 +1,27 @@
+2018-11-28  Yongjun Zhang  <yongjun_zhang@apple.com>
+
+        Allow WebKit clients to specify a minimum effective width for layout.
+        https://bugs.webkit.org/show_bug.cgi?id=191499
+        <rdar://problem/45362678>
+
+        Reviewed by Wenson Hsieh.
+
+        Allow UIScriptController to set WKWebView's minimum effective width with a new `setMinimumEffectiveWidth` method.
+
+        * DumpRenderTree/ios/UIScriptControllerIOS.mm:
+        (WTR::UIScriptController::setMinimumEffectiveWidth):
+        * DumpRenderTree/mac/UIScriptControllerMac.mm:
+        (WTR::UIScriptController::setViewScale):
+        (WTR::UIScriptController::setMinimumEffectiveWidth):
+        * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
+        * TestRunnerShared/UIScriptContext/UIScriptController.cpp:
+        (WTR::UIScriptController::setMinimumEffectiveWidth):
+        * TestRunnerShared/UIScriptContext/UIScriptController.h:
+        * WebKitTestRunner/UIScriptControllerCocoa.mm:
+        (WTR::UIScriptController::setMinimumEffectiveWidth):
+        * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
+        (WTR::TestController::cocoaResetStateToConsistentValues):
+
 2018-11-28  Lucas Forschler  <lforschler@apple.com>
 
         Fix webkitbot hi command.
index 7cc4fa0..25662e2 100644 (file)
@@ -90,6 +90,10 @@ void UIScriptController::setViewScale(double)
 {
 }
 
+void UIScriptController::setMinimumEffectiveWidth(double)
+{
+}
+
 void UIScriptController::simulateAccessibilitySettingsChangeNotification(JSValueRef)
 {
 }
index a670de2..c445145 100644 (file)
@@ -97,6 +97,10 @@ void UIScriptController::setViewScale(double)
 {
 }
 
+void UIScriptController::setMinimumEffectiveWidth(double)
+{
+}
+
 void UIScriptController::simulateAccessibilitySettingsChangeNotification(JSValueRef)
 {
 }
index 7793248..915f6db 100644 (file)
@@ -227,6 +227,7 @@ interface UIScriptController {
     void zoomToScale(double scale, object callback);
 
     void setViewScale(double scale);
+    void setMinimumEffectiveWidth(double effectiveWidth);
 
     void resignFirstResponder();
 
index 7cb17c2..e2d0535 100644 (file)
@@ -215,6 +215,10 @@ void UIScriptController::setViewScale(double)
 {
 }
 
+void UIScriptController::setMinimumEffectiveWidth(double)
+{
+}
+
 void UIScriptController::resignFirstResponder()
 {
 }
index 98472a4..2176f9d 100644 (file)
@@ -67,6 +67,7 @@ public:
 
     void zoomToScale(double scale, JSValueRef callback);
     void setViewScale(double);
+    void setMinimumEffectiveWidth(double);
 
     void resignFirstResponder();
 
index 9df62a1..a7b98e4 100644 (file)
@@ -45,6 +45,15 @@ void UIScriptController::setViewScale(double scale)
 #endif
 }
 
+void UIScriptController::setMinimumEffectiveWidth(double effectiveWidth)
+{
+#if WK_API_ENABLED
+    TestController::singleton().mainWebView()->platformView()._minimumEffectiveDeviceWidth = effectiveWidth;
+#else
+    UNUSED_PARAM(effectiveWidth);
+#endif
+}
+
 void UIScriptController::resignFirstResponder()
 {
 #if WK_API_ENABLED
index 93ec3a4..2274270 100644 (file)
@@ -251,6 +251,7 @@ void TestController::cocoaResetStateToConsistentValues(const TestOptions& option
         TestRunnerWKWebView *platformView = webView->platformView();
         [platformView.configuration.userContentController _removeAllUserContentFilters];
         platformView._viewScale = 1;
+        platformView._minimumEffectiveDeviceWidth = 0;
 
         // Toggle on before the test, and toggle off after the test.
         if (options.shouldShowSpellCheckingDots)