Implement contentInset for Mac WebKit2
authorbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Mar 2014 23:19:04 +0000 (23:19 +0000)
committerbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Mar 2014 23:19:04 +0000 (23:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=130273

Reviewed by Simon Fraser.

Source/WebCore:

This patch adds support for topContentInset(). If a page has a topContentInset(),
the root layer’s position is adjusted to account for the inset. It is assumed that
the area accounted for by the inset is visible but obscured, so scrollbars need to
be moved so that they only cover the non-obscured area, and most parts of WebCore
that wonder about visibleContentSize only care about the unobscured area, so this
patch makes that visibleContentRect return the unobscuredRect. Finally since this
is achieved by moving a layer’s position, the topContentInset() also needs to be
factored into various functions that are used to convert between coordinate
spaces.

Return Page::topContentInset() if this is the main frame.
* page/FrameView.cpp:
(WebCore::FrameView::topContentInset):
* page/FrameView.h:

Cache the inset on Page.
* page/Page.cpp:
(WebCore::Page::Page):
* page/Page.h:
(WebCore::Page::topContentInset):
(WebCore::Page::setTopContentInset):

unobscuredContentRect() used to unconditionally return visibleContentRect() on
non-iOS platforms. Now that it is possible for some technically visible content to
be obscured, this code needed to be re-worked a bit to make some more sense.
visibleContentRect() now represents that visible content that is completely
unobscured, so it should call into unobscuredContentRect() rather than the other
way around.
* platform/ScrollView.cpp:
(WebCore::ScrollView::unobscuredContentRect):

unscaledTotalVisibleContentSize() includes the size of all content that might be
visible. Some of this content might be obscured.
(WebCore::ScrollView::unscaledTotalVisibleContentSize):

Most of the time, we only care about the content that is FULLY visible. That is
what you get from unscaledUnobscuredVisibleContentSize().
(WebCore::ScrollView::unscaledUnobscuredVisibleContentSize):

Use the unobscured size for these computations.
(WebCore::ScrollView::visibleContentRectInternal):
(WebCore::ScrollView::layoutSize):

Factor in the topContentInset().
(WebCore::ScrollView::scrollOffsetRelativeToDocument):
(WebCore::ScrollView::scrollPositionRelativeToDocument):

The scrollbars should be positioned to cover the non-obscured content only.
(WebCore::ScrollView::updateScrollbars):

Again, factor the topContentInset() into these conversions since the root layer’s
position has been adjusted to account for it.
(WebCore::ScrollView::contentsToRootView):
(WebCore::ScrollView::contentsToWindow):

 Just like the scrollbars, the scroll corner must be moved the account for the
inset.
(WebCore::ScrollView::scrollCornerRect):
* platform/ScrollView.h:
(WebCore::ScrollView::topContentInset):

RenderLayerCompositor cares about unscaledTotalVisibleContentSize(). It does not
care if some of that content is obscured.
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::frameViewDidChangeSize):

Move the root layer’s position based on the contentInset.
(WebCore::RenderLayerCompositor::updateRootLayerPosition):
(WebCore::RenderLayerCompositor::ensureRootLayer):

Allow setting contentInset via Internals for testing purposes.
* testing/Internals.cpp:
(WebCore::Internals::setTopContentInset):
* testing/Internals.h:
* testing/Internals.idl:

Source/WebKit2:

This patch adds WKView API for setting a topContentInset(). All of this work gets
that number plumbed down to WebCore.

* Shared/WebPageCreationParameters.cpp:
(WebKit::WebPageCreationParameters::encode):
(WebKit::WebPageCreationParameters::decode):
* Shared/WebPageCreationParameters.h:
* UIProcess/API/Cocoa/WKViewPrivate.h:
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _setTopContentInset:]):
(-[WKWebView _topContentInset]):
* UIProcess/API/Cocoa/WKWebViewPrivate.h:
* UIProcess/API/mac/WKView.mm:
(-[WKView _setTopContentInset:]):
(-[WKView _topContentInset]):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::WebPageProxy):
(WebKit::WebPageProxy::setTopContentInset):
(WebKit::WebPageProxy::creationParameters):
* UIProcess/WebPageProxy.h:
(WebKit::WebPageProxy::topContentInset):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::WebPage):
(WebKit::WebPage::setTopContentInset):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

LayoutTests:

Add two tests for hit-testing with a topContentInset.

* platform/mac-wk2/tiled-drawing/content-inset-hit-testing-expected.txt: Added.
* platform/mac-wk2/tiled-drawing/content-inset-hit-testing-in-frame-expected.txt: Added.
* platform/mac-wk2/tiled-drawing/content-inset-hit-testing-in-frame.html: Added.
* platform/mac-wk2/tiled-drawing/content-inset-hit-testing.html: Added.

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

29 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac-wk2/tiled-drawing/content-inset-hit-testing-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/content-inset-hit-testing-in-frame-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/content-inset-hit-testing-in-frame.html [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/content-inset-hit-testing.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebCore/page/FrameView.cpp
Source/WebCore/page/FrameView.h
Source/WebCore/page/Page.cpp
Source/WebCore/page/Page.h
Source/WebCore/platform/ScrollView.cpp
Source/WebCore/platform/ScrollView.h
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/WebPageCreationParameters.cpp
Source/WebKit2/Shared/WebPageCreationParameters.h
Source/WebKit2/UIProcess/API/Cocoa/WKViewPrivate.h
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h
Source/WebKit2/UIProcess/API/mac/WKView.mm
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/WebPage.messages.in

index ba162c9..76dcf87 100644 (file)
@@ -1,3 +1,17 @@
+2014-03-20  Beth Dakin  <bdakin@apple.com>
+
+        Implement contentInset for Mac WebKit2
+        https://bugs.webkit.org/show_bug.cgi?id=130273
+
+        Reviewed by Simon Fraser.
+
+        Add two tests for hit-testing with a topContentInset.
+
+        * platform/mac-wk2/tiled-drawing/content-inset-hit-testing-expected.txt: Added.
+        * platform/mac-wk2/tiled-drawing/content-inset-hit-testing-in-frame-expected.txt: Added.
+        * platform/mac-wk2/tiled-drawing/content-inset-hit-testing-in-frame.html: Added.
+        * platform/mac-wk2/tiled-drawing/content-inset-hit-testing.html: Added.
+
 2014-03-20  Brent Fulgham  <bfulgham@apple.com>
 
         Add a flushing mechanism for the WebVTTParser
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/content-inset-hit-testing-expected.txt b/LayoutTests/platform/mac-wk2/tiled-drawing/content-inset-hit-testing-expected.txt
new file mode 100644 (file)
index 0000000..c3a50ff
--- /dev/null
@@ -0,0 +1 @@
+Pass!
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/content-inset-hit-testing-in-frame-expected.txt b/LayoutTests/platform/mac-wk2/tiled-drawing/content-inset-hit-testing-in-frame-expected.txt
new file mode 100644 (file)
index 0000000..ac137d2
--- /dev/null
@@ -0,0 +1,2 @@
+
+Pass!
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/content-inset-hit-testing-in-frame.html b/LayoutTests/platform/mac-wk2/tiled-drawing/content-inset-hit-testing-in-frame.html
new file mode 100644 (file)
index 0000000..ac7abab
--- /dev/null
@@ -0,0 +1,22 @@
+<html>
+<head>
+<script>
+    function runTest() {
+        if (!window.eventSender)
+            return;
+        if (window.internals)
+            window.internals.setTopContentInset(100);
+        if (window.testRunner)
+            testRunner.dumpAsText();
+
+        eventSender.mouseMoveTo(20, 120);
+        eventSender.mouseDown();
+        eventSender.mouseUp();
+    }
+</script>
+</head>
+<body onload="runTest()">
+    <iframe src="resources/iframe-to-hit-test.html" scrolling="no" frameborder="no" height="300" width="600"></iframe>
+    <div id="result">This test needs to be run through WebKitTestRunner.</div>
+</body>
+</html>
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/content-inset-hit-testing.html b/LayoutTests/platform/mac-wk2/tiled-drawing/content-inset-hit-testing.html
new file mode 100644 (file)
index 0000000..4a6580f
--- /dev/null
@@ -0,0 +1,41 @@
+<html>
+<head>
+<style>
+    #target {
+        background-color:purple;
+        width:25px;
+        height:25px;
+    }
+</style>
+<script>
+    var numberOfClicks = 0;
+
+    function runTest() {
+        if (!window.eventSender)
+            return;
+        if (window.internals)
+            window.internals.setTopContentInset(100);
+        if (window.testRunner)
+            testRunner.dumpAsText();
+
+        eventSender.mouseMoveTo(15, 115);
+        eventSender.mouseDown();
+        eventSender.mouseUp();
+
+        var result = document.getElementById("result");
+        if (numberOfClicks > 0)
+            result.innerHTML = "Pass!";
+        else
+            result.innerHTML = "Fail.";
+    }
+    
+    function clicked() {
+        numberOfClicks = 1;
+    }
+</script>
+</head>
+<body onload="runTest()">
+    <div id="target" onclick="clicked()"></div>
+    <div id="result">This test needs to be run through WebKitTestRunner.</div>
+</body>
+</html>
index 2a4ef85..fdb2756 100644 (file)
@@ -1,3 +1,86 @@
+2014-03-20  Beth Dakin  <bdakin@apple.com>
+
+        Implement contentInset for Mac WebKit2
+        https://bugs.webkit.org/show_bug.cgi?id=130273
+
+        Reviewed by Simon Fraser.
+
+        This patch adds support for topContentInset(). If a page has a topContentInset(), 
+        the root layer’s position is adjusted to account for the inset. It is assumed that 
+        the area accounted for by the inset is visible but obscured, so scrollbars need to 
+        be moved so that they only cover the non-obscured area, and most parts of WebCore 
+        that wonder about visibleContentSize only care about the unobscured area, so this 
+        patch makes that visibleContentRect return the unobscuredRect. Finally since this 
+        is achieved by moving a layer’s position, the topContentInset() also needs to be 
+        factored into various functions that are used to convert between coordinate 
+        spaces. 
+
+        Return Page::topContentInset() if this is the main frame.
+        * page/FrameView.cpp:
+        (WebCore::FrameView::topContentInset):
+        * page/FrameView.h:
+
+        Cache the inset on Page.
+        * page/Page.cpp:
+        (WebCore::Page::Page):
+        * page/Page.h:
+        (WebCore::Page::topContentInset):
+        (WebCore::Page::setTopContentInset):
+
+        unobscuredContentRect() used to unconditionally return visibleContentRect() on 
+        non-iOS platforms. Now that it is possible for some technically visible content to 
+        be obscured, this code needed to be re-worked a bit to make some more sense. 
+        visibleContentRect() now represents that visible content that is completely 
+        unobscured, so it should call into unobscuredContentRect() rather than the other 
+        way around.
+        * platform/ScrollView.cpp:
+        (WebCore::ScrollView::unobscuredContentRect):
+
+        unscaledTotalVisibleContentSize() includes the size of all content that might be 
+        visible. Some of this content might be obscured.
+        (WebCore::ScrollView::unscaledTotalVisibleContentSize):
+
+        Most of the time, we only care about the content that is FULLY visible. That is 
+        what you get from unscaledUnobscuredVisibleContentSize().
+        (WebCore::ScrollView::unscaledUnobscuredVisibleContentSize):
+
+        Use the unobscured size for these computations.
+        (WebCore::ScrollView::visibleContentRectInternal):
+        (WebCore::ScrollView::layoutSize):
+
+        Factor in the topContentInset().
+        (WebCore::ScrollView::scrollOffsetRelativeToDocument):
+        (WebCore::ScrollView::scrollPositionRelativeToDocument):
+
+        The scrollbars should be positioned to cover the non-obscured content only. 
+        (WebCore::ScrollView::updateScrollbars):
+
+        Again, factor the topContentInset() into these conversions since the root layer’s 
+        position has been adjusted to account for it.
+        (WebCore::ScrollView::contentsToRootView):
+        (WebCore::ScrollView::contentsToWindow):
+
+         Just like the scrollbars, the scroll corner must be moved the account for the 
+        inset.
+        (WebCore::ScrollView::scrollCornerRect):
+        * platform/ScrollView.h:
+        (WebCore::ScrollView::topContentInset):
+
+        RenderLayerCompositor cares about unscaledTotalVisibleContentSize(). It does not 
+        care if some of that content is obscured.
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::frameViewDidChangeSize):
+
+        Move the root layer’s position based on the contentInset.
+        (WebCore::RenderLayerCompositor::updateRootLayerPosition):
+        (WebCore::RenderLayerCompositor::ensureRootLayer):
+
+        Allow setting contentInset via Internals for testing purposes.
+        * testing/Internals.cpp:
+        (WebCore::Internals::setTopContentInset):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2014-03-20  Laszlo Vidacs  <lvidacs.u-szeged@partner.samsung.com>
 
         Optimize RenderTable::colToEffCol() for tables without colspans
index 4177337..1f71a51 100644 (file)
@@ -1039,6 +1039,7 @@ __ZN7WebCore4Page16setCanStartMediaEb
 __ZN7WebCore4Page16setDefersLoadingEb
 __ZN7WebCore4Page18removeSchedulePairEN3WTF10PassRefPtrINS1_12SchedulePairEEE
 __ZN7WebCore4Page18setPageScaleFactorEfRKNS_8IntPointE
+__ZN7WebCore4Page18setTopContentInsetEf
 __ZN7WebCore4Page19addLayoutMilestonesEj
 __ZN7WebCore4Page20scrollingCoordinatorEv
 __ZN7WebCore4Page20setDeviceScaleFactorEf
index b7dd755..b4a80b2 100644 (file)
@@ -929,6 +929,15 @@ void FrameView::setFooterHeight(int footerHeight)
         renderView->setNeedsLayout();
 }
 
+float FrameView::topContentInset() const
+{
+    if (!frame().isMainFrame())
+        return 0;
+    
+    Page* page = frame().page();
+    return page ? page->topContentInset() : 0;
+}
+    
 bool FrameView::hasCompositedContent() const
 {
     if (RenderView* renderView = this->renderView())
index bf98e27..b40e889 100644 (file)
@@ -449,6 +449,8 @@ public:
     virtual int footerHeight() const override { return m_footerHeight; }
     void setFooterHeight(int);
 
+    virtual float topContentInset() const override;
+
     virtual void willStartLiveResize() override;
     virtual void willEndLiveResize() override;
 
index 3fa9b1c..bcd2988 100644 (file)
@@ -159,6 +159,7 @@ Page::Page(PageClients& pageClients)
     , m_mediaVolume(1)
     , m_pageScaleFactor(1)
     , m_deviceScaleFactor(1)
+    , m_topContentInset(0)
     , m_suppressScrollbarAnimations(false)
     , m_didLoadUserStyleSheet(false)
     , m_userStyleSheetModificationTime(0)
@@ -748,7 +749,17 @@ void Page::setDeviceScaleFactor(float scaleFactor)
     pageCache()->markPagesForFullStyleRecalc(this);
     GraphicsContext::updateDocumentMarkerResources();
 }
-
+    
+void Page::setTopContentInset(float contentInset)
+{
+    if (m_topContentInset == contentInset)
+        return;
+    
+    m_topContentInset = contentInset;
+    if (RenderView* renderView = mainFrame().contentRenderer())
+        renderView->setNeedsLayout();
+}
+    
 void Page::setShouldSuppressScrollbarAnimations(bool suppressAnimations)
 {
     if (suppressAnimations == m_suppressScrollbarAnimations)
index a6f7c39..fec002c 100644 (file)
@@ -278,6 +278,9 @@ public:
     float deviceScaleFactor() const { return m_deviceScaleFactor; }
     void setDeviceScaleFactor(float);
 
+    float topContentInset() const { return m_topContentInset; }
+    void setTopContentInset(float);
+
     bool shouldSuppressScrollbarAnimations() const { return m_suppressScrollbarAnimations; }
     void setShouldSuppressScrollbarAnimations(bool suppressAnimations);
     void lockAllOverlayScrollbarsToHidden(bool lockOverlayScrollbars);
@@ -489,6 +492,8 @@ private:
     float m_pageScaleFactor;
     float m_deviceScaleFactor;
 
+    float m_topContentInset;
+
     bool m_suppressScrollbarAnimations;
 
     Pagination m_pagination;
index 5a76fe5..412e5b5 100644 (file)
@@ -235,8 +235,17 @@ void ScrollView::setDelegatesScrolling(bool delegatesScrolling)
     m_delegatesScrolling = delegatesScrolling;
     delegatesScrollingDidChange();
 }
-
-IntSize ScrollView::unscaledVisibleContentSize(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
+    
+#if !PLATFORM(IOS)
+IntRect ScrollView::unobscuredContentRect(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
+{
+    FloatSize visibleContentSize = unscaledUnobscuredVisibleContentSize(scrollbarInclusion);
+    visibleContentSize.scale(1 / visibleContentScaleFactor());
+    return IntRect(IntPoint(m_scrollOffset), expandedIntSize(visibleContentSize));
+}
+#endif
+    
+IntSize ScrollView::unscaledTotalVisibleContentSize(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
 {
     if (platformWidget())
         return platformVisibleContentSize(scrollbarInclusion == IncludeScrollbars);
@@ -258,9 +267,25 @@ IntSize ScrollView::unscaledVisibleContentSize(VisibleContentRectIncludesScrollb
 
     return IntSize(width() - verticalScrollbarWidth, height() - horizontalScrollbarHeight).expandedTo(IntSize());
 }
+    
+IntSize ScrollView::unscaledUnobscuredVisibleContentSize(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
+{
+    IntSize visibleContentSize = unscaledTotalVisibleContentSize(scrollbarInclusion);
+    
+    if (platformWidget())
+        return visibleContentSize;
+
+#if USE(TILED_BACKING_STORE)
+    if (!m_fixedVisibleContentRect.isEmpty())
+        return visibleContentSize;
+#endif
+
+    visibleContentSize.setHeight(visibleContentSize.height() - topContentInset());
+    return visibleContentSize;
+}
 
 #if !PLATFORM(GTK)
-IntRect ScrollView::visibleContentRectInternal(VisibleContentRectIncludesScrollbars scollbarInclusion, VisibleContentRectBehavior visibleContentRectBehavior) const
+IntRect ScrollView::visibleContentRectInternal(VisibleContentRectIncludesScrollbars scrollbarInclusion, VisibleContentRectBehavior visibleContentRectBehavior) const
 {
 #if PLATFORM(IOS)
     if (visibleContentRectBehavior == LegacyIOSDocumentViewRect) {
@@ -275,22 +300,20 @@ IntRect ScrollView::visibleContentRectInternal(VisibleContentRectIncludesScrollb
 #endif
 
     if (platformWidget())
-        return platformVisibleContentRect(scollbarInclusion == IncludeScrollbars);
+        return platformVisibleContentRect(scrollbarInclusion == IncludeScrollbars);
 
 #if USE(TILED_BACKING_STORE)
     if (!m_fixedVisibleContentRect.isEmpty())
         return m_fixedVisibleContentRect;
 #endif
 
-    FloatSize visibleContentSize = unscaledVisibleContentSize(scollbarInclusion);
-    visibleContentSize.scale(1 / visibleContentScaleFactor());
-    return IntRect(IntPoint(m_scrollOffset), expandedIntSize(visibleContentSize));
+    return unobscuredContentRect();
 }
 #endif
 
 IntSize ScrollView::layoutSize() const
 {
-    return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? unscaledVisibleContentSize(ExcludeScrollbars) : m_fixedLayoutSize;
+    return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? unscaledUnobscuredVisibleContentSize(ExcludeScrollbars) : m_fixedLayoutSize;
 }
 
 IntSize ScrollView::fixedLayoutSize() const
@@ -369,13 +392,13 @@ IntPoint ScrollView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint
 IntSize ScrollView::scrollOffsetRelativeToDocument() const
 {
     IntSize scrollOffset = this->scrollOffset();
-    return IntSize(scrollOffset.width(), scrollOffset.height() - headerHeight());
+    return IntSize(scrollOffset.width(), scrollOffset.height() - headerHeight() - topContentInset());
 }
 
 IntPoint ScrollView::scrollPositionRelativeToDocument() const
 {
     IntPoint scrollPosition = this->scrollPosition();
-    return IntPoint(scrollPosition.x(), scrollPosition.y() - headerHeight());
+    return IntPoint(scrollPosition.x(), scrollPosition.y() - headerHeight() - topContentInset());
 }
 
 int ScrollView::scrollSize(ScrollbarOrientation orientation) const
@@ -642,9 +665,9 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset)
         int pageStep = std::max(std::max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
         IntRect oldRect(m_horizontalScrollbar->frameRect());
         IntRect hBarRect(0,
-                        height() - m_horizontalScrollbar->height(),
-                        width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
-                        m_horizontalScrollbar->height());
+            height() - m_horizontalScrollbar->height(),
+            width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
+            m_horizontalScrollbar->height());
         m_horizontalScrollbar->setFrameRect(hBarRect);
         if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
             m_horizontalScrollbar->invalidate();
@@ -663,9 +686,9 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset)
         int pageStep = std::max(std::max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
         IntRect oldRect(m_verticalScrollbar->frameRect());
         IntRect vBarRect(width() - m_verticalScrollbar->width(), 
-                         0,
-                         m_verticalScrollbar->width(),
-                         height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
+            topContentInset(),
+            m_verticalScrollbar->width(),
+            height() - topContentInset() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
         m_verticalScrollbar->setFrameRect(vBarRect);
         if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
             m_verticalScrollbar->invalidate();
@@ -792,7 +815,7 @@ IntPoint ScrollView::contentsToRootView(const IntPoint& contentsPoint) const
     if (delegatesScrolling())
         return convertToRootView(contentsPoint);
 
-    IntPoint viewPoint = contentsPoint + IntSize(0, headerHeight()) - scrollOffset();
+    IntPoint viewPoint = contentsPoint + IntSize(0, headerHeight() + topContentInset()) - scrollOffset();
     return convertToRootView(viewPoint);  
 }
 
@@ -812,7 +835,7 @@ IntRect ScrollView::contentsToRootView(const IntRect& contentsRect) const
         return convertToRootView(contentsRect);
 
     IntRect viewRect = contentsRect;
-    viewRect.move(-scrollOffset() + IntSize(0, headerHeight()));
+    viewRect.move(-scrollOffset() + IntSize(0, headerHeight() + topContentInset()));
     return convertToRootView(viewRect);
 }
 
@@ -839,7 +862,7 @@ IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
     if (delegatesScrolling())
         return convertToContainingWindow(contentsPoint);
 
-    IntPoint viewPoint = contentsPoint + IntSize(0, headerHeight()) - scrollOffset();
+    IntPoint viewPoint = contentsPoint + IntSize(0, headerHeight() + topContentInset()) - scrollOffset();
     return convertToContainingWindow(viewPoint);  
 }
 
@@ -859,7 +882,7 @@ IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const
         return convertToContainingWindow(contentsRect);
 
     IntRect viewRect = contentsRect;
-    viewRect.move(-scrollOffset() + IntSize(0, headerHeight()));
+    viewRect.move(-scrollOffset() + IntSize(0, headerHeight() + topContentInset()));
     return convertToContainingWindow(viewRect);
 }
 
@@ -1056,20 +1079,22 @@ IntRect ScrollView::scrollCornerRect() const
     if (hasOverlayScrollbars())
         return cornerRect;
 
+    int heightTrackedByScrollbar = height() - topContentInset();
+
     if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) {
         cornerRect.unite(IntRect(m_horizontalScrollbar->width(),
-                                 height() - m_horizontalScrollbar->height(),
-                                 width() - m_horizontalScrollbar->width(),
-                                 m_horizontalScrollbar->height()));
+            height() - m_horizontalScrollbar->height(),
+            width() - m_horizontalScrollbar->width(),
+            m_horizontalScrollbar->height()));
     }
 
-    if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) {
+    if (m_verticalScrollbar && heightTrackedByScrollbar - m_verticalScrollbar->height() > 0) {
         cornerRect.unite(IntRect(width() - m_verticalScrollbar->width(),
-                                 m_verticalScrollbar->height(),
-                                 m_verticalScrollbar->width(),
-                                 height() - m_verticalScrollbar->height()));
+            m_verticalScrollbar->height() + topContentInset(),
+            m_verticalScrollbar->width(),
+            heightTrackedByScrollbar - m_verticalScrollbar->height()));
     }
-    
+
     return cornerRect;
 }
 
index 2d6ec9c..d5c97f6 100644 (file)
@@ -153,9 +153,11 @@ public:
     void setCanBlitOnScroll(bool);
     bool canBlitOnScroll() const;
 
-    // The visible content rect has a location that is the scrolled offset of the document. The width and height are the viewport width
-    // and height. By default the scrollbars themselves are excluded from this rectangle, but an optional boolean argument allows them to be
-    // included.
+    virtual float topContentInset() const { return 0; }
+
+    // The visible content rect has a location that is the scrolled offset of the document. The width and height are the unobscured viewport
+    // width and height. By default the scrollbars themselves are excluded from this rectangle, but an optional boolean argument allows them
+    // to be included.
     // In the situation the client is responsible for the scrolling (ie. with a tiled backing store) it is possible to use
     // the setFixedVisibleContentRect instead for the mainframe, though this must be updated manually, e.g just before resuming the page
     // which usually will happen when panning, pinching and rotation ends, or when scale or position are changed manually.
@@ -173,7 +175,7 @@ public:
     IntRect unobscuredContentRect() const;
     IntRect unobscuredContentRectIncludingScrollbars() const { return unobscuredContentRect(); }
 #else
-    IntRect unobscuredContentRect() const { return visibleContentRect(); }
+    IntRect unobscuredContentRect(VisibleContentRectIncludesScrollbars = ExcludeScrollbars) const;
     IntRect unobscuredContentRectIncludingScrollbars() const { return visibleContentRectIncludingScrollbars(); }
 #endif
 
@@ -189,11 +191,13 @@ public:
     TileCache* tileCache();
 #endif
 
-    // visibleContentRect().size() is computed from unscaledVisibleContentSize() divided by the value of visibleContentScaleFactor.
+    // visibleContentRect().size() is computed from unscaledUnobscuredVisibleContentSize() divided by the value of visibleContentScaleFactor.
     // visibleContentScaleFactor is usually 1, except when the setting delegatesPageScaling is true and the
     // ScrollView is the main frame; in that case, visibleContentScaleFactor is equal to the page's pageScaleFactor.
-    // Ports that don't use pageScaleFactor can treat unscaledVisibleContentSize and visibleContentRect().size() as equivalent.
-    IntSize unscaledVisibleContentSize(VisibleContentRectIncludesScrollbars = ExcludeScrollbars) const;
+    // Ports that don't use pageScaleFactor can treat unscaledUnobscuredVisibleContentSize and visibleContentRect().size() as equivalent.
+    // unscaledTotalVisibleContentSize() includes areas in the content that might be obscured by UI elements.
+    IntSize unscaledUnobscuredVisibleContentSize(VisibleContentRectIncludesScrollbars = ExcludeScrollbars) const;
+    IntSize unscaledTotalVisibleContentSize(VisibleContentRectIncludesScrollbars = ExcludeScrollbars) const;
     virtual float visibleContentScaleFactor() const { return 1; }
 
     // Functions for getting/setting the size webkit should use to layout the contents. By default this is the same as the visible
index 127c0c4..8206eb3 100644 (file)
@@ -1472,7 +1472,7 @@ void RenderLayerCompositor::frameViewDidChangeSize()
 {
     if (m_clipLayer) {
         const FrameView& frameView = m_renderView.frameView();
-        m_clipLayer->setSize(frameView.unscaledVisibleContentSize());
+        m_clipLayer->setSize(frameView.unscaledTotalVisibleContentSize());
 
         frameViewDidScroll();
         updateOverflowControlsLayers();
@@ -1875,11 +1875,12 @@ void RenderLayerCompositor::updateRootLayerPosition()
 {
     if (m_rootContentLayer) {
         const IntRect& documentRect = m_renderView.documentRect();
-        m_rootContentLayer->setSize(documentRect.size());
-        m_rootContentLayer->setPosition(FloatPoint(documentRect.x(), documentRect.y() + m_renderView.frameView().headerHeight()));
+        m_rootContentLayer->setSize(documentRect.size());        
+        m_rootContentLayer->setPosition(FloatPoint(documentRect.x(), documentRect.y() + m_renderView.frameView().headerHeight()
+            + m_renderView.frameView().topContentInset()));
     }
     if (m_clipLayer)
-        m_clipLayer->setSize(m_renderView.frameView().unscaledVisibleContentSize());
+        m_clipLayer->setSize(m_renderView.frameView().unscaledTotalVisibleContentSize());
 
 #if ENABLE(RUBBER_BANDING)
     if (m_contentShadowLayer) {
@@ -3123,7 +3124,7 @@ void RenderLayerCompositor::ensureRootLayer()
             m_clipLayer->addChild(m_scrollLayer.get());
             m_scrollLayer->addChild(m_rootContentLayer.get());
 
-            m_clipLayer->setSize(m_renderView.frameView().unscaledVisibleContentSize());
+            m_clipLayer->setSize(m_renderView.frameView().unscaledTotalVisibleContentSize());
 
             updateOverflowControlsLayers();
 
index 0e3998b..41a509e 100644 (file)
@@ -1827,6 +1827,16 @@ void Internals::setFooterHeight(float height)
     FrameView* frameView = document->view();
     frameView->setFooterHeight(height);
 }
+    
+void Internals::setTopContentInset(float contentInset)
+{
+    Document* document = contextDocument();
+    if (!document)
+        return;
+    
+    Page* page = document->page();
+    page->setTopContentInset(contentInset);
+}
 
 #if ENABLE(FULLSCREEN_API)
 void Internals::webkitWillEnterFullScreenForElement(Element* element)
index 6cae899..1aff5fe 100644 (file)
@@ -255,6 +255,8 @@ public:
     void setHeaderHeight(float);
     void setFooterHeight(float);
 
+    void setTopContentInset(float);
+
 #if ENABLE(FULLSCREEN_API)
     void webkitWillEnterFullScreenForElement(Element*);
     void webkitDidEnterFullScreenForElement(Element*);
index 2cc55c7..f311b4a 100644 (file)
     void setHeaderHeight(float height);
     void setFooterHeight(float height);
 
+    void setTopContentInset(float contentInset);
+
 #if defined(ENABLE_FULLSCREEN_API) && ENABLE_FULLSCREEN_API
     void webkitWillEnterFullScreenForElement(Element element);
     void webkitDidEnterFullScreenForElement(Element element);
index faa76b5..6ee232b 100644 (file)
@@ -1,3 +1,37 @@
+2014-03-20  Beth Dakin  <bdakin@apple.com>
+
+        Implement contentInset for Mac WebKit2
+        https://bugs.webkit.org/show_bug.cgi?id=130273
+
+        Reviewed by Simon Fraser.
+
+        This patch adds WKView API for setting a topContentInset(). All of this work gets 
+        that number plumbed down to WebCore.
+
+        * Shared/WebPageCreationParameters.cpp:
+        (WebKit::WebPageCreationParameters::encode):
+        (WebKit::WebPageCreationParameters::decode):
+        * Shared/WebPageCreationParameters.h:
+        * UIProcess/API/Cocoa/WKViewPrivate.h:
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _setTopContentInset:]):
+        (-[WKWebView _topContentInset]):
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        * UIProcess/API/mac/WKView.mm:
+        (-[WKView _setTopContentInset:]):
+        (-[WKView _topContentInset]):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::WebPageProxy):
+        (WebKit::WebPageProxy::setTopContentInset):
+        (WebKit::WebPageProxy::creationParameters):
+        * UIProcess/WebPageProxy.h:
+        (WebKit::WebPageProxy::topContentInset):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::WebPage):
+        (WebKit::WebPage::setTopContentInset):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2014-03-20  Anders Carlsson  <andersca@apple.com>
 
         Fix 32-bit build.
index bebb071..2266217 100644 (file)
@@ -55,6 +55,7 @@ void WebPageCreationParameters::encode(IPC::ArgumentEncoder& encoder) const
     encoder << canRunBeforeUnloadConfirmPanel;
     encoder << canRunModal;
     encoder << deviceScaleFactor;
+    encoder << topContentInset;
     encoder << mediaVolume;
     encoder << mayStartMediaWhenInWindow;
     encoder << minimumLayoutSize;
@@ -120,6 +121,8 @@ bool WebPageCreationParameters::decode(IPC::ArgumentDecoder& decoder, WebPageCre
         return false;
     if (!decoder.decode(parameters.deviceScaleFactor))
         return false;
+    if (!decoder.decode(parameters.topContentInset))
+        return false;
     if (!decoder.decode(parameters.mediaVolume))
         return false;
     if (!decoder.decode(parameters.mayStartMediaWhenInWindow))
index fda7091..86ee343 100644 (file)
@@ -90,6 +90,8 @@ struct WebPageCreationParameters {
     bool canRunModal;
 
     float deviceScaleFactor;
+
+    float topContentInset;
     
     float mediaVolume;
     bool mayStartMediaWhenInWindow;
index f1b7ac0..2d3e326 100644 (file)
@@ -81,6 +81,7 @@
 @property (readwrite) BOOL allowsMagnification;
 @property (readwrite) double magnification;
 @property (readwrite) BOOL allowsBackForwardNavigationGestures;
+@property (nonatomic, setter=_setTopContentInset:) CGFloat _topContentInset;
 
 @property (readonly) NSColor *_pageExtendedBackgroundColor;
 @property(copy, nonatomic) NSColor *underlayColor;
index c655b08..621660b 100644 (file)
@@ -1147,6 +1147,16 @@ static inline WebCore::LayoutMilestones layoutMilestones(_WKRenderingProgressEve
     _page->setDrawsTransparentBackground(drawsTransparentBackground);
 }
 
+- (void)_setTopContentInset:(CGFloat)contentInset
+{
+    _page->setTopContentInset(contentInset);
+}
+
+- (CGFloat)_topContentInset
+{
+    return _page->topContentInset();
+}
+
 #endif
 
 @end
index 0c29194..f528c1f 100644 (file)
@@ -94,6 +94,7 @@ typedef NS_ENUM(NSInteger, _WKPaginationMode) {
 #else
 @property (readonly) NSColor *_pageExtendedBackgroundColor;
 @property (nonatomic, setter=_setDrawsTransparentBackground:) BOOL _drawsTransparentBackground;
+@property (nonatomic, setter=_setTopContentInset:) CGFloat _topContentInset;
 #endif
 
 - (void)_runJavaScriptInMainFrame:(NSString *)scriptString;
index 390b657..ddf66bd 100644 (file)
@@ -3742,6 +3742,16 @@ static NSString *pathWithUniqueFilenameForPath(NSString *path)
     return _data->_allowsBackForwardNavigationGestures;
 }
 
+- (void)_setTopContentInset:(CGFloat)contentInset
+{
+    _data->_page->setTopContentInset(contentInset);
+}
+
+- (CGFloat)_topContentInset
+{
+    return _data->_page->topContentInset();
+}
+
 - (NSColor *)_pageExtendedBackgroundColor
 {
     WebCore::Color color = _data->_page->pageExtendedBackgroundColor();
index 0575c43..3357123 100644 (file)
@@ -274,6 +274,7 @@ WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uin
     , m_pageScaleFactor(1)
     , m_intrinsicDeviceScaleFactor(1)
     , m_customDeviceScaleFactor(0)
+    , m_topContentInset(0)
     , m_layerHostingMode(LayerHostingMode::InProcess)
     , m_drawsBackground(true)
     , m_drawsTransparentBackground(false)
@@ -925,6 +926,17 @@ void WebPageProxy::setDrawsTransparentBackground(bool drawsTransparentBackground
         m_process->send(Messages::WebPage::SetDrawsTransparentBackground(drawsTransparentBackground), m_pageID);
 }
 
+void WebPageProxy::setTopContentInset(float contentInset)
+{
+    if (m_topContentInset == contentInset)
+        return;
+
+    m_topContentInset = contentInset;
+
+    if (isValid())
+        m_process->send(Messages::WebPage::SetTopContentInset(contentInset), m_pageID);
+}
+
 void WebPageProxy::setUnderlayColor(const Color& color)
 {
     if (m_underlayColor == color)
@@ -4078,6 +4090,7 @@ WebPageCreationParameters WebPageProxy::creationParameters()
     parameters.canRunBeforeUnloadConfirmPanel = m_uiClient->canRunBeforeUnloadConfirmPanel();
     parameters.canRunModal = m_canRunModal;
     parameters.deviceScaleFactor = deviceScaleFactor();
+    parameters.topContentInset = m_topContentInset;
     parameters.mediaVolume = m_mediaVolume;
     parameters.mayStartMediaWhenInWindow = m_mayStartMediaWhenInWindow;
     parameters.minimumLayoutSize = m_minimumLayoutSize;
index f067093..7466216 100644 (file)
@@ -523,6 +523,9 @@ public:
     bool drawsTransparentBackground() const { return m_drawsTransparentBackground; }
     void setDrawsTransparentBackground(bool);
 
+    float topContentInset() const { return m_topContentInset; }
+    void setTopContentInset(float);
+
     WebCore::Color underlayColor() const { return m_underlayColor; }
     void setUnderlayColor(const WebCore::Color&);
 
@@ -1461,6 +1464,7 @@ private:
     double m_pageScaleFactor;
     float m_intrinsicDeviceScaleFactor;
     float m_customDeviceScaleFactor;
+    float m_topContentInset;
 
     LayerHostingMode m_layerHostingMode;
 
index 232586b..afc41a4 100644 (file)
@@ -404,6 +404,8 @@ WebPage::WebPage(uint64_t pageID, const WebPageCreationParameters& parameters)
     setScrollPinningBehavior(parameters.scrollPinningBehavior);
     setBackgroundExtendsBeyondPage(parameters.backgroundExtendsBeyondPage);
 
+    setTopContentInset(parameters.topContentInset);
+
     m_userAgent = parameters.userAgent;
 
     WebBackForwardListProxy::setHighestItemIDFromUIProcess(parameters.highestUsedBackForwardItemID);
@@ -2032,6 +2034,11 @@ void WebPage::setDrawsTransparentBackground(bool drawsTransparentBackground)
     m_drawingArea->setNeedsDisplay();
 }
 
+void WebPage::setTopContentInset(float contentInset)
+{
+    m_page->setTopContentInset(contentInset);
+}
+
 void WebPage::viewWillStartLiveResize()
 {
     if (!m_page)
index 3322ad9..305da15 100644 (file)
@@ -850,6 +850,8 @@ private:
     void setDrawsBackground(bool);
     void setDrawsTransparentBackground(bool);
 
+    void setTopContentInset(float);
+
     void viewWillStartLiveResize();
     void viewWillEndLiveResize();
 
index 1a2b6cd..0205840 100644 (file)
@@ -30,6 +30,8 @@ messages -> WebPage LegacyReceiver {
     SetDrawsBackground(bool drawsBackground)
     SetDrawsTransparentBackground(bool drawsTransparentBackground)
 
+    SetTopContentInset(float contentInset)
+
     SetUnderlayColor(WebCore::Color color)
 
     ViewWillStartLiveResize()