[SCM] WebKit Debian packaging branch, debian/experimental, updated. debian/1.3.8-1-1049-g2e11a8e
commit-queue at webkit.org
commit-queue at webkit.org
Fri Jan 21 14:37:40 UTC 2011
The following commit has been merged in the debian/experimental branch:
commit ec39dba893f89fa7d62724bec0537dc56bb2cd59
Author: commit-queue at webkit.org <commit-queue at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Thu Dec 23 13:49:46 2010 +0000
2010-12-23 Jonathan Dixon <joth at chromium.org>
Reviewed by Steve Block.
TouchEvents does not support multi-touch on a page with multiple touch targets
https://bugs.webkit.org/show_bug.cgi?id=51258
* fast/events/touch/multi-touch-grouped-targets-expected.txt: Added.
* fast/events/touch/multi-touch-grouped-targets.html: Added.
* fast/events/touch/script-tests/multi-touch-grouped-targets.js: Added.
(declareTouchHandler.return.shouldBe):
(declareTouchHandler):
(touchEndHandler):
Added new test that ensures both test targets receive events when hit by multiple
touch points from the same platform event.
* fast/events/touch/script-tests/touch-target-limited.js:
(declareTouchStart.return.touchStartHandler):
(declareTouchStart):
(declareTouchMove.return.touchMoveHandler):
(declareTouchMove):
* fast/events/touch/script-tests/touch-target.js:
(declareTouchStart.return.touchStartHandler):
(declareTouchStart):
(declareTouchMove.return.touchMoveHandler):
(declareTouchMove):
* fast/events/touch/touch-target-expected.txt:
* fast/events/touch/touch-target-limited-expected.txt:
Updated & rebaselined existing tests to reflect new expectations.
2010-12-23 Jonathan Dixon <joth at chromium.org>
Reviewed by Steve Block.
TouchEvents does not support multi-touch on a page with multiple touch targets
https://bugs.webkit.org/show_bug.cgi?id=51258
Test: fast/events/touch/multi-touch-grouped-targets.html
* page/EventHandler.cpp:
(WebCore::eventNameForTouchPointState):
(WebCore::EventHandler::handleTouchEvent):
Redesigned event handler to ensure all event targets involved in a given
multitouch event get the appropriate event(s) fired.
* platform/PlatformTouchPoint.h: Added end-stop marker for State enum.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@74553 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 6dd1c9d..bcf3c18 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,33 @@
+2010-12-23 Jonathan Dixon <joth at chromium.org>
+
+ Reviewed by Steve Block.
+
+ TouchEvents does not support multi-touch on a page with multiple touch targets
+ https://bugs.webkit.org/show_bug.cgi?id=51258
+
+ * fast/events/touch/multi-touch-grouped-targets-expected.txt: Added.
+ * fast/events/touch/multi-touch-grouped-targets.html: Added.
+ * fast/events/touch/script-tests/multi-touch-grouped-targets.js: Added.
+ (declareTouchHandler.return.shouldBe):
+ (declareTouchHandler):
+ (touchEndHandler):
+ Added new test that ensures both test targets receive events when hit by multiple
+ touch points from the same platform event.
+
+ * fast/events/touch/script-tests/touch-target-limited.js:
+ (declareTouchStart.return.touchStartHandler):
+ (declareTouchStart):
+ (declareTouchMove.return.touchMoveHandler):
+ (declareTouchMove):
+ * fast/events/touch/script-tests/touch-target.js:
+ (declareTouchStart.return.touchStartHandler):
+ (declareTouchStart):
+ (declareTouchMove.return.touchMoveHandler):
+ (declareTouchMove):
+ * fast/events/touch/touch-target-expected.txt:
+ * fast/events/touch/touch-target-limited-expected.txt:
+ Updated & rebaselined existing tests to reflect new expectations.
+
2010-12-23 Jeremy Moskovich <jeremy at chromium.org>
Unreviewed test expectations update.
diff --git a/LayoutTests/fast/events/touch/multi-touch-grouped-targets-expected.txt b/LayoutTests/fast/events/touch/multi-touch-grouped-targets-expected.txt
new file mode 100644
index 0000000..a1d032f
--- /dev/null
+++ b/LayoutTests/fast/events/touch/multi-touch-grouped-targets-expected.txt
@@ -0,0 +1,26 @@
+Tests that the an event is sent for every touch listener, and target touches contains all the points for that target
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+
+PASS event.touches.length is 3
+PASS event.changedTouches.length is 3
+PASS event.touches.length is 3
+PASS event.changedTouches.length is 3
+PASS event.touches.length is 3
+PASS event.changedTouches.length is 3
+PASS event.touches.length is 3
+PASS event.changedTouches.length is 3
+PASS event.type is "touchend"
+PASS event.touches.length is 0
+PASS event.targetTouches.length is 0
+PASS event.changedTouches.length is 3
+PASS event.type is "touchend"
+PASS event.touches.length is 0
+PASS event.targetTouches.length is 0
+PASS event.changedTouches.length is 3
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/events/touch/multi-touch-grouped-targets.html b/LayoutTests/fast/events/touch/multi-touch-grouped-targets.html
new file mode 100644
index 0000000..ef965c1
--- /dev/null
+++ b/LayoutTests/fast/events/touch/multi-touch-grouped-targets.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../js/resources/js-test-style.css">
+<script src="../../js/resources/js-test-pre.js"></script>
+<script src="../../js/resources/js-test-post-function.js"></script>
+<!--
+ Touch tests that involve the ontouchstart, ontouchmove, ontouchend or ontouchcancel callbacks
+ should be written in an asynchronous fashion so they can be run on mobile platforms like Android.
+ This template will generate an asynchronous style test by using the js-test-post-function script.
+ You will need to invoke isSuccessfullyParsed() in your test script when the test completes.
+-->
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/multi-touch-grouped-targets.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/events/touch/script-tests/multi-touch-grouped-targets.js b/LayoutTests/fast/events/touch/script-tests/multi-touch-grouped-targets.js
new file mode 100644
index 0000000..9d26dac
--- /dev/null
+++ b/LayoutTests/fast/events/touch/script-tests/multi-touch-grouped-targets.js
@@ -0,0 +1,89 @@
+var targetsDiv = document.createElement("div");
+targetsDiv.id = "targetsDiv";
+
+var div1 = document.createElement("div");
+div1.id = "targetA";
+div1.style.width = "100px";
+div1.style.height = "100px";
+div1.style.backgroundColor = "blue";
+
+var div2 = document.createElement("div");
+div2.id = "targetB";
+div2.style.width = "100px";
+div2.style.height = "100px";
+div2.style.backgroundColor = "green";
+
+document.body.insertBefore(targetsDiv, document.getElementById('console'));
+targetsDiv.appendChild(div1);
+targetsDiv.appendChild(document.createElement('br'));
+targetsDiv.appendChild(div2);
+
+function declareTouchHandler(div_id, expectedTargetTouches)
+{
+ return function ()
+ {
+ // Do not use the parameters (div_id, expectedTargetTouches) in shouldBe.. calls, as
+ // the order of event dispatch is not deterministic across executions and reordering
+ // ofthe PASS debug output details would cause the test to be unreliable.
+ shouldBe('event.touches.length', '3');
+ if (event.targetTouches.length != expectedTargetTouches)
+ testFailed('Wrong targetTouch length: ' + event.targetTouches.length + ' vs ' + expectedTargetTouches);
+ for (var i = 0; i < event.targetTouches.length; i++)
+ {
+ if (event.targetTouches[i].target.id != div_id)
+ testFailed('Incorrect targetTouch ID: ' + event.targetTouches[i].target.id + ' vs ' + div_id);
+ }
+ shouldBe('event.changedTouches.length', '3');
+ }
+}
+
+var endCount = 0;
+function touchEndHandler()
+{
+ shouldBeEqualToString('event.type', 'touchend');
+
+ shouldBe('event.touches.length', '0');
+ shouldBe('event.targetTouches.length', '0');
+ shouldBe('event.changedTouches.length', '3');
+
+ if (++endCount == 2)
+ {
+ successfullyParsed = true;
+ layoutTestController.notifyDone();
+ isSuccessfullyParsed();
+ }
+}
+
+div1.addEventListener("touchstart", declareTouchHandler('targetA', '2'), false);
+div1.addEventListener("touchmove", declareTouchHandler('targetA', '2'), false);
+div1.addEventListener("touchend", touchEndHandler, false);
+
+div2.addEventListener("touchstart", declareTouchHandler('targetB', '1'), false);
+div2.addEventListener("touchmove", declareTouchHandler('targetB', '1'), false);
+div2.addEventListener("touchend", touchEndHandler, false);
+
+description("Tests that the an event is sent for every touch listener, and target touches contains all the points for that target");
+
+if (window.layoutTestController) {
+ layoutTestController.waitUntilDone();
+}
+
+if (window.eventSender) {
+ eventSender.clearTouchPoints();
+ eventSender.addTouchPoint(50, 150);
+ eventSender.addTouchPoint(50, 250);
+ eventSender.addTouchPoint(50, 150);
+ eventSender.touchStart();
+
+ eventSender.updateTouchPoint(0, 200, 150);
+ eventSender.updateTouchPoint(1, 300, 250);
+ eventSender.updateTouchPoint(2, 400, 150);
+ eventSender.touchMove();
+
+ eventSender.releaseTouchPoint(0);
+ eventSender.releaseTouchPoint(1);
+ eventSender.releaseTouchPoint(2);
+ eventSender.touchEnd();
+} else
+ debug('This test requires DRT.');
+
diff --git a/LayoutTests/fast/events/touch/script-tests/touch-target-limited.js b/LayoutTests/fast/events/touch/script-tests/touch-target-limited.js
index fd3400c..3aae47a 100644
--- a/LayoutTests/fast/events/touch/script-tests/touch-target-limited.js
+++ b/LayoutTests/fast/events/touch/script-tests/touch-target-limited.js
@@ -13,59 +13,69 @@ div2.style.width = "100px";
div2.style.height = "100px";
div2.style.backgroundColor = "green";
-var touchStartCount = 0;
-var touchMoveCount = 0;
-
document.body.insertBefore(targetsDiv, document.getElementById('console'));
targetsDiv.appendChild(div1);
targetsDiv.appendChild(document.createElement('br'));
targetsDiv.appendChild(div2);
-function touchStartHandler()
+function declareTouchStart()
{
- shouldBeEqualToString('event.type', 'touchstart');
- switch (touchStartCount) {
- case 0:
- shouldBeEqualToString('event.touches[0].target.id', div1.id);
- shouldBeEqualToString('event.touches[1].target.id', div2.id);
- break;
- case 1:
- shouldBeEqualToString('event.touches[0].target.id', div2.id);
- shouldBeEqualToString('event.touches[1].target.id', div1.id);
- break;
+ var touchStartCount = 0;
+ return function touchStartHandler()
+ {
+ shouldBeEqualToString('event.type', 'touchstart');
+ switch (touchStartCount) {
+ case 0:
+ shouldBeEqualToString('event.touches[0].target.id', div1.id);
+ shouldBeEqualToString('event.touches[1].target.id', div2.id);
+ break;
+ case 1:
+ shouldBeEqualToString('event.touches[0].target.id', div2.id);
+ shouldBeEqualToString('event.touches[1].target.id', div1.id);
+ break;
+ }
+ shouldBe('event.targetTouches.length', '1');
+
+ touchStartCount++;
}
-
- touchStartCount++;
}
-function touchMoveHandler()
-{
- shouldBeEqualToString('event.type', 'touchmove');
- switch (touchMoveCount) {
- case 0:
- case 1:
- shouldBeEqualToString('event.touches[0].target.id', div1.id);
- shouldBeEqualToString('event.touches[1].target.id', div2.id);
- break;
- case 2:
- shouldBeEqualToString('event.touches[0].target.id', div2.id);
- shouldBeEqualToString('event.touches[1].target.id', div1.id);
- break;
- }
+var totalTouchMoveCount = 0;
- if (++touchMoveCount == 3)
+function declareTouchMove(div_id)
+{
+ var touchMoveCount = 0;
+ return function touchMoveHandler()
{
- successfullyParsed = true;
- layoutTestController.notifyDone();
- isSuccessfullyParsed();
+ shouldBeEqualToString('event.type', 'touchmove');
+ switch (touchMoveCount) {
+ case 0:
+ case 1:
+ shouldBeEqualToString('event.touches[0].target.id', div1.id);
+ shouldBeEqualToString('event.touches[1].target.id', div2.id);
+ break;
+ case 2:
+ shouldBeEqualToString('event.touches[0].target.id', div2.id);
+ shouldBeEqualToString('event.touches[1].target.id', div1.id);
+ break;
+ }
+ shouldBe('event.targetTouches.length', '1');
+ ++touchMoveCount;
+
+ if (++totalTouchMoveCount == 6)
+ {
+ successfullyParsed = true;
+ layoutTestController.notifyDone();
+ isSuccessfullyParsed();
+ }
}
}
-div1.addEventListener("touchstart", touchStartHandler, false);
-div1.addEventListener("touchmove", touchMoveHandler, false);
+div1.addEventListener("touchstart", declareTouchStart(), false);
+div1.addEventListener("touchmove", declareTouchMove(), false);
-div2.addEventListener("touchstart", touchStartHandler, false);
-div2.addEventListener("touchmove", touchMoveHandler, false);
+div2.addEventListener("touchstart", declareTouchStart(), false);
+div2.addEventListener("touchmove", declareTouchMove(), false);
description("Tests that the target of touches match the element where the event originated, not where the touch is currently occurring. This is a limited version of test touch-target.html that avoids the situation where one touch point is released while another is maintained.");
diff --git a/LayoutTests/fast/events/touch/script-tests/touch-target.js b/LayoutTests/fast/events/touch/script-tests/touch-target.js
index 8e47f23..de58606 100644
--- a/LayoutTests/fast/events/touch/script-tests/touch-target.js
+++ b/LayoutTests/fast/events/touch/script-tests/touch-target.js
@@ -13,59 +13,69 @@ div2.style.width = "100px";
div2.style.height = "100px";
div2.style.backgroundColor = "green";
-var touchStartCount = 0;
-var touchMoveCount = 0;
-
document.body.insertBefore(targetsDiv, document.getElementById('console'));
targetsDiv.appendChild(div1);
targetsDiv.appendChild(document.createElement('br'));
targetsDiv.appendChild(div2);
-function touchStartHandler()
+function declareTouchStart()
{
- shouldBeEqualToString('event.type', 'touchstart');
- switch (touchStartCount) {
- case 0:
- shouldBeEqualToString('event.touches[0].target.id', div1.id);
- shouldBeEqualToString('event.touches[1].target.id', div2.id);
- break;
- case 1:
- shouldBeEqualToString('event.touches[0].target.id', div2.id);
- shouldBeEqualToString('event.touches[1].target.id', div1.id);
- break;
+ var touchStartCount = 0;
+ return function touchStartHandler()
+ {
+ shouldBeEqualToString('event.type', 'touchstart');
+ switch (touchStartCount) {
+ case 0:
+ shouldBeEqualToString('event.touches[0].target.id', div1.id);
+ shouldBeEqualToString('event.touches[1].target.id', div2.id);
+ break;
+ case 1:
+ shouldBeEqualToString('event.touches[0].target.id', div2.id);
+ shouldBeEqualToString('event.touches[1].target.id', div1.id);
+ break;
+ }
+ shouldBe('event.targetTouches.length', '1');
+
+ touchStartCount++;
}
-
- touchStartCount++;
}
-function touchMoveHandler()
-{
- shouldBeEqualToString('event.type', 'touchmove');
- switch (touchMoveCount) {
- case 0:
- case 1:
- shouldBeEqualToString('event.touches[0].target.id', div1.id);
- shouldBeEqualToString('event.touches[1].target.id', div2.id);
- break;
- case 2:
- shouldBeEqualToString('event.touches[0].target.id', div2.id);
- shouldBeEqualToString('event.touches[1].target.id', div1.id);
- break;
- }
+var totalTouchMoveCount = 0;
- if (++touchMoveCount == 3)
+function declareTouchMove(div_id)
+{
+ var touchMoveCount = 0;
+ return function touchMoveHandler()
{
- successfullyParsed = true;
- layoutTestController.notifyDone();
- isSuccessfullyParsed();
+ shouldBeEqualToString('event.type', 'touchmove');
+ switch (touchMoveCount) {
+ case 0:
+ case 1:
+ shouldBeEqualToString('event.touches[0].target.id', div1.id);
+ shouldBeEqualToString('event.touches[1].target.id', div2.id);
+ break;
+ case 2:
+ shouldBeEqualToString('event.touches[0].target.id', div2.id);
+ shouldBeEqualToString('event.touches[1].target.id', div1.id);
+ break;
+ }
+ shouldBe('event.targetTouches.length', '1');
+ ++touchMoveCount;
+
+ if (++totalTouchMoveCount == 6)
+ {
+ successfullyParsed = true;
+ layoutTestController.notifyDone();
+ isSuccessfullyParsed();
+ }
}
}
-div1.addEventListener("touchstart", touchStartHandler, false);
-div1.addEventListener("touchmove", touchMoveHandler, false);
+div1.addEventListener("touchstart", declareTouchStart(), false);
+div1.addEventListener("touchmove", declareTouchMove(), false);
-div2.addEventListener("touchstart", touchStartHandler, false);
-div2.addEventListener("touchmove", touchMoveHandler, false);
+div2.addEventListener("touchstart", declareTouchStart(), false);
+div2.addEventListener("touchmove", declareTouchMove(), false);
description("Tests that the target of touches match the element where the event originated, not where the touch is currently occurring.");
diff --git a/LayoutTests/fast/events/touch/touch-target-expected.txt b/LayoutTests/fast/events/touch/touch-target-expected.txt
index 60a4c37..b1c865d 100644
--- a/LayoutTests/fast/events/touch/touch-target-expected.txt
+++ b/LayoutTests/fast/events/touch/touch-target-expected.txt
@@ -7,18 +7,39 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
PASS event.type is "touchstart"
PASS event.touches[0].target.id is "targetA"
PASS event.touches[1].target.id is "targetB"
+PASS event.targetTouches.length is 1
+PASS event.type is "touchstart"
+PASS event.touches[0].target.id is "targetA"
+PASS event.touches[1].target.id is "targetB"
+PASS event.targetTouches.length is 1
+PASS event.type is "touchmove"
+PASS event.touches[0].target.id is "targetA"
+PASS event.touches[1].target.id is "targetB"
+PASS event.targetTouches.length is 1
PASS event.type is "touchmove"
PASS event.touches[0].target.id is "targetA"
PASS event.touches[1].target.id is "targetB"
+PASS event.targetTouches.length is 1
PASS event.type is "touchmove"
PASS event.touches[0].target.id is "targetA"
PASS event.touches[1].target.id is "targetB"
+PASS event.targetTouches.length is 1
+PASS event.type is "touchmove"
+PASS event.touches[0].target.id is "targetA"
+PASS event.touches[1].target.id is "targetB"
+PASS event.targetTouches.length is 1
PASS event.type is "touchstart"
PASS event.touches[0].target.id is "targetB"
PASS event.touches[1].target.id is "targetA"
+PASS event.targetTouches.length is 1
+PASS event.type is "touchmove"
+PASS event.touches[0].target.id is "targetB"
+PASS event.touches[1].target.id is "targetA"
+PASS event.targetTouches.length is 1
PASS event.type is "touchmove"
PASS event.touches[0].target.id is "targetB"
PASS event.touches[1].target.id is "targetA"
+PASS event.targetTouches.length is 1
PASS successfullyParsed is true
TEST COMPLETE
diff --git a/LayoutTests/fast/events/touch/touch-target-limited-expected.txt b/LayoutTests/fast/events/touch/touch-target-limited-expected.txt
index 0c1efd0..f774434 100644
--- a/LayoutTests/fast/events/touch/touch-target-limited-expected.txt
+++ b/LayoutTests/fast/events/touch/touch-target-limited-expected.txt
@@ -7,18 +7,43 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
PASS event.type is "touchstart"
PASS event.touches[0].target.id is "targetA"
PASS event.touches[1].target.id is "targetB"
+PASS event.targetTouches.length is 1
+PASS event.type is "touchstart"
+PASS event.touches[0].target.id is "targetA"
+PASS event.touches[1].target.id is "targetB"
+PASS event.targetTouches.length is 1
+PASS event.type is "touchmove"
+PASS event.touches[0].target.id is "targetA"
+PASS event.touches[1].target.id is "targetB"
+PASS event.targetTouches.length is 1
PASS event.type is "touchmove"
PASS event.touches[0].target.id is "targetA"
PASS event.touches[1].target.id is "targetB"
+PASS event.targetTouches.length is 1
PASS event.type is "touchmove"
PASS event.touches[0].target.id is "targetA"
PASS event.touches[1].target.id is "targetB"
+PASS event.targetTouches.length is 1
+PASS event.type is "touchmove"
+PASS event.touches[0].target.id is "targetA"
+PASS event.touches[1].target.id is "targetB"
+PASS event.targetTouches.length is 1
+PASS event.type is "touchstart"
+PASS event.touches[0].target.id is "targetB"
+PASS event.touches[1].target.id is "targetA"
+PASS event.targetTouches.length is 1
PASS event.type is "touchstart"
PASS event.touches[0].target.id is "targetB"
PASS event.touches[1].target.id is "targetA"
+PASS event.targetTouches.length is 1
+PASS event.type is "touchmove"
+PASS event.touches[0].target.id is "targetB"
+PASS event.touches[1].target.id is "targetA"
+PASS event.targetTouches.length is 1
PASS event.type is "touchmove"
PASS event.touches[0].target.id is "targetB"
PASS event.touches[1].target.id is "targetA"
+PASS event.targetTouches.length is 1
PASS successfullyParsed is true
TEST COMPLETE
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 5af04ed..749c938 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,20 @@
+2010-12-23 Jonathan Dixon <joth at chromium.org>
+
+ Reviewed by Steve Block.
+
+ TouchEvents does not support multi-touch on a page with multiple touch targets
+ https://bugs.webkit.org/show_bug.cgi?id=51258
+
+ Test: fast/events/touch/multi-touch-grouped-targets.html
+
+ * page/EventHandler.cpp:
+ (WebCore::eventNameForTouchPointState):
+ (WebCore::EventHandler::handleTouchEvent):
+ Redesigned event handler to ensure all event targets involved in a given
+ multitouch event get the appropriate event(s) fired.
+
+ * platform/PlatformTouchPoint.h: Added end-stop marker for State enum.
+
2010-12-23 Philippe Normand <pnormand at igalia.com>
Reviewed by Xan Lopez.
diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp
index 9cc3b16..3c573e7 100644
--- a/WebCore/page/EventHandler.cpp
+++ b/WebCore/page/EventHandler.cpp
@@ -2830,33 +2830,53 @@ void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setL
#if ENABLE(TOUCH_EVENTS)
-static PassRefPtr<TouchList> assembleTargetTouches(Touch* touchTarget, TouchList* touches)
+static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
{
- RefPtr<TouchList> targetTouches = TouchList::create();
-
- for (unsigned i = 0; i < touches->length(); ++i) {
- if (touches->item(i)->target()->toNode()->isSameNode(touchTarget->target()->toNode()))
- targetTouches->append(touches->item(i));
+ switch (state) {
+ case PlatformTouchPoint::TouchReleased:
+ return eventNames().touchendEvent;
+ case PlatformTouchPoint::TouchCancelled:
+ return eventNames().touchcancelEvent;
+ case PlatformTouchPoint::TouchPressed:
+ return eventNames().touchstartEvent;
+ case PlatformTouchPoint::TouchMoved:
+ return eventNames().touchmoveEvent;
+ default:
+ ASSERT_NOT_REACHED();
+ return emptyAtom;
}
-
- return targetTouches.release();
}
bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
{
+ // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
+ // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
+ // for an overview of how these lists fit together.
+
+ // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
RefPtr<TouchList> touches = TouchList::create();
- RefPtr<TouchList> pressedTouches = TouchList::create();
- RefPtr<TouchList> releasedTouches = TouchList::create();
- RefPtr<TouchList> movedTouches = TouchList::create();
- RefPtr<TouchList> cancelTouches = TouchList::create();
+
+ // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
+ // 'targetTouches' list in the JS event.
+ typedef HashMap<EventTarget*, RefPtr<TouchList> > TargetTouchesMap;
+ TargetTouchesMap touchesByTarget;
+
+ // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
+ typedef HashSet<RefPtr<EventTarget> > EventTargetSet;
+ struct {
+ // The touches corresponding to the particular change state this struct instance represents.
+ RefPtr<TouchList> m_touches;
+ // Set of targets involved in m_touches.
+ EventTargetSet m_targets;
+ } changedTouches[PlatformTouchPoint::TouchStateEnd];
const Vector<PlatformTouchPoint>& points = event.touchPoints();
- AtomicString* eventName = 0;
UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
for (unsigned i = 0; i < points.size(); ++i) {
const PlatformTouchPoint& point = points[i];
+ PlatformTouchPoint::State pointState = point.state();
IntPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
HitTestRequest::HitTestRequestType hitType = HitTestRequest::Active | HitTestRequest::ReadOnly;
@@ -2865,7 +2885,7 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
// should affect the active state of the current node if necessary,
// HitTestRequest::Active signifies that the hit test is taking place
// with the mouse (or finger in this case) being pressed.
- switch (point.state()) {
+ switch (pointState) {
case PlatformTouchPoint::TouchPressed:
hitType = HitTestRequest::Active;
break;
@@ -2881,13 +2901,14 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
}
HitTestResult result = hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false, false, DontHitTestScrollbars, hitType);
- Node* target = result.innerNode();
+ Node* node = result.innerNode();
+ ASSERT(node);
// Touch events should not go to text nodes
- if (target && target->isTextNode())
- target = target->parentNode();
+ if (node->isTextNode())
+ node = node->parentNode();
- Document* doc = target->document();
+ Document* doc = node->document();
if (!doc)
continue;
if (!doc->hasListenerType(Document::TOUCH_LISTENER))
@@ -2904,10 +2925,10 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
// Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
unsigned touchPointTargetKey = point.id() + 1;
RefPtr<EventTarget> touchTarget;
- if (point.state() == PlatformTouchPoint::TouchPressed) {
- m_originatingTouchPointTargets.set(touchPointTargetKey, target);
- touchTarget = target;
- } else if (point.state() == PlatformTouchPoint::TouchReleased || point.state() == PlatformTouchPoint::TouchCancelled) {
+ if (pointState == PlatformTouchPoint::TouchPressed) {
+ m_originatingTouchPointTargets.set(touchPointTargetKey, node);
+ touchTarget = node;
+ } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
// The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel
// we also remove it from the map.
touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
@@ -2921,110 +2942,60 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
point.screenPos().x(), point.screenPos().y(),
adjustedPageX, adjustedPageY);
- // touches should contain information about every touch currently on the screen.
- if (point.state() != PlatformTouchPoint::TouchReleased)
+ // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below.
+ TargetTouchesMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
+ if (targetTouchesIterator == touchesByTarget.end())
+ targetTouchesIterator = touchesByTarget.set(touchTarget.get(), TouchList::create()).first;
+
+ // touches and targetTouches should only contain information about touches still on the screen, so if this point is
+ // released or cancelled it will only appear in the changedTouches list.
+ if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
touches->append(touch);
+ targetTouchesIterator->second->append(touch);
+ }
// Now build up the correct list for changedTouches.
// Note that any touches that are in the TouchStationary state (e.g. if
// the user had several points touched but did not move them all) should
- // only be present in the touches list. They may also be added to the
- // targetTouches list later, but should never be in the changedTouches
- // list so we do not handle them explicitly here.
+ // never be in the changedTouches list so we do not handle them explicitly here.
// See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion
// about the TouchStationary state.
- if (point.state() == PlatformTouchPoint::TouchReleased)
- releasedTouches->append(touch);
- else if (point.state() == PlatformTouchPoint::TouchCancelled)
- cancelTouches->append(touch);
- else if (point.state() == PlatformTouchPoint::TouchPressed)
- pressedTouches->append(touch);
- else if (point.state() == PlatformTouchPoint::TouchMoved)
- movedTouches->append(touch);
+ if (pointState != PlatformTouchPoint::TouchStationary) {
+ ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
+ if (!changedTouches[pointState].m_touches)
+ changedTouches[pointState].m_touches = TouchList::create();
+ changedTouches[pointState].m_touches->append(touch);
+ changedTouches[pointState].m_targets.add(touchTarget);
+ }
}
-
m_touchPressed = touches->length() > 0;
+ // Now iterate the changedTouches list and m_targets within it, sending events to the tagets as required.
bool defaultPrevented = false;
- Touch* changedTouch = 0;
- EventTarget* touchEventTarget = 0;
-
- if (cancelTouches->length() > 0) {
- // We dispatch the event to the target of the touch that caused this touch event to be generated, i.e.
- // we take it from the list that will be used as the changedTouches property of the event.
- // The choice to use the touch at index 0 guarantees that there is a target (as we checked the length
- // above). In the case that there are multiple touches in what becomes the changedTouches list, it is
- // difficult to say how we should prioritise touches and as such, item 0 is an arbitrary choice.
- changedTouch = cancelTouches->item(0);
- ASSERT(changedTouch);
- touchEventTarget = changedTouch->target();
- ASSERT(touchEventTarget);
-
- eventName = &eventNames().touchcancelEvent;
- RefPtr<TouchEvent> cancelEv =
- TouchEvent::create(TouchList::create().get(), TouchList::create().get(), cancelTouches.get(),
- *eventName, touchEventTarget->toNode()->document()->defaultView(),
- 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(),
- event.metaKey());
- ExceptionCode ec = 0;
- touchEventTarget->dispatchEvent(cancelEv.get(), ec);
- defaultPrevented |= cancelEv->defaultPrevented();
- }
-
- if (releasedTouches->length() > 0) {
- Touch* changedTouch = releasedTouches->item(0);
- ASSERT(changedTouch);
- touchEventTarget = changedTouch->target();
- ASSERT(touchEventTarget);
-
- RefPtr<TouchList> targetTouches = assembleTargetTouches(changedTouch, touches.get());
-
- eventName = &eventNames().touchendEvent;
- RefPtr<TouchEvent> endEv =
- TouchEvent::create(touches.get(), targetTouches.get(), releasedTouches.get(),
- *eventName, touchEventTarget->toNode()->document()->defaultView(),
- 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(),
- event.metaKey());
- ExceptionCode ec = 0;
- touchEventTarget->dispatchEvent(endEv.get(), ec);
- defaultPrevented |= endEv->defaultPrevented();
- }
- if (pressedTouches->length() > 0) {
- Touch* changedTouch = pressedTouches->item(0);
- ASSERT(changedTouch);
- touchEventTarget = changedTouch->target();
- ASSERT(touchEventTarget);
-
- RefPtr<TouchList> targetTouches = assembleTargetTouches(changedTouch, touches.get());
-
- eventName = &eventNames().touchstartEvent;
- RefPtr<TouchEvent> startEv =
- TouchEvent::create(touches.get(), targetTouches.get(), pressedTouches.get(),
- *eventName, touchEventTarget->toNode()->document()->defaultView(),
- 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(),
- event.metaKey());
- ExceptionCode ec = 0;
- touchEventTarget->dispatchEvent(startEv.get(), ec);
- defaultPrevented |= startEv->defaultPrevented();
- }
-
- if (movedTouches->length() > 0) {
- Touch* changedTouch = movedTouches->item(0);
- ASSERT(changedTouch);
- touchEventTarget = changedTouch->target();
- ASSERT(touchEventTarget);
-
- RefPtr<TouchList> targetTouches = assembleTargetTouches(changedTouch, touches.get());
-
- eventName = &eventNames().touchmoveEvent;
- RefPtr<TouchEvent> moveEv =
- TouchEvent::create(touches.get(), targetTouches.get(), movedTouches.get(),
- *eventName, touchEventTarget->toNode()->document()->defaultView(),
- 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(),
- event.metaKey());
- ExceptionCode ec = 0;
- touchEventTarget->dispatchEvent(moveEv.get(), ec);
- defaultPrevented |= moveEv->defaultPrevented();
+ RefPtr<TouchList> emptyList = TouchList::create();
+ for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
+ if (!changedTouches[state].m_touches)
+ continue;
+
+ // When sending a touch cancel event, use empty touches and targetTouches lists.
+ bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled);
+ RefPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches);
+ const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
+ const EventTargetSet& targetsForState = changedTouches[state].m_targets;
+
+ for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
+ EventTarget* touchEventTarget = it->get();
+ RefPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList : touchesByTarget.get(touchEventTarget));
+ ASSERT(targetTouches);
+
+ RefPtr<TouchEvent> touchEvent =
+ TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(),
+ stateName, touchEventTarget->toNode()->document()->defaultView(),
+ 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey());
+ ExceptionCode ec = 0;
+ touchEventTarget->dispatchEvent(touchEvent.get(), ec);
+ defaultPrevented |= touchEvent->defaultPrevented();
+ }
}
return defaultPrevented;
diff --git a/WebCore/platform/PlatformTouchPoint.h b/WebCore/platform/PlatformTouchPoint.h
index 82c8d78..5746b18 100644
--- a/WebCore/platform/PlatformTouchPoint.h
+++ b/WebCore/platform/PlatformTouchPoint.h
@@ -40,7 +40,8 @@ public:
TouchPressed,
TouchMoved,
TouchStationary,
- TouchCancelled
+ TouchCancelled,
+ TouchStateEnd // Placeholder: must remain the last item.
};
#if PLATFORM(QT)
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list