WKWebView inside a UICollectionView flashes when items are inserted above it
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Feb 2017 21:09:40 +0000 (21:09 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Feb 2017 21:09:40 +0000 (21:09 +0000)
commitc58869875849b492ad34a5aed84d52b58388a72f
tree164ac6d877dd6ae5025efbccdb25c778282829aa
parent26cc593c381d6cec1717ef0791eb82b2466b7e76
WKWebView inside a UICollectionView flashes when items are inserted above it
https://bugs.webkit.org/show_bug.cgi?id=168376
<rdar://problem/29322051>

Reviewed by Simon Fraser.

Previously, we would immediately send visible content rect updates
whenever we scrolled, or our frame or bounds changed, or ... a whole
bunch of other things. This message would be immediately sent to the
Web Content process, and coalesced at the whims of the Web Content process
main thread. However, if we received multiple such updates within the
same runloop cycle in the UI process, the Web Content process could
send back layer tree commits for intermediate states that would
never make it to the screen.

In the UICollectionView case, UIKit would first scroll to the new location
(potentially putting the WKWebView totally off-screen), and then update
our frame (back on screen), and we would get two layer tree commits;
one, with less tile coverage than needed to cover the area, and another
with full coverage.

Instead, wait until just before we commit the UI-side layer tree (and
thus everyone is done moving things around) to push the new visible
rect info to the Web Content process.

So far, I have not found a way to test that reliably fails before
and reliably passes after without adding a ton of supporting code to WebKit.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _didInvokeUIScrollViewDelegateCallback]):
(-[WKWebView _didCommitLayerTree:]):
(-[WKWebView _didFinishScrolling]):
(-[WKWebView scrollViewDidScroll:]):
(-[WKWebView scrollViewDidZoom:]):
(-[WKWebView scrollViewDidEndZooming:withView:atScale:]):
(-[WKWebView _scrollViewDidInterruptDecelerating:]):
(-[WKWebView _didScroll]):
(-[WKWebView _enclosingScrollerScrollingEnded:]):
(-[WKWebView _frameOrBoundsChanged]):
(-[WKWebView _scheduleVisibleContentRectUpdate]):
(-[WKWebView _scrollViewIsInStableState:]):
(-[WKWebView _scheduleVisibleContentRectUpdateAfterScrollInView:]):
(-[WKWebView _keyboardChangedWithInfo:adjustScrollView:]):
(-[WKWebView _setObscuredInsets:]):
(-[WKWebView _endInteractiveObscuredInsetsChange]):
(-[WKWebView _beginAnimatedResizeWithUpdates:]):
(-[WKWebView _endAnimatedResize]):
(-[WKWebView _updateVisibleContentRects]): Deleted.
(-[WKWebView _updateVisibleContentRectAfterScrollInView:]): Deleted.
* UIProcess/API/Cocoa/WKWebViewInternal.h:
* UIProcess/ios/WKContentView.mm:
(-[WKContentView _didCommitLayerTree:]):
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _startAssistingNode:userIsInteracting:blurPreviousNode:userObject:]):
(-[WKContentView _stopAssistingNode]):
* UIProcess/ios/WKScrollView.mm:
(-[WKScrollView setContentInset:]):
Have existing callers of _updateVisibleContentRect* instead call
_scheduleVisibleContentRectUpdate*.

In _scheduleVisibleContentRectUpdate, schedule a pre-commit callback
in which we will compute the new visible content rect information
and send it to the Web Content process.

Keep track of the stable state of the scroll view which most recently
scheduled an update, and use that to inform _updateVisibleContentRects.
This matches the previous behavior where the updates might get coalesced
in the Web Content process, and the most recent update wins.

Make a few callers of _updateVisibleContentRectAfterScrollInView
that passed in our scroll view just use _scheduleVisibleContentRectUpdate instead.

* WebKitTestRunner/cocoa/TestRunnerWKWebView.mm:
(-[TestRunnerWKWebView _setStableStateOverride:]):
Update the one external caller of this internal method...

* DumpRenderTree/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::doAfterVisibleContentRectUpdate):
* DumpRenderTree/mac/UIScriptControllerMac.mm:
(WTR::UIScriptController::doAfterVisibleContentRectUpdate):
* TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
* TestRunnerShared/UIScriptContext/UIScriptController.cpp:
(WTR::UIScriptController::doAfterVisibleContentRectUpdate):
* TestRunnerShared/UIScriptContext/UIScriptController.h:
* WebKitTestRunner/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::doAfterVisibleContentRectUpdate):
* WebKitTestRunner/mac/UIScriptControllerMac.mm:
(WTR::UIScriptController::doAfterVisibleContentRectUpdate):
Expose doAfterVisibleContentRectUpdate to DRT and WKTR. It is called
back after we dispatch a visible content rect update from the UI process
to the Web Content process, so any messages sent from the block will arrive
after the visible content rect update.

* scrollingcoordinator/ios/sync-layer-positions-after-scroll.html:
* scrollingcoordinator/ios/sync-layer-positions-after-scroll-expected.txt:
Make use of doAfterVisibleContentRectUpdate; we previously were
guaranteed by message ordering that our uiScriptComplete message
would arrive after the visible content rect update, but that is
no longer the case.

Also, adjust to have a initial scale and flexible viewport in order
to work around https://bugs.webkit.org/show_bug.cgi?id=168403.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212459 268f45cc-cd09-0410-ab3c-d52691b4dbfc
19 files changed:
LayoutTests/ChangeLog
LayoutTests/scrollingcoordinator/ios/sync-layer-positions-after-scroll-expected.txt
LayoutTests/scrollingcoordinator/ios/sync-layer-positions-after-scroll.html
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/API/Cocoa/WKWebViewInternal.h
Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h
Source/WebKit2/UIProcess/ios/WKContentView.mm
Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm
Source/WebKit2/UIProcess/ios/WKScrollView.mm
Tools/ChangeLog
Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm
Tools/DumpRenderTree/mac/UIScriptControllerMac.mm
Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl
Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp
Tools/TestRunnerShared/UIScriptContext/UIScriptController.h
Tools/WebKitTestRunner/cocoa/TestRunnerWKWebView.mm
Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm
Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm