Title: [234661] trunk
Revision
234661
Author
[email protected]
Date
2018-08-07 11:32:42 -0700 (Tue, 07 Aug 2018)

Log Message

REGRESSION (r233778): Text selection sometimes cannot be extended in iframes
https://bugs.webkit.org/show_bug.cgi?id=188374
<rdar://problem/42928657>

Reviewed by Simon Fraser.

Source/WebKit:

rangeForPoint contains logic for converting a selection handle location in root view coordinates to an updated
selection. In doing so, we first convert the selection handle location to content coordinates; however, the call
site to EventHandler::hitTestResultAtPoint still hit-tests using the location in root view coordinates rather
than content coordinates, which means that when the focused frame is a subframe, hit-testing will fail to find
nodes within the subframe under the selection handle. This manifests in behaviors such as snapping to a single
character when selecting text in subframes.

To fix this, we just need to pass in the point in the frame's content coordinates when hit-testing.

Tests:  editing/selection/ios/selection-handles-in-iframe.html
        editing/selection/ios/selection-handles-in-readonly-input.html

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

Make a couple of other minor adjustments:
1.  Take a Frame& instead of a Frame*, since Frame& is assumed to be non-null here.
2.  Rename rangeForPoint to rangeForPointInRootViewCoordinates, as well as the point argument to
    pointInRootViewCoordinates.

(WebKit::WebPage::updateSelectionWithTouches):
(WebKit::rangeForPoint): Deleted.

LayoutTests:

Add 2 new layout tests to cover the original bug that r233778 fixed, as well as the regression in this bug.

* editing/selection/ios/selection-handles-in-iframe-expected.txt: Added.
* editing/selection/ios/selection-handles-in-iframe.html: Added.

Add a test to verify that the user can select text in an iframe by dragging selection handles.

* editing/selection/ios/selection-handles-in-readonly-input-expected.txt: Added.
* editing/selection/ios/selection-handles-in-readonly-input.html: Added.

Add a test to verify that dragging a selection handle outside of a readonly input does not cause the selection
to jump outside of the input and clear out the selection in the input.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (234660 => 234661)


--- trunk/LayoutTests/ChangeLog	2018-08-07 18:12:59 UTC (rev 234660)
+++ trunk/LayoutTests/ChangeLog	2018-08-07 18:32:42 UTC (rev 234661)
@@ -1,3 +1,24 @@
+2018-08-07  Wenson Hsieh  <[email protected]>
+
+        REGRESSION (r233778): Text selection sometimes cannot be extended in iframes
+        https://bugs.webkit.org/show_bug.cgi?id=188374
+        <rdar://problem/42928657>
+
+        Reviewed by Simon Fraser.
+
+        Add 2 new layout tests to cover the original bug that r233778 fixed, as well as the regression in this bug.
+
+        * editing/selection/ios/selection-handles-in-iframe-expected.txt: Added.
+        * editing/selection/ios/selection-handles-in-iframe.html: Added.
+
+        Add a test to verify that the user can select text in an iframe by dragging selection handles.
+
+        * editing/selection/ios/selection-handles-in-readonly-input-expected.txt: Added.
+        * editing/selection/ios/selection-handles-in-readonly-input.html: Added.
+
+        Add a test to verify that dragging a selection handle outside of a readonly input does not cause the selection
+        to jump outside of the input and clear out the selection in the input.
+
 2018-08-07  Alex Christensen  <[email protected]>
 
         Fix things after r234640

Added: trunk/LayoutTests/editing/selection/ios/selection-handles-in-iframe-expected.txt (0 => 234661)


--- trunk/LayoutTests/editing/selection/ios/selection-handles-in-iframe-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/selection/ios/selection-handles-in-iframe-expected.txt	2018-08-07 18:32:42 UTC (rev 234661)
@@ -0,0 +1,9 @@
+selectionchange: 'M'
+selectionchange: 'M '
+selectionchange: 'M M'
+
+Verifies that the user can select text in an iframe by dragging selection handles. This test is best run under WebKitTestRunner.
+
+To manually run the test, select "M" in the iframe above and drag the selection handles.
+
+The output above should log selection changes in the subframe.

Added: trunk/LayoutTests/editing/selection/ios/selection-handles-in-iframe.html (0 => 234661)


--- trunk/LayoutTests/editing/selection/ios/selection-handles-in-iframe.html	                        (rev 0)
+++ trunk/LayoutTests/editing/selection/ios/selection-handles-in-iframe.html	2018-08-07 18:32:42 UTC (rev 234661)
@@ -0,0 +1,83 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+<script src=""
+<script src=""
+<meta name=viewport content="width=device-width">
+<style>
+body, html {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+}
+
+#output {
+    width: 320px;
+    height: 160px;
+    overflow: scroll;
+    color: green;
+    border: 1px green solid;
+}
+
+#target {
+    width: 320px;
+    height: 160px;
+}
+</style>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+function appendOutput(s) {
+    const paragraph = document.createElement("div");
+    paragraph.textContent = s;
+    output.appendChild(paragraph);
+}
+
+function checkForCompletion() {
+    doneCount = window.doneCount ? doneCount : 0;
+    if (++doneCount == 4 && window.testRunner)
+        testRunner.notifyDone();
+}
+
+addEventListener("message", event => {
+    appendOutput(event.data);
+    checkForCompletion();
+});
+
+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(30, 240);
+    let grabberEndRect = null;
+    while (!grabberEndRect || !grabberEndRect.width || !grabberEndRect.height)
+        grabberEndRect = await UIHelper.getSelectionEndGrabberViewRect();
+
+    const [midX, midY] = [grabberEndRect.left + (grabberEndRect.width / 2), grabberEndRect.top + (grabberEndRect.height / 2)];
+    await touchAndDragFromPointToPoint(midX, midY, midX + 150, midY);
+    await liftUpAtPoint(midX + 150, midY);
+    checkForCompletion();
+}
+</script>
+</head>
+
+<body _onload_="runTest()">
+<pre id="output"></pre>
+<iframe _onload_="runTest()" src=""
+    <span id='text' style='font-size: 140px;'>M M</span>
+    <script>
+    document.addEventListener('selectionchange', () => {
+        const eventData = 'selectionchange: \'' + getSelection().toString() + '\'';
+        parent.postMessage(eventData, '*');
+    });
+    </script>" id="target"></iframe>
+<p>Verifies that the user can select text in an iframe by dragging selection handles. This test is best run under WebKitTestRunner.</p>
+<p>To manually run the test, select "M" in the iframe above and drag the selection handles.</p>
+<p>The output above should log selection changes in the subframe.</p>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/editing/selection/ios/selection-handles-in-readonly-input-expected.txt (0 => 234661)


--- trunk/LayoutTests/editing/selection/ios/selection-handles-in-readonly-input-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/selection/ios/selection-handles-in-readonly-input-expected.txt	2018-08-07 18:32:42 UTC (rev 234661)
@@ -0,0 +1,10 @@
+
+Initial selected range: (0, 2)
+Final selected range: (0, 2)
+Verifies that dragging a selection handle outside of a readonly input does not cause the selection to jump outside of the input.
+
+To manually test, double-tap to select the word "aa", drag the selection end handle out of the bounds of the input, and then drag the selection handle back in.
+
+"aa" should remain selected.
+
+This test is best run under WebKitTestRunner.

Added: trunk/LayoutTests/editing/selection/ios/selection-handles-in-readonly-input.html (0 => 234661)


--- trunk/LayoutTests/editing/selection/ios/selection-handles-in-readonly-input.html	                        (rev 0)
+++ trunk/LayoutTests/editing/selection/ios/selection-handles-in-readonly-input.html	2018-08-07 18:32:42 UTC (rev 234661)
@@ -0,0 +1,65 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+<script src=""
+<script src=""
+<meta name=viewport content="width=device-width">
+<style>
+body, html {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+}
+
+#output {
+    width: 320px;
+    height: 160px;
+    overflow: scroll;
+    color: green;
+    border: 1px green solid;
+}
+
+input {
+    font-size: 150px;
+    width: 300px;
+    height: 100px;
+    padding-left: 0;
+}
+</style>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+function appendOutput(s) {
+    const paragraph = document.createElement("div");
+    paragraph.textContent = s;
+    output.appendChild(paragraph);
+}
+
+async function runTest() {
+    await UIHelper.activateAndWaitForInputSessionAt(100, 50);
+    input.setSelectionRange(0, 2);
+    let grabberEndRect = null;
+    while (!grabberEndRect || !grabberEndRect.width || !grabberEndRect.height)
+        grabberEndRect = await UIHelper.getSelectionEndGrabberViewRect();
+
+    const [midX, midY] = [grabberEndRect.left + (grabberEndRect.width / 2), grabberEndRect.top + (grabberEndRect.height / 2)];
+    appendOutput(`Initial selected range: (${input.selectionStart}, ${input.selectionEnd})`);
+    await touchAndDragFromPointToPoint(midX, midY, midX + 25, midY + 150);
+    await liftUpAtPoint(midX + 25, midY + 150);
+    appendOutput(`Final selected range: (${input.selectionStart}, ${input.selectionEnd})`);
+    testRunner.notifyDone();
+}
+</script>
+</head>
+
+<body _onload_="runTest()">
+<input id="input" readonly value="aa">
+<pre id="output"></pre>
+<p>Verifies that dragging a selection handle outside of a readonly input does not cause the selection to jump outside of the input.</p>
+<p>To manually test, double-tap to select the word "aa", drag the selection end handle out of the bounds of the input, and then drag the selection handle back in.</p>
+<p>"aa" should remain selected.</p>
+<p>This test is best run under WebKitTestRunner.</p></body>
+</html>
\ No newline at end of file

Modified: trunk/Source/WebKit/ChangeLog (234660 => 234661)


--- trunk/Source/WebKit/ChangeLog	2018-08-07 18:12:59 UTC (rev 234660)
+++ trunk/Source/WebKit/ChangeLog	2018-08-07 18:32:42 UTC (rev 234661)
@@ -1,3 +1,34 @@
+2018-08-07  Wenson Hsieh  <[email protected]>
+
+        REGRESSION (r233778): Text selection sometimes cannot be extended in iframes
+        https://bugs.webkit.org/show_bug.cgi?id=188374
+        <rdar://problem/42928657>
+
+        Reviewed by Simon Fraser.
+
+        rangeForPoint contains logic for converting a selection handle location in root view coordinates to an updated
+        selection. In doing so, we first convert the selection handle location to content coordinates; however, the call
+        site to EventHandler::hitTestResultAtPoint still hit-tests using the location in root view coordinates rather
+        than content coordinates, which means that when the focused frame is a subframe, hit-testing will fail to find
+        nodes within the subframe under the selection handle. This manifests in behaviors such as snapping to a single
+        character when selecting text in subframes.
+
+        To fix this, we just need to pass in the point in the frame's content coordinates when hit-testing.
+
+        Tests:  editing/selection/ios/selection-handles-in-iframe.html
+                editing/selection/ios/selection-handles-in-readonly-input.html
+
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::rangeForPointInRootViewCoordinates):
+
+        Make a couple of other minor adjustments:
+        1.  Take a Frame& instead of a Frame*, since Frame& is assumed to be non-null here.
+        2.  Rename rangeForPoint to rangeForPointInRootViewCoordinates, as well as the point argument to
+            pointInRootViewCoordinates.
+
+        (WebKit::WebPage::updateSelectionWithTouches):
+        (WebKit::rangeForPoint): Deleted.
+
 2018-08-07  Alex Christensen  <[email protected]>
 
         Fix things after r234640

Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (234660 => 234661)


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2018-08-07 18:12:59 UTC (rev 234660)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2018-08-07 18:32:42 UTC (rev 234661)
@@ -1215,17 +1215,19 @@
     send(Messages::WebPageProxy::GestureCallback(point, gestureType, gestureState, static_cast<uint32_t>(flags), callbackID));
 }
 
-static RefPtr<Range> rangeForPoint(Frame* frame, const IntPoint& point, bool baseIsStart)
+static RefPtr<Range> rangeForPointInRootViewCoordinates(Frame& frame, const IntPoint& pointInRootViewCoordinates, bool baseIsStart)
 {
-    IntPoint pointInDocument = frame->view()->rootViewToContents(point);
-    Position result = frame->visiblePositionForPoint(pointInDocument).deepEquivalent();
+    IntPoint pointInDocument = frame.view()->rootViewToContents(pointInRootViewCoordinates);
+    Position result;
     RefPtr<Range> range;
     
-    HitTestResult hitTest = frame->eventHandler().hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowChildFrameContent);
+    HitTestResult hitTest = frame.eventHandler().hitTestResultAtPoint(pointInDocument, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowChildFrameContent);
     if (hitTest.targetNode())
-        result = frame->eventHandler().selectionExtentRespectingEditingBoundary(frame->selection().selection(), hitTest.localPoint(), hitTest.targetNode()).deepEquivalent();
+        result = frame.eventHandler().selectionExtentRespectingEditingBoundary(frame.selection().selection(), hitTest.localPoint(), hitTest.targetNode()).deepEquivalent();
+    else
+        result = frame.visiblePositionForPoint(pointInDocument).deepEquivalent();
     
-    VisibleSelection existingSelection = frame->selection().selection();
+    VisibleSelection existingSelection = frame.selection().selection();
     Position selectionStart = existingSelection.visibleStart().deepEquivalent();
     Position selectionEnd = existingSelection.visibleEnd().deepEquivalent();
     
@@ -1235,7 +1237,7 @@
         else if (&selectionStart.anchorNode()->treeScope() != &hitTest.targetNode()->treeScope())
             result = VisibleSelection::adjustPositionForEnd(result, selectionStart.containerNode());
         if (result.isNotNull())
-            range = Range::create(*frame->document(), selectionStart, result);
+            range = Range::create(*frame.document(), selectionStart, result);
     } else {
         if (comparePositions(selectionEnd, result) <= 0)
             result = selectionEnd.previous();
@@ -1242,7 +1244,7 @@
         else if (&hitTest.targetNode()->treeScope() != &selectionEnd.anchorNode()->treeScope())
             result = VisibleSelection::adjustPositionForStart(result, selectionEnd.containerNode());
         if (result.isNotNull())
-            range = Range::create(*frame->document(), result, selectionEnd);
+            range = Range::create(*frame.document(), result, selectionEnd);
     }
     
     return range;
@@ -1329,7 +1331,7 @@
             if (result.isNotNull())
                 range = Range::create(*frame.document(), result, result);
         } else
-            range = rangeForPoint(&frame, point, baseIsStart);
+            range = rangeForPointInRootViewCoordinates(frame, point, baseIsStart);
         break;
 
     case SelectionTouch::EndedMovingForward:
@@ -1341,7 +1343,7 @@
         break;
 
     case SelectionTouch::Moved:
-        range = rangeForPoint(&frame, point, baseIsStart);
+        range = rangeForPointInRootViewCoordinates(frame, point, baseIsStart);
         break;
     }
     if (range)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to