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