[iOS WK2] Hit-testing fails when specifying a large top content inset
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 15 Mar 2018 20:50:03 +0000 (20:50 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 15 Mar 2018 20:50:03 +0000 (20:50 +0000)
commit5804c30b08bc3456766f33c40bb64540ee9df9ec
treea9785e7b5adfe95cb5271f3d5acfc56e43dad52a
parent6827b132ab4cd6d30637e4ebe1c1dba26878adab
[iOS WK2] Hit-testing fails when specifying a large top content inset
https://bugs.webkit.org/show_bug.cgi?id=183648
<rdar://problem/38421894>

Reviewed by Tim Horton.

Source/WebKit:

Currently, in the process of computing unobscured content rect in the UI process on iOS, we subtract away parts
of the view that are obscured by insets (e.g. MobileSafari's chrome). The helper method -[WKWebView
_computeContentInset] is intended to compute these obscuring insets around the view, but it takes scroll view
insets into account. This means that if WKWebView's inner scroll view has content insets, we'll end up shrinking
the unobscured content rect as if the insetted region obscures the viewport; this causes visible content on the
page to be uninteractible, since WKWebView erroneously thinks it's obscured.

To address this, we rename _computeContentInset to _computeObscuredInset, and make it _not_ affected by the
scroll view's content insets. From code inspection and testing, all but one of the former call sites of
_computeContentInset really need the obscured inset instead (see below). The one exception, -[WKWebView
_adjustedContentOffset:], takes a scroll position from the page and maps it to a content offset in the inner
UIScrollView (see below for more details).

Tests:  ScrollViewInsetTests.InnerHeightWithLargeTopContentInset
        ScrollViewInsetTests.InnerHeightWithLargeBottomContentInset
        ScrollViewInsetTests.RestoreInitialContentOffsetAfterCrash
        ScrollViewInsetTests.RestoreInitialContentOffsetAfterNavigation

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _setHasCustomContentView:loadedMIMEType:]):
(-[WKWebView _initialContentOffsetForScrollView]):

See -_contentOffsetAdjustedForObscuredInset: below.

(-[WKWebView _contentOffsetAdjustedForObscuredInset:]):

Formerly -_adjustedContentOffset:. -_contentOffsetAdjustedForObscuredInset: no longer takes scroll view content
inset into account, and only cares about insets that obscure the view. This means that the scroll position
(0, 0) in the document now maps to the content offset in the inner UIScrollView, such that the top of the page
is aligned with the top of the viewport.

However, many call sites of -_adjustedContentOffset: were intended to compute the initial, top-left-most content
offset in the scroll view to scroll to when resetting the web view (i.e., they pass in CGPointZero for the
scroll position). An example of this is the scroll position to jump to after web content process termination, or
the scroll position after main frame navigation. In these cases, we actually want to jump to the top of the
scroll view, so we do want to use the version of the computed content insets that accounts for scroll view
insets.

Since these cases are limited to finding the top-left-most scroll position, we pull this out into a separate
helper method (-_initialContentOffsetForScrollView) and replace calls to
`-[self _adjustedContentOffset:CGPointZero]` with this instead.

(-[WKWebView _computedObscuredInset]):

A version of -_computeContentInset that doesn't care about scroll view insets. Used whereever we need to account
for obscured insets rather than the combination of content insets and unobscured insets (e.g.
-_initialContentOffsetForScrollView).

(-[WKWebView _processDidExit]):
(-[WKWebView _didCommitLayerTree:]):
(-[WKWebView _dynamicViewportUpdateChangedTargetToScale:position:nextValidLayerTreeTransactionID:]):
(-[WKWebView _scrollToContentScrollPosition:scrollOrigin:]):
(-[WKWebView scrollViewWillEndDragging:withVelocity:targetContentOffset:]):
(-[WKWebView _updateVisibleContentRects]):
(-[WKWebView _navigationGestureDidBegin]):

In all these places where we inset the view bounds to compute the unobscured region of the viewport, it doesn't
make sense to additionally inset by the scroll view's content insets, since (1) the scroll view's content insets
don't obscure the viewport, and (2) it's perfectly valid for the inner scroll view to have arbitrarily large
content insets.

(-[WKWebView _adjustedContentOffset:]): Deleted.

Renamed to -_contentOffsetAdjustedForObscuredInset:.

* UIProcess/API/Cocoa/WKWebViewInternal.h:
* UIProcess/ios/WKPDFView.mm:
(-[WKPDFView _offsetForPageNumberIndicator]):

Similar to -_scrollToFragment: (see below).

(-[WKPDFView _scrollToFragment:]):

This helper figures out which content offset to scroll to, given the y-origin of a page in a PDF document. If
insets are added to the scroll view, we end up scrolling to the wrong content offset since we'll add the height
of the top content inset (imagine that the top content inset is enormous — then we'll scroll an amount equal to
the top content inset _past_ the point where the y-origin of the page is at the top of the viewport).

Tools:

Adds four new API tests to verify that adding top or bottom content insets to the WKWebView's scroll view does
not cause the DOMWindow's innerHeight to shrink. Currently, doing so would cause the innerHeight to be reported
as (viewHeight - inset.top) or (viewHeight - inset.bottom).

See WebKit ChangeLog for more details.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/ios/ScrollViewInsetTests.mm: Added.
(TestWebKitAPI::TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229641 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h
Source/WebKit/UIProcess/ios/WKPDFView.mm
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/ios/ScrollViewInsetTests.mm [new file with mode: 0644]