blob: 2d5f32822f03fb1a0fbcbd945c25684243572758 [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
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.
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/dom/MouseEvent.h"
25
26#include "core/dom/Clipboard.h"
27#include "core/dom/EventDispatcher.h"
28#include "core/dom/EventNames.h"
29#include "core/dom/EventRetargeter.h"
30#include "core/html/HTMLIFrameElement.h"
31#include "core/page/Frame.h"
32#include "core/page/FrameView.h"
33#include "core/platform/PlatformMouseEvent.h"
34
35namespace WebCore {
36
37MouseEventInit::MouseEventInit()
38 : screenX(0)
39 , screenY(0)
40 , clientX(0)
41 , clientY(0)
42 , ctrlKey(false)
43 , altKey(false)
44 , shiftKey(false)
45 , metaKey(false)
46 , button(0)
47 , relatedTarget(0)
48{
49}
50
51PassRefPtr<MouseEvent> MouseEvent::create(const AtomicString& type, const MouseEventInit& initializer)
52{
53 return adoptRef(new MouseEvent(type, initializer));
54}
55
56PassRefPtr<MouseEvent> MouseEvent::create(const AtomicString& eventType, PassRefPtr<AbstractView> view, const PlatformMouseEvent& event, int detail, PassRefPtr<Node> relatedTarget)
57{
58 ASSERT(event.type() == PlatformEvent::MouseMoved || event.button() != NoButton);
59
Ben Murdoche69819b2013-07-17 14:56:49 +010060 bool isMouseEnterOrLeave = eventType == eventNames().mouseenterEvent || eventType == eventNames().mouseleaveEvent;
61 bool isCancelable = eventType != eventNames().mousemoveEvent && !isMouseEnterOrLeave;
62 bool isBubbling = !isMouseEnterOrLeave;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010063
Ben Murdoche69819b2013-07-17 14:56:49 +010064 return MouseEvent::create(eventType, isBubbling, isCancelable, view,
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010065 detail, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
66 event.movementDelta().x(), event.movementDelta().y(),
67 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), event.button(),
68 relatedTarget, 0, false);
69}
70
71PassRefPtr<MouseEvent> MouseEvent::create(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<AbstractView> view,
72 int detail, int screenX, int screenY, int pageX, int pageY,
73 int movementX, int movementY,
74 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button,
75 PassRefPtr<EventTarget> relatedTarget)
76
77{
78 return MouseEvent::create(type, canBubble, cancelable, view,
79 detail, screenX, screenY, pageX, pageY,
80 movementX, movementY,
81 ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget, 0, false);
82}
83
84PassRefPtr<MouseEvent> MouseEvent::create(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<AbstractView> view,
85 int detail, int screenX, int screenY, int pageX, int pageY,
86 int movementX, int movementY,
87 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button,
88 PassRefPtr<EventTarget> relatedTarget, PassRefPtr<Clipboard> clipboard, bool isSimulated)
89{
90 return adoptRef(new MouseEvent(type, canBubble, cancelable, view,
91 detail, screenX, screenY, pageX, pageY,
92 movementX, movementY,
93 ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget, clipboard, isSimulated));
94}
95
96MouseEvent::MouseEvent()
97 : m_button(0)
98 , m_buttonDown(false)
99{
100 ScriptWrappable::init(this);
101}
102
103MouseEvent::MouseEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtr<AbstractView> view,
104 int detail, int screenX, int screenY, int pageX, int pageY,
105 int movementX, int movementY,
106 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
107 unsigned short button, PassRefPtr<EventTarget> relatedTarget,
108 PassRefPtr<Clipboard> clipboard, bool isSimulated)
109 : MouseRelatedEvent(eventType, canBubble, cancelable, view, detail, IntPoint(screenX, screenY),
110 IntPoint(pageX, pageY),
111 IntPoint(movementX, movementY),
112 ctrlKey, altKey, shiftKey, metaKey, isSimulated)
113 , m_button(button == (unsigned short)-1 ? 0 : button)
114 , m_buttonDown(button != (unsigned short)-1)
115 , m_relatedTarget(relatedTarget)
116 , m_clipboard(clipboard)
117{
118 ScriptWrappable::init(this);
119}
120
121MouseEvent::MouseEvent(const AtomicString& eventType, const MouseEventInit& initializer)
122 : MouseRelatedEvent(eventType, initializer.bubbles, initializer.cancelable, initializer.view, initializer.detail, IntPoint(initializer.screenX, initializer.screenY),
123 IntPoint(0 /* pageX */, 0 /* pageY */),
124 IntPoint(0 /* movementX */, 0 /* movementY */),
125 initializer.ctrlKey, initializer.altKey, initializer.shiftKey, initializer.metaKey, false /* isSimulated */)
126 , m_button(initializer.button == (unsigned short)-1 ? 0 : initializer.button)
127 , m_buttonDown(initializer.button != (unsigned short)-1)
128 , m_relatedTarget(initializer.relatedTarget)
129 , m_clipboard(0 /* clipboard */)
130{
131 ScriptWrappable::init(this);
132 initCoordinates(IntPoint(initializer.clientX, initializer.clientY));
133}
134
135MouseEvent::~MouseEvent()
136{
137}
138
139void MouseEvent::initMouseEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<AbstractView> view,
140 int detail, int screenX, int screenY, int clientX, int clientY,
141 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
142 unsigned short button, PassRefPtr<EventTarget> relatedTarget)
143{
144 if (dispatched())
145 return;
146
147 initUIEvent(type, canBubble, cancelable, view, detail);
148
149 m_screenLocation = IntPoint(screenX, screenY);
150 m_ctrlKey = ctrlKey;
151 m_altKey = altKey;
152 m_shiftKey = shiftKey;
153 m_metaKey = metaKey;
154 m_button = button == (unsigned short)-1 ? 0 : button;
155 m_buttonDown = button != (unsigned short)-1;
156 m_relatedTarget = relatedTarget;
157
158 initCoordinates(IntPoint(clientX, clientY));
159
160 // FIXME: m_isSimulated is not set to false here.
161 // FIXME: m_clipboard is not set to 0 here.
162}
163
164const AtomicString& MouseEvent::interfaceName() const
165{
166 return eventNames().interfaceForMouseEvent;
167}
168
169bool MouseEvent::isMouseEvent() const
170{
171 return true;
172}
173
174bool MouseEvent::isDragEvent() const
175{
176 const AtomicString& t = type();
177 return t == eventNames().dragenterEvent || t == eventNames().dragoverEvent || t == eventNames().dragleaveEvent || t == eventNames().dropEvent
178 || t == eventNames().dragstartEvent|| t == eventNames().dragEvent || t == eventNames().dragendEvent;
179}
180
181int MouseEvent::which() const
182{
183 // For the DOM, the return values for left, middle and right mouse buttons are 0, 1, 2, respectively.
Ben Murdoch02772c62013-07-26 10:21:05 +0100184 // For the Netscape "which" property, the return values for left, middle and right mouse buttons are 1, 2, 3, respectively.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100185 // So we must add 1.
186 if (!m_buttonDown)
187 return 0;
188 return m_button + 1;
189}
190
191Node* MouseEvent::toElement() const
192{
193 // MSIE extension - "the object toward which the user is moving the mouse pointer"
Ben Murdoche69819b2013-07-17 14:56:49 +0100194 if (type() == eventNames().mouseoutEvent || type() == eventNames().mouseleaveEvent)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100195 return relatedTarget() ? relatedTarget()->toNode() : 0;
Ben Murdoche69819b2013-07-17 14:56:49 +0100196
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100197 return target() ? target()->toNode() : 0;
198}
199
200Node* MouseEvent::fromElement() const
201{
202 // MSIE extension - "object from which activation or the mouse pointer is exiting during the event" (huh?)
Ben Murdoche69819b2013-07-17 14:56:49 +0100203 if (type() != eventNames().mouseoutEvent && type() != eventNames().mouseleaveEvent)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100204 return relatedTarget() ? relatedTarget()->toNode() : 0;
Ben Murdoche69819b2013-07-17 14:56:49 +0100205
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100206 return target() ? target()->toNode() : 0;
207}
208
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100209PassRefPtr<SimulatedMouseEvent> SimulatedMouseEvent::create(const AtomicString& eventType, PassRefPtr<AbstractView> view, PassRefPtr<Event> underlyingEvent)
210{
211 return adoptRef(new SimulatedMouseEvent(eventType, view, underlyingEvent));
212}
213
214SimulatedMouseEvent::~SimulatedMouseEvent()
215{
216}
217
218SimulatedMouseEvent::SimulatedMouseEvent(const AtomicString& eventType, PassRefPtr<AbstractView> view, PassRefPtr<Event> underlyingEvent)
219 : MouseEvent(eventType, true, true, view, 0, 0, 0, 0, 0,
220 0, 0,
221 false, false, false, false, 0, 0, 0, true)
222{
223 if (UIEventWithKeyState* keyStateEvent = findEventWithKeyState(underlyingEvent.get())) {
224 m_ctrlKey = keyStateEvent->ctrlKey();
225 m_altKey = keyStateEvent->altKey();
226 m_shiftKey = keyStateEvent->shiftKey();
227 m_metaKey = keyStateEvent->metaKey();
228 }
229 setUnderlyingEvent(underlyingEvent);
230
231 if (this->underlyingEvent() && this->underlyingEvent()->isMouseEvent()) {
Ben Murdoch591b9582013-07-10 11:41:44 +0100232 MouseEvent* mouseEvent = toMouseEvent(this->underlyingEvent());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100233 m_screenLocation = mouseEvent->screenLocation();
234 initCoordinates(mouseEvent->clientLocation());
235 }
236}
237
238PassRefPtr<MouseEventDispatchMediator> MouseEventDispatchMediator::create(PassRefPtr<MouseEvent> mouseEvent, MouseEventType mouseEventType)
239{
240 return adoptRef(new MouseEventDispatchMediator(mouseEvent, mouseEventType));
241}
242
243MouseEventDispatchMediator::MouseEventDispatchMediator(PassRefPtr<MouseEvent> mouseEvent, MouseEventType mouseEventType)
244 : EventDispatchMediator(mouseEvent), m_mouseEventType(mouseEventType)
245{
246}
247
248MouseEvent* MouseEventDispatchMediator::event() const
249{
Ben Murdoch591b9582013-07-10 11:41:44 +0100250 return toMouseEvent(EventDispatchMediator::event());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100251}
252
253bool MouseEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const
254{
255 if (isSyntheticMouseEvent()) {
256 EventRetargeter::adjustForMouseEvent(dispatcher->node(), *event());
257 return dispatcher->dispatch();
258 }
259
260 if (isDisabledFormControl(dispatcher->node()))
261 return false;
262
263 if (event()->type().isEmpty())
264 return true; // Shouldn't happen.
265
266 ASSERT(!event()->target() || event()->target() != event()->relatedTarget());
267
268 EventTarget* relatedTarget = event()->relatedTarget();
269 EventRetargeter::adjustForMouseEvent(dispatcher->node(), *event());
270
271 dispatcher->dispatch();
272 bool swallowEvent = event()->defaultHandled() || event()->defaultPrevented();
273
274 if (event()->type() != eventNames().clickEvent || event()->detail() != 2)
275 return !swallowEvent;
276
277 // Special case: If it's a double click event, we also send the dblclick event. This is not part
278 // of the DOM specs, but is used for compatibility with the ondblclick="" attribute. This is treated
279 // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same.
280 RefPtr<MouseEvent> doubleClickEvent = MouseEvent::create();
281 doubleClickEvent->initMouseEvent(eventNames().dblclickEvent, event()->bubbles(), event()->cancelable(), event()->view(),
282 event()->detail(), event()->screenX(), event()->screenY(), event()->clientX(), event()->clientY(),
283 event()->ctrlKey(), event()->altKey(), event()->shiftKey(), event()->metaKey(),
284 event()->button(), relatedTarget);
285 if (event()->defaultHandled())
286 doubleClickEvent->setDefaultHandled();
287 EventDispatcher::dispatchEvent(dispatcher->node(), MouseEventDispatchMediator::create(doubleClickEvent));
288 if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented())
289 return false;
290 return !swallowEvent;
291}
292
293} // namespace WebCore