Title: [219668] trunk
Revision
219668
Author
[email protected]
Date
2017-07-19 17:15:08 -0700 (Wed, 19 Jul 2017)

Log Message

getBoundingClientRects not updated for programmatic scrolls
https://bugs.webkit.org/show_bug.cgi?id=174538
rdar://problem/33049012

Reviewed by Tim Horton.
Source/WebCore:

Baidu.com has two event handlers on its <input>, and both query the input location with getBoundingClientRect()
and the current pageYOffset (via jQuery), then try to scroll the input to the top of the screen. The bug is that
programmatic scrolls did not immediately update the layout viewport rect, so the second call to
getBoundingClientRect() would return stale coordinates, triggering an extra scroll.

To fix this, undo the fix for r219320 which tried to keep getBoundingClientRect() current during unstable scroll
updates by adding a shadow layout viewport rect. Instead, almost always update the layout viewport rect on
FrameView, even during unstable visible rect updates, but not if content insets are being changed interactively,
since changing viewport heights cause problems with bottom-fixed elements. Also, we need to compute a new layout
viewport rect in FrameView::updateLayoutViewport() for programmatic scrolls.

However, always updating the layout viewport triggered issues with the scrolling tree. The scrolling state tree
fossilizes layer positions relative to a specific viewport rect, and that relationship has to be maintained.
There are code paths that recompute fixed/sticky viewport constraints when the layout viewport has changed but
we haven't done layout or recomputed layer positions (e.g. updating viewport-constrained layers via
updateScrollCoordinatedLayersAfterFlush()) and in these cases using a new layout viewport for those computations
results in an inconsistent scrolling tree.

Fix this by not updating scrolling constraints every time we have to re-register scrolling nodes.
updateScrollCoordinatedLayersAfterFlush() only needs to update the layer on the scrolling node (to handle
tiled/non-tiled switches), so make updateScrollCoordinatedLayer() a little more fine-grained, and only update
constraints when we've just computed layer geometry. This allows for different scrolling nodes to have
constraints computed at different times, with different layout viewports, which happens.

Two additional fixes were required to make bottom-fixed bars behave correctly.

First, FrameView::computeLayoutViewportOrigin() had a bug where rounding of half-pixel values would cause it to
fall into the if (visualViewport.height() > layoutViewport.height()) clause, but then fail to clamp for
rubber-banding.

Second, the FrameView::unscaledMaximumScrollPosition() was wrong after zooming on iOS, since it uses visibleSize()
which is affected by page scale on iOS only (and the function wants scale-independent values). Fix with a hack that
should be cleaned up via webkit.org/b/174648.

Tested by existing tests.

* page/FrameView.cpp:
(WebCore::FrameView::computeUpdatedLayoutViewportRect):
(WebCore::FrameView::computeLayoutViewportOrigin):
(WebCore::FrameView::setLayoutViewportOverrideRect):
(WebCore::FrameView::updateLayoutViewport):
(WebCore::FrameView::unscaledMaximumScrollPosition):
(WebCore::FrameView::documentToClientOffset):
(WebCore::FrameView::setUnstableLayoutViewportRect): Deleted.
* page/FrameView.h:
* page/scrolling/AsyncScrollingCoordinator.cpp:
(WebCore::AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll):
(WebCore::AsyncScrollingCoordinator::reconcileScrollingState):
(WebCore::AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions):
(WebCore::AsyncScrollingCoordinator::updateNodeLayer):
(WebCore::AsyncScrollingCoordinator::updateNodeViewportConstraints):
(WebCore::AsyncScrollingCoordinator::updateViewportConstrainedNode): Deleted.
* page/scrolling/AsyncScrollingCoordinator.h:
* page/scrolling/ScrollingCoordinator.cpp:
(WebCore::operator<<):
* page/scrolling/ScrollingCoordinator.h:
(WebCore::ScrollingCoordinator::reconcileScrollingState):
(WebCore::ScrollingCoordinator::updateNodeLayer):
(WebCore::ScrollingCoordinator::updateNodeViewportConstraints):
(WebCore::ScrollingCoordinator::updateViewportConstrainedNode): Deleted.
* page/scrolling/ScrollingStateFixedNode.cpp:
(WebCore::ScrollingStateFixedNode::updateConstraints):
* page/scrolling/ScrollingStateStickyNode.cpp:
(WebCore::ScrollingStateStickyNode::updateConstraints):
(WebCore::ScrollingStateStickyNode::reconcileLayerPositionForViewportRect):
* page/scrolling/ScrollingTree.cpp:
(WebCore::ScrollingTree::commitTreeState):
* page/scrolling/mac/ScrollingTreeFixedNode.mm:
(WebCore::ScrollingTreeFixedNode::updateLayersAfterAncestorChange):
* page/scrolling/mac/ScrollingTreeStickyNode.mm:
(WebCore::ScrollingTreeStickyNode::updateLayersAfterAncestorChange):
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::updateGeometry):
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::updateScrollCoordinatedLayersAfterFlush):
(WebCore::RenderLayerCompositor::updateBacking):
(WebCore::RenderLayerCompositor::fixedRootBackgroundLayerChanged):
(WebCore::RenderLayerCompositor::requiresCompositingForPosition):
(WebCore::RenderLayerCompositor::updateScrollCoordinatedStatus):
(WebCore::RenderLayerCompositor::computeFixedViewportConstraints):
(WebCore::RenderLayerCompositor::computeStickyViewportConstraints):
(WebCore::RenderLayerCompositor::updateScrollCoordinatedLayer):
(WebCore::RenderLayerCompositor::didAddScrollingLayer):
* rendering/RenderLayerCompositor.h:

Source/WebKit:

Feed ViewportRectStability and ScrollingLayerPositionAction into reconcileScrollingState().

* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::updateVisibleContentRects):

LayoutTests:

New results for these tests, reflecting the fact that programmatic scrolls now update
the layout viewport.

Clean up fast/dom/elementFromPoint-relative-to-viewport.html, and land an iOS expectation. The test
uses eventSender.zoomPageOut() which is not expected to work correctly on iOS. It works when tested
manually.

* fast/dom/elementFromPoint-relative-to-viewport-expected.txt:
* fast/dom/elementFromPoint-relative-to-viewport.html:
* platform/ios-wk2/fast/dom/elementFromPoint-relative-to-viewport-expected.txt: Copied from LayoutTests/fast/dom/elementFromPoint-relative-to-viewport-expected.txt.
* platform/ios-wk2/fast/visual-viewport/client-rects-relative-to-layout-viewport-expected.txt:
* platform/ios-wk2/fast/visual-viewport/rtl-zoomed-rects-expected.txt:
* platform/ios-wk2/fast/visual-viewport/zoomed-fixed-scroll-down-then-up-expected.txt:
* platform/ios-wk2/fast/visual-viewport/zoomed-rects-expected.txt:
* platform/ios/fast/visual-viewport/zoomed-fixed-expected.txt:
* platform/ios/fast/visual-viewport/zoomed-fixed-header-and-footer-expected.txt:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (219667 => 219668)


--- trunk/LayoutTests/ChangeLog	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/LayoutTests/ChangeLog	2017-07-20 00:15:08 UTC (rev 219668)
@@ -1,3 +1,28 @@
+2017-07-19  Simon Fraser  <[email protected]>
+
+        getBoundingClientRects not updated for programmatic scrolls
+        https://bugs.webkit.org/show_bug.cgi?id=174538
+        rdar://problem/33049012
+
+        Reviewed by Tim Horton.
+        
+        New results for these tests, reflecting the fact that programmatic scrolls now update
+        the layout viewport.
+        
+        Clean up fast/dom/elementFromPoint-relative-to-viewport.html, and land an iOS expectation. The test
+        uses eventSender.zoomPageOut() which is not expected to work correctly on iOS. It works when tested
+        manually.
+
+        * fast/dom/elementFromPoint-relative-to-viewport-expected.txt:
+        * fast/dom/elementFromPoint-relative-to-viewport.html:
+        * platform/ios-wk2/fast/dom/elementFromPoint-relative-to-viewport-expected.txt: Copied from LayoutTests/fast/dom/elementFromPoint-relative-to-viewport-expected.txt.
+        * platform/ios-wk2/fast/visual-viewport/client-rects-relative-to-layout-viewport-expected.txt:
+        * platform/ios-wk2/fast/visual-viewport/rtl-zoomed-rects-expected.txt:
+        * platform/ios-wk2/fast/visual-viewport/zoomed-fixed-scroll-down-then-up-expected.txt:
+        * platform/ios-wk2/fast/visual-viewport/zoomed-rects-expected.txt:
+        * platform/ios/fast/visual-viewport/zoomed-fixed-expected.txt:
+        * platform/ios/fast/visual-viewport/zoomed-fixed-header-and-footer-expected.txt:
+
 2017-07-19  Myles C. Maxfield  <[email protected]>
 
         Setting the minimum font size preference doesn’t affect absolute line-height values, so lines overlap

Modified: trunk/LayoutTests/fast/dom/elementFromPoint-relative-to-viewport-expected.txt (219667 => 219668)


--- trunk/LayoutTests/fast/dom/elementFromPoint-relative-to-viewport-expected.txt	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/LayoutTests/fast/dom/elementFromPoint-relative-to-viewport-expected.txt	2017-07-20 00:15:08 UTC (rev 219668)
@@ -3,14 +3,21 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
+
+Test Initial
 PASS unscrolledBoxInitial is '0'
 PASS scrolledDownBoxInitial is '5'
 PASS scrolledRightBoxInitial is '3'
 PASS scrolledDownAndRightBoxInitial is '8'
+
+Test Offscreen
 PASS unscrolledBoxOffscreen is '0'
 PASS scrolledDownBoxOffscreen is '5'
 PASS scrolledRightBoxOffscreen is '3'
 PASS scrolledDownAndRightBoxOffscreen is '8'
+Zoomed out
+
+Test Initial
 PASS unscrolledBoxInitial is '0'
 PASS scrolledDownBoxInitial is '5'
 PASS scrolledRightBoxInitial is '3'

Modified: trunk/LayoutTests/fast/dom/elementFromPoint-relative-to-viewport.html (219667 => 219668)


--- trunk/LayoutTests/fast/dom/elementFromPoint-relative-to-viewport.html	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/LayoutTests/fast/dom/elementFromPoint-relative-to-viewport.html	2017-07-20 00:15:08 UTC (rev 219668)
@@ -43,6 +43,8 @@
     description('This test document.elementFromPoint is evaluated in with respect to the viewport, not the document.');
 
     function testElement(element, label, offsetX, offsetY, hasZoom) {
+        debug('');
+        debug('Test ' + label);
         for (var i = 0; i < 25; ++i) {
             var item = document.createElement("div");
             item.className = "testItem";
@@ -94,7 +96,9 @@
     testElement(elementInitial, "Initial", offset.left, offset.top);
     testElement(elementOffscreen, "Offscreen", offset.left, offset.top + 1100);
 
-    eventSender.zoomPageOut();
+    if (window.eventSender)
+        eventSender.zoomPageOut();
+    debug('Zoomed out');
     testElement(elementInitial, "Initial", offset.left, offset.top, /* hasZoom */ true);
 
     if (window.testRunner) {

Modified: trunk/LayoutTests/platform/ios/fast/visual-viewport/zoomed-fixed-expected.txt (219667 => 219668)


--- trunk/LayoutTests/platform/ios/fast/visual-viewport/zoomed-fixed-expected.txt	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/LayoutTests/platform/ios/fast/visual-viewport/zoomed-fixed-expected.txt	2017-07-20 00:15:08 UTC (rev 219668)
@@ -15,7 +15,7 @@
 JSON.stringify(fixedElement.getBoundingClientRect()) is {"x":700,"y":0,"width":100,"height":600,"top":0,"right":800,"bottom":600,"left":700}
 
 Scrolled to 475, 525
-JSON.stringify(internals.layoutViewportRect()) is {"x":0,"y":0,"width":800,"height":600,"top":0,"right":800,"bottom":600,"left":0}
+JSON.stringify(internals.layoutViewportRect()) is {"x":75,"y":225,"width":800,"height":600,"top":225,"right":875,"bottom":825,"left":75}
 JSON.stringify(internals.visualViewportRect()) is {"x":475,"y":525,"width":400,"height":300,"top":525,"right":875,"bottom":825,"left":475}
 client rect of top:
 JSON.stringify(fixedElement.getBoundingClientRect()) is {"x":0,"y":0,"width":800,"height":100,"top":0,"right":800,"bottom":100,"left":0}
@@ -27,7 +27,7 @@
 JSON.stringify(fixedElement.getBoundingClientRect()) is {"x":700,"y":0,"width":100,"height":600,"top":0,"right":800,"bottom":600,"left":700}
 
 Scrolled to 100, 776
-JSON.stringify(internals.layoutViewportRect()) is {"x":0,"y":0,"width":800,"height":600,"top":0,"right":800,"bottom":600,"left":0}
+JSON.stringify(internals.layoutViewportRect()) is {"x":75,"y":476,"width":800,"height":600,"top":476,"right":875,"bottom":1076,"left":75}
 JSON.stringify(internals.visualViewportRect()) is {"x":100,"y":776,"width":400,"height":300,"top":776,"right":500,"bottom":1076,"left":100}
 client rect of top:
 JSON.stringify(fixedElement.getBoundingClientRect()) is {"x":0,"y":0,"width":800,"height":100,"top":0,"right":800,"bottom":100,"left":0}
@@ -39,7 +39,7 @@
 JSON.stringify(fixedElement.getBoundingClientRect()) is {"x":700,"y":0,"width":100,"height":600,"top":0,"right":800,"bottom":600,"left":700}
 
 Scrolled to 50, 300
-JSON.stringify(internals.layoutViewportRect()) is {"x":0,"y":0,"width":800,"height":600,"top":0,"right":800,"bottom":600,"left":0}
+JSON.stringify(internals.layoutViewportRect()) is {"x":50,"y":300,"width":800,"height":600,"top":300,"right":850,"bottom":900,"left":50}
 JSON.stringify(internals.visualViewportRect()) is {"x":50,"y":300,"width":400,"height":300,"top":300,"right":450,"bottom":600,"left":50}
 client rect of top:
 JSON.stringify(fixedElement.getBoundingClientRect()) is {"x":0,"y":0,"width":800,"height":100,"top":0,"right":800,"bottom":100,"left":0}

Modified: trunk/LayoutTests/platform/ios/fast/visual-viewport/zoomed-fixed-header-and-footer-expected.txt (219667 => 219668)


--- trunk/LayoutTests/platform/ios/fast/visual-viewport/zoomed-fixed-header-and-footer-expected.txt	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/LayoutTests/platform/ios/fast/visual-viewport/zoomed-fixed-header-and-footer-expected.txt	2017-07-20 00:15:08 UTC (rev 219668)
@@ -15,7 +15,7 @@
 JSON.stringify(fixedElement.getBoundingClientRect()) is {"x":700,"y":0,"width":100,"height":600,"top":0,"right":800,"bottom":600,"left":700}
 
 Scrolled to 475, 525
-JSON.stringify(internals.layoutViewportRect()) is {"x":0,"y":0,"width":800,"height":600,"top":0,"right":800,"bottom":600,"left":0}
+JSON.stringify(internals.layoutViewportRect()) is {"x":75,"y":182,"width":800,"height":600,"top":182,"right":875,"bottom":782,"left":75}
 JSON.stringify(internals.visualViewportRect()) is {"x":475,"y":482,"width":400,"height":300,"top":482,"right":875,"bottom":782,"left":475}
 client rect of top:
 JSON.stringify(fixedElement.getBoundingClientRect()) is {"x":0,"y":0,"width":800,"height":100,"top":0,"right":800,"bottom":100,"left":0}
@@ -27,7 +27,7 @@
 JSON.stringify(fixedElement.getBoundingClientRect()) is {"x":700,"y":0,"width":100,"height":600,"top":0,"right":800,"bottom":600,"left":700}
 
 Scrolled to 100, 776
-JSON.stringify(internals.layoutViewportRect()) is {"x":0,"y":0,"width":800,"height":600,"top":0,"right":800,"bottom":600,"left":0}
+JSON.stringify(internals.layoutViewportRect()) is {"x":75,"y":433,"width":800,"height":600,"top":433,"right":875,"bottom":1033,"left":75}
 JSON.stringify(internals.visualViewportRect()) is {"x":100,"y":733,"width":400,"height":300,"top":733,"right":500,"bottom":1033,"left":100}
 client rect of top:
 JSON.stringify(fixedElement.getBoundingClientRect()) is {"x":0,"y":0,"width":800,"height":100,"top":0,"right":800,"bottom":100,"left":0}
@@ -39,7 +39,7 @@
 JSON.stringify(fixedElement.getBoundingClientRect()) is {"x":700,"y":0,"width":100,"height":600,"top":0,"right":800,"bottom":600,"left":700}
 
 Scrolled to 50, 300
-JSON.stringify(internals.layoutViewportRect()) is {"x":0,"y":0,"width":800,"height":600,"top":0,"right":800,"bottom":600,"left":0}
+JSON.stringify(internals.layoutViewportRect()) is {"x":50,"y":257,"width":800,"height":600,"top":257,"right":850,"bottom":857,"left":50}
 JSON.stringify(internals.visualViewportRect()) is {"x":50,"y":257,"width":400,"height":300,"top":257,"right":450,"bottom":557,"left":50}
 client rect of top:
 JSON.stringify(fixedElement.getBoundingClientRect()) is {"x":0,"y":0,"width":800,"height":100,"top":0,"right":800,"bottom":100,"left":0}

Copied: trunk/LayoutTests/platform/ios-wk2/fast/dom/elementFromPoint-relative-to-viewport-expected.txt (from rev 219667, trunk/LayoutTests/fast/dom/elementFromPoint-relative-to-viewport-expected.txt) (0 => 219668)


--- trunk/LayoutTests/platform/ios-wk2/fast/dom/elementFromPoint-relative-to-viewport-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/ios-wk2/fast/dom/elementFromPoint-relative-to-viewport-expected.txt	2017-07-20 00:15:08 UTC (rev 219668)
@@ -0,0 +1,28 @@
+This test document.elementFromPoint is evaluated in with respect to the viewport, not the document.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+
+Test Initial
+PASS unscrolledBoxInitial is '0'
+PASS scrolledDownBoxInitial is '5'
+PASS scrolledRightBoxInitial is '3'
+PASS scrolledDownAndRightBoxInitial is '8'
+
+Test Offscreen
+PASS unscrolledBoxOffscreen is '0'
+PASS scrolledDownBoxOffscreen is '5'
+PASS scrolledRightBoxOffscreen is '3'
+PASS scrolledDownAndRightBoxOffscreen is '8'
+Zoomed out
+
+Test Initial
+PASS unscrolledBoxInitial is '0'
+PASS scrolledDownBoxInitial is '5'
+FAIL scrolledRightBoxInitial should be 3. Was 2.
+FAIL scrolledDownAndRightBoxInitial should be 8. Was 7.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Modified: trunk/LayoutTests/platform/ios-wk2/fast/visual-viewport/client-rects-relative-to-layout-viewport-expected.txt (219667 => 219668)


--- trunk/LayoutTests/platform/ios-wk2/fast/visual-viewport/client-rects-relative-to-layout-viewport-expected.txt	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/LayoutTests/platform/ios-wk2/fast/visual-viewport/client-rects-relative-to-layout-viewport-expected.txt	2017-07-20 00:15:08 UTC (rev 219668)
@@ -11,28 +11,28 @@
 absolute client rect: 120, 100 - 50 x 25
 
 Scrolled to 476, 526
-layoutViewport: 0, 0 - 800 x 600
+layoutViewport: 76, 226 - 800 x 600
 visualViewportRect: 476, 526 - 400 x 300
 fixed client bounds: 12, 10 - 30 x 20
 fixed client rect: 12, 10 - 30 x 20
-absolute client bounds: 120, 100 - 50 x 25
-absolute client rect: 120, 100 - 50 x 25
+absolute client bounds: 44, -126 - 50 x 25
+absolute client rect: 44, -126 - 50 x 25
 
 Scrolled to 100, 776
-layoutViewport: 0, 0 - 800 x 600
+layoutViewport: 76, 476 - 800 x 600
 visualViewportRect: 100, 776 - 400 x 300
 fixed client bounds: 12, 10 - 30 x 20
 fixed client rect: 12, 10 - 30 x 20
-absolute client bounds: 120, 100 - 50 x 25
-absolute client rect: 120, 100 - 50 x 25
+absolute client bounds: 44, -376 - 50 x 25
+absolute client rect: 44, -376 - 50 x 25
 
 Scrolled to 50, 300
-layoutViewport: 0, 0 - 800 x 600
+layoutViewport: 50, 300 - 800 x 600
 visualViewportRect: 50, 300 - 400 x 300
 fixed client bounds: 12, 10 - 30 x 20
 fixed client rect: 12, 10 - 30 x 20
-absolute client bounds: 120, 100 - 50 x 25
-absolute client rect: 120, 100 - 50 x 25
+absolute client bounds: 70, -200 - 50 x 25
+absolute client rect: 70, -200 - 50 x 25
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/platform/ios-wk2/fast/visual-viewport/rtl-zoomed-rects-expected.txt (219667 => 219668)


--- trunk/LayoutTests/platform/ios-wk2/fast/visual-viewport/rtl-zoomed-rects-expected.txt	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/LayoutTests/platform/ios-wk2/fast/visual-viewport/rtl-zoomed-rects-expected.txt	2017-07-20 00:15:08 UTC (rev 219668)
@@ -7,15 +7,15 @@
 JSON.stringify(internals.visualViewportRect()) is {"x":0,"y":0,"width":400,"height":300,"top":0,"right":400,"bottom":300,"left":0}
 
 Scrolled to -475, 525
-JSON.stringify(internals.layoutViewportRect()) is {"x":0,"y":0,"width":800,"height":600,"top":0,"right":800,"bottom":600,"left":0}
+JSON.stringify(internals.layoutViewportRect()) is {"x":-475,"y":225,"width":800,"height":600,"top":225,"right":325,"bottom":825,"left":-475}
 JSON.stringify(internals.visualViewportRect()) is {"x":-475,"y":525,"width":400,"height":300,"top":525,"right":-75,"bottom":825,"left":-475}
 
 Scrolled to -100, 776
-JSON.stringify(internals.layoutViewportRect()) is {"x":0,"y":0,"width":800,"height":600,"top":0,"right":800,"bottom":600,"left":0}
+JSON.stringify(internals.layoutViewportRect()) is {"x":-475,"y":476,"width":800,"height":600,"top":476,"right":325,"bottom":1076,"left":-475}
 JSON.stringify(internals.visualViewportRect()) is {"x":-100,"y":776,"width":400,"height":300,"top":776,"right":300,"bottom":1076,"left":-100}
 
 Scrolled to -50, 300
-JSON.stringify(internals.layoutViewportRect()) is {"x":0,"y":0,"width":800,"height":600,"top":0,"right":800,"bottom":600,"left":0}
+JSON.stringify(internals.layoutViewportRect()) is {"x":-450,"y":300,"width":800,"height":600,"top":300,"right":350,"bottom":900,"left":-450}
 JSON.stringify(internals.visualViewportRect()) is {"x":-50,"y":300,"width":400,"height":300,"top":300,"right":350,"bottom":600,"left":-50}
 PASS successfullyParsed is true
 

Modified: trunk/LayoutTests/platform/ios-wk2/fast/visual-viewport/zoomed-fixed-scroll-down-then-up-expected.txt (219667 => 219668)


--- trunk/LayoutTests/platform/ios-wk2/fast/visual-viewport/zoomed-fixed-scroll-down-then-up-expected.txt	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/LayoutTests/platform/ios-wk2/fast/visual-viewport/zoomed-fixed-scroll-down-then-up-expected.txt	2017-07-20 00:15:08 UTC (rev 219668)
@@ -3,12 +3,12 @@
 layer at (0,0) size 800x2016
   RenderBlock {HTML} at (0,0) size 800x2016
     RenderBody {BODY} at (8,8) size 2000x2000
-layer at (200,0) size 400x100
+layer at (200,10) size 400x100
   RenderBlock (positioned) {DIV} at (200,0) size 400x100 [bgcolor=#808080]
-layer at (200,500) size 400x100
+layer at (200,510) size 400x100
   RenderBlock (positioned) {DIV} at (200,500) size 400x100 [bgcolor=#808080]
-layer at (0,150) size 100x300
+layer at (0,160) size 100x300
   RenderBlock (positioned) {DIV} at (0,150) size 100x300 [bgcolor=#808080]
-layer at (700,150) size 100x300
+layer at (700,160) size 100x300
   RenderBlock (positioned) {DIV} at (700,150) size 100x300 [bgcolor=#808080]
 scrolled to 275,10

Modified: trunk/LayoutTests/platform/ios-wk2/fast/visual-viewport/zoomed-rects-expected.txt (219667 => 219668)


--- trunk/LayoutTests/platform/ios-wk2/fast/visual-viewport/zoomed-rects-expected.txt	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/LayoutTests/platform/ios-wk2/fast/visual-viewport/zoomed-rects-expected.txt	2017-07-20 00:15:08 UTC (rev 219668)
@@ -7,15 +7,15 @@
 JSON.stringify(internals.visualViewportRect()) is {"x":0,"y":0,"width":400,"height":300,"top":0,"right":400,"bottom":300,"left":0}
 
 Scrolled to 475, 525
-JSON.stringify(internals.layoutViewportRect()) is {"x":0,"y":0,"width":800,"height":600,"top":0,"right":800,"bottom":600,"left":0}
+JSON.stringify(internals.layoutViewportRect()) is {"x":75,"y":225,"width":800,"height":600,"top":225,"right":875,"bottom":825,"left":75}
 JSON.stringify(internals.visualViewportRect()) is {"x":475,"y":525,"width":400,"height":300,"top":525,"right":875,"bottom":825,"left":475}
 
 Scrolled to 100, 776
-JSON.stringify(internals.layoutViewportRect()) is {"x":0,"y":0,"width":800,"height":600,"top":0,"right":800,"bottom":600,"left":0}
+JSON.stringify(internals.layoutViewportRect()) is {"x":75,"y":476,"width":800,"height":600,"top":476,"right":875,"bottom":1076,"left":75}
 JSON.stringify(internals.visualViewportRect()) is {"x":100,"y":776,"width":400,"height":300,"top":776,"right":500,"bottom":1076,"left":100}
 
 Scrolled to 50, 300
-JSON.stringify(internals.layoutViewportRect()) is {"x":0,"y":0,"width":800,"height":600,"top":0,"right":800,"bottom":600,"left":0}
+JSON.stringify(internals.layoutViewportRect()) is {"x":50,"y":300,"width":800,"height":600,"top":300,"right":850,"bottom":900,"left":50}
 JSON.stringify(internals.visualViewportRect()) is {"x":50,"y":300,"width":400,"height":300,"top":300,"right":450,"bottom":600,"left":50}
 PASS successfullyParsed is true
 

Modified: trunk/Source/WebCore/ChangeLog (219667 => 219668)


--- trunk/Source/WebCore/ChangeLog	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/ChangeLog	2017-07-20 00:15:08 UTC (rev 219668)
@@ -1,3 +1,96 @@
+2017-07-19  Simon Fraser  <[email protected]>
+
+        getBoundingClientRects not updated for programmatic scrolls
+        https://bugs.webkit.org/show_bug.cgi?id=174538
+        rdar://problem/33049012
+
+        Reviewed by Tim Horton.
+
+        Baidu.com has two event handlers on its <input>, and both query the input location with getBoundingClientRect()
+        and the current pageYOffset (via jQuery), then try to scroll the input to the top of the screen. The bug is that
+        programmatic scrolls did not immediately update the layout viewport rect, so the second call to
+        getBoundingClientRect() would return stale coordinates, triggering an extra scroll.
+
+        To fix this, undo the fix for r219320 which tried to keep getBoundingClientRect() current during unstable scroll
+        updates by adding a shadow layout viewport rect. Instead, almost always update the layout viewport rect on
+        FrameView, even during unstable visible rect updates, but not if content insets are being changed interactively,
+        since changing viewport heights cause problems with bottom-fixed elements. Also, we need to compute a new layout
+        viewport rect in FrameView::updateLayoutViewport() for programmatic scrolls.
+
+        However, always updating the layout viewport triggered issues with the scrolling tree. The scrolling state tree
+        fossilizes layer positions relative to a specific viewport rect, and that relationship has to be maintained.
+        There are code paths that recompute fixed/sticky viewport constraints when the layout viewport has changed but
+        we haven't done layout or recomputed layer positions (e.g. updating viewport-constrained layers via
+        updateScrollCoordinatedLayersAfterFlush()) and in these cases using a new layout viewport for those computations
+        results in an inconsistent scrolling tree.
+
+        Fix this by not updating scrolling constraints every time we have to re-register scrolling nodes.
+        updateScrollCoordinatedLayersAfterFlush() only needs to update the layer on the scrolling node (to handle
+        tiled/non-tiled switches), so make updateScrollCoordinatedLayer() a little more fine-grained, and only update
+        constraints when we've just computed layer geometry. This allows for different scrolling nodes to have
+        constraints computed at different times, with different layout viewports, which happens.
+
+        Two additional fixes were required to make bottom-fixed bars behave correctly.
+
+        First, FrameView::computeLayoutViewportOrigin() had a bug where rounding of half-pixel values would cause it to
+        fall into the if (visualViewport.height() > layoutViewport.height()) clause, but then fail to clamp for
+        rubber-banding.
+        
+        Second, the FrameView::unscaledMaximumScrollPosition() was wrong after zooming on iOS, since it uses visibleSize()
+        which is affected by page scale on iOS only (and the function wants scale-independent values). Fix with a hack that
+        should be cleaned up via webkit.org/b/174648.
+
+        Tested by existing tests.
+
+        * page/FrameView.cpp:
+        (WebCore::FrameView::computeUpdatedLayoutViewportRect):
+        (WebCore::FrameView::computeLayoutViewportOrigin):
+        (WebCore::FrameView::setLayoutViewportOverrideRect):
+        (WebCore::FrameView::updateLayoutViewport):
+        (WebCore::FrameView::unscaledMaximumScrollPosition):
+        (WebCore::FrameView::documentToClientOffset):
+        (WebCore::FrameView::setUnstableLayoutViewportRect): Deleted.
+        * page/FrameView.h:
+        * page/scrolling/AsyncScrollingCoordinator.cpp:
+        (WebCore::AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll):
+        (WebCore::AsyncScrollingCoordinator::reconcileScrollingState):
+        (WebCore::AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions):
+        (WebCore::AsyncScrollingCoordinator::updateNodeLayer):
+        (WebCore::AsyncScrollingCoordinator::updateNodeViewportConstraints):
+        (WebCore::AsyncScrollingCoordinator::updateViewportConstrainedNode): Deleted.
+        * page/scrolling/AsyncScrollingCoordinator.h:
+        * page/scrolling/ScrollingCoordinator.cpp:
+        (WebCore::operator<<):
+        * page/scrolling/ScrollingCoordinator.h:
+        (WebCore::ScrollingCoordinator::reconcileScrollingState):
+        (WebCore::ScrollingCoordinator::updateNodeLayer):
+        (WebCore::ScrollingCoordinator::updateNodeViewportConstraints):
+        (WebCore::ScrollingCoordinator::updateViewportConstrainedNode): Deleted.
+        * page/scrolling/ScrollingStateFixedNode.cpp:
+        (WebCore::ScrollingStateFixedNode::updateConstraints):
+        * page/scrolling/ScrollingStateStickyNode.cpp:
+        (WebCore::ScrollingStateStickyNode::updateConstraints):
+        (WebCore::ScrollingStateStickyNode::reconcileLayerPositionForViewportRect):
+        * page/scrolling/ScrollingTree.cpp:
+        (WebCore::ScrollingTree::commitTreeState):
+        * page/scrolling/mac/ScrollingTreeFixedNode.mm:
+        (WebCore::ScrollingTreeFixedNode::updateLayersAfterAncestorChange):
+        * page/scrolling/mac/ScrollingTreeStickyNode.mm:
+        (WebCore::ScrollingTreeStickyNode::updateLayersAfterAncestorChange):
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::updateGeometry):
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::updateScrollCoordinatedLayersAfterFlush):
+        (WebCore::RenderLayerCompositor::updateBacking):
+        (WebCore::RenderLayerCompositor::fixedRootBackgroundLayerChanged):
+        (WebCore::RenderLayerCompositor::requiresCompositingForPosition):
+        (WebCore::RenderLayerCompositor::updateScrollCoordinatedStatus):
+        (WebCore::RenderLayerCompositor::computeFixedViewportConstraints):
+        (WebCore::RenderLayerCompositor::computeStickyViewportConstraints):
+        (WebCore::RenderLayerCompositor::updateScrollCoordinatedLayer):
+        (WebCore::RenderLayerCompositor::didAddScrollingLayer):
+        * rendering/RenderLayerCompositor.h:
+
 2017-07-19  Megan Gardner  <[email protected]>
 
         Don't write file URLs to iOS Pasteboard

Modified: trunk/Source/WebCore/page/FrameView.cpp (219667 => 219668)


--- trunk/Source/WebCore/page/FrameView.cpp	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/FrameView.cpp	2017-07-20 00:15:08 UTC (rev 219668)
@@ -1828,7 +1828,8 @@
     layoutViewportRect.setSize(constrainedSize.expandedTo(unobscuredContentSize));
         
     LayoutPoint layoutViewportOrigin = computeLayoutViewportOrigin(unobscuredContentRect, stableLayoutViewportOriginMin, stableLayoutViewportOriginMax, layoutViewportRect, StickToViewportBounds);
-        
+
+    // FIXME: Is this equivalent to calling computeLayoutViewportOrigin() with StickToDocumentBounds?
     if (constraint == LayoutViewportConstraint::ConstrainedToDocumentRect) {
         // The max stable layout viewport origin really depends on the size of the layout viewport itself, so we need to adjust the location of the layout viewport one final time to make sure it does not end up out of bounds of the document.
         // Without this adjustment (and with using the non-constrained unobscuredContentRect's size as the size of the layout viewport) the layout viewport can be pushed past the bounds of the document during rubber-banding, and cannot be pushed
@@ -1847,9 +1848,15 @@
     LayoutPoint layoutViewportOrigin = layoutViewport.location();
     bool allowRubberBanding = fixedBehavior == StickToViewportBounds;
 
-    if (visualViewport.width() > layoutViewport.width())
+    if (visualViewport.width() > layoutViewport.width()) {
         layoutViewportOrigin.setX(visualViewport.x());
-    else {
+        if (!allowRubberBanding) {
+            if (layoutViewportOrigin.x() < stableLayoutViewportOriginMin.x())
+                layoutViewportOrigin.setX(stableLayoutViewportOriginMin.x());
+            else if (layoutViewportOrigin.x() > stableLayoutViewportOriginMax.x())
+                layoutViewportOrigin.setX(stableLayoutViewportOriginMax.x());
+        }
+    } else {
         bool rubberbandingAtLeft = allowRubberBanding && visualViewport.x() < stableLayoutViewportOriginMin.x();
         bool rubberbandingAtRight = allowRubberBanding && (visualViewport.maxX() - layoutViewport.width()) > stableLayoutViewportOriginMax.x();
 
@@ -1858,7 +1865,7 @@
 
         if (visualViewport.maxX() > layoutViewport.maxX() || rubberbandingAtRight)
             layoutViewportOrigin.setX(visualViewport.maxX() - layoutViewport.width());
-        
+
         if (!rubberbandingAtLeft && layoutViewportOrigin.x() < stableLayoutViewportOriginMin.x())
             layoutViewportOrigin.setX(stableLayoutViewportOriginMin.x());
         
@@ -1866,9 +1873,15 @@
             layoutViewportOrigin.setX(stableLayoutViewportOriginMax.x());
     }
 
-    if (visualViewport.height() > layoutViewport.height())
+    if (visualViewport.height() > layoutViewport.height()) {
         layoutViewportOrigin.setY(visualViewport.y());
-    else {
+        if (!allowRubberBanding) {
+            if (layoutViewportOrigin.y() < stableLayoutViewportOriginMin.y())
+                layoutViewportOrigin.setY(stableLayoutViewportOriginMin.y());
+            else if (layoutViewportOrigin.y() > stableLayoutViewportOriginMax.y())
+                layoutViewportOrigin.setY(stableLayoutViewportOriginMax.y());
+        }
+    } else {
         bool rubberbandingAtTop = allowRubberBanding && visualViewport.y() < stableLayoutViewportOriginMin.y();
         bool rubberbandingAtBottom = allowRubberBanding && (visualViewport.maxY() - layoutViewport.height()) > stableLayoutViewportOriginMax.y();
 
@@ -1877,10 +1890,10 @@
 
         if (visualViewport.maxY() > layoutViewport.maxY() || rubberbandingAtBottom)
             layoutViewportOrigin.setY(visualViewport.maxY() - layoutViewport.height());
-        
+
         if (!rubberbandingAtTop && layoutViewportOrigin.y() < stableLayoutViewportOriginMin.y())
             layoutViewportOrigin.setY(stableLayoutViewportOriginMin.y());
-        
+
         if (!rubberbandingAtBottom && layoutViewportOrigin.y() > stableLayoutViewportOriginMax.y())
             layoutViewportOrigin.setY(stableLayoutViewportOriginMax.y());
     }
@@ -1906,7 +1919,7 @@
     }
 }
 
-void FrameView::setLayoutViewportOverrideRect(std::optional<LayoutRect> rect)
+void FrameView::setLayoutViewportOverrideRect(std::optional<LayoutRect> rect, TriggerLayoutOrNot layoutTriggering)
 {
     if (rect == m_layoutViewportOverrideRect)
         return;
@@ -1914,20 +1927,16 @@
     LayoutRect oldRect = layoutViewportRect();
     m_layoutViewportOverrideRect = rect;
 
-    LOG_WITH_STREAM(Scrolling, stream << "\nFrameView " << this << " setLayoutViewportOverrideRect() - changing layout viewport from " << oldRect << " to " << m_layoutViewportOverrideRect.value());
+    // Triggering layout on height changes is necessary to make bottom-fixed elements behave correctly.
+    if (oldRect.height() != layoutViewportRect().height())
+        layoutTriggering = TriggerLayoutOrNot::Yes;
 
-    if (oldRect != layoutViewportRect())
+    LOG_WITH_STREAM(Scrolling, stream << "\nFrameView " << this << " setLayoutViewportOverrideRect() - changing override layout viewport from " << oldRect << " to " << m_layoutViewportOverrideRect.value_or(LayoutRect()) << " layoutTriggering " << (layoutTriggering == TriggerLayoutOrNot::Yes ? "yes" : "no"));
+
+    if (oldRect != layoutViewportRect() && layoutTriggering == TriggerLayoutOrNot::Yes)
         setViewportConstrainedObjectsNeedLayout();
 }
 
-void FrameView::setUnstableLayoutViewportRect(std::optional<LayoutRect> rect)
-{
-    if (rect == m_unstableLayoutViewportRect)
-        return;
-
-    m_unstableLayoutViewportRect = rect;
-}
-
 LayoutSize FrameView::baseLayoutViewportSize() const
 {
     return renderView() ? renderView()->size() : size();
@@ -1942,11 +1951,6 @@
     // as a post-layout task.
     if (m_layoutPhase == InViewSizeAdjust)
         return;
-    
-    if (m_layoutViewportOverrideRect) {
-        LOG_WITH_STREAM(Scrolling, stream << "\nFrameView " << this << " updateLayoutViewport() - has layoutViewportOverrideRect" << m_layoutViewportOverrideRect.value());
-        return;
-    }
 
     LayoutRect layoutViewport = layoutViewportRect();
 
@@ -1953,7 +1957,15 @@
     LOG_WITH_STREAM(Scrolling, stream << "\nFrameView " << this << " updateLayoutViewport() totalContentSize " << totalContentsSize() << " unscaledDocumentRect " << (renderView() ? renderView()->unscaledDocumentRect() : IntRect()) << " header height " << headerHeight() << " footer height " << footerHeight() << " fixed behavior " << scrollBehaviorForFixedElements());
     LOG_WITH_STREAM(Scrolling, stream << "layoutViewport: " << layoutViewport);
     LOG_WITH_STREAM(Scrolling, stream << "visualViewport: " << visualViewportRect());
-    LOG_WITH_STREAM(Scrolling, stream << "scroll positions: min: " << unscaledMinimumScrollPosition() << " max: "<< unscaledMaximumScrollPosition());
+    LOG_WITH_STREAM(Scrolling, stream << "stable origins: min: " << minStableLayoutViewportOrigin() << " max: "<< maxStableLayoutViewportOrigin());
+    
+    if (m_layoutViewportOverrideRect) {
+        if (m_inProgrammaticScroll) {
+            LayoutPoint newOrigin = computeLayoutViewportOrigin(visualViewportRect(), minStableLayoutViewportOrigin(), maxStableLayoutViewportOrigin(), layoutViewport, StickToDocumentBounds);
+            setLayoutViewportOverrideRect(LayoutRect(newOrigin, m_layoutViewportOverrideRect.value().size()));
+        }
+        return;
+    }
 
     LayoutPoint newLayoutViewportOrigin = computeLayoutViewportOrigin(visualViewportRect(), minStableLayoutViewportOrigin(), maxStableLayoutViewportOrigin(), layoutViewport, scrollBehaviorForFixedElements());
     if (newLayoutViewportOrigin != m_layoutViewportOrigin) {
@@ -2205,8 +2217,12 @@
     if (RenderView* renderView = this->renderView()) {
         IntRect unscaledDocumentRect = renderView->unscaledDocumentRect();
         unscaledDocumentRect.expand(0, headerHeight() + footerHeight());
-        ScrollPosition maximumPosition = ScrollPosition(unscaledDocumentRect.maxXMaxYCorner() - visibleSize()).expandedTo({ 0, 0 });
-
+        IntSize visibleSize = this->visibleSize();
+#if PLATFORM(IOS)
+        // FIXME: visibleSize() is the unscaled size on macOS, but the scaled size on iOS. This should be consistent. webkit.org/b/174648.
+        visibleSize.scale(visibleContentScaleFactor());
+#endif        
+        ScrollPosition maximumPosition = ScrollPosition(unscaledDocumentRect.maxXMaxYCorner() - visibleSize).expandedTo({ 0, 0 });
         if (frame().isMainFrame() && m_scrollPinningBehavior == PinToTop)
             maximumPosition.setY(unscaledMinimumScrollPosition().y());
 
@@ -4915,12 +4931,7 @@
 
 FloatSize FrameView::documentToClientOffset() const
 {
-    FloatSize clientOrigin;
-    
-    if (frame().settings().visualViewportEnabled())
-        clientOrigin = -toFloatSize(m_unstableLayoutViewportRect ? m_unstableLayoutViewportRect.value().location() : layoutViewportRect().location()); 
-    else
-        clientOrigin = -toFloatSize(visibleContentRect().location());
+    FloatSize clientOrigin = frame().settings().visualViewportEnabled() ? -toFloatSize(layoutViewportRect().location()) : -toFloatSize(visibleContentRect().location());
 
     // Layout and visual viewports are affected by page zoom, so we need to factor that out.
     return clientOrigin.scaled(1 / frame().pageZoomFactor());

Modified: trunk/Source/WebCore/page/FrameView.h (219667 => 219668)


--- trunk/Source/WebCore/page/FrameView.h	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/FrameView.h	2017-07-20 00:15:08 UTC (rev 219668)
@@ -257,11 +257,7 @@
     
     // If set, overrides the default "m_layoutViewportOrigin, size of initial containing block" rect.
     // Used with delegated scrolling (i.e. iOS).
-    WEBCORE_EXPORT void setLayoutViewportOverrideRect(std::optional<LayoutRect>);
-    // If set, overrides m_layoutViewportOverrideRect. Only used during unstable scroll updates, so that "client" coordinates are 
-    // computed with an origin that changes along with the scroll position.
-    // FIXME: This is ugly; would be better to be able to make setLayoutViewportOverrideRect() callable during unstable updates. 
-    WEBCORE_EXPORT void setUnstableLayoutViewportRect(std::optional<LayoutRect>);
+    WEBCORE_EXPORT void setLayoutViewportOverrideRect(std::optional<LayoutRect>, TriggerLayoutOrNot = TriggerLayoutOrNot::Yes);
 
     // These are in document coordinates, unaffected by page scale (but affected by zooming).
     WEBCORE_EXPORT LayoutRect layoutViewportRect() const;
@@ -846,7 +842,6 @@
     
     LayoutPoint m_layoutViewportOrigin;
     std::optional<LayoutRect> m_layoutViewportOverrideRect;
-    std::optional<LayoutRect> m_unstableLayoutViewportRect;
 
     unsigned m_deferSetNeedsLayoutCount;
     bool m_setNeedsLayoutWasDeferred;

Modified: trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp (219667 => 219668)


--- trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp	2017-07-20 00:15:08 UTC (rev 219668)
@@ -341,7 +341,7 @@
     FrameView& frameView = *frameViewPtr;
 
     if (scrollingNodeID == frameView.scrollLayerID()) {
-        reconcileScrollingState(frameView, scrollPosition, layoutViewportOrigin, programmaticScroll, true, scrollingLayerPositionAction);
+        reconcileScrollingState(frameView, scrollPosition, layoutViewportOrigin, programmaticScroll, ViewportRectStability::Stable, scrollingLayerPositionAction);
 
 #if PLATFORM(COCOA)
         if (m_page->expectsWheelEventTriggers()) {
@@ -372,12 +372,12 @@
     }
 }
 
-void AsyncScrollingCoordinator::reconcileScrollingState(FrameView& frameView, const FloatPoint& scrollPosition, const LayoutViewportOriginOrOverrideRect& layoutViewportOriginOrOverrideRect, bool programmaticScroll, bool inStableState, ScrollingLayerPositionAction scrollingLayerPositionAction)
+void AsyncScrollingCoordinator::reconcileScrollingState(FrameView& frameView, const FloatPoint& scrollPosition, const LayoutViewportOriginOrOverrideRect& layoutViewportOriginOrOverrideRect, bool programmaticScroll, ViewportRectStability viewportRectStability, ScrollingLayerPositionAction scrollingLayerPositionAction)
 {
     bool oldProgrammaticScroll = frameView.inProgrammaticScroll();
     frameView.setInProgrammaticScroll(programmaticScroll);
 
-    LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator " << this << " reconcileScrollingState scrollPosition " << scrollPosition << " programmaticScroll " << programmaticScroll << " stable " << inStableState << " " << scrollingLayerPositionAction);
+    LOG_WITH_STREAM(Scrolling, stream << getpid() << " AsyncScrollingCoordinator " << this << " reconcileScrollingState scrollPosition " << scrollPosition << " programmaticScroll " << programmaticScroll << " stability " << viewportRectStability << " " << scrollingLayerPositionAction);
 
     std::optional<FloatRect> layoutViewportRect;
 
@@ -385,20 +385,15 @@
         [&frameView](std::optional<FloatPoint> origin) {
             if (origin)
                 frameView.setBaseLayoutViewportOrigin(LayoutPoint(origin.value()), FrameView::TriggerLayoutOrNot::No);
-        }, [&frameView, &layoutViewportRect, inStableState, visualViewportEnabled = visualViewportEnabled()](std::optional<FloatRect> overrideRect) {
+        }, [&frameView, &layoutViewportRect, viewportRectStability, visualViewportEnabled = visualViewportEnabled()](std::optional<FloatRect> overrideRect) {
             if (!overrideRect)
                 return;
-        
+
             layoutViewportRect = overrideRect;
-            if (visualViewportEnabled) {
-                if (inStableState) {
-                    frameView.setLayoutViewportOverrideRect(LayoutRect(overrideRect.value()));
-                    frameView.setUnstableLayoutViewportRect(std::nullopt);
-                } else
-                    frameView.setUnstableLayoutViewportRect(LayoutRect(layoutViewportRect.value()));
-            }
+            if (visualViewportEnabled && viewportRectStability != ViewportRectStability::ChangingObscuredInsetsInteractively)
+                frameView.setLayoutViewportOverrideRect(LayoutRect(overrideRect.value()), viewportRectStability == ViewportRectStability::Stable ? FrameView::TriggerLayoutOrNot::Yes : FrameView::TriggerLayoutOrNot::No);
 #if PLATFORM(IOS)
-            else if (inStableState)
+            else if (viewportRectStability == ViewportRectStability::Stable)
                 frameView.setCustomFixedPositionLayoutRect(enclosingIntRect(overrideRect.value()));
 #endif
         }
@@ -410,7 +405,7 @@
     frameView.setInProgrammaticScroll(oldProgrammaticScroll);
 
     if (!programmaticScroll && scrollingLayerPositionAction != ScrollingLayerPositionAction::Set) {
-        if (inStableState)
+        if (viewportRectStability == ViewportRectStability::Stable)
             reconcileViewportConstrainedLayerPositions(frameView.rectForFixedPositionLayout(), scrollingLayerPositionAction);
         else if (layoutViewportRect)
             reconcileViewportConstrainedLayerPositions(LayoutRect(layoutViewportRect.value()), scrollingLayerPositionAction);
@@ -509,7 +504,7 @@
     if (!children)
         return;
 
-    LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions for viewport rect " << viewportRect);
+    LOG_WITH_STREAM(Scrolling, stream << getpid() << " AsyncScrollingCoordinator::reconcileViewportConstrainedLayerPositions for viewport rect " << viewportRect);
 
     // FIXME: We'll have to traverse deeper into the tree at some point.
     for (auto& child : *children)
@@ -568,22 +563,29 @@
     }
 }
 
-void AsyncScrollingCoordinator::updateViewportConstrainedNode(ScrollingNodeID nodeID, const ViewportConstraints& constraints, GraphicsLayer* graphicsLayer)
+void AsyncScrollingCoordinator::updateNodeLayer(ScrollingNodeID nodeID, GraphicsLayer* graphicsLayer)
 {
     ScrollingStateNode* node = m_scrollingStateTree->stateNodeForID(nodeID);
     if (!node)
         return;
 
+    node->setLayer(graphicsLayer);
+}
+
+void AsyncScrollingCoordinator::updateNodeViewportConstraints(ScrollingNodeID nodeID, const ViewportConstraints& constraints)
+{
+    ScrollingStateNode* node = m_scrollingStateTree->stateNodeForID(nodeID);
+    if (!node)
+        return;
+
     switch (constraints.constraintType()) {
     case ViewportConstraints::FixedPositionConstraint: {
         ScrollingStateFixedNode& fixedNode = downcast<ScrollingStateFixedNode>(*node);
-        fixedNode.setLayer(graphicsLayer);
         fixedNode.updateConstraints((const FixedPositionViewportConstraints&)constraints);
         break;
     }
     case ViewportConstraints::StickyPositionConstraint: {
         ScrollingStateStickyNode& stickyNode = downcast<ScrollingStateStickyNode>(*node);
-        stickyNode.setLayer(graphicsLayer);
         stickyNode.updateConstraints((const StickyPositionViewportConstraints&)constraints);
         break;
     }

Modified: trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h (219667 => 219668)


--- trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h	2017-07-20 00:15:08 UTC (rev 219668)
@@ -101,12 +101,13 @@
     WEBCORE_EXPORT void detachFromStateTree(ScrollingNodeID) override;
     WEBCORE_EXPORT void clearStateTree() override;
     
-    WEBCORE_EXPORT void updateViewportConstrainedNode(ScrollingNodeID, const ViewportConstraints&, GraphicsLayer*) override;
+    WEBCORE_EXPORT void updateNodeLayer(ScrollingNodeID, GraphicsLayer*) override;
+    WEBCORE_EXPORT void updateNodeViewportConstraints(ScrollingNodeID, const ViewportConstraints&) override;
     
     WEBCORE_EXPORT void updateFrameScrollingNode(ScrollingNodeID, GraphicsLayer* scrollLayer, GraphicsLayer* scrolledContentsLayer, GraphicsLayer* counterScrollingLayer, GraphicsLayer* insetClipLayer, const ScrollingGeometry* = nullptr) override;
     WEBCORE_EXPORT void updateOverflowScrollingNode(ScrollingNodeID, GraphicsLayer* scrollLayer, GraphicsLayer* scrolledContentsLayer, const ScrollingGeometry* = nullptr) override;
     
-    WEBCORE_EXPORT void reconcileScrollingState(FrameView&, const FloatPoint&, const LayoutViewportOriginOrOverrideRect&, bool programmaticScroll, bool inStableState, ScrollingLayerPositionAction) override;
+    WEBCORE_EXPORT void reconcileScrollingState(FrameView&, const FloatPoint&, const LayoutViewportOriginOrOverrideRect&, bool programmaticScroll, ViewportRectStability, ScrollingLayerPositionAction) override;
 
     bool isRubberBandInProgress() const override;
     void setScrollPinningBehavior(ScrollPinningBehavior) override;

Modified: trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp (219667 => 219668)


--- trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp	2017-07-20 00:15:08 UTC (rev 219668)
@@ -31,7 +31,6 @@
 #include "EventNames.h"
 #include "FrameView.h"
 #include "GraphicsLayer.h"
-#include "IntRect.h"
 #include "MainFrame.h"
 #include "Page.h"
 #include "PlatformWheelEvent.h"
@@ -458,4 +457,20 @@
     return ts;
 }
 
+TextStream& operator<<(TextStream& ts, ViewportRectStability stability)
+{
+    switch (stability) {
+    case ViewportRectStability::Stable:
+        ts << "stable";
+        break;
+    case ViewportRectStability::Unstable:
+        ts << "unstable";
+        break;
+    case ViewportRectStability::ChangingObscuredInsetsInteractively:
+        ts << "changing obscured insets interactively";
+        break;
+    }
+    return ts;
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h (219667 => 219668)


--- trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h	2017-07-20 00:15:08 UTC (rev 219668)
@@ -112,6 +112,12 @@
     }
 };
 
+enum class ViewportRectStability {
+    Stable,
+    Unstable,
+    ChangingObscuredInsetsInteractively // This implies Unstable.
+};
+
 class ScrollingCoordinator : public ThreadSafeRefCounted<ScrollingCoordinator> {
 public:
     static Ref<ScrollingCoordinator> create(Page*);
@@ -129,7 +135,7 @@
     virtual void frameViewLayoutUpdated(FrameView&) { }
 
     using LayoutViewportOriginOrOverrideRect = WTF::Variant<std::optional<FloatPoint>, std::optional<FloatRect>>;
-    virtual void reconcileScrollingState(FrameView&, const FloatPoint&, const LayoutViewportOriginOrOverrideRect&, bool /* programmaticScroll */, bool /* inStableState*/, ScrollingLayerPositionAction) { }
+    virtual void reconcileScrollingState(FrameView&, const FloatPoint&, const LayoutViewportOriginOrOverrideRect&, bool /* programmaticScroll */, ViewportRectStability, ScrollingLayerPositionAction) { }
 
     // Should be called whenever the slow repaint objects counter changes between zero and one.
     void frameViewHasSlowRepaintObjectsDidChange(FrameView&);
@@ -159,8 +165,10 @@
     virtual ScrollingNodeID attachToStateTree(ScrollingNodeType, ScrollingNodeID newNodeID, ScrollingNodeID /*parentID*/) { return newNodeID; }
     virtual void detachFromStateTree(ScrollingNodeID) { }
     virtual void clearStateTree() { }
-    virtual void updateViewportConstrainedNode(ScrollingNodeID, const ViewportConstraints&, GraphicsLayer*) { }
 
+    virtual void updateNodeLayer(ScrollingNodeID, GraphicsLayer*) { }
+    virtual void updateNodeViewportConstraints(ScrollingNodeID, const ViewportConstraints&) { }
+
     struct ScrollingGeometry {
         FloatSize scrollableAreaSize;
         FloatSize contentSize;
@@ -235,7 +243,7 @@
     void updateSynchronousScrollingReasonsForAllFrames();
 
     EventTrackingRegions absoluteEventTrackingRegionsForFrame(const Frame&) const;
-    
+
     bool m_forceSynchronousScrollLayerPositionUpdates { false };
 };
 
@@ -242,6 +250,7 @@
 WEBCORE_EXPORT TextStream& operator<<(TextStream&, ScrollableAreaParameters);
 WEBCORE_EXPORT TextStream& operator<<(TextStream&, ScrollingNodeType);
 WEBCORE_EXPORT TextStream& operator<<(TextStream&, ScrollingLayerPositionAction);
+WEBCORE_EXPORT TextStream& operator<<(TextStream&, ViewportRectStability);
 
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/page/scrolling/ScrollingStateFixedNode.cpp (219667 => 219668)


--- trunk/Source/WebCore/page/scrolling/ScrollingStateFixedNode.cpp	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/scrolling/ScrollingStateFixedNode.cpp	2017-07-20 00:15:08 UTC (rev 219668)
@@ -65,7 +65,7 @@
     if (m_constraints == constraints)
         return;
 
-    LOG_WITH_STREAM(Scrolling, stream << "ScrollingStateFixedNode " << scrollingNodeID() << " updateConstraints with viewport rect " << constraints.viewportRectAtLastLayout());
+    LOG_WITH_STREAM(Scrolling, stream << "ScrollingStateFixedNode " << scrollingNodeID() << " updateConstraints with viewport rect " << constraints.viewportRectAtLastLayout() << " layer pos at last layout " << constraints.layerPositionAtLastLayout() << " offset from top " << (constraints.layerPositionAtLastLayout().y() - constraints.viewportRectAtLastLayout().y()));
 
     m_constraints = constraints;
     setPropertyChanged(ViewportConstraints);

Modified: trunk/Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp (219667 => 219668)


--- trunk/Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp	2017-07-20 00:15:08 UTC (rev 219668)
@@ -65,6 +65,8 @@
     if (m_constraints == constraints)
         return;
 
+    LOG_WITH_STREAM(Scrolling, stream << "ScrollingStateStickyNode " << scrollingNodeID() << " updateConstraints with constraining rect " << constraints.constrainingRectAtLastLayout() << " sticky offset " << constraints.stickyOffsetAtLastLayout() << " layer pos at last layout " << constraints.layerPositionAtLastLayout());
+
     m_constraints = constraints;
     setPropertyChanged(ViewportConstraints);
 }
@@ -75,7 +77,7 @@
     if (layer().representsGraphicsLayer()) {
         GraphicsLayer* graphicsLayer = static_cast<GraphicsLayer*>(layer());
 
-        LOG_WITH_STREAM(Compositing, stream << "ScrollingStateStickyNode::reconcileLayerPositionForViewportRect setting position of layer " << graphicsLayer->primaryLayerID() << " to " << position);
+        LOG_WITH_STREAM(Compositing, stream << "ScrollingStateStickyNode " << scrollingNodeID() << " reconcileLayerPositionForViewportRect " << action << " position of layer " << graphicsLayer->primaryLayerID() << " to " << position << " sticky offset " << m_constraints.stickyOffsetAtLastLayout());
         
         switch (action) {
         case ScrollingLayerPositionAction::Set:

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp (219667 => 219668)


--- trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp	2017-07-20 00:15:08 UTC (rev 219668)
@@ -119,6 +119,8 @@
 {
     bool rootStateNodeChanged = scrollingStateTree->hasNewRootStateNode();
     
+    LOG(Scrolling, "\nScrollingTree::commitTreeState");
+    
     ScrollingStateScrollingNode* rootNode = scrollingStateTree->rootStateNode();
     if (rootNode
         && (rootStateNodeChanged

Modified: trunk/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.cpp (219667 => 219668)


--- trunk/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.cpp	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.cpp	2017-07-20 00:15:08 UTC (rev 219668)
@@ -72,16 +72,24 @@
     m_scrollingStateTree->clear();
 }
 
-void ScrollingCoordinatorCoordinatedGraphics::updateViewportConstrainedNode(ScrollingNodeID nodeID, const ViewportConstraints& constraints, GraphicsLayer* graphicsLayer)
+void ScrollingCoordinatorCoordinatedGraphics::updateNodeLayer(ScrollingNodeID nodeID, GraphicsLayer* graphicsLayer)
 {
     ScrollingStateNode* node = m_scrollingStateTree->stateNodeForID(nodeID);
     if (!node)
         return;
 
+    node->setLayer(graphicsLayer);
+}
+
+void AsyncScrollingCoordinator::updateNodeViewportConstraints(ScrollingNodeID nodeID, const ViewportConstraints& constraints)
+{
+    ScrollingStateNode* node = m_scrollingStateTree->stateNodeForID(nodeID);
+    if (!node)
+        return;
+
     switch (constraints.constraintType()) {
     case ViewportConstraints::FixedPositionConstraint: {
         downcast<CoordinatedGraphicsLayer>(*graphicsLayer).setFixedToViewport(true);
-        downcast<ScrollingStateFixedNode>(*node).setLayer(graphicsLayer);
         break;
     }
     case ViewportConstraints::StickyPositionConstraint:

Modified: trunk/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.h (219667 => 219668)


--- trunk/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.h	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/scrolling/coordinatedgraphics/ScrollingCoordinatorCoordinatedGraphics.h	2017-07-20 00:15:08 UTC (rev 219668)
@@ -42,7 +42,8 @@
     void detachFromStateTree(ScrollingNodeID) override;
     void clearStateTree() override;
 
-    void updateViewportConstrainedNode(ScrollingNodeID, const ViewportConstraints&, GraphicsLayer*) override;
+    void updateNodeLayer(ScrollingNodeID, GraphicsLayer*) override;
+    void updateNodeViewportConstraints(ScrollingNodeID, const ViewportConstraints&) override;
 
     void scrollableAreaScrollLayerDidChange(ScrollableArea&) override;
     void willDestroyScrollableArea(ScrollableArea&) override;

Modified: trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeFixedNode.mm (219667 => 219668)


--- trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeFixedNode.mm	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeFixedNode.mm	2017-07-20 00:15:08 UTC (rev 219668)
@@ -28,6 +28,7 @@
 
 #if ENABLE(ASYNC_SCROLLING)
 
+#include "Logging.h"
 #include "ScrollingStateFixedNode.h"
 #include "ScrollingTree.h"
 #include "TextStream.h"
@@ -70,6 +71,9 @@
 void ScrollingTreeFixedNode::updateLayersAfterAncestorChange(const ScrollingTreeNode& changedNode, const FloatRect& fixedPositionRect, const FloatSize& cumulativeDelta)
 {
     FloatPoint layerPosition = m_constraints.layerPositionForViewportRect(fixedPositionRect);
+
+    LOG_WITH_STREAM(Scrolling, stream << "ScrollingTreeFixedNode " << scrollingNodeID() << " updateLayersAfterAncestorChange: new viewport " << fixedPositionRect << " viewportRectAtLastLayout " << m_constraints.viewportRectAtLastLayout() << " last layer pos " << m_constraints.layerPositionAtLastLayout() << " new offset from bottom " << (fixedPositionRect.maxY() - layerPosition.y()));
+
     layerPosition -= cumulativeDelta;
 
     CGRect layerBounds = [m_layer bounds];

Modified: trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeStickyNode.mm (219667 => 219668)


--- trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeStickyNode.mm	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeStickyNode.mm	2017-07-20 00:15:08 UTC (rev 219668)
@@ -28,6 +28,7 @@
 
 #if ENABLE(ASYNC_SCROLLING)
 
+#include "Logging.h"
 #include "ScrollingStateStickyNode.h"
 #include "ScrollingTree.h"
 #include "ScrollingTreeFrameScrollingNode.h"
@@ -82,6 +83,8 @@
         adjustStickyLayer = true;
     }
 
+    LOG_WITH_STREAM(Scrolling, stream << "ScrollingTreeStickyNode " << scrollingNodeID() << " updateLayersAfterAncestorChange: new viewport " << fixedPositionRect << " constrainingRectAtLastLayout " << m_constraints.constrainingRectAtLastLayout() << " last layer pos " << m_constraints.layerPositionAtLastLayout() << " adjustStickyLayer " << adjustStickyLayer);
+
     FloatSize deltaForDescendants = cumulativeDelta;
 
     if (adjustStickyLayer) {

Modified: trunk/Source/WebCore/rendering/RenderLayerBacking.cpp (219667 => 219668)


--- trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2017-07-20 00:15:08 UTC (rev 219668)
@@ -1206,7 +1206,7 @@
     if (subpixelOffsetFromRendererChanged(oldSubpixelOffsetFromRenderer, m_subpixelOffsetFromRenderer, deviceScaleFactor()) && canIssueSetNeedsDisplay())
         setContentsNeedDisplay();
 
-    compositor().updateScrollCoordinatedStatus(m_owningLayer);
+    compositor().updateScrollCoordinatedStatus(m_owningLayer, { RenderLayerCompositor::ScrollingNodeChangeFlags::Layer, RenderLayerCompositor::ScrollingNodeChangeFlags::LayerGeometry });
 }
 
 void RenderLayerBacking::updateAfterDescendants()

Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (219667 => 219668)


--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2017-07-20 00:15:08 UTC (rev 219668)
@@ -492,7 +492,7 @@
 #endif
 
     for (auto* layer : m_scrollCoordinatedLayersNeedingUpdate)
-        updateScrollCoordinatedStatus(*layer);
+        updateScrollCoordinatedStatus(*layer, ScrollingNodeChangeFlags::Layer);
 
     m_scrollCoordinatedLayersNeedingUpdate.clear();
 }
@@ -1024,7 +1024,7 @@
             layer.ensureBacking();
 
             if (layer.isRootLayer() && useCoordinatedScrollingForLayer(layer)) {
-                updateScrollCoordinatedStatus(layer);
+                updateScrollCoordinatedStatus(layer, { ScrollingNodeChangeFlags::Layer, ScrollingNodeChangeFlags::LayerGeometry });
                 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
                     scrollingCoordinator->frameViewRootLayerDidChange(m_renderView.frameView());
 #if ENABLE(RUBBER_BANDING)
@@ -1820,7 +1820,7 @@
         return;
 
     if (m_renderView.layer()->isComposited())
-        updateScrollCoordinatedStatus(*m_renderView.layer());
+        updateScrollCoordinatedStatus(*m_renderView.layer(), ScrollingNodeChangeFlags::Layer);
 }
 
 String RenderLayerCompositor::layerTreeAsText(LayerTreeFlags flags)
@@ -2825,7 +2825,7 @@
     if (!viewBounds.intersects(enclosingIntRect(absoluteBounds))) {
         if (viewportConstrainedNotCompositedReason)
             *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForBoundsOutOfView;
-        LOG_WITH_STREAM(Compositing, stream << "Layer " << &layer << " bounds " << layerBounds << " outside visible rect " << viewBounds);
+        LOG_WITH_STREAM(Compositing, stream << "Layer " << &layer << " bounds " << absoluteBounds << " outside visible rect " << viewBounds);
         return false;
     }
     
@@ -3673,7 +3673,7 @@
         rootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
 }
 
-void RenderLayerCompositor::updateScrollCoordinatedStatus(RenderLayer& layer)
+void RenderLayerCompositor::updateScrollCoordinatedStatus(RenderLayer& layer, OptionSet<ScrollingNodeChangeFlags> changes)
 {
     LayerScrollCoordinationRoles coordinationRoles = 0;
     if (isViewportConstrainedFixedOrStickyLayer(layer))
@@ -3686,7 +3686,7 @@
         if (m_scrollCoordinatedLayers.add(&layer).isNewEntry)
             m_subframeScrollLayersNeedReattach = true;
 
-        updateScrollCoordinatedLayer(layer, coordinationRoles);
+        updateScrollCoordinatedLayer(layer, coordinationRoles, changes);
     } else
         removeFromScrollCoordinatedLayers(layer);
 }
@@ -3709,11 +3709,10 @@
     ASSERT(layer.isComposited());
 
     GraphicsLayer* graphicsLayer = layer.backing()->graphicsLayer();
-    LayoutRect viewportRect = m_renderView.frameView().rectForFixedPositionLayout();
 
     FixedPositionViewportConstraints constraints;
     constraints.setLayerPositionAtLastLayout(graphicsLayer->position());
-    constraints.setViewportRectAtLastLayout(viewportRect);
+    constraints.setViewportRectAtLastLayout(m_renderView.frameView().rectForFixedPositionLayout());
     constraints.setAlignmentOffset(graphicsLayer->pixelAlignmentOffset());
 
     const RenderStyle& style = layer.renderer().style();
@@ -3755,7 +3754,6 @@
     renderer.computeStickyPositionConstraints(constraints, renderer.constrainingRectForStickyPosition());
 
     GraphicsLayer* graphicsLayer = layer.backing()->graphicsLayer();
-
     constraints.setLayerPositionAtLastLayout(graphicsLayer->position());
     constraints.setStickyOffsetAtLastLayout(renderer.stickyPositionOffset());
     constraints.setAlignmentOffset(graphicsLayer->pixelAlignmentOffset());
@@ -3888,7 +3886,7 @@
     scrollingCoordinator->updateFrameScrollingNode(nodeID, m_scrollLayer.get(), m_rootContentLayer.get(), fixedRootBackgroundLayer(), clipLayer());
 }
 
-void RenderLayerCompositor::updateScrollCoordinatedLayer(RenderLayer& layer, LayerScrollCoordinationRoles reasons)
+void RenderLayerCompositor::updateScrollCoordinatedLayer(RenderLayer& layer, LayerScrollCoordinationRoles reasons, OptionSet<ScrollingNodeChangeFlags> changes)
 {
     ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator();
     if (!scrollingCoordinator || !scrollingCoordinator->coordinatesScrollingForFrameView(m_renderView.frameView()))
@@ -3919,7 +3917,7 @@
     ScrollingNodeID parentNodeID = enclosingScrollingNodeID(layer, ExcludeSelf);
     if (!parentNodeID && !isRootLayer)
         return;
-    
+
     // Always call this even if the backing is already attached because the parent may have changed.
     // If a node plays both roles, fixed/sticky is always the ancestor node of scrolling.
     if (reasons & ViewportConstrained) {
@@ -3935,18 +3933,23 @@
         if (!nodeID)
             return;
             
-        LOG(Compositing, "Registering ViewportConstrained scrolling node %" PRIu64 " (layer %" PRIu64 ") as child of %" PRIu64, nodeID, backing->graphicsLayer()->primaryLayerID(), parentNodeID);
+        LOG_WITH_STREAM(Compositing, stream << "Registering ViewportConstrained " << nodeType << " node " << nodeID << " (layer " << backing->graphicsLayer()->primaryLayerID() << ") as child of " << parentNodeID);
 
-        switch (nodeType) {
-        case FixedNode:
-            scrollingCoordinator->updateViewportConstrainedNode(nodeID, computeFixedViewportConstraints(layer), backing->graphicsLayer());
-            break;
-        case StickyNode:
-            scrollingCoordinator->updateViewportConstrainedNode(nodeID, computeStickyViewportConstraints(layer), backing->graphicsLayer());
-            break;
-        case FrameScrollingNode:
-        case OverflowScrollingNode:
-            break;
+        if (changes.contains(ScrollingNodeChangeFlags::Layer))
+            scrollingCoordinator->updateNodeLayer(nodeID, backing->graphicsLayer());
+
+        if (changes.contains(ScrollingNodeChangeFlags::LayerGeometry)) {
+            switch (nodeType) {
+            case FixedNode:
+                scrollingCoordinator->updateNodeViewportConstraints(nodeID, computeFixedViewportConstraints(layer));
+                break;
+            case StickyNode:
+                scrollingCoordinator->updateNodeViewportConstraints(nodeID, computeStickyViewportConstraints(layer));
+                break;
+            case FrameScrollingNode:
+            case OverflowScrollingNode:
+                break;
+            }
         }
         
         parentNodeID = nodeID;
@@ -4090,7 +4093,7 @@
 
 void RenderLayerCompositor::didAddScrollingLayer(RenderLayer& layer)
 {
-    updateScrollCoordinatedStatus(layer);
+    updateScrollCoordinatedStatus(layer, { ScrollingNodeChangeFlags::Layer, ScrollingNodeChangeFlags::LayerGeometry });
 
     if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) {
         // For Coordinated Graphics.

Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.h (219667 => 219668)


--- trunk/Source/WebCore/rendering/RenderLayerCompositor.h	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.h	2017-07-20 00:15:08 UTC (rev 219668)
@@ -279,7 +279,12 @@
 
     ScrollableArea* scrollableAreaForScrollLayerID(ScrollingNodeID) const;
 
-    void updateScrollCoordinatedStatus(RenderLayer&);
+    enum class ScrollingNodeChangeFlags {
+        Layer           = 1 << 0,
+        LayerGeometry   = 1 << 1,
+    };
+
+    void updateScrollCoordinatedStatus(RenderLayer&, OptionSet<ScrollingNodeChangeFlags>);
     void removeFromScrollCoordinatedLayers(RenderLayer&);
 
     void willRemoveScrollingLayerWithBacking(RenderLayer&, RenderLayerBacking&);
@@ -443,7 +448,7 @@
 
     void updateScrollCoordinationForThisFrame(ScrollingNodeID);
     ScrollingNodeID attachScrollingNode(RenderLayer&, ScrollingNodeType, ScrollingNodeID parentNodeID);
-    void updateScrollCoordinatedLayer(RenderLayer&, LayerScrollCoordinationRoles);
+    void updateScrollCoordinatedLayer(RenderLayer&, LayerScrollCoordinationRoles, OptionSet<ScrollingNodeChangeFlags>);
     void detachScrollCoordinatedLayer(RenderLayer&, LayerScrollCoordinationRoles);
     void reattachSubframeScrollLayers();
     

Modified: trunk/Source/WebKit/ChangeLog (219667 => 219668)


--- trunk/Source/WebKit/ChangeLog	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebKit/ChangeLog	2017-07-20 00:15:08 UTC (rev 219668)
@@ -1,3 +1,16 @@
+2017-07-19  Simon Fraser  <[email protected]>
+
+        getBoundingClientRects not updated for programmatic scrolls
+        https://bugs.webkit.org/show_bug.cgi?id=174538
+        rdar://problem/33049012
+
+        Reviewed by Tim Horton.
+        
+        Feed ViewportRectStability and ScrollingLayerPositionAction into reconcileScrollingState().
+
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::updateVisibleContentRects):
+
 2017-07-19  Brady Eidson  <[email protected]>
 
         iBooks sometimes crashes when closing a book.

Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (219667 => 219668)


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2017-07-19 23:59:22 UTC (rev 219667)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2017-07-20 00:15:08 UTC (rev 219668)
@@ -3268,8 +3268,19 @@
     if (!visibleContentRectUpdateInfo.isChangingObscuredInsetsInteractively())
         frameView.setCustomSizeForResizeEvent(expandedIntSize(visibleContentRectUpdateInfo.unobscuredRectInScrollViewCoordinates().size()));
 
-    if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
-        scrollingCoordinator->reconcileScrollingState(frameView, scrollPosition, visibleContentRectUpdateInfo.customFixedPositionRect(), false, m_isInStableState, m_isInStableState ? ScrollingLayerPositionAction::Sync : ScrollingLayerPositionAction::SetApproximate);
+    if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) {
+        ViewportRectStability viewportStability = ViewportRectStability::Stable;
+        ScrollingLayerPositionAction layerAction = ScrollingLayerPositionAction::Sync;
+        
+        if (visibleContentRectUpdateInfo.isChangingObscuredInsetsInteractively()) {
+            viewportStability = ViewportRectStability::ChangingObscuredInsetsInteractively;
+            layerAction = ScrollingLayerPositionAction::SetApproximate;
+        } else if (!m_isInStableState) {
+            viewportStability = ViewportRectStability::Unstable;
+            layerAction = ScrollingLayerPositionAction::SetApproximate;
+        }
+        scrollingCoordinator->reconcileScrollingState(frameView, scrollPosition, visibleContentRectUpdateInfo.customFixedPositionRect(), false, viewportStability, layerAction);
+    }
 }
 
 void WebPage::willStartUserTriggeredZooming()
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to