Diff
Modified: trunk/LayoutTests/ChangeLog (240138 => 240139)
--- trunk/LayoutTests/ChangeLog 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/LayoutTests/ChangeLog 2019-01-18 04:15:24 UTC (rev 240139)
@@ -1,3 +1,27 @@
+2019-01-17 Wenson Hsieh <wenson_hs...@apple.com>
+
+ [iOS] Content offset jumps erratically when autoscrolling near scroll view content inset areas
+ https://bugs.webkit.org/show_bug.cgi?id=193494
+ <rdar://problem/46859627>
+
+ Reviewed by Simon Fraser and Tim Horton.
+
+ * editing/selection/ios/autoscroll-with-top-content-inset-expected.txt: Added.
+ * editing/selection/ios/autoscroll-with-top-content-inset.html: Added.
+
+ Add a new test to verify that moving the selection by autoscrolling near the top content inset area does not
+ cause the scroll view's content offset to jump.
+
+ * fast/scrolling/ios/scroll-into-view-with-top-content-inset-expected.txt: Added.
+ * fast/scrolling/ios/scroll-into-view-with-top-content-inset.html: Added.
+
+ Add a new test to verify that programmatically scrolling an element that's already visible into view does not
+ scroll away the scroll view's content inset.
+
+ * resources/ui-helper.js:
+ (window.UIHelper.contentOffset):
+ (window.UIHelper):
+
2019-01-17 John Wilander <wilan...@apple.com>
Add infrastructure to enable/disable ITP Debug Mode through Preferences
Added: trunk/LayoutTests/editing/selection/ios/autoscroll-with-top-content-inset-expected.txt (0 => 240139)
--- trunk/LayoutTests/editing/selection/ios/autoscroll-with-top-content-inset-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/selection/ios/autoscroll-with-top-content-inset-expected.txt 2019-01-18 04:15:24 UTC (rev 240139)
@@ -0,0 +1,13 @@
+Select me and drag up.
+
+Verifies that triggering autoscroll near the top of a web view with a top content inset does not cause the scroll view's content offset to jump to 0. This test requires WebKitTestRunner. To verify manually, load this page in a web view that has a scroll view top content inset, and scroll such that the full top content inset area is visible. Check that starting a text selection loupe gesture near the top of the top of the document and dragging upwards does not thrash the scroll view's content offset.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS finalContentOffset.x is 0
+PASS verticalMovementDuringDrag < 1 is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/editing/selection/ios/autoscroll-with-top-content-inset.html (0 => 240139)
--- trunk/LayoutTests/editing/selection/ios/autoscroll-with-top-content-inset.html (rev 0)
+++ trunk/LayoutTests/editing/selection/ios/autoscroll-with-top-content-inset.html 2019-01-18 04:15:24 UTC (rev 240139)
@@ -0,0 +1,51 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true, contentInset.top=100 ] -->
+<html>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<head>
+ <script src=""
+ <script src=""
+ <script src=""
+ <style>
+ body {
+ margin: 0;
+ box-sizing: border-box;
+ border: red 1px solid;
+ }
+
+ #text {
+ font-size: 30px;
+ }
+
+ #console {
+ overflow: scroll;
+ height: 100px;
+ }
+ </style>
+ <script>
+ jsTestIsAsync = true;
+
+ async function run()
+ {
+ await UIHelper.activateAndWaitForInputSessionAt(110, 40);
+ originalContentOffset = await UIHelper.contentOffset();
+ await longPressAndHoldAtPoint(110, 40);
+ await touchAndDragFromPointToPoint(110, 40, 210, 40);
+ await liftUpAtPoint(210, 40);
+ finalContentOffset = await UIHelper.contentOffset();
+ verticalMovementDuringDrag = Math.abs(finalContentOffset.y - originalContentOffset.y);
+
+ shouldBe("finalContentOffset.x", "0");
+ shouldBeTrue("verticalMovementDuringDrag < 1");
+ finishJSTest();
+ }
+ </script>
+</head>
+<body contenteditable _onload_="run()">
+ <p id="text"><strong>Select me and drag up.</strong></p>
+ <p id="description"></p>
+ <p id="console"></p>
+</body>
+<script>
+ description("Verifies that triggering autoscroll near the top of a web view with a top content inset does not cause the scroll view's content offset to jump to 0. This test requires WebKitTestRunner. To verify manually, load this page in a web view that has a scroll view top content inset, and scroll such that the full top content inset area is visible. Check that starting a text selection loupe gesture near the top of the top of the document and dragging upwards does not thrash the scroll view's content offset.");
+</script>
+</html>
Added: trunk/LayoutTests/fast/scrolling/ios/scroll-into-view-with-top-content-inset-expected.txt (0 => 240139)
--- trunk/LayoutTests/fast/scrolling/ios/scroll-into-view-with-top-content-inset-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/scrolling/ios/scroll-into-view-with-top-content-inset-expected.txt 2019-01-18 04:15:24 UTC (rev 240139)
@@ -0,0 +1,13 @@
+Verifies that Element.scrollIntoView() does not scroll away the top content inset if the element is already visible. This test requires WebKitTestRunner.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS originalContentOffset.x is 0
+PASS originalContentOffset.y is -100
+PASS finalContentOffset.x is 0
+PASS finalContentOffset.y is -100
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/scrolling/ios/scroll-into-view-with-top-content-inset.html (0 => 240139)
--- trunk/LayoutTests/fast/scrolling/ios/scroll-into-view-with-top-content-inset.html (rev 0)
+++ trunk/LayoutTests/fast/scrolling/ios/scroll-into-view-with-top-content-inset.html 2019-01-18 04:15:24 UTC (rev 240139)
@@ -0,0 +1,47 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true, contentInset.top=100 ] -->
+<html>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<head>
+ <script src=""
+ <script src=""
+ <style>
+ body {
+ margin: 0;
+ border: red 1px solid;
+ }
+
+ #target {
+ position: absolute;
+ width: 4px;
+ height: 4px;
+ top: 0px;
+ left: 0px;
+ background-color: silver;
+ }
+ </style>
+ <script>
+ jsTestIsAsync = true;
+
+ async function run()
+ {
+ originalContentOffset = await UIHelper.contentOffset();
+ target.scrollIntoView({ block: "nearest", inline: "nearest" });
+ finalContentOffset = await UIHelper.contentOffset();
+
+ shouldBe("originalContentOffset.x", "0");
+ shouldBe("originalContentOffset.y", "-100");
+ shouldBe("finalContentOffset.x", "0");
+ shouldBe("finalContentOffset.y", "-100");
+ finishJSTest();
+ }
+ </script>
+</head>
+<body contenteditable _onload_="run()">
+ <div id="target"></div>
+ <p id="description"></p>
+ <p id="console"></p>
+</body>
+<script>
+ description("Verifies that Element.scrollIntoView() does not scroll away the top content inset if the element is already visible. This test requires WebKitTestRunner.");
+</script>
+</html>
Modified: trunk/LayoutTests/resources/ui-helper.js (240138 => 240139)
--- trunk/LayoutTests/resources/ui-helper.js 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/LayoutTests/resources/ui-helper.js 2019-01-18 04:15:24 UTC (rev 240139)
@@ -554,4 +554,16 @@
const escapedIdentifier = identifier.replace(/`/g, "\\`");
return new Promise(resolve => testRunner.runUIScript(`uiController.setKeyboardInputModeIdentifier(\`${escapedIdentifier}\`)`, resolve));
}
+
+ static contentOffset()
+ {
+ if (!this.isIOS())
+ return Promise.resolve();
+
+ const uiScript = "JSON.stringify([uiController.contentOffsetX, uiController.contentOffsetY])";
+ return new Promise(resolve => testRunner.runUIScript(uiScript, result => {
+ const [offsetX, offsetY] = JSON.parse(result)
+ resolve({ x: offsetX, y: offsetY });
+ }));
+ }
}
Modified: trunk/Source/WebCore/ChangeLog (240138 => 240139)
--- trunk/Source/WebCore/ChangeLog 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Source/WebCore/ChangeLog 2019-01-18 04:15:24 UTC (rev 240139)
@@ -1,3 +1,43 @@
+2019-01-17 Wenson Hsieh <wenson_hs...@apple.com>
+
+ [iOS] Content offset jumps erratically when autoscrolling near scroll view content inset areas
+ https://bugs.webkit.org/show_bug.cgi?id=193494
+ <rdar://problem/46859627>
+
+ Reviewed by Simon Fraser and Tim Horton.
+
+ When computing the content offset to scroll to when revealing a given rect in content coordinates, we currently
+ just use the unobscured content rect. As a result, when scrolling to reveal a rect, we'll clamp the final scroll
+ position such that only content is visible. For example, when asked to reveal the rect `(0, 0, 1, 1)`, we adjust
+ the scroll position to be the origin.
+
+ However, consider the case where a client (e.g. Mail on iOS) has added a content inset to the web view's scroll
+ view. If we're asked to reveal a rect that is outside the content area but within a content inset, we will still
+ end up clamping the scroll position to the unobscured rect. This manifests in a bug where selecting text and
+ autoscrolling in iOS Mail compose while the scroll view is scrolled all the way to the top to reveal the To/Cc/
+ Subject fields causes the content offset to jump to the origin, rather than staying at (0, -topContentInset).
+
+ To fix this, we teach `RenderLayer::scrollRectToVisible` about content insets that are visible. Rather than use
+ the content rects as-is, expand to encompass visible content insets as well. This ensures that revealing a
+ position which is already visible won't cause us to scroll away the content inset area and only show the
+ unobscured rect.
+
+ Tests: editing/selection/ios/autoscroll-with-top-content-inset.html
+ fast/scrolling/ios/scroll-into-view-with-top-content-inset.html
+
+ * page/FrameView.cpp:
+ (WebCore::FrameView::unobscuredContentRectExpandedByContentInsets const):
+
+ Introduce a helper method that expands the unobscured content rect to include surrounding content insets.
+
+ * page/FrameView.h:
+ * page/Page.h:
+ (WebCore::Page::contentInsets const):
+ (WebCore::Page::setContentInsets):
+ * rendering/RenderLayer.cpp:
+ (WebCore::RenderLayer::scrollRectToVisible):
+ (WebCore::RenderLayer::getRectToExpose const):
+
2019-01-17 Truitt Savell <tsav...@apple.com>
Unreviewed, rolling out r240124.
Modified: trunk/Source/WebCore/page/FrameView.cpp (240138 => 240139)
--- trunk/Source/WebCore/page/FrameView.cpp 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Source/WebCore/page/FrameView.cpp 2019-01-18 04:15:24 UTC (rev 240139)
@@ -2014,6 +2014,14 @@
#endif
}
+IntRect FrameView::unobscuredContentRectExpandedByContentInsets() const
+{
+ FloatRect unobscuredContentRect = this->unobscuredContentRect();
+ if (auto* page = frame().page())
+ unobscuredContentRect.expand(page->contentInsets());
+ return IntRect(unobscuredContentRect);
+}
+
bool FrameView::fixedElementsLayoutRelativeToFrame() const
{
return frame().settings().fixedElementsLayoutRelativeToFrame();
Modified: trunk/Source/WebCore/page/FrameView.h (240138 => 240139)
--- trunk/Source/WebCore/page/FrameView.h 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Source/WebCore/page/FrameView.h 2019-01-18 04:15:24 UTC (rev 240139)
@@ -326,6 +326,8 @@
// Static function can be called from another thread.
WEBCORE_EXPORT static LayoutRect rectForViewportConstrainedObjects(const LayoutRect& visibleContentRect, const LayoutSize& totalContentsSize, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame, ScrollBehaviorForFixedElements);
#endif
+
+ IntRect unobscuredContentRectExpandedByContentInsets() const;
bool fixedElementsLayoutRelativeToFrame() const;
Modified: trunk/Source/WebCore/page/Page.h (240138 => 240139)
--- trunk/Source/WebCore/page/Page.h 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Source/WebCore/page/Page.h 2019-01-18 04:15:24 UTC (rev 240139)
@@ -348,6 +348,9 @@
const FloatBoxExtent& obscuredInsets() const { return m_obscuredInsets; }
void setObscuredInsets(const FloatBoxExtent& obscuredInsets) { m_obscuredInsets = obscuredInsets; }
+ const FloatBoxExtent& contentInsets() const { return m_contentInsets; }
+ void setContentInsets(const FloatBoxExtent& insets) { m_contentInsets = insets; }
+
const FloatBoxExtent& unobscuredSafeAreaInsets() const { return m_unobscuredSafeAreaInsets; }
WEBCORE_EXPORT void setUnobscuredSafeAreaInsets(const FloatBoxExtent&);
@@ -792,6 +795,7 @@
float m_topContentInset { 0 };
FloatBoxExtent m_obscuredInsets;
+ FloatBoxExtent m_contentInsets;
FloatBoxExtent m_unobscuredSafeAreaInsets;
FloatBoxExtent m_fullscreenInsets;
Seconds m_fullscreenAutoHideDuration { 0_s };
Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (240138 => 240139)
--- trunk/Source/WebCore/rendering/RenderLayer.cpp 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp 2019-01-18 04:15:24 UTC (rev 240139)
@@ -2551,7 +2551,7 @@
#if !PLATFORM(IOS_FAMILY)
LayoutRect viewRect = frameView.visibleContentRect();
#else
- LayoutRect viewRect = frameView.unobscuredContentRect();
+ LayoutRect viewRect = frameView.unobscuredContentRectExpandedByContentInsets();
#endif
// Move the target rect into "scrollView contents" coordinates.
LayoutRect targetRect = absoluteRect;
@@ -2591,7 +2591,7 @@
}
}
-LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &exposeRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY) const
+LayoutRect RenderLayer::getRectToExpose(const LayoutRect& visibleRect, const LayoutRect& exposeRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY) const
{
FrameView& frameView = renderer().view().frameView();
if (renderer().isRenderView() && insideFixed) {
Modified: trunk/Source/WebKit/ChangeLog (240138 => 240139)
--- trunk/Source/WebKit/ChangeLog 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Source/WebKit/ChangeLog 2019-01-18 04:15:24 UTC (rev 240139)
@@ -1,3 +1,48 @@
+2019-01-17 Wenson Hsieh <wenson_hs...@apple.com>
+
+ [iOS] Content offset jumps erratically when autoscrolling near scroll view content inset areas
+ https://bugs.webkit.org/show_bug.cgi?id=193494
+ <rdar://problem/46859627>
+
+ Reviewed by Simon Fraser and Tim Horton.
+
+ Adds `contentInsets` to `VisibleContentRectUpdateInfo`. This keeps track of the visible content insets
+ surrounding the unobscured content rect. See WebCore ChangeLog for more details.
+
+ * Shared/VisibleContentRectUpdateInfo.cpp:
+ (WebKit::VisibleContentRectUpdateInfo::encode const):
+ (WebKit::VisibleContentRectUpdateInfo::decode):
+ (WebKit::operator<<):
+ * Shared/VisibleContentRectUpdateInfo.h:
+ (WebKit::VisibleContentRectUpdateInfo::VisibleContentRectUpdateInfo):
+ (WebKit::VisibleContentRectUpdateInfo::contentInsets const):
+ (WebKit::operator==):
+ * UIProcess/API/Cocoa/WKWebView.mm:
+ (-[WKWebView _computedObscuredInset]):
+ (-[WKWebView _computedContentInset]):
+ (-[WKWebView _computedUnobscuredSafeAreaInset]):
+
+ We don't care about source compatibility with iOS 10 and below anymore, so we should change these >= iOS 11
+ target checks to simply `PLATFORM(IOS)`.
+
+ (-[WKWebView _updateVisibleContentRects]):
+
+ Compute the visible content insets on all sides of the unobscured content rect. These insets are scaled to
+ content coordinates.
+
+ * UIProcess/ios/WKContentView.h:
+ * UIProcess/ios/WKContentView.mm:
+ (floatBoxExtent):
+
+ Add a helper to convert `UIEdgeInsets` to `WebCore::FloatBoxExtent`, and use it in a few places below.
+
+ (-[WKContentView didUpdateVisibleRect:unobscuredRect:contentInsets:unobscuredRectInScrollViewCoordinates:obscuredInsets:unobscuredSafeAreaInsets:inputViewBounds:scale:minimumScale:inStableState:isChangingObscuredInsetsInteractively:enclosedInScrollableAncestorView:]):
+ (-[WKContentView didUpdateVisibleRect:unobscuredRect:unobscuredRectInScrollViewCoordinates:obscuredInsets:unobscuredSafeAreaInsets:inputViewBounds:scale:minimumScale:inStableState:isChangingObscuredInsetsInteractively:enclosedInScrollableAncestorView:]): Deleted.
+ * WebProcess/WebPage/ios/WebPageIOS.mm:
+ (WebKit::WebPage::updateVisibleContentRects):
+
+ Update the Page's content insets.
+
2019-01-17 Truitt Savell <tsav...@apple.com>
Unreviewed, rolling out r240124.
Modified: trunk/Source/WebKit/Shared/VisibleContentRectUpdateInfo.cpp (240138 => 240139)
--- trunk/Source/WebKit/Shared/VisibleContentRectUpdateInfo.cpp 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Source/WebKit/Shared/VisibleContentRectUpdateInfo.cpp 2019-01-18 04:15:24 UTC (rev 240139)
@@ -37,6 +37,7 @@
{
encoder << m_exposedContentRect;
encoder << m_unobscuredContentRect;
+ encoder << m_contentInsets;
encoder << m_unobscuredContentRectRespectingInputViewBounds;
encoder << m_unobscuredRectInScrollViewCoordinates;
encoder << m_customFixedPositionRect;
@@ -61,6 +62,8 @@
return false;
if (!decoder.decode(result.m_unobscuredContentRect))
return false;
+ if (!decoder.decode(result.m_contentInsets))
+ return false;
if (!decoder.decode(result.m_unobscuredContentRectRespectingInputViewBounds))
return false;
if (!decoder.decode(result.m_unobscuredRectInScrollViewCoordinates))
@@ -114,6 +117,7 @@
ts.dumpProperty("exposedContentRect", info.exposedContentRect());
ts.dumpProperty("unobscuredContentRect", info.unobscuredContentRect());
+ ts.dumpProperty("contentInsets", info.contentInsets());
ts.dumpProperty("unobscuredContentRectRespectingInputViewBounds", info.unobscuredContentRectRespectingInputViewBounds());
ts.dumpProperty("unobscuredRectInScrollViewCoordinates", info.unobscuredRectInScrollViewCoordinates());
ts.dumpProperty("customFixedPositionRect", info.customFixedPositionRect());
Modified: trunk/Source/WebKit/Shared/VisibleContentRectUpdateInfo.h (240138 => 240139)
--- trunk/Source/WebKit/Shared/VisibleContentRectUpdateInfo.h 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Source/WebKit/Shared/VisibleContentRectUpdateInfo.h 2019-01-18 04:15:24 UTC (rev 240139)
@@ -45,9 +45,10 @@
public:
VisibleContentRectUpdateInfo() = default;
- VisibleContentRectUpdateInfo(const WebCore::FloatRect& exposedContentRect, const WebCore::FloatRect& unobscuredContentRect, const WebCore::FloatRect& unobscuredRectInScrollViewCoordinates, const WebCore::FloatRect& unobscuredContentRectRespectingInputViewBounds, const WebCore::FloatRect& customFixedPositionRect, const WebCore::FloatBoxExtent& obscuredInsets, const WebCore::FloatBoxExtent& unobscuredSafeAreaInsets, double scale, bool inStableState, bool isFirstUpdateForNewViewSize, bool isChangingObscuredInsetsInteractively, bool allowShrinkToFit, bool enclosedInScrollableAncestorView, MonotonicTime timestamp, double horizontalVelocity, double verticalVelocity, double scaleChangeRate, uint64_t lastLayerTreeTransactionId)
+ VisibleContentRectUpdateInfo(const WebCore::FloatRect& exposedContentRect, const WebCore::FloatRect& unobscuredContentRect, const WebCore::FloatBoxExtent& contentInsets, const WebCore::FloatRect& unobscuredRectInScrollViewCoordinates, const WebCore::FloatRect& unobscuredContentRectRespectingInputViewBounds, const WebCore::FloatRect& customFixedPositionRect, const WebCore::FloatBoxExtent& obscuredInsets, const WebCore::FloatBoxExtent& unobscuredSafeAreaInsets, double scale, bool inStableState, bool isFirstUpdateForNewViewSize, bool isChangingObscuredInsetsInteractively, bool allowShrinkToFit, bool enclosedInScrollableAncestorView, MonotonicTime timestamp, double horizontalVelocity, double verticalVelocity, double scaleChangeRate, uint64_t lastLayerTreeTransactionId)
: m_exposedContentRect(exposedContentRect)
, m_unobscuredContentRect(unobscuredContentRect)
+ , m_contentInsets(contentInsets)
, m_unobscuredContentRectRespectingInputViewBounds(unobscuredContentRectRespectingInputViewBounds)
, m_unobscuredRectInScrollViewCoordinates(unobscuredRectInScrollViewCoordinates)
, m_customFixedPositionRect(customFixedPositionRect)
@@ -69,6 +70,7 @@
const WebCore::FloatRect& exposedContentRect() const { return m_exposedContentRect; }
const WebCore::FloatRect& unobscuredContentRect() const { return m_unobscuredContentRect; }
+ const WebCore::FloatBoxExtent& contentInsets() const { return m_contentInsets; }
const WebCore::FloatRect& unobscuredRectInScrollViewCoordinates() const { return m_unobscuredRectInScrollViewCoordinates; }
const WebCore::FloatRect& unobscuredContentRectRespectingInputViewBounds() const { return m_unobscuredContentRectRespectingInputViewBounds; }
const WebCore::FloatRect& customFixedPositionRect() const { return m_customFixedPositionRect; }
@@ -97,6 +99,7 @@
private:
WebCore::FloatRect m_exposedContentRect;
WebCore::FloatRect m_unobscuredContentRect;
+ WebCore::FloatBoxExtent m_contentInsets;
WebCore::FloatRect m_unobscuredContentRectRespectingInputViewBounds;
WebCore::FloatRect m_unobscuredRectInScrollViewCoordinates;
WebCore::FloatRect m_customFixedPositionRect; // When visual viewports are enabled, this is the layout viewport.
@@ -121,6 +124,7 @@
return a.scale() == b.scale()
&& a.exposedContentRect() == b.exposedContentRect()
&& a.unobscuredContentRect() == b.unobscuredContentRect()
+ && a.contentInsets() == b.contentInsets()
&& a.unobscuredContentRectRespectingInputViewBounds() == b.unobscuredContentRectRespectingInputViewBounds()
&& a.customFixedPositionRect() == b.customFixedPositionRect()
&& a.obscuredInsets() == b.obscuredInsets()
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (240138 => 240139)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm 2019-01-18 04:15:24 UTC (rev 240139)
@@ -1734,7 +1734,7 @@
if (_haveSetObscuredInsets)
return _obscuredInsets;
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
+#if PLATFORM(IOS)
if (self._safeAreaShouldAffectObscuredInsets)
return UIEdgeInsetsAdd(UIEdgeInsetsZero, self._scrollViewSystemContentInset, self._effectiveObscuredInsetEdgesAffectedBySafeArea);
#endif
@@ -1749,7 +1749,7 @@
UIEdgeInsets insets = [_scrollView contentInset];
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
+#if PLATFORM(IOS)
if (self._safeAreaShouldAffectObscuredInsets)
insets = UIEdgeInsetsAdd(insets, self._scrollViewSystemContentInset, self._effectiveObscuredInsetEdgesAffectedBySafeArea);
#endif
@@ -1762,7 +1762,7 @@
if (_haveSetUnobscuredSafeAreaInsets)
return _unobscuredSafeAreaInsets;
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
+#if PLATFORM(IOS)
if (!self._safeAreaShouldAffectObscuredInsets)
return self.safeAreaInsets;
#endif
@@ -2974,6 +2974,26 @@
CGRect unobscuredRectInContentCoordinates = _frozenUnobscuredContentRect ? _frozenUnobscuredContentRect.value() : [self convertRect:unobscuredRect toView:_contentView.get()];
unobscuredRectInContentCoordinates = CGRectIntersection(unobscuredRectInContentCoordinates, [self _contentBoundsExtendedForRubberbandingWithScale:scaleFactor]);
+ // The following logic computes the extent to which the bottom, top, left and right content insets are visible.
+ auto scrollViewInsets = [_scrollView contentInset];
+ auto scrollViewBounds = [_scrollView bounds];
+ auto scrollViewContentSize = [_scrollView contentSize];
+ auto scrollViewOriginIncludingInset = UIEdgeInsetsInsetRect(scrollViewBounds, computedContentInsetUnadjustedForKeyboard).origin;
+ auto maximumVerticalScrollExtentWithoutRevealingBottomContentInset = scrollViewContentSize.height - CGRectGetHeight(scrollViewBounds);
+ auto maximumHorizontalScrollExtentWithoutRevealingRightContentInset = scrollViewContentSize.width - CGRectGetWidth(scrollViewBounds);
+ auto contentInsets = UIEdgeInsetsZero;
+ if (scrollViewInsets.left > 0 && scrollViewOriginIncludingInset.x < 0)
+ contentInsets.left = std::min(-scrollViewOriginIncludingInset.x, scrollViewInsets.left) / scaleFactor;
+
+ if (scrollViewInsets.top > 0 && scrollViewOriginIncludingInset.y < 0)
+ contentInsets.top = std::min(-scrollViewOriginIncludingInset.y, scrollViewInsets.top) / scaleFactor;
+
+ if (scrollViewInsets.right > 0 && scrollViewOriginIncludingInset.x > maximumHorizontalScrollExtentWithoutRevealingRightContentInset)
+ contentInsets.right = std::min(scrollViewOriginIncludingInset.x - maximumHorizontalScrollExtentWithoutRevealingRightContentInset, scrollViewInsets.right) / scaleFactor;
+
+ if (scrollViewInsets.bottom > 0 && scrollViewOriginIncludingInset.y > maximumVerticalScrollExtentWithoutRevealingBottomContentInset)
+ contentInsets.bottom = std::min(scrollViewOriginIncludingInset.y - maximumVerticalScrollExtentWithoutRevealingBottomContentInset, scrollViewInsets.bottom) / scaleFactor;
+
#if ENABLE(CSS_SCROLL_SNAP) && ENABLE(ASYNC_SCROLLING)
if (inStableState) {
WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy();
@@ -2993,6 +3013,7 @@
[_contentView didUpdateVisibleRect:visibleRectInContentCoordinates
unobscuredRect:unobscuredRectInContentCoordinates
+ contentInsets:contentInsets
unobscuredRectInScrollViewCoordinates:unobscuredRect
obscuredInsets:_obscuredInsets
unobscuredSafeAreaInsets:[self _computedUnobscuredSafeAreaInset]
Modified: trunk/Source/WebKit/UIProcess/ios/WKContentView.h (240138 => 240139)
--- trunk/Source/WebKit/UIProcess/ios/WKContentView.h 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentView.h 2019-01-18 04:15:24 UTC (rev 240139)
@@ -71,6 +71,7 @@
- (void)didUpdateVisibleRect:(CGRect)visibleRect
unobscuredRect:(CGRect)unobscuredRect
+ contentInsets:(UIEdgeInsets)contentInsets
unobscuredRectInScrollViewCoordinates:(CGRect)unobscuredRectInScrollViewCoordinates
obscuredInsets:(UIEdgeInsets)obscuredInsets
unobscuredSafeAreaInsets:(UIEdgeInsets)unobscuredSafeAreaInsets
Modified: trunk/Source/WebKit/UIProcess/ios/WKContentView.mm (240138 => 240139)
--- trunk/Source/WebKit/UIProcess/ios/WKContentView.mm 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentView.mm 2019-01-18 04:15:24 UTC (rev 240139)
@@ -365,6 +365,11 @@
[_textSelectionAssistant deactivateSelection];
}
+static WebCore::FloatBoxExtent floatBoxExtent(UIEdgeInsets insets)
+{
+ return WebCore::FloatBoxExtent(insets.top, insets.right, insets.bottom, insets.left);
+}
+
- (CGRect)_computeUnobscuredContentRectRespectingInputViewBounds:(CGRect)unobscuredContentRect inputViewBounds:(CGRect)inputViewBounds
{
// The input view bounds are in window coordinates, but the unobscured rect is in content coordinates. Account for this by converting input view bounds to content coordinates.
@@ -376,6 +381,7 @@
- (void)didUpdateVisibleRect:(CGRect)visibleContentRect
unobscuredRect:(CGRect)unobscuredContentRect
+ contentInsets:(UIEdgeInsets)contentInsets
unobscuredRectInScrollViewCoordinates:(CGRect)unobscuredRectInScrollViewCoordinates
obscuredInsets:(UIEdgeInsets)obscuredInsets
unobscuredSafeAreaInsets:(UIEdgeInsets)unobscuredSafeAreaInsets
@@ -404,11 +410,12 @@
WebKit::VisibleContentRectUpdateInfo visibleContentRectUpdateInfo(
visibleContentRect,
unobscuredContentRect,
+ floatBoxExtent(contentInsets),
unobscuredRectInScrollViewCoordinates,
unobscuredContentRectRespectingInputViewBounds,
fixedPositionRectForLayout,
- WebCore::FloatBoxExtent(obscuredInsets.top, obscuredInsets.right, obscuredInsets.bottom, obscuredInsets.left),
- WebCore::FloatBoxExtent(unobscuredSafeAreaInsets.top, unobscuredSafeAreaInsets.right, unobscuredSafeAreaInsets.bottom, unobscuredSafeAreaInsets.left),
+ floatBoxExtent(obscuredInsets),
+ floatBoxExtent(unobscuredSafeAreaInsets),
zoomScale,
isStableState,
_sizeChangedSinceLastVisibleContentRectUpdate,
Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (240138 => 240139)
--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm 2019-01-18 04:15:24 UTC (rev 240139)
@@ -3016,6 +3016,7 @@
viewportConfigurationChanged();
frameView.setUnobscuredContentSize(visibleContentRectUpdateInfo.unobscuredContentRect().size());
+ m_page->setContentInsets(visibleContentRectUpdateInfo.contentInsets());
m_page->setObscuredInsets(visibleContentRectUpdateInfo.obscuredInsets());
m_page->setUnobscuredSafeAreaInsets(visibleContentRectUpdateInfo.unobscuredSafeAreaInsets());
m_page->setEnclosedInScrollableAncestorView(visibleContentRectUpdateInfo.enclosedInScrollableAncestorView());
Modified: trunk/Tools/ChangeLog (240138 => 240139)
--- trunk/Tools/ChangeLog 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Tools/ChangeLog 2019-01-18 04:15:24 UTC (rev 240139)
@@ -1,3 +1,35 @@
+2019-01-17 Wenson Hsieh <wenson_hs...@apple.com>
+
+ [iOS] Content offset jumps erratically when autoscrolling near scroll view content inset areas
+ https://bugs.webkit.org/show_bug.cgi?id=193494
+ <rdar://problem/46859627>
+
+ Reviewed by Simon Fraser and Tim Horton.
+
+ Add a new test option to add a top content inset to the test runner's WKWebView's scroll view, and automatically
+ scroll to reveal this top content inset area when beginning the test (i.e., scroll to (0, -topContentInset)).
+
+ * DumpRenderTree/ios/UIScriptControllerIOS.mm:
+ (WTR::UIScriptController::contentOffsetX const):
+ (WTR::UIScriptController::contentOffsetY const):
+ * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
+ * TestRunnerShared/UIScriptContext/UIScriptController.cpp:
+ (WTR::UIScriptController::contentOffsetX const):
+ (WTR::UIScriptController::contentOffsetY const):
+ * TestRunnerShared/UIScriptContext/UIScriptController.h:
+
+ Also add new UIScriptController methods to ask for the content offset of the platform scroll view.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::updateTestOptionsFromTestHeader):
+ * WebKitTestRunner/TestOptions.h:
+ (WTR::TestOptions::hasSameInitializationOptions const):
+ * WebKitTestRunner/ios/TestControllerIOS.mm:
+ (WTR::TestController::platformResetStateToConsistentValues):
+ * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+ (WTR::UIScriptController::contentOffsetX const):
+ (WTR::UIScriptController::contentOffsetY const):
+
2019-01-17 Truitt Savell <tsav...@apple.com>
Unreviewed, rolling out r240124.
Modified: trunk/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm (240138 => 240139)
--- trunk/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm 2019-01-18 04:15:24 UTC (rev 240139)
@@ -211,6 +211,16 @@
return contentOffset;
}
+double UIScriptController::contentOffsetX() const
+{
+ return [gWebScrollView contentOffset].x;
+}
+
+double UIScriptController::contentOffsetY() const
+{
+ return [gWebScrollView contentOffset].y;
+}
+
void UIScriptController::scrollToOffset(long x, long y)
{
[gWebScrollView setContentOffset:contentOffsetBoundedInValidRange(gWebScrollView, CGPointMake(x, y)) animated:YES];
Modified: trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl (240138 => 240139)
--- trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl 2019-01-18 04:15:24 UTC (rev 240139)
@@ -231,6 +231,9 @@
void resignFirstResponder();
+ readonly attribute double contentOffsetX;
+ readonly attribute double contentOffsetY;
+
void scrollToOffset(long x, long y); // Initiate an animated scroll in the UI process.
attribute object didEndScrollingCallback;
Modified: trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp (240138 => 240139)
--- trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp 2019-01-18 04:15:24 UTC (rev 240139)
@@ -336,6 +336,16 @@
return nullptr;
}
+double UIScriptController::contentOffsetX() const
+{
+ return 0;
+}
+
+double UIScriptController::contentOffsetY() const
+{
+ return 0;
+}
+
void UIScriptController::scrollToOffset(long x, long y)
{
}
Modified: trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h (240138 => 240139)
--- trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h 2019-01-18 04:15:24 UTC (rev 240139)
@@ -113,6 +113,9 @@
JSObjectRef contentsOfUserInterfaceItem(JSStringRef) const;
void overridePreference(JSStringRef preference, JSStringRef value);
+ double contentOffsetX() const;
+ double contentOffsetY() const;
+
void scrollToOffset(long x, long y);
void immediateScrollToOffset(long x, long y);
Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (240138 => 240139)
--- trunk/Tools/WebKitTestRunner/TestController.cpp 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp 2019-01-18 04:15:24 UTC (rev 240139)
@@ -1266,6 +1266,8 @@
testOptions.editable = parseBooleanTestHeaderValue(value);
else if (key == "enableUndoManagerAPI")
testOptions.enableUndoManagerAPI = parseBooleanTestHeaderValue(value);
+ else if (key == "contentInset.top")
+ testOptions.contentInsetTop = std::stod(value);
pairStart = pairEnd + 1;
}
}
Modified: trunk/Tools/WebKitTestRunner/TestOptions.h (240138 => 240139)
--- trunk/Tools/WebKitTestRunner/TestOptions.h 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Tools/WebKitTestRunner/TestOptions.h 2019-01-18 04:15:24 UTC (rev 240139)
@@ -69,6 +69,8 @@
bool editable { false };
bool enableUndoManagerAPI { false };
+ double contentInsetTop { 0 };
+
float deviceScaleFactor { 1 };
Vector<String> overrideLanguages;
std::string applicationManifest;
@@ -113,7 +115,8 @@
|| shouldIgnoreMetaViewport != options.shouldIgnoreMetaViewport
|| enableEditableImages != options.enableEditableImages
|| editable != options.editable
- || enableUndoManagerAPI != options.enableUndoManagerAPI)
+ || enableUndoManagerAPI != options.enableUndoManagerAPI
+ || contentInsetTop != options.contentInsetTop)
return false;
if (experimentalFeatures != options.experimentalFeatures)
Modified: trunk/Tools/WebKitTestRunner/ios/TestControllerIOS.mm (240138 => 240139)
--- trunk/Tools/WebKitTestRunner/ios/TestControllerIOS.mm 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Tools/WebKitTestRunner/ios/TestControllerIOS.mm 2019-01-18 04:15:24 UTC (rev 240139)
@@ -132,7 +132,8 @@
UIScrollView *scrollView = webView.scrollView;
[scrollView _removeAllAnimations:YES];
[scrollView setZoomScale:1 animated:NO];
- [scrollView setContentOffset:CGPointZero];
+ scrollView.contentInset = UIEdgeInsetsMake(options.contentInsetTop, 0, 0, 0);
+ scrollView.contentOffset = CGPointMake(0, -options.contentInsetTop);
if (webView.interactingWithFormControl)
shouldRestoreFirstResponder = [webView resignFirstResponder];
Modified: trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm (240138 => 240139)
--- trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm 2019-01-18 02:11:44 UTC (rev 240138)
+++ trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm 2019-01-18 04:15:24 UTC (rev 240139)
@@ -487,6 +487,18 @@
return contentOffset;
}
+double UIScriptController::contentOffsetX() const
+{
+ TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
+ return webView.scrollView.contentOffset.x;
+}
+
+double UIScriptController::contentOffsetY() const
+{
+ TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
+ return webView.scrollView.contentOffset.y;
+}
+
void UIScriptController::scrollToOffset(long x, long y)
{
TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();