2 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
3 * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
4 * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
5 * Copyright (C) 2003, 2005, 2006, 2008 Apple Inc. All rights reserved.
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.
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.
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.
24 #include "core/events/MouseEvent.h"
26 #include "core/clipboard/DataTransfer.h"
27 #include "core/dom/Element.h"
28 #include "core/events/EventDispatcher.h"
29 #include "platform/PlatformMouseEvent.h"
33 MouseEventInit::MouseEventInit()
43 , relatedTarget(nullptr)
47 PassRefPtrWillBeRawPtr<MouseEvent> MouseEvent::create(const AtomicString& type, const MouseEventInit& initializer)
49 return adoptRefWillBeNoop(new MouseEvent(type, initializer));
52 PassRefPtrWillBeRawPtr<MouseEvent> MouseEvent::create(const AtomicString& eventType, PassRefPtrWillBeRawPtr<AbstractView> view, const PlatformMouseEvent& event, int detail, PassRefPtrWillBeRawPtr<Node> relatedTarget)
54 ASSERT(event.type() == PlatformEvent::MouseMoved || event.button() != NoButton);
56 bool isMouseEnterOrLeave = eventType == EventTypeNames::mouseenter || eventType == EventTypeNames::mouseleave;
57 bool isCancelable = !isMouseEnterOrLeave;
58 bool isBubbling = !isMouseEnterOrLeave;
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);
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)
74 return adoptRefWillBeNoop(new MouseEvent(type, canBubble, cancelable, view,
75 detail, screenX, screenY, pageX, pageY,
77 ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget, dataTransfer, isSimulated));
80 MouseEvent::MouseEvent()
84 ScriptWrappable::init(this);
87 MouseEvent::MouseEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtrWillBeRawPtr<AbstractView> view,
88 int detail, int screenX, int screenY, int pageX, int pageY,
89 int movementX, int movementY,
90 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
91 unsigned short button, PassRefPtrWillBeRawPtr<EventTarget> relatedTarget,
92 PassRefPtrWillBeRawPtr<DataTransfer> dataTransfer, bool isSimulated)
93 : MouseRelatedEvent(eventType, canBubble, cancelable, view, detail, IntPoint(screenX, screenY),
94 IntPoint(pageX, pageY),
95 IntPoint(movementX, movementY),
96 ctrlKey, altKey, shiftKey, metaKey, isSimulated)
97 , m_button(button == (unsigned short)-1 ? 0 : button)
98 , m_buttonDown(button != (unsigned short)-1)
99 , m_relatedTarget(relatedTarget)
100 , m_dataTransfer(dataTransfer)
102 ScriptWrappable::init(this);
105 MouseEvent::MouseEvent(const AtomicString& eventType, const MouseEventInit& initializer)
106 : MouseRelatedEvent(eventType, initializer.bubbles, initializer.cancelable, initializer.view, initializer.detail, IntPoint(initializer.screenX, initializer.screenY),
107 IntPoint(0 /* pageX */, 0 /* pageY */),
108 IntPoint(0 /* movementX */, 0 /* movementY */),
109 initializer.ctrlKey, initializer.altKey, initializer.shiftKey, initializer.metaKey, false /* isSimulated */)
110 , m_button(initializer.button == (unsigned short)-1 ? 0 : initializer.button)
111 , m_buttonDown(initializer.button != (unsigned short)-1)
112 , m_relatedTarget(initializer.relatedTarget)
113 , m_dataTransfer(nullptr)
115 ScriptWrappable::init(this);
116 initCoordinates(IntPoint(initializer.clientX, initializer.clientY));
119 MouseEvent::~MouseEvent()
123 void MouseEvent::initMouseEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtrWillBeRawPtr<AbstractView> view,
124 int detail, int screenX, int screenY, int clientX, int clientY,
125 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
126 unsigned short button, PassRefPtrWillBeRawPtr<EventTarget> relatedTarget)
131 initUIEvent(type, canBubble, cancelable, view, detail);
133 m_screenLocation = IntPoint(screenX, screenY);
136 m_shiftKey = shiftKey;
138 m_button = button == (unsigned short)-1 ? 0 : button;
139 m_buttonDown = button != (unsigned short)-1;
140 m_relatedTarget = relatedTarget;
142 initCoordinates(IntPoint(clientX, clientY));
144 // FIXME: m_isSimulated is not set to false here.
145 // FIXME: m_dataTransfer is not set to nullptr here.
148 const AtomicString& MouseEvent::interfaceName() const
150 return EventNames::MouseEvent;
153 bool MouseEvent::isMouseEvent() const
158 bool MouseEvent::isDragEvent() const
160 const AtomicString& t = type();
161 return t == EventTypeNames::dragenter || t == EventTypeNames::dragover || t == EventTypeNames::dragleave || t == EventTypeNames::drop
162 || t == EventTypeNames::dragstart|| t == EventTypeNames::drag || t == EventTypeNames::dragend;
165 int MouseEvent::which() const
167 // For the DOM, the return values for left, middle and right mouse buttons are 0, 1, 2, respectively.
168 // For the Netscape "which" property, the return values for left, middle and right mouse buttons are 1, 2, 3, respectively.
175 Node* MouseEvent::toElement() const
177 // MSIE extension - "the object toward which the user is moving the mouse pointer"
178 if (type() == EventTypeNames::mouseout || type() == EventTypeNames::mouseleave)
179 return relatedTarget() ? relatedTarget()->toNode() : 0;
181 return target() ? target()->toNode() : 0;
184 Node* MouseEvent::fromElement() const
186 // MSIE extension - "object from which activation or the mouse pointer is exiting during the event" (huh?)
187 if (type() != EventTypeNames::mouseout && type() != EventTypeNames::mouseleave)
188 return relatedTarget() ? relatedTarget()->toNode() : 0;
190 return target() ? target()->toNode() : 0;
193 void MouseEvent::trace(Visitor* visitor)
195 visitor->trace(m_relatedTarget);
196 visitor->trace(m_dataTransfer);
197 MouseRelatedEvent::trace(visitor);
200 PassRefPtrWillBeRawPtr<SimulatedMouseEvent> SimulatedMouseEvent::create(const AtomicString& eventType, PassRefPtrWillBeRawPtr<AbstractView> view, PassRefPtrWillBeRawPtr<Event> underlyingEvent)
202 return adoptRefWillBeNoop(new SimulatedMouseEvent(eventType, view, underlyingEvent));
205 SimulatedMouseEvent::~SimulatedMouseEvent()
209 SimulatedMouseEvent::SimulatedMouseEvent(const AtomicString& eventType, PassRefPtrWillBeRawPtr<AbstractView> view, PassRefPtrWillBeRawPtr<Event> underlyingEvent)
210 : MouseEvent(eventType, true, true, view, 0, 0, 0, 0, 0,
212 false, false, false, false, 0, nullptr, nullptr, true)
214 if (UIEventWithKeyState* keyStateEvent = findEventWithKeyState(underlyingEvent.get())) {
215 m_ctrlKey = keyStateEvent->ctrlKey();
216 m_altKey = keyStateEvent->altKey();
217 m_shiftKey = keyStateEvent->shiftKey();
218 m_metaKey = keyStateEvent->metaKey();
220 setUnderlyingEvent(underlyingEvent);
222 if (this->underlyingEvent() && this->underlyingEvent()->isMouseEvent()) {
223 MouseEvent* mouseEvent = toMouseEvent(this->underlyingEvent());
224 m_screenLocation = mouseEvent->screenLocation();
225 initCoordinates(mouseEvent->clientLocation());
229 void SimulatedMouseEvent::trace(Visitor* visitor)
231 MouseEvent::trace(visitor);
234 PassRefPtrWillBeRawPtr<MouseEventDispatchMediator> MouseEventDispatchMediator::create(PassRefPtrWillBeRawPtr<MouseEvent> mouseEvent, MouseEventType mouseEventType)
236 return adoptRefWillBeNoop(new MouseEventDispatchMediator(mouseEvent, mouseEventType));
239 MouseEventDispatchMediator::MouseEventDispatchMediator(PassRefPtrWillBeRawPtr<MouseEvent> mouseEvent, MouseEventType mouseEventType)
240 : EventDispatchMediator(mouseEvent), m_mouseEventType(mouseEventType)
244 MouseEvent* MouseEventDispatchMediator::event() const
246 return toMouseEvent(EventDispatchMediator::event());
249 bool MouseEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const
251 if (isSyntheticMouseEvent()) {
252 event()->eventPath().adjustForRelatedTarget(dispatcher->node(), event()->relatedTarget());
253 return dispatcher->dispatch();
256 if (isDisabledFormControl(dispatcher->node()))
259 if (event()->type().isEmpty())
260 return true; // Shouldn't happen.
262 ASSERT(!event()->target() || event()->target() != event()->relatedTarget());
264 EventTarget* relatedTarget = event()->relatedTarget();
265 event()->eventPath().adjustForRelatedTarget(dispatcher->node(), relatedTarget);
267 dispatcher->dispatch();
268 bool swallowEvent = event()->defaultHandled() || event()->defaultPrevented();
270 if (event()->type() != EventTypeNames::click || event()->detail() != 2)
271 return !swallowEvent;
273 // Special case: If it's a double click event, we also send the dblclick event. This is not part
274 // of the DOM specs, but is used for compatibility with the ondblclick="" attribute. This is treated
275 // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same.
276 RefPtrWillBeRawPtr<MouseEvent> doubleClickEvent = MouseEvent::create();
277 doubleClickEvent->initMouseEvent(EventTypeNames::dblclick, event()->bubbles(), event()->cancelable(), event()->view(),
278 event()->detail(), event()->screenX(), event()->screenY(), event()->clientX(), event()->clientY(),
279 event()->ctrlKey(), event()->altKey(), event()->shiftKey(), event()->metaKey(),
280 event()->button(), relatedTarget);
281 if (event()->defaultHandled())
282 doubleClickEvent->setDefaultHandled();
283 EventDispatcher::dispatchEvent(dispatcher->node(), MouseEventDispatchMediator::create(doubleClickEvent));
284 if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented())
286 return !swallowEvent;