[iOS WK2] When zoomed in and panning on pages with fixed bars, parts of the bars are sometimes missing
https://bugs.webkit.org/show_bug.cgi?id=164855

Reviewed by Sam Weinig.
Source/WebCore:

During UI-process panning and zooming, we send visible rect updates to the web process
with inStableState=false, and don't update GraphicsLayers until we get into a stable state.

This causes a problem where the web process has a stale notion of where the GraphicsLayers
for position:fixed elements are, but is then told to update tiling coverage with an up-to-date
visible rect. The existing "sync layer positions" path isn't useful to fix this, because it
breaks the relationship between the GraphicsLayer positions and their FixedPositionViewportConstraints
in the scrolling tree.

To address this, add the notion of an Optional<> approximatePosition on GraphicsLayers. This is used
only by the coverageRect computation code path, and is cleared by a setPosition(). ApproximatePositions
are pushed onto GraphicsLayers via the syncViewportConstrainedLayerPositions() code path (renamed to
reconcileViewportConstrainedLayerPositions).

This allows us to remmove "viewportIsStable" from GraphicsLayer flushing, and FrameView.

SetOrSyncScrollingLayerPosition is made into an enum class.

Tested by scrollingcoordinator/ios/non-stable-viewport-scroll.html

* page/FrameView.cpp:
(WebCore::FrameView::reset):
* page/FrameView.h:
* page/scrolling/AsyncScrollingCoordinator.cpp:
(WebCore::AsyncScrollingCoordinator::requestScrollPositionUpdate):
(WebCore::AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll):
(WebCore::AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll):
(WebCore::AsyncScrollingCoordinator::reconcileScrollingState):
(WebCore::AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions):
(WebCore::AsyncScrollingCoordinator::syncViewportConstrainedLayerPositions): Deleted.
* page/scrolling/AsyncScrollingCoordinator.h:
(WebCore::AsyncScrollingCoordinator::ScheduledScrollUpdate::ScheduledScrollUpdate):
* page/scrolling/ScrollingCoordinator.cpp:
(WebCore::operator<<):
* page/scrolling/ScrollingCoordinator.h:
(WebCore::ScrollingCoordinator::reconcileScrollingState):
(WebCore::ScrollingCoordinator::reconcileViewportConstrainedLayerPositions):
(WebCore::ScrollingCoordinator::syncViewportConstrainedLayerPositions): Deleted.
* page/scrolling/ScrollingStateFixedNode.cpp:
(WebCore::ScrollingStateFixedNode::reconcileLayerPositionForViewportRect):
(WebCore::ScrollingStateFixedNode::syncLayerPositionForViewportRect): Deleted.
* page/scrolling/ScrollingStateFixedNode.h:
* page/scrolling/ScrollingStateNode.h:
(WebCore::ScrollingStateNode::reconcileLayerPositionForViewportRect):
(WebCore::ScrollingStateNode::syncLayerPositionForViewportRect): Deleted.
* page/scrolling/ScrollingStateStickyNode.cpp:
(WebCore::ScrollingStateStickyNode::reconcileLayerPositionForViewportRect):
(WebCore::ScrollingStateStickyNode::syncLayerPositionForViewportRect): Deleted.
* page/scrolling/ScrollingStateStickyNode.h:
* page/scrolling/ScrollingTree.cpp:
(WebCore::ScrollingTree::scrollPositionChangedViaDelegatedScrolling):
* page/scrolling/ScrollingTree.h:
* page/scrolling/ThreadedScrollingTree.cpp:
(WebCore::ThreadedScrollingTree::scrollingTreeNodeDidScroll):
* page/scrolling/ThreadedScrollingTree.h:
* page/scrolling/ios/ScrollingTreeFrameScrollingNodeIOS.mm:
(WebCore::ScrollingTreeFrameScrollingNodeIOS::setScrollPositionWithoutContentEdgeConstraints):
* page/scrolling/ios/ScrollingTreeIOS.cpp:
(WebCore::ScrollingTreeIOS::scrollingTreeNodeDidScroll):
* page/scrolling/ios/ScrollingTreeIOS.h:
* page/scrolling/mac/ScrollingTreeFixedNode.mm:
(WebCore::ScrollingTreeFixedNode::updateLayersAfterAncestorChange):
* platform/graphics/GraphicsLayer.cpp:
(WebCore::GraphicsLayer::dumpProperties):
* platform/graphics/GraphicsLayer.h:
(WebCore::GraphicsLayer::setPosition):
(WebCore::GraphicsLayer::approximatePosition):
(WebCore::GraphicsLayer::setApproximatePosition):
(WebCore::GraphicsLayer::flushCompositingState):
(WebCore::GraphicsLayer::flushCompositingStateForThisLayerOnly):
* platform/graphics/ca/GraphicsLayerCA.cpp:
(WebCore::GraphicsLayerCA::flushCompositingState):
(WebCore::GraphicsLayerCA::flushCompositingStateForThisLayerOnly):
(WebCore::GraphicsLayerCA::computeVisibleAndCoverageRect):
(WebCore::GraphicsLayerCA::setVisibleAndCoverageRects): No longer bail for viewportConstained layers when the viewport is unstable.
(WebCore::GraphicsLayerCA::recursiveCommitChanges):
* platform/graphics/ca/GraphicsLayerCA.h:
(WebCore::GraphicsLayerCA::CommitState::CommitState): Deleted.
* platform/graphics/texmap/GraphicsLayerTextureMapper.cpp:
(WebCore::GraphicsLayerTextureMapper::flushCompositingState):
* platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp:
(WebCore::CoordinatedGraphicsLayer::flushCompositingState):
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::flushPendingLayerChanges):

Source/WebKit/win:

Remove the "inStableState" parameter from flushCompositingState() etc.

* WebCoreSupport/AcceleratedCompositingContext.cpp:
(AcceleratedCompositingContext::flushPendingLayerChanges):
* WebView.cpp:
(WebView::flushPendingGraphicsLayerChanges):

Source/WebKit2:

During UI-process panning and zooming, we send visible rect updates to the web process
with inStableState=false, and don't update GraphicsLayers until we get into a stable state.

This causes a problem where the web process has a stale notion of where the GraphicsLayers
for position:fixed elements are, but is then told to update tiling coverage with an up-to-date
visible rect. The existing "sync layer positions" path isn't useful to fix this, because it
breaks the relationship between the GraphicsLayer positions and their FixedPositionViewportConstraints
in the scrolling tree.

To address this, add the notion of an Optional<> approximatePosition on GraphicsLayers. This is used
only by the coverageRect computation code path, and is cleared by a setPosition(). ApproximatePositions
are pushed onto GraphicsLayers via the syncViewportConstrainedLayerPositions() code path (renamed to
reconcileViewportConstrainedLayerPositions).

Tested by scrollingcoordinator/ios/non-stable-viewport-scroll.html

* UIProcess/Scrolling/RemoteScrollingCoordinatorProxy.cpp:
(WebKit::RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidScroll):
* UIProcess/Scrolling/RemoteScrollingCoordinatorProxy.h:
* UIProcess/Scrolling/RemoteScrollingTree.cpp:
(WebKit::RemoteScrollingTree::scrollingTreeNodeDidScroll):
* UIProcess/Scrolling/RemoteScrollingTree.h:
* WebProcess/Scrolling/RemoteScrollingCoordinator.mm:
(WebKit::RemoteScrollingCoordinator::scrollPositionChangedForNode):
* WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.cpp:
(WebKit::CompositingCoordinator::flushPendingLayerChanges):
* WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.cpp:
(WebKit::CoordinatedLayerTreeHost::didFlushRootLayer):
* WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp:
(WebKit::LayerTreeHostGtk::flushPendingLayerChanges):
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::updateVisibleContentRects): Always push the custom fixed position rect down, but send
ScrollingLayerPositionAction::SetApproximate if the state is not stable.
* WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.mm:
(WebKit::RemoteLayerTreeDrawingArea::flushLayers):
* WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:
(WebKit::TiledCoreAnimationDrawingArea::flushLayers):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@208927 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp b/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp
index 4c286a1..85a6472 100644
--- a/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp
+++ b/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp
@@ -220,7 +220,7 @@
 
     bool isProgrammaticScroll = frameView.inProgrammaticScroll();
     if (isProgrammaticScroll || frameView.frame().document()->pageCacheState() != Document::NotInPageCache)
-        updateScrollPositionAfterAsyncScroll(frameView.scrollLayerID(), scrollPosition, Nullopt, isProgrammaticScroll, SetScrollingLayerPosition);
+        updateScrollPositionAfterAsyncScroll(frameView.scrollLayerID(), scrollPosition, Nullopt, isProgrammaticScroll, ScrollingLayerPositionAction::Set);
 
     // If this frame view's document is being put into the page cache, we don't want to update our
     // main frame scroll position. Just let the FrameView think that we did.
@@ -235,7 +235,7 @@
     return true;
 }
 
-void AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll(ScrollingNodeID nodeID, const FloatPoint& scrollPosition, const Optional<FloatPoint>& layoutViewportOrigin, bool programmaticScroll, SetOrSyncScrollingLayerPosition scrollingLayerPositionAction)
+void AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll(ScrollingNodeID nodeID, const FloatPoint& scrollPosition, const Optional<FloatPoint>& layoutViewportOrigin, bool programmaticScroll, ScrollingLayerPositionAction scrollingLayerPositionAction)
 {
     ScheduledScrollUpdate scrollUpdate(nodeID, scrollPosition, layoutViewportOrigin, programmaticScroll, scrollingLayerPositionAction);
     
@@ -297,7 +297,7 @@
     return nullptr;
 }
 
-void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll(ScrollingNodeID scrollingNodeID, const FloatPoint& scrollPosition, Optional<FloatPoint> layoutViewportOrigin, bool programmaticScroll, SetOrSyncScrollingLayerPosition scrollingLayerPositionAction)
+void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll(ScrollingNodeID scrollingNodeID, const FloatPoint& scrollPosition, Optional<FloatPoint> layoutViewportOrigin, bool programmaticScroll, ScrollingLayerPositionAction scrollingLayerPositionAction)
 {
     ASSERT(isMainThread());
 
@@ -308,12 +308,12 @@
     if (!frameViewPtr)
         return;
 
-    LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll node " << scrollingNodeID << " scrollPosition " << scrollPosition << (scrollingLayerPositionAction == SetScrollingLayerPosition ? " set" : " sync") << " layer positions");
+    LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll node " << scrollingNodeID << " scrollPosition " << scrollPosition << " action " << scrollingLayerPositionAction);
 
     FrameView& frameView = *frameViewPtr;
 
     if (scrollingNodeID == frameView.scrollLayerID()) {
-        reconcileScrollingState(frameView, scrollPosition, layoutViewportOrigin, programmaticScroll, scrollingLayerPositionAction);
+        reconcileScrollingState(frameView, scrollPosition, layoutViewportOrigin, programmaticScroll, true, scrollingLayerPositionAction);
 
 #if PLATFORM(COCOA)
         if (m_page->expectsWheelEventTriggers()) {
@@ -328,10 +328,10 @@
 
     // Overflow-scroll area.
     if (ScrollableArea* scrollableArea = frameView.scrollableAreaForScrollLayerID(scrollingNodeID)) {
-        scrollableArea->setIsUserScroll(scrollingLayerPositionAction == SyncScrollingLayerPosition);
+        scrollableArea->setIsUserScroll(scrollingLayerPositionAction == ScrollingLayerPositionAction::Sync);
         scrollableArea->scrollToOffsetWithoutAnimation(scrollPosition);
         scrollableArea->setIsUserScroll(false);
-        if (scrollingLayerPositionAction == SetScrollingLayerPosition)
+        if (scrollingLayerPositionAction == ScrollingLayerPositionAction::Set)
             m_page->editorClient().overflowScrollPositionChanged();
 
 #if PLATFORM(COCOA)
@@ -344,22 +344,27 @@
     }
 }
 
-void AsyncScrollingCoordinator::reconcileScrollingState(FrameView& frameView, const FloatPoint& scrollPosition, const LayoutViewportOriginOrOverrideRect& layoutViewportOriginOrOverrideRect, bool programmaticScroll, SetOrSyncScrollingLayerPosition scrollingLayerPositionAction)
+void AsyncScrollingCoordinator::reconcileScrollingState(FrameView& frameView, const FloatPoint& scrollPosition, const LayoutViewportOriginOrOverrideRect& layoutViewportOriginOrOverrideRect, bool programmaticScroll, bool inStableState, ScrollingLayerPositionAction scrollingLayerPositionAction)
 {
     bool oldProgrammaticScroll = frameView.inProgrammaticScroll();
     frameView.setInProgrammaticScroll(programmaticScroll);
 
+    Optional<FloatRect> layoutViewportRect;
+
     WTF::switchOn(layoutViewportOriginOrOverrideRect,
         [&frameView](Optional<FloatPoint> origin) {
             if (origin)
                 frameView.setBaseLayoutViewportOrigin(LayoutPoint(origin.value()), FrameView::TriggerLayoutOrNot::No);
-        }, [&frameView](Optional<FloatRect> overrideRect) {
+        }, [&frameView, &layoutViewportRect, inStableState, visualViewportEnabled = visualViewportEnabled()](Optional<FloatRect> overrideRect) {
+            layoutViewportRect = overrideRect;
+            if (overrideRect && inStableState) {
+                if (visualViewportEnabled)
+                    frameView.setLayoutViewportOverrideRect(LayoutRect(overrideRect.value()));
 #if PLATFORM(IOS)
-            if (overrideRect)
-                frameView.setCustomFixedPositionLayoutRect(enclosingIntRect(overrideRect.value()));
-#else
-            UNUSED_PARAM(overrideRect);
+                else
+                    frameView.setCustomFixedPositionLayoutRect(enclosingIntRect(overrideRect.value()));
 #endif
+            }
         }
     );
 
@@ -368,8 +373,12 @@
     frameView.setConstrainsScrollingToContentEdge(true);
     frameView.setInProgrammaticScroll(oldProgrammaticScroll);
 
-    if (!programmaticScroll && scrollingLayerPositionAction == SyncScrollingLayerPosition)
-        syncViewportConstrainedLayerPositions(frameView.rectForFixedPositionLayout());
+    if (!programmaticScroll && scrollingLayerPositionAction != ScrollingLayerPositionAction::Set) {
+        if (inStableState)
+            reconcileViewportConstrainedLayerPositions(frameView.rectForFixedPositionLayout(), scrollingLayerPositionAction);
+        else if (layoutViewportRect)
+            reconcileViewportConstrainedLayerPositions(LayoutRect(layoutViewportRect.value()), scrollingLayerPositionAction);
+    }
 
     GraphicsLayer* scrollLayer = scrollLayerForFrameView(frameView);
     if (!scrollLayer)
@@ -395,7 +404,7 @@
     FloatPoint positionForFooterLayer = FloatPoint(scrollPositionForFixed.x(),
         FrameView::yPositionForFooterLayer(scrollPosition, topContentInset, frameView.totalContentsSize().height(), frameView.footerHeight()));
 
-    if (programmaticScroll || scrollingLayerPositionAction == SetScrollingLayerPosition) {
+    if (programmaticScroll || scrollingLayerPositionAction == ScrollingLayerPositionAction::Set) {
         scrollLayer->setPosition(-frameView.scrollPosition());
         if (counterScrollingLayer)
             counterScrollingLayer->setPosition(scrollPositionForFixed);
@@ -455,7 +464,7 @@
     m_scrollingStateTree->clear();
 }
 
-void AsyncScrollingCoordinator::syncViewportConstrainedLayerPositions(const LayoutRect& viewportRect)
+void AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions(const LayoutRect& viewportRect, ScrollingLayerPositionAction action)
 {
     if (!m_scrollingStateTree->rootStateNode())
         return;
@@ -464,11 +473,11 @@
     if (!children)
         return;
 
-    LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::syncChildPositions for viewport rect " << viewportRect);
+    LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions for viewport rect " << viewportRect);
 
     // FIXME: We'll have to traverse deeper into the tree at some point.
     for (auto& child : *children)
-        child->syncLayerPositionForViewportRect(viewportRect);
+        child->reconcileLayerPositionForViewportRect(viewportRect, action);
 }
 
 void AsyncScrollingCoordinator::ensureRootStateNodeForFrameView(FrameView& frameView)