<!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>[235834] 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/235834">235834</a></dd>
<dt>Author</dt> <dd>wenson_hsieh@apple.com</dd>
<dt>Date</dt> <dd>2018-09-08 20:25:05 -0700 (Sat, 08 Sep 2018)</dd>
</dl>

<h3>Log Message</h3>
<pre>REGRESSION (<a href="http://trac.webkit.org/projects/webkit/changeset/235153">r235153</a>): [iOS] Can't move selection start grabber when selecting text in a subframe
https://bugs.webkit.org/show_bug.cgi?id=189454
<rdar://problem/44265956>

Reviewed by Darin Adler.

Source/WebKit:

rangeForPointInRootViewCoordinates is responsible for taking a user gesture location representing the location
of the selection start or end handle (given in root view coordinates) and computing a Range representing an
updated selection. <a href="http://trac.webkit.org/projects/webkit/changeset/235153">r235153</a> introduced a mechanism here to clamp the y offset of this user gesture location to
a max or min value determined by computing the bounds of the other selection handle, which more closely matches
platform behavior elsewhere in iOS.

However, this clamping logic would cause the user gesture location in root view coordinates to incorrectly clamp
in cases where the user selects text within an iframe that is offset from the top of the main document, since it
compares content coordinates (i.e. the caret bounds) against root view coordinates (i.e. the gesture location).
This makes it impossible to use selection handles to select text in some iframes.

We fix this by first converting the gesture location to document coordinates, and then clamping.

Test: editing/selection/ios/selection-handle-clamping-in-iframe.html

* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::rangeForPointInRootViewCoordinates):

Also reuse `selectionStart` and `selectionEnd` when computing absolute caret bounds, instead of creating new
VisiblePositions.

LayoutTests:

Adds a test that selects a word inside an iframe, moves the selection start handle down past the selection end,
and then moves the selection end handle up above the selection start. The test verifies that the entire word
remains selected.

* editing/selection/ios/selection-handle-clamping-in-iframe-expected.txt: Added.
* editing/selection/ios/selection-handle-clamping-in-iframe.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitWebProcessWebPageiosWebPageIOSmm">trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestseditingselectioniosselectionhandleclampinginiframeexpectedtxt">trunk/LayoutTests/editing/selection/ios/selection-handle-clamping-in-iframe-expected.txt</a></li>
<li><a href="#trunkLayoutTestseditingselectioniosselectionhandleclampinginiframehtml">trunk/LayoutTests/editing/selection/ios/selection-handle-clamping-in-iframe.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (235833 => 235834)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2018-09-09 02:03:52 UTC (rev 235833)
+++ trunk/LayoutTests/ChangeLog 2018-09-09 03:25:05 UTC (rev 235834)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2018-09-08  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        REGRESSION (r235153): [iOS] Can't move selection start grabber when selecting text in a subframe
+        https://bugs.webkit.org/show_bug.cgi?id=189454
+        <rdar://problem/44265956>
+
+        Reviewed by Darin Adler.
+
+        Adds a test that selects a word inside an iframe, moves the selection start handle down past the selection end,
+        and then moves the selection end handle up above the selection start. The test verifies that the entire word
+        remains selected.
+
+        * editing/selection/ios/selection-handle-clamping-in-iframe-expected.txt: Added.
+        * editing/selection/ios/selection-handle-clamping-in-iframe.html: Added.
+
</ins><span class="cx"> 2018-09-08  Andy Estes  <aestes@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [Apple Pay] Dispatch a paymentmethodchange event when the payment method changes
</span></span></pre></div>
<a id="trunkLayoutTestseditingselectioniosselectionhandleclampinginiframeexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/selection/ios/selection-handle-clamping-in-iframe-expected.txt (0 => 235834)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/selection/ios/selection-handle-clamping-in-iframe-expected.txt                         (rev 0)
+++ trunk/LayoutTests/editing/selection/ios/selection-handle-clamping-in-iframe-expected.txt    2018-09-09 03:25:05 UTC (rev 235834)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+The final selection is: "iOS"
+
+Verifies that the selection remains the same when dragging the start selection handles below the end selection handle and vice versa.
+
+To manually run the test, select "iOS" in the iframe above, drag the start selection handle down, and then drag the end selection handle up.
+
+The text "iOS" should remain selected.
</ins></span></pre></div>
<a id="trunkLayoutTestseditingselectioniosselectionhandleclampinginiframehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/selection/ios/selection-handle-clamping-in-iframe.html (0 => 235834)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/selection/ios/selection-handle-clamping-in-iframe.html                         (rev 0)
+++ trunk/LayoutTests/editing/selection/ios/selection-handle-clamping-in-iframe.html    2018-09-09 03:25:05 UTC (rev 235834)
</span><span class="lines">@@ -0,0 +1,76 @@
</span><ins>+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+<script src="../../../resources/ui-helper.js"></script>
+<script src="../../../resources/basic-gestures.js"></script>
+<meta name=viewport content="width=device-width">
+<style>
+body, html {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+}
+
+pre {
+    width: 300px;
+    height: 160px;
+    overflow: scroll;
+    border: 1px green solid;
+}
+
+pre > #result {
+    color: green;
+}
+
+#target {
+    width: 300px;
+    height: 160px;
+}
+</style>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+function midPointOfRect(rect) {
+    return [rect.left + (rect.width / 2), rect.top + (rect.height / 2)];
+}
+
+async function runTest() {
+    // Wait for both the main frame and the subframe to finish loading.
+    loadCount = window.loadCount ? loadCount : 0;
+    if (++loadCount != 2)
+        return;
+
+    await longPressAtPoint(160, 240);
+    let startRect = { };
+    let endRect = { };
+    while (!startRect.width || !startRect.height || !endRect.width || !endRect.height) {
+        startRect = await UIHelper.getSelectionStartGrabberViewRect();
+        endRect = await UIHelper.getSelectionEndGrabberViewRect();
+    }
+
+    const [startX, startY] = midPointOfRect(startRect);
+    await touchAndDragFromPointToPoint(startX, startY, startX, startY + 100);
+    await liftUpAtPoint(startX, startY + 100);
+
+    const [endX, endY] = midPointOfRect(endRect);
+    await touchAndDragFromPointToPoint(endX, endY, endX, endY - 100);
+    await liftUpAtPoint(endX, endY - 100);
+
+    result.textContent = target.contentWindow.getSelection().toString();
+    testRunner.notifyDone();
+}
+</script>
+</head>
+
+<body onload="runTest()">
+<pre>The final selection is: "<span id="result"></span>"</pre>
+<iframe onload="runTest()" src="data:text/html,
+    <span id='text' style='font-size: 140px;'>iOS</span>" id="target"></iframe>
+<p>Verifies that the selection remains the same when dragging the start selection handles below the end selection handle and vice versa.</p>
+<p>To manually run the test, select "iOS" in the iframe above, drag the start selection handle down, and then drag the end selection handle up.</p>
+<p>The text "iOS" should remain selected.</p>
+</body>
+</html>
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (235833 => 235834)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog    2018-09-09 02:03:52 UTC (rev 235833)
+++ trunk/Source/WebKit/ChangeLog       2018-09-09 03:25:05 UTC (rev 235834)
</span><span class="lines">@@ -1,3 +1,32 @@
</span><ins>+2018-09-08  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        REGRESSION (r235153): [iOS] Can't move selection start grabber when selecting text in a subframe
+        https://bugs.webkit.org/show_bug.cgi?id=189454
+        <rdar://problem/44265956>
+
+        Reviewed by Darin Adler.
+
+        rangeForPointInRootViewCoordinates is responsible for taking a user gesture location representing the location
+        of the selection start or end handle (given in root view coordinates) and computing a Range representing an
+        updated selection. r235153 introduced a mechanism here to clamp the y offset of this user gesture location to
+        a max or min value determined by computing the bounds of the other selection handle, which more closely matches
+        platform behavior elsewhere in iOS.
+
+        However, this clamping logic would cause the user gesture location in root view coordinates to incorrectly clamp
+        in cases where the user selects text within an iframe that is offset from the top of the main document, since it
+        compares content coordinates (i.e. the caret bounds) against root view coordinates (i.e. the gesture location).
+        This makes it impossible to use selection handles to select text in some iframes.
+
+        We fix this by first converting the gesture location to document coordinates, and then clamping.
+
+        Test: editing/selection/ios/selection-handle-clamping-in-iframe.html
+
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::rangeForPointInRootViewCoordinates):
+
+        Also reuse `selectionStart` and `selectionEnd` when computing absolute caret bounds, instead of creating new
+        VisiblePositions.
+
</ins><span class="cx"> 2018-09-08  Tim Horton  <timothy_horton@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Unify most of the WebKit Objective-C API sources
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessWebPageiosWebPageIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (235833 => 235834)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm 2018-09-09 02:03:52 UTC (rev 235833)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm    2018-09-09 03:25:05 UTC (rev 235834)
</span><span class="lines">@@ -1221,22 +1221,19 @@
</span><span class="cx">     VisibleSelection existingSelection = frame.selection().selection();
</span><span class="cx">     VisiblePosition selectionStart = existingSelection.visibleStart();
</span><span class="cx">     VisiblePosition selectionEnd = existingSelection.visibleEnd();
</span><del>-    
-    IntPoint adjustedPoint = pointInRootViewCoordinates;
-    
</del><ins>+
+    auto pointInDocument = frame.view()->rootViewToContents(pointInRootViewCoordinates);
+
</ins><span class="cx">     if (baseIsStart) {
</span><del>-        IntRect caret = existingSelection.visibleStart().absoluteCaretBounds();
-        int startY = caret.center().y();
-        if (adjustedPoint.y() < startY)
-            adjustedPoint.setY(startY);
</del><ins>+        int startY = selectionStart.absoluteCaretBounds().center().y();
+        if (pointInDocument.y() < startY)
+            pointInDocument.setY(startY);
</ins><span class="cx">     } else {
</span><del>-        IntRect caret = existingSelection.visibleEnd().absoluteCaretBounds();
-        int endY = caret.center().y();
-        if (adjustedPoint.y() > endY)
-            adjustedPoint.setY(endY);
</del><ins>+        int endY = selectionEnd.absoluteCaretBounds().center().y();
+        if (pointInDocument.y() > endY)
+            pointInDocument.setY(endY);
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    IntPoint pointInDocument = frame.view()->rootViewToContents(adjustedPoint);
</del><span class="cx">     VisiblePosition result;
</span><span class="cx">     RefPtr<Range> range;
</span><span class="cx">     
</span></span></pre>
</div>
</div>

</body>
</html>