Add modern API for overriding the page's specified viewport configuration
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 10 Apr 2019 21:32:58 +0000 (21:32 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 10 Apr 2019 21:32:58 +0000 (21:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=167734
<rdar://problem/30331795>

Reviewed by Simon Fraser.

Source/WebCore:

New API test: WebKit.OverrideViewportArguments

* dom/Document.cpp:
(WebCore::Document::updateViewportArguments):
* dom/Document.h:
(WebCore::Document::viewportArguments const):
Make the viewportArguments() getter respect the overridden arguments.

* dom/ViewportArguments.cpp:
(WebCore::numericPrefix):
(WebCore::findSizeValue):
(WebCore::findScaleValue):
(WebCore::findBooleanValue):
(WebCore::parseViewportFitValue):
(WebCore::viewportErrorMessage):
(WebCore::reportViewportWarning):
(WebCore::setViewportFeature):
* dom/ViewportArguments.h:
Make it possible to parse ViewportArguments without a Document, so
that it can be used in the UI process. We only used the Document for
two things: error reporting, and getting the state of one setting.
Refactor error handling to use a passed-arund function, and add a
variant of setViewportFeature() that doesn't take a Document.

Source/WebKit:

* Shared/WebPageCreationParameters.cpp:
(WebKit::WebPageCreationParameters::encode const):
(WebKit::WebPageCreationParameters::decode):
* Shared/WebPageCreationParameters.h:
Plumb overrideViewportArguments in WebPageCreationParameters, so that
if the process crashes (or swaps) they are maintained.

* UIProcess/API/Cocoa/WKWebView.mm:
(viewportArgumentsFromDictionary):
(-[WKWebView _overrideViewportWithArguments:]):
Add SPI to set override viewport arguments. Parse them into a ViewportArguments
object and use the existing (now improved) overrideViewportArguments mechanism
to take over the page's viewport arguments.

* UIProcess/API/Cocoa/WKWebViewPrivate.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::creationParameters):
* UIProcess/WebPageProxy.h:
* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::setOverrideViewportArguments):
* WebProcess/WebPage/WebPage.cpp:
Plumb overrideViewportArguments around more.

Tools:

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/OverrideViewportArguments.mm: Added.

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

17 files changed:
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/ViewportArguments.cpp
Source/WebCore/dom/ViewportArguments.h
Source/WebKit/ChangeLog
Source/WebKit/Shared/WebPageCreationParameters.cpp
Source/WebKit/Shared/WebPageCreationParameters.h
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKitCocoa/OverrideViewportArguments.mm [new file with mode: 0644]

index 8b50737..05068e8 100644 (file)
@@ -1,3 +1,35 @@
+2019-04-10  Tim Horton  <timothy_horton@apple.com>
+
+        Add modern API for overriding the page's specified viewport configuration
+        https://bugs.webkit.org/show_bug.cgi?id=167734
+        <rdar://problem/30331795>
+
+        Reviewed by Simon Fraser.
+
+        New API test: WebKit.OverrideViewportArguments
+
+        * dom/Document.cpp:
+        (WebCore::Document::updateViewportArguments):
+        * dom/Document.h:
+        (WebCore::Document::viewportArguments const):
+        Make the viewportArguments() getter respect the overridden arguments.
+
+        * dom/ViewportArguments.cpp:
+        (WebCore::numericPrefix):
+        (WebCore::findSizeValue):
+        (WebCore::findScaleValue):
+        (WebCore::findBooleanValue):
+        (WebCore::parseViewportFitValue):
+        (WebCore::viewportErrorMessage):
+        (WebCore::reportViewportWarning):
+        (WebCore::setViewportFeature):
+        * dom/ViewportArguments.h:
+        Make it possible to parse ViewportArguments without a Document, so
+        that it can be used in the UI process. We only used the Document for
+        two things: error reporting, and getting the state of one setting.
+        Refactor error handling to use a passed-arund function, and add a
+        variant of setViewportFeature() that doesn't take a Document.
+
 2019-04-10  Justin Fan  <justin_fan@apple.com>
 
         [Web GPU] Indexed drawing and GPUCommandEncoder crash prevention
index ef964fb..064eb94 100644 (file)
@@ -3621,7 +3621,7 @@ void Document::updateViewportArguments()
 #ifndef NDEBUG
         m_didDispatchViewportPropertiesChanged = true;
 #endif
-        page()->chrome().dispatchViewportPropertiesDidChange(m_overrideViewportArguments ? m_overrideViewportArguments.value() : m_viewportArguments);
+        page()->chrome().dispatchViewportPropertiesDidChange(viewportArguments());
         page()->chrome().didReceiveDocType(*frame());
     }
 }
index d67f6e8..722b07f 100644 (file)
@@ -411,7 +411,7 @@ public:
     void clearSelectorQueryCache();
 
     void setViewportArguments(const ViewportArguments& viewportArguments) { m_viewportArguments = viewportArguments; }
-    ViewportArguments viewportArguments() const { return m_viewportArguments; }
+    ViewportArguments viewportArguments() const { return m_overrideViewportArguments.valueOr(m_viewportArguments); }
 
     WEBCORE_EXPORT void setOverrideViewportArguments(const Optional<ViewportArguments>&);
 
index f3a8461..cc63d96 100644 (file)
@@ -38,6 +38,8 @@
 
 namespace WebCore {
 
+typedef WTF::Function<void(ViewportErrorCode, StringView, StringView)> InternalViewportErrorHandler;
+
 #if PLATFORM(GTK)
 const float ViewportArguments::deprecatedTargetDPI = 160;
 #endif
@@ -288,9 +290,7 @@ void restrictScaleFactorToInitialScaleIfNotUserScalable(ViewportAttributes& resu
         result.maximumScale = result.minimumScale = result.initialScale;
 }
 
-static void reportViewportWarning(Document&, ViewportErrorCode, StringView replacement1 = { }, StringView replacement2 = { });
-
-static float numericPrefix(Document& document, StringView key, StringView value, bool* ok = nullptr)
+static float numericPrefix(StringView key, StringView value, const InternalViewportErrorHandler& errorHandler, bool* ok = nullptr)
 {
     size_t parsedLength;
     float numericValue;
@@ -299,19 +299,19 @@ static float numericPrefix(Document& document, StringView key, StringView value,
     else
         numericValue = charactersToFloat(value.characters16(), value.length(), parsedLength);
     if (!parsedLength) {
-        reportViewportWarning(document, UnrecognizedViewportArgumentValueError, value, key);
+        errorHandler(UnrecognizedViewportArgumentValueError, value, key);
         if (ok)
             *ok = false;
         return 0;
     }
     if (parsedLength < value.length())
-        reportViewportWarning(document, TruncatedViewportArgumentValueError, value, key);
+        errorHandler(TruncatedViewportArgumentValueError, value, key);
     if (ok)
         *ok = true;
     return numericValue;
 }
 
-static float findSizeValue(Document& document, StringView key, StringView value, bool* valueWasExplicit = nullptr)
+static float findSizeValue(StringView key, StringView value, const InternalViewportErrorHandler& errorHandler, bool* valueWasExplicit = nullptr)
 {
     // 1) Non-negative number values are translated to px lengths.
     // 2) Negative number values are translated to auto.
@@ -327,7 +327,7 @@ static float findSizeValue(Document& document, StringView key, StringView value,
     if (equalLettersIgnoringASCIICase(value, "device-height"))
         return ViewportArguments::ValueDeviceHeight;
 
-    float sizeValue = numericPrefix(document, key, value);
+    float sizeValue = numericPrefix(key, value, errorHandler);
 
     if (sizeValue < 0) {
         if (valueWasExplicit)
@@ -338,7 +338,7 @@ static float findSizeValue(Document& document, StringView key, StringView value,
     return sizeValue;
 }
 
-static float findScaleValue(Document& document, StringView key, StringView value)
+static float findScaleValue(StringView key, StringView value, const InternalViewportErrorHandler& errorHandler)
 {
     // 1) Non-negative number values are translated to <number> values.
     // 2) Negative number values are translated to auto.
@@ -355,18 +355,18 @@ static float findScaleValue(Document& document, StringView key, StringView value
     if (equalLettersIgnoringASCIICase(value, "device-height"))
         return 10;
 
-    float numericValue = numericPrefix(document, key, value);
+    float numericValue = numericPrefix(key, value, errorHandler);
 
     if (numericValue < 0)
         return ViewportArguments::ValueAuto;
 
     if (numericValue > 10.0)
-        reportViewportWarning(document, MaximumScaleTooLargeError);
+        errorHandler(MaximumScaleTooLargeError, { }, { });
 
     return numericValue;
 }
 
-static bool findBooleanValue(Document& document, StringView key, StringView value)
+static bool findBooleanValue(StringView key, StringView value, const InternalViewportErrorHandler& errorHandler)
 {
     // yes and no are used as keywords.
     // Numbers >= 1, numbers <= -1, device-width and device-height are mapped to yes.
@@ -380,10 +380,10 @@ static bool findBooleanValue(Document& document, StringView key, StringView valu
         return true;
     if (equalLettersIgnoringASCIICase(value, "device-height"))
         return true;
-    return std::abs(numericPrefix(document, key, value)) >= 1;
+    return std::abs(numericPrefix(key, value, errorHandler)) >= 1;
 }
 
-static ViewportFit parseViewportFitValue(Document& document, StringView key, StringView value)
+static ViewportFit parseViewportFitValue(StringView key, StringView value, const InternalViewportErrorHandler& errorHandler)
 {
     if (equalLettersIgnoringASCIICase(value, "auto"))
         return ViewportFit::Auto;
@@ -392,39 +392,11 @@ static ViewportFit parseViewportFitValue(Document& document, StringView key, Str
     if (equalLettersIgnoringASCIICase(value, "cover"))
         return ViewportFit::Cover;
 
-    reportViewportWarning(document, UnrecognizedViewportArgumentValueError, value, key);
+    errorHandler(UnrecognizedViewportArgumentValueError, value, key);
 
     return ViewportFit::Auto;
 }
 
-void setViewportFeature(ViewportArguments& arguments, Document& document, StringView key, StringView value)
-{
-    if (equalLettersIgnoringASCIICase(key, "width"))
-        arguments.width = findSizeValue(document, key, value, &arguments.widthWasExplicit);
-    else if (equalLettersIgnoringASCIICase(key, "height"))
-        arguments.height = findSizeValue(document, key, value);
-    else if (equalLettersIgnoringASCIICase(key, "initial-scale"))
-        arguments.zoom = findScaleValue(document, key, value);
-    else if (equalLettersIgnoringASCIICase(key, "minimum-scale"))
-        arguments.minZoom = findScaleValue(document, key, value);
-    else if (equalLettersIgnoringASCIICase(key, "maximum-scale"))
-        arguments.maxZoom = findScaleValue(document, key, value);
-    else if (equalLettersIgnoringASCIICase(key, "user-scalable"))
-        arguments.userZoom = findBooleanValue(document, key, value);
-#if PLATFORM(IOS_FAMILY)
-    else if (equalLettersIgnoringASCIICase(key, "minimal-ui")) {
-        // FIXME: Ignore silently for now. This code should eventually be removed
-        // so we start giving the warning in the web inspector as for other unimplemented keys.
-    }
-#endif
-    else if (equalLettersIgnoringASCIICase(key, "shrink-to-fit"))
-        arguments.shrinkToFit = findBooleanValue(document, key, value);
-    else if (equalLettersIgnoringASCIICase(key, "viewport-fit") && document.settings().viewportFitEnabled())
-        arguments.viewportFit = parseViewportFitValue(document, key, value);
-    else
-        reportViewportWarning(document, UnrecognizedViewportArgumentKeyError, key);
-}
-
 static const char* viewportErrorMessageTemplate(ViewportErrorCode errorCode)
 {
     static const char* const errors[] = {
@@ -452,12 +424,8 @@ static MessageLevel viewportErrorMessageLevel(ViewportErrorCode errorCode)
     return MessageLevel::Error;
 }
 
-void reportViewportWarning(Document& document, ViewportErrorCode errorCode, StringView replacement1, StringView replacement2)
+static String viewportErrorMessage(ViewportErrorCode errorCode, StringView replacement1, StringView replacement2)
 {
-    // FIXME: Why is this null check needed? Can't addConsoleMessage deal with this?
-    if (!document.frame())
-        return;
-
     String message = viewportErrorMessageTemplate(errorCode);
     if (!replacement1.isNull())
         message.replace("%replacement1", replacement1.toStringWithoutCopying());
@@ -468,10 +436,58 @@ void reportViewportWarning(Document& document, ViewportErrorCode errorCode, Stri
     if ((errorCode == UnrecognizedViewportArgumentValueError || errorCode == TruncatedViewportArgumentValueError) && replacement1.contains(';'))
         message.append(" Note that ';' is not a separator in viewport values. The list should be comma-separated.");
 
+    return message;
+}
+
+static void reportViewportWarning(Document& document, ViewportErrorCode errorCode, const String& message)
+{
+    // FIXME: Why is this null check needed? Can't addConsoleMessage deal with this?
+    if (!document.frame())
+        return;
+
     // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
     document.addConsoleMessage(MessageSource::Rendering, viewportErrorMessageLevel(errorCode), message);
 }
 
+void setViewportFeature(ViewportArguments& arguments, StringView key, StringView value, bool viewportFitEnabled, const ViewportErrorHandler& errorHandler)
+{
+    InternalViewportErrorHandler internalErrorHandler = [&errorHandler] (ViewportErrorCode errorCode, StringView replacement1, StringView replacement2) {
+        errorHandler(errorCode, viewportErrorMessage(errorCode, replacement1, replacement2));
+    };
+
+    if (equalLettersIgnoringASCIICase(key, "width"))
+        arguments.width = findSizeValue(key, value, internalErrorHandler, &arguments.widthWasExplicit);
+    else if (equalLettersIgnoringASCIICase(key, "height"))
+        arguments.height = findSizeValue(key, value, internalErrorHandler);
+    else if (equalLettersIgnoringASCIICase(key, "initial-scale"))
+        arguments.zoom = findScaleValue(key, value, internalErrorHandler);
+    else if (equalLettersIgnoringASCIICase(key, "minimum-scale"))
+        arguments.minZoom = findScaleValue(key, value, internalErrorHandler);
+    else if (equalLettersIgnoringASCIICase(key, "maximum-scale"))
+        arguments.maxZoom = findScaleValue(key, value, internalErrorHandler);
+    else if (equalLettersIgnoringASCIICase(key, "user-scalable"))
+        arguments.userZoom = findBooleanValue(key, value, internalErrorHandler);
+#if PLATFORM(IOS_FAMILY)
+    else if (equalLettersIgnoringASCIICase(key, "minimal-ui")) {
+        // FIXME: Ignore silently for now. This code should eventually be removed
+        // so we start giving the warning in the web inspector as for other unimplemented keys.
+    }
+#endif
+    else if (equalLettersIgnoringASCIICase(key, "shrink-to-fit"))
+        arguments.shrinkToFit = findBooleanValue(key, value, internalErrorHandler);
+    else if (equalLettersIgnoringASCIICase(key, "viewport-fit") && viewportFitEnabled)
+        arguments.viewportFit = parseViewportFitValue(key, value, internalErrorHandler);
+    else
+        internalErrorHandler(UnrecognizedViewportArgumentKeyError, key, { });
+}
+
+void setViewportFeature(ViewportArguments& arguments, Document& document, StringView key, StringView value)
+{
+    setViewportFeature(arguments, key, value, document.settings().viewportFitEnabled(), [&](ViewportErrorCode errorCode, const String& message) {
+        reportViewportWarning(document, errorCode, message);
+    });
+}
+
 TextStream& operator<<(TextStream& ts, const ViewportArguments& viewportArguments)
 {
     TextStream::IndentScope indentScope(ts);
index 4dbf093..8250986 100644 (file)
@@ -143,7 +143,9 @@ WEBCORE_EXPORT void restrictMinimumScaleFactorToViewportSize(ViewportAttributes&
 WEBCORE_EXPORT void restrictScaleFactorToInitialScaleIfNotUserScalable(ViewportAttributes& result);
 WEBCORE_EXPORT float computeMinimumScaleFactorForContentContained(const ViewportAttributes& result, const IntSize& viewportSize, const IntSize& contentSize);
 
+typedef WTF::Function<void(ViewportErrorCode, const String&)> ViewportErrorHandler;
 void setViewportFeature(ViewportArguments&, Document&, StringView key, StringView value);
+WEBCORE_EXPORT void setViewportFeature(ViewportArguments&, StringView key, StringView value, bool viewportFitEnabled, const ViewportErrorHandler&);
 
 WTF::TextStream& operator<<(WTF::TextStream&, const ViewportArguments&);
 
index ec32aa0..93b9c35 100644 (file)
@@ -1,3 +1,34 @@
+2019-04-10  Tim Horton  <timothy_horton@apple.com>
+
+        Add modern API for overriding the page's specified viewport configuration
+        https://bugs.webkit.org/show_bug.cgi?id=167734
+        <rdar://problem/30331795>
+
+        Reviewed by Simon Fraser.
+
+        * Shared/WebPageCreationParameters.cpp:
+        (WebKit::WebPageCreationParameters::encode const):
+        (WebKit::WebPageCreationParameters::decode):
+        * Shared/WebPageCreationParameters.h:
+        Plumb overrideViewportArguments in WebPageCreationParameters, so that
+        if the process crashes (or swaps) they are maintained.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (viewportArgumentsFromDictionary):
+        (-[WKWebView _overrideViewportWithArguments:]):
+        Add SPI to set override viewport arguments. Parse them into a ViewportArguments
+        object and use the existing (now improved) overrideViewportArguments mechanism
+        to take over the page's viewport arguments.
+
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::creationParameters):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/ios/WebPageProxyIOS.mm:
+        (WebKit::WebPageProxy::setOverrideViewportArguments):
+        * WebProcess/WebPage/WebPage.cpp:
+        Plumb overrideViewportArguments around more.
+
 2019-04-10  Jiewen Tan  <jiewen_tan@apple.com>
 
         Add runJavaScriptInFrame for WebPageProxy/WebPage
index 18b25b1..47c6ed6 100644 (file)
@@ -95,6 +95,7 @@ void WebPageCreationParameters::encode(IPC::Encoder& encoder) const
     encoder << maximumUnobscuredSize;
     encoder << deviceOrientation;
     encoder << keyboardIsAttached;
+    encoder << overrideViewportArguments;
 #endif
 #if PLATFORM(COCOA)
     encoder << smartInsertDeleteEnabled;
@@ -279,6 +280,12 @@ Optional<WebPageCreationParameters> WebPageCreationParameters::decode(IPC::Decod
         return WTF::nullopt;
     if (!decoder.decode(parameters.keyboardIsAttached))
         return WTF::nullopt;
+
+    Optional<Optional<WebCore::ViewportArguments>> overrideViewportArguments;
+    decoder >> overrideViewportArguments;
+    if (!overrideViewportArguments)
+        return WTF::nullopt;
+    parameters.overrideViewportArguments = WTFMove(*overrideViewportArguments);
 #endif
 
 #if PLATFORM(COCOA)
index ab3b8e0..159fdee 100644 (file)
@@ -42,6 +42,7 @@
 #include <WebCore/Pagination.h>
 #include <WebCore/ScrollTypes.h>
 #include <WebCore/UserInterfaceLayoutDirection.h>
+#include <WebCore/ViewportArguments.h>
 #include <pal/SessionID.h>
 #include <wtf/HashMap.h>
 #include <wtf/text/WTFString.h>
@@ -153,6 +154,7 @@ struct WebPageCreationParameters {
     WebCore::FloatSize maximumUnobscuredSize;
     int32_t deviceOrientation { 0 };
     bool keyboardIsAttached { false };
+    Optional<WebCore::ViewportArguments> overrideViewportArguments;
 #endif
 #if PLATFORM(COCOA)
     bool smartInsertDeleteEnabled;
index 6bda245..b3cdfa1 100644 (file)
@@ -6253,6 +6253,34 @@ static inline WebKit::FindOptions toFindOptions(_WKFindOptions wkFindOptions)
     _maximumUnobscuredSizeOverride = CGSizeZero;
 }
 
+static WTF::Optional<WebCore::ViewportArguments> viewportArgumentsFromDictionary(NSDictionary<NSString *, NSString *> *viewportArgumentPairs, bool viewportFitEnabled)
+{
+    if (!viewportArgumentPairs)
+        return WTF::nullopt;
+
+    WebCore::ViewportArguments viewportArguments(WebCore::ViewportArguments::ViewportMeta);
+
+    [viewportArgumentPairs enumerateKeysAndObjectsUsingBlock:makeBlockPtr([&] (NSString *key, NSString *value, BOOL* stop) {
+        if (![key isKindOfClass:[NSString class]] || ![value isKindOfClass:[NSString class]])
+            [NSException raise:NSInvalidArgumentException format:@"-[WKWebView _overrideViewportWithArguments:]: Keys and values must all be NSStrings."];
+        String keyString = key;
+        String valueString = value;
+        WebCore::setViewportFeature(viewportArguments, keyString, valueString, viewportFitEnabled, [] (WebCore::ViewportErrorCode, const String& errorMessage) {
+            NSLog(@"-[WKWebView _overrideViewportWithArguments:]: Error parsing viewport argument: %s", errorMessage.utf8().data());
+        });
+    }).get()];
+
+    return viewportArguments;
+}
+
+- (void)_overrideViewportWithArguments:(NSDictionary<NSString *, NSString *> *)arguments
+{
+    if (!_page)
+        return;
+
+    _page->setOverrideViewportArguments(viewportArgumentsFromDictionary(arguments, _page->preferences().viewportFitEnabled()));
+}
+
 - (UIView *)_viewForFindUI
 {
     return [self viewForZoomingInScrollView:[self scrollView]];
index bd344c2..499588c 100644 (file)
@@ -281,6 +281,7 @@ typedef NS_OPTIONS(NSUInteger, _WKRectEdge) {
 - (void)_snapshotRect:(CGRect)rectInViewCoordinates intoImageOfWidth:(CGFloat)imageWidth completionHandler:(void(^)(CGImageRef))completionHandler;
 
 - (void)_overrideLayoutParametersWithMinimumLayoutSize:(CGSize)minimumLayoutSize maximumUnobscuredSizeOverride:(CGSize)maximumUnobscuredSizeOverride WK_API_AVAILABLE(ios(9_0));
+- (void)_overrideViewportWithArguments:(NSDictionary<NSString *, NSString *> *)arguments WK_API_AVAILABLE(ios(WK_IOS_TBA));
 
 - (void)_clearOverrideLayoutParameters WK_API_AVAILABLE(ios(11.0));
 - (void)_clearInterfaceOrientationOverride WK_API_AVAILABLE(ios(11.0));
index 2044517..be71514 100644 (file)
@@ -7023,6 +7023,7 @@ WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& proc
     parameters.maximumUnobscuredSize = m_maximumUnobscuredSize;
     parameters.deviceOrientation = m_deviceOrientation;
     parameters.keyboardIsAttached = isInHardwareKeyboardMode();
+    parameters.overrideViewportArguments = m_overrideViewportArguments;
 #endif
 
 #if PLATFORM(MAC)
index 7e4f9b2..17981ea 100644 (file)
@@ -91,6 +91,7 @@
 #include <WebCore/TextChecking.h>
 #include <WebCore/TextGranularity.h>
 #include <WebCore/UserInterfaceLayoutDirection.h>
+#include <WebCore/ViewportArguments.h>
 #include <memory>
 #include <wtf/CompletionHandler.h>
 #include <wtf/HashMap.h>
@@ -2127,6 +2128,7 @@ private:
 #endif
 
 #if PLATFORM(IOS_FAMILY)
+    Optional<WebCore::ViewportArguments> m_overrideViewportArguments;
     VisibleContentRectUpdateInfo m_lastVisibleContentRectUpdate;
     uint64_t m_firstLayerTreeTransactionIdAfterDidCommitLoad { 0 };
     int32_t m_deviceOrientation { 0 };
index 1018e0e..981c4ca 100644 (file)
@@ -371,6 +371,11 @@ void WebPageProxy::setDeviceOrientation(int32_t deviceOrientation)
 
 void WebPageProxy::setOverrideViewportArguments(const Optional<ViewportArguments>& viewportArguments)
 {
+    if (viewportArguments == m_overrideViewportArguments)
+        return;
+
+    m_overrideViewportArguments = viewportArguments;
+
     if (hasRunningProcess())
         m_process->send(Messages::WebPage::SetOverrideViewportArguments(viewportArguments), m_pageID);
 }
index 7d87e25..a96cbad 100644 (file)
@@ -537,6 +537,7 @@ WebPage::WebPage(uint64_t pageID, WebPageCreationParameters&& parameters)
     m_page->setUserInterfaceLayoutDirection(m_userInterfaceLayoutDirection);
 #if PLATFORM(IOS_FAMILY)
     m_page->setTextAutosizingWidth(parameters.textAutosizingWidth);
+    setOverrideViewportArguments(parameters.overrideViewportArguments);
 #endif
 
     platformInitialize();
index bdfab11..1819f7c 100644 (file)
@@ -1,3 +1,14 @@
+2019-04-10  Tim Horton  <timothy_horton@apple.com>
+
+        Add modern API for overriding the page's specified viewport configuration
+        https://bugs.webkit.org/show_bug.cgi?id=167734
+        <rdar://problem/30331795>
+
+        Reviewed by Simon Fraser.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/OverrideViewportArguments.mm: Added.
+
 2019-04-10  Tadeu Zagallo  <tzagallo@apple.com>
 
         Add support for incremental bytecode cache updates
index b66c5cc..2ef36c4 100644 (file)
                2D70059921EDA4D0003463CB /* OffscreenWindow.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D70059721EDA4D0003463CB /* OffscreenWindow.mm */; };
                2D7FD19322419087007887F1 /* DocumentEditingContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D7FD19222419087007887F1 /* DocumentEditingContext.mm */; };
                2D838B1F1EEF3A5C009B980E /* WKContentViewEditingActions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D838B1E1EEF3A5B009B980E /* WKContentViewEditingActions.mm */; };
+               2DA2586F225C67DC00B45C1C /* OverrideViewportArguments.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2DA2586E225C67DC00B45C1C /* OverrideViewportArguments.mm */; };
                2DADF26321CB8F32003D3E3A /* GetResourceData.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2DADF26221CB8F32003D3E3A /* GetResourceData.mm */; };
                2DB0232F1E4E871800707123 /* InteractionDeadlockAfterCrash.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2DB0232E1E4E871800707123 /* InteractionDeadlockAfterCrash.mm */; };
                2DB647881F4163D60051A89E /* WKWebViewDoesNotLogDuringInitialization.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2DB647871F4161F70051A89E /* WKWebViewDoesNotLogDuringInitialization.mm */; };
                2D8104CB1BEC13E70020DA46 /* FindInPage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FindInPage.mm; sourceTree = "<group>"; };
                2D838B1E1EEF3A5B009B980E /* WKContentViewEditingActions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKContentViewEditingActions.mm; sourceTree = "<group>"; };
                2D9A53AE1B31FA8D0074D5AA /* ShrinkToFit.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ShrinkToFit.mm; sourceTree = "<group>"; };
+               2DA2586E225C67DC00B45C1C /* OverrideViewportArguments.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OverrideViewportArguments.mm; sourceTree = "<group>"; };
                2DADF26221CB8F32003D3E3A /* GetResourceData.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GetResourceData.mm; sourceTree = "<group>"; };
                2DB0232E1E4E871800707123 /* InteractionDeadlockAfterCrash.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InteractionDeadlockAfterCrash.mm; sourceTree = "<group>"; };
                2DB647871F4161F70051A89E /* WKWebViewDoesNotLogDuringInitialization.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WKWebViewDoesNotLogDuringInitialization.mm; sourceTree = "<group>"; };
                                37A22AA51DCAA27200AFBFC4 /* ObservedRenderingProgressEventsAfterCrash.mm */,
                                CEA6CF2219CCF5BD0064F5A7 /* OpenAndCloseWindow.mm */,
                                CEBCA12E1E3A660100C73293 /* OverrideContentSecurityPolicy.mm */,
+                               2DA2586E225C67DC00B45C1C /* OverrideViewportArguments.mm */,
                                2D3CA3A4221DF2390088E803 /* PageOverlayPlugin.mm */,
                                F44C79FB20F9E50C0014478C /* ParserYieldTokenPlugIn.mm */,
                                F44C79FD20F9E8710014478C /* ParserYieldTokenTests.h */,
                                2D70059921EDA4D0003463CB /* OffscreenWindow.mm in Sources */,
                                7CCE7F251A411AF600447C4C /* OpenAndCloseWindow.mm in Sources */,
                                CEBCA12F1E3A660100C73293 /* OverrideContentSecurityPolicy.mm in Sources */,
+                               2DA2586F225C67DC00B45C1C /* OverrideViewportArguments.mm in Sources */,
                                7CCB4DA91C83AE7300CC6918 /* PageGroup.cpp in Sources */,
                                7CCE7F071A411AE600447C4C /* PageLoadBasic.cpp in Sources */,
                                7CCE7F081A411AE600447C4C /* PageLoadDidChangeLocationWithinPageForFrame.cpp in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/OverrideViewportArguments.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/OverrideViewportArguments.mm
new file mode 100644 (file)
index 0000000..7e10fad
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#import "PlatformUtilities.h"
+#import "TestNavigationDelegate.h"
+#import "TestWKWebView.h"
+#import <WebKit/WKPreferences.h>
+#import <WebKit/WKWebViewPrivate.h>
+#import <wtf/RetainPtr.h>
+
+#if PLATFORM(IOS_FAMILY)
+
+TEST(WebKit, OverrideViewportArguments)
+{
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 20, 20)]);
+
+    auto bodyWidth = ^{
+        return [webView stringByEvaluatingJavaScript:@"document.body.clientWidth"];
+    };
+
+    [webView synchronouslyLoadHTMLString:@"<meta name='viewport' content='initial-scale=1'><div id='divWithViewportUnits' style='width: 100vw;'></div>"];
+    EXPECT_WK_STREQ("20", bodyWidth());
+
+    [webView _overrideViewportWithArguments:@{ @"width" : @"1000" }];
+    EXPECT_WK_STREQ("1000", bodyWidth());
+
+    [webView _overrideViewportWithArguments:@{ @"width" : @"1000", @"initial-scale": @"1" }];
+    [webView waitForNextPresentationUpdate];
+    EXPECT_WK_STREQ("1000", bodyWidth());
+    EXPECT_EQ(1., [webView scrollView].zoomScale);
+
+    [webView _overrideViewportWithArguments:@{ @"width" : @"1000", @"initial-scale": @"5" }];
+    [webView waitForNextPresentationUpdate];
+    EXPECT_WK_STREQ("1000", bodyWidth());
+    EXPECT_EQ(5., [webView scrollView].zoomScale);
+
+    [webView _overrideViewportWithArguments:nil];
+    EXPECT_WK_STREQ("20", bodyWidth());
+
+    [webView synchronouslyLoadHTMLString:@"<meta name='viewport' content='width=10'><div id='divWithViewportUnits' style='width: 100vw;'></div>"];
+    EXPECT_WK_STREQ("10", bodyWidth());
+
+    [webView _overrideViewportWithArguments:@{ @"width" : @"1000", @"initial-scale": @"1" }];
+    EXPECT_WK_STREQ("1000", bodyWidth());
+
+    [webView _overrideViewportWithArguments:@{ @"width" : @"device-width", @"initial-scale": @"1" }];
+    EXPECT_WK_STREQ("20", bodyWidth());
+
+    [webView _overrideViewportWithArguments:@{ @"width" : @"500", @"initial-scale": @"1", @"garbage": @"nonsense" }];
+    EXPECT_WK_STREQ("500", bodyWidth());
+}
+
+#endif