Title: [126284] trunk
Revision
126284
Author
[email protected]
Date
2012-08-22 03:23:55 -0700 (Wed, 22 Aug 2012)

Log Message

[TouchAdjustment] Adjust to word or selection
https://bugs.webkit.org/show_bug.cgi?id=94449

Reviewed by Antonio Gomes.

Source/WebCore:

Makes each separate word a separate subtarget when context menu triggers
selections, and only the selected part of a partial selected node a
target when selections are not overridden.

Fix of reverted commit r126026, fix misplaced ASSERT.

Test: touchadjustment/context-menu-text-subtargets.html

* page/TouchAdjustment.cpp:
(TouchAdjustment):
(WebCore::TouchAdjustment::providesContextMenuItems):
(WebCore::TouchAdjustment::appendQuadsToSubtargetList):
(WebCore::TouchAdjustment::appendBasicSubtargetsForNode):
(WebCore::TouchAdjustment::appendContextSubtargetsForNode):
(WebCore::TouchAdjustment::compileSubtargetList):
(WebCore::findBestClickableCandidate):
(WebCore::findBestContextMenuCandidate):

LayoutTests:

Tests that touch-adjustment can adjust to the right subtargets within text-nodes.

* touchadjustment/context-menu-select-text.html:
* touchadjustment/context-menu-text-subtargets-expected.txt: Added.
* touchadjustment/context-menu-text-subtargets.html: Added.
* touchadjustment/resources/touchadjustment.js:
(pointToString):
(shouldBeWithin):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (126283 => 126284)


--- trunk/LayoutTests/ChangeLog	2012-08-22 09:19:06 UTC (rev 126283)
+++ trunk/LayoutTests/ChangeLog	2012-08-22 10:23:55 UTC (rev 126284)
@@ -1,3 +1,19 @@
+2012-08-22  Allan Sandfeld Jensen  <[email protected]>
+
+        [TouchAdjustment] Adjust to word or selection
+        https://bugs.webkit.org/show_bug.cgi?id=94449
+
+        Reviewed by Antonio Gomes.
+
+        Tests that touch-adjustment can adjust to the right subtargets within text-nodes.
+
+        * touchadjustment/context-menu-select-text.html:
+        * touchadjustment/context-menu-text-subtargets-expected.txt: Added.
+        * touchadjustment/context-menu-text-subtargets.html: Added.
+        * touchadjustment/resources/touchadjustment.js:
+        (pointToString):
+        (shouldBeWithin):
+
 2012-08-22  Balazs Ankes  <[email protected]>
 
         [Qt][GTK] REGRESSION(r126194): http/tests/security/contentSecurityPolicy/register-bypassing-scheme.html fails

Modified: trunk/LayoutTests/touchadjustment/context-menu-select-text.html (126283 => 126284)


--- trunk/LayoutTests/touchadjustment/context-menu-select-text.html	2012-08-22 09:19:06 UTC (rev 126283)
+++ trunk/LayoutTests/touchadjustment/context-menu-select-text.html	2012-08-22 10:23:55 UTC (rev 126284)
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
-    <title>Touch Adjustment : Adjust context-menu to selectable words - bug 94101</title>
+    <title>Touch Adjustment : Adjust context-menu to selectable text - bug 94101</title>
     <script src=""
     <script src=""
     <style>

Added: trunk/LayoutTests/touchadjustment/context-menu-text-subtargets-expected.txt (0 => 126284)


--- trunk/LayoutTests/touchadjustment/context-menu-text-subtargets-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/touchadjustment/context-menu-text-subtargets-expected.txt	2012-08-22 10:23:55 UTC (rev 126284)
@@ -0,0 +1,15 @@
+Test touch-adjustment to individual words or active selection.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS adjusted point was within (10,10)x(80,20)
+PASS adjusted point was within (10,10)x(80,20)
+PASS adjusted point was within (170,10)x(80,20)
+PASS adjusted point was within (170,10)x(80,20)
+PASS adjusted point was within (50,10)x(80,20)
+PASS adjusted point was within (50,10)x(80,20)
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/touchadjustment/context-menu-text-subtargets.html (0 => 126284)


--- trunk/LayoutTests/touchadjustment/context-menu-text-subtargets.html	                        (rev 0)
+++ trunk/LayoutTests/touchadjustment/context-menu-text-subtargets.html	2012-08-22 10:23:55 UTC (rev 126284)
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Touch Adjustment : Adjust context-menu to text-node subtargets - bug 94449</title>
+    <script src=""
+    <script src=""
+    <style>
+        #sandbox {
+            position: absolute;
+            top: 0px;
+            left: 0px;
+            width: 400px;
+            height: 200px;
+        }
+        #sandbox div {
+            padding: 10px;
+            font: 20px Ahem;
+            white-space: pre-wrap;
+        }
+    </style>
+</head>
+<body>
+
+<div id=sandbox>
+<!-- The layout of the two words should be: (10,10)x(80,20) and (170,10)x(80,20). -->
+    <div id=div1><span id=span1>Text    text</span></div>
+</div>
+
+<p id='description'></p>
+<div id='console'></div>
+
+<script>
+    // Set up shortcut access to elements
+    var e = {};
+    ['sandbox', 'div1', 'span1'].forEach(function(a) {
+        e[a] = document.getElementById(a);
+    });
+
+    function testAdjustedTouches()
+    {
+        var adjustedPoint;
+        var word1Bounds = { left: 10, top: 10, width: 80, height: 20 };
+        var word2Bounds = { left: 170, top: 10, width: 80, height: 20 };
+
+        // Set editing-behaviour mac, so context-menu gesture triggers selections.
+        internals.settings.setEditingBehavior('mac');
+        // Check the context-menu is adjusted to the individual words.
+        adjustedPoint = adjustTouchPointContextMenu(touchPoint(5, 5, 20, 10));
+        shouldBeWithin(adjustedPoint, word1Bounds);
+        adjustedPoint = adjustTouchPointContextMenu(touchPoint(100, 15, 20, 10));
+        shouldBeWithin(adjustedPoint, word1Bounds);
+
+        adjustedPoint = adjustTouchPointContextMenu(touchPoint(150, 15, 30, 10));
+        shouldBeWithin(adjustedPoint, word2Bounds);
+        adjustedPoint = adjustTouchPointContextMenu(touchPoint(260, 35, 20, 10));
+        shouldBeWithin(adjustedPoint, word2Bounds);
+
+        // Set editing-behaviour to win, so context-menu gesture does not trigger selections.
+        internals.settings.setEditingBehavior('win');
+        var range = document.createRange();
+        range.setStart(e.span1.firstChild, 2);
+        range.setEnd(e.span1.firstChild, 6);
+        window.getSelection().addRange(range);
+        var selectionBounds = { left: 50, top: 10, width: 80, height: 20 };
+        adjustedPoint = adjustTouchPointContextMenu(touchPoint(25, 5, 30, 20));
+        shouldBeWithin(adjustedPoint, selectionBounds);
+        adjustedPoint = adjustTouchPointContextMenu(touchPoint(140, 10, 20, 10));
+        shouldBeWithin(adjustedPoint, selectionBounds);
+    }
+
+    function runTests()
+    {
+        if (window.testRunner && window.internals && internals.touchNodeAdjustedToBestContextMenuNode) {
+            description('Test touch-adjustment to individual words or active selection.');
+            testAdjustedTouches();
+            e.sandbox.style.display = 'none';
+        }
+    }
+    runTests();
+</script>
+
+<script src=""
+
+</body>
+</html>

Modified: trunk/LayoutTests/touchadjustment/resources/touchadjustment.js (126283 => 126284)


--- trunk/LayoutTests/touchadjustment/resources/touchadjustment.js	2012-08-22 09:19:06 UTC (rev 126283)
+++ trunk/LayoutTests/touchadjustment/resources/touchadjustment.js	2012-08-22 10:23:55 UTC (rev 126284)
@@ -24,6 +24,17 @@
     return node.nodeName + (node.id ? ('#' + node.id) : '');
 }
 
+function boundsToString(bounds)
+{
+    return "("+bounds.left+","+bounds.top+")x("+bounds.width+","+bounds.height+")";
+}
+
+function pointToString(point)
+{
+    return "("+point.x+","+point.y+")";
+}
+
+
 function shouldBeNode(adjustedNode, targetNode) {
     if (typeof targetNode == "string") {
         var adjustedNodeString = nodeToString(adjustedNode);
@@ -43,6 +54,17 @@
     }
 }
 
+function shouldBeWithin(adjustedPoint, targetArea) {
+    if (adjustedPoint.x >= targetArea.left && adjustedPoint.y >= targetArea.top
+        && adjustedPoint.x <= (targetArea.left + targetArea.width)
+        && adjustedPoint.y <= (targetArea.top + targetArea.height)) {
+        testPassed("adjusted point was within " + boundsToString(targetArea));
+    } else {
+        testFailed("adjusted node should be within " + boundsToString(targetArea)  + ". Was " + pointToString(adjustedPoint));
+    }
+}
+
+
 function testTouchPoint(touchpoint, targetNode, allowTextNodes)
 {
     var adjustedNode = internals.touchNodeAdjustedToBestClickableNode(touchpoint.left, touchpoint.top, touchpoint.width, touchpoint.height, document);

Modified: trunk/Source/WebCore/ChangeLog (126283 => 126284)


--- trunk/Source/WebCore/ChangeLog	2012-08-22 09:19:06 UTC (rev 126283)
+++ trunk/Source/WebCore/ChangeLog	2012-08-22 10:23:55 UTC (rev 126284)
@@ -1,3 +1,28 @@
+2012-08-22  Allan Sandfeld Jensen  <[email protected]>
+
+        [TouchAdjustment] Adjust to word or selection
+        https://bugs.webkit.org/show_bug.cgi?id=94449
+
+        Reviewed by Antonio Gomes.
+
+        Makes each separate word a separate subtarget when context menu triggers
+        selections, and only the selected part of a partial selected node a 
+        target when selections are not overridden.
+
+        Fix of reverted commit r126026, fix misplaced ASSERT.
+
+        Test: touchadjustment/context-menu-text-subtargets.html
+
+        * page/TouchAdjustment.cpp:
+        (TouchAdjustment):
+        (WebCore::TouchAdjustment::providesContextMenuItems):
+        (WebCore::TouchAdjustment::appendQuadsToSubtargetList):
+        (WebCore::TouchAdjustment::appendBasicSubtargetsForNode):
+        (WebCore::TouchAdjustment::appendContextSubtargetsForNode):
+        (WebCore::TouchAdjustment::compileSubtargetList):
+        (WebCore::findBestClickableCandidate):
+        (WebCore::findBestContextMenuCandidate):
+
 2012-08-22  Andrey Adaikin  <[email protected]>
 
         Web Inspector: [WebGL] Generic framework draft for tracking WebGL resources

Modified: trunk/Source/WebCore/page/TouchAdjustment.cpp (126283 => 126284)


--- trunk/Source/WebCore/page/TouchAdjustment.cpp	2012-08-22 09:19:06 UTC (rev 126283)
+++ trunk/Source/WebCore/page/TouchAdjustment.cpp	2012-08-22 10:23:55 UTC (rev 126284)
@@ -35,7 +35,10 @@
 #include "RenderBox.h"
 #include "RenderObject.h"
 #include "RenderStyle.h"
+#include "RenderText.h"
 #include "ShadowRoot.h"
+#include "Text.h"
+#include "TextBreakIterator.h"
 
 namespace WebCore {
 
@@ -62,6 +65,7 @@
 
 typedef Vector<SubtargetGeometry> SubtargetGeometryList;
 typedef bool (*NodeFilter)(Node*);
+typedef void (*AppendSubtargetsForNode)(Node*, SubtargetGeometryList&);
 typedef float (*DistanceFunction)(const IntPoint&, const IntRect&, const SubtargetGeometry&);
 
 // Takes non-const Node* because isContentEditable is a non-const function.
@@ -101,33 +105,95 @@
     if (node->renderer()->isMedia())
         return true;
     if (node->renderer()->canBeSelectionLeaf()) {
-        // If the context menu gesture will trigger a selection all selectable nodes are targets.
-        // FIXME: To improve the adjusted point, each individual word should be a separate subtarget,
-        // see for example FatFingers::checkForText() in WebKit/blackberry.
+        // If the context menu gesture will trigger a selection all selectable nodes are valid targets.
         if (node->renderer()->frame()->editor()->behavior().shouldSelectOnContextualMenuClick())
             return true;
-        // FIXME: A selected text might only be partially selected, and we should only append
-        // the selected subtargets of it in appendSubtargetsForNodeToList().
+        // Only the selected part of the renderer is a valid target, but this will be corrected in
+        // appendContextSubtargetsForNode.
         if (node->renderer()->selectionState() != RenderObject::SelectionNone)
             return true;
     }
     return false;
 }
 
-static inline void appendSubtargetsForNodeToList(Node* node, SubtargetGeometryList& subtargets)
+static inline void appendQuadsToSubtargetList(Vector<FloatQuad>& quads, Node* node, SubtargetGeometryList& subtargets)
 {
+    Vector<FloatQuad>::const_iterator it = quads.begin();
+    const Vector<FloatQuad>::const_iterator end = quads.end();
+    for (; it != end; ++it)
+        subtargets.append(SubtargetGeometry(node, *it));
+}
+
+static inline void appendBasicSubtargetsForNode(Node* node, SubtargetGeometryList& subtargets)
+{
     // Since the node is a result of a hit test, we are already ensured it has a renderer.
     ASSERT(node->renderer());
 
     Vector<FloatQuad> quads;
     node->renderer()->absoluteQuads(quads);
 
-    Vector<FloatQuad>::const_iterator it = quads.begin();
-    const Vector<FloatQuad>::const_iterator end = quads.end();
-    for (; it != end; ++it)
-        subtargets.append(SubtargetGeometry(node, *it));
+    appendQuadsToSubtargetList(quads, node, subtargets);
 }
 
+static inline void appendContextSubtargetsForNode(Node* node, SubtargetGeometryList& subtargets)
+{
+    // This is a variant of appendBasicSubtargetsForNode that adds special subtargets for
+    // selected or auto-selectable parts of text nodes.
+    ASSERT(node->renderer());
+
+    if (!node->isTextNode())
+        return appendBasicSubtargetsForNode(node, subtargets);
+
+    Text* textNode = static_cast<WebCore::Text*>(node);
+    RenderText* textRenderer = static_cast<RenderText*>(textNode->renderer());
+
+    if (textRenderer->frame()->editor()->behavior().shouldSelectOnContextualMenuClick()) {
+        // Make subtargets out of every word.
+        String textValue = textNode->data();
+        TextBreakIterator* wordIterator = wordBreakIterator(textValue.characters(), textValue.length());
+        int lastOffset = textBreakFirst(wordIterator);
+        if (lastOffset == -1)
+            return;
+        int offset;
+        while ((offset = textBreakNext(wordIterator)) != -1) {
+            if (isWordTextBreak(wordIterator)) {
+                Vector<FloatQuad> quads;
+                textRenderer->absoluteQuadsForRange(quads, lastOffset, offset);
+                appendQuadsToSubtargetList(quads, textNode, subtargets);
+            }
+            lastOffset = offset;
+        }
+    } else {
+        if (textRenderer->selectionState() == RenderObject::SelectionNone)
+            return appendBasicSubtargetsForNode(node, subtargets);
+        // If selected, make subtargets out of only the selected part of the text.
+        int startPos, endPos;
+        switch (textRenderer->selectionState()) {
+        case RenderObject::SelectionInside:
+            startPos = 0;
+            endPos = textRenderer->textLength();
+            break;
+        case RenderObject::SelectionStart:
+            textRenderer->selectionStartEnd(startPos, endPos);
+            endPos = textRenderer->textLength();
+            break;
+        case RenderObject::SelectionEnd:
+            textRenderer->selectionStartEnd(startPos, endPos);
+            startPos = 0;
+            break;
+        case RenderObject::SelectionBoth:
+            textRenderer->selectionStartEnd(startPos, endPos);
+            break;
+        default:
+            ASSERT_NOT_REACHED();
+            return;
+        }
+        Vector<FloatQuad> quads;
+        textRenderer->absoluteQuadsForRange(quads, startPos, endPos);
+        appendQuadsToSubtargetList(quads, textNode, subtargets);
+    }
+}
+
 static inline void appendZoomableSubtargets(Node* node, SubtargetGeometryList& subtargets)
 {
     RenderBox* renderer = toRenderBox(node->renderer());
@@ -148,7 +214,7 @@
 }
 
 // Compiles a list of subtargets of all the relevant target nodes.
-void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryList& subtargets, NodeFilter nodeFilter)
+void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryList& subtargets, NodeFilter nodeFilter, AppendSubtargetsForNode appendSubtargetsForNode)
 {
     // Find candidates responding to tap gesture events in O(n) time.
     HashMap<Node*, Node*> responderMap;
@@ -201,7 +267,7 @@
         ASSERT(respondingNode);
         if (ancestorsToRespondersSet.contains(respondingNode))
             continue;
-        appendSubtargetsForNodeToList(candidate, subtargets);
+        appendSubtargetsForNode(candidate, subtargets);
     }
 }
 
@@ -408,7 +474,7 @@
 {
     IntRect targetArea;
     TouchAdjustment::SubtargetGeometryList subtargets;
-    TouchAdjustment::compileSubtargetList(nodeList, subtargets, TouchAdjustment::nodeRespondsToTapGesture);
+    TouchAdjustment::compileSubtargetList(nodeList, subtargets, TouchAdjustment::nodeRespondsToTapGesture, TouchAdjustment::appendBasicSubtargetsForNode);
     return TouchAdjustment::findNodeWithLowestDistanceMetric(targetNode, targetPoint, targetArea, touchHotspot, touchArea, subtargets, TouchAdjustment::hybridDistanceFunction);
 }
 
@@ -416,7 +482,7 @@
 {
     IntRect targetArea;
     TouchAdjustment::SubtargetGeometryList subtargets;
-    TouchAdjustment::compileSubtargetList(nodeList, subtargets, TouchAdjustment::providesContextMenuItems);
+    TouchAdjustment::compileSubtargetList(nodeList, subtargets, TouchAdjustment::providesContextMenuItems, TouchAdjustment::appendContextSubtargetsForNode);
     return TouchAdjustment::findNodeWithLowestDistanceMetric(targetNode, targetPoint, targetArea, touchHotspot, touchArea, subtargets, TouchAdjustment::hybridDistanceFunction);
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to