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