Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: content/common/input/web_input_event_traits.cc

Issue 1560553002: Framelet Prototype 2016 Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased + Applied Brett's Windows + Fixed security issue Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 <bitset>
8 #include <limits>
9
10 #include "base/logging.h"
11 #include "base/strings/stringprintf.h"
12
13 using base::StringAppendF;
14 using base::SStringPrintf;
15 using blink::WebGestureEvent;
16 using blink::WebInputEvent;
17 using blink::WebKeyboardEvent;
18 using blink::WebMouseEvent;
19 using blink::WebMouseWheelEvent;
20 using blink::WebTouchEvent;
21 using blink::WebTouchPoint;
22 using std::numeric_limits;
23
24 namespace content {
25 namespace {
26
27 const int kInvalidTouchIndex = -1;
28
29 void ApppendEventDetails(const WebKeyboardEvent& event, std::string* result) {
30 StringAppendF(result,
31 "{\n WinCode: %d\n NativeCode: %d\n IsSystem: %d\n"
32 " Text: %s\n UnmodifiedText: %s\n KeyIdentifier: %s\n}",
33 event.windowsKeyCode,
34 event.nativeKeyCode,
35 event.isSystemKey,
36 reinterpret_cast<const char*>(event.text),
37 reinterpret_cast<const char*>(event.unmodifiedText),
38 reinterpret_cast<const char*>(event.keyIdentifier));
39 }
40
41 void ApppendEventDetails(const WebMouseEvent& event, std::string* result) {
42 StringAppendF(result,
43 "{\n Button: %d\n Pos: (%d, %d)\n WindowPos: (%d, %d)\n"
44 " GlobalPos: (%d, %d)\n Movement: (%d, %d)\n Clicks: %d\n}",
45 event.button,
46 event.x,
47 event.y,
48 event.windowX,
49 event.windowY,
50 event.globalX,
51 event.globalY,
52 event.movementX,
53 event.movementY,
54 event.clickCount);
55 }
56
57 void ApppendEventDetails(const WebMouseWheelEvent& event, std::string* result) {
58 StringAppendF(result,
59 "{\n Delta: (%f, %f)\n WheelTicks: (%f, %f)\n Accel: (%f, %f)\n"
60 " ScrollByPage: %d\n HasPreciseScrollingDeltas: %d\n"
61 " Phase: (%d, %d)\n CanRubberband: (%d, %d)\n CanScroll: %d\n}",
62 event.deltaX,
63 event.deltaY,
64 event.wheelTicksX,
65 event.wheelTicksY,
66 event.accelerationRatioX,
67 event.accelerationRatioY,
68 event.scrollByPage,
69 event.hasPreciseScrollingDeltas,
70 event.phase,
71 event.momentumPhase,
72 event.canRubberbandLeft,
73 event.canRubberbandRight,
74 event.canScroll);
75 }
76
77 void ApppendEventDetails(const WebGestureEvent& event, std::string* result) {
78 StringAppendF(result,
79 "{\n Pos: (%d, %d)\n GlobalPos: (%d, %d)\n SourceDevice: %d\n"
80 " RawData: (%f, %f, %f, %f, %d)\n}",
81 event.x,
82 event.y,
83 event.globalX,
84 event.globalY,
85 event.sourceDevice,
86 event.data.scrollUpdate.deltaX,
87 event.data.scrollUpdate.deltaY,
88 event.data.scrollUpdate.velocityX,
89 event.data.scrollUpdate.velocityY,
90 event.data.scrollUpdate.previousUpdateInSequencePrevented);
91 }
92
93 void ApppendTouchPointDetails(const WebTouchPoint& point, std::string* result) {
94 StringAppendF(result,
95 " (ID: %d, State: %d, ScreenPos: (%f, %f), Pos: (%f, %f),"
96 " Radius: (%f, %f), Rot: %f, Force: %f,"
97 " Tilt: (%d, %d)),\n",
98 point.id,
99 point.state,
100 point.screenPosition.x,
101 point.screenPosition.y,
102 point.position.x,
103 point.position.y,
104 point.radiusX,
105 point.radiusY,
106 point.rotationAngle,
107 point.force,
108 point.tiltX,
109 point.tiltY);
110 }
111
112 void ApppendEventDetails(const WebTouchEvent& event, std::string* result) {
113 StringAppendF(result,
114 "{\n Touches: %u, Cancelable: %d, CausesScrolling: %d,"
115 " uniqueTouchEventId: %u\n[\n",
116 event.touchesLength, event.cancelable,
117 event.causesScrollingIfUncanceled, event.uniqueTouchEventId);
118 for (unsigned i = 0; i < event.touchesLength; ++i)
119 ApppendTouchPointDetails(event.touches[i], result);
120 result->append(" ]\n}");
121 }
122
123 bool CanCoalesce(const WebKeyboardEvent& event_to_coalesce,
124 const WebKeyboardEvent& event) {
125 return false;
126 }
127
128 void Coalesce(const WebKeyboardEvent& event_to_coalesce,
129 WebKeyboardEvent* event) {
130 DCHECK(CanCoalesce(event_to_coalesce, *event));
131 }
132
133 bool CanCoalesce(const WebMouseEvent& event_to_coalesce,
134 const WebMouseEvent& event) {
135 return event.type == event_to_coalesce.type &&
136 event.type == WebInputEvent::MouseMove;
137 }
138
139 void Coalesce(const WebMouseEvent& event_to_coalesce, WebMouseEvent* event) {
140 DCHECK(CanCoalesce(event_to_coalesce, *event));
141 // Accumulate movement deltas.
142 int x = event->movementX;
143 int y = event->movementY;
144 *event = event_to_coalesce;
145 event->movementX += x;
146 event->movementY += y;
147 }
148
149 bool CanCoalesce(const WebMouseWheelEvent& event_to_coalesce,
150 const WebMouseWheelEvent& event) {
151 return event.modifiers == event_to_coalesce.modifiers &&
152 event.scrollByPage == event_to_coalesce.scrollByPage &&
153 event.phase == event_to_coalesce.phase &&
154 event.momentumPhase == event_to_coalesce.momentumPhase &&
155 event.hasPreciseScrollingDeltas ==
156 event_to_coalesce.hasPreciseScrollingDeltas &&
157 event.canScroll == event_to_coalesce.canScroll;
158 }
159
160 float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) {
161 return accelerated_delta * acceleration_ratio;
162 }
163
164 float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) {
165 if (unaccelerated_delta == 0.f || accelerated_delta == 0.f)
166 return 1.f;
167 return unaccelerated_delta / accelerated_delta;
168 }
169
170 void Coalesce(const WebMouseWheelEvent& event_to_coalesce,
171 WebMouseWheelEvent* event) {
172 DCHECK(CanCoalesce(event_to_coalesce, *event));
173 float unaccelerated_x =
174 GetUnacceleratedDelta(event->deltaX,
175 event->accelerationRatioX) +
176 GetUnacceleratedDelta(event_to_coalesce.deltaX,
177 event_to_coalesce.accelerationRatioX);
178 float unaccelerated_y =
179 GetUnacceleratedDelta(event->deltaY,
180 event->accelerationRatioY) +
181 GetUnacceleratedDelta(event_to_coalesce.deltaY,
182 event_to_coalesce.accelerationRatioY);
183 event->deltaX += event_to_coalesce.deltaX;
184 event->deltaY += event_to_coalesce.deltaY;
185 event->wheelTicksX += event_to_coalesce.wheelTicksX;
186 event->wheelTicksY += event_to_coalesce.wheelTicksY;
187 event->accelerationRatioX =
188 GetAccelerationRatio(event->deltaX, unaccelerated_x);
189 event->accelerationRatioY =
190 GetAccelerationRatio(event->deltaY, unaccelerated_y);
191 }
192
193 // Returns |kInvalidTouchIndex| iff |event| lacks a touch with an ID of |id|.
194 int GetIndexOfTouchID(const WebTouchEvent& event, int id) {
195 for (unsigned i = 0; i < event.touchesLength; ++i) {
196 if (event.touches[i].id == id)
197 return i;
198 }
199 return kInvalidTouchIndex;
200 }
201
202 bool CanCoalesce(const WebTouchEvent& event_to_coalesce,
203 const WebTouchEvent& event) {
204 if (event.type != event_to_coalesce.type ||
205 event.type != WebInputEvent::TouchMove ||
206 event.modifiers != event_to_coalesce.modifiers ||
207 event.touchesLength != event_to_coalesce.touchesLength ||
208 event.touchesLength > WebTouchEvent::touchesLengthCap)
209 return false;
210
211 static_assert(WebTouchEvent::touchesLengthCap <= sizeof(int32_t) * 8U,
212 "suboptimal touchesLengthCap size");
213 // Ensure that we have a 1-to-1 mapping of pointer ids between touches.
214 std::bitset<WebTouchEvent::touchesLengthCap> unmatched_event_touches(
215 (1 << event.touchesLength) - 1);
216 for (unsigned i = 0; i < event_to_coalesce.touchesLength; ++i) {
217 int event_touch_index =
218 GetIndexOfTouchID(event, event_to_coalesce.touches[i].id);
219 if (event_touch_index == kInvalidTouchIndex)
220 return false;
221 if (!unmatched_event_touches[event_touch_index])
222 return false;
223 unmatched_event_touches[event_touch_index] = false;
224 }
225 return unmatched_event_touches.none();
226 }
227
228 void Coalesce(const WebTouchEvent& event_to_coalesce, WebTouchEvent* event) {
229 DCHECK(CanCoalesce(event_to_coalesce, *event));
230 // The WebTouchPoints include absolute position information. So it is
231 // sufficient to simply replace the previous event with the new event->
232 // However, it is necessary to make sure that all the points have the
233 // correct state, i.e. the touch-points that moved in the last event, but
234 // didn't change in the current event, will have Stationary state. It is
235 // necessary to change them back to Moved state.
236 WebTouchEvent old_event = *event;
237 *event = event_to_coalesce;
238 for (unsigned i = 0; i < event->touchesLength; ++i) {
239 int i_old = GetIndexOfTouchID(old_event, event->touches[i].id);
240 if (old_event.touches[i_old].state == blink::WebTouchPoint::StateMoved)
241 event->touches[i].state = blink::WebTouchPoint::StateMoved;
242 }
243 event->causesScrollingIfUncanceled |= old_event.causesScrollingIfUncanceled;
244 }
245
246 bool CanCoalesce(const WebGestureEvent& event_to_coalesce,
247 const WebGestureEvent& event) {
248 if (event.type != event_to_coalesce.type ||
249 event.sourceDevice != event_to_coalesce.sourceDevice ||
250 event.modifiers != event_to_coalesce.modifiers)
251 return false;
252
253 if (event.type == WebInputEvent::GestureScrollUpdate)
254 return true;
255
256 // GesturePinchUpdate scales can be combined only if they share a focal point,
257 // e.g., with double-tap drag zoom.
258 if (event.type == WebInputEvent::GesturePinchUpdate &&
259 event.x == event_to_coalesce.x &&
260 event.y == event_to_coalesce.y)
261 return true;
262
263 return false;
264 }
265
266 void Coalesce(const WebGestureEvent& event_to_coalesce,
267 WebGestureEvent* event) {
268 DCHECK(CanCoalesce(event_to_coalesce, *event));
269 if (event->type == WebInputEvent::GestureScrollUpdate) {
270 event->data.scrollUpdate.deltaX +=
271 event_to_coalesce.data.scrollUpdate.deltaX;
272 event->data.scrollUpdate.deltaY +=
273 event_to_coalesce.data.scrollUpdate.deltaY;
274 DCHECK_EQ(
275 event->data.scrollUpdate.previousUpdateInSequencePrevented,
276 event_to_coalesce.data.scrollUpdate.previousUpdateInSequencePrevented);
277 } else if (event->type == WebInputEvent::GesturePinchUpdate) {
278 event->data.pinchUpdate.scale *= event_to_coalesce.data.pinchUpdate.scale;
279 // Ensure the scale remains bounded above 0 and below Infinity so that
280 // we can reliably perform operations like log on the values.
281 if (event->data.pinchUpdate.scale < numeric_limits<float>::min())
282 event->data.pinchUpdate.scale = numeric_limits<float>::min();
283 else if (event->data.pinchUpdate.scale > numeric_limits<float>::max())
284 event->data.pinchUpdate.scale = numeric_limits<float>::max();
285 }
286 }
287
288 struct WebInputEventToString {
289 template <class EventType>
290 bool Execute(const WebInputEvent& event, std::string* result) const {
291 SStringPrintf(result, "%s (Time: %lf, Modifiers: %d)\n",
292 WebInputEventTraits::GetName(event.type),
293 event.timeStampSeconds,
294 event.modifiers);
295 const EventType& typed_event = static_cast<const EventType&>(event);
296 ApppendEventDetails(typed_event, result);
297 return true;
298 }
299 };
300
301 struct WebInputEventSize {
302 template <class EventType>
303 bool Execute(WebInputEvent::Type /* type */, size_t* type_size) const {
304 *type_size = sizeof(EventType);
305 return true;
306 }
307 };
308
309 struct WebInputEventClone {
310 template <class EventType>
311 bool Execute(const WebInputEvent& event,
312 ScopedWebInputEvent* scoped_event) const {
313 DCHECK_EQ(sizeof(EventType), event.size);
314 *scoped_event = ScopedWebInputEvent(
315 new EventType(static_cast<const EventType&>(event)));
316 return true;
317 }
318 };
319
320 struct WebInputEventDelete {
321 template <class EventType>
322 bool Execute(WebInputEvent* event, bool* /* dummy_var */) const {
323 if (!event)
324 return false;
325 DCHECK_EQ(sizeof(EventType), event->size);
326 delete static_cast<EventType*>(event);
327 return true;
328 }
329 };
330
331 struct WebInputEventCanCoalesce {
332 template <class EventType>
333 bool Execute(const WebInputEvent& event_to_coalesce,
334 const WebInputEvent* event) const {
335 if (event_to_coalesce.type != event->type)
336 return false;
337 DCHECK_EQ(sizeof(EventType), event->size);
338 DCHECK_EQ(sizeof(EventType), event_to_coalesce.size);
339 return CanCoalesce(static_cast<const EventType&>(event_to_coalesce),
340 *static_cast<const EventType*>(event));
341 }
342 };
343
344 struct WebInputEventCoalesce {
345 template <class EventType>
346 bool Execute(const WebInputEvent& event_to_coalesce,
347 WebInputEvent* event) const {
348 // New events get coalesced into older events, and the newer timestamp
349 // should always be preserved.
350 const double time_stamp_seconds = event_to_coalesce.timeStampSeconds;
351 Coalesce(static_cast<const EventType&>(event_to_coalesce),
352 static_cast<EventType*>(event));
353 event->timeStampSeconds = time_stamp_seconds;
354 return true;
355 }
356 };
357
358 template <typename Operator, typename ArgIn, typename ArgOut>
359 bool Apply(Operator op,
360 WebInputEvent::Type type,
361 const ArgIn& arg_in,
362 ArgOut* arg_out) {
363 if (WebInputEvent::isMouseEventType(type))
364 return op.template Execute<WebMouseEvent>(arg_in, arg_out);
365 else if (type == WebInputEvent::MouseWheel)
366 return op.template Execute<WebMouseWheelEvent>(arg_in, arg_out);
367 else if (WebInputEvent::isKeyboardEventType(type))
368 return op.template Execute<WebKeyboardEvent>(arg_in, arg_out);
369 else if (WebInputEvent::isTouchEventType(type))
370 return op.template Execute<WebTouchEvent>(arg_in, arg_out);
371 else if (WebInputEvent::isGestureEventType(type))
372 return op.template Execute<WebGestureEvent>(arg_in, arg_out);
373
374 NOTREACHED() << "Unknown webkit event type " << type;
375 return false;
376 }
377
378 } // namespace
379
380 const char* WebInputEventTraits::GetName(WebInputEvent::Type type) {
381 #define CASE_TYPE(t) case WebInputEvent::t: return #t
382 switch(type) {
383 CASE_TYPE(Undefined);
384 CASE_TYPE(MouseDown);
385 CASE_TYPE(MouseUp);
386 CASE_TYPE(MouseMove);
387 CASE_TYPE(MouseEnter);
388 CASE_TYPE(MouseLeave);
389 CASE_TYPE(ContextMenu);
390 CASE_TYPE(MouseWheel);
391 CASE_TYPE(RawKeyDown);
392 CASE_TYPE(KeyDown);
393 CASE_TYPE(KeyUp);
394 CASE_TYPE(Char);
395 CASE_TYPE(GestureScrollBegin);
396 CASE_TYPE(GestureScrollEnd);
397 CASE_TYPE(GestureScrollUpdate);
398 CASE_TYPE(GestureFlingStart);
399 CASE_TYPE(GestureFlingCancel);
400 CASE_TYPE(GestureShowPress);
401 CASE_TYPE(GestureTap);
402 CASE_TYPE(GestureTapUnconfirmed);
403 CASE_TYPE(GestureTapDown);
404 CASE_TYPE(GestureTapCancel);
405 CASE_TYPE(GestureDoubleTap);
406 CASE_TYPE(GestureTwoFingerTap);
407 CASE_TYPE(GestureLongPress);
408 CASE_TYPE(GestureLongTap);
409 CASE_TYPE(GesturePinchBegin);
410 CASE_TYPE(GesturePinchEnd);
411 CASE_TYPE(GesturePinchUpdate);
412 CASE_TYPE(TouchStart);
413 CASE_TYPE(TouchMove);
414 CASE_TYPE(TouchEnd);
415 CASE_TYPE(TouchCancel);
416 default:
417 // Must include default to let blink::WebInputEvent add new event types
418 // before they're added here.
419 DLOG(WARNING) <<
420 "Unhandled WebInputEvent type in WebInputEventTraits::GetName.\n";
421 break;
422 }
423 #undef CASE_TYPE
424 return "";
425 }
426
427 std::string WebInputEventTraits::ToString(const WebInputEvent& event) {
428 std::string result;
429 Apply(WebInputEventToString(), event.type, event, &result);
430 return result;
431 }
432
433 size_t WebInputEventTraits::GetSize(WebInputEvent::Type type) {
434 size_t size = 0;
435 Apply(WebInputEventSize(), type, type, &size);
436 return size;
437 }
438
439 ScopedWebInputEvent WebInputEventTraits::Clone(const WebInputEvent& event) {
440 ScopedWebInputEvent scoped_event;
441 Apply(WebInputEventClone(), event.type, event, &scoped_event);
442 return scoped_event;
443 }
444
445 void WebInputEventTraits::Delete(WebInputEvent* event) {
446 if (!event)
447 return;
448 bool dummy_var = false;
449 Apply(WebInputEventDelete(), event->type, event, &dummy_var);
450 }
451
452 bool WebInputEventTraits::CanCoalesce(const WebInputEvent& event_to_coalesce,
453 const WebInputEvent& event) {
454 // Early out before casting.
455 if (event_to_coalesce.type != event.type)
456 return false;
457 return Apply(WebInputEventCanCoalesce(),
458 event.type,
459 event_to_coalesce,
460 &event);
461 }
462
463 void WebInputEventTraits::Coalesce(const WebInputEvent& event_to_coalesce,
464 WebInputEvent* event) {
465 DCHECK(event);
466 Apply(WebInputEventCoalesce(), event->type, event_to_coalesce, event);
467 }
468
469 bool WebInputEventTraits::WillReceiveAckFromRenderer(
470 const WebInputEvent& event) {
471 switch (event.type) {
472 case WebInputEvent::MouseDown:
473 case WebInputEvent::MouseUp:
474 case WebInputEvent::MouseEnter:
475 case WebInputEvent::MouseLeave:
476 case WebInputEvent::ContextMenu:
477 case WebInputEvent::GestureScrollBegin:
478 case WebInputEvent::GestureScrollEnd:
479 case WebInputEvent::GestureShowPress:
480 case WebInputEvent::GestureTapUnconfirmed:
481 case WebInputEvent::GestureTapDown:
482 case WebInputEvent::GestureTapCancel:
483 case WebInputEvent::GesturePinchBegin:
484 case WebInputEvent::GesturePinchEnd:
485 case WebInputEvent::TouchCancel:
486 return false;
487 case WebInputEvent::TouchStart:
488 case WebInputEvent::TouchEnd:
489 return static_cast<const WebTouchEvent&>(event).cancelable;
490 default:
491 return true;
492 }
493 }
494
495 uint32_t WebInputEventTraits::GetUniqueTouchEventId(
496 const WebInputEvent& event) {
497 if (WebInputEvent::isTouchEventType(event.type)) {
498 return static_cast<const WebTouchEvent&>(event).uniqueTouchEventId;
499 }
500 return 0U;
501 }
502
503 } // namespace content
OLDNEW
« no previous file with comments | « content/common/input/web_input_event_traits.h ('k') | content/common/input/web_input_event_traits_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698