<!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>[171507] 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/171507">171507</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2014-07-23 22:02:10 -0700 (Wed, 23 Jul 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[iOS][WK2] <a href="http://trac.webkit.org/projects/webkit/changeset/171124">r171124</a> is incorrect when the virtual keyboard is up
https://bugs.webkit.org/show_bug.cgi?id=135187

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2014-07-23
Reviewed by Simon Fraser.

Unfortunately, restricting the input into the document rect does not work.
When the keyboard is up, the keyboard bounds can overlap the WKWebView, and
the valid range should account for that.

Instead of playing with the keyboard rect, we can limit the scroll position
inside the valid range of UIScrollView. The keyboard always adjusts the UIScrollView
range as needed to give access to the content. Using that range is a bit more permissive
because the page could scroll to reveal content in the content inset defined by the client
of the API (this could actually be quite useful for hybrid apps).

There was already a function to change the content offset in the valid scrollview
range: changeContentOffsetBoundedInValidRange(), I extracted the range check
to contentOffsetBoundedInValidRange() for the needs of -[WKWebView _scrollToContentOffset:].

So...contentOffsetBoundedInValidRange() is cool, but it is not in the right coordinate
system. The scroll position we get from the WebProcess is in document coordinates, while
contentOffsetBoundedInValidRange() works with the UIScrollView coordinates.
To fix that, we scale the input position to get to the same scale as UIScrollView, then
apply the insets with the weirdly named [WKWebView _adjustedContentOffset:].

* UIProcess/API/Cocoa/WKWebView.mm:
(contentOffsetBoundedInValidRange):
(changeContentOffsetBoundedInValidRange):
(-[WKWebView _scrollToContentOffset:]):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPICocoaWKWebViewmm">trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (171506 => 171507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2014-07-24 04:38:03 UTC (rev 171506)
+++ trunk/Source/WebKit2/ChangeLog        2014-07-24 05:02:10 UTC (rev 171507)
</span><span class="lines">@@ -1,3 +1,35 @@
</span><ins>+2014-07-23  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [iOS][WK2] r171124 is incorrect when the virtual keyboard is up
+        https://bugs.webkit.org/show_bug.cgi?id=135187
+
+        Reviewed by Simon Fraser.
+
+        Unfortunately, restricting the input into the document rect does not work.
+        When the keyboard is up, the keyboard bounds can overlap the WKWebView, and
+        the valid range should account for that.
+
+        Instead of playing with the keyboard rect, we can limit the scroll position
+        inside the valid range of UIScrollView. The keyboard always adjusts the UIScrollView
+        range as needed to give access to the content. Using that range is a bit more permissive
+        because the page could scroll to reveal content in the content inset defined by the client
+        of the API (this could actually be quite useful for hybrid apps).
+
+        There was already a function to change the content offset in the valid scrollview
+        range: changeContentOffsetBoundedInValidRange(), I extracted the range check
+        to contentOffsetBoundedInValidRange() for the needs of -[WKWebView _scrollToContentOffset:].
+
+        So...contentOffsetBoundedInValidRange() is cool, but it is not in the right coordinate
+        system. The scroll position we get from the WebProcess is in document coordinates, while
+        contentOffsetBoundedInValidRange() works with the UIScrollView coordinates.
+        To fix that, we scale the input position to get to the same scale as UIScrollView, then
+        apply the insets with the weirdly named [WKWebView _adjustedContentOffset:].
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (contentOffsetBoundedInValidRange):
+        (changeContentOffsetBoundedInValidRange):
+        (-[WKWebView _scrollToContentOffset:]):
+
</ins><span class="cx"> 2014-07-23  Commit Queue  &lt;commit-queue@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, rolling out r171498.
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPICocoaWKWebViewmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (171506 => 171507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm        2014-07-24 04:38:03 UTC (rev 171506)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm        2014-07-24 05:02:10 UTC (rev 171507)
</span><span class="lines">@@ -784,25 +784,27 @@
</span><span class="cx">     _usesMinimalUI = NO;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void changeContentOffsetBoundedInValidRange(UIScrollView *scrollView, WebCore::FloatPoint contentOffset)
</del><ins>+static CGPoint contentOffsetBoundedInValidRange(UIScrollView *scrollView, CGPoint contentOffset)
</ins><span class="cx"> {
</span><span class="cx">     UIEdgeInsets contentInsets = scrollView.contentInset;
</span><span class="cx">     CGSize contentSize = scrollView.contentSize;
</span><span class="cx">     CGSize scrollViewSize = scrollView.bounds.size;
</span><span class="cx"> 
</span><del>-    float maxHorizontalOffset = contentSize.width + contentInsets.right - scrollViewSize.width;
-    if (contentOffset.x() &gt; maxHorizontalOffset)
-        contentOffset.setX(maxHorizontalOffset);
-    float maxVerticalOffset = contentSize.height + contentInsets.bottom - scrollViewSize.height;
-    if (contentOffset.y() &gt; maxVerticalOffset)
-        contentOffset.setY(maxVerticalOffset);
-    if (contentOffset.x() &lt; -contentInsets.left)
-        contentOffset.setX(-contentInsets.left);
-    if (contentOffset.y() &lt; -contentInsets.top)
-        contentOffset.setY(-contentInsets.top);
-    scrollView.contentOffset = contentOffset;
</del><ins>+    CGFloat maxHorizontalOffset = contentSize.width + contentInsets.right - scrollViewSize.width;
+    contentOffset.x = std::min(maxHorizontalOffset, contentOffset.x);
+    contentOffset.x = std::max(-contentInsets.left, contentOffset.x);
+
+    CGFloat maxVerticalOffset = contentSize.height + contentInsets.bottom - scrollViewSize.height;
+    contentOffset.y = std::min(maxVerticalOffset, contentOffset.y);
+    contentOffset.y = std::max(-contentInsets.top, contentOffset.y);
+    return contentOffset;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static void changeContentOffsetBoundedInValidRange(UIScrollView *scrollView, WebCore::FloatPoint contentOffset)
+{
+    scrollView.contentOffset = contentOffsetBoundedInValidRange(scrollView, contentOffset);
+}
+
</ins><span class="cx"> // WebCore stores the page scale factor as float instead of double. When we get a scale from WebCore,
</span><span class="cx"> // we need to ignore differences that are within a small rounding error on floats.
</span><span class="cx"> template &lt;typename TypeA, typename TypeB&gt;
</span><span class="lines">@@ -1002,29 +1004,22 @@
</span><span class="cx">     return contentOffset;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)_scrollToContentOffset:(WebCore::FloatPoint)contentOffset
</del><ins>+- (void)_scrollToContentOffset:(WebCore::FloatPoint)contentOffsetInPageCoordinates
</ins><span class="cx"> {
</span><span class="cx">     if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    WebCore::FloatPoint scaledOffset = contentOffset;
</del><ins>+    WebCore::FloatPoint scaledOffset = contentOffsetInPageCoordinates;
</ins><span class="cx">     CGFloat zoomScale = contentZoomScale(self);
</span><span class="cx">     scaledOffset.scale(zoomScale, zoomScale);
</span><span class="cx"> 
</span><del>-    WebCore::FloatPoint contentOffsetInDocument = scaledOffset;
-    WebCore::FloatSize documentSizeInSelfCoordinates([_contentView frame].size);
-    WebCore::FloatSize unobscuredRectSize(UIEdgeInsetsInsetRect(self.bounds, [self _computedContentInset]).size);
</del><ins>+    CGPoint contentOffsetInScrollViewCoordinates = [self _adjustedContentOffset:scaledOffset];
+    contentOffsetInScrollViewCoordinates = contentOffsetBoundedInValidRange(_scrollView.get(), contentOffsetInScrollViewCoordinates);
</ins><span class="cx"> 
</span><del>-    float maximumHorizontalOffset = documentSizeInSelfCoordinates.width() - unobscuredRectSize.width();
-    float maximumVerticalOffset = documentSizeInSelfCoordinates.height() - unobscuredRectSize.height();
-    contentOffsetInDocument = contentOffsetInDocument.shrunkTo(WebCore::FloatPoint(maximumHorizontalOffset, maximumVerticalOffset));
-    contentOffsetInDocument = contentOffsetInDocument.expandedTo(WebCore::FloatPoint(0, 0));
-
</del><span class="cx">     [_scrollView _stopScrollingAndZoomingAnimations];
</span><span class="cx"> 
</span><del>-    CGPoint adjustedContentOffset = [self _adjustedContentOffset:contentOffsetInDocument];
-    if (!CGPointEqualToPoint(adjustedContentOffset, [_scrollView contentOffset]))
-        [_scrollView setContentOffset:adjustedContentOffset];
</del><ins>+    if (!CGPointEqualToPoint(contentOffsetInScrollViewCoordinates, [_scrollView contentOffset]))
+        [_scrollView setContentOffset:contentOffsetInScrollViewCoordinates];
</ins><span class="cx">     else {
</span><span class="cx">         // If we haven't changed anything, there would not be any VisibleContentRect update sent to the content.
</span><span class="cx">         // The WebProcess would keep the invalid contentOffset as its scroll position.
</span></span></pre>
</div>
</div>

</body>
</html>