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);
}