1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/common/input/touch_event_stream_validator.h" 6 7#include "base/logging.h" 8#include "content/common/input/web_touch_event_traits.h" 9 10using blink::WebInputEvent; 11using blink::WebTouchEvent; 12using blink::WebTouchPoint; 13 14namespace content { 15namespace { 16 17const WebTouchPoint* FindTouchPoint(const WebTouchEvent& event, int id) { 18 for (unsigned i = 0; i < event.touchesLength; ++i) { 19 if (event.touches[i].id == id) 20 return &event.touches[i]; 21 } 22 return NULL; 23} 24 25} // namespace 26 27TouchEventStreamValidator::TouchEventStreamValidator() { 28} 29 30TouchEventStreamValidator::~TouchEventStreamValidator() { 31} 32 33bool TouchEventStreamValidator::Validate(const WebTouchEvent& event, 34 std::string* error_msg) { 35 DCHECK(error_msg); 36 error_msg->clear(); 37 38 WebTouchEvent previous_event = previous_event_; 39 previous_event_ = event; 40 41 // Allow "hard" restarting of touch stream validation. This is necessary 42 // in cases where touch event forwarding ceases in response to the event ack 43 // or removal of touch handlers. 44 if (WebTouchEventTraits::IsTouchSequenceStart(event)) 45 previous_event = WebTouchEvent(); 46 47 // Unreleased points from the previous event should exist in the latest event. 48 for (unsigned i = 0; i < previous_event.touchesLength; ++i) { 49 const WebTouchPoint& previous_point = previous_event.touches[i]; 50 if (previous_point.state == WebTouchPoint::StateCancelled || 51 previous_point.state == WebTouchPoint::StateReleased) 52 continue; 53 54 const WebTouchPoint* point = FindTouchPoint(event, previous_point.id); 55 if (!point) 56 error_msg->append("Previously active touch point not in new event.\n"); 57 } 58 59 for (unsigned i = 0; i < event.touchesLength; ++i) { 60 const WebTouchPoint& point = event.touches[i]; 61 const WebTouchPoint* previous_point = 62 FindTouchPoint(previous_event, point.id); 63 64 // The point should exist in the previous event if it is not a new point. 65 if (!previous_point) { 66 if (point.state != WebTouchPoint::StatePressed) 67 error_msg->append("Active touch point not found in previous event.\n"); 68 } else { 69 if (point.state == WebTouchPoint::StatePressed && 70 previous_point->state != WebTouchPoint::StateCancelled && 71 previous_point->state != WebTouchPoint::StateReleased) { 72 error_msg->append("Pressed touch point id already exists.\n"); 73 } 74 } 75 76 switch (point.state) { 77 case WebTouchPoint::StateUndefined: 78 error_msg->append("Undefined WebTouchPoint state.\n"); 79 break; 80 81 case WebTouchPoint::StateReleased: 82 if (event.type != WebInputEvent::TouchEnd) 83 error_msg->append("Released touch point outside touchend.\n"); 84 break; 85 86 case WebTouchPoint::StatePressed: 87 if (event.type != WebInputEvent::TouchStart) 88 error_msg->append("Pressed touch point outside touchstart.\n"); 89 break; 90 91 case WebTouchPoint::StateMoved: 92 if (event.type != WebInputEvent::TouchMove) 93 error_msg->append("Moved touch point outside touchmove.\n"); 94 break; 95 96 case WebTouchPoint::StateStationary: 97 break; 98 99 case WebTouchPoint::StateCancelled: 100 if (event.type != WebInputEvent::TouchCancel) 101 error_msg->append("Cancelled touch point outside touchcancel.\n"); 102 break; 103 } 104 } 105 return error_msg->empty(); 106} 107 108} // namespace content 109