File: touch_event_stream_validator.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (170 lines) | stat: -rw-r--r-- 5,685 bytes parent folder | download | duplicates (9)
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