| Index: LayoutTests/fast/events/touch/multi-touch-partial-sequence.html | 
| diff --git a/LayoutTests/fast/events/touch/multi-touch-partial-sequence.html b/LayoutTests/fast/events/touch/multi-touch-partial-sequence.html | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..b3e2f66206c1ee2fa4c32f52ba15cb6e267f59b4 | 
| --- /dev/null | 
| +++ b/LayoutTests/fast/events/touch/multi-touch-partial-sequence.html | 
| @@ -0,0 +1,120 @@ | 
| +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> | 
| +<html> | 
| +<head> | 
| +<script src="../../../resources/js-test.js"></script> | 
| +</head> | 
| +<body> | 
| +<p id="description"></p> | 
| +<div id="target" style="padding: 10px; background-color: blue;"></div> | 
| +<div id="console"></div> | 
| +<script> | 
| +description("Tests that events are received properly even when we never saw the touchstart for the first finger (eg. was skipped by cc touch hit testing) - crbug.com/363321"); | 
| + | 
| +var event; | 
| +var expectingStart = false; | 
| +var expectingEnd = false; | 
| + | 
| +var target = document.getElementById('target'); | 
| +var rect = target.getBoundingClientRect(); | 
| +var targetX = rect.left + rect.width / 2; | 
| +var targetY = rect.top + rect.height / 2; | 
| + | 
| +window.addEventListener('touchstart', function(e) { | 
| +    if (!expectingStart) { | 
| +      testFailed('Got unexpected touchstart event'); | 
| +      return; | 
| +    } | 
| +    expectingStart = false; | 
| +    event = e; | 
| + | 
| +    shouldBe('event.target', 'target'); | 
| + | 
| +    // Touch ID 0 is the one we never got a touchstart for, so it should | 
| +    // be targetted at the document. | 
| +    shouldBe('event.touches.length', '2'); | 
| +    shouldBe('event.touches[0].identifier', '0'); | 
| +    shouldBe('event.touches[0].pageX', '12'); | 
| +    shouldBe('event.touches[0].pageY', '0'); | 
| +    shouldBe('event.touches[0].target', 'document'); | 
| + | 
| +    // Touch ID 1 should be the new touch. | 
| +    shouldBe('event.touches[1].identifier', '1'); | 
| +    shouldBe('event.touches[1].pageX', 'targetX'); | 
| +    shouldBe('event.touches[1].pageY', 'targetY'); | 
| +    shouldBe('event.touches[1].target', 'target'); | 
| + | 
| +    shouldBe('event.changedTouches.length', '1'); | 
| +    shouldBe('event.changedTouches[0].identifier', '1'); | 
| + | 
| +    shouldBe('event.targetTouches.length', '1'); | 
| +    shouldBe('event.targetTouches[0].identifier', '1'); | 
| +}); | 
| + | 
| +window.addEventListener('touchmove', function(e) { | 
| +    testFailed('Got unexpected touchmove event'); | 
| +}); | 
| + | 
| +window.addEventListener('touchend', function(e) { | 
| +    if (!expectingEnd) { | 
| +      testFailed('Got unexpected touchstart event'); | 
| +      return; | 
| +    } | 
| +    expectingEnd = false; | 
| +    event = e; | 
| + | 
| +    shouldBe('event.target', 'target'); | 
| + | 
| +    shouldBe('event.touches.length', '0'); | 
| + | 
| +    shouldBe('event.changedTouches.length', '1'); | 
| +    shouldBe('event.changedTouches[0].identifier', '1'); | 
| +    shouldBe('event.changedTouches[0].pageX', 'targetX'); | 
| +    shouldBe('event.changedTouches[0].pageY', 'targetY'); | 
| +    shouldBe('event.changedTouches[0].target', 'target'); | 
| + | 
| +    shouldBe('event.targetTouches.length', '0'); | 
| +}); | 
| + | 
| +if (document.elementFromPoint(targetX, targetY) != target) { | 
| +    testFailed('Failed to hit expected target at ' + targetX + ',' + targetY); | 
| +} else if (!window.eventSender) { | 
| +    testFailed('This test requires eventSender'); | 
| +} else { | 
| +    eventSender.clearTouchPoints(); | 
| + | 
| +    // First touch point is outside our target, but we never actually | 
| +    // get a touchstart event sent to the renderer for it. | 
| +    eventSender.addTouchPoint(10, 0); | 
| +    eventSender.updateTouchPoint(0, 12, 0); | 
| + | 
| +    // Second point is on our target and we expect touchstart | 
| +    eventSender.addTouchPoint(targetX, targetY); | 
| +    debug('Sending touchstart event.'); | 
| +    expectingStart = true; | 
| +    eventSender.touchStart(); | 
| +    if (expectingStart) | 
| +      testFailed("Didn't receive expected touchstart event"); | 
| +    debug(''); | 
| + | 
| +    // Make sure we don't get any events (or crash) if we receive a move or | 
| +    // end for just the first touch point. | 
| +    debug('Sending touchmove and touchend for unrelated touch point.'); | 
| +    eventSender.updateTouchPoint(0, 13, 0); | 
| +    eventSender.touchMove(); | 
| +    eventSender.releaseTouchPoint(0); | 
| +    eventSender.touchEnd(); | 
| +    debug(''); | 
| + | 
| +    // If the 2nd touch point lifts, we get an event showing just that change. | 
| +    debug('Sending touchend.'); | 
| +    eventSender.releaseTouchPoint(0); | 
| +    expectingEnd = true; | 
| +    eventSender.touchEnd(); | 
| +    if (expectingEnd) | 
| +      testFailed("Didn't receive expected touchend event"); | 
| +    debug(''); | 
| +} | 
| +</script> | 
| +</body> | 
| +</html> | 
| + | 
|  |