[iOS WK2] WKWebViews should consult ancestor UIScrollViews to determine tiling area
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 9 Apr 2016 01:18:46 +0000 (01:18 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 9 Apr 2016 01:18:46 +0000 (01:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=156429
rdar://problem/25455111

Reviewed by Tim Horton.

When a WKWebView is expanded to full size, then embedded in UIScrollView, it would
create huge tiles that cover the entire view area (since it considered itself non-scrollable).

Fix to always use 512x512 tiles in this configuration, and to adjust the tile coverage
for the area exposed through the enclosing UIScrollView.

Source/WebCore:

* loader/HistoryController.cpp:
(WebCore::HistoryController::saveScrollPositionAndViewStateToItem): setObscuredInset()
moved from FrameView to Page.
* page/FrameView.cpp:
(WebCore::FrameView::adjustTiledBackingScrollability): If we're clipped by an ancestor scrollView,
just assume we're scrollable on both axes.
* page/Page.h:
(WebCore::Page::obscuredInset):
(WebCore::Page::setObscuredInset):
(WebCore::Page::enclosedInScrollView):
(WebCore::Page::setEnclosedInScrollView):
* platform/ScrollView.h:
(WebCore::ScrollView::platformObscuredInset): Deleted.
(WebCore::ScrollView::platformSetObscuredInset): Deleted.

Source/WebKit2:

* Shared/VisibleContentRectUpdateInfo.cpp: Add enclosedInScrollView(), which is used to
trigger normal-sized tiles.
(WebKit::VisibleContentRectUpdateInfo::encode):
(WebKit::VisibleContentRectUpdateInfo::decode):
* Shared/VisibleContentRectUpdateInfo.h:
(WebKit::VisibleContentRectUpdateInfo::VisibleContentRectUpdateInfo):
(WebKit::VisibleContentRectUpdateInfo::enclosedInScrollView):
(WebKit::operator==):
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _didInvokeUIScrollViewDelegateCallback]): Pass our scrollView.
(-[WKWebView _didFinishScrolling]):
(-[WKWebView scrollViewDidScroll:]):
(-[WKWebView scrollViewDidZoom:]):
(-[WKWebView scrollViewDidEndZooming:withView:atScale:]):
(-[WKWebView _scrollViewDidInterruptDecelerating:]):
(-[WKWebView _visibleRectInEnclosingScrollView:]):
(-[WKWebView _visibleContentRect]): Compute the exposed part of the content relative
to the WKWebView, then intersect with the exposed part via any ancestor UIScrollView.
(-[WKWebView _didScroll]): This is called by UIKit when some ancestor UIScrollView scrolls.
However, we don't get all the UIScrollView delegate callbacks, so have to use a timer to
trigger a call to -_updateVisibleContentRects when we're in a stable state.
(-[WKWebView _enclosingScrollerScrollingEnded:]):
(-[WKWebView _frameOrBoundsChanged]):
(-[WKWebView _updateVisibleContentRects]):
(-[WKWebView _updateVisibleContentRectAfterScrollInView:]): Get the stable state from the
scroll view that the user is interacting with.
(-[WKWebView _updateContentRectsWithState:]):
* UIProcess/API/Cocoa/WKWebViewInternal.h:
* UIProcess/WebPageProxy.h: Rather than pass a bazillion arguments through updateVisibleContentRects(), just
pass the VisibleContentRectUpdateInfo struct.
* UIProcess/ios/WKContentView.h:
* UIProcess/ios/WKContentView.mm:
(-[WKContentView didUpdateVisibleRect:unobscuredRect:unobscuredRectInScrollViewCoordinates:obscuredInset:scale:minimumScale:inStableState:isChangingObscuredInsetsInteractively:enclosedInScrollView:]):
(-[WKContentView didUpdateVisibleRect:unobscuredRect:unobscuredRectInScrollViewCoordinates:obscuredInset:scale:minimumScale:inStableState:isChangingObscuredInsetsInteractively:]): Deleted.
* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::updateVisibleContentRects):
* UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.mm:
(WebKit::RemoteLayerTreeDrawingAreaProxy::RemoteLayerTreeDrawingAreaProxy):
(WebKit::RemoteLayerTreeDrawingAreaProxy::indicatorLocation):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::updatePreferences):
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::updateVisibleContentRects):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@199259 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
Source/WebCore/ChangeLog
Source/WebCore/loader/HistoryController.cpp
Source/WebCore/page/FrameView.cpp
Source/WebCore/page/Page.h
Source/WebCore/platform/ScrollView.h
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/VisibleContentRectUpdateInfo.cpp
Source/WebKit2/Shared/VisibleContentRectUpdateInfo.h
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/API/Cocoa/WKWebViewInternal.h
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/ios/WKContentView.h
Source/WebKit2/UIProcess/ios/WKContentView.mm
Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm
Source/WebKit2/UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.mm
Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm

index e4bb878..ef17057 100644 (file)
@@ -1,3 +1,32 @@
+2016-04-08  Simon Fraser  <simon.fraser@apple.com>
+
+        [iOS WK2] WKWebViews should consult ancestor UIScrollViews to determine tiling area
+        https://bugs.webkit.org/show_bug.cgi?id=156429
+        rdar://problem/25455111
+
+        Reviewed by Tim Horton.
+
+        When a WKWebView is expanded to full size, then embedded in UIScrollView, it would
+        create huge tiles that cover the entire view area (since it considered itself non-scrollable).
+
+        Fix to always use 512x512 tiles in this configuration, and to adjust the tile coverage
+        for the area exposed through the enclosing UIScrollView.
+
+        * loader/HistoryController.cpp:
+        (WebCore::HistoryController::saveScrollPositionAndViewStateToItem): setObscuredInset()
+        moved from FrameView to Page.
+        * page/FrameView.cpp:
+        (WebCore::FrameView::adjustTiledBackingScrollability): If we're clipped by an ancestor scrollView,
+        just assume we're scrollable on both axes.
+        * page/Page.h:
+        (WebCore::Page::obscuredInset):
+        (WebCore::Page::setObscuredInset):
+        (WebCore::Page::enclosedInScrollView):
+        (WebCore::Page::setEnclosedInScrollView):
+        * platform/ScrollView.h:
+        (WebCore::ScrollView::platformObscuredInset): Deleted.
+        (WebCore::ScrollView::platformSetObscuredInset): Deleted.
+
 2016-04-08  Joseph Pecoraro  <pecoraro@apple.com>
 
         [iOS Simulator] Build failure (property 'contentsFormat' not found on object of type 'LegacyTileLayer *')
index 767805f..3303d33 100644 (file)
@@ -79,15 +79,19 @@ void HistoryController::saveScrollPositionAndViewStateToItem(HistoryItem* item)
         item->setScrollPosition(frameView->cachedScrollPosition());
     else
         item->setScrollPosition(frameView->scrollPosition());
+
 #if PLATFORM(IOS)
     item->setExposedContentRect(frameView->exposedContentRect());
     item->setUnobscuredContentRect(frameView->unobscuredContentRect());
-    item->setObscuredInset(frameView->platformObscuredInset());
 #endif
 
     Page* page = m_frame.page();
-    if (page && m_frame.isMainFrame())
+    if (page && m_frame.isMainFrame()) {
         item->setPageScaleFactor(page->pageScaleFactor() / page->viewScaleFactor());
+#if PLATFORM(IOS)
+        item->setObscuredInset(page->obscuredInset());
+#endif
+    }
 
     // FIXME: It would be great to work out a way to put this code in WebCore instead of calling through to the client.
     m_frame.loader().client().saveViewStateToItem(item);
index 15cdc90..671ba5e 100644 (file)
@@ -2485,6 +2485,11 @@ void FrameView::adjustTiledBackingScrollability()
     bool verticallyScrollable;
     bool clippedByAncestorView = static_cast<bool>(m_viewExposedRect);
 
+#if PLATFORM(IOS)
+    if (Page* page = frame().page())
+        clippedByAncestorView |= page->enclosedInScrollView();
+#endif
+
     if (delegatesScrolling()) {
         IntSize documentSize = contentsSize();
         IntSize visibleSize = this->visibleSize();
index 505625a..90af43e 100644 (file)
@@ -293,7 +293,15 @@ public:
 
     float topContentInset() const { return m_topContentInset; }
     WEBCORE_EXPORT void setTopContentInset(float);
+
+#if PLATFORM(IOS)
+    FloatSize obscuredInset() const { return m_obscuredInset; }
+    void setObscuredInset(FloatSize inset) { m_obscuredInset = inset; }
     
+    bool enclosedInScrollView() const { return m_enclosedInScrollView; }
+    void setEnclosedInScrollView(bool f) { m_enclosedInScrollView = f; }
+#endif
+
 #if ENABLE(IOS_TEXT_AUTOSIZING)
     float textAutosizingWidth() const { return m_textAutosizingWidth; }
     void setTextAutosizingWidth(float textAutosizingWidth) { m_textAutosizingWidth = textAutosizingWidth; }
@@ -599,7 +607,13 @@ private:
     float m_viewScaleFactor { 1 };
 
     float m_topContentInset;
-    
+
+#if PLATFORM(IOS)
+    // This is only used for history scroll position restoration.
+    FloatSize m_obscuredInset;
+    bool m_enclosedInScrollView { false };
+#endif
+
 #if ENABLE(IOS_TEXT_AUTOSIZING)
     float m_textAutosizingWidth;
 #endif
index 1ac6baf..4f805a2 100644 (file)
@@ -378,11 +378,6 @@ public:
 
     WEBCORE_EXPORT void scrollOffsetChangedViaPlatformWidget(const ScrollOffset& oldOffset, const ScrollOffset& newOffset);
 
-#if PLATFORM(IOS)
-    FloatSize platformObscuredInset() const { return m_obscuredInset; }
-    void platformSetObscuredInset(FloatSize inset) { m_obscuredInset = inset; }
-#endif
-
 protected:
     ScrollView();
 
@@ -458,7 +453,6 @@ private:
     FloatRect m_exposedContentRect;
     FloatSize m_unobscuredContentSize;
     // This is only used for history scroll position restoration.
-    FloatSize m_obscuredInset;
 #else
     IntRect m_fixedVisibleContentRect;
 #endif
index 62427e7..6aecdcc 100644 (file)
@@ -1,3 +1,61 @@
+2016-04-08  Simon Fraser  <simon.fraser@apple.com>
+
+        [iOS WK2] WKWebViews should consult ancestor UIScrollViews to determine tiling area
+        https://bugs.webkit.org/show_bug.cgi?id=156429
+        rdar://problem/25455111
+
+        Reviewed by Tim Horton.
+
+        When a WKWebView is expanded to full size, then embedded in UIScrollView, it would
+        create huge tiles that cover the entire view area (since it considered itself non-scrollable).
+
+        Fix to always use 512x512 tiles in this configuration, and to adjust the tile coverage
+        for the area exposed through the enclosing UIScrollView.
+
+        * Shared/VisibleContentRectUpdateInfo.cpp: Add enclosedInScrollView(), which is used to
+        trigger normal-sized tiles.
+        (WebKit::VisibleContentRectUpdateInfo::encode):
+        (WebKit::VisibleContentRectUpdateInfo::decode):
+        * Shared/VisibleContentRectUpdateInfo.h:
+        (WebKit::VisibleContentRectUpdateInfo::VisibleContentRectUpdateInfo):
+        (WebKit::VisibleContentRectUpdateInfo::enclosedInScrollView):
+        (WebKit::operator==):
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _didInvokeUIScrollViewDelegateCallback]): Pass our scrollView.
+        (-[WKWebView _didFinishScrolling]):
+        (-[WKWebView scrollViewDidScroll:]):
+        (-[WKWebView scrollViewDidZoom:]):
+        (-[WKWebView scrollViewDidEndZooming:withView:atScale:]):
+        (-[WKWebView _scrollViewDidInterruptDecelerating:]):
+        (-[WKWebView _visibleRectInEnclosingScrollView:]):
+        (-[WKWebView _visibleContentRect]): Compute the exposed part of the content relative
+        to the WKWebView, then intersect with the exposed part via any ancestor UIScrollView.
+        (-[WKWebView _didScroll]): This is called by UIKit when some ancestor UIScrollView scrolls.
+        However, we don't get all the UIScrollView delegate callbacks, so have to use a timer to
+        trigger a call to -_updateVisibleContentRects when we're in a stable state.
+        (-[WKWebView _enclosingScrollerScrollingEnded:]):
+        (-[WKWebView _frameOrBoundsChanged]):
+        (-[WKWebView _updateVisibleContentRects]):
+        (-[WKWebView _updateVisibleContentRectAfterScrollInView:]): Get the stable state from the
+        scroll view that the user is interacting with.
+        (-[WKWebView _updateContentRectsWithState:]):
+        * UIProcess/API/Cocoa/WKWebViewInternal.h:
+        * UIProcess/WebPageProxy.h: Rather than pass a bazillion arguments through updateVisibleContentRects(), just
+        pass the VisibleContentRectUpdateInfo struct.
+        * UIProcess/ios/WKContentView.h:
+        * UIProcess/ios/WKContentView.mm:
+        (-[WKContentView didUpdateVisibleRect:unobscuredRect:unobscuredRectInScrollViewCoordinates:obscuredInset:scale:minimumScale:inStableState:isChangingObscuredInsetsInteractively:enclosedInScrollView:]):
+        (-[WKContentView didUpdateVisibleRect:unobscuredRect:unobscuredRectInScrollViewCoordinates:obscuredInset:scale:minimumScale:inStableState:isChangingObscuredInsetsInteractively:]): Deleted.
+        * UIProcess/ios/WebPageProxyIOS.mm:
+        (WebKit::WebPageProxy::updateVisibleContentRects):
+        * UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.mm:
+        (WebKit::RemoteLayerTreeDrawingAreaProxy::RemoteLayerTreeDrawingAreaProxy):
+        (WebKit::RemoteLayerTreeDrawingAreaProxy::indicatorLocation):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::updatePreferences):
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::updateVisibleContentRects):
+
 2016-04-08  Joseph Pecoraro  <pecoraro@apple.com>
 
         [iOS Simulator] Build failure (property 'contentsFormat' not found on object of type 'LegacyTileLayer *')
         * UIProcess/ios/WKContentView.h:
         * UIProcess/ios/WKContentView.mm:
         (-[WKContentView didUpdateVisibleRect:unobscuredRect:unobscuredRectInScrollViewCoordinates:obscuredInset:scale:minimumScale:inStableState:isChangingObscuredInsetsInteractively:]):
+        Make the VisibleContentRectUpdateInfo here and pass it down.
         (-[WKContentView didUpdateVisibleRect:unobscuredRect:unobscuredRectInScrollViewCoordinates:scale:minimumScale:inStableState:isChangingObscuredInsetsInteractively:]): Deleted.
         * UIProcess/ios/WebPageProxyIOS.mm:
         (WebKit::WebPageProxy::updateVisibleContentRects):
         (WebKit::WebPageProxy::restorePageState):
         * WebProcess/WebPage/ios/WebPageIOS.mm:
         (WebKit::WebPage::restorePageState):
-        (WebKit::WebPage::updateVisibleContentRects):
+        (WebKit::WebPage::updateVisibleContentRects): setObscuredInset() moved from FrameView to Page.
+        Also call setEnclosedInScrollView() on Page.
 
 2016-04-08  Brady Eidson  <beidson@apple.com>
 
index 4d46eea..55258ec 100644 (file)
@@ -46,6 +46,7 @@ void VisibleContentRectUpdateInfo::encode(IPC::ArgumentEncoder& encoder) const
     encoder << m_inStableState;
     encoder << m_isChangingObscuredInsetsInteractively;
     encoder << m_allowShrinkToFit;
+    encoder << m_enclosedInScrollView;
 }
 
 bool VisibleContentRectUpdateInfo::decode(IPC::ArgumentDecoder& decoder, VisibleContentRectUpdateInfo& result)
@@ -78,6 +79,8 @@ bool VisibleContentRectUpdateInfo::decode(IPC::ArgumentDecoder& decoder, Visible
         return false;
     if (!decoder.decode(result.m_allowShrinkToFit))
         return false;
+    if (!decoder.decode(result.m_enclosedInScrollView))
+        return false;
 
     return true;
 }
index 0f37014..6847027 100644 (file)
@@ -41,7 +41,7 @@ public:
 
     VisibleContentRectUpdateInfo(const WebCore::FloatRect& exposedContentRect, const WebCore::FloatRect& unobscuredContentRect,
         const WebCore::FloatRect& unobscuredRectInScrollViewCoordinates, const WebCore::FloatRect& customFixedPositionRect,
-        const WebCore::FloatSize& obscuredInset, double scale, bool inStableState, bool isChangingObscuredInsetsInteractively, bool allowShrinkToFit,
+        const WebCore::FloatSize& obscuredInset, double scale, bool inStableState, bool isChangingObscuredInsetsInteractively, bool allowShrinkToFit, bool enclosedInScrollView,
         double timestamp, double horizontalVelocity, double verticalVelocity, double scaleChangeRate, uint64_t lastLayerTreeTransactionId)
         : m_exposedContentRect(exposedContentRect)
         , m_unobscuredContentRect(unobscuredContentRect)
@@ -57,6 +57,7 @@ public:
         , m_inStableState(inStableState)
         , m_isChangingObscuredInsetsInteractively(isChangingObscuredInsetsInteractively)
         , m_allowShrinkToFit(allowShrinkToFit)
+        , m_enclosedInScrollView(enclosedInScrollView)
     {
     }
 
@@ -70,6 +71,7 @@ public:
     bool inStableState() const { return m_inStableState; }
     bool isChangingObscuredInsetsInteractively() const { return m_isChangingObscuredInsetsInteractively; }
     bool allowShrinkToFit() const { return m_allowShrinkToFit; }
+    bool enclosedInScrollView() const { return m_enclosedInScrollView; }
 
     double timestamp() const { return m_timestamp; }
     double horizontalVelocity() const { return m_horizontalVelocity; }
@@ -96,6 +98,7 @@ private:
     bool m_inStableState { false };
     bool m_isChangingObscuredInsetsInteractively { false };
     bool m_allowShrinkToFit { false };
+    bool m_enclosedInScrollView { false };
 };
 
 inline bool operator==(const VisibleContentRectUpdateInfo& a, const VisibleContentRectUpdateInfo& b)
@@ -110,7 +113,8 @@ inline bool operator==(const VisibleContentRectUpdateInfo& a, const VisibleConte
         && a.verticalVelocity() == b.verticalVelocity()
         && a.scaleChangeRate() == b.scaleChangeRate()
         && a.inStableState() == b.inStableState()
-        && a.allowShrinkToFit() == b.allowShrinkToFit();
+        && a.allowShrinkToFit() == b.allowShrinkToFit()
+        && a.enclosedInScrollView() == b.enclosedInScrollView();
 }
 
 } // namespace WebKit
index e2ce162..3b7bad3 100644 (file)
@@ -240,6 +240,9 @@ WKWebView* fromWebPageProxy(WebKit::WebPageProxy& page)
     RetainPtr<UIView <WKWebViewContentProvider>> _customContentView;
     RetainPtr<UIView> _customContentFixedOverlayView;
 
+    RetainPtr<NSTimer> _enclosingScrollViewScrollTimer;
+    BOOL _didScrollSinceLastTimerFire;
+
     WebCore::Color _scrollViewBackgroundColor;
 
     // This value tracks the current adjustment added to the bottom inset due to the keyboard sliding out from the bottom
@@ -1006,7 +1009,7 @@ static CGSize roundScrollViewContentSize(const WebKit::WebPageProxy& page, CGSiz
     _delayUpdateVisibleContentRects = NO;
     if (_hadDelayedUpdateVisibleContentRects) {
         _hadDelayedUpdateVisibleContentRects = NO;
-        [self _updateVisibleContentRects];
+        [self _updateVisibleContentRectAfterScrollInView:_scrollView.get()];
     }
 }
 
@@ -1750,7 +1753,7 @@ static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
     if (![self usesStandardContentView])
         return;
 
-    [self _updateVisibleContentRects];
+    [self _updateVisibleContentRectAfterScrollInView:_scrollView.get()];
     [_contentView didFinishScrolling];
 }
 
@@ -1804,7 +1807,7 @@ static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
     if (![self usesStandardContentView])
         [_customContentView scrollViewDidScroll:(UIScrollView *)scrollView];
 
-    [self _updateVisibleContentRects];
+    [self _updateVisibleContentRectAfterScrollInView:scrollView];
     
     if (WebKit::RemoteLayerTreeScrollingPerformanceData* scrollPerfData = _page->scrollingPerformanceData())
         scrollPerfData->didScroll([self visibleRectInViewCoordinates]);
@@ -1813,13 +1816,13 @@ static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
 - (void)scrollViewDidZoom:(UIScrollView *)scrollView
 {
     [self _updateScrollViewBackground];
-    [self _updateVisibleContentRects];
+    [self _updateVisibleContentRectAfterScrollInView:scrollView];
 }
 
 - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale
 {
     ASSERT(scrollView == _scrollView);
-    [self _updateVisibleContentRects];
+    [self _updateVisibleContentRectAfterScrollInView:scrollView];
     [_contentView didZoomToScale:scale];
 }
 
@@ -1834,7 +1837,55 @@ static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
         return;
 
     [_contentView didInterruptScrolling];
+    [self _updateVisibleContentRectAfterScrollInView:scrollView];
+}
+
+- (CGRect)_visibleRectInEnclosingScrollView:(UIScrollView *)enclosingScrollView
+{
+    if (!enclosingScrollView)
+        return self.bounds;
+
+    CGRect exposedRect = [enclosingScrollView convertRect:enclosingScrollView.bounds toView:self];
+    return CGRectIntersectsRect(exposedRect, self.bounds) ? CGRectIntersection(exposedRect, self.bounds) : CGRectZero;
+}
+
+- (CGRect)_visibleContentRect
+{
+    CGRect visibleRectInContentCoordinates = _frozenVisibleContentRect ? _frozenVisibleContentRect.value() : [self convertRect:self.bounds toView:_contentView.get()];
+    
+    if (UIScrollView *enclosingScroller = [self _scroller]) {
+        CGRect viewVisibleRect = [self _visibleRectInEnclosingScrollView:enclosingScroller];
+        CGRect viewVisibleContentRect = [self convertRect:viewVisibleRect toView:_contentView.get()];
+        visibleRectInContentCoordinates = CGRectIntersection(visibleRectInContentCoordinates, viewVisibleContentRect);
+    }
+
+    return visibleRectInContentCoordinates;
+}
+
+// Called when some ancestor UIScrollView scrolls.
+- (void)_didScroll
+{
+    [self _updateVisibleContentRectAfterScrollInView:[self _scroller]];
+
+    const NSTimeInterval ScrollingEndedTimerInterval = 0.032;
+    if (!_enclosingScrollViewScrollTimer) {
+        _enclosingScrollViewScrollTimer = adoptNS([[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:ScrollingEndedTimerInterval]
+            interval:0 target:self selector:@selector(_enclosingScrollerScrollingEnded:) userInfo:nil repeats:YES]);
+        [[NSRunLoop mainRunLoop] addTimer:_enclosingScrollViewScrollTimer.get() forMode:NSDefaultRunLoopMode];
+    }
+    _didScrollSinceLastTimerFire = YES;
+}
+
+- (void)_enclosingScrollerScrollingEnded:(NSTimer *)timer
+{
+    if (_didScrollSinceLastTimerFire) {
+        _didScrollSinceLastTimerFire = NO;
+        return;
+    }
+
     [self _updateVisibleContentRects];
+    [_enclosingScrollViewScrollTimer invalidate];
+    _enclosingScrollViewScrollTimer = nil;
 }
 
 - (void)_frameOrBoundsChanged
@@ -1847,7 +1898,7 @@ static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
             _page->setViewportConfigurationMinimumLayoutSize(WebCore::FloatSize(bounds.size));
         if (!_overridesMaximumUnobscuredSize)
             _page->setMaximumUnobscuredSize(WebCore::FloatSize(bounds.size));
-        if (WebKit::DrawingAreaProxy* drawingArea = _page->drawingArea())
+        if (auto drawingArea = _page->drawingArea())
             drawingArea->setSize(WebCore::IntSize(bounds.size), WebCore::IntSize(), WebCore::IntSize());
     }
 
@@ -1877,6 +1928,29 @@ static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
 
 - (void)_updateVisibleContentRects
 {
+    // For visible rect updates not associated with a spefic UIScrollView, just consider our own scroller.
+    [self _updateVisibleContentRectAfterScrollInView:_scrollView.get()];
+}
+
+- (void)_updateVisibleContentRectAfterScrollInView:(UIScrollView *)scrollView
+{
+    BOOL isStableState = !([scrollView isDragging] || [scrollView isDecelerating] || [scrollView isZooming] || [scrollView _isAnimatingZoom] || [scrollView _isScrollingToTop]);
+
+    if (isStableState && scrollView == _scrollView.get())
+        isStableState = !_isChangingObscuredInsetsInteractively;
+    
+    if (isStableState && scrollView == _scrollView.get())
+        isStableState = ![self _scrollViewIsRubberBanding];
+
+    // FIXME: this can be made static after we stop supporting iOS 8.x.
+    if (isStableState && [scrollView respondsToSelector:@selector(_isInterruptingDeceleration)])
+        isStableState = ![scrollView performSelector:@selector(_isInterruptingDeceleration)];
+
+    [self _updateContentRectsWithState:isStableState];
+}
+
+- (void)_updateContentRectsWithState:(BOOL)inStableState
+{
     if (![self usesStandardContentView]) {
         [_customContentView web_computedContentInsetDidChange];
         return;
@@ -1894,7 +1968,7 @@ static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
         return;
 
     CGRect fullViewRect = self.bounds;
-    CGRect visibleRectInContentCoordinates = _frozenVisibleContentRect ? _frozenVisibleContentRect.value() : [self convertRect:fullViewRect toView:_contentView.get()];
+    CGRect visibleRectInContentCoordinates = [self _visibleContentRect];
 
     UIEdgeInsets computedContentInsetUnadjustedForKeyboard = [self _computedContentInset];
     if (!_haveSetObscuredInsets)
@@ -1905,17 +1979,10 @@ static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
 
     CGFloat scaleFactor = contentZoomScale(self);
 
-    BOOL isStableState = !(_isChangingObscuredInsetsInteractively || [_scrollView isDragging] || [_scrollView isDecelerating] || [_scrollView isZooming] || [_scrollView _isAnimatingZoom] || [_scrollView _isScrollingToTop] || [self _scrollViewIsRubberBanding]);
-
-    // FIXME: this can be made static after we stop supporting iOS 8.x.
-    if (isStableState && [_scrollView respondsToSelector:@selector(_isInterruptingDeceleration)])
-        isStableState = ![_scrollView performSelector:@selector(_isInterruptingDeceleration)];
-
 #if ENABLE(CSS_SCROLL_SNAP) && ENABLE(ASYNC_SCROLLING)
-    if (isStableState) {
+    if (inStableState) {
         WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy();
         if (coordinator && coordinator->hasActiveSnapPoint()) {
-            CGRect fullViewRect = self.bounds;
             CGRect unobscuredRect = UIEdgeInsetsInsetRect(fullViewRect, computedContentInsetUnadjustedForKeyboard);
             
             CGPoint currentPoint = [_scrollView contentOffset];
@@ -1936,8 +2003,9 @@ static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
         unobscuredRectInScrollViewCoordinates:unobscuredRect
         obscuredInset:CGSizeMake(_obscuredInsets.left, _obscuredInsets.top)
         scale:scaleFactor minimumScale:[_scrollView minimumZoomScale]
-        inStableState:isStableState
-        isChangingObscuredInsetsInteractively:_isChangingObscuredInsetsInteractively];
+        inStableState:inStableState
+        isChangingObscuredInsetsInteractively:_isChangingObscuredInsetsInteractively
+        enclosedInScrollView:[self _scroller] != nil];
 }
 
 - (void)_didFinishLoadForMainFrame
index b531a31..6e9d435 100644 (file)
@@ -99,6 +99,8 @@ struct PrintInfo;
 - (void)_didInvokeUIScrollViewDelegateCallback;
 
 - (void)_updateVisibleContentRects;
+- (void)_updateVisibleContentRectAfterScrollInView:(UIScrollView *)scrollView;
+- (void)_updateContentRectsWithState:(BOOL)inStableState;
 
 - (void)_didFinishLoadForMainFrame;
 - (void)_didFailLoadForMainFrame;
index 468a8f1..899ce4c 100644 (file)
@@ -452,7 +452,7 @@ public:
     const WebCore::FloatRect& exposedContentRect() const { return m_lastVisibleContentRectUpdate.exposedContentRect(); }
     const WebCore::FloatRect& unobscuredContentRect() const { return m_lastVisibleContentRectUpdate.unobscuredContentRect(); }
 
-    void updateVisibleContentRects(const WebCore::FloatRect& exposedRect, const WebCore::FloatRect& unobscuredRect, const WebCore::FloatRect& unobscuredRectInScrollViewCoordinates, const WebCore::FloatRect& customFixedPositionRect, const WebCore::FloatSize& obscuredInset, double scale, bool inStableState, bool isChangingObscuredInsetsInteractively, bool allowShrinkToFit, double timestamp, double horizontalVelocity, double verticalVelocity, double scaleChangeRate);
+    void updateVisibleContentRects(const VisibleContentRectUpdateInfo&);
     void resendLastVisibleContentRects();
 
     enum class UnobscuredRectConstraint { ConstrainedToDocumentRect, Unconstrained };
index cad014c..12df557 100644 (file)
@@ -70,7 +70,9 @@ class WebProcessPool;
     unobscuredRectInScrollViewCoordinates:(CGRect)unobscuredRectInScrollViewCoordinates
     obscuredInset:(CGSize)topInset
     scale:(CGFloat)scale minimumScale:(CGFloat)minimumScale
-    inStableState:(BOOL)isStableState isChangingObscuredInsetsInteractively:(BOOL)isChangingObscuredInsetsInteractively;
+    inStableState:(BOOL)isStableState
+    isChangingObscuredInsetsInteractively:(BOOL)isChangingObscuredInsetsInteractively
+    enclosedInScrollView:(BOOL)enclosedInScrollView;
 
 - (void)didFinishScrolling;
 - (void)didInterruptScrolling;
index b395b26..9025fc0 100644 (file)
@@ -356,8 +356,12 @@ private:
 }
 
 - (void)didUpdateVisibleRect:(CGRect)visibleRect unobscuredRect:(CGRect)unobscuredRect unobscuredRectInScrollViewCoordinates:(CGRect)unobscuredRectInScrollViewCoordinates
-    obscuredInset:(CGSize)obscuredInset scale:(CGFloat)zoomScale minimumScale:(CGFloat)minimumScale inStableState:(BOOL)isStableState isChangingObscuredInsetsInteractively:(BOOL)isChangingObscuredInsetsInteractively
+    obscuredInset:(CGSize)obscuredInset scale:(CGFloat)zoomScale minimumScale:(CGFloat)minimumScale inStableState:(BOOL)isStableState isChangingObscuredInsetsInteractively:(BOOL)isChangingObscuredInsetsInteractively enclosedInScrollView:(BOOL)enclosedInScrollView
 {
+    auto drawingArea = _page->drawingArea();
+    if (!drawingArea)
+        return;
+
     double timestamp = monotonicallyIncreasingTime();
     HistoricalVelocityData::VelocityData velocityData;
     if (!isStableState)
@@ -366,16 +370,32 @@ private:
         _historicalKinematicData.clear();
 
     FloatRect fixedPositionRectForLayout = _page->computeCustomFixedPositionRect(unobscuredRect, zoomScale, WebPageProxy::UnobscuredRectConstraint::ConstrainedToDocumentRect);
-    _page->updateVisibleContentRects(visibleRect, unobscuredRect, unobscuredRectInScrollViewCoordinates, fixedPositionRectForLayout, WebCore::FloatSize(obscuredInset),
-        zoomScale, isStableState, isChangingObscuredInsetsInteractively, _webView._allowsViewportShrinkToFit, timestamp, velocityData.horizontalVelocity, velocityData.verticalVelocity, velocityData.scaleChangeRate);
+
+    VisibleContentRectUpdateInfo visibleContentRectUpdateInfo(
+        visibleRect,
+        unobscuredRect,
+        unobscuredRectInScrollViewCoordinates,
+        fixedPositionRectForLayout,
+        WebCore::FloatSize(obscuredInset),
+        zoomScale,
+        isStableState,
+        isChangingObscuredInsetsInteractively,
+        _webView._allowsViewportShrinkToFit,
+        enclosedInScrollView,
+        timestamp,
+        velocityData.horizontalVelocity,
+        velocityData.verticalVelocity,
+        velocityData.scaleChangeRate,
+        downcast<RemoteLayerTreeDrawingAreaProxy>(*drawingArea).lastCommittedLayerTreeTransactionID());
+
+    _page->updateVisibleContentRects(visibleContentRectUpdateInfo);
 
     RemoteScrollingCoordinatorProxy* scrollingCoordinator = _page->scrollingCoordinatorProxy();
     FloatRect fixedPositionRect = _page->computeCustomFixedPositionRect(_page->unobscuredContentRect(), zoomScale);
     scrollingCoordinator->viewportChangedViaDelegatedScrolling(scrollingCoordinator->rootScrollingNodeID(), fixedPositionRect, zoomScale);
 
-    if (auto drawingArea = _page->drawingArea())
-        drawingArea->updateDebugIndicator();
-        
+    drawingArea->updateDebugIndicator();
+    
     [self updateFixedClippingView:fixedPositionRect];
 }
 
index babf2ee..36025c6 100644 (file)
@@ -182,18 +182,16 @@ void WebPageProxy::autocorrectionContextCallback(const String& beforeText, const
     callback->performCallbackWithReturnValue(beforeText, markedText, selectedText, afterText, location, length);
 }
 
-void WebPageProxy::updateVisibleContentRects(const WebCore::FloatRect& exposedRect, const WebCore::FloatRect& unobscuredRect, const WebCore::FloatRect& unobscuredRectInScrollViewCoordinates, const WebCore::FloatRect& customFixedPositionRect, const WebCore::FloatSize& obscuredInset, double scale, bool inStableState, bool isChangingObscuredInsetsInteractively, bool allowShrinkToFit, double timestamp, double horizontalVelocity, double verticalVelocity, double scaleChangeRate)
+void WebPageProxy::updateVisibleContentRects(const VisibleContentRectUpdateInfo& visibleContentRectUpdate)
 {
     if (!isValid())
         return;
 
-    VisibleContentRectUpdateInfo visibleContentRectUpdateInfo(exposedRect, unobscuredRect, unobscuredRectInScrollViewCoordinates, customFixedPositionRect, obscuredInset, scale, inStableState, isChangingObscuredInsetsInteractively, allowShrinkToFit, timestamp, horizontalVelocity, verticalVelocity, scaleChangeRate, downcast<RemoteLayerTreeDrawingAreaProxy>(*drawingArea()).lastCommittedLayerTreeTransactionID());
-
-    if (visibleContentRectUpdateInfo == m_lastVisibleContentRectUpdate)
+    if (visibleContentRectUpdate == m_lastVisibleContentRectUpdate)
         return;
 
-    m_lastVisibleContentRectUpdate = visibleContentRectUpdateInfo;
-    m_process->send(Messages::ViewUpdateDispatcher::VisibleContentRectUpdate(m_pageID, visibleContentRectUpdateInfo), 0);
+    m_lastVisibleContentRectUpdate = visibleContentRectUpdate;
+    m_process->send(Messages::ViewUpdateDispatcher::VisibleContentRectUpdate(m_pageID, visibleContentRectUpdate), 0);
 }
 
 void WebPageProxy::resendLastVisibleContentRects()
index 74e5b06..6f296e7 100644 (file)
@@ -259,6 +259,8 @@ FloatPoint RemoteLayerTreeDrawingAreaProxy::indicatorLocation() const
     if (m_webPageProxy.delegatesScrolling()) {
 #if PLATFORM(IOS)
         FloatPoint tiledMapLocation = m_webPageProxy.unobscuredContentRect().location();
+        tiledMapLocation = tiledMapLocation.expandedTo(m_webPageProxy.exposedContentRect().location() + FloatSize(0, 60));
+
         float absoluteInset = indicatorInset / m_webPageProxy.displayedContentScale();
         tiledMapLocation += FloatSize(absoluteInset, absoluteInset);
 #else
index 50b49a0..88405ae 100644 (file)
@@ -2964,7 +2964,8 @@ void WebPage::updateVisibleContentRects(const VisibleContentRectUpdateInfo& visi
         viewportConfigurationChanged();
 
     frameView.setUnobscuredContentSize(visibleContentRectUpdateInfo.unobscuredContentRect().size());
-    frameView.platformSetObscuredInset(visibleContentRectUpdateInfo.obscuredInset());
+    m_page->setObscuredInset(visibleContentRectUpdateInfo.obscuredInset());
+    m_page->setEnclosedInScrollView(visibleContentRectUpdateInfo.enclosedInScrollView());
 
     double horizontalVelocity = visibleContentRectUpdateInfo.horizontalVelocity();
     double verticalVelocity = visibleContentRectUpdateInfo.verticalVelocity();