Provide a viewport parameter to disable clipping to the safe area
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Apr 2017 20:24:14 +0000 (20:24 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Apr 2017 20:24:14 +0000 (20:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=170766
<rdar://problem/31564634>

Reviewed by Beth Dakin.

Tests: tiled-drawing/ios/viewport-clip-to-safe-area-no-gets-margin-tiles.html,
       tiled-drawing/ios/viewport-clip-to-safe-area-yes-gets-no-margin-tiles.html,

* dom/ViewportArguments.cpp:
(WebCore::ViewportArguments::resolve):
(WebCore::setViewportFeature):
* dom/ViewportArguments.h:
(WebCore::ViewportArguments::operator==):
* page/ViewportConfiguration.cpp:
(WebCore::ViewportConfiguration::updateConfiguration):
(WebCore::operator<<):
(WebCore::ViewportConfiguration::description):
* page/ViewportConfiguration.h:
(WebCore::ViewportConfiguration::Parameters::Parameters):
(WebCore::ViewportConfiguration::clipToSafeArea):
Add viewport parameter.

* page/ChromeClient.h:
* page/FrameView.h:
* page/FrameView.cpp:
(WebCore::FrameView::enableSpeculativeTilingIfNeeded):
If not clipping to the safe area, enable "speculative" tiling immediately,
because the margin tiles can be visible immediately.

(WebCore::FrameView::hasExtendedBackgroundRectForPainting):
(WebCore::FrameView::updateTilesForExtendedBackgroundMode):
Don't check the setting here; just respect the mode that is computed
by calculateExtendedBackgroundMode.

(WebCore::FrameView::calculateExtendedBackgroundMode):
If the viewport parameter was set, add margin tiles on both axes.

(WebCore::FrameView::setClipToSafeArea):
Notify ChromeClient of the change, and re-compute the margin tile mode.

* rendering/RenderLayerCompositor.h:
* rendering/RenderLayerCompositor.cpp:
Factor out code that decides whether the content layer clips to bounds,
and make it take the new viewport parameter into account.

* rendering/RenderObject.cpp:
Don't clip RenderView repaints to RenderView's GraphicsLayer bounds if
clip-to-safe-area is off, just like we do for slow-repaint objects in
extended background mode.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::resetState):
(WebKit::WebPageProxy::setClipToSafeArea):
* UIProcess/WebPageProxy.h:
(WebKit::WebPageProxy::clipToSafeArea):
* UIProcess/WebPageProxy.messages.in:
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::didChangeClipToSafeArea):
* WebProcess/WebCoreSupport/WebChromeClient.h:
* UIProcess/API/gtk/PageClientImpl.h:
* UIProcess/PageClient.h:
* UIProcess/ios/PageClientImplIOS.h:
* UIProcess/ios/PageClientImplIOS.mm:
(WebKit::PageClientImpl::didChangeClipToSafeArea):
* UIProcess/mac/PageClientImpl.h:
Forward clip-to-safe-area changes from ChromeClient to WKWebView.
Update visible content rects when it changes, which will
result in a call to updateFixedClippingView, as below.
Keep track of the current state in the UI process.

* UIProcess/API/Cocoa/WKWebViewPrivate.h:
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _contentMayDrawInObscuredInsets]):
Expose the current state of the clip-to-safe-area bit as SPI.

* UIProcess/ios/WKContentView.mm:
(-[WKContentView updateFixedClippingView:]):
Disable fixed clipping when clip-to-safe-area is disabled.

* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::viewportConfigurationChanged):
Push the viewport's clip-to-safe-area bit onto the main frame's FrameView.

* DumpRenderTree/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::setObscuredInsets):
* TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
* TestRunnerShared/UIScriptContext/UIScriptController.cpp:
(WTR::UIScriptController::setObscuredInsets):
* TestRunnerShared/UIScriptContext/UIScriptController.h:
* WebKitTestRunner/ios/TestControllerIOS.mm:
(WTR::TestController::platformResetStateToConsistentValues):
* WebKitTestRunner/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::setObscuredInsets):
Add a UIScriptController mechanism to install obscured insets
on the web view.

* tiled-drawing/ios/viewport-clip-to-safe-area-no-gets-margin-tiles-expected.txt: Added.
* tiled-drawing/ios/viewport-clip-to-safe-area-no-gets-margin-tiles.html: Added.
* tiled-drawing/ios/viewport-clip-to-safe-area-yes-gets-no-margin-tiles-expected.txt: Added.
* tiled-drawing/ios/viewport-clip-to-safe-area-yes-gets-no-margin-tiles.html: Added.

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

38 files changed:
LayoutTests/ChangeLog
LayoutTests/tiled-drawing/ios/viewport-clip-to-safe-area-no-gets-margin-tiles-expected.txt [new file with mode: 0644]
LayoutTests/tiled-drawing/ios/viewport-clip-to-safe-area-no-gets-margin-tiles.html [new file with mode: 0644]
LayoutTests/tiled-drawing/ios/viewport-clip-to-safe-area-yes-gets-no-margin-tiles-expected.txt [new file with mode: 0644]
LayoutTests/tiled-drawing/ios/viewport-clip-to-safe-area-yes-gets-no-margin-tiles.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/ViewportArguments.cpp
Source/WebCore/dom/ViewportArguments.h
Source/WebCore/page/ChromeClient.h
Source/WebCore/page/FrameView.cpp
Source/WebCore/page/FrameView.h
Source/WebCore/page/ViewportConfiguration.cpp
Source/WebCore/page/ViewportConfiguration.h
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/rendering/RenderLayerCompositor.h
Source/WebCore/rendering/RenderObject.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h
Source/WebKit2/UIProcess/API/gtk/PageClientImpl.h
Source/WebKit2/UIProcess/PageClient.h
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/WebPageProxy.messages.in
Source/WebKit2/UIProcess/ios/PageClientImplIOS.h
Source/WebKit2/UIProcess/ios/PageClientImplIOS.mm
Source/WebKit2/UIProcess/ios/WKContentView.mm
Source/WebKit2/UIProcess/mac/PageClientImpl.h
Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.cpp
Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.h
Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm
Tools/ChangeLog
Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm
Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl
Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp
Tools/TestRunnerShared/UIScriptContext/UIScriptController.h
Tools/WebKitTestRunner/ios/TestControllerIOS.mm
Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm

index 4f69d54..2da13c3 100644 (file)
@@ -1,3 +1,16 @@
+2017-04-17  Tim Horton  <timothy_horton@apple.com>
+
+        Provide a viewport parameter to disable clipping to the safe area
+        https://bugs.webkit.org/show_bug.cgi?id=170766
+        <rdar://problem/31564634>
+
+        Reviewed by Beth Dakin.
+
+        * tiled-drawing/ios/viewport-clip-to-safe-area-no-gets-margin-tiles-expected.txt: Added.
+        * tiled-drawing/ios/viewport-clip-to-safe-area-no-gets-margin-tiles.html: Added.
+        * tiled-drawing/ios/viewport-clip-to-safe-area-yes-gets-no-margin-tiles-expected.txt: Added.
+        * tiled-drawing/ios/viewport-clip-to-safe-area-yes-gets-no-margin-tiles.html: Added.
+
 2017-04-14  Jiewen Tan  <jiewen_tan@apple.com>
 
         [WebCrypto] Add support for ECDSA
diff --git a/LayoutTests/tiled-drawing/ios/viewport-clip-to-safe-area-no-gets-margin-tiles-expected.txt b/LayoutTests/tiled-drawing/ios/viewport-clip-to-safe-area-no-gets-margin-tiles-expected.txt
new file mode 100644 (file)
index 0000000..f750bd3
--- /dev/null
@@ -0,0 +1,23 @@
+(GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 320.00 548.00)
+  (visible rect 0.00, 0.00 280.00 x 538.00)
+  (coverage rect -40.00, -10.00 320.00 x 548.00)
+  (intersects coverage rect 1)
+  (contentsScale 2.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 320.00 548.00)
+      (contentsOpaque 1)
+      (visible rect 0.00, 0.00 280.00 x 538.00)
+      (coverage rect -40.00, -10.00 576.00 x 804.00)
+      (intersects coverage rect 1)
+      (contentsScale 2.00)
+      (tile cache coverage -512, -512 1344 x 1572)
+      (tile size 512 x 548)
+      (top left tile -1, -1 tiles grid 3 x 3)
+      (in window 1)
+    )
+  )
+)
+
diff --git a/LayoutTests/tiled-drawing/ios/viewport-clip-to-safe-area-no-gets-margin-tiles.html b/LayoutTests/tiled-drawing/ios/viewport-clip-to-safe-area-no-gets-margin-tiles.html
new file mode 100644 (file)
index 0000000..0aa5328
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1, clip-to-safe-area=no">
+    <script>
+        function getUIScript()
+        {
+            return `
+            (function() {
+                uiController.setObscuredInsets(10, 20, 30, 40);
+                uiController.immediateScrollToOffset(-40, -10);
+                uiController.doAfterVisibleContentRectUpdate(function () {
+                    uiController.uiScriptComplete();
+                })
+            })();`
+        }
+
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        function doTest()
+        {
+            testRunner.runUIScript(getUIScript(), function(result) {
+                if (window.internals) {
+                    document.getElementById('layers').innerText = internals.layerTreeAsText(document,
+                        internals.LAYER_TREE_INCLUDES_VISIBLE_RECTS | internals.LAYER_TREE_INCLUDES_TILE_CACHES);
+                }
+                
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            });
+        }
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+
+<body>
+<pre id="layers">Layer tree goes here</p>
+</body>
+</html>
diff --git a/LayoutTests/tiled-drawing/ios/viewport-clip-to-safe-area-yes-gets-no-margin-tiles-expected.txt b/LayoutTests/tiled-drawing/ios/viewport-clip-to-safe-area-yes-gets-no-margin-tiles-expected.txt
new file mode 100644 (file)
index 0000000..7547c95
--- /dev/null
@@ -0,0 +1,23 @@
+(GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 320.00 548.00)
+  (visible rect 0.00, 0.00 280.00 x 538.00)
+  (coverage rect 0.00, 0.00 280.00 x 538.00)
+  (intersects coverage rect 1)
+  (contentsScale 2.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 320.00 548.00)
+      (contentsOpaque 1)
+      (visible rect 0.00, 0.00 280.00 x 538.00)
+      (coverage rect 0.00, 0.00 280.00 x 538.00)
+      (intersects coverage rect 1)
+      (contentsScale 2.00)
+      (tile cache coverage 0, 0 320 x 548)
+      (tile size 512 x 548)
+      (top left tile 0, 0 tiles grid 1 x 1)
+      (in window 1)
+    )
+  )
+)
+
diff --git a/LayoutTests/tiled-drawing/ios/viewport-clip-to-safe-area-yes-gets-no-margin-tiles.html b/LayoutTests/tiled-drawing/ios/viewport-clip-to-safe-area-yes-gets-no-margin-tiles.html
new file mode 100644 (file)
index 0000000..16d195a
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1, clip-to-safe-area=yes">
+    <script>
+        function getUIScript()
+        {
+            return `
+            (function() {
+                uiController.setObscuredInsets(10, 20, 30, 40);
+                uiController.immediateScrollToOffset(-40, -10);
+                uiController.doAfterVisibleContentRectUpdate(function () {
+                    uiController.uiScriptComplete();
+                })
+            })();`
+        }
+
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        function doTest()
+        {
+            testRunner.runUIScript(getUIScript(), function(result) {
+                if (window.internals) {
+                    document.getElementById('layers').innerText = internals.layerTreeAsText(document,
+                        internals.LAYER_TREE_INCLUDES_VISIBLE_RECTS | internals.LAYER_TREE_INCLUDES_TILE_CACHES);
+                }
+                
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            });
+        }
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+
+<body>
+<pre id="layers">Layer tree goes here</p>
+</body>
+</html>
index e06bf9c..25db5e4 100644 (file)
@@ -1,3 +1,56 @@
+2017-04-17  Tim Horton  <timothy_horton@apple.com>
+
+        Provide a viewport parameter to disable clipping to the safe area
+        https://bugs.webkit.org/show_bug.cgi?id=170766
+        <rdar://problem/31564634>
+
+        Reviewed by Beth Dakin.
+
+        Tests: tiled-drawing/ios/viewport-clip-to-safe-area-no-gets-margin-tiles.html,
+               tiled-drawing/ios/viewport-clip-to-safe-area-yes-gets-no-margin-tiles.html,
+
+        * dom/ViewportArguments.cpp:
+        (WebCore::ViewportArguments::resolve):
+        (WebCore::setViewportFeature):
+        * dom/ViewportArguments.h:
+        (WebCore::ViewportArguments::operator==):
+        * page/ViewportConfiguration.cpp:
+        (WebCore::ViewportConfiguration::updateConfiguration):
+        (WebCore::operator<<):
+        (WebCore::ViewportConfiguration::description):
+        * page/ViewportConfiguration.h:
+        (WebCore::ViewportConfiguration::Parameters::Parameters):
+        (WebCore::ViewportConfiguration::clipToSafeArea):
+        Add viewport parameter.
+
+        * page/ChromeClient.h:
+        * page/FrameView.h:
+        * page/FrameView.cpp:
+        (WebCore::FrameView::enableSpeculativeTilingIfNeeded):
+        If not clipping to the safe area, enable "speculative" tiling immediately,
+        because the margin tiles can be visible immediately.
+
+        (WebCore::FrameView::hasExtendedBackgroundRectForPainting):
+        (WebCore::FrameView::updateTilesForExtendedBackgroundMode):
+        Don't check the setting here; just respect the mode that is computed
+        by calculateExtendedBackgroundMode.
+
+        (WebCore::FrameView::calculateExtendedBackgroundMode):
+        If the viewport parameter was set, add margin tiles on both axes.
+
+        (WebCore::FrameView::setClipToSafeArea):
+        Notify ChromeClient of the change, and re-compute the margin tile mode.
+
+        * rendering/RenderLayerCompositor.h:
+        * rendering/RenderLayerCompositor.cpp:
+        Factor out code that decides whether the content layer clips to bounds,
+        and make it take the new viewport parameter into account.
+
+        * rendering/RenderObject.cpp:
+        Don't clip RenderView repaints to RenderView's GraphicsLayer bounds if
+        clip-to-safe-area is off, just like we do for slow-repaint objects in
+        extended background mode.
+
 2017-04-17  Dan Bernstein  <mitz@apple.com>
 
         [Cocoa] Move isNullFunctionPointer down into WTF
index 1e69b92..c00dd90 100644 (file)
@@ -246,6 +246,7 @@ ViewportAttributes ViewportArguments::resolve(const FloatSize& initialViewportSi
     result.userScalable = userZoom;
     result.orientation = orientation;
     result.shrinkToFit = shrinkToFit;
+    result.clipToSafeArea = clipToSafeArea;
 
     return result;
 }
@@ -363,22 +364,21 @@ static float findScaleValue(Document& document, StringView key, StringView value
     return numericValue;
 }
 
-// FIXME: It's kind of bizarre to use floating point values of 1 and 0 to represent true and false.
-static float findBooleanValue(Document& document, StringView key, StringView value)
+static bool findBooleanValue(Document& document, StringView key, StringView value)
 {
     // yes and no are used as keywords.
     // Numbers >= 1, numbers <= -1, device-width and device-height are mapped to yes.
     // Numbers in the range <-1, 1>, and unknown values, are mapped to no.
 
     if (equalLettersIgnoringASCIICase(value, "yes"))
-        return 1;
+        return true;
     if (equalLettersIgnoringASCIICase(value, "no"))
-        return 0;
+        return false;
     if (equalLettersIgnoringASCIICase(value, "device-width"))
-        return 1;
+        return true;
     if (equalLettersIgnoringASCIICase(value, "device-height"))
-        return 1;
-    return std::abs(numericPrefix(document, key, value)) >= 1 ? 1 : 0;
+        return true;
+    return std::abs(numericPrefix(document, key, value)) >= 1;
 }
 
 void setViewportFeature(ViewportArguments& arguments, Document& document, StringView key, StringView value)
@@ -403,6 +403,8 @@ void setViewportFeature(ViewportArguments& arguments, Document& document, String
 #endif
     else if (equalLettersIgnoringASCIICase(key, "shrink-to-fit"))
         arguments.shrinkToFit = findBooleanValue(document, key, value);
+    else if (equalLettersIgnoringASCIICase(key, "clip-to-safe-area"))
+        arguments.clipToSafeArea = findBooleanValue(document, key, value);
     else
         reportViewportWarning(document, UnrecognizedViewportArgumentKeyError, key);
 }
index 4e6907f..1e8cc23 100644 (file)
@@ -51,6 +51,7 @@ struct ViewportAttributes {
     float userScalable;
     float orientation;
     float shrinkToFit;
+    bool clipToSafeArea;
 };
 
 struct ViewportArguments {
@@ -94,6 +95,7 @@ struct ViewportArguments {
     float userZoom { ValueAuto };
     float orientation { ValueAuto };
     float shrinkToFit { ValueAuto };
+    bool clipToSafeArea { true };
     bool widthWasExplicit { false };
 
     bool operator==(const ViewportArguments& other) const
@@ -112,6 +114,7 @@ struct ViewportArguments {
             && userZoom == other.userZoom
             && orientation == other.orientation
             && shrinkToFit == other.shrinkToFit
+            && clipToSafeArea == other.clipToSafeArea
             && widthWasExplicit == other.widthWasExplicit;
     }
 
index 8480d91..b6fdc9a 100644 (file)
@@ -468,6 +468,8 @@ public:
     virtual void reportProcessCPUTime(int64_t, ActivityStateForCPUSampling) { }
     virtual RefPtr<Icon> createIconForFiles(const Vector<String>& /* filenames */) = 0;
 
+    virtual void didChangeClipToSafeArea(bool) { }
+
 protected:
     virtual ~ChromeClient() { }
 };
index 148084b..368c6cd 100644 (file)
@@ -2929,6 +2929,10 @@ void FrameView::enableSpeculativeTilingIfNeeded()
         m_speculativeTilingEnabled = true;
         return;
     }
+    if (!m_clipToSafeArea) {
+        m_speculativeTilingEnabled = true;
+        return;
+    }
     if (!shouldEnableSpeculativeTilingDuringLoading(*this))
         return;
 
@@ -3238,9 +3242,6 @@ void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool t
 
 bool FrameView::hasExtendedBackgroundRectForPainting() const
 {
-    if (!frame().settings().backgroundShouldExtendBeyondPage())
-        return false;
-
     TiledBacking* tiledBacking = this->tiledBacking();
     if (!tiledBacking)
         return false;
@@ -3259,11 +3260,8 @@ void FrameView::updateExtendBackgroundIfNecessary()
 
 FrameView::ExtendedBackgroundMode FrameView::calculateExtendedBackgroundMode() const
 {
-    // Just because Settings::backgroundShouldExtendBeyondPage() is true does not necessarily mean
-    // that the background rect needs to be extended for painting. Simple backgrounds can be extended
-    // just with RenderLayerCompositor::setRootExtendedBackgroundColor(). More complicated backgrounds,
-    // such as images, require extending the background rect to continue painting into the extended
-    // region. This function finds out if it is necessary to extend the background rect for painting.
+    if (!m_clipToSafeArea)
+        return ExtendedBackgroundModeAll;
 
 #if PLATFORM(IOS)
     // <rdar://problem/16201373>
@@ -3272,6 +3270,12 @@ FrameView::ExtendedBackgroundMode FrameView::calculateExtendedBackgroundMode() c
     if (!frame().settings().backgroundShouldExtendBeyondPage())
         return ExtendedBackgroundModeNone;
 
+    // Just because Settings::backgroundShouldExtendBeyondPage() is true does not necessarily mean
+    // that the background rect needs to be extended for painting. Simple backgrounds can be extended
+    // just with RenderLayerCompositor::setRootExtendedBackgroundColor(). More complicated backgrounds,
+    // such as images, require extending the background rect to continue painting into the extended
+    // region. This function finds out if it is necessary to extend the background rect for painting.
+
     if (!frame().isMainFrame())
         return ExtendedBackgroundModeNone;
 
@@ -3301,9 +3305,6 @@ FrameView::ExtendedBackgroundMode FrameView::calculateExtendedBackgroundMode() c
 
 void FrameView::updateTilesForExtendedBackgroundMode(ExtendedBackgroundMode mode)
 {
-    if (!frame().settings().backgroundShouldExtendBeyondPage())
-        return;
-
     RenderView* renderView = this->renderView();
     if (!renderView)
         return;
@@ -3348,6 +3349,30 @@ IntRect FrameView::extendedBackgroundRectForPainting() const
     return snappedIntRect(extendedRect);
 }
 
+void FrameView::setClipToSafeArea(bool clipToSafeArea)
+{
+    if (!frame().isMainFrame())
+        return;
+
+    if (m_clipToSafeArea == clipToSafeArea)
+        return;
+
+    m_clipToSafeArea = clipToSafeArea;
+
+    if (Page* page = frame().page())
+        page->chrome().client().didChangeClipToSafeArea(clipToSafeArea);
+
+    updateExtendBackgroundIfNecessary();
+    adjustTiledBackingCoverage();
+
+    RenderView* renderView = this->renderView();
+    if (!renderView)
+        return;
+
+    RenderLayerCompositor& compositor = renderView->compositor();
+    compositor.updateRootContentLayerClipping();
+}
+
 bool FrameView::shouldUpdateWhileOffscreen() const
 {
     return m_shouldUpdateWhileOffscreen;
index b14fef3..0a32753 100644 (file)
@@ -213,6 +213,9 @@ public:
     bool hasExtendedBackgroundRectForPainting() const;
     IntRect extendedBackgroundRectForPainting() const;
 
+    bool clipToSafeArea() const { return m_clipToSafeArea; }
+    WEBCORE_EXPORT void setClipToSafeArea(bool);
+
     bool shouldUpdateWhileOffscreen() const;
     WEBCORE_EXPORT void setShouldUpdateWhileOffscreen(bool);
     bool shouldUpdate() const;
@@ -813,6 +816,8 @@ private:
 
     bool m_needsDeferredScrollbarsUpdate { false };
 
+    bool m_clipToSafeArea { true };
+
     RefPtr<ContainerNode> m_maintainScrollPositionAnchor;
 
     // Renderer to hold our custom scroll corner.
index 805c6e0..206f02b 100644 (file)
@@ -336,6 +336,9 @@ void ViewportConfiguration::updateConfiguration()
 
     if (booleanViewportArgumentIsSet(m_viewportArguments.shrinkToFit))
         m_configuration.allowsShrinkToFit = m_viewportArguments.shrinkToFit != 0.;
+
+    if (booleanViewportArgumentIsSet(m_viewportArguments.clipToSafeArea))
+        m_configuration.clipToSafeArea = m_viewportArguments.clipToSafeArea;
 }
 
 double ViewportConfiguration::viewportArgumentsLength(double length) const
@@ -439,6 +442,7 @@ TextStream& operator<<(TextStream& ts, const ViewportConfiguration::Parameters&
     ts.dumpProperty("maximumScale", parameters.maximumScale);
     ts.dumpProperty("allowsUserScaling", parameters.allowsUserScaling);
     ts.dumpProperty("allowsShrinkToFit", parameters.allowsShrinkToFit);
+    ts.dumpProperty("clipToSafeArea", parameters.clipToSafeArea);
 
     return ts;
 }
@@ -472,6 +476,7 @@ CString ViewportConfiguration::description() const
     ts.dumpProperty("computed layout size", layoutSize());
     ts.dumpProperty("ignoring horizontal scaling constraints", shouldIgnoreHorizontalScalingConstraints() ? "true" : "false");
     ts.dumpProperty("ignoring vertical scaling constraints", shouldIgnoreVerticalScalingConstraints() ? "true" : "false");
+    ts.dumpProperty("clip to safe area", clipToSafeArea() ? "true" : "false");
     
     ts.endGroup();
 
index b72c0bf..badd6e8 100644 (file)
@@ -50,6 +50,7 @@ public:
             , maximumScale(0)
             , allowsUserScaling(false)
             , allowsShrinkToFit(false)
+            , clipToSafeArea(true)
             , widthIsSet(false)
             , heightIsSet(false)
             , initialScaleIsSet(false)
@@ -63,6 +64,7 @@ public:
         double maximumScale;
         bool allowsUserScaling;
         bool allowsShrinkToFit;
+        bool clipToSafeArea;
 
         bool widthIsSet;
         bool heightIsSet;
@@ -95,6 +97,7 @@ public:
     WEBCORE_EXPORT bool allowsUserScaling() const;
     WEBCORE_EXPORT bool allowsUserScalingIgnoringAlwaysScalable() const;
     bool allowsShrinkToFit() const;
+    bool clipToSafeArea() const { return m_configuration.clipToSafeArea; }
 
     WEBCORE_EXPORT static Parameters webpageParameters();
     WEBCORE_EXPORT static Parameters textDocumentParameters();
index 184567e..be0ebdd 100644 (file)
@@ -976,6 +976,11 @@ static RenderLayerModelObject& rendererForCompositingTests(const RenderLayer& la
     return *renderer;
 }
 
+void RenderLayerCompositor::updateRootContentLayerClipping()
+{
+    m_rootContentLayer->setMasksToBounds(!m_renderView.settings().backgroundShouldExtendBeyondPage() && m_renderView.frameView().clipToSafeArea());
+}
+
 bool RenderLayerCompositor::updateBacking(RenderLayer& layer, CompositingChangeRepaint shouldRepaint, BackingRequired backingRequired)
 {
     bool layerChanged = false;
@@ -1007,8 +1012,7 @@ bool RenderLayerCompositor::updateBacking(RenderLayer& layer, CompositingChangeR
                 updateLayerForHeader(page().headerHeight());
                 updateLayerForFooter(page().footerHeight());
 #endif
-                if (m_renderView.settings().backgroundShouldExtendBeyondPage())
-                    m_rootContentLayer->setMasksToBounds(false);
+                updateRootContentLayerClipping();
 
                 if (TiledBacking* tiledBacking = layer.backing()->tiledBacking())
                     tiledBacking->setTopContentInset(m_renderView.frameView().topContentInset());
@@ -3382,7 +3386,7 @@ void RenderLayerCompositor::ensureRootLayer()
 #endif
 
         // Need to clip to prevent transformed content showing outside this frame
-        m_rootContentLayer->setMasksToBounds(true);
+        updateRootContentLayerClipping();
     }
 
     if (requiresScrollLayer(expectedAttachment)) {
index 828ae9d..8afcd5d 100644 (file)
@@ -313,6 +313,8 @@ public:
     void setRootExtendedBackgroundColor(const Color&);
     const Color& rootExtendedBackgroundColor() const { return m_rootExtendedBackgroundColor; }
 
+    void updateRootContentLayerClipping();
+
 #if ENABLE(CSS_SCROLL_SNAP)
     void updateScrollSnapPropertiesWithFrameView(const FrameView&);
 #endif
index 1169d92..05e8bb1 100644 (file)
@@ -897,6 +897,9 @@ void RenderObject::repaintUsingContainer(const RenderLayerModelObject* repaintCo
             view.repaintViewRectangle(rect);
             return;
         }
+
+        if (!view.frameView().clipToSafeArea())
+            shouldClipToLayer = false;
     }
 
     if (view().usesCompositing()) {
index 8697067..5ca7fe0 100644 (file)
@@ -1,3 +1,44 @@
+2017-04-17  Tim Horton  <timothy_horton@apple.com>
+
+        Provide a viewport parameter to disable clipping to the safe area
+        https://bugs.webkit.org/show_bug.cgi?id=170766
+        <rdar://problem/31564634>
+
+        Reviewed by Beth Dakin.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::resetState):
+        (WebKit::WebPageProxy::setClipToSafeArea):
+        * UIProcess/WebPageProxy.h:
+        (WebKit::WebPageProxy::clipToSafeArea):
+        * UIProcess/WebPageProxy.messages.in:
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::didChangeClipToSafeArea):
+        * WebProcess/WebCoreSupport/WebChromeClient.h:
+        * UIProcess/API/gtk/PageClientImpl.h:
+        * UIProcess/PageClient.h:
+        * UIProcess/ios/PageClientImplIOS.h:
+        * UIProcess/ios/PageClientImplIOS.mm:
+        (WebKit::PageClientImpl::didChangeClipToSafeArea):
+        * UIProcess/mac/PageClientImpl.h:
+        Forward clip-to-safe-area changes from ChromeClient to WKWebView.
+        Update visible content rects when it changes, which will
+        result in a call to updateFixedClippingView, as below.
+        Keep track of the current state in the UI process.
+
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _contentMayDrawInObscuredInsets]):
+        Expose the current state of the clip-to-safe-area bit as SPI.
+
+        * UIProcess/ios/WKContentView.mm:
+        (-[WKContentView updateFixedClippingView:]):
+        Disable fixed clipping when clip-to-safe-area is disabled.
+        
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::viewportConfigurationChanged):
+        Push the viewport's clip-to-safe-area bit onto the main frame's FrameView.
+
 2017-04-17  Dan Bernstein  <mitz@apple.com>
 
         [Cocoa] Move isNullFunctionPointer down into WTF
index e3f3118..9a46bd1 100644 (file)
@@ -4260,6 +4260,11 @@ static inline WebKit::FindOptions toFindOptions(_WKFindOptions wkFindOptions)
     return _page->isShowingNavigationGestureSnapshot();
 }
 
+- (BOOL)_contentMayDrawInObscuredInsets
+{
+    return !_page->clipToSafeArea();
+}
+
 - (_WKLayoutMode)_layoutMode
 {
 #if PLATFORM(MAC)
index 2bb1509..d0e5fc0 100644 (file)
@@ -150,6 +150,8 @@ typedef NS_ENUM(NSInteger, _WKImmediateActionType) {
 // Define the inset of the scrollview unusable by the web page.
 @property (nonatomic, setter=_setObscuredInsets:) UIEdgeInsets _obscuredInsets;
 
+@property (nonatomic, readonly) BOOL _contentMayDrawInObscuredInsets;
+
 // Override the interface orientation. Clients using _beginAnimatedResizeWithUpdates: must update the interface orientation
 // in the update block.
 @property (nonatomic, setter=_setInterfaceOrientationOverride:) UIInterfaceOrientation _interfaceOrientationOverride;
index 8c5776f..add3f66 100644 (file)
@@ -146,6 +146,8 @@ private:
 
     WebCore::UserInterfaceLayoutDirection userInterfaceLayoutDirection() override { return WebCore::UserInterfaceLayoutDirection::LTR; }
 
+    void didChangeClipToSafeArea(bool) override { }
+
     // Members of PageClientImpl class
     GtkWidget* m_viewWidget;
     DefaultUndoController m_undoController;
index b56debf..0ddfd46 100644 (file)
@@ -386,6 +386,8 @@ public:
     virtual void didConcludeEditDataInteraction(std::optional<WebCore::TextIndicatorData>) = 0;
     virtual void didChangeDataInteractionCaretRect(const WebCore::IntRect& previousCaretRect, const WebCore::IntRect& caretRect) = 0;
 #endif
+
+    virtual void didChangeClipToSafeArea(bool clipToSafeArea) = 0;
 };
 
 } // namespace WebKit
index d77d407..c883358 100644 (file)
@@ -5455,6 +5455,8 @@ void WebPageProxy::resetState(ResetStateReason resetStateReason)
 #if ENABLE(POINTER_LOCK)
     requestPointerUnlock();
 #endif
+
+    m_clipToSafeArea = true;
 }
 
 void WebPageProxy::resetStateAfterProcessExited()
@@ -6880,4 +6882,11 @@ void WebPageProxy::stopURLSchemeHandlerTask(uint64_t handlerIdentifier, uint64_t
     iterator->value->stopTask(*this, resourceIdentifier);
 }
 
+void WebPageProxy::setClipToSafeArea(bool clipToSafeArea)
+{
+    m_clipToSafeArea = clipToSafeArea;
+
+    m_pageClient.didChangeClipToSafeArea(clipToSafeArea);
+}
+
 } // namespace WebKit
index b1cb846..27cdffd 100644 (file)
@@ -1195,6 +1195,9 @@ public:
     void createSandboxExtensionsIfNeeded(const Vector<String>& files, SandboxExtension::Handle& fileReadHandle, SandboxExtension::HandleArray& fileUploadHandles);
 #endif
 
+    void setClipToSafeArea(bool);
+    bool clipToSafeArea() const { return m_clipToSafeArea; }
+
 private:
     WebPageProxy(PageClient&, WebProcessProxy&, uint64_t pageID, Ref<API::PageConfiguration>&&);
     void platformInitialize();
@@ -1980,7 +1983,9 @@ private:
 #endif
 
     bool m_isUsingHighPerformanceWebGL { false };
-        
+
+    bool m_clipToSafeArea { true };
+
     WeakPtrFactory<WebPageProxy> m_weakPtrFactory;
 
     HashMap<String, Ref<WebURLSchemeHandler>> m_urlSchemeHandlersByScheme;
index f6c54c7..845d430 100644 (file)
@@ -494,4 +494,6 @@ messages -> WebPageProxy {
 
     StartURLSchemeHandlerTask(uint64_t loaderIdentifier, uint64_t resourceIdentifier, WebCore::ResourceRequest request)
     StopURLSchemeHandlerTask(uint64_t loaderIdentifier, uint64_t resourceIdentifier)
+
+    SetClipToSafeArea(bool clipToSafeArea)
 }
index 521e1dd..691426d 100644 (file)
@@ -198,6 +198,8 @@ private:
 
     void handleActiveNowPlayingSessionInfoResponse(bool hasActiveSession, const String& title, double duration, double elapsedTime) override;
 
+    void didChangeClipToSafeArea(bool clipToSafeArea) override;
+
 #if USE(QUICK_LOOK)
     void requestPasswordForQuickLookDocument(const String& fileName, std::function<void(const String&)>&&) override;
 #endif
index b96cd2e..d8d5bb0 100644 (file)
@@ -821,6 +821,11 @@ void PageClientImpl::requestPasswordForQuickLookDocument(const String& fileName,
 }
 #endif
 
+void PageClientImpl::didChangeClipToSafeArea(bool clipToSafeArea)
+{
+    [m_webView _scheduleVisibleContentRectUpdate];
+}
+
 } // namespace WebKit
 
 #endif // PLATFORM(IOS)
index d7c6392..75f718b 100644 (file)
@@ -360,6 +360,7 @@ private:
 
     [_fixedClippingView setCenter:clippingBounds.location()]; // Not really the center since we set an anchor point.
     [_fixedClippingView setBounds:clippingBounds];
+    [_fixedClippingView layer].masksToBounds = _page->clipToSafeArea();
 }
 
 - (void)_didExitStableState
index 3cb6ca8..0f8e7e3 100644 (file)
@@ -251,6 +251,8 @@ private:
 
     void didRestoreScrollPosition() override;
     bool windowIsFrontWindowUnderMouse(const NativeWebMouseEvent&) override;
+
+    void didChangeClipToSafeArea(bool clipToSafeArea) override { }
 };
 
 } // namespace WebKit
index 98a5f88..3593d90 100644 (file)
@@ -1227,4 +1227,9 @@ void WebChromeClient::didInvalidateDocumentMarkerRects()
     m_page.findController().didInvalidateDocumentMarkerRects();
 }
 
+void WebChromeClient::didChangeClipToSafeArea(bool clipToSafeArea)
+{
+    m_page.send(Messages::WebPageProxy::SetClipToSafeArea(clipToSafeArea));
+}
+
 } // namespace WebKit
index 73f9cc2..576cd79 100644 (file)
@@ -342,6 +342,8 @@ private:
 
     void didInvalidateDocumentMarkerRects() final;
 
+    void didChangeClipToSafeArea(bool) final;
+
     String m_cachedToolTip;
     mutable RefPtr<WebFrame> m_cachedFrameSetLargestFrame;
     mutable bool m_cachedMainFrameHasHorizontalScrollbar { false };
index 0ac7b83..4b135d0 100644 (file)
@@ -3045,6 +3045,8 @@ void WebPage::viewportConfigurationChanged()
     updateViewportSizeForCSSViewportUnits();
 
     FrameView& frameView = *mainFrameView();
+    frameView.setClipToSafeArea(m_viewportConfiguration.clipToSafeArea());
+
     IntPoint scrollPosition = frameView.scrollPosition();
     if (!m_hasReceivedVisibleContentRectsAfterDidCommitLoad) {
         FloatSize minimumLayoutSizeInScrollViewCoordinates = m_viewportConfiguration.minimumLayoutSize();
index ab8b832..cc9a783 100644 (file)
@@ -1,3 +1,24 @@
+2017-04-17  Tim Horton  <timothy_horton@apple.com>
+
+        Provide a viewport parameter to disable clipping to the safe area
+        https://bugs.webkit.org/show_bug.cgi?id=170766
+        <rdar://problem/31564634>
+
+        Reviewed by Beth Dakin.
+
+        * DumpRenderTree/ios/UIScriptControllerIOS.mm:
+        (WTR::UIScriptController::setObscuredInsets):
+        * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
+        * TestRunnerShared/UIScriptContext/UIScriptController.cpp:
+        (WTR::UIScriptController::setObscuredInsets):
+        * TestRunnerShared/UIScriptContext/UIScriptController.h:
+        * WebKitTestRunner/ios/TestControllerIOS.mm:
+        (WTR::TestController::platformResetStateToConsistentValues):
+        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+        (WTR::UIScriptController::setObscuredInsets):
+        Add a UIScriptController mechanism to install obscured insets
+        on the web view.
+
 2017-04-17  Dan Bernstein  <mitz@apple.com>
 
         [Cocoa] Move isNullFunctionPointer down into WTF
index 403b59b..b0e04dd 100644 (file)
@@ -316,6 +316,10 @@ void UIScriptController::addViewToWindow(JSValueRef)
 {
 }
 
+void UIScriptController::setObscuredInsets(double, double, double, double)
+{
+}
+
 }
 
 #endif // PLATFORM(IOS)
index f66ae15..dba456e 100644 (file)
@@ -232,4 +232,6 @@ interface UIScriptController {
     void addViewToWindow(object callback);
 
     void overridePreference(DOMString preference, DOMString value);
+
+    void setObscuredInsets(double top, double right, double bottom, double left);
 };
index 612c9e2..0f1fcc1 100644 (file)
@@ -399,6 +399,10 @@ JSRetainPtr<JSStringRef> UIScriptController::accessibilitySpeakSelectionContent(
     return nullptr;
 }
 
+void UIScriptController::setObscuredInsets(double top, double right, double bottom, double left)
+{
+}
+
 #endif
 
 #if !PLATFORM(COCOA)
index 46c28b1..6627388 100644 (file)
@@ -156,6 +156,8 @@ public:
     void removeViewFromWindow(JSValueRef);
     void addViewToWindow(JSValueRef);
 
+    void setObscuredInsets(double top, double right, double bottom, double left);
+
 private:
     UIScriptController(UIScriptContext&);
     
index 7c351f8..a0d112f 100644 (file)
@@ -85,6 +85,9 @@ void TestController::platformResetStateToConsistentValues()
         [scrollView _removeAllAnimations:YES];
         [scrollView setZoomScale:1 animated:NO];
         [scrollView setContentOffset:CGPointZero];
+
+        scrollView.contentInset = UIEdgeInsetsZero;
+        webView->platformView()._obscuredInsets = UIEdgeInsetsZero;
     }
 }
 
index ce67f5e..57a1954 100644 (file)
@@ -668,6 +668,14 @@ void UIScriptController::platformClearAllCallbacks()
     webView.didEndScrollingCallback = nil;
 }
 
+void UIScriptController::setObscuredInsets(double top, double right, double bottom, double left)
+{
+    UIEdgeInsets insets = UIEdgeInsetsMake(top, left, bottom, right);
+    TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
+    webView.scrollView.contentInset = insets;
+    webView._obscuredInsets = insets;
+}
+
 }
 
 #endif // PLATFORM(IOS)