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.
5 #include "content/common/input/touch_event_stream_validator.h"
7 #include "base/logging.h"
8 #include "base/strings/stringprintf.h"
9 #include "content/common/input/web_input_event_traits.h"
10 #include "content/common/input/web_touch_event_traits.h"
12 using base::StringPrintf
;
13 using blink::WebInputEvent
;
14 using blink::WebTouchEvent
;
15 using blink::WebTouchPoint
;
20 const WebTouchPoint
* FindTouchPoint(const WebTouchEvent
& event
, int id
) {
21 for (unsigned i
= 0; i
< event
.touchesLength
; ++i
) {
22 if (event
.touches
[i
].id
== id
)
23 return &event
.touches
[i
];
28 std::string
TouchPointIdsToString(const WebTouchEvent
& event
) {
30 for (unsigned i
= 0; i
< event
.touchesLength
; ++i
) {
33 ss
<< event
.touches
[i
].id
;
40 TouchEventStreamValidator::TouchEventStreamValidator() {
43 TouchEventStreamValidator::~TouchEventStreamValidator() {
46 bool TouchEventStreamValidator::Validate(const WebTouchEvent
& event
,
47 std::string
* error_msg
) {
51 WebTouchEvent previous_event
= previous_event_
;
52 previous_event_
= event
;
54 if (!event
.touchesLength
) {
55 error_msg
->append("Touch event is empty.\n");
59 if (!WebInputEvent::isTouchEventType(event
.type
)) {
60 error_msg
->append(StringPrintf("Touch event has invalid type: %s\n",
61 WebInputEventTraits::GetName(event
.type
)));
64 // Allow "hard" restarting of touch stream validation. This is necessary
65 // in cases where touch event forwarding ceases in response to the event ack
66 // or removal of touch handlers.
67 if (WebTouchEventTraits::IsTouchSequenceStart(event
))
68 previous_event
= WebTouchEvent();
70 // Unreleased points from the previous event should exist in the latest event.
71 for (unsigned i
= 0; i
< previous_event
.touchesLength
; ++i
) {
72 const WebTouchPoint
& previous_point
= previous_event
.touches
[i
];
73 if (previous_point
.state
== WebTouchPoint::StateCancelled
||
74 previous_point
.state
== WebTouchPoint::StateReleased
)
77 const WebTouchPoint
* point
= FindTouchPoint(event
, previous_point
.id
);
79 error_msg
->append(StringPrintf(
80 "Previously active touch point (id=%d) not in new event (ids=%s).\n",
81 previous_point
.id
, TouchPointIdsToString(event
).c_str()));
85 bool found_valid_state_for_type
= false;
86 for (unsigned i
= 0; i
< event
.touchesLength
; ++i
) {
87 const WebTouchPoint
& point
= event
.touches
[i
];
88 const WebTouchPoint
* previous_point
=
89 FindTouchPoint(previous_event
, point
.id
);
91 // The point should exist in the previous event if it is not a new point.
92 if (!previous_point
) {
93 if (point
.state
!= WebTouchPoint::StatePressed
)
94 error_msg
->append(StringPrintf(
95 "Active touch point (id=%d) not in previous event (ids=%s).\n",
96 point
.id
, TouchPointIdsToString(previous_event
).c_str()));
98 if (point
.state
== WebTouchPoint::StatePressed
&&
99 previous_point
->state
!= WebTouchPoint::StateCancelled
&&
100 previous_point
->state
!= WebTouchPoint::StateReleased
) {
101 error_msg
->append(StringPrintf(
102 "Pressed touch point (id=%d) already exists in previous event "
104 point
.id
, TouchPointIdsToString(previous_event
).c_str()));
108 switch (point
.state
) {
109 case WebTouchPoint::StateUndefined
:
111 StringPrintf("Undefined touch point state (id=%d).\n", point
.id
));
114 case WebTouchPoint::StateReleased
:
115 if (event
.type
!= WebInputEvent::TouchEnd
) {
116 error_msg
->append(StringPrintf(
117 "Released touch point (id=%d) outside touchend.\n", point
.id
));
119 found_valid_state_for_type
= true;
123 case WebTouchPoint::StatePressed
:
124 if (event
.type
!= WebInputEvent::TouchStart
) {
125 error_msg
->append(StringPrintf(
126 "Pressed touch point (id=%d) outside touchstart.\n", point
.id
));
128 found_valid_state_for_type
= true;
132 case WebTouchPoint::StateMoved
:
133 if (event
.type
!= WebInputEvent::TouchMove
) {
134 error_msg
->append(StringPrintf(
135 "Moved touch point (id=%d) outside touchmove.\n", point
.id
));
137 found_valid_state_for_type
= true;
141 case WebTouchPoint::StateStationary
:
144 case WebTouchPoint::StateCancelled
:
145 if (event
.type
!= WebInputEvent::TouchCancel
) {
146 error_msg
->append(StringPrintf(
147 "Cancelled touch point (id=%d) outside touchcancel.\n",
150 found_valid_state_for_type
= true;
156 if (!found_valid_state_for_type
) {
158 StringPrintf("No valid touch point corresponding to event type: %s\n",
159 WebInputEventTraits::GetName(event
.type
)));
162 return error_msg
->empty();
165 } // namespace content