[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