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// MSVC++ requires this to be set before any other includes to get M_PI.
6#define _USE_MATH_DEFINES
7
8#include "content/browser/renderer_host/input/motion_event_web.h"
9
10#include <cmath>
11
12#include "base/logging.h"
13#include "content/browser/renderer_host/input/web_input_event_util.h"
14#include "content/common/input/web_touch_event_traits.h"
15
16using blink::WebInputEvent;
17using blink::WebTouchEvent;
18using blink::WebTouchPoint;
19
20namespace content {
21namespace {
22
23ui::MotionEvent::Action GetActionFrom(const WebTouchEvent& event) {
24  DCHECK(event.touchesLength);
25  switch (event.type) {
26    case WebInputEvent::TouchStart:
27      if (WebTouchEventTraits::AllTouchPointsHaveState(
28              event, WebTouchPoint::StatePressed))
29        return ui::MotionEvent::ACTION_DOWN;
30      else
31        return ui::MotionEvent::ACTION_POINTER_DOWN;
32    case WebInputEvent::TouchEnd:
33      if (WebTouchEventTraits::AllTouchPointsHaveState(
34              event, WebTouchPoint::StateReleased))
35        return ui::MotionEvent::ACTION_UP;
36      else
37        return ui::MotionEvent::ACTION_POINTER_UP;
38    case WebInputEvent::TouchCancel:
39      DCHECK(WebTouchEventTraits::AllTouchPointsHaveState(
40          event, WebTouchPoint::StateCancelled));
41      return ui::MotionEvent::ACTION_CANCEL;
42    case WebInputEvent::TouchMove:
43      return ui::MotionEvent::ACTION_MOVE;
44    default:
45      break;
46  };
47  NOTREACHED()
48      << "Unable to derive a valid MotionEvent::Action from the WebTouchEvent.";
49  return ui::MotionEvent::ACTION_CANCEL;
50}
51
52int GetActionIndexFrom(const WebTouchEvent& event) {
53  for (size_t i = 0; i < event.touchesLength; ++i) {
54    if (event.touches[i].state != WebTouchPoint::StateUndefined &&
55        event.touches[i].state != WebTouchPoint::StateStationary)
56      return i;
57  }
58  return -1;
59}
60
61}  // namespace
62
63MotionEventWeb::MotionEventWeb(const WebTouchEvent& event)
64    : event_(event),
65      cached_action_(GetActionFrom(event)),
66      cached_action_index_(GetActionIndexFrom(event)) {
67  DCHECK_GT(GetPointerCount(), 0U);
68}
69
70MotionEventWeb::~MotionEventWeb() {}
71
72int MotionEventWeb::GetId() const {
73  return 0;
74}
75
76MotionEventWeb::Action MotionEventWeb::GetAction() const {
77  return cached_action_;
78}
79
80int MotionEventWeb::GetActionIndex() const { return cached_action_index_; }
81
82size_t MotionEventWeb::GetPointerCount() const { return event_.touchesLength; }
83
84int MotionEventWeb::GetPointerId(size_t pointer_index) const {
85  DCHECK_LT(pointer_index, GetPointerCount());
86  return event_.touches[pointer_index].id;
87}
88
89float MotionEventWeb::GetX(size_t pointer_index) const {
90  DCHECK_LT(pointer_index, GetPointerCount());
91  return event_.touches[pointer_index].position.x;
92}
93
94float MotionEventWeb::GetY(size_t pointer_index) const {
95  DCHECK_LT(pointer_index, GetPointerCount());
96  return event_.touches[pointer_index].position.y;
97}
98
99float MotionEventWeb::GetRawX(size_t pointer_index) const {
100  DCHECK_LT(pointer_index, GetPointerCount());
101  return event_.touches[pointer_index].screenPosition.x;
102}
103
104float MotionEventWeb::GetRawY(size_t pointer_index) const {
105  DCHECK_LT(pointer_index, GetPointerCount());
106  return event_.touches[pointer_index].screenPosition.y;
107}
108
109float MotionEventWeb::GetTouchMajor(size_t pointer_index) const {
110  DCHECK_LT(pointer_index, GetPointerCount());
111  return 2.f * std::max(event_.touches[pointer_index].radiusX,
112                        event_.touches[pointer_index].radiusY);
113}
114
115float MotionEventWeb::GetTouchMinor(size_t pointer_index) const {
116  DCHECK_LT(pointer_index, GetPointerCount());
117  return 2.f * std::min(event_.touches[pointer_index].radiusX,
118                        event_.touches[pointer_index].radiusY);
119}
120
121float MotionEventWeb::GetOrientation(size_t pointer_index) const {
122  DCHECK_LT(pointer_index, GetPointerCount());
123
124  float rotation_angle_rad = event_.touches[pointer_index].rotationAngle
125      * M_PI / 180.f;
126  DCHECK(0 <= rotation_angle_rad && rotation_angle_rad <= M_PI_2)
127      << "Unexpected touch rotation angle";
128
129  if (event_.touches[pointer_index].radiusX
130      > event_.touches[pointer_index].radiusY) {
131    // The case radiusX == radiusY is omitted from here on purpose: for circles,
132    // we want to pass the angle (which could be any value in such cases but
133    // always seem to be set to zero) unchanged.
134    rotation_angle_rad -= (float) M_PI_2;
135  }
136
137  return rotation_angle_rad;
138}
139
140float MotionEventWeb::GetPressure(size_t pointer_index) const {
141  return 0.f;
142}
143
144base::TimeTicks MotionEventWeb::GetEventTime() const {
145  return base::TimeTicks() +
146         base::TimeDelta::FromMicroseconds(event_.timeStampSeconds *
147                                           base::Time::kMicrosecondsPerSecond);
148}
149
150ui::MotionEvent::ToolType MotionEventWeb::GetToolType(
151    size_t pointer_index) const {
152  // TODO(jdduke): Plumb tool type from the platform event, crbug.com/404128.
153  DCHECK_LT(pointer_index, GetPointerCount());
154  return TOOL_TYPE_UNKNOWN;
155}
156
157int MotionEventWeb::GetButtonState() const {
158  NOTIMPLEMENTED();
159  return 0;
160}
161
162int MotionEventWeb::GetFlags() const {
163  return WebEventModifiersToEventFlags(event_.modifiers);
164}
165
166scoped_ptr<ui::MotionEvent> MotionEventWeb::Clone() const {
167  return scoped_ptr<MotionEvent>(new MotionEventWeb(event_));
168}
169
170scoped_ptr<ui::MotionEvent> MotionEventWeb::Cancel() const {
171  WebTouchEvent cancel_event(event_);
172  WebTouchEventTraits::ResetTypeAndTouchStates(
173      blink::WebInputEvent::TouchCancel,
174      // TODO(rbyers): Shouldn't we use a fresh timestamp?
175      event_.timeStampSeconds,
176      &cancel_event);
177  return scoped_ptr<MotionEvent>(new MotionEventWeb(cancel_event));
178}
179
180}  // namespace content
181