+2012-03-19 Allan Sandfeld Jensen <allan.jensen@nokia.com>
+
+ Select best target for tap gesture.
+ https://bugs.webkit.org/show_bug.cgi?id=78801
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Test of touch adjustments. Tests several both normal and tricky cases.
+
+ * platform/chromium/test_expectations.txt:
+ * platform/efl/Skipped:
+ * platform/gtk/Skipped:
+ * platform/mac/Skipped:
+ * platform/win/Skipped:
+ * touchadjustment/event-triggered-widgets-expected.txt: Added.
+ * touchadjustment/event-triggered-widgets.html: Added.
+ * touchadjustment/html-label-expected.txt: Added.
+ * touchadjustment/html-label.html: Added.
+ * touchadjustment/nested-touch-expected.txt: Added.
+ * touchadjustment/nested-touch.html: Added.
+ * touchadjustment/touch-inlines-expected.txt: Added.
+ * touchadjustment/touch-inlines.html: Added.
+
2012-03-19 Robert Kroeger <rjkroege@chromium.org>
[chromium] synthesize wheel events for fling on main thread
// Battery Status API is not supported yet in the chromium port.
BUGWK62698 SKIP : batterystatus = PASS FAIL
+// Touch Adjustment is not supported yet in the chromium port.
+BUGWK78801 SKIP : touchadjustment/ = FAIL
+
// -----------------------------------------------------------------
// WONTFIX TESTS
// -----------------------------------------------------------------
fast/events/page-visibility-iframe-propagation-test.html
fast/events/page-visibility-transition-test.html
+# Touch adjustment not enabled
+# https://bugs.webkit.org/show_bug.cgi?id=78801
+touchadjustment
+
# There are no expected result set yet.
animations/additive-transform-animations.html
animations/animation-border-overflow.html
# https://bugs.webkit.org/show_bug.cgi?id=80534
fast/events/autoscroll-in-textfield.html
+# Touch adjustment not enabled
+# https://bugs.webkit.org/show_bug.cgi?id=78801
+touchadjustment
+
# https://bugs.webkit.org/show_bug.cgi?id=81089
inspector/debugger/snippets-model.html
# Needs PageClients::vibrationClient() implementation.
fast/dom/navigator-vibration.html
+# Touch adjustment not enabled
+# https://bugs.webkit.org/show_bug.cgi?id=78801
+touchadjustment
+
# http:///webkit.org/b/80531
# REGRESSION(r110072): fast/forms/textfield-overflow.html is failing
fast/forms/textfield-overflow.html
#Battery Status API is not implemented.
batterystatus
+# Touch adjustment not enabled
+# https://bugs.webkit.org/show_bug.cgi?id=78801
+touchadjustment
+
# Those tests need a text baseline after lazily allocating layers.
# The change should only be layer removal.
animations/combo-transform-translate+scale.html
--- /dev/null
+Test various ways to trigger input-widgets. On a touch interface, all the actions should be triggerable with either a touch down or a touch tap.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Testing small direct hits
+PASS adjustedNode.id is element.id
+PASS adjustedNode.id is element.id
+PASS adjustedNode.id is element.id
+PASS adjustedNode.id is not element.id
+PASS adjustedNode.id is element.id
+Testing large direct hits
+PASS adjustedNode.id is element.id
+PASS adjustedNode.id is element.id
+PASS adjustedNode.id is element.id
+PASS adjustedNode.id is not element.id
+PASS adjustedNode.id is element.id
+Testing large direct hits
+PASS adjustedNode.id is element.id
+PASS adjustedNode.id is element.id
+PASS adjustedNode.id is element.id
+PASS adjustedNode.id is not element.id
+PASS adjustedNode.id is element.id
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Focus here should give a text input-field.
+Mouse-over here should give a text input-field.
+Hovering here should give a text input-field.
+Focusing here should only give focus outline.
+Focusing here should give a text input-field.
--- /dev/null
+<html>
+<head>
+<style>
+ .box { border: 1px solid black; border-radius: 5px 5px; margin: 1em; max-width: 40em; }
+</style>
+
+<script src="../fast/js/resources/js-test-pre.js"></script>
+
+</head>
+
+<body onload="runTests()">
+
+<p id='description'></p>
+
+<div id='console'></div>
+
+<script>
+ var element;
+ var adjustedNode;
+ function findAbsolutePosition(node) {
+ var pos = new Object();
+ pos.left = 0; pos.top = 0;
+ do {
+ pos.left += node.offsetLeft;
+ pos.top += node.offsetTop;
+ } while (node = node.offsetParent);
+ return pos;
+ }
+
+ function testDirectTouch(element)
+ {
+ var pos = findAbsolutePosition(element);
+ var x = pos.left + element.clientWidth / 2 - 1;
+ var y = pos.top + element.clientHeight / 2 - 1;
+ var width = 3;
+ var height = 3;
+ adjustedNode = internals.touchNodeAdjustedToBestClickableNode(x, y, width, height, document);
+
+ if (adjustedNode.nodeType == 3) // TEXT node
+ adjustedNode = adjustedNode.parentNode;
+ }
+
+ function testDirectFatFinger(element)
+ {
+ var pos = findAbsolutePosition(element);
+ var x = pos.left + element.clientWidth / 2 - 1;
+ var y = pos.top - 5 ;
+ var width = element.clientHeight;
+ var height = element.clientHeight + 10;
+ adjustedNode = internals.touchNodeAdjustedToBestClickableNode(x, y, width, height, document);
+ if (adjustedNode.nodeType == 3) // TEXT node
+ adjustedNode = adjustedNode.parentNode;
+ }
+
+ function testIndirectFatFinger(element)
+ {
+ var pos = findAbsolutePosition(element);
+ var x = pos.left + element.clientWidth / 2 - 1;
+ var y = pos.top - 7;
+ var width = 10;
+ var height = 10;
+ adjustedNode = internals.touchNodeAdjustedToBestClickableNode(x, y, width, height, document);
+ if (adjustedNode.nodeType == 3) // TEXT node
+ adjustedNode = adjustedNode.parentNode;
+ }
+
+ function testTouchHit(elementid, touchType) {
+ element = document.getElementById(elementid);
+ touchType(element);
+ shouldBe('adjustedNode.id', 'element.id');
+ }
+
+ function testTouchMiss(elementid, touchType) {
+ element = document.getElementById(elementid);
+ touchType(element);
+ shouldNotBe('adjustedNode.id', 'element.id');
+ }
+
+ function testDirectTouches()
+ {
+ debug('Testing small direct hits');
+ testTouchHit('test1', testDirectTouch);
+ testTouchHit('test2', testDirectTouch);
+ testTouchHit('test3', testDirectTouch);
+ testTouchMiss('test4', testDirectTouch);
+ testTouchHit('test5', testDirectTouch);
+ }
+
+ function testDirectFatFingers()
+ {
+ debug('Testing large direct hits');
+ testTouchHit('test1', testDirectFatFinger);
+ testTouchHit('test2', testDirectFatFinger);
+ testTouchHit('test3', testDirectFatFinger);
+ testTouchMiss('test4', testDirectFatFinger);
+ testTouchHit('test5', testDirectFatFinger);
+ }
+
+ function testIndirectFatFingers()
+ {
+ debug('Testing large direct hits');
+ testTouchHit('test1', testIndirectFatFinger);
+ testTouchHit('test2', testIndirectFatFinger);
+ testTouchHit('test3', testIndirectFatFinger);
+ testTouchMiss('test4', testIndirectFatFinger);
+ testTouchHit('test5', testIndirectFatFinger);
+ }
+
+ function runTests()
+ {
+ if (window.layoutTestController && window.internals && internals.touchNodeAdjustedToBestClickableNode) {
+ description('Test various ways to trigger input-widgets. On a touch interface, all the actions should be triggerable with either a touch down or a touch tap.');
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+ testDirectTouches();
+ testDirectFatFingers();
+ testIndirectFatFingers();
+ isSuccessfullyParsed();
+ layoutTestController.notifyDone();
+ }
+ }
+</script>
+
+<script>
+ function triggerInput() {
+ var element = event.srcElement;
+ if (!element.open) {
+ element.innerHTML = '<input type=text style="width: 100%"></input>'
+ element.open = true;
+ }
+ element.firstChild.focus();
+ }
+</script>
+
+<div id=test1 class=box tabindex=1 onfocus='triggerInput()'>
+Focus here should give a text input-field.
+</div>
+
+<div id=test2 class=box onmouseover='triggerInput()'>
+Mouse-over here should give a text input-field.
+</div>
+
+<style>
+ .box:not(:hover) .hovertriggered { visibility: hidden;}
+ .box:hover .hoverfallback { display: none; }
+</style>
+
+<div id=test3 class=box>
+ <span class=hoverfallback>Hovering here should give a text input-field.</span>
+ <input type=text class=hovertriggered></input>
+</div>
+
+<div id=test4 class=box onfocus='triggerInput()'>
+ <span tabindex=1> Focusing here should only give focus outline.
+ </span>
+</div>
+
+<div id=test5 class=box>
+ <span tabindex=1> Focusing here should give a text input-field.
+ </span>
+</div>
+
+<script>
+ var element = document.getElementById('test5');
+ element.addEventListener('DOMFocusIn', triggerInput, false);
+</script>
+
+</body>
+</html>
--- /dev/null
+Do not click here
+Click here, but not here.
+
+
+
+Tests if labels are treated as clickable if the input they control is.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Testing small direct hits.
+PASS adjustedNode.id is "mylink"
+PASS adjustedNode.id is "mylabel"
+PASS adjustedNode.id is "myinput"
+Testing indirect hits.
+PASS adjustedNode.id is "mylink"
+PASS adjustedNode.id is "mylabel"
+PASS adjustedNode.id is "myinput"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<html>
+<head>
+<script src="../fast/js/resources/js-test-pre.js"></script>
+
+</head>
+
+<body id="mybody" onload="runTests()">
+
+<a href="#myform" id="mylink">Do not click here</a><br>
+<form id="myform">
+<label for="myinput" id="mylabel">Click here,</label>
+<span id="myspan">but not here.</span>
+<input type="text" id="myinput" value="To focus this."></input>
+</form>
+<br><br><br>
+
+<p id='description'></p>
+<div id='console'></div>
+
+<script>
+ var element;
+ var adjustedNode;
+ function findAbsolutePosition(node) {
+ var pos = new Object();
+ pos.left = 0; pos.top = 0;
+ do {
+ pos.left += node.offsetLeft;
+ pos.top += node.offsetTop;
+ } while (node = node.offsetParent);
+ return pos;
+ }
+
+ function testDirectTouch(element)
+ {
+ var pos = findAbsolutePosition(element);
+ var x = pos.left + element.clientWidth / 2 - 20;
+ var y = pos.top + element.clientHeight / 2 - 30;
+ var width = 40;
+ var height = 60;
+ var adjustedNode = internals.touchNodeAdjustedToBestClickableNode(x, y, width, height, document);
+ while (adjustedNode.nodeType != 1) // Not an element.
+ adjustedNode = adjustedNode.parentNode;
+ return adjustedNode;
+ }
+
+ function testIndirectTouch(element)
+ {
+ // Touch just right of the element.
+ var pos = findAbsolutePosition(element);
+ var x = pos.left + element.clientWidth + 10 - 30;
+ var y = pos.top + element.clientHeight / 2 - 20;
+ var width = 60;
+ var height = 40;
+ var adjustedNode = internals.touchNodeAdjustedToBestClickableNode(x, y, width, height, document);
+ while (adjustedNode.nodeType != 1 ) // Not an element.
+ adjustedNode = adjustedNode.parentNode;
+ return adjustedNode;
+ }
+
+ function testDirectTouches()
+ {
+ debug('Testing small direct hits.');
+
+ element = document.getElementById('mylink');
+ adjustedNode = testDirectTouch(element);
+ shouldBeEqualToString('adjustedNode.id', 'mylink');
+
+ element = document.getElementById('mylabel');
+ adjustedNode = testDirectTouch(element);
+ shouldBeEqualToString('adjustedNode.id', 'mylabel');
+
+ element = document.getElementById('myinput');
+ adjustedNode = testDirectTouch(element);
+ shouldBeEqualToString('adjustedNode.id', 'myinput');
+ }
+
+ function testIndirectTouches()
+ {
+ debug('Testing indirect hits.');
+
+ element = document.getElementById('mylink');
+ adjustedNode = testIndirectTouch(element);
+ shouldBeEqualToString('adjustedNode.id', 'mylink');
+
+ element = document.getElementById('mylabel');
+ adjustedNode = testIndirectTouch(element);
+ shouldBeEqualToString('adjustedNode.id', 'mylabel');
+
+ element = document.getElementById('myinput');
+ adjustedNode = testIndirectTouch(element);
+ shouldBeEqualToString('adjustedNode.id', 'myinput');
+ }
+
+ function runTests()
+ {
+ if (window.layoutTestController && window.internals && internals.touchNodeAdjustedToBestClickableNode) {
+ description('Tests if labels are treated as clickable if the input they control is.');
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+ testDirectTouches();
+ testIndirectTouches();
+ isSuccessfullyParsed();
+ layoutTestController.notifyDone();
+ }
+ }
+</script>
+</body>
+</html>
--- /dev/null
+Box with a local click handler.
+Box without a local click handler.
+Test the case where a clickable target is nested inside a document that is monitoring clicks. The target with the local event-handler should be chosen if multiple targets are touched.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Testing small direct hits.
+PASS adjustedNode.id is element.id
+PASS adjustedNode.id is element.id
+Testing prefered hits.
+PASS adjustedNode.id is element1.id
+PASS adjustedNode.id is element1.id
+PASS adjustedNode.id is element1.id
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<html>
+<head>
+<style>
+ .box { border: 1px solid black; border-radius: 5px 5px; margin: 1em; max-width: 40em; }
+</style>
+<script src="../fast/js/resources/js-test-pre.js"></script>
+
+</head>
+
+<body onload="runTests()">
+
+<div class=box id=mybox1>
+Box with a local click handler.
+</div>
+
+<div class=box id=mybox2>
+Box without a local click handler.
+</div>
+
+<script>
+ function monitor(e) { alert(e.target +( e.target.id ? ( ' #' + e.target.id) : '')); };
+ function doSomething(e) {};
+
+ var element = document.getElementById('mybox1');
+ element.addEventListener('click', doSomething, false);
+ element = document.body;
+ element.addEventListener('click', monitor, false);
+</script>
+
+
+<p id='description'></p>
+<div id='console'></div>
+
+<script>
+ var element;
+ var adjustedNode;
+ function findAbsolutePosition(node) {
+ var pos = new Object();
+ pos.left = 0; pos.top = 0;
+ do {
+ pos.left += node.offsetLeft;
+ pos.top += node.offsetTop;
+ } while (node = node.offsetParent);
+ return pos;
+ }
+
+ function testDirectTouch(element)
+ {
+ var pos = findAbsolutePosition(element);
+ var x = pos.left + element.clientWidth / 2 - 1;
+ var y = pos.top + element.clientHeight / 2 - 1;
+ var width = 3;
+ var height = 3;
+ var adjustedNode = internals.touchNodeAdjustedToBestClickableNode(x, y, width, height, document);
+ if (adjustedNode.nodeType == 3) // TEXT node
+ adjustedNode = adjustedNode.parentNode;
+ return adjustedNode;
+ }
+
+ function testDoubleTouch(element1, element2, offset)
+ {
+ var pos1 = findAbsolutePosition(element1);
+ var pos2 = findAbsolutePosition(element2);
+ // We assume the elements have the same x coord and width.
+ var x = pos1.left + element1.clientWidth/2 - 1;
+ var y1 = pos1.top + element1.clientHeight/2 + 1;
+ var y2 = pos2.top + element2.clientHeight/2 - 1;
+ var width = y2 - y1;
+ var height = y2 - y1;
+ var adjustedNode = internals.touchNodeAdjustedToBestClickableNode(x, y1, width, height, document);
+ if (adjustedNode.nodeType == 3) // TEXT node
+ adjustedNode = adjustedNode.parentNode;
+ return adjustedNode;
+ }
+
+ function testDirectTouches()
+ {
+ debug('Testing small direct hits.');
+
+ element = document.getElementById('mybox1');
+ adjustedNode = testDirectTouch(element);
+ shouldBe('adjustedNode.id', 'element.id');
+
+ element = document.getElementById('mybox2');
+ adjustedNode = testDirectTouch(element);
+ shouldBe('adjustedNode.id', 'element.id');
+ }
+
+ function testPreferedTouch()
+ {
+ debug('Testing prefered hits.');
+
+ element1 = document.getElementById('mybox1');
+ element2 = document.getElementById('mybox2');
+ adjustedNode = testDoubleTouch(element1, element2, 0);
+ shouldBe('adjustedNode.id', 'element1.id');
+
+ // First test was centered, now move the test closer to the wrong node, and ensure we still get the prefered node.
+ adjustedNode = testDoubleTouch(element1, element2, 5);
+ shouldBe('adjustedNode.id', 'element1.id');
+
+ adjustedNode = testDoubleTouch(element1, element2, 10);
+ shouldBe('adjustedNode.id', 'element1.id');
+ }
+
+ function runTests()
+ {
+ if (window.layoutTestController && window.internals && internals.touchNodeAdjustedToBestClickableNode) {
+ description('Test the case where a clickable target is nested inside a document that is monitoring clicks. The target with the local event-handler should be chosen if multiple targets are touched.');
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+ testDirectTouches();
+ testPreferedTouch();
+ isSuccessfullyParsed();
+ layoutTestController.notifyDone();
+ }
+ }
+</script>
+</body>
+</html>
--- /dev/null
+some link
+some link breaking lines and link
+hola mundo! a split up link
+hello world some link also breaking
+hi there some link that is breaking multiple lines just for the very fun of it
+
+Test touch-adjustment on inline links. Making sure we can hit over line-breaks, and can miss when tapping between parts of a line-broken link.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Test some direct hits.
+PASS adjustedNode.id is "1"
+PASS adjustedNode.id is "2"
+PASS adjustedNode.id is "4"
+PASS adjustedNode.id is "6"
+Test a few direct misses.
+PASS adjustedNode.id is ""
+PASS adjustedNode.id is ""
+Test some in-direct hits.
+PASS adjustedNode.id is "2"
+PASS adjustedNode.id is "3"
+PASS adjustedNode.id is "4"
+PASS adjustedNode.id is "4"
+PASS adjustedNode.id is "6"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<html>
+<head>
+ <script src="../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body onload="runTests()">
+
+<p style="width: 10em;">
+<a id="1" href="#1">some link</a><br>
+<a id="2" href="#2">some link breaking lines</a> and <a id="3" href="#3">link</a><br>
+hola mundo! <a id="4" href="#4">a split up link</a><br>
+hello world <a id="5" href="#5">some link also breaking</a><br>
+hi there <a id="6" href="#6">some link that is breaking multiple lines just for the very fun of it</a><br><br>
+</p>
+
+
+<p id='description'></p>
+<div id='console'></div>
+
+<script>
+ var element;
+ var adjustedNode;
+ function testRoundTouch(x, y, radius)
+ {
+ var x = x - radius;
+ var y = y - radius;
+ var width = radius * 2;
+ var height = radius * 2;
+ var adjustedNode = internals.touchNodeAdjustedToBestClickableNode(x, y, width, height, document);
+ if (adjustedNode.nodeType == 3) // TEXT node
+ adjustedNode = adjustedNode.parentNode;
+ return adjustedNode;
+ }
+
+ function testDirectTouches()
+ {
+ debug('Test some direct hits.');
+
+ adjustedNode = testRoundTouch(30, 20, 8)
+ shouldBeEqualToString('adjustedNode.id', '1');
+
+ adjustedNode = testRoundTouch(30, 60, 8)
+ shouldBeEqualToString('adjustedNode.id', '2');
+
+ adjustedNode = testRoundTouch(120, 80, 8)
+ shouldBeEqualToString('adjustedNode.id', '4');
+
+ adjustedNode = testRoundTouch(80, 180, 8)
+ shouldBeEqualToString('adjustedNode.id', '6');
+ }
+
+ function testDirectMisses()
+ {
+ debug('Test a few direct misses.');
+
+ adjustedNode = testRoundTouch(56, 60, 8)
+ shouldBeEqualToString('adjustedNode.id', '');
+
+ adjustedNode = testRoundTouch(20, 160, 4)
+ shouldBeEqualToString('adjustedNode.id', '');
+
+ }
+
+ function testIndirectTouches()
+ {
+ debug('Test some in-direct hits.');
+
+ adjustedNode = testRoundTouch(56, 60, 20)
+ shouldBeEqualToString('adjustedNode.id', '2');
+
+ adjustedNode = testRoundTouch(85, 80, 20)
+ shouldBeEqualToString('adjustedNode.id', '3');
+
+ adjustedNode = testRoundTouch(120, 60, 20)
+ shouldBeEqualToString('adjustedNode.id', '4');
+
+ adjustedNode = testRoundTouch(40, 100, 20)
+ shouldBeEqualToString('adjustedNode.id', '4');
+
+ adjustedNode = testRoundTouch(20, 165, 20)
+ shouldBeEqualToString('adjustedNode.id', '6');
+
+ }
+
+ function runTests()
+ {
+ if (window.layoutTestController && window.internals && internals.touchNodeAdjustedToBestClickableNode) {
+ description('Test touch-adjustment on inline links. Making sure we can hit over line-breaks, and can miss when tapping between parts of a line-broken link.');
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+ testDirectTouches();
+ testDirectMisses();
+ testIndirectTouches();
+ isSuccessfullyParsed();
+ layoutTestController.notifyDone();
+ }
+ }
+</script>
+</body>
+</html>
+2012-03-19 Allan Sandfeld Jensen <allan.jensen@nokia.com>
+
+ Select best target for tap gesture.
+ https://bugs.webkit.org/show_bug.cgi?id=78801
+
+ Reviewed by Kenneth Rohde Christiansen.
+ IntRect changes reviewed by Dave Hyatt.
+
+ The new API is available through EventHandler::bestClickableNodeForTouchPoint, but
+ implementation details have been placed in page/TouchAdjustment.
+
+ The default hit detection is performed by measuring the distance to the center
+ lines of the absolute rects of the hit nodes. Absolute rects are used instead
+ of bounding rects to make hit-detecting against links over line breaks. Distance
+ to center line is used to make it easier to hit small links next to large links.
+ For line-rects the distance to the center-line is a better expression of the distance
+ to a rectangles center than the distance to the center-point.
+
+ Tests: touchadjustment/event-triggered-widgets.html
+ touchadjustment/html-label.html
+ touchadjustment/nested-touch.html
+ touchadjustment/touch-inlines.html
+
+ * Target.pri:
+ * page/EventHandler.cpp:
+ (WebCore::EventHandler::handleGestureTap):
+ (WebCore::EventHandler::bestClickableNodeForTouchPoint):
+ * page/EventHandler.h:
+ * page/TouchAdjustment.cpp: Added.
+ (WebCore::TouchAdjustment::QuadForHitTest::QuadForHitTest):
+ (WebCore::TouchAdjustment::QuadForHitTest::node):
+ (WebCore::TouchAdjustment::QuadForHitTest::quad):
+ (WebCore::TouchAdjustment::QuadForHitTest::boundingBox):
+ (WebCore::TouchAdjustment::nodeRespondsToTapGesture):
+ (WebCore::TouchAdjustment::appendAbsoluteQuadsForNodeToHitTestList):
+ (WebCore::TouchAdjustment::compileQuadsForHitTesting):
+ (WebCore::TouchAdjustment::distanceSquaredToQuadCenterLine):
+ (WebCore::TouchAdjustment::findNodeWithLowestMetric):
+ (WebCore::findBestClickableCandidate):
+ * page/TouchAdjustment.h: Added.
+ * platform/graphics/FloatQuad.h:
+ (WebCore::FloatQuad::center):
+ * platform/graphics/IntPoint.h:
+ (WebCore::IntPoint::distanceSquaredToPoint):
+ * platform/graphics/IntRect.cpp:
+ (WebCore::distanceToInterval):
+ (WebCore::IntRect::differenceToPoint):
+ (WebCore::IntRect::differenceFromCenterLineToPoint):
+ * platform/graphics/IntRect.h:
+ (WebCore::IntRect::distanceSquaredToPoint):
+ (WebCore::IntRect::distanceSquaredFromCenterLineToPoint):
+ * platform/graphics/IntSize.h:
+ (WebCore::IntSize::diagonalLengthSquared):
+ * testing/Internals.cpp:
+ (WebCore::Internals::touchPositionAdjustedToBestClickableNode):
+ (WebCore::Internals::touchNodeAdjustedToBestClickableNode):
+ * testing/Internals.h:
+ * testing/Internals.idl:
+
2012-03-19 Mark Pilgrim <pilgrim@chromium.org>
Add ENABLED(FILE_SYSTEM) to DOMFilePath.h
page/SecurityPolicy.cpp \
page/Settings.cpp \
page/SpatialNavigation.cpp \
+ page/TouchAdjustment.cpp \
page/SuspendableTimer.cpp \
page/UserContentURLPattern.cpp \
page/WindowFeatures.cpp \
page/SpeechInputListener.h \
page/SpeechInputResult.h \
page/SpeechInputResultList.h \
+ page/TouchAdjustment.h \
page/WebKitAnimation.h \
page/WebKitAnimationList.h \
page/WindowFeatures.h \
#include "Scrollbar.h"
#include "Settings.h"
#include "SpatialNavigation.h"
+#include "StaticHashSetNodeList.h"
#include "StyleCachedImage.h"
#include "TextEvent.h"
#include "TextIterator.h"
#include "PlatformGestureEvent.h"
#endif
+#if ENABLE(TOUCH_ADJUSTMENT)
+#include "TouchAdjustment.h"
+#endif
+
#if ENABLE(SVG)
#include "SVGDocument.h"
#include "SVGElementInstance.h"
bool EventHandler::handleGestureTap(const PlatformGestureEvent& gestureEvent)
{
// FIXME: Refactor this code to not hit test multiple times.
+ IntPoint adjustedPoint = gestureEvent.position();
+#if ENABLE(TOUCH_ADJUSTMENT)
+ if (!gestureEvent.area().isEmpty()) {
+ Node* targetNode = 0;
+ // For now we use the adjusted position to ensure the later redundant hit-tests hits the right node.
+ bestClickableNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
+ if (!targetNode)
+ return false;
+ }
+#endif
bool defaultPrevented = false;
- PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(), NoButton, PlatformEvent::MouseMoved, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
- PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
- PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseReleased, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
+ PlatformMouseEvent fakeMouseMove(adjustedPoint, gestureEvent.globalPosition(), NoButton, PlatformEvent::MouseMoved, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
+ PlatformMouseEvent fakeMouseDown(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
+ PlatformMouseEvent fakeMouseUp(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseReleased, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
mouseMoved(fakeMouseMove);
defaultPrevented |= handleMousePressEvent(fakeMouseDown);
defaultPrevented |= handleMouseReleaseEvent(fakeMouseUp);
}
#endif
+#if ENABLE(TOUCH_ADJUSTMENT)
+void EventHandler::bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
+{
+ HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
+ HitTestResult result = hitTestResultAtPoint(touchCenter, /*allowShadowContent*/ false, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius);
+
+ IntRect touchRect = result.rectForPoint(touchCenter);
+ RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
+ if (!findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, *nodeList.get())) {
+ // Default to just returning innerNonSharedNode.
+ targetPoint = touchCenter;
+ targetNode = result.innerNonSharedNode();
+ }
+}
+#endif
+
#if ENABLE(CONTEXT_MENUS)
bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
{
bool handleGestureScrollUpdate(const PlatformGestureEvent&);
#endif
+#if ENABLE(TOUCH_ADJUSTMENT)
+ void bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode);
+#endif
+
#if ENABLE(CONTEXT_MENUS)
bool sendContextMenuEvent(const PlatformMouseEvent&);
bool sendContextMenuEventForKey();
--- /dev/null
+/*
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "TouchAdjustment.h"
+
+#include "ContainerNode.h"
+#include "FloatPoint.h"
+#include "FloatQuad.h"
+#include "HTMLLabelElement.h"
+#include "HTMLNames.h"
+#include "IntPoint.h"
+#include "IntSize.h"
+#include "Node.h"
+#include "RenderBox.h"
+#include "RenderObject.h"
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+namespace TouchAdjustment {
+
+// Class for remembering absolute quads of a target node and what node they represent.
+class SubtargetGeometry {
+public:
+ SubtargetGeometry(Node* node, const FloatQuad& quad)
+ : m_node(node)
+ , m_quad(quad)
+ { }
+
+ Node* node() const { return m_node; }
+ FloatQuad quad() const { return m_quad; }
+ IntRect boundingBox() const { return m_quad.enclosingBoundingBox(); }
+
+private:
+ Node* m_node;
+ FloatQuad m_quad;
+};
+
+typedef Vector<SubtargetGeometry> SubtargetGeometryList;
+typedef bool (*NodeFilter)(Node*);
+typedef float (*DistanceFunction)(const IntPoint&, const IntRect&, const SubtargetGeometry&);
+
+// Takes non-const Node* because isContentEditable is a non-const function.
+bool nodeRespondsToTapGesture(Node* node)
+{
+ if (node->isLink()
+ || node->isContentEditable()
+ || node->isMouseFocusable())
+ return true;
+ if (node->isElementNode()) {
+ Element* element = static_cast<Element*>(node);
+ if (element->hasTagName(HTMLNames::labelTag) && static_cast<HTMLLabelElement*>(element)->control())
+ return true;
+ }
+ // FIXME: Implement hasDefaultEventHandler and use that instead of all of the above checks.
+ if (node->hasEventListeners()
+ && (node->hasEventListeners(eventNames().clickEvent)
+ || node->hasEventListeners(eventNames().DOMActivateEvent)
+ || node->hasEventListeners(eventNames().mousedownEvent)
+ || node->hasEventListeners(eventNames().mouseupEvent)
+ || node->hasEventListeners(eventNames().mousemoveEvent)
+ // Checking for focus events is not necessary since they can only fire on
+ // focusable elements which have already been captured above.
+ ))
+ return true;
+ if (node->renderStyle()) {
+ // Accept nodes that has a CSS effect when touched.
+ if (node->renderStyle()->affectedByActiveRules() || node->renderStyle()->affectedByHoverRules())
+ return true;
+ }
+ return false;
+}
+
+static inline void appendSubtargetsForNodeToList(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));
+}
+
+// Compiles a list of subtargets of all the relevant target nodes.
+void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryList& subtargets, NodeFilter nodeFilter)
+{
+ // Find candidates responding to tap gesture events in O(n) time.
+ HashMap<Node*, Node*> responderMap;
+ HashSet<Node*> ancestorsToRespondersSet;
+ Vector<Node*> candidates;
+
+ // A node matching the NodeFilter is called a responder. Candidate nodes must either be a
+ // responder or have an ancestor that is a responder.
+ // This iteration tests all ancestors at most once by caching earlier results.
+ unsigned length = intersectedNodes.length();
+ for (unsigned i = 0; i < length; ++i) {
+ Node* const node = intersectedNodes.item(i);
+ if (responderMap.contains(node))
+ // Skip nodes that are direct ancestors of other candidates. They would hit-test
+ // against the same absolute quads.
+ continue;
+ Vector<Node*> visitedNodes;
+ Node* respondingNode = 0;
+ for (Node* visitedNode = node; visitedNode; visitedNode = visitedNode->parentOrHostNode()) {
+ // Check if we already have a result for a common ancestor from another candidate.
+ respondingNode = responderMap.get(visitedNode);
+ if (respondingNode)
+ break;
+ visitedNodes.append(visitedNode);
+ // Check if the node filter applies, which would mean we have found a responding node.
+ if (nodeFilter(visitedNode)) {
+ respondingNode = visitedNode;
+ // Continue the iteration to collect the ancestors of the responder, which we will need later.
+ for (visitedNode = visitedNode->parentOrHostNode(); visitedNode; visitedNode = visitedNode->parentOrHostNode()) {
+ pair<HashSet<Node*>::iterator, bool> addResult = ancestorsToRespondersSet.add(visitedNode);
+ if (!addResult.second)
+ break;
+ }
+ break;
+ }
+ }
+ // Insert the detected responder for all the visited nodes.
+ for (unsigned j = 0; j < visitedNodes.size(); j++)
+ responderMap.add(visitedNodes[j], respondingNode);
+
+ if (respondingNode)
+ candidates.append(node);
+ }
+
+ // We compile the list of component absolute quads instead of using the bounding rect
+ // to be able to perform better hit-testing on inline links on line-breaks.
+ length = candidates.size();
+ for (unsigned i = 0; i < length; i++) {
+ Node* candidate = candidates[i];
+ // Skip nodes who's responders are ancestors of other responders. This gives preference to
+ // the inner-most event-handlers. So that a link is always preferred even when contained
+ // in an element that monitors all click-events.
+ Node* respondingNode = responderMap.get(candidate);
+ ASSERT(respondingNode);
+ if (ancestorsToRespondersSet.contains(respondingNode))
+ continue;
+ appendSubtargetsForNodeToList(candidate, subtargets);
+ }
+}
+
+float distanceSquaredToTargetCenterLine(const IntPoint& touchHotspot, const IntRect& touchArea, const SubtargetGeometry& subtarget)
+{
+ UNUSED_PARAM(touchArea);
+ // For a better center of a line-box we use the center-line instead of the center-point.
+ // We use the center-line of the bounding box of the quad though, since it is much faster
+ // and gives the same result in all untransformed cases, and in transformed cases still
+ // gives a better distance-function than the distance to the center-point.
+ IntRect rect = subtarget.boundingBox();
+
+ return rect.distanceSquaredFromCenterLineToPoint(touchHotspot);
+}
+
+// A generic function for finding the target node with the lowest distance metric. A distance metric here is the result
+// of a distance-like function, that computes how well the touch hits the node.
+// Distance functions could for instance be distance squared or area of intersection.
+bool findNodeWithLowestDistanceMetric(Node*& targetNode, IntPoint& targetPoint, const IntPoint& touchHotspot, const IntRect& touchArea, SubtargetGeometryList& subtargets, DistanceFunction distanceFunction)
+{
+ targetNode = 0;
+
+ float bestDistanceMetric = INFINITY;
+ SubtargetGeometryList::const_iterator it = subtargets.begin();
+ const SubtargetGeometryList::const_iterator end = subtargets.end();
+ for (; it != end; ++it) {
+ Node* node = it->node();
+ float distanceMetric = distanceFunction(touchHotspot, touchArea, *it);
+ if (distanceMetric < bestDistanceMetric) {
+ targetPoint = roundedIntPoint(it->quad().center());
+ targetNode = node;
+ bestDistanceMetric = distanceMetric;
+ }
+ }
+
+ return (targetNode);
+}
+
+} // namespace TouchAdjustment
+
+bool findBestClickableCandidate(Node*& targetNode, IntPoint &targetPoint, const IntPoint &touchHotspot, const IntRect &touchArea, const NodeList& nodeList)
+{
+ TouchAdjustment::SubtargetGeometryList subtargets;
+ TouchAdjustment::compileSubtargetList(nodeList, subtargets, TouchAdjustment::nodeRespondsToTapGesture);
+ return TouchAdjustment::findNodeWithLowestDistanceMetric(targetNode, targetPoint, touchHotspot, touchArea, subtargets, TouchAdjustment::distanceSquaredToTargetCenterLine);
+}
+
+} // namespace WebCore
--- /dev/null
+/*
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TouchAdjustment_h
+#define TouchAdjustment_h
+
+#include "IntPoint.h"
+#include "IntRect.h"
+#include "Node.h"
+#include "NodeList.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+bool findBestClickableCandidate(Node*& targetNode, IntPoint& targetPoint, const IntPoint& touchHotspot, const IntRect& touchArea, const NodeList&);
+// FIXME: Implement the similar functions for other gestures here as well.
+
+} // namespace WebCore
+
+#endif
// from transformed rects.
bool containsQuad(const FloatQuad&) const;
+ // The center of the quad. If the quad is the result of a affine-transformed rectangle this is the same as the original center transformed.
+ FloatPoint center() const
+ {
+ return FloatPoint((m_p1.x() + m_p2.x() + m_p3.x() + m_p4.x()) / 4.0,
+ (m_p1.y() + m_p2.y() + m_p3.y() + m_p4.y()) / 4.0);
+ }
+
FloatRect boundingBox() const;
IntRect enclosingBoundingBox() const
{
m_y < other.m_y ? m_y : other.m_y);
}
+ int distanceSquaredToPoint(const IntPoint&) const;
+
void clampNegativeToZero()
{
*this = expandedTo(zero());
return IntSize(a.x(), a.y());
}
+inline int IntPoint::distanceSquaredToPoint(const IntPoint& point) const
+{
+ return ((*this) - point).diagonalLengthSquared();
+}
+
#if PLATFORM(QT)
inline QDataStream& operator<<(QDataStream& stream, const IntPoint& point)
{
m_size.setHeight((int)(height() * s));
}
+static inline int distanceToInterval(int pos, int start, int end)
+{
+ if (pos < start)
+ return start - pos;
+ if (pos > end)
+ return end - pos;
+ return 0;
+}
+
+IntSize IntRect::differenceToPoint(const IntPoint& point) const
+{
+ int xdistance = distanceToInterval(point.x(), x(), maxX());
+ int ydistance = distanceToInterval(point.y(), y(), maxY());
+ return IntSize(xdistance, ydistance);
+}
+
+IntSize IntRect::differenceFromCenterLineToPoint(const IntPoint& point) const
+{
+ // The center-line is the natural center of a rectangle. It has an equal distance to all sides of the rectangle.
+ IntPoint centerPoint = center();
+ int xdistance = centerPoint.x() - point.x();
+ int ydistance = centerPoint.y() - point.y();
+ if (width() > height())
+ xdistance = distanceToInterval(point.x(), x() + (height() / 2), maxX() - (height() / 2));
+ else
+ ydistance = distanceToInterval(point.y(), y() + (width() / 2), maxY() - (width() / 2));
+ return IntSize(xdistance, ydistance);
+}
+
IntRect unionRect(const Vector<IntRect>& rects)
{
IntRect result;
void inflate(int d) { inflateX(d); inflateY(d); }
void scale(float s);
+ IntSize differenceToPoint(const IntPoint&) const;
+ IntSize differenceFromCenterLineToPoint(const IntPoint&) const;
+ int distanceSquaredToPoint(const IntPoint& p) const { return differenceToPoint(p).diagonalLengthSquared(); }
+ int distanceSquaredFromCenterLineToPoint(const IntPoint& p) const { return differenceFromCenterLineToPoint(p).diagonalLengthSquared(); }
+
IntRect transposedRect() const { return IntRect(m_location.transposedPoint(), m_size.transposedSize()); }
#if PLATFORM(WX)
*this = expandedTo(IntSize());
}
+ int diagonalLengthSquared() const
+ {
+ return m_width * m_width + m_height * m_height;
+ }
+
IntSize transposedSize() const
{
return IntSize(m_height, m_width);
#include "BatteryController.h"
#endif
+#if ENABLE(TOUCH_ADJUSTMENT)
+#include "EventHandler.h"
+#include "WebKitPoint.h"
+#endif
+
namespace WebCore {
static bool markerTypesFrom(const String& markerType, DocumentMarker::MarkerTypes& result)
return range->text();
}
+
+#if ENABLE(TOUCH_ADJUSTMENT)
+PassRefPtr<WebKitPoint> Internals::touchPositionAdjustedToBestClickableNode(long x, long y, long width, long height, Document* document, ExceptionCode& ec)
+{
+ if (!document || !document->frame()) {
+ ec = INVALID_ACCESS_ERR;
+ return 0;
+ }
+
+ IntSize radius(width / 2, height / 2);
+ IntPoint point(x + radius.width(), y + radius.height());
+
+ Node* targetNode;
+ IntPoint adjustedPoint;
+ document->frame()->eventHandler()->bestClickableNodeForTouchPoint(point, radius, adjustedPoint, targetNode);
+ return WebKitPoint::create(adjustedPoint.x(), adjustedPoint.y());
+}
+
+Node* Internals::touchNodeAdjustedToBestClickableNode(long x, long y, long width, long height, Document* document, ExceptionCode& ec)
+{
+ if (!document || !document->frame()) {
+ ec = INVALID_ACCESS_ERR;
+ return 0;
+ }
+
+ IntSize radius(width / 2, height / 2);
+ IntPoint point(x + radius.width(), y + radius.height());
+
+ Node* targetNode;
+ IntPoint adjustedPoint;
+ document->frame()->eventHandler()->bestClickableNodeForTouchPoint(point, radius, adjustedPoint, targetNode);
+ return targetNode;
+}
+#endif
+
+
int Internals::lastSpellCheckRequestSequence(Document* document, ExceptionCode& ec)
{
SpellChecker* checker = spellchecker(document);
class Node;
class Range;
class ShadowRoot;
+class WebKitPoint;
typedef int ExceptionCode;
unsigned lengthFromRange(Element* scope, const Range*, ExceptionCode&);
String rangeAsText(const Range*, ExceptionCode&);
+#if ENABLE(TOUCH_ADJUSTMENT)
+ PassRefPtr<WebKitPoint> touchPositionAdjustedToBestClickableNode(long x, long y, long width, long height, Document*, ExceptionCode&);
+ Node* touchNodeAdjustedToBestClickableNode(long x, long y, long width, long height, Document*, ExceptionCode&);
+#endif
+
int lastSpellCheckRequestSequence(Document*, ExceptionCode&);
int lastSpellCheckProcessedSequence(Document*, ExceptionCode&);
unsigned long lengthFromRange(in Element scope, in Range range) raises (DOMException);
DOMString rangeAsText(in Range range) raises (DOMException);
+#if defined(ENABLE_TOUCH_ADJUSTMENT) && ENABLE_TOUCH_ADJUSTMENT
+ WebKitPoint touchPositionAdjustedToBestClickableNode(in long x, in long y, in long width, in long height, in Document document) raises (DOMException);
+ Node touchNodeAdjustedToBestClickableNode(in long x, in long y, in long width, in long height, in Document document) raises (DOMException);
+#endif
+
long lastSpellCheckRequestSequence(in Document document) raises (DOMException);
long lastSpellCheckProcessedSequence(in Document document) raises (DOMException);
+2012-03-19 Allan Sandfeld Jensen <allan.jensen@nokia.com>
+
+ Select best target for tap gesture.
+ https://bugs.webkit.org/show_bug.cgi?id=78801
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Send radius to handlePotentialSingleTapEvent so it can do the same hit
+ detection the tap gesture later does.
+
+ * UIProcess/WebPageProxy.cpp:
+ (WebKit::WebPageProxy::handlePotentialActivation):
+ * UIProcess/WebPageProxy.h:
+ * UIProcess/qt/QtWebPageEventHandler.cpp:
+ (QtWebPageEventHandler::handlePotentialSingleTapEvent):
+ * WebProcess/WebPage/WebPage.cpp:
+ (WebKit::WebPage::highlightPotentialActivation):
+ * WebProcess/WebPage/WebPage.h:
+ * WebProcess/WebPage/WebPage.messages.in:
+
2012-03-19 Alexander Færøy <alexander.faeroy@nokia.com>
[Qt] Add experimental API for dynamically changing the UA string
#if ENABLE(TOUCH_EVENTS)
#if PLATFORM(QT)
-void WebPageProxy::handlePotentialActivation(const IntPoint& layoutPoint)
+void WebPageProxy::handlePotentialActivation(const IntPoint& touchPoint, const IntSize& touchArea)
{
- process()->send(Messages::WebPage::HighlightPotentialActivation(layoutPoint), m_pageID);
+ process()->send(Messages::WebPage::HighlightPotentialActivation(touchPoint, touchArea), m_pageID);
}
#endif
#if ENABLE(TOUCH_EVENTS)
void handleTouchEvent(const NativeWebTouchEvent&);
#if PLATFORM(QT)
- void handlePotentialActivation(const WebCore::IntPoint&);
+ void handlePotentialActivation(const WebCore::IntPoint& touchPoint, const WebCore::IntSize& touchArea);
#endif
#endif
{
#if ENABLE(TOUCH_EVENTS)
QTransform fromItemTransform = m_webPage->transformFromItem();
- m_webPageProxy->handlePotentialActivation(fromItemTransform.map(point.pos()).toPoint());
+ m_webPageProxy->handlePotentialActivation(fromItemTransform.map(point.pos()).toPoint(), IntSize(point.rect().size().toSize()));
#else
Q_UNUSED(point);
#endif
#if ENABLE(TOUCH_EVENTS)
#if PLATFORM(QT)
-void WebPage::highlightPotentialActivation(const IntPoint& point)
+void WebPage::highlightPotentialActivation(const IntPoint& point, const IntSize& area)
{
Node* activationNode = 0;
Frame* mainframe = m_page->mainFrame();
+ IntPoint adjustedPoint;
if (point != IntPoint::zero()) {
+#if ENABLE(TOUCH_ADJUSTMENT)
+ mainframe->eventHandler()->bestClickableNodeForTouchPoint(point, IntSize(area.width() / 2, area.height() / 2), adjustedPoint, activationNode);
+#else
HitTestResult result = mainframe->eventHandler()->hitTestResultAtPoint(mainframe->view()->windowToContents(point), /*allowShadowContent*/ false, /*ignoreClipping*/ true);
activationNode = result.innerNode();
-
- if (!activationNode->isFocusable())
+#endif
+ if (activationNode && !activationNode->isFocusable())
activationNode = activationNode->enclosingLinkEventParentOrSelf();
}
void touchEvent(const WebTouchEvent&);
void touchEventSyncForTesting(const WebTouchEvent&, bool& handled);
#if PLATFORM(QT)
- void highlightPotentialActivation(const WebCore::IntPoint&);
+ void highlightPotentialActivation(const WebCore::IntPoint&, const WebCore::IntSize& area);
#endif
#endif
void contextMenuHidden() { m_isShowingContextMenu = false; }
#if ENABLE(TOUCH_EVENTS)
TouchEvent(WebKit::WebTouchEvent event)
TouchEventSyncForTesting(WebKit::WebTouchEvent event) -> (bool handled)
-#endif
#if ENABLE(TOUCH_EVENTS) && PLATFORM(QT)
- HighlightPotentialActivation(WebCore::IntPoint point)
+ HighlightPotentialActivation(WebCore::IntPoint point, WebCore::IntSize area)
#endif
ContextMenuHidden()
+2012-03-19 Allan Sandfeld Jensen <allan.jensen@nokia.com>
+
+ Select best target for tap gesture.
+ https://bugs.webkit.org/show_bug.cgi?id=78801
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Add TOUCH_ADJUSTMENT to enabled features.
+
+ * qmake/mkspecs/features/features.prf:
+
2012-03-19 Robert Kroeger <rjkroege@chromium.org>
[chromium] synthesize wheel events for fling on main thread
!contains(DEFINES, ENABLE_VIDEO_TRACK=.): DEFINES += ENABLE_VIDEO_TRACK=0
!contains(DEFINES, ENABLE_TOUCH_ICON_LOADING=.): DEFINES += ENABLE_TOUCH_ICON_LOADING=0
!contains(DEFINES, ENABLE_ANIMATION_API=.): DEFINES += ENABLE_ANIMATION_API=0
+!contains(DEFINES, ENABLE_TOUCH_ADJUSTMENT=.): DEFINES += ENABLE_TOUCH_ADJUSTMENT=1
# Policy decisions: for using a particular third-party library or optional OS service
!contains(DEFINES, WTF_USE_QT_IMAGE_DECODER=.): DEFINES += WTF_USE_QT_IMAGE_DECODER=1
contains(DEFINES, ENABLE_DATA_TRANSFER_ITEMS=1): FEATURE_DEFINES_JAVASCRIPT += ENABLE_DATA_TRANSFER_ITEMS=1
contains(DEFINES, ENABLE_FULLSCREEN_API=1): FEATURE_DEFINES_JAVASCRIPT += ENABLE_FULLSCREEN_API=1
contains(DEFINES, ENABLE_REQUEST_ANIMATION_FRAME=1): FEATURE_DEFINES_JAVASCRIPT += ENABLE_REQUEST_ANIMATION_FRAME=1
+contains(DEFINES, ENABLE_TOUCH_ADJUSTMENT=1): FEATURE_DEFINES_JAVASCRIPT += ENABLE_TOUCH_ADJUSTMENT=1
# Used to compute defaults for the build-webkit script
# Don't place anything after this!