Home | History | Annotate | Download | only in web
      1 /*
      2  * Copyright (C) 2009 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "WebInputEventConversion.h"
     33 
     34 #include "core/dom/Touch.h"
     35 #include "core/dom/TouchList.h"
     36 #include "core/events/GestureEvent.h"
     37 #include "core/events/KeyboardEvent.h"
     38 #include "core/events/MouseEvent.h"
     39 #include "core/events/ThreadLocalEventNames.h"
     40 #include "core/events/TouchEvent.h"
     41 #include "core/events/WheelEvent.h"
     42 #include "core/rendering/RenderObject.h"
     43 #include "platform/KeyboardCodes.h"
     44 #include "platform/Widget.h"
     45 #include "platform/scroll/ScrollView.h"
     46 
     47 using namespace WebCore;
     48 
     49 namespace blink {
     50 
     51 static const double millisPerSecond = 1000.0;
     52 
     53 static float widgetInputEventsScaleFactor(const Widget* widget)
     54 {
     55     if (!widget)
     56         return 1;
     57 
     58     ScrollView* rootView =  toScrollView(widget->root());
     59     if (!rootView)
     60         return 1;
     61 
     62     return rootView->inputEventsScaleFactor();
     63 }
     64 
     65 static IntSize widgetInputEventsOffset(const Widget* widget)
     66 {
     67     if (!widget)
     68         return IntSize();
     69     ScrollView* rootView =  toScrollView(widget->root());
     70     if (!rootView)
     71         return IntSize();
     72 
     73     return rootView->inputEventsOffsetForEmulation();
     74 }
     75 
     76 // MakePlatformMouseEvent -----------------------------------------------------
     77 
     78 PlatformMouseEventBuilder::PlatformMouseEventBuilder(Widget* widget, const WebMouseEvent& e)
     79 {
     80     float scale = widgetInputEventsScaleFactor(widget);
     81     IntSize offset = widgetInputEventsOffset(widget);
     82 
     83     // FIXME: Widget is always toplevel, unless it's a popup. We may be able
     84     // to get rid of this once we abstract popups into a WebKit API.
     85     m_position = widget->convertFromContainingWindow(IntPoint((e.x - offset.width()) / scale, (e.y - offset.height()) / scale));
     86     m_globalPosition = IntPoint(e.globalX, e.globalY);
     87     m_movementDelta = IntPoint(e.movementX / scale, e.movementY / scale);
     88     m_button = static_cast<MouseButton>(e.button);
     89 
     90     m_modifiers = 0;
     91     if (e.modifiers & WebInputEvent::ShiftKey)
     92         m_modifiers |= PlatformEvent::ShiftKey;
     93     if (e.modifiers & WebInputEvent::ControlKey)
     94         m_modifiers |= PlatformEvent::CtrlKey;
     95     if (e.modifiers & WebInputEvent::AltKey)
     96         m_modifiers |= PlatformEvent::AltKey;
     97     if (e.modifiers & WebInputEvent::MetaKey)
     98         m_modifiers |= PlatformEvent::MetaKey;
     99 
    100     m_modifierFlags = e.modifiers;
    101     m_timestamp = e.timeStampSeconds;
    102     m_clickCount = e.clickCount;
    103 
    104     switch (e.type) {
    105     case WebInputEvent::MouseMove:
    106     case WebInputEvent::MouseLeave:  // synthesize a move event
    107         m_type = PlatformEvent::MouseMoved;
    108         break;
    109 
    110     case WebInputEvent::MouseDown:
    111         m_type = PlatformEvent::MousePressed;
    112         break;
    113 
    114     case WebInputEvent::MouseUp:
    115         m_type = PlatformEvent::MouseReleased;
    116         break;
    117 
    118     default:
    119         ASSERT_NOT_REACHED();
    120     }
    121 }
    122 
    123 // PlatformWheelEventBuilder --------------------------------------------------
    124 
    125 PlatformWheelEventBuilder::PlatformWheelEventBuilder(Widget* widget, const WebMouseWheelEvent& e)
    126 {
    127     float scale = widgetInputEventsScaleFactor(widget);
    128     IntSize offset = widgetInputEventsOffset(widget);
    129 
    130     m_position = widget->convertFromContainingWindow(IntPoint((e.x - offset.width()) / scale, (e.y - offset.height()) / scale));
    131     m_globalPosition = IntPoint(e.globalX, e.globalY);
    132     m_deltaX = e.deltaX;
    133     m_deltaY = e.deltaY;
    134     m_wheelTicksX = e.wheelTicksX;
    135     m_wheelTicksY = e.wheelTicksY;
    136     m_granularity = e.scrollByPage ?
    137         ScrollByPageWheelEvent : ScrollByPixelWheelEvent;
    138 
    139     m_type = PlatformEvent::Wheel;
    140 
    141     m_modifiers = 0;
    142     if (e.modifiers & WebInputEvent::ShiftKey)
    143         m_modifiers |= PlatformEvent::ShiftKey;
    144     if (e.modifiers & WebInputEvent::ControlKey)
    145         m_modifiers |= PlatformEvent::CtrlKey;
    146     if (e.modifiers & WebInputEvent::AltKey)
    147         m_modifiers |= PlatformEvent::AltKey;
    148     if (e.modifiers & WebInputEvent::MetaKey)
    149         m_modifiers |= PlatformEvent::MetaKey;
    150 
    151     m_hasPreciseScrollingDeltas = e.hasPreciseScrollingDeltas;
    152 #if OS(MACOSX)
    153     m_phase = static_cast<WebCore::PlatformWheelEventPhase>(e.phase);
    154     m_momentumPhase = static_cast<WebCore::PlatformWheelEventPhase>(e.momentumPhase);
    155     m_timestamp = e.timeStampSeconds;
    156     m_scrollCount = 0;
    157     m_unacceleratedScrollingDeltaX = e.deltaX;
    158     m_unacceleratedScrollingDeltaY = e.deltaY;
    159 #endif
    160 }
    161 
    162 // PlatformGestureEventBuilder --------------------------------------------------
    163 
    164 PlatformGestureEventBuilder::PlatformGestureEventBuilder(Widget* widget, const WebGestureEvent& e)
    165 {
    166     float scale = widgetInputEventsScaleFactor(widget);
    167     IntSize offset = widgetInputEventsOffset(widget);
    168 
    169     switch (e.type) {
    170     case WebInputEvent::GestureScrollBegin:
    171         m_type = PlatformEvent::GestureScrollBegin;
    172         break;
    173     case WebInputEvent::GestureScrollEnd:
    174         m_type = PlatformEvent::GestureScrollEnd;
    175         break;
    176     case WebInputEvent::GestureFlingStart:
    177         m_type = PlatformEvent::GestureFlingStart;
    178         break;
    179     case WebInputEvent::GestureScrollUpdate:
    180         m_type = PlatformEvent::GestureScrollUpdate;
    181         m_data.m_scrollUpdate.m_deltaX = e.data.scrollUpdate.deltaX / scale;
    182         m_data.m_scrollUpdate.m_deltaY = e.data.scrollUpdate.deltaY / scale;
    183         m_data.m_scrollUpdate.m_velocityX = e.data.scrollUpdate.velocityX;
    184         m_data.m_scrollUpdate.m_velocityY = e.data.scrollUpdate.velocityY;
    185         break;
    186     case WebInputEvent::GestureScrollUpdateWithoutPropagation:
    187         m_type = PlatformEvent::GestureScrollUpdateWithoutPropagation;
    188         m_data.m_scrollUpdate.m_deltaX = e.data.scrollUpdate.deltaX / scale;
    189         m_data.m_scrollUpdate.m_deltaY = e.data.scrollUpdate.deltaY / scale;
    190         m_data.m_scrollUpdate.m_velocityX = e.data.scrollUpdate.velocityX;
    191         m_data.m_scrollUpdate.m_velocityY = e.data.scrollUpdate.velocityY;
    192         break;
    193     case WebInputEvent::GestureTap:
    194         m_type = PlatformEvent::GestureTap;
    195         m_area = expandedIntSize(FloatSize(e.data.tap.width / scale, e.data.tap.height / scale));
    196         m_data.m_tap.m_tapCount = e.data.tap.tapCount;
    197         break;
    198     case WebInputEvent::GestureTapUnconfirmed:
    199         m_type = PlatformEvent::GestureTapUnconfirmed;
    200         m_area = expandedIntSize(FloatSize(e.data.tap.width / scale, e.data.tap.height / scale));
    201         break;
    202     case WebInputEvent::GestureTapDown:
    203         m_type = PlatformEvent::GestureTapDown;
    204         m_area = expandedIntSize(FloatSize(e.data.tapDown.width / scale, e.data.tapDown.height / scale));
    205         break;
    206     case WebInputEvent::GestureShowPress:
    207         m_type = PlatformEvent::GestureShowPress;
    208         m_area = expandedIntSize(FloatSize(e.data.showPress.width / scale, e.data.showPress.height / scale));
    209         break;
    210     case WebInputEvent::GestureTapCancel:
    211         m_type = PlatformEvent::GestureTapDownCancel;
    212         break;
    213     case WebInputEvent::GestureDoubleTap:
    214         // DoubleTap gesture is now handled as PlatformEvent::GestureTap with tap_count = 2. So no
    215         // need to convert to a Platfrom DoubleTap gesture. But in WebViewImpl::handleGestureEvent
    216         // all WebGestureEvent are converted to PlatformGestureEvent, for completeness and not reach
    217         // the ASSERT_NOT_REACHED() at the end, convert the DoubleTap to a NoType.
    218         m_type = PlatformEvent::NoType;
    219         break;
    220     case WebInputEvent::GestureTwoFingerTap:
    221         m_type = PlatformEvent::GestureTwoFingerTap;
    222         m_area = expandedIntSize(FloatSize(e.data.twoFingerTap.firstFingerWidth / scale, e.data.twoFingerTap.firstFingerHeight / scale));
    223         break;
    224     case WebInputEvent::GestureLongPress:
    225         m_type = PlatformEvent::GestureLongPress;
    226         m_area = expandedIntSize(FloatSize(e.data.longPress.width / scale, e.data.longPress.height / scale));
    227         break;
    228     case WebInputEvent::GestureLongTap:
    229         m_type = PlatformEvent::GestureLongTap;
    230         m_area = expandedIntSize(FloatSize(e.data.longPress.width / scale, e.data.longPress.height / scale));
    231         break;
    232     case WebInputEvent::GesturePinchBegin:
    233         m_type = PlatformEvent::GesturePinchBegin;
    234         break;
    235     case WebInputEvent::GesturePinchEnd:
    236         m_type = PlatformEvent::GesturePinchEnd;
    237         break;
    238     case WebInputEvent::GesturePinchUpdate:
    239         m_type = PlatformEvent::GesturePinchUpdate;
    240         m_data.m_pinchUpdate.m_scale = e.data.pinchUpdate.scale;
    241         break;
    242     default:
    243         ASSERT_NOT_REACHED();
    244     }
    245     m_position = widget->convertFromContainingWindow(IntPoint((e.x - offset.width()) / scale, (e.y - offset.height()) / scale));
    246     m_globalPosition = IntPoint(e.globalX, e.globalY);
    247     m_timestamp = e.timeStampSeconds;
    248 
    249     m_modifiers = 0;
    250     if (e.modifiers & WebInputEvent::ShiftKey)
    251         m_modifiers |= PlatformEvent::ShiftKey;
    252     if (e.modifiers & WebInputEvent::ControlKey)
    253         m_modifiers |= PlatformEvent::CtrlKey;
    254     if (e.modifiers & WebInputEvent::AltKey)
    255         m_modifiers |= PlatformEvent::AltKey;
    256     if (e.modifiers & WebInputEvent::MetaKey)
    257         m_modifiers |= PlatformEvent::MetaKey;
    258 }
    259 
    260 // MakePlatformKeyboardEvent --------------------------------------------------
    261 
    262 inline PlatformEvent::Type toPlatformKeyboardEventType(WebInputEvent::Type type)
    263 {
    264     switch (type) {
    265     case WebInputEvent::KeyUp:
    266         return PlatformEvent::KeyUp;
    267     case WebInputEvent::KeyDown:
    268         return PlatformEvent::KeyDown;
    269     case WebInputEvent::RawKeyDown:
    270         return PlatformEvent::RawKeyDown;
    271     case WebInputEvent::Char:
    272         return PlatformEvent::Char;
    273     default:
    274         ASSERT_NOT_REACHED();
    275     }
    276     return PlatformEvent::KeyDown;
    277 }
    278 
    279 PlatformKeyboardEventBuilder::PlatformKeyboardEventBuilder(const WebKeyboardEvent& e)
    280 {
    281     m_type = toPlatformKeyboardEventType(e.type);
    282     m_text = String(e.text);
    283     m_unmodifiedText = String(e.unmodifiedText);
    284     m_keyIdentifier = String(e.keyIdentifier);
    285     m_autoRepeat = (e.modifiers & WebInputEvent::IsAutoRepeat);
    286     m_nativeVirtualKeyCode = e.nativeKeyCode;
    287     m_isKeypad = (e.modifiers & WebInputEvent::IsKeyPad);
    288     m_isSystemKey = e.isSystemKey;
    289 
    290     m_modifiers = 0;
    291     if (e.modifiers & WebInputEvent::ShiftKey)
    292         m_modifiers |= PlatformEvent::ShiftKey;
    293     if (e.modifiers & WebInputEvent::ControlKey)
    294         m_modifiers |= PlatformEvent::CtrlKey;
    295     if (e.modifiers & WebInputEvent::AltKey)
    296         m_modifiers |= PlatformEvent::AltKey;
    297     if (e.modifiers & WebInputEvent::MetaKey)
    298         m_modifiers |= PlatformEvent::MetaKey;
    299 
    300     // FIXME: PlatformKeyboardEvents expect a locational version of the keycode (e.g. VK_LSHIFT
    301     // instead of VK_SHIFT). This should be changed so the location/keycode are stored separately,
    302     // as in other places in the code.
    303     m_windowsVirtualKeyCode = e.windowsKeyCode;
    304     if (e.windowsKeyCode == VK_SHIFT) {
    305         if (e.modifiers & WebInputEvent::IsLeft)
    306             m_windowsVirtualKeyCode = VK_LSHIFT;
    307         else if (e.modifiers & WebInputEvent::IsRight)
    308             m_windowsVirtualKeyCode = VK_RSHIFT;
    309     } else if (e.windowsKeyCode == VK_CONTROL) {
    310         if (e.modifiers & WebInputEvent::IsLeft)
    311             m_windowsVirtualKeyCode = VK_LCONTROL;
    312         else if (e.modifiers & WebInputEvent::IsRight)
    313             m_windowsVirtualKeyCode = VK_RCONTROL;
    314     } else if (e.windowsKeyCode == VK_MENU) {
    315         if (e.modifiers & WebInputEvent::IsLeft)
    316             m_windowsVirtualKeyCode = VK_LMENU;
    317         else if (e.modifiers & WebInputEvent::IsRight)
    318             m_windowsVirtualKeyCode = VK_RMENU;
    319     }
    320 
    321 }
    322 
    323 void PlatformKeyboardEventBuilder::setKeyType(Type type)
    324 {
    325     // According to the behavior of Webkit in Windows platform,
    326     // we need to convert KeyDown to RawKeydown and Char events
    327     // See WebKit/WebKit/Win/WebView.cpp
    328     ASSERT(m_type == KeyDown);
    329     ASSERT(type == RawKeyDown || type == Char);
    330     m_type = type;
    331 
    332     if (type == RawKeyDown) {
    333         m_text = String();
    334         m_unmodifiedText = String();
    335     } else {
    336         m_keyIdentifier = String();
    337         m_windowsVirtualKeyCode = 0;
    338     }
    339 }
    340 
    341 // Please refer to bug http://b/issue?id=961192, which talks about Webkit
    342 // keyboard event handling changes. It also mentions the list of keys
    343 // which don't have associated character events.
    344 bool PlatformKeyboardEventBuilder::isCharacterKey() const
    345 {
    346     switch (windowsVirtualKeyCode()) {
    347     case VKEY_BACK:
    348     case VKEY_ESCAPE:
    349         return false;
    350     }
    351     return true;
    352 }
    353 
    354 inline PlatformEvent::Type toPlatformTouchEventType(const WebInputEvent::Type type)
    355 {
    356     switch (type) {
    357     case WebInputEvent::TouchStart:
    358         return PlatformEvent::TouchStart;
    359     case WebInputEvent::TouchMove:
    360         return PlatformEvent::TouchMove;
    361     case WebInputEvent::TouchEnd:
    362         return PlatformEvent::TouchEnd;
    363     case WebInputEvent::TouchCancel:
    364         return PlatformEvent::TouchCancel;
    365     default:
    366         ASSERT_NOT_REACHED();
    367     }
    368     return PlatformEvent::TouchStart;
    369 }
    370 
    371 inline PlatformTouchPoint::State toPlatformTouchPointState(const WebTouchPoint::State state)
    372 {
    373     switch (state) {
    374     case WebTouchPoint::StateReleased:
    375         return PlatformTouchPoint::TouchReleased;
    376     case WebTouchPoint::StatePressed:
    377         return PlatformTouchPoint::TouchPressed;
    378     case WebTouchPoint::StateMoved:
    379         return PlatformTouchPoint::TouchMoved;
    380     case WebTouchPoint::StateStationary:
    381         return PlatformTouchPoint::TouchStationary;
    382     case WebTouchPoint::StateCancelled:
    383         return PlatformTouchPoint::TouchCancelled;
    384     case WebTouchPoint::StateUndefined:
    385         ASSERT_NOT_REACHED();
    386     }
    387     return PlatformTouchPoint::TouchReleased;
    388 }
    389 
    390 inline WebTouchPoint::State toWebTouchPointState(const AtomicString& type)
    391 {
    392     if (type == EventTypeNames::touchend)
    393         return WebTouchPoint::StateReleased;
    394     if (type == EventTypeNames::touchcancel)
    395         return WebTouchPoint::StateCancelled;
    396     if (type == EventTypeNames::touchstart)
    397         return WebTouchPoint::StatePressed;
    398     if (type == EventTypeNames::touchmove)
    399         return WebTouchPoint::StateMoved;
    400     return WebTouchPoint::StateUndefined;
    401 }
    402 
    403 PlatformTouchPointBuilder::PlatformTouchPointBuilder(Widget* widget, const WebTouchPoint& point)
    404 {
    405     float scale = widgetInputEventsScaleFactor(widget);
    406     IntSize offset = widgetInputEventsOffset(widget);
    407     m_id = point.id;
    408     m_state = toPlatformTouchPointState(point.state);
    409     m_pos = widget->convertFromContainingWindow(IntPoint((point.position.x - offset.width()) / scale, (point.position.y - offset.height()) / scale));
    410     m_screenPos = point.screenPosition;
    411     m_radiusY = point.radiusY / scale;
    412     m_radiusX = point.radiusX / scale;
    413     m_rotationAngle = point.rotationAngle;
    414     m_force = point.force;
    415 }
    416 
    417 PlatformTouchEventBuilder::PlatformTouchEventBuilder(Widget* widget, const WebTouchEvent& event)
    418 {
    419     m_type = toPlatformTouchEventType(event.type);
    420 
    421     m_modifiers = 0;
    422     if (event.modifiers & WebInputEvent::ShiftKey)
    423         m_modifiers |= PlatformEvent::ShiftKey;
    424     if (event.modifiers & WebInputEvent::ControlKey)
    425         m_modifiers |= PlatformEvent::CtrlKey;
    426     if (event.modifiers & WebInputEvent::AltKey)
    427         m_modifiers |= PlatformEvent::AltKey;
    428     if (event.modifiers & WebInputEvent::MetaKey)
    429         m_modifiers |= PlatformEvent::MetaKey;
    430 
    431     m_timestamp = event.timeStampSeconds;
    432 
    433     for (unsigned i = 0; i < event.touchesLength; ++i)
    434         m_touchPoints.append(PlatformTouchPointBuilder(widget, event.touches[i]));
    435 }
    436 
    437 static int getWebInputModifiers(const UIEventWithKeyState& event)
    438 {
    439     int modifiers = 0;
    440     if (event.ctrlKey())
    441         modifiers |= WebInputEvent::ControlKey;
    442     if (event.shiftKey())
    443         modifiers |= WebInputEvent::ShiftKey;
    444     if (event.altKey())
    445         modifiers |= WebInputEvent::AltKey;
    446     if (event.metaKey())
    447         modifiers |= WebInputEvent::MetaKey;
    448     return modifiers;
    449 }
    450 
    451 static IntPoint convertAbsoluteLocationForRenderObject(const LayoutPoint& location, const WebCore::RenderObject& renderObject)
    452 {
    453     return roundedIntPoint(renderObject.absoluteToLocal(location, UseTransforms));
    454 }
    455 
    456 static void updateWebMouseEventFromWebCoreMouseEvent(const MouseRelatedEvent& event, const Widget& widget, const WebCore::RenderObject& renderObject, WebMouseEvent& webEvent)
    457 {
    458     webEvent.timeStampSeconds = event.timeStamp() / millisPerSecond;
    459     webEvent.modifiers = getWebInputModifiers(event);
    460 
    461     ScrollView* view =  toScrollView(widget.parent());
    462     IntPoint windowPoint = IntPoint(event.absoluteLocation().x(), event.absoluteLocation().y());
    463     if (view)
    464         windowPoint = view->contentsToWindow(windowPoint);
    465     webEvent.globalX = event.screenX();
    466     webEvent.globalY = event.screenY();
    467     webEvent.windowX = windowPoint.x();
    468     webEvent.windowY = windowPoint.y();
    469     IntPoint localPoint = convertAbsoluteLocationForRenderObject(event.absoluteLocation(), renderObject);
    470     webEvent.x = localPoint.x();
    471     webEvent.y = localPoint.y();
    472 }
    473 
    474 WebMouseEventBuilder::WebMouseEventBuilder(const Widget* widget, const WebCore::RenderObject* renderObject, const MouseEvent& event)
    475 {
    476     if (event.type() == EventTypeNames::mousemove)
    477         type = WebInputEvent::MouseMove;
    478     else if (event.type() == EventTypeNames::mouseout)
    479         type = WebInputEvent::MouseLeave;
    480     else if (event.type() == EventTypeNames::mouseover)
    481         type = WebInputEvent::MouseEnter;
    482     else if (event.type() == EventTypeNames::mousedown)
    483         type = WebInputEvent::MouseDown;
    484     else if (event.type() == EventTypeNames::mouseup)
    485         type = WebInputEvent::MouseUp;
    486     else if (event.type() == EventTypeNames::contextmenu)
    487         type = WebInputEvent::ContextMenu;
    488     else
    489         return; // Skip all other mouse events.
    490 
    491     updateWebMouseEventFromWebCoreMouseEvent(event, *widget, *renderObject, *this);
    492 
    493     switch (event.button()) {
    494     case LeftButton:
    495         button = WebMouseEvent::ButtonLeft;
    496         break;
    497     case MiddleButton:
    498         button = WebMouseEvent::ButtonMiddle;
    499         break;
    500     case RightButton:
    501         button = WebMouseEvent::ButtonRight;
    502         break;
    503     }
    504     if (event.buttonDown()) {
    505         switch (event.button()) {
    506         case LeftButton:
    507             modifiers |= WebInputEvent::LeftButtonDown;
    508             break;
    509         case MiddleButton:
    510             modifiers |= WebInputEvent::MiddleButtonDown;
    511             break;
    512         case RightButton:
    513             modifiers |= WebInputEvent::RightButtonDown;
    514             break;
    515         }
    516     } else
    517         button = WebMouseEvent::ButtonNone;
    518     movementX = event.webkitMovementX();
    519     movementY = event.webkitMovementY();
    520     clickCount = event.detail();
    521 }
    522 
    523 WebMouseEventBuilder::WebMouseEventBuilder(const Widget* widget, const WebCore::RenderObject* renderObject, const TouchEvent& event)
    524 {
    525     if (!event.touches())
    526         return;
    527     if (event.touches()->length() != 1) {
    528         if (event.touches()->length() || event.type() != EventTypeNames::touchend || !event.changedTouches() || event.changedTouches()->length() != 1)
    529             return;
    530     }
    531 
    532     const Touch* touch = event.touches()->length() == 1 ? event.touches()->item(0) : event.changedTouches()->item(0);
    533     if (touch->identifier())
    534         return;
    535 
    536     if (event.type() == EventTypeNames::touchstart)
    537         type = MouseDown;
    538     else if (event.type() == EventTypeNames::touchmove)
    539         type = MouseMove;
    540     else if (event.type() == EventTypeNames::touchend)
    541         type = MouseUp;
    542     else
    543         return;
    544 
    545     updateWebMouseEventFromWebCoreMouseEvent(event, *widget, *renderObject, *this);
    546 
    547     button = WebMouseEvent::ButtonLeft;
    548     modifiers |= WebInputEvent::LeftButtonDown;
    549     clickCount = (type == MouseDown || type == MouseUp);
    550 
    551     IntPoint localPoint = convertAbsoluteLocationForRenderObject(touch->absoluteLocation(), *renderObject);
    552     x = localPoint.x();
    553     y = localPoint.y();
    554 }
    555 
    556 WebMouseEventBuilder::WebMouseEventBuilder(const WebCore::Widget* widget, const WebCore::PlatformMouseEvent& event)
    557 {
    558     switch (event.type()) {
    559     case PlatformEvent::MouseMoved:
    560         type = MouseMove;
    561         break;
    562     case PlatformEvent::MousePressed:
    563         type = MouseDown;
    564         break;
    565     case PlatformEvent::MouseReleased:
    566         type = MouseUp;
    567         break;
    568     default:
    569         ASSERT_NOT_REACHED();
    570         type = Undefined;
    571         return;
    572     }
    573 
    574     modifiers = 0;
    575     if (event.modifiers() & PlatformEvent::ShiftKey)
    576         modifiers |= ShiftKey;
    577     if (event.modifiers() & PlatformEvent::CtrlKey)
    578         modifiers |= ControlKey;
    579     if (event.modifiers() & PlatformEvent::AltKey)
    580         modifiers |= AltKey;
    581     if (event.modifiers() & PlatformEvent::MetaKey)
    582         modifiers |= MetaKey;
    583 
    584     timeStampSeconds = event.timestamp();
    585 
    586     // FIXME: Widget is always toplevel, unless it's a popup. We may be able
    587     // to get rid of this once we abstract popups into a WebKit API.
    588     IntPoint position = widget->convertToContainingWindow(event.position());
    589     float scale = widgetInputEventsScaleFactor(widget);
    590     position.scale(scale, scale);
    591     x = position.x();
    592     y = position.y();
    593     globalX = event.globalPosition().x();
    594     globalY = event.globalPosition().y();
    595     movementX = event.movementDelta().x() * scale;
    596     movementY = event.movementDelta().y() * scale;
    597 
    598     button = static_cast<Button>(event.button());
    599     clickCount = event.clickCount();
    600 }
    601 
    602 WebMouseWheelEventBuilder::WebMouseWheelEventBuilder(const Widget* widget, const WebCore::RenderObject* renderObject, const WheelEvent& event)
    603 {
    604     if (event.type() != EventTypeNames::wheel && event.type() != EventTypeNames::mousewheel)
    605         return;
    606     type = WebInputEvent::MouseWheel;
    607     updateWebMouseEventFromWebCoreMouseEvent(event, *widget, *renderObject, *this);
    608     deltaX = -event.deltaX();
    609     deltaY = -event.deltaY();
    610     wheelTicksX = event.ticksX();
    611     wheelTicksY = event.ticksY();
    612     scrollByPage = event.deltaMode() == WheelEvent::DOM_DELTA_PAGE;
    613 }
    614 
    615 WebKeyboardEventBuilder::WebKeyboardEventBuilder(const KeyboardEvent& event)
    616 {
    617     if (event.type() == EventTypeNames::keydown)
    618         type = KeyDown;
    619     else if (event.type() == EventTypeNames::keyup)
    620         type = WebInputEvent::KeyUp;
    621     else if (event.type() == EventTypeNames::keypress)
    622         type = WebInputEvent::Char;
    623     else
    624         return; // Skip all other keyboard events.
    625 
    626     modifiers = getWebInputModifiers(event);
    627     if (event.location() == KeyboardEvent::DOM_KEY_LOCATION_NUMPAD)
    628         modifiers |= WebInputEvent::IsKeyPad;
    629     else if (event.location() == KeyboardEvent::DOM_KEY_LOCATION_LEFT)
    630         modifiers |= WebInputEvent::IsLeft;
    631     else if (event.location() == KeyboardEvent::DOM_KEY_LOCATION_RIGHT)
    632         modifiers |= WebInputEvent::IsRight;
    633 
    634     timeStampSeconds = event.timeStamp() / millisPerSecond;
    635     windowsKeyCode = event.keyCode();
    636 
    637     // The platform keyevent does not exist if the event was created using
    638     // initKeyboardEvent.
    639     if (!event.keyEvent())
    640         return;
    641     nativeKeyCode = event.keyEvent()->nativeVirtualKeyCode();
    642     unsigned numberOfCharacters = std::min(event.keyEvent()->text().length(), static_cast<unsigned>(textLengthCap));
    643     for (unsigned i = 0; i < numberOfCharacters; ++i) {
    644         text[i] = event.keyEvent()->text()[i];
    645         unmodifiedText[i] = event.keyEvent()->unmodifiedText()[i];
    646     }
    647     memcpy(keyIdentifier, event.keyIdentifier().ascii().data(), event.keyIdentifier().length());
    648 }
    649 
    650 WebInputEvent::Type toWebKeyboardEventType(PlatformEvent::Type type)
    651 {
    652     switch (type) {
    653     case PlatformEvent::KeyUp:
    654         return WebInputEvent::KeyUp;
    655     case PlatformEvent::KeyDown:
    656         return WebInputEvent::KeyDown;
    657     case PlatformEvent::RawKeyDown:
    658         return WebInputEvent::RawKeyDown;
    659     case PlatformEvent::Char:
    660         return WebInputEvent::Char;
    661     default:
    662         return WebInputEvent::Undefined;
    663     }
    664 }
    665 
    666 int toWebKeyboardEventModifiers(int modifiers)
    667 {
    668     int newModifiers = 0;
    669     if (modifiers & PlatformEvent::ShiftKey)
    670         newModifiers |= WebInputEvent::ShiftKey;
    671     if (modifiers & PlatformEvent::CtrlKey)
    672         newModifiers |= WebInputEvent::ControlKey;
    673     if (modifiers & PlatformEvent::AltKey)
    674         newModifiers |= WebInputEvent::AltKey;
    675     if (modifiers & PlatformEvent::MetaKey)
    676         newModifiers |= WebInputEvent::MetaKey;
    677     return newModifiers;
    678 }
    679 
    680 WebKeyboardEventBuilder::WebKeyboardEventBuilder(const WebCore::PlatformKeyboardEvent& event)
    681 {
    682     type = toWebKeyboardEventType(event.type());
    683     modifiers = toWebKeyboardEventModifiers(event.modifiers());
    684     if (event.isAutoRepeat())
    685         modifiers |= WebInputEvent::IsAutoRepeat;
    686     if (event.isKeypad())
    687         modifiers |= WebInputEvent::IsKeyPad;
    688     isSystemKey = event.isSystemKey();
    689     nativeKeyCode = event.nativeVirtualKeyCode();
    690 
    691     windowsKeyCode = windowsKeyCodeWithoutLocation(event.windowsVirtualKeyCode());
    692     modifiers |= locationModifiersFromWindowsKeyCode(event.windowsVirtualKeyCode());
    693 
    694     event.text().copyTo(text, 0, textLengthCap);
    695     event.unmodifiedText().copyTo(unmodifiedText, 0, textLengthCap);
    696     memcpy(keyIdentifier, event.keyIdentifier().ascii().data(), std::min(static_cast<unsigned>(keyIdentifierLengthCap), event.keyIdentifier().length()));
    697 }
    698 
    699 static void addTouchPoints(const Widget* widget, const AtomicString& touchType, TouchList* touches, WebTouchPoint* touchPoints, unsigned* touchPointsLength, const WebCore::RenderObject* renderObject)
    700 {
    701     unsigned numberOfTouches = std::min(touches->length(), static_cast<unsigned>(WebTouchEvent::touchesLengthCap));
    702     for (unsigned i = 0; i < numberOfTouches; ++i) {
    703         const Touch* touch = touches->item(i);
    704 
    705         WebTouchPoint point;
    706         point.id = touch->identifier();
    707         point.screenPosition = WebPoint(touch->screenX(), touch->screenY());
    708         point.position = convertAbsoluteLocationForRenderObject(touch->absoluteLocation(), *renderObject);
    709         point.radiusX = touch->webkitRadiusX();
    710         point.radiusY = touch->webkitRadiusY();
    711         point.rotationAngle = touch->webkitRotationAngle();
    712         point.force = touch->webkitForce();
    713         point.state = toWebTouchPointState(touchType);
    714 
    715         touchPoints[i] = point;
    716     }
    717     *touchPointsLength = numberOfTouches;
    718 }
    719 
    720 WebTouchEventBuilder::WebTouchEventBuilder(const Widget* widget, const WebCore::RenderObject* renderObject, const TouchEvent& event)
    721 {
    722     if (event.type() == EventTypeNames::touchstart)
    723         type = TouchStart;
    724     else if (event.type() == EventTypeNames::touchmove)
    725         type = TouchMove;
    726     else if (event.type() == EventTypeNames::touchend)
    727         type = TouchEnd;
    728     else if (event.type() == EventTypeNames::touchcancel)
    729         type = TouchCancel;
    730     else {
    731         ASSERT_NOT_REACHED();
    732         type = Undefined;
    733         return;
    734     }
    735 
    736     modifiers = getWebInputModifiers(event);
    737     timeStampSeconds = event.timeStamp() / millisPerSecond;
    738 
    739     addTouchPoints(widget, event.type(), event.touches(), touches, &touchesLength, renderObject);
    740     addTouchPoints(widget, event.type(), event.changedTouches(), changedTouches, &changedTouchesLength, renderObject);
    741     addTouchPoints(widget, event.type(), event.targetTouches(), targetTouches, &targetTouchesLength, renderObject);
    742 }
    743 
    744 WebGestureEventBuilder::WebGestureEventBuilder(const Widget* widget, const WebCore::RenderObject* renderObject, const GestureEvent& event)
    745 {
    746     if (event.type() == EventTypeNames::gestureshowpress)
    747         type = GestureShowPress;
    748     else if (event.type() == EventTypeNames::gesturetapdown)
    749         type = GestureTapDown;
    750     else if (event.type() == EventTypeNames::gesturescrollstart)
    751         type = GestureScrollBegin;
    752     else if (event.type() == EventTypeNames::gesturescrollend)
    753         type = GestureScrollEnd;
    754     else if (event.type() == EventTypeNames::gesturescrollupdate) {
    755         type = GestureScrollUpdate;
    756         data.scrollUpdate.deltaX = event.deltaX();
    757         data.scrollUpdate.deltaY = event.deltaY();
    758     } else if (event.type() == EventTypeNames::gesturetap) {
    759         type = GestureTap;
    760         data.tap.tapCount = 1;
    761     }
    762 
    763     timeStampSeconds = event.timeStamp() / millisPerSecond;
    764     modifiers = getWebInputModifiers(event);
    765 
    766     globalX = event.screenX();
    767     globalY = event.screenY();
    768     IntPoint localPoint = convertAbsoluteLocationForRenderObject(event.absoluteLocation(), *renderObject);
    769     x = localPoint.x();
    770     y = localPoint.y();
    771 }
    772 
    773 } // namespace blink
    774