<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[167614] trunk/Source/WebKit2</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/167614">167614</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2014-04-21 13:10:12 -0700 (Mon, 21 Apr 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[iOS][WK2] Make dynamic viewport size update content aware
https://bugs.webkit.org/show_bug.cgi?id=131874

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2014-04-21
Reviewed by Tim Horton.

When possible, adjust the scroll position based on the content on dynamic viewport resize.

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::WebPage):
(WebKit::WebPage::scalePage):
(WebKit::WebPage::pageDidScroll):
* WebProcess/WebPage/WebPage.h:
The scrolling heuristic are not invertible, especially the content heuristic. To have the right
behavior when doing resize without changing the page, we save the old scroll position and restore
it when the content size and scale is restored.

* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::dynamicViewportSizeUpdate):
On dynamic update, start by finding what node is at the center of the screen. After the layout, put that
node back in the center.

(WebKit::WebPage::updateVisibleContentRects):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageWebPagecpp">trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageWebPageh">trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageiosWebPageIOSmm">trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (167613 => 167614)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2014-04-21 19:53:55 UTC (rev 167613)
+++ trunk/Source/WebKit2/ChangeLog        2014-04-21 20:10:12 UTC (rev 167614)
</span><span class="lines">@@ -1,3 +1,28 @@
</span><ins>+2014-04-21  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [iOS][WK2] Make dynamic viewport size update content aware
+        https://bugs.webkit.org/show_bug.cgi?id=131874
+
+        Reviewed by Tim Horton.
+
+        When possible, adjust the scroll position based on the content on dynamic viewport resize.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::WebPage):
+        (WebKit::WebPage::scalePage):
+        (WebKit::WebPage::pageDidScroll):
+        * WebProcess/WebPage/WebPage.h:
+        The scrolling heuristic are not invertible, especially the content heuristic. To have the right
+        behavior when doing resize without changing the page, we save the old scroll position and restore
+        it when the content size and scale is restored.
+
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::dynamicViewportSizeUpdate):
+        On dynamic update, start by finding what node is at the center of the screen. After the layout, put that
+        node back in the center.
+
+        (WebKit::WebPage::updateVisibleContentRects):
+
</ins><span class="cx"> 2014-04-21  Anders Carlsson  &lt;andersca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Need default WKNavigationDelegate behavior
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageWebPagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (167613 => 167614)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp        2014-04-21 19:53:55 UTC (rev 167613)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp        2014-04-21 20:10:12 UTC (rev 167614)
</span><span class="lines">@@ -288,6 +288,7 @@
</span><span class="cx">     , m_userHasChangedPageScaleFactor(false)
</span><span class="cx">     , m_screenSize(parameters.screenSize)
</span><span class="cx">     , m_availableScreenSize(parameters.availableScreenSize)
</span><ins>+    , m_inDynamicSizeUpdate(false)
</ins><span class="cx"> #endif
</span><span class="cx">     , m_inspectorClient(0)
</span><span class="cx">     , m_backgroundColor(Color::white)
</span><span class="lines">@@ -1286,6 +1287,8 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS)
</span><ins>+    if (!m_inDynamicSizeUpdate)
+        m_dynamicSizeUpdateHistory.clear();
</ins><span class="cx">     m_scaleWasSetByUIProcess = false;
</span><span class="cx"> #endif
</span><span class="cx">     PluginView* pluginView = pluginViewForFrame(&amp;m_page-&gt;mainFrame());
</span><span class="lines">@@ -1620,6 +1623,10 @@
</span><span class="cx"> 
</span><span class="cx"> void WebPage::pageDidScroll()
</span><span class="cx"> {
</span><ins>+#if PLATFORM(IOS)
+    if (!m_inDynamicSizeUpdate)
+        m_dynamicSizeUpdateHistory.clear();
+#endif
</ins><span class="cx">     m_uiClient-&gt;pageDidScroll(this);
</span><span class="cx"> 
</span><span class="cx">     send(Messages::WebPageProxy::PageDidScroll());
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageWebPageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h (167613 => 167614)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h        2014-04-21 19:53:55 UTC (rev 167613)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h        2014-04-21 20:10:12 UTC (rev 167614)
</span><span class="lines">@@ -50,6 +50,7 @@
</span><span class="cx"> #include &lt;WebCore/Editor.h&gt;
</span><span class="cx"> #include &lt;WebCore/FrameLoaderTypes.h&gt;
</span><span class="cx"> #include &lt;WebCore/IntRect.h&gt;
</span><ins>+#include &lt;WebCore/IntSizeHash.h&gt;
</ins><span class="cx"> #include &lt;WebCore/Page.h&gt;
</span><span class="cx"> #include &lt;WebCore/PageVisibilityState.h&gt;
</span><span class="cx"> #include &lt;WebCore/ScrollTypes.h&gt;
</span><span class="lines">@@ -1159,6 +1160,8 @@
</span><span class="cx">     WebCore::FloatSize m_screenSize;
</span><span class="cx">     WebCore::FloatSize m_availableScreenSize;
</span><span class="cx">     WebCore::IntSize m_blockSelectionDesiredSize;
</span><ins>+    bool m_inDynamicSizeUpdate;
+    HashMap&lt;std::pair&lt;WebCore::IntSize, double&gt;, WebCore::IntPoint&gt; m_dynamicSizeUpdateHistory;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     WebInspectorClient* m_inspectorClient;
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageiosWebPageIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm (167613 => 167614)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm        2014-04-21 19:53:55 UTC (rev 167613)
+++ trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm        2014-04-21 20:10:12 UTC (rev 167614)
</span><span class="lines">@@ -75,12 +75,14 @@
</span><span class="cx"> #import &lt;WebCore/PlatformMouseEvent.h&gt;
</span><span class="cx"> #import &lt;WebCore/RenderBlock.h&gt;
</span><span class="cx"> #import &lt;WebCore/RenderImage.h&gt;
</span><ins>+#import &lt;WebCore/RenderView.h&gt;
</ins><span class="cx"> #import &lt;WebCore/ResourceBuffer.h&gt;
</span><span class="cx"> #import &lt;WebCore/SharedBuffer.h&gt;
</span><span class="cx"> #import &lt;WebCore/TextIterator.h&gt;
</span><span class="cx"> #import &lt;WebCore/VisibleUnits.h&gt;
</span><span class="cx"> #import &lt;WebCore/WKContentObservation.h&gt;
</span><span class="cx"> #import &lt;WebCore/WebEvent.h&gt;
</span><ins>+#import &lt;wtf/TemporaryChange.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> using namespace WebCore;
</span><span class="cx"> 
</span><span class="lines">@@ -1764,12 +1766,40 @@
</span><span class="cx"> 
</span><span class="cx"> void WebPage::dynamicViewportSizeUpdate(const IntSize&amp; minimumLayoutSize, const FloatRect&amp; targetExposedContentRect, const FloatRect&amp; targetUnobscuredRect, double targetScale)
</span><span class="cx"> {
</span><ins>+    TemporaryChange&lt;bool&gt; dynamicSizeUpdateGuard(m_inDynamicSizeUpdate, true);
</ins><span class="cx">     // FIXME: this does not handle the cases where the content would change the content size or scroll position from JavaScript.
</span><span class="cx">     // To handle those cases, we would need to redo this computation on every change until the next visible content rect update.
</span><span class="cx"> 
</span><span class="cx">     FrameView&amp; frameView = *m_page-&gt;mainFrame().view();
</span><span class="cx">     IntSize oldContentSize = frameView.contentsSize();
</span><ins>+    float oldPageScaleFactor = m_page-&gt;pageScaleFactor();
</ins><span class="cx"> 
</span><ins>+    m_dynamicSizeUpdateHistory.add(std::make_pair(oldContentSize, oldPageScaleFactor), IntPoint(frameView.scrollOffset()));
+
+    RefPtr&lt;Node&gt; oldNodeAtCenter;
+    float relativeHorizontalPositionInNodeAtCenter = 0;
+    float relativeVerticalPositionInNodeAtCenter = 0;
+    {
+        IntRect unobscuredContentRect = frameView.unobscuredContentRect();
+        IntPoint unobscuredContentRectCenter = unobscuredContentRect.center();
+
+        HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
+        HitTestResult hitTestResult = HitTestResult(unobscuredContentRectCenter);
+
+        RenderView* mainFrameRenderView = frameView.renderView();
+        mainFrameRenderView-&gt;hitTest(request, hitTestResult);
+
+        if (Node* node = hitTestResult.innerNode()) {
+            if (RenderObject* renderer = node-&gt;renderer()) {
+                FrameView&amp; containingView = *node-&gt;document().frame()-&gt;view();
+                FloatRect boundingBox = containingView.contentsToRootView(renderer-&gt;absoluteBoundingBoxRect(true));
+                relativeHorizontalPositionInNodeAtCenter = (unobscuredContentRectCenter.x() - boundingBox.x()) / boundingBox.width();
+                relativeVerticalPositionInNodeAtCenter = (unobscuredContentRectCenter.y() - boundingBox.y()) / boundingBox.height();
+                oldNodeAtCenter = node;
+            }
+        }
+    }
+
</ins><span class="cx">     m_viewportConfiguration.setMinimumLayoutSize(minimumLayoutSize);
</span><span class="cx">     IntSize newLayoutSize = m_viewportConfiguration.layoutSize();
</span><span class="cx">     setFixedLayoutSize(newLayoutSize);
</span><span class="lines">@@ -1807,21 +1837,34 @@
</span><span class="cx">                                           newUnobscuredRectY - obscuredTopMargin,
</span><span class="cx">                                           newUnobscuredRectWidth + obscuredLeftMargin + obscuredRightMargin,
</span><span class="cx">                                           newUnobscuredRectHeight + obscuredTopMargin + obscuredBottomMargin);
</span><del>-
-        // FIXME: Adjust the rects based on the content.
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (oldContentSize != newContentSize || scale != targetScale) {
</span><span class="cx">         // Snap the new unobscured rect back into the content rect.
</span><del>-        newUnobscuredContentRect.setWidth(std::min(static_cast&lt;float&gt;(newContentSize.width()), newExposedContentRect.width()));
-        newUnobscuredContentRect.setHeight(std::min(static_cast&lt;float&gt;(newContentSize.height()), newExposedContentRect.height()));
</del><ins>+        newUnobscuredContentRect.setWidth(std::min(static_cast&lt;float&gt;(newContentSize.width()), newUnobscuredContentRect.width()));
+        newUnobscuredContentRect.setHeight(std::min(static_cast&lt;float&gt;(newContentSize.height()), newUnobscuredContentRect.height()));
</ins><span class="cx"> 
</span><del>-        if (oldContentSize != newContentSize) {
-            // If the content size has changed, keep the same relative position.
-            FloatPoint oldContentCenter = targetUnobscuredRect.center();
-            float relativeHorizontalPosition = oldContentCenter.x() / oldContentSize.width();
-            float relativeVerticalPosition =  oldContentCenter.y() / oldContentSize.height();
-            FloatPoint newRelativeContentCenter(relativeHorizontalPosition * newContentSize.width(), relativeVerticalPosition * newContentSize.height());
</del><ins>+        const auto&amp; previousPosition = m_dynamicSizeUpdateHistory.find(std::pair&lt;IntSize, float&gt;(newContentSize, scale));
+        if (previousPosition != m_dynamicSizeUpdateHistory.end()) {
+            IntPoint restoredPosition = previousPosition-&gt;value;
+            FloatPoint deltaPosition(restoredPosition.x() - newUnobscuredContentRect.x(), restoredPosition.y() - newUnobscuredContentRect.y());
+            newUnobscuredContentRect.moveBy(deltaPosition);
+            newExposedContentRect.moveBy(deltaPosition);
+        } else if (oldContentSize != newContentSize) {
+            FloatPoint newRelativeContentCenter;
+
+            if (RenderObject* renderer = oldNodeAtCenter ? oldNodeAtCenter-&gt;renderer() : nullptr) {
+                FrameView&amp; containingView = *oldNodeAtCenter-&gt;document().frame()-&gt;view();
+                FloatRect newBoundingBox = containingView.contentsToRootView(renderer-&gt;absoluteBoundingBoxRect(true));
+                newRelativeContentCenter = FloatPoint(newBoundingBox.x() + relativeHorizontalPositionInNodeAtCenter * newBoundingBox.width(), newBoundingBox.y() + relativeVerticalPositionInNodeAtCenter * newBoundingBox.height());
+            } else {
+                // If the content size has changed, keep the same relative position.
+                FloatPoint oldContentCenter = targetUnobscuredRect.center();
+                float relativeHorizontalPosition = oldContentCenter.x() / oldContentSize.width();
+                float relativeVerticalPosition =  oldContentCenter.y() / oldContentSize.height();
+                newRelativeContentCenter = FloatPoint(relativeHorizontalPosition * newContentSize.width(), relativeVerticalPosition * newContentSize.height());
+            }
+
</ins><span class="cx">             FloatPoint newUnobscuredContentRectCenter = newUnobscuredContentRect.center();
</span><span class="cx">             FloatPoint positionDelta(newRelativeContentCenter.x() - newUnobscuredContentRectCenter.x(), newRelativeContentCenter.y() - newUnobscuredContentRectCenter.y());
</span><span class="cx">             newUnobscuredContentRect.moveBy(positionDelta);
</span><span class="lines">@@ -1863,10 +1906,10 @@
</span><span class="cx">     m_drawingArea-&gt;setExposedContentRect(newExposedContentRect);
</span><span class="cx"> 
</span><span class="cx">     if (scale == targetScale)
</span><del>-        scalePage(scale, frameView.scrollPosition());
</del><ins>+        scalePage(scale, roundedUnobscuredContentRect.location());
</ins><span class="cx"> 
</span><span class="cx">     if (scale != targetScale || roundedIntPoint(targetUnobscuredRect.location()) != roundedUnobscuredContentRect.location())
</span><del>-        send(Messages::WebPageProxy::DynamicViewportUpdateChangedTarget(scale, frameView.scrollPosition()));
</del><ins>+        send(Messages::WebPageProxy::DynamicViewportUpdateChangedTarget(scale, roundedUnobscuredContentRect.location()));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebPage::viewportConfigurationChanged()
</span><span class="lines">@@ -1957,21 +2000,27 @@
</span><span class="cx">     if (floatBoundedScale != m_page-&gt;pageScaleFactor()) {
</span><span class="cx">         m_scaleWasSetByUIProcess = true;
</span><span class="cx"> 
</span><ins>+        m_dynamicSizeUpdateHistory.clear();
+
</ins><span class="cx">         m_page-&gt;setPageScaleFactor(floatBoundedScale, scrollPosition);
</span><del>-        if (m_drawingArea-&gt;layerTreeHost())
-            m_drawingArea-&gt;layerTreeHost()-&gt;deviceOrPageScaleFactorChanged();
</del><ins>+        if (LayerTreeHost* layerTreeHost = m_drawingArea-&gt;layerTreeHost())
+            layerTreeHost-&gt;deviceOrPageScaleFactorChanged();
</ins><span class="cx">         send(Messages::WebPageProxy::PageScaleFactorDidChange(floatBoundedScale));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_page-&gt;mainFrame().view()-&gt;setScrollOffset(scrollPosition);
-    m_page-&gt;mainFrame().view()-&gt;setUnobscuredContentRect(roundedUnobscuredRect);
</del><ins>+    FrameView&amp; frameView = *m_page-&gt;mainFrame().view();
+    if (scrollPosition != IntPoint(frameView.scrollOffset()))
+        m_dynamicSizeUpdateHistory.clear();
</ins><span class="cx"> 
</span><ins>+    frameView.setScrollOffset(scrollPosition);
+    frameView.setUnobscuredContentRect(roundedUnobscuredRect);
+
</ins><span class="cx">     double horizontalVelocity = visibleContentRectUpdateInfo.horizontalVelocity();
</span><span class="cx">     double verticalVelocity = visibleContentRectUpdateInfo.verticalVelocity();
</span><span class="cx">     double scaleChangeRate = visibleContentRectUpdateInfo.scaleChangeRate();
</span><span class="cx">     adjustVelocityDataForBoundedScale(horizontalVelocity, verticalVelocity, scaleChangeRate, visibleContentRectUpdateInfo.scale(), boundedScale);
</span><span class="cx"> 
</span><del>-    m_page-&gt;mainFrame().view()-&gt;setScrollVelocity(horizontalVelocity, verticalVelocity, scaleChangeRate, visibleContentRectUpdateInfo.timestamp());
</del><ins>+    frameView.setScrollVelocity(horizontalVelocity, verticalVelocity, scaleChangeRate, visibleContentRectUpdateInfo.timestamp());
</ins><span class="cx"> 
</span><span class="cx">     if (visibleContentRectUpdateInfo.inStableState())
</span><span class="cx">         m_page-&gt;mainFrame().view()-&gt;setCustomFixedPositionLayoutRect(enclosingIntRect(visibleContentRectUpdateInfo.customFixedPositionRect()));
</span></span></pre>
</div>
</div>

</body>
</html>