Home | History | Annotate | Download | only in events
      1 /*
      2  * Copyright (C) 2001 Peter Kelly (pmk (at) post.com)
      3  * Copyright (C) 2001 Tobias Anton (anton (at) stud.fbi.fh-darmstadt.de)
      4  * Copyright (C) 2006 Samuel Weinig (sam.weinig (at) gmail.com)
      5  * Copyright (C) 2003, 2005, 2006, 2008 Apple Inc. All rights reserved.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Library General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Library General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Library General Public License
     18  * along with this library; see the file COPYING.LIB.  If not, write to
     19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20  * Boston, MA 02110-1301, USA.
     21  */
     22 
     23 #include "config.h"
     24 #include "core/events/MouseEvent.h"
     25 
     26 #include "core/clipboard/DataTransfer.h"
     27 #include "core/dom/Element.h"
     28 #include "core/events/EventDispatcher.h"
     29 #include "platform/PlatformMouseEvent.h"
     30 
     31 namespace blink {
     32 
     33 MouseEventInit::MouseEventInit()
     34     : screenX(0)
     35     , screenY(0)
     36     , clientX(0)
     37     , clientY(0)
     38     , ctrlKey(false)
     39     , altKey(false)
     40     , shiftKey(false)
     41     , metaKey(false)
     42     , button(0)
     43     , relatedTarget(nullptr)
     44 {
     45 }
     46 
     47 PassRefPtrWillBeRawPtr<MouseEvent> MouseEvent::create(const AtomicString& type, const MouseEventInit& initializer)
     48 {
     49     return adoptRefWillBeNoop(new MouseEvent(type, initializer));
     50 }
     51 
     52 PassRefPtrWillBeRawPtr<MouseEvent> MouseEvent::create(const AtomicString& eventType, PassRefPtrWillBeRawPtr<AbstractView> view, const PlatformMouseEvent& event, int detail, PassRefPtrWillBeRawPtr<Node> relatedTarget)
     53 {
     54     ASSERT(event.type() == PlatformEvent::MouseMoved || event.button() != NoButton);
     55 
     56     bool isMouseEnterOrLeave = eventType == EventTypeNames::mouseenter || eventType == EventTypeNames::mouseleave;
     57     bool isCancelable = !isMouseEnterOrLeave;
     58     bool isBubbling = !isMouseEnterOrLeave;
     59 
     60     return MouseEvent::create(
     61         eventType, isBubbling, isCancelable, view,
     62         detail, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
     63         event.movementDelta().x(), event.movementDelta().y(),
     64         event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), event.button(),
     65         relatedTarget, nullptr, false, event.syntheticEventType());
     66 }
     67 
     68 PassRefPtrWillBeRawPtr<MouseEvent> MouseEvent::create(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtrWillBeRawPtr<AbstractView> view,
     69     int detail, int screenX, int screenY, int pageX, int pageY,
     70     int movementX, int movementY,
     71     bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button,
     72     PassRefPtrWillBeRawPtr<EventTarget> relatedTarget, PassRefPtrWillBeRawPtr<DataTransfer> dataTransfer, bool isSimulated, PlatformMouseEvent::SyntheticEventType syntheticEventType)
     73 {
     74     return adoptRefWillBeNoop(new MouseEvent(type, canBubble, cancelable, view,
     75         detail, screenX, screenY, pageX, pageY,
     76         movementX, movementY,
     77         ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget, dataTransfer, isSimulated, syntheticEventType));
     78 }
     79 
     80 MouseEvent::MouseEvent()
     81     : m_button(0)
     82     , m_buttonDown(false)
     83 {
     84 }
     85 
     86 MouseEvent::MouseEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtrWillBeRawPtr<AbstractView> view,
     87     int detail, int screenX, int screenY, int pageX, int pageY,
     88     int movementX, int movementY,
     89     bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
     90     unsigned short button, PassRefPtrWillBeRawPtr<EventTarget> relatedTarget,
     91     PassRefPtrWillBeRawPtr<DataTransfer> dataTransfer, bool isSimulated, PlatformMouseEvent::SyntheticEventType syntheticEventType)
     92     : MouseRelatedEvent(eventType, canBubble, cancelable, view, detail, IntPoint(screenX, screenY),
     93                         IntPoint(pageX, pageY),
     94                         IntPoint(movementX, movementY),
     95                         ctrlKey, altKey, shiftKey, metaKey, isSimulated)
     96     , m_button(button == (unsigned short)-1 ? 0 : button)
     97     , m_buttonDown(button != (unsigned short)-1)
     98     , m_relatedTarget(relatedTarget)
     99     , m_dataTransfer(dataTransfer)
    100     , m_syntheticEventType(syntheticEventType)
    101 {
    102 }
    103 
    104 MouseEvent::MouseEvent(const AtomicString& eventType, const MouseEventInit& initializer)
    105     : MouseRelatedEvent(eventType, initializer.bubbles, initializer.cancelable, initializer.view, initializer.detail, IntPoint(initializer.screenX, initializer.screenY),
    106         IntPoint(0 /* pageX */, 0 /* pageY */),
    107         IntPoint(0 /* movementX */, 0 /* movementY */),
    108         initializer.ctrlKey, initializer.altKey, initializer.shiftKey, initializer.metaKey, false /* isSimulated */)
    109     , m_button(initializer.button == (unsigned short)-1 ? 0 : initializer.button)
    110     , m_buttonDown(initializer.button != (unsigned short)-1)
    111     , m_relatedTarget(initializer.relatedTarget)
    112     , m_dataTransfer(nullptr)
    113 {
    114     initCoordinates(IntPoint(initializer.clientX, initializer.clientY));
    115 }
    116 
    117 MouseEvent::~MouseEvent()
    118 {
    119 }
    120 
    121 void MouseEvent::initMouseEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtrWillBeRawPtr<AbstractView> view,
    122                                 int detail, int screenX, int screenY, int clientX, int clientY,
    123                                 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
    124                                 unsigned short button, PassRefPtrWillBeRawPtr<EventTarget> relatedTarget)
    125 {
    126     if (dispatched())
    127         return;
    128 
    129     initUIEvent(type, canBubble, cancelable, view, detail);
    130 
    131     m_screenLocation = IntPoint(screenX, screenY);
    132     m_ctrlKey = ctrlKey;
    133     m_altKey = altKey;
    134     m_shiftKey = shiftKey;
    135     m_metaKey = metaKey;
    136     m_button = button == (unsigned short)-1 ? 0 : button;
    137     m_buttonDown = button != (unsigned short)-1;
    138     m_relatedTarget = relatedTarget;
    139 
    140     initCoordinates(IntPoint(clientX, clientY));
    141 
    142     // FIXME: m_isSimulated is not set to false here.
    143     // FIXME: m_dataTransfer is not set to nullptr here.
    144 }
    145 
    146 const AtomicString& MouseEvent::interfaceName() const
    147 {
    148     return EventNames::MouseEvent;
    149 }
    150 
    151 bool MouseEvent::isMouseEvent() const
    152 {
    153     return true;
    154 }
    155 
    156 bool MouseEvent::isDragEvent() const
    157 {
    158     const AtomicString& t = type();
    159     return t == EventTypeNames::dragenter || t == EventTypeNames::dragover || t == EventTypeNames::dragleave || t == EventTypeNames::drop
    160                || t == EventTypeNames::dragstart|| t == EventTypeNames::drag || t == EventTypeNames::dragend;
    161 }
    162 
    163 int MouseEvent::which() const
    164 {
    165     // For the DOM, the return values for left, middle and right mouse buttons are 0, 1, 2, respectively.
    166     // For the Netscape "which" property, the return values for left, middle and right mouse buttons are 1, 2, 3, respectively.
    167     // So we must add 1.
    168     if (!m_buttonDown)
    169         return 0;
    170     return m_button + 1;
    171 }
    172 
    173 Node* MouseEvent::toElement() const
    174 {
    175     // MSIE extension - "the object toward which the user is moving the mouse pointer"
    176     if (type() == EventTypeNames::mouseout || type() == EventTypeNames::mouseleave)
    177         return relatedTarget() ? relatedTarget()->toNode() : 0;
    178 
    179     return target() ? target()->toNode() : 0;
    180 }
    181 
    182 Node* MouseEvent::fromElement() const
    183 {
    184     // MSIE extension - "object from which activation or the mouse pointer is exiting during the event" (huh?)
    185     if (type() != EventTypeNames::mouseout && type() != EventTypeNames::mouseleave)
    186         return relatedTarget() ? relatedTarget()->toNode() : 0;
    187 
    188     return target() ? target()->toNode() : 0;
    189 }
    190 
    191 void MouseEvent::trace(Visitor* visitor)
    192 {
    193     visitor->trace(m_relatedTarget);
    194     visitor->trace(m_dataTransfer);
    195     MouseRelatedEvent::trace(visitor);
    196 }
    197 
    198 PassRefPtrWillBeRawPtr<SimulatedMouseEvent> SimulatedMouseEvent::create(const AtomicString& eventType, PassRefPtrWillBeRawPtr<AbstractView> view, PassRefPtrWillBeRawPtr<Event> underlyingEvent)
    199 {
    200     return adoptRefWillBeNoop(new SimulatedMouseEvent(eventType, view, underlyingEvent));
    201 }
    202 
    203 SimulatedMouseEvent::~SimulatedMouseEvent()
    204 {
    205 }
    206 
    207 SimulatedMouseEvent::SimulatedMouseEvent(const AtomicString& eventType, PassRefPtrWillBeRawPtr<AbstractView> view, PassRefPtrWillBeRawPtr<Event> underlyingEvent)
    208     : MouseEvent(eventType, true, true, view, 0, 0, 0, 0, 0, 0, 0, false, false, false, false, 0,
    209         nullptr, nullptr, true, PlatformMouseEvent::RealOrIndistinguishable)
    210 {
    211     if (UIEventWithKeyState* keyStateEvent = findEventWithKeyState(underlyingEvent.get())) {
    212         m_ctrlKey = keyStateEvent->ctrlKey();
    213         m_altKey = keyStateEvent->altKey();
    214         m_shiftKey = keyStateEvent->shiftKey();
    215         m_metaKey = keyStateEvent->metaKey();
    216     }
    217     setUnderlyingEvent(underlyingEvent);
    218 
    219     if (this->underlyingEvent() && this->underlyingEvent()->isMouseEvent()) {
    220         MouseEvent* mouseEvent = toMouseEvent(this->underlyingEvent());
    221         m_screenLocation = mouseEvent->screenLocation();
    222         initCoordinates(mouseEvent->clientLocation());
    223     }
    224 }
    225 
    226 void SimulatedMouseEvent::trace(Visitor* visitor)
    227 {
    228     MouseEvent::trace(visitor);
    229 }
    230 
    231 PassRefPtrWillBeRawPtr<MouseEventDispatchMediator> MouseEventDispatchMediator::create(PassRefPtrWillBeRawPtr<MouseEvent> mouseEvent, MouseEventType mouseEventType)
    232 {
    233     return adoptRefWillBeNoop(new MouseEventDispatchMediator(mouseEvent, mouseEventType));
    234 }
    235 
    236 MouseEventDispatchMediator::MouseEventDispatchMediator(PassRefPtrWillBeRawPtr<MouseEvent> mouseEvent, MouseEventType mouseEventType)
    237     : EventDispatchMediator(mouseEvent), m_mouseEventType(mouseEventType)
    238 {
    239 }
    240 
    241 MouseEvent* MouseEventDispatchMediator::event() const
    242 {
    243     return toMouseEvent(EventDispatchMediator::event());
    244 }
    245 
    246 bool MouseEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const
    247 {
    248     if (isSyntheticMouseEvent()) {
    249         event()->eventPath().adjustForRelatedTarget(dispatcher->node(), event()->relatedTarget());
    250         return dispatcher->dispatch();
    251     }
    252 
    253     if (isDisabledFormControl(dispatcher->node()))
    254         return false;
    255 
    256     if (event()->type().isEmpty())
    257         return true; // Shouldn't happen.
    258 
    259     ASSERT(!event()->target() || event()->target() != event()->relatedTarget());
    260 
    261     EventTarget* relatedTarget = event()->relatedTarget();
    262     event()->eventPath().adjustForRelatedTarget(dispatcher->node(), relatedTarget);
    263 
    264     dispatcher->dispatch();
    265     bool swallowEvent = event()->defaultHandled() || event()->defaultPrevented();
    266 
    267     if (event()->type() != EventTypeNames::click || event()->detail() != 2)
    268         return !swallowEvent;
    269 
    270     // Special case: If it's a double click event, we also send the dblclick event. This is not part
    271     // of the DOM specs, but is used for compatibility with the ondblclick="" attribute. This is treated
    272     // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same.
    273     RefPtrWillBeRawPtr<MouseEvent> doubleClickEvent = MouseEvent::create();
    274     doubleClickEvent->initMouseEvent(EventTypeNames::dblclick, event()->bubbles(), event()->cancelable(), event()->view(),
    275                                      event()->detail(), event()->screenX(), event()->screenY(), event()->clientX(), event()->clientY(),
    276                                      event()->ctrlKey(), event()->altKey(), event()->shiftKey(), event()->metaKey(),
    277                                      event()->button(), relatedTarget);
    278     if (event()->defaultHandled())
    279         doubleClickEvent->setDefaultHandled();
    280     EventDispatcher::dispatchEvent(dispatcher->node(), MouseEventDispatchMediator::create(doubleClickEvent));
    281     if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented())
    282         return false;
    283     return !swallowEvent;
    284 }
    285 
    286 } // namespace blink
    287