<!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>[245317] trunk</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/245317">245317</a></dd>
<dt>Author</dt> <dd>wenson_hsieh@apple.com</dd>
<dt>Date</dt> <dd>2019-05-14 21:57:56 -0700 (Tue, 14 May 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>Missing cursor/caret showing in search field on google.com
https://bugs.webkit.org/show_bug.cgi?id=197862
<rdar://problem/50291989>

Reviewed by Simon Fraser.

Source/WebCore:

In this bug, the search field is inside of a fixed position container, which is inside of an empty "overflow:
hidden" form element (the new layout test demonstrates a simple version of this). The layer of the fixed
position container's renderer has an overflow clipping layer of itself, and its clipping rect is non-empty, so
the heuristic initially identifies the layer as not fully clipped. However, as the heuristic ascends the
RenderLayer tree, it then finds the layer for the "overflow: hidden" form element's renderer; this layer is
completely clipped, which causes the heuristic to incorrectly believe that the editable element is completely
clipped.

To fix the bug, this patch reworks the clipping portion of the heuristic, such that we no longer need to ascend
the layer tree. Instead of computing the clip rect relative to the nearest ancestor that has an overflow clip
and then walking up the layer tree repeating this process, simply compute the clip rect relative to RenderView's
layer, and then walk up to the parent frame and repeat if necessary.

Test: editing/selection/ios/do-not-hide-selection-in-visible-field.html

* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::isTransparentOrFullyClippedRespectingParentFrames const):

LayoutTests:

Add a new layout test that represents a reduced test case version of google.com's search field.

* editing/selection/ios/do-not-hide-selection-in-visible-field.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderLayercpp">trunk/Source/WebCore/rendering/RenderLayer.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestseditingselectioniosdonothideselectioninvisiblefieldexpectedtxt">trunk/LayoutTests/editing/selection/ios/do-not-hide-selection-in-visible-field-expected.txt</a></li>
<li><a href="#trunkLayoutTestseditingselectioniosdonothideselectioninvisiblefieldhtml">trunk/LayoutTests/editing/selection/ios/do-not-hide-selection-in-visible-field.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (245316 => 245317)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2019-05-15 04:00:05 UTC (rev 245316)
+++ trunk/LayoutTests/ChangeLog 2019-05-15 04:57:56 UTC (rev 245317)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2019-05-14  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Missing cursor/caret showing in search field on google.com
+        https://bugs.webkit.org/show_bug.cgi?id=197862
+        <rdar://problem/50291989>
+
+        Reviewed by Simon Fraser.
+
+        Add a new layout test that represents a reduced test case version of google.com's search field.
+
+        * editing/selection/ios/do-not-hide-selection-in-visible-field.html: Added.
+
</ins><span class="cx"> 2019-05-14  Megan Gardner  <megan_gardner@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Fix flakey test fast/events/autoscroll-when-input-is-offscreen.html
</span></span></pre></div>
<a id="trunkLayoutTestseditingselectioniosdonothideselectioninvisiblefieldexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/selection/ios/do-not-hide-selection-in-visible-field-expected.txt (0 => 245317)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/selection/ios/do-not-hide-selection-in-visible-field-expected.txt                              (rev 0)
+++ trunk/LayoutTests/editing/selection/ios/do-not-hide-selection-in-visible-field-expected.txt 2019-05-15 04:57:56 UTC (rev 245317)
</span><span class="lines">@@ -0,0 +1,15 @@
</span><ins>+
+Click me
+This test verifies platform selection UI is not incorrectly suppressed when the editable element is visible. To manually run the test, tap the button to focus the search field, and confirm that the caret view appears in the field.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS caretRect.top is 7
+PASS caretRect.left is 11
+PASS caretRect.width is 2
+PASS caretRect.height is 25
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestseditingselectioniosdonothideselectioninvisiblefieldhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/selection/ios/do-not-hide-selection-in-visible-field.html (0 => 245317)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/selection/ios/do-not-hide-selection-in-visible-field.html                              (rev 0)
+++ trunk/LayoutTests/editing/selection/ios/do-not-hide-selection-in-visible-field.html 2019-05-15 04:57:56 UTC (rev 245317)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <script src="../../../resources/ui-helper.js"></script>
+    <script src="../../../resources/js-test.js"></script>
+    <style>
+        html, body {
+            width: 100%;
+            height: 100%;
+            margin: 0;
+            padding: 0;
+        }
+
+        form {
+            overflow: hidden;
+        }
+
+        input, p {
+            font-size: 20px;
+            width: 300px;
+        }
+
+        .fixed {
+            position: fixed;
+            width: 100%;
+            height: 100%;
+            top: 0;
+            left: 0;
+            overflow: auto;
+        }
+
+        button {
+            position: absolute;
+            top: 40px;
+        }
+    </style>
+</head>
+<body>
+    <form>
+        <div class="fixed">
+            <input type="search" />
+        </div>
+    </form>
+    <button>Click me</button>
+    <p id="description"></p>
+    <p id="console"></p>
+</body>
+<script>
+    jsTestIsAsync = true;
+
+    description("This test verifies platform selection UI is not incorrectly suppressed when the editable element is visible. To manually run the test, tap the button to focus the search field, and confirm that the caret view appears in the field.");
+
+    const button = document.querySelector("button");
+    button.addEventListener("click", () => document.querySelector("input").focus());
+
+    addEventListener("load", async () => {
+        if (!window.testRunner)
+            return;
+
+        await UIHelper.activateElementAndWaitForInputSession(button);
+
+        caretRect = null;
+        while (!caretRect || !caretRect.width || !caretRect.height)
+            caretRect = await UIHelper.getUICaretViewRect();
+
+        shouldBe("caretRect.top", "7");
+        shouldBe("caretRect.left", "11");
+        shouldBe("caretRect.width", "2");
+        shouldBe("caretRect.height", "25");
+        finishJSTest();
+    });
+</script>
+</html>
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (245316 => 245317)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2019-05-15 04:00:05 UTC (rev 245316)
+++ trunk/Source/WebCore/ChangeLog      2019-05-15 04:57:56 UTC (rev 245317)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2019-05-14  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Missing cursor/caret showing in search field on google.com
+        https://bugs.webkit.org/show_bug.cgi?id=197862
+        <rdar://problem/50291989>
+
+        Reviewed by Simon Fraser.
+
+        In this bug, the search field is inside of a fixed position container, which is inside of an empty "overflow:
+        hidden" form element (the new layout test demonstrates a simple version of this). The layer of the fixed
+        position container's renderer has an overflow clipping layer of itself, and its clipping rect is non-empty, so
+        the heuristic initially identifies the layer as not fully clipped. However, as the heuristic ascends the
+        RenderLayer tree, it then finds the layer for the "overflow: hidden" form element's renderer; this layer is
+        completely clipped, which causes the heuristic to incorrectly believe that the editable element is completely
+        clipped.
+
+        To fix the bug, this patch reworks the clipping portion of the heuristic, such that we no longer need to ascend
+        the layer tree. Instead of computing the clip rect relative to the nearest ancestor that has an overflow clip
+        and then walking up the layer tree repeating this process, simply compute the clip rect relative to RenderView's
+        layer, and then walk up to the parent frame and repeat if necessary.
+
+        Test: editing/selection/ios/do-not-hide-selection-in-visible-field.html
+
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::isTransparentOrFullyClippedRespectingParentFrames const):
+
</ins><span class="cx"> 2019-05-14  Andy Estes  <aestes@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [Apple Pay] Payment APIs should be completely disabled in web views into which clients have injected user scripts
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderLayercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (245316 => 245317)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderLayer.cpp   2019-05-15 04:00:05 UTC (rev 245316)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp      2019-05-15 04:57:56 UTC (rev 245317)
</span><span class="lines">@@ -6801,17 +6801,28 @@
</span><span class="cx">             return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    RenderLayer* enclosingClipLayer = nullptr;
-    for (auto* layer = this; layer; layer = enclosingClipLayer ? enclosingClipLayer->parent() : enclosingFrameRenderLayer(*layer)) {
-        enclosingClipLayer = layer->enclosingOverflowClipLayer(IncludeSelfOrNot::IncludeSelf);
-        if (!enclosingClipLayer)
-            continue;
</del><ins>+    auto hasEmptyClipRect = [] (const RenderLayer& layer) -> bool {
+        auto* frameView = layer.renderer().document().view();
+        if (!frameView)
+            return false;
</ins><span class="cx"> 
</span><ins>+        auto* renderView = frameView->renderView();
+        if (!renderView)
+            return false;
+
+        auto* renderViewLayer = renderView->layer();
+        if (!renderViewLayer)
+            return false;
+
</ins><span class="cx">         LayoutRect layerBounds;
</span><span class="cx">         ClipRect backgroundRect;
</span><span class="cx">         ClipRect foregroundRect;
</span><del>-        layer->calculateRects({ enclosingClipLayer, TemporaryClipRects }, LayoutRect::infiniteRect(), layerBounds, backgroundRect, foregroundRect, layer->offsetFromAncestor(enclosingClipLayer));
-        if (backgroundRect.isEmpty())
</del><ins>+        layer.calculateRects({ renderViewLayer, TemporaryClipRects }, LayoutRect::infiniteRect(), layerBounds, backgroundRect, foregroundRect, layer.offsetFromAncestor(renderViewLayer));
+        return backgroundRect.isEmpty();
+    };
+
+    for (auto* layer = this; layer; layer = enclosingFrameRenderLayer(*layer)) {
+        if (hasEmptyClipRect(*layer))
</ins><span class="cx">             return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>