1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/input/touch_event_stream_validator.h"
#include "base/check.h"
#include "base/strings/stringprintf.h"
#include "third_party/blink/public/common/input/web_touch_event.h"
#include "ui/events/blink/web_input_event_traits.h"
using base::StringPrintf;
using blink::WebInputEvent;
using blink::WebTouchEvent;
using blink::WebTouchPoint;
namespace input {
namespace {
const WebTouchPoint* FindTouchPoint(const WebTouchEvent& event, int id) {
for (unsigned i = 0; i < event.touches_length; ++i) {
if (event.touches[i].id == id)
return &event.touches[i];
}
return nullptr;
}
std::string TouchPointIdsToString(const WebTouchEvent& event) {
std::stringstream ss;
for (unsigned i = 0; i < event.touches_length; ++i) {
if (i)
ss << ",";
ss << event.touches[i].id;
}
return ss.str();
}
} // namespace
TouchEventStreamValidator::TouchEventStreamValidator() {
}
TouchEventStreamValidator::~TouchEventStreamValidator() {
}
bool TouchEventStreamValidator::Validate(const WebTouchEvent& event,
std::string* error_msg) {
DCHECK(error_msg);
error_msg->clear();
// TouchScrollStarted is not part of a regular touch event stream.
if (event.GetType() == WebInputEvent::Type::kTouchScrollStarted)
return true;
WebTouchEvent previous_event = previous_event_;
previous_event_ = event;
if (!event.touches_length) {
error_msg->append("Touch event is empty.\n");
return false;
}
if (!WebInputEvent::IsTouchEventType(event.GetType())) {
error_msg->append(StringPrintf("Touch event has invalid type: %s\n",
WebInputEvent::GetName(event.GetType())));
}
// Allow "hard" restarting of touch stream validation. This is necessary
// in cases where touch event forwarding ceases in response to the event ack
// or removal of touch handlers.
if (event.IsTouchSequenceStart()) {
previous_event = WebTouchEvent();
}
// Unreleased points from the previous event should exist in the latest event.
for (unsigned i = 0; i < previous_event.touches_length; ++i) {
const WebTouchPoint& previous_point = previous_event.touches[i];
if (previous_point.state == WebTouchPoint::State::kStateCancelled ||
previous_point.state == WebTouchPoint::State::kStateReleased)
continue;
const WebTouchPoint* point = FindTouchPoint(event, previous_point.id);
if (!point) {
error_msg->append(StringPrintf(
"Previously active touch point (id=%d) not in new event (ids=%s).\n",
previous_point.id, TouchPointIdsToString(event).c_str()));
}
}
bool found_valid_state_for_type = false;
for (unsigned i = 0; i < event.touches_length; ++i) {
const WebTouchPoint& point = event.touches[i];
const WebTouchPoint* previous_point =
FindTouchPoint(previous_event, point.id);
// The point should exist in the previous event if it is not a new point.
if (!previous_point) {
if (point.state != WebTouchPoint::State::kStatePressed)
error_msg->append(StringPrintf(
"Active touch point (id=%d) not in previous event (ids=%s).\n",
point.id, TouchPointIdsToString(previous_event).c_str()));
} else {
if (point.state == WebTouchPoint::State::kStatePressed &&
previous_point->state != WebTouchPoint::State::kStateCancelled &&
previous_point->state != WebTouchPoint::State::kStateReleased) {
error_msg->append(StringPrintf(
"Pressed touch point (id=%d) already exists in previous event "
"(ids=%s).\n",
point.id, TouchPointIdsToString(previous_event).c_str()));
}
}
switch (point.state) {
case WebTouchPoint::State::kStateUndefined:
error_msg->append(
StringPrintf("Undefined touch point state (id=%d).\n", point.id));
break;
case WebTouchPoint::State::kStateReleased:
if (event.GetType() != WebInputEvent::Type::kTouchEnd) {
error_msg->append(StringPrintf(
"Released touch point (id=%d) outside touchend.\n", point.id));
} else {
found_valid_state_for_type = true;
}
break;
case WebTouchPoint::State::kStatePressed:
if (event.GetType() != WebInputEvent::Type::kTouchStart) {
error_msg->append(StringPrintf(
"Pressed touch point (id=%d) outside touchstart.\n", point.id));
} else {
found_valid_state_for_type = true;
}
break;
case WebTouchPoint::State::kStateMoved:
if (event.GetType() != WebInputEvent::Type::kTouchMove) {
error_msg->append(StringPrintf(
"Moved touch point (id=%d) outside touchmove.\n", point.id));
} else {
found_valid_state_for_type = true;
}
break;
case WebTouchPoint::State::kStateStationary:
break;
case WebTouchPoint::State::kStateCancelled:
if (event.GetType() != WebInputEvent::Type::kTouchCancel) {
error_msg->append(StringPrintf(
"Cancelled touch point (id=%d) outside touchcancel.\n",
point.id));
} else {
found_valid_state_for_type = true;
}
break;
}
}
if (!found_valid_state_for_type) {
error_msg->append(
StringPrintf("No valid touch point corresponding to event type: %s\n",
WebInputEvent::GetName(event.GetType())));
}
return error_msg->empty();
}
} // namespace input
|