1 // Copyright 2013 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/web_input_event_traits.h" 6 7 #include "base/logging.h" 8 9 using blink::WebGestureEvent; 10 using blink::WebInputEvent; 11 using blink::WebKeyboardEvent; 12 using blink::WebMouseEvent; 13 using blink::WebMouseWheelEvent; 14 using blink::WebTouchEvent; 15 16 namespace content { 17 namespace { 18 19 bool CanCoalesce(const WebKeyboardEvent& event_to_coalesce, 20 const WebKeyboardEvent& event) { 21 return false; 22 } 23 24 void Coalesce(const WebKeyboardEvent& event_to_coalesce, 25 WebKeyboardEvent* event) { 26 DCHECK(CanCoalesce(event_to_coalesce, *event)); 27 } 28 29 bool CanCoalesce(const WebMouseEvent& event_to_coalesce, 30 const WebMouseEvent& event) { 31 return event.type == event_to_coalesce.type && 32 event.type == WebInputEvent::MouseMove; 33 } 34 35 void Coalesce(const WebMouseEvent& event_to_coalesce, WebMouseEvent* event) { 36 DCHECK(CanCoalesce(event_to_coalesce, *event)); 37 // Accumulate movement deltas. 38 int x = event->movementX; 39 int y = event->movementY; 40 *event = event_to_coalesce; 41 event->movementX += x; 42 event->movementY += y; 43 } 44 45 bool CanCoalesce(const WebMouseWheelEvent& event_to_coalesce, 46 const WebMouseWheelEvent& event) { 47 return event.modifiers == event_to_coalesce.modifiers && 48 event.scrollByPage == event_to_coalesce.scrollByPage && 49 event.phase == event_to_coalesce.phase && 50 event.momentumPhase == event_to_coalesce.momentumPhase && 51 event.hasPreciseScrollingDeltas == 52 event_to_coalesce.hasPreciseScrollingDeltas; 53 } 54 55 float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) { 56 return accelerated_delta * acceleration_ratio; 57 } 58 59 float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) { 60 if (unaccelerated_delta == 0.f || accelerated_delta == 0.f) 61 return 1.f; 62 return unaccelerated_delta / accelerated_delta; 63 } 64 65 void Coalesce(const WebMouseWheelEvent& event_to_coalesce, 66 WebMouseWheelEvent* event) { 67 DCHECK(CanCoalesce(event_to_coalesce, *event)); 68 float unaccelerated_x = 69 GetUnacceleratedDelta(event->deltaX, 70 event->accelerationRatioX) + 71 GetUnacceleratedDelta(event_to_coalesce.deltaX, 72 event_to_coalesce.accelerationRatioX); 73 float unaccelerated_y = 74 GetUnacceleratedDelta(event->deltaY, 75 event->accelerationRatioY) + 76 GetUnacceleratedDelta(event_to_coalesce.deltaY, 77 event_to_coalesce.accelerationRatioY); 78 event->deltaX += event_to_coalesce.deltaX; 79 event->deltaY += event_to_coalesce.deltaY; 80 event->wheelTicksX += event_to_coalesce.wheelTicksX; 81 event->wheelTicksY += event_to_coalesce.wheelTicksY; 82 event->accelerationRatioX = 83 GetAccelerationRatio(event->deltaX, unaccelerated_x); 84 event->accelerationRatioY = 85 GetAccelerationRatio(event->deltaY, unaccelerated_y); 86 DCHECK_GE(event_to_coalesce.timeStampSeconds, event->timeStampSeconds); 87 event->timeStampSeconds = event_to_coalesce.timeStampSeconds; 88 } 89 90 bool CanCoalesce(const WebTouchEvent& event_to_coalesce, 91 const WebTouchEvent& event) { 92 return event.type == event_to_coalesce.type && 93 event.type == WebInputEvent::TouchMove && 94 event.modifiers == event_to_coalesce.modifiers && 95 event.touchesLength == event_to_coalesce.touchesLength; 96 } 97 98 void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) { 99 DCHECK(CanCoalesce(event_to_coalesce, *event)); 100 // The WebTouchPoints include absolute position information. So it is 101 // sufficient to simply replace the previous event with the new event-> 102 // However, it is necessary to make sure that all the points have the 103 // correct state, i.e. the touch-points that moved in the last event, but 104 // didn't change in the current event, will have Stationary state. It is 105 // necessary to change them back to Moved state. 106 WebTouchEvent old_event = *event; 107 *event = event_to_coalesce; 108 for (unsigned i = 0; i < event->touchesLength; ++i) { 109 if (old_event.touches[i].state == blink::WebTouchPoint::StateMoved) 110 event->touches[i].state = blink::WebTouchPoint::StateMoved; 111 } 112 } 113 114 bool CanCoalesce(const WebGestureEvent& event_to_coalesce, 115 const WebGestureEvent& event) { 116 return event.type == event_to_coalesce.type && 117 event.type == WebInputEvent::GestureScrollUpdate && 118 event.modifiers == event_to_coalesce.modifiers; 119 } 120 121 void Coalesce(const WebGestureEvent& event_to_coalesce, 122 WebGestureEvent* event) { 123 DCHECK(CanCoalesce(event_to_coalesce, *event)); 124 event->data.scrollUpdate.deltaX += event_to_coalesce.data.scrollUpdate.deltaX; 125 event->data.scrollUpdate.deltaY += event_to_coalesce.data.scrollUpdate.deltaY; 126 } 127 128 struct WebInputEventSize { 129 template <class EventType> 130 bool Execute(WebInputEvent::Type /* type */, size_t* type_size) const { 131 *type_size = sizeof(EventType); 132 return true; 133 } 134 }; 135 136 struct WebInputEventClone { 137 template <class EventType> 138 bool Execute(const WebInputEvent& event, 139 ScopedWebInputEvent* scoped_event) const { 140 DCHECK_EQ(sizeof(EventType), event.size); 141 *scoped_event = ScopedWebInputEvent( 142 new EventType(static_cast<const EventType&>(event))); 143 return true; 144 } 145 }; 146 147 struct WebInputEventDelete { 148 template <class EventType> 149 bool Execute(WebInputEvent* event, bool* /* dummy_var */) const { 150 if (!event) 151 return false; 152 DCHECK_EQ(sizeof(EventType), event->size); 153 delete static_cast<EventType*>(event); 154 return true; 155 } 156 }; 157 158 struct WebInputEventCanCoalesce { 159 template <class EventType> 160 bool Execute(const WebInputEvent& event_to_coalesce, 161 const WebInputEvent* event) const { 162 if (event_to_coalesce.type != event->type) 163 return false; 164 DCHECK_EQ(sizeof(EventType), event->size); 165 DCHECK_EQ(sizeof(EventType), event_to_coalesce.size); 166 return CanCoalesce(static_cast<const EventType&>(event_to_coalesce), 167 *static_cast<const EventType*>(event)); 168 } 169 }; 170 171 struct WebInputEventCoalesce { 172 template <class EventType> 173 bool Execute(const WebInputEvent& event_to_coalesce, 174 WebInputEvent* event) const { 175 Coalesce(static_cast<const EventType&>(event_to_coalesce), 176 static_cast<EventType*>(event)); 177 return true; 178 } 179 }; 180 181 template <typename Operator, typename ArgIn, typename ArgOut> 182 bool Apply(Operator op, 183 WebInputEvent::Type type, 184 const ArgIn& arg_in, 185 ArgOut* arg_out) { 186 if (WebInputEvent::isMouseEventType(type)) 187 return op.template Execute<WebMouseEvent>(arg_in, arg_out); 188 else if (type == WebInputEvent::MouseWheel) 189 return op.template Execute<WebMouseWheelEvent>(arg_in, arg_out); 190 else if (WebInputEvent::isKeyboardEventType(type)) 191 return op.template Execute<WebKeyboardEvent>(arg_in, arg_out); 192 else if (WebInputEvent::isTouchEventType(type)) 193 return op.template Execute<WebTouchEvent>(arg_in, arg_out); 194 else if (WebInputEvent::isGestureEventType(type)) 195 return op.template Execute<WebGestureEvent>(arg_in, arg_out); 196 197 NOTREACHED() << "Unknown webkit event type " << type; 198 return false; 199 } 200 201 } // namespace 202 203 const char* WebInputEventTraits::GetName(WebInputEvent::Type type) { 204 #define CASE_TYPE(t) case WebInputEvent::t: return #t 205 switch(type) { 206 CASE_TYPE(Undefined); 207 CASE_TYPE(MouseDown); 208 CASE_TYPE(MouseUp); 209 CASE_TYPE(MouseMove); 210 CASE_TYPE(MouseEnter); 211 CASE_TYPE(MouseLeave); 212 CASE_TYPE(ContextMenu); 213 CASE_TYPE(MouseWheel); 214 CASE_TYPE(RawKeyDown); 215 CASE_TYPE(KeyDown); 216 CASE_TYPE(KeyUp); 217 CASE_TYPE(Char); 218 CASE_TYPE(GestureScrollBegin); 219 CASE_TYPE(GestureScrollEnd); 220 CASE_TYPE(GestureScrollUpdate); 221 CASE_TYPE(GestureFlingStart); 222 CASE_TYPE(GestureFlingCancel); 223 CASE_TYPE(GestureShowPress); 224 CASE_TYPE(GestureTap); 225 CASE_TYPE(GestureTapUnconfirmed); 226 CASE_TYPE(GestureTapDown); 227 CASE_TYPE(GestureTapCancel); 228 CASE_TYPE(GestureDoubleTap); 229 CASE_TYPE(GestureTwoFingerTap); 230 CASE_TYPE(GestureLongPress); 231 CASE_TYPE(GestureLongTap); 232 CASE_TYPE(GesturePinchBegin); 233 CASE_TYPE(GesturePinchEnd); 234 CASE_TYPE(GesturePinchUpdate); 235 CASE_TYPE(TouchStart); 236 CASE_TYPE(TouchMove); 237 CASE_TYPE(TouchEnd); 238 CASE_TYPE(TouchCancel); 239 default: 240 // Must include default to let blink::WebInputEvent add new event types 241 // before they're added here. 242 DLOG(WARNING) << 243 "Unhandled WebInputEvent type in WebInputEventTraits::GetName.\n"; 244 break; 245 } 246 #undef CASE_TYPE 247 return ""; 248 } 249 250 size_t WebInputEventTraits::GetSize(WebInputEvent::Type type) { 251 size_t size = 0; 252 Apply(WebInputEventSize(), type, type, &size); 253 return size; 254 } 255 256 ScopedWebInputEvent WebInputEventTraits::Clone(const WebInputEvent& event) { 257 ScopedWebInputEvent scoped_event; 258 Apply(WebInputEventClone(), event.type, event, &scoped_event); 259 return scoped_event.Pass(); 260 } 261 262 void WebInputEventTraits::Delete(WebInputEvent* event) { 263 if (!event) 264 return; 265 bool dummy_var = false; 266 Apply(WebInputEventDelete(), event->type, event, &dummy_var); 267 } 268 269 bool WebInputEventTraits::CanCoalesce(const WebInputEvent& event_to_coalesce, 270 const WebInputEvent& event) { 271 // Early out before casting. 272 if (event_to_coalesce.type != event.type) 273 return false; 274 return Apply(WebInputEventCanCoalesce(), 275 event.type, 276 event_to_coalesce, 277 &event); 278 } 279 280 void WebInputEventTraits::Coalesce(const WebInputEvent& event_to_coalesce, 281 WebInputEvent* event) { 282 DCHECK(event); 283 Apply(WebInputEventCoalesce(), event->type, event_to_coalesce, event); 284 } 285 286 bool WebInputEventTraits::IgnoresAckDisposition( 287 blink::WebInputEvent::Type type) { 288 switch (type) { 289 case WebInputEvent::GestureTapDown: 290 case WebInputEvent::GestureShowPress: 291 case WebInputEvent::GestureTapCancel: 292 case WebInputEvent::GesturePinchBegin: 293 case WebInputEvent::GesturePinchEnd: 294 case WebInputEvent::GestureScrollBegin: 295 case WebInputEvent::GestureScrollEnd: 296 case WebInputEvent::TouchCancel: 297 return true; 298 default: 299 break; 300 } 301 return false; 302 } 303 304 } // namespace content 305