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