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

<h3>Log Message</h3>
<pre>[iOS WK2] Protect WKWebView dynamic viewport change against empty sizes
https://bugs.webkit.org/show_bug.cgi?id=137988
rdar://problem/17785162

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

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _beginAnimatedResizeWithUpdates:]):
The algorithm behind dynamic size update finds the best content area to put in the viewport
after a viewport change. If an initial size or a target size is empty, it is impossible to
compute a reasonable area to keep in the view. We end up handling NaN scales
and/or sizes and CoreAnimation raises an exception when applying that value.

This patch add early exits when that occurs and fallback to the common code.

On Input, things are easy. If any of the initial values is empty, we just execute the updateBlock
without attempting any of the dynamic behaviors.

For the target values, things are trickier. We do not know what the values are going to be before we execute
the block. But once we executed the block, we have already skipped all the setters that call the web process.

To handle that, every value is set manually on WebPageProxy. This is a bit unfortunate because the setters
get yet another entry point.</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 (175080 => 175081)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2014-10-23 02:39:14 UTC (rev 175080)
+++ trunk/Source/WebKit2/ChangeLog        2014-10-23 02:40:07 UTC (rev 175081)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2014-10-22  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [iOS WK2] Protect WKWebView dynamic viewport change against empty sizes
+        https://bugs.webkit.org/show_bug.cgi?id=137988
+        rdar://problem/17785162
+
+        Reviewed by Simon Fraser.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _beginAnimatedResizeWithUpdates:]):
+        The algorithm behind dynamic size update finds the best content area to put in the viewport
+        after a viewport change. If an initial size or a target size is empty, it is impossible to
+        compute a reasonable area to keep in the view. We end up handling NaN scales
+        and/or sizes and CoreAnimation raises an exception when applying that value.
+
+        This patch add early exits when that occurs and fallback to the common code.
+
+        On Input, things are easy. If any of the initial values is empty, we just execute the updateBlock
+        without attempting any of the dynamic behaviors.
+
+        For the target values, things are trickier. We do not know what the values are going to be before we execute
+        the block. But once we executed the block, we have already skipped all the setters that call the web process.
+
+        To handle that, every value is set manually on WebPageProxy. This is a bit unfortunate because the setters
+        get yet another entry point.
+
</ins><span class="cx"> 2014-10-22  Gyuyoung Kim  &lt;gyuyoung.kim@samsung.com&gt;
</span><span class="cx"> 
</span><span class="cx">         EFL and GTK ports have broken since r175075
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPICocoaWKWebViewmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (175080 => 175081)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm        2014-10-23 02:39:14 UTC (rev 175080)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm        2014-10-23 02:40:07 UTC (rev 175081)
</span><span class="lines">@@ -2197,20 +2197,21 @@
</span><span class="cx"> 
</span><span class="cx"> - (void)_beginAnimatedResizeWithUpdates:(void (^)(void))updateBlock
</span><span class="cx"> {
</span><del>-    if (_customContentView || !_hasCommittedLoadForMainFrame) {
</del><ins>+    CGRect oldBounds = self.bounds;
+    WebCore::FloatRect oldUnobscuredContentRect = _page-&gt;unobscuredContentRect();
+
+    if (_customContentView || !_hasCommittedLoadForMainFrame || CGRectIsEmpty(oldBounds) || oldUnobscuredContentRect.isEmpty()) {
</ins><span class="cx">         updateBlock();
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _dynamicViewportUpdateMode = DynamicViewportUpdateMode::ResizingWithAnimation;
</span><span class="cx"> 
</span><del>-    CGRect oldBounds = self.bounds;
</del><span class="cx">     WebCore::FloatSize oldMinimumLayoutSize = activeMinimumLayoutSize(self, oldBounds);
</span><span class="cx">     WebCore::FloatSize oldMinimumLayoutSizeForMinimalUI = activeMinimumLayoutSizeForMinimalUI(self, oldMinimumLayoutSize);
</span><span class="cx">     WebCore::FloatSize oldMaximumUnobscuredSize = activeMaximumUnobscuredSize(self, oldBounds);
</span><span class="cx">     int32_t oldOrientation = activeOrientation(self);
</span><span class="cx">     UIEdgeInsets oldObscuredInsets = _obscuredInsets;
</span><del>-    WebCore::FloatRect oldUnobscuredContentRect = _page-&gt;unobscuredContentRect();
</del><span class="cx"> 
</span><span class="cx">     updateBlock();
</span><span class="cx"> 
</span><span class="lines">@@ -2220,7 +2221,25 @@
</span><span class="cx">     WebCore::FloatSize newMaximumUnobscuredSize = activeMaximumUnobscuredSize(self, newBounds);
</span><span class="cx">     int32_t newOrientation = activeOrientation(self);
</span><span class="cx">     UIEdgeInsets newObscuredInsets = _obscuredInsets;
</span><ins>+    CGRect futureUnobscuredRectInSelfCoordinates = UIEdgeInsetsInsetRect(newBounds, _obscuredInsets);
</ins><span class="cx"> 
</span><ins>+    ASSERT_WITH_MESSAGE(!(_overridesMinimumLayoutSize &amp;&amp; newMinimumLayoutSize.isEmpty()), &quot;Clients controlling the layout size should maintain a valid layout size to minimize layouts.&quot;);
+    ASSERT_WITH_MESSAGE(!(_overridesMinimumLayoutSizeForMinimalUI &amp;&amp; newMinimumLayoutSizeForMinimalUI.isEmpty()), &quot;Clients controlling the layout size should maintain a valid layout size for minimal UI to minimize layouts.&quot;);
+    if (CGRectIsEmpty(newBounds) || newMinimumLayoutSize.isEmpty() || newMinimumLayoutSizeForMinimalUI.isEmpty() || CGRectIsEmpty(futureUnobscuredRectInSelfCoordinates)) {
+        _dynamicViewportUpdateMode = DynamicViewportUpdateMode::NotResizing;
+        [self _frameOrBoundsChanged];
+        if (_overridesMinimumLayoutSize)
+            _page-&gt;setViewportConfigurationMinimumLayoutSize(WebCore::FloatSize(newMinimumLayoutSize));
+        if (_overridesMinimumLayoutSizeForMinimalUI)
+            _page-&gt;setViewportConfigurationMinimumLayoutSizeForMinimalUI(WebCore::FloatSize(newMinimumLayoutSizeForMinimalUI));
+        if (_overridesMaximumUnobscuredSize)
+            _page-&gt;setMaximumUnobscuredSize(WebCore::FloatSize(newMaximumUnobscuredSize));
+        if (_overridesInterfaceOrientation)
+            _page-&gt;setDeviceOrientation(newOrientation);
+        [self _updateVisibleContentRects];
+        return;
+    }
+
</ins><span class="cx">     if (CGRectEqualToRect(oldBounds, newBounds)
</span><span class="cx">         &amp;&amp; oldMinimumLayoutSize == newMinimumLayoutSize
</span><span class="cx">         &amp;&amp; oldMinimumLayoutSizeForMinimalUI == newMinimumLayoutSizeForMinimalUI
</span><span class="lines">@@ -2254,7 +2273,6 @@
</span><span class="cx">     // Compute a new position to keep the content centered.
</span><span class="cx">     CGPoint originalContentCenter = oldUnobscuredContentRect.center();
</span><span class="cx">     CGPoint originalContentCenterInSelfCoordinates = [self convertPoint:originalContentCenter fromView:_contentView.get()];
</span><del>-    CGRect futureUnobscuredRectInSelfCoordinates = UIEdgeInsetsInsetRect(newBounds, _obscuredInsets);
</del><span class="cx">     CGPoint futureUnobscuredRectCenterInSelfCoordinates = CGPointMake(futureUnobscuredRectInSelfCoordinates.origin.x + futureUnobscuredRectInSelfCoordinates.size.width / 2, futureUnobscuredRectInSelfCoordinates.origin.y + futureUnobscuredRectInSelfCoordinates.size.height / 2);
</span><span class="cx"> 
</span><span class="cx">     CGPoint originalContentOffset = [_scrollView contentOffset];
</span></span></pre>
</div>
</div>

</body>
</html>