Sideways-scrollable RTL document has wrong initial and reload offset in WKWebView
https://bugs.webkit.org/show_bug.cgi?id=155660
Source/WebCore:

rdar://problem/22212662

Reviewed by Tim Horton.

There were two problems with the scroll position of RTL documents on initial and reload
in WKWebView.

First, in the delegatesScrolling() code path, ScrollView::updateScrollbars() needs to
tell someone that the scroll origin changed, to trigger a scroll to the page origin.

Secondly, WKWebView had scrollPosition/scrollOffset confusion in various places.

Test: fast/scrolling/rtl-initial-scroll-position.html

* platform/ScrollView.cpp:
(WebCore::ScrollView::updateScrollbars):

Source/WebKit2:

Reviewed by Tim Horton.

There were two problems with the scroll position of RTL documents on initial and reload
in WKWebView.

First, in the delegatesScrolling() code path, ScrollView::updateScrollbars() needs to
tell someone that the scroll origin changed, to trigger a scroll to the page origin.

Secondly, WKWebView had scrollPosition/scrollOffset confusion in various places. In
the restorePageState() code path, WebCore passes an exposedRect; this patch makes
it explicit that it's an exposedContentRect, and passes scrollOrigin so that it can
be mapped into scrollOffset-relative coordinates that the UIScrollView wants.

When reloading an RTL page, there was an additional issue; restorePageState()
restored the exposedRect, but then we'd see the origin change as a programmatic scroll
to 0,0, clobbering the exposedRect. Fix by using a "_commitDidRestoreExposedRect" flag
on the WKWebView that is used to ignore the programmatic scroll in that case.

Ideally these changes would fix fast/scrolling/scroll-position-on-reload-rtl.html, but the
test still fails because of timing differences between OS X and iOS.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _didCommitLayerTree:]):
(-[WKWebView _layerTreeCommitComplete]):
(-[WKWebView _restorePageStateToExposedRect:scrollOrigin:scale:]):
(-[WKWebView _scrollToContentScrollPosition:scrollOrigin:]):
(-[WKWebView _restorePageStateToExposedRect:scale:]): Deleted.
(-[WKWebView _scrollToContentOffset:scrollOrigin:]): Deleted.
* UIProcess/API/Cocoa/WKWebViewInternal.h:
* UIProcess/PageClient.h:
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* UIProcess/ios/PageClientImplIOS.h:
* UIProcess/ios/PageClientImplIOS.mm:
(WebKit::PageClientImpl::requestScroll):
(WebKit::PageClientImpl::layerTreeCommitComplete):
(WebKit::PageClientImpl::restorePageState):
* UIProcess/ios/WKContentView.h:
* UIProcess/ios/WKContentView.mm:
(-[WKContentView _layerTreeCommitComplete]):
* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::layerTreeCommitComplete):
(WebKit::WebPageProxy::restorePageState):
* UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.mm:
(WebKit::RemoteLayerTreeDrawingAreaProxy::commitLayerTree):
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::restorePageState):

LayoutTests:

Reviewed by Tim Horton.

Test for initial scroll position in an RTL page.

* fast/scrolling/rtl-initial-scroll-position-expected.html: Added.
* fast/scrolling/rtl-initial-scroll-position.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@198455 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 4d277ee..fd0e738 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,15 @@
+2016-03-18  Simon Fraser  <simon.fraser@apple.com>
+
+        Sideways-scrollable RTL document has wrong initial and reload offset in WKWebView
+        https://bugs.webkit.org/show_bug.cgi?id=155660
+
+        Reviewed by Tim Horton.
+        
+        Test for initial scroll position in an RTL page.
+
+        * fast/scrolling/rtl-initial-scroll-position-expected.html: Added.
+        * fast/scrolling/rtl-initial-scroll-position.html: Added.
+
 2016-03-18  Darin Adler  <darin@apple.com>
 
         ASSERTION FAILED: m_isValid == valid() in WebCore::HTMLFormControlElement::isValidFormControlElement
diff --git a/LayoutTests/fast/scrolling/rtl-initial-scroll-position-expected.html b/LayoutTests/fast/scrolling/rtl-initial-scroll-position-expected.html
new file mode 100644
index 0000000..93a4503
--- /dev/null
+++ b/LayoutTests/fast/scrolling/rtl-initial-scroll-position-expected.html
@@ -0,0 +1,27 @@
+<html>
+<head>
+    <style>
+        body {
+            margin: 0;
+            overflow: hidden;
+        }
+        .wide {
+            width: 2000px;
+            height: 10px;
+            background-color: silver;
+        }
+        .origin {
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100px;
+            height: 100px;
+            background-color: green;
+        }
+    </style>
+</head>
+<body>
+    <div class="wide"></div>
+    <div class="origin"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/scrolling/rtl-initial-scroll-position.html b/LayoutTests/fast/scrolling/rtl-initial-scroll-position.html
new file mode 100644
index 0000000..356aaeb
--- /dev/null
+++ b/LayoutTests/fast/scrolling/rtl-initial-scroll-position.html
@@ -0,0 +1,27 @@
+<html dir="rtl">
+<head>
+    <style>
+        body {
+            margin: 0;
+            overflow: hidden;
+        }
+        .wide {
+            width: 2000px;
+            height: 10px;
+            background-color: silver;
+        }
+        .origin {
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100px;
+            height: 100px;
+            background-color: green;
+        }
+    </style>
+</head>
+<body>
+    <div class="wide"></div>
+    <div class="origin"></div>
+</body>
+</html>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 5e5c21a..3d781ec 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,24 @@
+2016-03-18  Simon Fraser  <simon.fraser@apple.com>
+
+        Sideways-scrollable RTL document has wrong initial and reload offset in WKWebView
+        https://bugs.webkit.org/show_bug.cgi?id=155660
+        rdar://problem/22212662
+
+        Reviewed by Tim Horton.
+        
+        There were two problems with the scroll position of RTL documents on initial and reload
+        in WKWebView.
+
+        First, in the delegatesScrolling() code path, ScrollView::updateScrollbars() needs to
+        tell someone that the scroll origin changed, to trigger a scroll to the page origin.
+
+        Secondly, WKWebView had scrollPosition/scrollOffset confusion in various places.
+
+        Test: fast/scrolling/rtl-initial-scroll-position.html
+
+        * platform/ScrollView.cpp:
+        (WebCore::ScrollView::updateScrollbars):
+
 2016-03-18  Ryan Haddad  <ryanhaddad@apple.com>
 
         Unreviewed, rolling out r198443.
diff --git a/Source/WebCore/platform/ScrollView.cpp b/Source/WebCore/platform/ScrollView.cpp
index bb7f835..4e9fcaf 100644
--- a/Source/WebCore/platform/ScrollView.cpp
+++ b/Source/WebCore/platform/ScrollView.cpp
@@ -582,8 +582,16 @@
 {
     LOG_WITH_STREAM(Scrolling, stream << "ScrollView::updateScrollbars " << desiredPosition);
 
-    if (m_inUpdateScrollbars || prohibitsScrolling() || platformWidget() || delegatesScrolling())
+    if (m_inUpdateScrollbars || prohibitsScrolling() || platformWidget())
         return;
+    
+    if (delegatesScrolling()) {
+        if (scrollOriginChanged()) {
+            ScrollableArea::scrollToOffsetWithoutAnimation(scrollOffsetFromPosition(desiredPosition));
+            resetScrollOriginChanged();
+        }
+        return;
+    }
 
     bool hasOverlayScrollbars = (!m_horizontalScrollbar || m_horizontalScrollbar->isOverlayScrollbar()) && (!m_verticalScrollbar || m_verticalScrollbar->isOverlayScrollbar());
 
diff --git a/Source/WebKit2/ChangeLog b/Source/WebKit2/ChangeLog
index 68838e7..283619d 100644
--- a/Source/WebKit2/ChangeLog
+++ b/Source/WebKit2/ChangeLog
@@ -1,3 +1,56 @@
+2016-03-18  Simon Fraser  <simon.fraser@apple.com>
+
+        Sideways-scrollable RTL document has wrong initial and reload offset in WKWebView
+        https://bugs.webkit.org/show_bug.cgi?id=155660
+
+        Reviewed by Tim Horton.
+
+        There were two problems with the scroll position of RTL documents on initial and reload
+        in WKWebView.
+
+        First, in the delegatesScrolling() code path, ScrollView::updateScrollbars() needs to
+        tell someone that the scroll origin changed, to trigger a scroll to the page origin.
+
+        Secondly, WKWebView had scrollPosition/scrollOffset confusion in various places. In
+        the restorePageState() code path, WebCore passes an exposedRect; this patch makes
+        it explicit that it's an exposedContentRect, and passes scrollOrigin so that it can
+        be mapped into scrollOffset-relative coordinates that the UIScrollView wants.
+
+        When reloading an RTL page, there was an additional issue; restorePageState()
+        restored the exposedRect, but then we'd see the origin change as a programmatic scroll
+        to 0,0, clobbering the exposedRect. Fix by using a "_commitDidRestoreExposedRect" flag
+        on the WKWebView that is used to ignore the programmatic scroll in that case.
+
+        Ideally these changes would fix fast/scrolling/scroll-position-on-reload-rtl.html, but the
+        test still fails because of timing differences between OS X and iOS.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _didCommitLayerTree:]):
+        (-[WKWebView _layerTreeCommitComplete]):
+        (-[WKWebView _restorePageStateToExposedRect:scrollOrigin:scale:]):
+        (-[WKWebView _scrollToContentScrollPosition:scrollOrigin:]):
+        (-[WKWebView _restorePageStateToExposedRect:scale:]): Deleted.
+        (-[WKWebView _scrollToContentOffset:scrollOrigin:]): Deleted.
+        * UIProcess/API/Cocoa/WKWebViewInternal.h:
+        * UIProcess/PageClient.h:
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        * UIProcess/ios/PageClientImplIOS.h:
+        * UIProcess/ios/PageClientImplIOS.mm:
+        (WebKit::PageClientImpl::requestScroll):
+        (WebKit::PageClientImpl::layerTreeCommitComplete):
+        (WebKit::PageClientImpl::restorePageState):
+        * UIProcess/ios/WKContentView.h:
+        * UIProcess/ios/WKContentView.mm:
+        (-[WKContentView _layerTreeCommitComplete]):
+        * UIProcess/ios/WebPageProxyIOS.mm:
+        (WebKit::WebPageProxy::layerTreeCommitComplete):
+        (WebKit::WebPageProxy::restorePageState):
+        * UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.mm:
+        (WebKit::RemoteLayerTreeDrawingAreaProxy::commitLayerTree):
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::restorePageState):
+
 2016-03-18  Brady Eidson  <beidson@apple.com>
 
         NSURLSession: Set download resume data when a download fails due to an error.
diff --git a/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm b/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
index 53e0f30..9c6bd53 100644
--- a/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
+++ b/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
@@ -112,6 +112,7 @@
 #import <WebCore/FrameLoaderTypes.h>
 #import <WebCore/InspectorOverlay.h>
 #import <WebCore/QuartzCoreSPI.h>
+#import <WebCore/ScrollableArea.h>
 
 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000
 #if __has_include(<AccessibilitySupport.h>)
@@ -240,6 +241,7 @@
     Optional<CGRect> _frozenUnobscuredContentRect;
 
     BOOL _needsToRestoreExposedRect;
+    BOOL _commitDidRestoreExposedRect;
     WebCore::FloatRect _exposedRectToRestore;
     BOOL _needsToRestoreUnobscuredCenter;
     WebCore::FloatPoint _unobscuredCenterToRestore;
@@ -1233,6 +1235,7 @@
             exposedPosition.scale(_scaleToRestore, _scaleToRestore);
 
             changeContentOffsetBoundedInValidRange(_scrollView.get(), exposedPosition);
+            _commitDidRestoreExposedRect = YES;
             if (_gestureController)
                 _gestureController->didRestoreScrollPosition();
         }
@@ -1261,6 +1264,11 @@
         scrollPerfData->didCommitLayerTree([self visibleRectInViewCoordinates]);
 }
 
+- (void)_layerTreeCommitComplete
+{
+    _commitDidRestoreExposedRect = NO;
+}
+
 - (void)_dynamicViewportUpdateChangedTargetToScale:(double)newScale position:(CGPoint)newScrollPosition nextValidLayerTreeTransactionID:(uint64_t)nextValidLayerTreeTransactionID
 {
     if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing) {
@@ -1288,7 +1296,7 @@
         _gestureController->didRestoreScrollPosition();
 }
 
-- (void)_restorePageStateToExposedRect:(WebCore::FloatRect)exposedRect scale:(double)scale
+- (void)_restorePageStateToExposedRect:(WebCore::FloatRect)exposedRect scrollOrigin:(WebCore::IntPoint)scrollOrigin scale:(double)scale
 {
     if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing)
         return;
@@ -1299,6 +1307,9 @@
     _needsToRestoreUnobscuredCenter = NO;
     _needsToRestoreExposedRect = YES;
     _firstTransactionIDAfterPageRestore = downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(*_page->drawingArea()).nextLayerTreeTransactionID();
+    
+    // Move the exposed rect into scrollView coordinates.
+    exposedRect.move(toFloatSize(scrollOrigin));
     _exposedRectToRestore = exposedRect;
     _scaleToRestore = scale;
 }
@@ -1408,14 +1419,14 @@
     return contentOffset.constrainedBetween(WebCore::FloatPoint(), WebCore::FloatPoint(maximumContentOffset));
 }
 
-- (void)_scrollToContentOffset:(WebCore::FloatPoint)contentOffsetInPageCoordinates scrollOrigin:(WebCore::IntPoint)scrollOrigin
+- (void)_scrollToContentScrollPosition:(WebCore::FloatPoint)scrollPosition scrollOrigin:(WebCore::IntPoint)scrollOrigin
 {
-    if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing)
+    if (_commitDidRestoreExposedRect || _dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing)
         return;
 
-    WebCore::FloatPoint contentOffsetRespectingOrigin = scrollOrigin + toFloatSize(contentOffsetInPageCoordinates);
+    WebCore::FloatPoint contentOffset = WebCore::ScrollableArea::scrollOffsetFromPosition(scrollPosition, toFloatSize(scrollOrigin));
 
-    WebCore::FloatPoint scaledOffset = contentOffsetRespectingOrigin;
+    WebCore::FloatPoint scaledOffset = contentOffset;
     CGFloat zoomScale = contentZoomScale(self);
     scaledOffset.scale(zoomScale, zoomScale);
 
diff --git a/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewInternal.h b/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewInternal.h
index d5bfd98..a36e2b3 100644
--- a/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewInternal.h
+++ b/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewInternal.h
@@ -75,15 +75,16 @@
 
 - (void)_didCommitLoadForMainFrame;
 - (void)_didCommitLayerTree:(const WebKit::RemoteLayerTreeTransaction&)layerTreeTransaction;
+- (void)_layerTreeCommitComplete;
 
 - (void)_dynamicViewportUpdateChangedTargetToScale:(double)newScale position:(CGPoint)newScrollPosition nextValidLayerTreeTransactionID:(uint64_t)nextValidLayerTreeTransactionID;
 - (void)_couldNotRestorePageState;
-- (void)_restorePageStateToExposedRect:(WebCore::FloatRect)exposedRect scale:(double)scale;
-- (void)_restorePageStateToUnobscuredCenter:(WebCore::FloatPoint)center scale:(double)scale;
+- (void)_restorePageStateToExposedRect:(WebCore::FloatRect)exposedRect scrollOrigin:(WebCore::IntPoint)scrollOrigin scale:(double)scale;
+- (void)_restorePageStateToUnobscuredCenter:(WebCore::FloatPoint)center scale:(double)scale; // FIXME: needs scroll origin?
 
 - (PassRefPtr<WebKit::ViewSnapshot>)_takeViewSnapshot;
 
-- (void)_scrollToContentOffset:(WebCore::FloatPoint)contentOffset scrollOrigin:(WebCore::IntPoint)scrollOrigin;
+- (void)_scrollToContentScrollPosition:(WebCore::FloatPoint)scrollPosition scrollOrigin:(WebCore::IntPoint)scrollOrigin;
 - (BOOL)_scrollToRect:(WebCore::FloatRect)targetRect origin:(WebCore::FloatPoint)origin minimumScrollDistance:(float)minimumScrollDistance;
 - (void)_scrollByContentOffset:(WebCore::FloatPoint)offset;
 - (void)_zoomToFocusRect:(WebCore::FloatRect)focusedElementRect selectionRect:(WebCore::FloatRect)selectionRectInDocumentCoordinates fontSize:(float)fontSize minimumScale:(double)minimumScale maximumScale:(double)maximumScale allowScaling:(BOOL)allowScaling forceScroll:(BOOL)forceScroll;
diff --git a/Source/WebKit2/UIProcess/PageClient.h b/Source/WebKit2/UIProcess/PageClient.h
index d38600c..0acdd55 100644
--- a/Source/WebKit2/UIProcess/PageClient.h
+++ b/Source/WebKit2/UIProcess/PageClient.h
@@ -288,9 +288,11 @@
     virtual void didGetTapHighlightGeometries(uint64_t requestID, const WebCore::Color&, const Vector<WebCore::FloatQuad>& highlightedQuads, const WebCore::IntSize& topLeftRadius, const WebCore::IntSize& topRightRadius, const WebCore::IntSize& bottomLeftRadius, const WebCore::IntSize& bottomRightRadius) = 0;
 
     virtual void didCommitLayerTree(const RemoteLayerTreeTransaction&) = 0;
+    virtual void layerTreeCommitComplete() = 0;
+
     virtual void dynamicViewportUpdateChangedTarget(double newScale, const WebCore::FloatPoint& newScrollPosition, uint64_t transactionID) = 0;
     virtual void couldNotRestorePageState() = 0;
-    virtual void restorePageState(const WebCore::FloatRect&, double) = 0;
+    virtual void restorePageState(const WebCore::FloatRect& exposedContentRect, const WebCore::IntPoint& scrollOrigin, double scale) = 0;
     virtual void restorePageCenterAndScale(const WebCore::FloatPoint&, double) = 0;
 
     virtual void startAssistingNode(const AssistedNodeInformation&, bool userIsInteracting, bool blurPreviousNode, API::Object* userData) = 0;
diff --git a/Source/WebKit2/UIProcess/WebPageProxy.h b/Source/WebKit2/UIProcess/WebPageProxy.h
index 68d7ee5..7e8d10b 100644
--- a/Source/WebKit2/UIProcess/WebPageProxy.h
+++ b/Source/WebKit2/UIProcess/WebPageProxy.h
@@ -526,6 +526,7 @@
     void setDataDetectionResult(const DataDetectionResult&);
 #endif
     void didCommitLayerTree(const WebKit::RemoteLayerTreeTransaction&);
+    void layerTreeCommitComplete();
 
 #if USE(COORDINATED_GRAPHICS_MULTIPROCESS)
     void didRenderFrame(const WebCore::IntSize& contentsSize, const WebCore::IntRect& coveredRect);
@@ -1406,7 +1407,7 @@
 
     void dynamicViewportUpdateChangedTarget(double newTargetScale, const WebCore::FloatPoint& newScrollPosition, uint64_t dynamicViewportSizeUpdateID);
     void couldNotRestorePageState();
-    void restorePageState(const WebCore::FloatRect&, double scale);
+    void restorePageState(const WebCore::FloatRect& exposedContentRect, const WebCore::IntPoint& scrollOrigin, double scale);
     void restorePageCenterAndScale(const WebCore::FloatPoint&, double scale);
 
     void didGetTapHighlightGeometries(uint64_t requestID, const WebCore::Color& color, const Vector<WebCore::FloatQuad>& geometries, const WebCore::IntSize& topLeftRadius, const WebCore::IntSize& topRightRadius, const WebCore::IntSize& bottomLeftRadius, const WebCore::IntSize& bottomRightRadius);
diff --git a/Source/WebKit2/UIProcess/WebPageProxy.messages.in b/Source/WebKit2/UIProcess/WebPageProxy.messages.in
index f59d408..e4af7ce 100644
--- a/Source/WebKit2/UIProcess/WebPageProxy.messages.in
+++ b/Source/WebKit2/UIProcess/WebPageProxy.messages.in
@@ -358,7 +358,7 @@
 #if PLATFORM(IOS)
     DynamicViewportUpdateChangedTarget(double newTargetScale, WebCore::FloatPoint newScrollPosition, uint64_t dynamicViewportSizeUpdateID)
     CouldNotRestorePageState()
-    RestorePageState(WebCore::FloatRect exposedRect, double scale)
+    RestorePageState(WebCore::FloatRect exposedContentRect, WebCore::IntPoint scrollOrigin, double scale)
     RestorePageCenterAndScale(WebCore::FloatPoint unobscuredCenter, double scale)
     DidGetTapHighlightGeometries(uint64_t requestID, WebCore::Color color, Vector<WebCore::FloatQuad> geometries, WebCore::IntSize topLeftRadius, WebCore::IntSize topRightRadius, WebCore::IntSize bottomLeftRadius, WebCore::IntSize bottomRightRadius)
 
diff --git a/Source/WebKit2/UIProcess/ios/PageClientImplIOS.h b/Source/WebKit2/UIProcess/ios/PageClientImplIOS.h
index c049773..af167f1 100644
--- a/Source/WebKit2/UIProcess/ios/PageClientImplIOS.h
+++ b/Source/WebKit2/UIProcess/ios/PageClientImplIOS.h
@@ -118,9 +118,11 @@
     void didGetTapHighlightGeometries(uint64_t requestID, const WebCore::Color&, const Vector<WebCore::FloatQuad>& highlightedQuads, const WebCore::IntSize& topLeftRadius, const WebCore::IntSize& topRightRadius, const WebCore::IntSize& bottomLeftRadius, const WebCore::IntSize& bottomRightRadius) override;
 
     void didCommitLayerTree(const RemoteLayerTreeTransaction&) override;
+    void layerTreeCommitComplete() override;
+
     void dynamicViewportUpdateChangedTarget(double newScale, const WebCore::FloatPoint& newScrollPosition, uint64_t transactionID) override;
     void couldNotRestorePageState() override;
-    void restorePageState(const WebCore::FloatRect&, double) override;
+    void restorePageState(const WebCore::FloatRect&, const WebCore::IntPoint&, double) override;
     void restorePageCenterAndScale(const WebCore::FloatPoint&, double) override;
 
     void startAssistingNode(const AssistedNodeInformation&, bool userIsInteracting, bool blurPreviousNode, API::Object* userData) override;
diff --git a/Source/WebKit2/UIProcess/ios/PageClientImplIOS.mm b/Source/WebKit2/UIProcess/ios/PageClientImplIOS.mm
index a3c3297..9fe90f9 100644
--- a/Source/WebKit2/UIProcess/ios/PageClientImplIOS.mm
+++ b/Source/WebKit2/UIProcess/ios/PageClientImplIOS.mm
@@ -147,7 +147,7 @@
 void PageClientImpl::requestScroll(const FloatPoint& scrollPosition, const IntPoint& scrollOrigin, bool isProgrammaticScroll)
 {
     UNUSED_PARAM(isProgrammaticScroll);
-    [m_webView _scrollToContentOffset:scrollPosition scrollOrigin:scrollOrigin];
+    [m_webView _scrollToContentScrollPosition:scrollPosition scrollOrigin:scrollOrigin];
 }
 
 IntSize PageClientImpl::viewSize()
@@ -512,6 +512,11 @@
     [m_contentView _didCommitLayerTree:layerTreeTransaction];
 }
 
+void PageClientImpl::layerTreeCommitComplete()
+{
+    [m_contentView _layerTreeCommitComplete];
+}
+
 void PageClientImpl::dynamicViewportUpdateChangedTarget(double newScale, const WebCore::FloatPoint& newScrollPosition, uint64_t nextValidLayerTreeTransactionID)
 {
     [m_webView _dynamicViewportUpdateChangedTargetToScale:newScale position:newScrollPosition nextValidLayerTreeTransactionID:nextValidLayerTreeTransactionID];
@@ -522,9 +527,9 @@
     [m_webView _couldNotRestorePageState];
 }
 
-void PageClientImpl::restorePageState(const WebCore::FloatRect& exposedRect, double scale)
+void PageClientImpl::restorePageState(const WebCore::FloatRect& exposedContentRect, const WebCore::IntPoint& scrollOrigin, double scale)
 {
-    [m_webView _restorePageStateToExposedRect:exposedRect scale:scale];
+    [m_webView _restorePageStateToExposedRect:exposedContentRect scrollOrigin:scrollOrigin scale:scale];
 }
 
 void PageClientImpl::restorePageCenterAndScale(const WebCore::FloatPoint& center, double scale)
diff --git a/Source/WebKit2/UIProcess/ios/WKContentView.h b/Source/WebKit2/UIProcess/ios/WKContentView.h
index a2a05ff..ed565a4 100644
--- a/Source/WebKit2/UIProcess/ios/WKContentView.h
+++ b/Source/WebKit2/UIProcess/ios/WKContentView.h
@@ -88,6 +88,7 @@
 
 - (void)_didCommitLoadForMainFrame;
 - (void)_didCommitLayerTree:(const WebKit::RemoteLayerTreeTransaction&)layerTreeTransaction;
+- (void)_layerTreeCommitComplete;
 
 - (void)_setAccessibilityWebProcessToken:(NSData *)data;
 
diff --git a/Source/WebKit2/UIProcess/ios/WKContentView.mm b/Source/WebKit2/UIProcess/ios/WKContentView.mm
index 2ec755b..9575c73 100644
--- a/Source/WebKit2/UIProcess/ios/WKContentView.mm
+++ b/Source/WebKit2/UIProcess/ios/WKContentView.mm
@@ -520,6 +520,11 @@
         [self _updateChangedSelection];
 }
 
+- (void)_layerTreeCommitComplete
+{
+    [_webView _layerTreeCommitComplete];
+}
+
 - (void)_setAcceleratedCompositingRootView:(UIView *)rootView
 {
     for (UIView* subview in [_rootContentView subviews])
diff --git a/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm b/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm
index 9be7db1..42f6978 100644
--- a/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm
+++ b/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm
@@ -372,6 +372,11 @@
     }
 }
 
+void WebPageProxy::layerTreeCommitComplete()
+{
+    m_pageClient.layerTreeCommitComplete();
+}
+
 void WebPageProxy::selectWithGesture(const WebCore::IntPoint point, WebCore::TextGranularity granularity, uint32_t gestureType, uint32_t gestureState, bool isInteractingWithAssistedNode, std::function<void (const WebCore::IntPoint&, uint32_t, uint32_t, uint32_t, CallbackBase::Error)> callbackFunction)
 {
     if (!isValid()) {
@@ -814,9 +819,9 @@
     m_pageClient.couldNotRestorePageState();
 }
 
-void WebPageProxy::restorePageState(const WebCore::FloatRect& exposedRect, double scale)
+void WebPageProxy::restorePageState(const WebCore::FloatRect& exposedContentRect, const WebCore::IntPoint& scrollOrigin, double scale)
 {
-    m_pageClient.restorePageState(exposedRect, scale);
+    m_pageClient.restorePageState(exposedContentRect, scrollOrigin, scale);
 }
 
 void WebPageProxy::restorePageCenterAndScale(const WebCore::FloatPoint& center, double scale)
diff --git a/Source/WebKit2/UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.mm b/Source/WebKit2/UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.mm
index 88b7ef4..d107aab 100644
--- a/Source/WebKit2/UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.mm
+++ b/Source/WebKit2/UIProcess/mac/RemoteLayerTreeDrawingAreaProxy.mm
@@ -229,6 +229,8 @@
         asLayer(m_debugIndicatorLayerTreeHost->rootLayer()).name = @"Indicator host root";
     }
 
+    m_webPageProxy.layerTreeCommitComplete();
+
 #if PLATFORM(IOS)
     [m_displayLinkHandler schedule];
 #else
diff --git a/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm b/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm
index 274b9d2..8a8d109 100644
--- a/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm
+++ b/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm
@@ -290,6 +290,8 @@
 
     m_userHasChangedPageScaleFactor = !historyItem.scaleIsInitial();
 
+    FrameView& frameView = *m_page->mainFrame().view();
+
     FloatSize currentMinimumLayoutSizeInScrollViewCoordinates = m_viewportConfiguration.minimumLayoutSize();
     if (historyItem.minimumLayoutSizeInScrollViewCoordinates() == currentMinimumLayoutSizeInScrollViewCoordinates) {
         float boundedScale = std::min<float>(m_viewportConfiguration.maximumScale(), std::max<float>(m_viewportConfiguration.minimumScale(), historyItem.pageScaleFactor()));
@@ -297,10 +299,9 @@
 
         m_drawingArea->setExposedContentRect(historyItem.exposedContentRect());
 
-        send(Messages::WebPageProxy::RestorePageState(historyItem.exposedContentRect(), boundedScale));
+        send(Messages::WebPageProxy::RestorePageState(historyItem.exposedContentRect(), frameView.scrollOrigin(), boundedScale));
     } else {
         IntSize oldContentSize = historyItem.contentSize();
-        FrameView& frameView = *m_page->mainFrame().view();
         IntSize newContentSize = frameView.contentsSize();
         double visibleHorizontalFraction = static_cast<float>(historyItem.unobscuredContentRect().width()) / oldContentSize.width();