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 if (!event.touchesLength) { 42 error_msg->append("Touch event is empty.\n"); 43 return false; 44 } 45 46 if (!WebInputEvent::isTouchEventType(event.type)) 47 error_msg->append("Touch event has invalid type.\n"); 48 49 // Allow "hard" restarting of touch stream validation. This is necessary 50 // in cases where touch event forwarding ceases in response to the event ack 51 // or removal of touch handlers. 52 if (WebTouchEventTraits::IsTouchSequenceStart(event)) 53 previous_event = WebTouchEvent(); 54 55 // Unreleased points from the previous event should exist in the latest event. 56 for (unsigned i = 0; i < previous_event.touchesLength; ++i) { 57 const WebTouchPoint& previous_point = previous_event.touches[i]; 58 if (previous_point.state == WebTouchPoint::StateCancelled || 59 previous_point.state == WebTouchPoint::StateReleased) 60 continue; 61 62 const WebTouchPoint* point = FindTouchPoint(event, previous_point.id); 63 if (!point) 64 error_msg->append("Previously active touch point not in new event.\n"); 65 } 66 67 bool found_valid_state_for_type = false; 68 for (unsigned i = 0; i < event.touchesLength; ++i) { 69 const WebTouchPoint& point = event.touches[i]; 70 const WebTouchPoint* previous_point = 71 FindTouchPoint(previous_event, point.id); 72 73 // The point should exist in the previous event if it is not a new point. 74 if (!previous_point) { 75 if (point.state != WebTouchPoint::StatePressed) 76 error_msg->append("Active touch point not found in previous event.\n"); 77 } else { 78 if (point.state == WebTouchPoint::StatePressed && 79 previous_point->state != WebTouchPoint::StateCancelled && 80 previous_point->state != WebTouchPoint::StateReleased) { 81 error_msg->append("Pressed touch point id already exists.\n"); 82 } 83 } 84 85 switch (point.state) { 86 case WebTouchPoint::StateUndefined: 87 error_msg->append("Undefined WebTouchPoint state.\n"); 88 break; 89 90 case WebTouchPoint::StateReleased: 91 if (event.type != WebInputEvent::TouchEnd) 92 error_msg->append("Released touch point outside touchend.\n"); 93 else 94 found_valid_state_for_type = true; 95 break; 96 97 case WebTouchPoint::StatePressed: 98 if (event.type != WebInputEvent::TouchStart) 99 error_msg->append("Pressed touch point outside touchstart.\n"); 100 else 101 found_valid_state_for_type = true; 102 break; 103 104 case WebTouchPoint::StateMoved: 105 if (event.type != WebInputEvent::TouchMove) 106 error_msg->append("Moved touch point outside touchmove.\n"); 107 else 108 found_valid_state_for_type = true; 109 break; 110 111 case WebTouchPoint::StateStationary: 112 break; 113 114 case WebTouchPoint::StateCancelled: 115 if (event.type != WebInputEvent::TouchCancel) 116 error_msg->append("Cancelled touch point outside touchcancel.\n"); 117 else 118 found_valid_state_for_type = true; 119 break; 120 } 121 } 122 123 if (!found_valid_state_for_type) 124 error_msg->append("No valid touch point corresponding to event type."); 125 126 return error_msg->empty(); 127} 128 129} // namespace content 130