event.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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 29namespace { 30 31base::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 49std::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 102bool 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 112namespace ui { 113 114//////////////////////////////////////////////////////////////////////////////// 115// Event 116 117Event::~Event() { 118#if defined(USE_X11) 119 if (delete_native_event_) 120 delete native_event_; 121#endif 122} 123 124bool 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 130void 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 138void 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 146Event::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 163Event::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 192Event::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 211void 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 219void Event::Init() { 220 std::memset(&native_event_, 0, sizeof(native_event_)); 221} 222 223void Event::InitWithNativeEvent(const base::NativeEvent& native_event) { 224 native_event_ = native_event; 225} 226 227void Event::InitLatencyInfo() { 228 latency_.AddLatencyNumberWithTimestamp(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 229 0, 230 0, 231 base::TimeTicks::FromInternalValue( 232 time_stamp_.ToInternalValue()), 233 1, 234 true); 235 latency_.AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); 236} 237 238//////////////////////////////////////////////////////////////////////////////// 239// CancelModeEvent 240 241CancelModeEvent::CancelModeEvent() 242 : Event(ET_CANCEL_MODE, base::TimeDelta(), 0) { 243 set_cancelable(false); 244} 245 246CancelModeEvent::~CancelModeEvent() { 247} 248 249//////////////////////////////////////////////////////////////////////////////// 250// LocatedEvent 251 252LocatedEvent::~LocatedEvent() { 253} 254 255LocatedEvent::LocatedEvent(const base::NativeEvent& native_event) 256 : Event(native_event, 257 EventTypeFromNative(native_event), 258 EventFlagsFromNative(native_event)), 259 location_(EventLocationFromNative(native_event)), 260 root_location_(location_) { 261} 262 263LocatedEvent::LocatedEvent(EventType type, 264 const gfx::Point& location, 265 const gfx::Point& root_location, 266 base::TimeDelta time_stamp, 267 int flags) 268 : Event(type, time_stamp, flags), 269 location_(location), 270 root_location_(root_location) { 271} 272 273void LocatedEvent::UpdateForRootTransform( 274 const gfx::Transform& reversed_root_transform) { 275 // Transform has to be done at root level. 276 gfx::Point3F p(location_); 277 reversed_root_transform.TransformPoint(&p); 278 root_location_ = location_ = gfx::ToFlooredPoint(p.AsPointF()); 279} 280 281//////////////////////////////////////////////////////////////////////////////// 282// MouseEvent 283 284MouseEvent::MouseEvent(const base::NativeEvent& native_event) 285 : LocatedEvent(native_event), 286 changed_button_flags_( 287 GetChangedMouseButtonFlagsFromNative(native_event)) { 288 if (type() == ET_MOUSE_PRESSED || type() == ET_MOUSE_RELEASED) 289 SetClickCount(GetRepeatCount(*this)); 290} 291 292MouseEvent::MouseEvent(EventType type, 293 const gfx::Point& location, 294 const gfx::Point& root_location, 295 int flags) 296 : LocatedEvent(type, location, root_location, EventTimeForNow(), flags), 297 changed_button_flags_(0) { 298 if (this->type() == ET_MOUSE_MOVED && IsAnyButton()) 299 SetType(ET_MOUSE_DRAGGED); 300} 301 302// static 303bool MouseEvent::IsRepeatedClickEvent( 304 const MouseEvent& event1, 305 const MouseEvent& event2) { 306 // These values match the Windows defaults. 307 static const int kDoubleClickTimeMS = 500; 308 static const int kDoubleClickWidth = 4; 309 static const int kDoubleClickHeight = 4; 310 311 if (event1.type() != ET_MOUSE_PRESSED || 312 event2.type() != ET_MOUSE_PRESSED) 313 return false; 314 315 // Compare flags, but ignore EF_IS_DOUBLE_CLICK to allow triple clicks. 316 if ((event1.flags() & ~EF_IS_DOUBLE_CLICK) != 317 (event2.flags() & ~EF_IS_DOUBLE_CLICK)) 318 return false; 319 320 base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp(); 321 322 if (time_difference.InMilliseconds() > kDoubleClickTimeMS) 323 return false; 324 325 if (abs(event2.x() - event1.x()) > kDoubleClickWidth / 2) 326 return false; 327 328 if (abs(event2.y() - event1.y()) > kDoubleClickHeight / 2) 329 return false; 330 331 return true; 332} 333 334// static 335int MouseEvent::GetRepeatCount(const MouseEvent& event) { 336 int click_count = 1; 337 if (last_click_event_) { 338 if (event.type() == ui::ET_MOUSE_RELEASED) 339 return last_click_event_->GetClickCount(); 340 if (IsX11SendEventTrue(event.native_event())) 341 click_count = last_click_event_->GetClickCount(); 342 else if (IsRepeatedClickEvent(*last_click_event_, event)) 343 click_count = last_click_event_->GetClickCount() + 1; 344 delete last_click_event_; 345 } 346 last_click_event_ = new MouseEvent(event); 347 if (click_count > 3) 348 click_count = 3; 349 last_click_event_->SetClickCount(click_count); 350 return click_count; 351} 352 353// static 354MouseEvent* MouseEvent::last_click_event_ = NULL; 355 356int MouseEvent::GetClickCount() const { 357 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED) 358 return 0; 359 360 if (flags() & EF_IS_TRIPLE_CLICK) 361 return 3; 362 else if (flags() & EF_IS_DOUBLE_CLICK) 363 return 2; 364 else 365 return 1; 366} 367 368void MouseEvent::SetClickCount(int click_count) { 369 if (type() != ET_MOUSE_PRESSED && type() != ET_MOUSE_RELEASED) 370 return; 371 372 DCHECK(click_count > 0); 373 DCHECK(click_count <= 3); 374 375 int f = flags(); 376 switch (click_count) { 377 case 1: 378 f &= ~EF_IS_DOUBLE_CLICK; 379 f &= ~EF_IS_TRIPLE_CLICK; 380 break; 381 case 2: 382 f |= EF_IS_DOUBLE_CLICK; 383 f &= ~EF_IS_TRIPLE_CLICK; 384 break; 385 case 3: 386 f &= ~EF_IS_DOUBLE_CLICK; 387 f |= EF_IS_TRIPLE_CLICK; 388 break; 389 } 390 set_flags(f); 391} 392 393//////////////////////////////////////////////////////////////////////////////// 394// MouseWheelEvent 395 396MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event) 397 : MouseEvent(native_event), 398 offset_(GetMouseWheelOffset(native_event)) { 399} 400 401MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event) 402 : MouseEvent(scroll_event), 403 offset_(scroll_event.x_offset(), scroll_event.y_offset()){ 404 SetType(ET_MOUSEWHEEL); 405} 406 407MouseWheelEvent::MouseWheelEvent(const MouseEvent& mouse_event, 408 int x_offset, 409 int y_offset) 410 : MouseEvent(mouse_event), offset_(x_offset, y_offset) { 411 DCHECK(type() == ET_MOUSEWHEEL); 412} 413 414MouseWheelEvent::MouseWheelEvent(const MouseWheelEvent& mouse_wheel_event) 415 : MouseEvent(mouse_wheel_event), 416 offset_(mouse_wheel_event.offset()) { 417 DCHECK(type() == ET_MOUSEWHEEL); 418} 419 420#if defined(OS_WIN) 421// This value matches windows WHEEL_DELTA. 422// static 423const int MouseWheelEvent::kWheelDelta = 120; 424#else 425// This value matches GTK+ wheel scroll amount. 426const int MouseWheelEvent::kWheelDelta = 53; 427#endif 428 429void MouseWheelEvent::UpdateForRootTransform( 430 const gfx::Transform& inverted_root_transform) { 431 LocatedEvent::UpdateForRootTransform(inverted_root_transform); 432 gfx::DecomposedTransform decomp; 433 bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform); 434 DCHECK(success); 435 if (decomp.scale[0]) 436 offset_.set_x(offset_.x() * decomp.scale[0]); 437 if (decomp.scale[1]) 438 offset_.set_y(offset_.y() * decomp.scale[1]); 439} 440 441//////////////////////////////////////////////////////////////////////////////// 442// TouchEvent 443 444TouchEvent::TouchEvent(const base::NativeEvent& native_event) 445 : LocatedEvent(native_event), 446 touch_id_(GetTouchId(native_event)), 447 radius_x_(GetTouchRadiusX(native_event)), 448 radius_y_(GetTouchRadiusY(native_event)), 449 rotation_angle_(GetTouchAngle(native_event)), 450 force_(GetTouchForce(native_event)) { 451 InitLatencyInfo(); 452} 453 454TouchEvent::TouchEvent(EventType type, 455 const gfx::Point& location, 456 int touch_id, 457 base::TimeDelta time_stamp) 458 : LocatedEvent(type, location, location, time_stamp, 0), 459 touch_id_(touch_id), 460 radius_x_(0.0f), 461 radius_y_(0.0f), 462 rotation_angle_(0.0f), 463 force_(0.0f) { 464 InitLatencyInfo(); 465} 466 467TouchEvent::TouchEvent(EventType type, 468 const gfx::Point& location, 469 int flags, 470 int touch_id, 471 base::TimeDelta time_stamp, 472 float radius_x, 473 float radius_y, 474 float angle, 475 float force) 476 : LocatedEvent(type, location, location, time_stamp, flags), 477 touch_id_(touch_id), 478 radius_x_(radius_x), 479 radius_y_(radius_y), 480 rotation_angle_(angle), 481 force_(force) { 482 InitLatencyInfo(); 483} 484 485TouchEvent::~TouchEvent() { 486 // In ctor TouchEvent(native_event) we call GetTouchId() which in X11 487 // platform setups the tracking_id to slot mapping. So in dtor here, 488 // if this touch event is a release event, we clear the mapping accordingly. 489 if (HasNativeEvent()) 490 ClearTouchIdIfReleased(native_event()); 491} 492 493void TouchEvent::Relocate(const gfx::Point& origin) { 494 location_ -= origin.OffsetFromOrigin(); 495 root_location_ -= origin.OffsetFromOrigin(); 496} 497 498void TouchEvent::UpdateForRootTransform( 499 const gfx::Transform& inverted_root_transform) { 500 LocatedEvent::UpdateForRootTransform(inverted_root_transform); 501 gfx::DecomposedTransform decomp; 502 bool success = gfx::DecomposeTransform(&decomp, inverted_root_transform); 503 DCHECK(success); 504 if (decomp.scale[0]) 505 radius_x_ *= decomp.scale[0]; 506 if (decomp.scale[1]) 507 radius_y_ *= decomp.scale[1]; 508} 509 510//////////////////////////////////////////////////////////////////////////////// 511// KeyEvent 512 513KeyEvent::KeyEvent(const base::NativeEvent& native_event, bool is_char) 514 : Event(native_event, 515 EventTypeFromNative(native_event), 516 EventFlagsFromNative(native_event)), 517 key_code_(KeyboardCodeFromNative(native_event)), 518 code_(CodeFromNative(native_event)), 519 is_char_(is_char), 520 character_(0) { 521#if defined(USE_X11) 522 NormalizeFlags(); 523#endif 524} 525 526KeyEvent::KeyEvent(EventType type, 527 KeyboardCode key_code, 528 int flags, 529 bool is_char) 530 : Event(type, EventTimeForNow(), flags), 531 key_code_(key_code), 532 is_char_(is_char), 533 character_(GetCharacterFromKeyCode(key_code, flags)) { 534} 535 536KeyEvent::KeyEvent(EventType type, 537 KeyboardCode key_code, 538 const std::string& code, 539 int flags, 540 bool is_char) 541 : Event(type, EventTimeForNow(), flags), 542 key_code_(key_code), 543 code_(code), 544 is_char_(is_char), 545 character_(GetCharacterFromKeyCode(key_code, flags)) { 546} 547 548uint16 KeyEvent::GetCharacter() const { 549 if (character_) 550 return character_; 551 552#if defined(OS_WIN) 553 return (native_event().message == WM_CHAR) ? key_code_ : 554 GetCharacterFromKeyCode(key_code_, flags()); 555#elif defined(USE_X11) 556 if (!native_event()) 557 return GetCharacterFromKeyCode(key_code_, flags()); 558 559 DCHECK(native_event()->type == KeyPress || 560 native_event()->type == KeyRelease); 561 562 uint16 ch = 0; 563 if (!IsControlDown()) 564 ch = GetCharacterFromXEvent(native_event()); 565 return ch ? ch : GetCharacterFromKeyCode(key_code_, flags()); 566#else 567 if (native_event()) { 568 DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED || 569 EventTypeFromNative(native_event()) == ET_KEY_RELEASED); 570 } 571 572 return GetCharacterFromKeyCode(key_code_, flags()); 573#endif 574} 575 576bool KeyEvent::IsUnicodeKeyCode() const { 577 if (!IsAltDown()) 578 return false; 579 const int key = key_code(); 580 if (key >= VKEY_NUMPAD0 && key <= VKEY_NUMPAD9) 581 return true; 582 // Check whether the user is using the numeric keypad with num-lock off. 583 // In that case, EF_EXTENDED will not be set; if it is set, the key event 584 // originated from the relevant non-numpad dedicated key, e.g. [Insert]. 585 return (!(flags() & EF_EXTENDED) && 586 (key == VKEY_INSERT || key == VKEY_END || key == VKEY_DOWN || 587 key == VKEY_NEXT || key == VKEY_LEFT || key == VKEY_CLEAR || 588 key == VKEY_RIGHT || key == VKEY_HOME || key == VKEY_UP || 589 key == VKEY_PRIOR)); 590} 591 592void KeyEvent::NormalizeFlags() { 593 int mask = 0; 594 switch (key_code()) { 595 case VKEY_CONTROL: 596 mask = EF_CONTROL_DOWN; 597 break; 598 case VKEY_SHIFT: 599 mask = EF_SHIFT_DOWN; 600 break; 601 case VKEY_MENU: 602 mask = EF_ALT_DOWN; 603 break; 604 case VKEY_CAPITAL: 605 mask = EF_CAPS_LOCK_DOWN; 606 break; 607 default: 608 return; 609 } 610 if (type() == ET_KEY_PRESSED) 611 set_flags(flags() | mask); 612 else 613 set_flags(flags() & ~mask); 614} 615 616//////////////////////////////////////////////////////////////////////////////// 617// TranslatedKeyEvent 618 619TranslatedKeyEvent::TranslatedKeyEvent(const base::NativeEvent& native_event, 620 bool is_char) 621 : KeyEvent(native_event, is_char) { 622 SetType(type() == ET_KEY_PRESSED ? 623 ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE); 624} 625 626TranslatedKeyEvent::TranslatedKeyEvent(bool is_press, 627 KeyboardCode key_code, 628 int flags) 629 : KeyEvent((is_press ? ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE), 630 key_code, 631 flags, 632 false) { 633} 634 635void TranslatedKeyEvent::ConvertToKeyEvent() { 636 SetType(type() == ET_TRANSLATED_KEY_PRESS ? 637 ET_KEY_PRESSED : ET_KEY_RELEASED); 638} 639 640//////////////////////////////////////////////////////////////////////////////// 641// ScrollEvent 642 643ScrollEvent::ScrollEvent(const base::NativeEvent& native_event) 644 : MouseEvent(native_event) { 645 if (type() == ET_SCROLL) { 646 GetScrollOffsets(native_event, 647 &x_offset_, &y_offset_, 648 &x_offset_ordinal_, &y_offset_ordinal_, 649 &finger_count_); 650 } else if (type() == ET_SCROLL_FLING_START || 651 type() == ET_SCROLL_FLING_CANCEL) { 652 GetFlingData(native_event, 653 &x_offset_, &y_offset_, 654 &x_offset_ordinal_, &y_offset_ordinal_, 655 NULL); 656 } else { 657 NOTREACHED() << "Unexpected event type " << type() 658 << " when constructing a ScrollEvent."; 659 } 660} 661 662ScrollEvent::ScrollEvent(EventType type, 663 const gfx::Point& location, 664 base::TimeDelta time_stamp, 665 int flags, 666 float x_offset, 667 float y_offset, 668 float x_offset_ordinal, 669 float y_offset_ordinal, 670 int finger_count) 671 : MouseEvent(type, location, location, flags), 672 x_offset_(x_offset), 673 y_offset_(y_offset), 674 x_offset_ordinal_(x_offset_ordinal), 675 y_offset_ordinal_(y_offset_ordinal), 676 finger_count_(finger_count) { 677 set_time_stamp(time_stamp); 678 CHECK(IsScrollEvent()); 679} 680 681void ScrollEvent::Scale(const float factor) { 682 x_offset_ *= factor; 683 y_offset_ *= factor; 684 x_offset_ordinal_ *= factor; 685 y_offset_ordinal_ *= factor; 686} 687 688//////////////////////////////////////////////////////////////////////////////// 689// GestureEvent 690 691GestureEvent::GestureEvent(EventType type, 692 int x, 693 int y, 694 int flags, 695 base::TimeDelta time_stamp, 696 const GestureEventDetails& details, 697 unsigned int touch_ids_bitfield) 698 : LocatedEvent(type, 699 gfx::Point(x, y), 700 gfx::Point(x, y), 701 time_stamp, 702 flags | EF_FROM_TOUCH), 703 details_(details), 704 touch_ids_bitfield_(touch_ids_bitfield) { 705} 706 707GestureEvent::~GestureEvent() { 708} 709 710int GestureEvent::GetLowestTouchId() const { 711 if (touch_ids_bitfield_ == 0) 712 return -1; 713 int i = -1; 714 // Find the index of the least significant 1 bit 715 while (!(1 << ++i & touch_ids_bitfield_)); 716 return i; 717} 718 719} // namespace ui 720