Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / events / event.cc
1 // Copyright (c) 2012 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 "ui/events/event.h"
6
7 #if defined(USE_X11)
8 #include <X11/extensions/XInput2.h>
9 #include <X11/Xlib.h>
10 #endif
11
12 #include <cmath>
13 #include <cstring>
14
15 #include "base/metrics/histogram.h"
16 #include "base/strings/stringprintf.h"
17 #include "ui/events/event_utils.h"
18 #include "ui/events/keycodes/keyboard_code_conversion.h"
19 #include "ui/gfx/point3_f.h"
20 #include "ui/gfx/point_conversions.h"
21 #include "ui/gfx/transform.h"
22 #include "ui/gfx/transform_util.h"
23
24 #if defined(USE_X11)
25 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
26 #elif defined(USE_OZONE)
27 #include "ui/events/keycodes/keyboard_code_conversion.h"
28 #endif
29
30 namespace {
31
32 std::string EventTypeName(ui::EventType type) {
33 #define RETURN_IF_TYPE(t) if (type == ui::t)  return #t
34 #define CASE_TYPE(t) case ui::t:  return #t
35   switch (type) {
36     CASE_TYPE(ET_UNKNOWN);
37     CASE_TYPE(ET_MOUSE_PRESSED);
38     CASE_TYPE(ET_MOUSE_DRAGGED);
39     CASE_TYPE(ET_MOUSE_RELEASED);
40     CASE_TYPE(ET_MOUSE_MOVED);
41     CASE_TYPE(ET_MOUSE_ENTERED);
42     CASE_TYPE(ET_MOUSE_EXITED);
43     CASE_TYPE(ET_KEY_PRESSED);
44     CASE_TYPE(ET_KEY_RELEASED);
45     CASE_TYPE(ET_MOUSEWHEEL);
46     CASE_TYPE(ET_MOUSE_CAPTURE_CHANGED);
47     CASE_TYPE(ET_TOUCH_RELEASED);
48     CASE_TYPE(ET_TOUCH_PRESSED);
49     CASE_TYPE(ET_TOUCH_MOVED);
50     CASE_TYPE(ET_TOUCH_CANCELLED);
51     CASE_TYPE(ET_DROP_TARGET_EVENT);
52     CASE_TYPE(ET_TRANSLATED_KEY_PRESS);
53     CASE_TYPE(ET_TRANSLATED_KEY_RELEASE);
54     CASE_TYPE(ET_GESTURE_SCROLL_BEGIN);
55     CASE_TYPE(ET_GESTURE_SCROLL_END);
56     CASE_TYPE(ET_GESTURE_SCROLL_UPDATE);
57     CASE_TYPE(ET_GESTURE_SHOW_PRESS);
58     CASE_TYPE(ET_GESTURE_WIN8_EDGE_SWIPE);
59     CASE_TYPE(ET_GESTURE_TAP);
60     CASE_TYPE(ET_GESTURE_TAP_DOWN);
61     CASE_TYPE(ET_GESTURE_TAP_CANCEL);
62     CASE_TYPE(ET_GESTURE_BEGIN);
63     CASE_TYPE(ET_GESTURE_END);
64     CASE_TYPE(ET_GESTURE_TWO_FINGER_TAP);
65     CASE_TYPE(ET_GESTURE_PINCH_BEGIN);
66     CASE_TYPE(ET_GESTURE_PINCH_END);
67     CASE_TYPE(ET_GESTURE_PINCH_UPDATE);
68     CASE_TYPE(ET_GESTURE_LONG_PRESS);
69     CASE_TYPE(ET_GESTURE_LONG_TAP);
70     CASE_TYPE(ET_GESTURE_MULTIFINGER_SWIPE);
71     CASE_TYPE(ET_GESTURE_TAP_UNCONFIRMED);
72     CASE_TYPE(ET_GESTURE_DOUBLE_TAP);
73     CASE_TYPE(ET_SCROLL);
74     CASE_TYPE(ET_SCROLL_FLING_START);
75     CASE_TYPE(ET_SCROLL_FLING_CANCEL);
76     CASE_TYPE(ET_CANCEL_MODE);
77     CASE_TYPE(ET_UMA_DATA);
78     case ui::ET_LAST: NOTREACHED(); return std::string();
79     // Don't include default, so that we get an error when new type is added.
80   }
81 #undef CASE_TYPE
82
83   NOTREACHED();
84   return std::string();
85 }
86
87 bool IsX11SendEventTrue(const base::NativeEvent& event) {
88 #if defined(USE_X11)
89   if (event && event->xany.send_event)
90     return true;
91 #endif
92   return false;
93 }
94
95 }  // namespace
96
97 namespace ui {
98
99 ////////////////////////////////////////////////////////////////////////////////
100 // Event
101
102 Event::~Event() {
103   if (delete_native_event_)
104     ReleaseCopiedNativeEvent(native_event_);
105 }
106
107 bool Event::HasNativeEvent() const {
108   base::NativeEvent null_event;
109   std::memset(&null_event, 0, sizeof(null_event));
110   return !!std::memcmp(&native_event_, &null_event, sizeof(null_event));
111 }
112
113 void Event::StopPropagation() {
114   // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
115   // events.
116   // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
117   CHECK(cancelable_);
118   result_ = static_cast<EventResult>(result_ | ER_CONSUMED);
119 }
120
121 void Event::SetHandled() {
122   // TODO(sad): Re-enable these checks once View uses dispatcher to dispatch
123   // events.
124   // CHECK(phase_ != EP_PREDISPATCH && phase_ != EP_POSTDISPATCH);
125   CHECK(cancelable_);
126   result_ = static_cast<EventResult>(result_ | ER_HANDLED);
127 }
128
129 Event::Event(EventType type, base::TimeDelta time_stamp, int flags)
130     : type_(type),
131       time_stamp_(time_stamp),
132       flags_(flags),
133       native_event_(base::NativeEvent()),
134       delete_native_event_(false),
135       cancelable_(true),
136       target_(NULL),
137       phase_(EP_PREDISPATCH),
138       result_(ER_UNHANDLED) {
139   if (type_ < ET_LAST)
140     name_ = EventTypeName(type_);
141 }
142
143 Event::Event(const base::NativeEvent& native_event,
144              EventType type,
145              int flags)
146     : type_(type),
147       time_stamp_(EventTimeFromNative(native_event)),
148       flags_(flags),
149       native_event_(native_event),
150       delete_native_event_(false),
151       cancelable_(true),
152       target_(NULL),
153       phase_(EP_PREDISPATCH),
154       result_(ER_UNHANDLED) {
155   base::TimeDelta delta = EventTimeForNow() - time_stamp_;
156   if (type_ < ET_LAST)
157     name_ = EventTypeName(type_);
158   UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser",
159                               delta.InMicroseconds(), 1, 1000000, 100);
160   std::string name_for_event =
161       base::StringPrintf("Event.Latency.Browser.%s", name_.c_str());
162   base::HistogramBase* counter_for_type =
163       base::Histogram::FactoryGet(
164           name_for_event,
165           1,
166           1000000,
167           100,
168           base::HistogramBase::kUmaTargetedHistogramFlag);
169   counter_for_type->Add(delta.InMicroseconds());
170 }
171
172 Event::Event(const Event& copy)
173     : type_(copy.type_),
174       time_stamp_(copy.time_stamp_),
175       latency_(copy.latency_),
176       flags_(copy.flags_),
177       native_event_(CopyNativeEvent(copy.native_event_)),
178       delete_native_event_(true),
179       cancelable_(true),
180       target_(NULL),
181       phase_(EP_PREDISPATCH),
182       result_(ER_UNHANDLED) {
183   if (type_ < ET_LAST)
184     name_ = EventTypeName(type_);
185 }
186
187 void Event::SetType(EventType type) {
188   if (type_ < ET_LAST)
189     name_ = std::string();
190   type_ = type;
191   if (type_ < ET_LAST)
192     name_ = EventTypeName(type_);
193 }
194
195 ////////////////////////////////////////////////////////////////////////////////
196 // CancelModeEvent
197
198 CancelModeEvent::CancelModeEvent()
199     : Event(ET_CANCEL_MODE, base::TimeDelta(), 0) {
200   set_cancelable(false);
201 }
202
203 CancelModeEvent::~CancelModeEvent() {
204 }
205
206 ////////////////////////////////////////////////////////////////////////////////
207 // LocatedEvent
208
209 LocatedEvent::~LocatedEvent() {
210 }
211
212 LocatedEvent::LocatedEvent(const base::NativeEvent& native_event)
213     : Event(native_event,
214             EventTypeFromNative(native_event),
215             EventFlagsFromNative(native_event)),
216       location_(EventLocationFromNative(native_event)),
217       root_location_(location_) {
218 }
219
220 LocatedEvent::LocatedEvent(EventType type,
221                            const gfx::PointF& location,
222                            const gfx::PointF& root_location,
223                            base::TimeDelta time_stamp,
224                            int flags)
225     : Event(type, time_stamp, flags),
226       location_(location),
227       root_location_(root_location) {
228 }
229
230 void LocatedEvent::UpdateForRootTransform(
231     const gfx::Transform& reversed_root_transform) {
232   // Transform has to be done at root level.
233   gfx::Point3F p(location_);
234   reversed_root_transform.TransformPoint(&p);
235   location_ = p.AsPointF();
236   root_location_ = location_;
237 }
238
239 ////////////////////////////////////////////////////////////////////////////////
240 // MouseEvent
241
242 MouseEvent::MouseEvent(const base::NativeEvent& native_event)
243     : LocatedEvent(native_event),
244       changed_button_flags_(
245           GetChangedMouseButtonFlagsFromNative(native_event)) {
246   if (type() == ET_MOUSE_PRESSED || type() == ET_MOUSE_RELEASED)
247     SetClickCount(GetRepeatCount(*this));
248 }
249
250 MouseEvent::MouseEvent(EventType type,
251                        const gfx::PointF& location,
252                        const gfx::PointF& root_location,
253                        int flags,
254                        int changed_button_flags)
255     : LocatedEvent(type, location, root_location, EventTimeForNow(), flags),
256       changed_button_flags_(changed_button_flags) {
257   if (this->type() == ET_MOUSE_MOVED && IsAnyButton())
258     SetType(ET_MOUSE_DRAGGED);
259 }
260
261 // static
262 bool MouseEvent::IsRepeatedClickEvent(
263     const MouseEvent& event1,
264     const MouseEvent& event2) {
265   // These values match the Windows defaults.
266   static const int kDoubleClickTimeMS = 500;
267   static const int kDoubleClickWidth = 4;
268   static const int kDoubleClickHeight = 4;
269
270   if (event1.type() != ET_MOUSE_PRESSED ||
271       event2.type() != ET_MOUSE_PRESSED)
272     return false;
273
274   // Compare flags, but ignore EF_IS_DOUBLE_CLICK to allow triple clicks.
275   if ((event1.flags() & ~EF_IS_DOUBLE_CLICK) !=
276       (event2.flags() & ~EF_IS_DOUBLE_CLICK))
277     return false;
278
279   base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp();
280
281   if (time_difference.InMilliseconds() > kDoubleClickTimeMS)
282     return false;
283
284   if (std::abs(event2.x() - event1.x()) > kDoubleClickWidth / 2)
285     return false;
286
287   if (std::abs(event2.y() - event1.y()) > kDoubleClickHeight / 2)
288     return false;
289
290   return true;
291 }
292
293 // static
294 int MouseEvent::GetRepeatCount(const MouseEvent& event) {
295   int click_count = 1;
296   if (last_click_event_) {
297     if (event.type() == ui::ET_MOUSE_RELEASED)
298       return last_click_event_->GetClickCount();
299     if (IsX11SendEventTrue(event.native_event()))
300       click_count = last_click_event_->GetClickCount();
301     else if (IsRepeatedClickEvent(*last_click_event_, event))
302       click_count = last_click_event_->GetClickCount() + 1;
303     delete last_click_event_;
304   }
305   last_click_event_ = new MouseEvent(event);
306   if (click_count > 3)
307     click_count = 3;
308   last_click_event_->SetClickCount(click_count);
309   return click_count;
310 }
311
312 // static
313 MouseEvent* MouseEvent::last_click_event_ = NULL;
314
315 int MouseEvent::GetClickCount() const {
316   if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
317     return 0;
318
319   if (flags() & EF_IS_TRIPLE_CLICK)
320     return 3;
321   else if (flags() & EF_IS_DOUBLE_CLICK)
322     return 2;
323   else
324     return 1;
325 }
326
327 void MouseEvent::SetClickCount(int click_count) {
328   if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED)
329     return;
330
331   DCHECK(click_count > 0);
332   DCHECK(click_count <= 3);
333
334   int f = flags();
335   switch (click_count) {
336     case 1:
337       f &= ~EF_IS_DOUBLE_CLICK;
338       f &= ~EF_IS_TRIPLE_CLICK;
339       break;
340     case 2:
341       f |= EF_IS_DOUBLE_CLICK;
342       f &= ~EF_IS_TRIPLE_CLICK;
343       break;
344     case 3:
345       f &= ~EF_IS_DOUBLE_CLICK;
346       f |= EF_IS_TRIPLE_CLICK;
347       break;
348   }
349   set_flags(f);
350 }
351
352 ////////////////////////////////////////////////////////////////////////////////
353 // MouseWheelEvent
354
355 MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event)
356     : MouseEvent(native_event),
357       offset_(GetMouseWheelOffset(native_event)) {
358 }
359
360 MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event)
361     : MouseEvent(scroll_event),
362       offset_(scroll_event.x_offset(), scroll_event.y_offset()){
363   SetType(ET_MOUSEWHEEL);
364 }
365
366 MouseWheelEvent::MouseWheelEvent(const MouseEvent& mouse_event,
367                                  int x_offset,
368                                  int y_offset)
369     : MouseEvent(mouse_event), offset_(x_offset, y_offset) {
370   DCHECK(type() == ET_MOUSEWHEEL);
371 }
372
373 MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event)
374     : MouseEvent(mouse_wheel_event),
375       offset_(mouse_wheel_event.offset()) {
376   DCHECK(type() == ET_MOUSEWHEEL);
377 }
378
379 #if defined(OS_WIN)
380 // This value matches windows WHEEL_DELTA.
381 // static
382 const int MouseWheelEvent::kWheelDelta = 120;
383 #else
384 // This value matches GTK+ wheel scroll amount.
385 const int MouseWheelEvent::kWheelDelta = 53;
386 #endif
387
388 void MouseWheelEvent::UpdateForRootTransform(
389     const gfx::Transform& inverted_root_transform) {
390   LocatedEvent::UpdateForRootTransform(inverted_root_transform);
391   gfx::DecomposedTransform decomp;
392   bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
393   DCHECK(success);
394   if (decomp.scale[0])
395     offset_.set_x(offset_.x() * decomp.scale[0]);
396   if (decomp.scale[1])
397     offset_.set_y(offset_.y() * decomp.scale[1]);
398 }
399
400 ////////////////////////////////////////////////////////////////////////////////
401 // TouchEvent
402
403 TouchEvent::TouchEvent(const base::NativeEvent& native_event)
404     : LocatedEvent(native_event),
405       touch_id_(GetTouchId(native_event)),
406       radius_x_(GetTouchRadiusX(native_event)),
407       radius_y_(GetTouchRadiusY(native_event)),
408       rotation_angle_(GetTouchAngle(native_event)),
409       force_(GetTouchForce(native_event)),
410       source_device_id_(-1) {
411   latency()->AddLatencyNumberWithTimestamp(
412       INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
413       0,
414       0,
415       base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()),
416       1);
417
418 #if defined(USE_X11)
419   XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(native_event->xcookie.data);
420   source_device_id_ = xiev->deviceid;
421 #endif
422
423   latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
424 }
425
426 TouchEvent::TouchEvent(EventType type,
427                        const gfx::PointF& location,
428                        int touch_id,
429                        base::TimeDelta time_stamp)
430     : LocatedEvent(type, location, location, time_stamp, 0),
431       touch_id_(touch_id),
432       radius_x_(0.0f),
433       radius_y_(0.0f),
434       rotation_angle_(0.0f),
435       force_(0.0f),
436       source_device_id_(-1) {
437   latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
438 }
439
440 TouchEvent::TouchEvent(EventType type,
441                        const gfx::PointF& location,
442                        int flags,
443                        int touch_id,
444                        base::TimeDelta time_stamp,
445                        float radius_x,
446                        float radius_y,
447                        float angle,
448                        float force)
449     : LocatedEvent(type, location, location, time_stamp, flags),
450       touch_id_(touch_id),
451       radius_x_(radius_x),
452       radius_y_(radius_y),
453       rotation_angle_(angle),
454       force_(force),
455       source_device_id_(-1) {
456   latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
457 }
458
459 TouchEvent::~TouchEvent() {
460   // In ctor TouchEvent(native_event) we call GetTouchId() which in X11
461   // platform setups the tracking_id to slot mapping. So in dtor here,
462   // if this touch event is a release event, we clear the mapping accordingly.
463   if (HasNativeEvent())
464     ClearTouchIdIfReleased(native_event());
465 }
466
467 void TouchEvent::Relocate(const gfx::Point& origin) {
468   location_ -= origin.OffsetFromOrigin();
469   root_location_ -= origin.OffsetFromOrigin();
470 }
471
472 void TouchEvent::UpdateForRootTransform(
473     const gfx::Transform& inverted_root_transform) {
474   LocatedEvent::UpdateForRootTransform(inverted_root_transform);
475   gfx::DecomposedTransform decomp;
476   bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform);
477   DCHECK(success);
478   if (decomp.scale[0])
479     radius_x_ *= decomp.scale[0];
480   if (decomp.scale[1])
481     radius_y_ *= decomp.scale[1];
482 }
483
484 ////////////////////////////////////////////////////////////////////////////////
485 // KeyEvent
486
487 KeyEvent::KeyEvent(const base::NativeEvent& native_event, bool is_char)
488     : Event(native_event,
489             EventTypeFromNative(native_event),
490             EventFlagsFromNative(native_event)),
491       key_code_(KeyboardCodeFromNative(native_event)),
492       code_(CodeFromNative(native_event)),
493       is_char_(is_char),
494       character_(0) {
495 #if defined(USE_X11)
496   NormalizeFlags();
497 #endif
498 }
499
500 KeyEvent::KeyEvent(EventType type,
501                    KeyboardCode key_code,
502                    int flags,
503                    bool is_char)
504     : Event(type, EventTimeForNow(), flags),
505       key_code_(key_code),
506       is_char_(is_char),
507       character_(GetCharacterFromKeyCode(key_code, flags)) {
508 }
509
510 KeyEvent::KeyEvent(EventType type,
511                    KeyboardCode key_code,
512                    const std::string& code,
513                    int flags,
514                    bool is_char)
515     : Event(type, EventTimeForNow(), flags),
516       key_code_(key_code),
517       code_(code),
518       is_char_(is_char),
519       character_(GetCharacterFromKeyCode(key_code, flags)) {
520 }
521
522 uint16 KeyEvent::GetCharacter() const {
523   if (character_)
524     return character_;
525
526 #if defined(OS_WIN)
527   return (native_event().message == WM_CHAR) ? key_code_ :
528       GetCharacterFromKeyCode(key_code_, flags());
529 #elif defined(USE_X11)
530   if (!native_event())
531     return GetCharacterFromKeyCode(key_code_, flags());
532
533   DCHECK(native_event()->type == KeyPress ||
534          native_event()->type == KeyRelease);
535
536   uint16 ch = 0;
537   if (!IsControlDown())
538     ch = GetCharacterFromXEvent(native_event());
539   return ch ? ch : GetCharacterFromKeyCode(key_code_, flags());
540 #else
541   if (native_event()) {
542     DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED ||
543            EventTypeFromNative(native_event()) == ET_KEY_RELEASED);
544   }
545
546   return GetCharacterFromKeyCode(key_code_, flags());
547 #endif
548 }
549
550 bool KeyEvent::IsUnicodeKeyCode() const {
551 #if defined(OS_WIN)
552   if (!IsAltDown())
553     return false;
554   const int key = key_code();
555   if (key >= VKEY_NUMPAD0 && key <= VKEY_NUMPAD9)
556     return true;
557   // Check whether the user is using the numeric keypad with num-lock off.
558   // In that case, EF_EXTENDED will not be set; if it is set, the key event
559   // originated from the relevant non-numpad dedicated key, e.g. [Insert].
560   return (!(flags() & EF_EXTENDED) &&
561           (key == VKEY_INSERT || key == VKEY_END  || key == VKEY_DOWN ||
562            key == VKEY_NEXT   || key == VKEY_LEFT || key == VKEY_CLEAR ||
563            key == VKEY_RIGHT  || key == VKEY_HOME || key == VKEY_UP ||
564            key == VKEY_PRIOR));
565 #else
566   return false;
567 #endif
568 }
569
570 void KeyEvent::NormalizeFlags() {
571   int mask = 0;
572   switch (key_code()) {
573     case VKEY_CONTROL:
574       mask = EF_CONTROL_DOWN;
575       break;
576     case VKEY_SHIFT:
577       mask = EF_SHIFT_DOWN;
578       break;
579     case VKEY_MENU:
580       mask = EF_ALT_DOWN;
581       break;
582     case VKEY_CAPITAL:
583       mask = EF_CAPS_LOCK_DOWN;
584       break;
585     default:
586       return;
587   }
588   if (type() == ET_KEY_PRESSED)
589     set_flags(flags() | mask);
590   else
591     set_flags(flags() & ~mask);
592 }
593
594 ////////////////////////////////////////////////////////////////////////////////
595 // TranslatedKeyEvent
596
597 TranslatedKeyEvent::TranslatedKeyEvent(const base::NativeEvent& native_event,
598                                        bool is_char)
599     : KeyEvent(native_event, is_char) {
600   SetType(type() == ET_KEY_PRESSED ?
601           ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE);
602 }
603
604 TranslatedKeyEvent::TranslatedKeyEvent(bool is_press,
605                                        KeyboardCode key_code,
606                                        int flags)
607     : KeyEvent((is_press ? ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE),
608                key_code,
609                flags,
610                false) {
611 }
612
613 TranslatedKeyEvent::TranslatedKeyEvent(const KeyEvent& key_event)
614     : KeyEvent(key_event) {
615   SetType(type() == ET_KEY_PRESSED ?
616           ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE);
617   set_is_char(false);
618 }
619
620 void TranslatedKeyEvent::ConvertToKeyEvent() {
621   SetType(type() == ET_TRANSLATED_KEY_PRESS ?
622           ET_KEY_PRESSED : ET_KEY_RELEASED);
623 }
624
625 ////////////////////////////////////////////////////////////////////////////////
626 // ScrollEvent
627
628 ScrollEvent::ScrollEvent(const base::NativeEvent& native_event)
629     : MouseEvent(native_event) {
630   if (type() == ET_SCROLL) {
631     GetScrollOffsets(native_event,
632                      &x_offset_, &y_offset_,
633                      &x_offset_ordinal_, &y_offset_ordinal_,
634                      &finger_count_);
635   } else if (type() == ET_SCROLL_FLING_START ||
636              type() == ET_SCROLL_FLING_CANCEL) {
637     GetFlingData(native_event,
638                  &x_offset_, &y_offset_,
639                  &x_offset_ordinal_, &y_offset_ordinal_,
640                  NULL);
641   } else {
642     NOTREACHED() << "Unexpected event type " << type()
643         << " when constructing a ScrollEvent.";
644   }
645 }
646
647 ScrollEvent::ScrollEvent(EventType type,
648                          const gfx::PointF& location,
649                          base::TimeDelta time_stamp,
650                          int flags,
651                          float x_offset,
652                          float y_offset,
653                          float x_offset_ordinal,
654                          float y_offset_ordinal,
655                          int finger_count)
656     : MouseEvent(type, location, location, flags, 0),
657       x_offset_(x_offset),
658       y_offset_(y_offset),
659       x_offset_ordinal_(x_offset_ordinal),
660       y_offset_ordinal_(y_offset_ordinal),
661       finger_count_(finger_count) {
662   set_time_stamp(time_stamp);
663   CHECK(IsScrollEvent());
664 }
665
666 void ScrollEvent::Scale(const float factor) {
667   x_offset_ *= factor;
668   y_offset_ *= factor;
669   x_offset_ordinal_ *= factor;
670   y_offset_ordinal_ *= factor;
671 }
672
673 ////////////////////////////////////////////////////////////////////////////////
674 // GestureEvent
675
676 GestureEvent::GestureEvent(EventType type,
677                            float x,
678                            float y,
679                            int flags,
680                            base::TimeDelta time_stamp,
681                            const GestureEventDetails& details,
682                            unsigned int touch_ids_bitfield)
683     : LocatedEvent(type,
684                    gfx::PointF(x, y),
685                    gfx::PointF(x, y),
686                    time_stamp,
687                    flags | EF_FROM_TOUCH),
688       details_(details),
689       touch_ids_bitfield_(touch_ids_bitfield) {
690 }
691
692 GestureEvent::~GestureEvent() {
693 }
694
695 int GestureEvent::GetLowestTouchId() const {
696   if (touch_ids_bitfield_ == 0)
697     return -1;
698   int i = -1;
699   // Find the index of the least significant 1 bit
700   while (!(1 << ++i & touch_ids_bitfield_));
701   return i;
702 }
703
704 }  // namespace ui