14d3a7b6084c71647b89cb5915807358114a9fe0
[WebKit-https.git] / Source / WebCore / dom / MouseEvent.cpp
1 /*
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-2016 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 "MouseEvent.h"
25
26 #include "DataTransfer.h"
27 #include "EventNames.h"
28 #include "Frame.h"
29 #include "FrameView.h"
30 #include "HTMLIFrameElement.h"
31 #include "JSDOMConvert.h"
32 #include "JSEventTarget.h"
33 #include "JSEventTargetCustom.h"
34 #include "PlatformMouseEvent.h"
35 #include "RuntimeApplicationChecks.h"
36 #include <wtf/CurrentTime.h>
37
38 namespace WebCore {
39
40 using namespace JSC;
41
42 Ref<MouseEvent> MouseEvent::create(const AtomicString& type, const MouseEventInit& initializer, IsTrusted isTrusted)
43 {
44     return adoptRef(*new MouseEvent(type, initializer, isTrusted));
45 }
46
47 Ref<MouseEvent> MouseEvent::create(const AtomicString& eventType, DOMWindow* view, const PlatformMouseEvent& event, int detail, Node* relatedTarget)
48 {
49     bool isMouseEnterOrLeave = eventType == eventNames().mouseenterEvent || eventType == eventNames().mouseleaveEvent;
50     bool isCancelable = eventType != eventNames().mousemoveEvent && !isMouseEnterOrLeave;
51     bool canBubble = !isMouseEnterOrLeave;
52
53     return MouseEvent::create(eventType, canBubble, isCancelable, event.timestamp(), view,
54         detail, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
55 #if ENABLE(POINTER_LOCK)
56         event.movementDelta().x(), event.movementDelta().y(),
57 #endif
58         event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), event.button(),
59         relatedTarget, event.force(), event.syntheticClickType());
60 }
61
62 Ref<MouseEvent> MouseEvent::create(const AtomicString& type, bool canBubble, bool cancelable, double timestamp, DOMWindow* view, int detail, int screenX, int screenY, int pageX, int pageY,
63 #if ENABLE(POINTER_LOCK)
64     int movementX, int movementY,
65 #endif
66     bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button, EventTarget* relatedTarget, double force, unsigned short syntheticClickType, DataTransfer* dataTransfer, bool isSimulated)
67 {
68     return adoptRef(*new MouseEvent(type, canBubble, cancelable, timestamp, view,
69         detail, { screenX, screenY }, { pageX, pageY },
70 #if ENABLE(POINTER_LOCK)
71         { movementX, movementY },
72 #endif
73         ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget, force, syntheticClickType, dataTransfer, isSimulated));
74 }
75
76 Ref<MouseEvent> MouseEvent::create(const AtomicString& eventType, bool canBubble, bool cancelable, DOMWindow* view, int detail, int screenX, int screenY, int clientX, int clientY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button, unsigned short syntheticClickType, EventTarget* relatedTarget)
77 {
78     return adoptRef(*new MouseEvent(eventType, canBubble, cancelable, view, detail, { screenX, screenY }, { clientX, clientY }, ctrlKey, altKey, shiftKey, metaKey, button, syntheticClickType, relatedTarget));
79 }
80
81 MouseEvent::MouseEvent()
82 {
83 }
84
85 MouseEvent::MouseEvent(const AtomicString& eventType, bool canBubble, bool cancelable, double timestamp, DOMWindow* view, int detail, const IntPoint& screenLocation, const IntPoint& windowLocation,
86 #if ENABLE(POINTER_LOCK)
87         const IntPoint& movementDelta,
88 #endif
89         bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button, EventTarget* relatedTarget, double force, unsigned short syntheticClickType, DataTransfer* dataTransfer, bool isSimulated)
90     : MouseRelatedEvent(eventType, canBubble, cancelable, timestamp, view, detail, screenLocation, windowLocation,
91 #if ENABLE(POINTER_LOCK)
92         movementDelta,
93 #endif
94         ctrlKey, altKey, shiftKey, metaKey, isSimulated)
95     , m_button(button == (unsigned short)-1 ? 0 : button)
96     , m_syntheticClickType(button == (unsigned short)-1 ? 0 : syntheticClickType)
97     , m_buttonDown(button != (unsigned short)-1)
98     , m_relatedTarget(relatedTarget)
99     , m_force(force)
100     , m_dataTransfer(dataTransfer)
101 {
102 }
103
104 MouseEvent::MouseEvent(const AtomicString& eventType, bool canBubble, bool cancelable, DOMWindow* view, int detail, const IntPoint& screenLocation, const IntPoint& clientLocation, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button, unsigned short syntheticClickType, EventTarget* relatedTarget)
105     : MouseRelatedEvent(eventType, canBubble, cancelable, WTF::currentTime(), view, detail, screenLocation, { },
106 #if ENABLE(POINTER_LOCK)
107         { },
108 #endif
109         ctrlKey, altKey, shiftKey, metaKey, false)
110     , m_button(button == (unsigned short)-1 ? 0 : button)
111     , m_syntheticClickType(button == (unsigned short)-1 ? 0 : syntheticClickType)
112     , m_buttonDown(button != (unsigned short)-1)
113     , m_relatedTarget(relatedTarget)
114 {
115     initCoordinates(clientLocation);
116 }
117
118 MouseEvent::MouseEvent(const AtomicString& eventType, const MouseEventInit& initializer, IsTrusted isTrusted)
119     : MouseRelatedEvent(eventType, initializer, isTrusted)
120     , m_button(initializer.button == (unsigned short)-1 ? 0 : initializer.button)
121     , m_buttonDown(initializer.button != (unsigned short)-1)
122     , m_relatedTarget(initializer.relatedTarget)
123 {
124     initCoordinates({ initializer.clientX, initializer.clientY });
125 }
126
127 MouseEvent::~MouseEvent()
128 {
129 }
130
131 void MouseEvent::initMouseEvent(const AtomicString& type, bool canBubble, bool cancelable, DOMWindow* view, int detail, int screenX, int screenY, int clientX, int clientY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button, EventTarget* relatedTarget)
132 {
133     if (dispatched())
134         return;
135
136     initUIEvent(type, canBubble, cancelable, view, detail);
137
138     m_screenLocation = IntPoint(screenX, screenY);
139     m_ctrlKey = ctrlKey;
140     m_altKey = altKey;
141     m_shiftKey = shiftKey;
142     m_metaKey = metaKey;
143     m_button = button == (unsigned short)-1 ? 0 : button;
144     m_syntheticClickType = 0;
145     m_buttonDown = button != (unsigned short)-1;
146     m_relatedTarget = relatedTarget;
147
148     initCoordinates(IntPoint(clientX, clientY));
149
150     // FIXME: m_isSimulated is not set to false here.
151     // FIXME: m_dataTransfer is not set to 0 here.
152 }
153
154 // FIXME: We need this quirk because iAd Producer is calling this function with a relatedTarget that is not an EventTarget (rdar://problem/30640101).
155 // We should remove this quirk when possible.
156 void MouseEvent::initMouseEventQuirk(ExecState& state, ScriptExecutionContext& scriptExecutionContext, const AtomicString& type, bool canBubble, bool cancelable, DOMWindow* view, int detail, int screenX, int screenY, int clientX, int clientY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button, JSValue relatedTargetValue)
157 {
158     EventTarget* relatedTarget = nullptr;
159 #if PLATFORM(MAC)
160     if (MacApplication::isIAdProducer()) {
161         // jsEventTargetCast() does not throw and will silently convert bad input to nullptr.
162         auto jsRelatedTarget = jsEventTargetCast(state.vm(), relatedTargetValue);
163         if (!jsRelatedTarget && !relatedTargetValue.isUndefinedOrNull())
164             scriptExecutionContext.addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("Calling initMouseEvent() with a relatedTarget that is not an EventTarget is deprecated."));
165         relatedTarget = jsRelatedTarget ? &jsRelatedTarget->wrapped() : nullptr;
166     } else {
167 #else
168     UNUSED_PARAM(scriptExecutionContext);
169 #endif
170         // This is what the bindings generator would have produced.
171         auto throwScope = DECLARE_THROW_SCOPE(state.vm());
172         relatedTarget = convert<IDLNullable<IDLInterface<EventTarget>>>(state, relatedTargetValue, [](ExecState& state, ThrowScope& scope) {
173             throwArgumentTypeError(state, scope, 14, "relatedTarget", "MouseEvent", "initMouseEvent", "EventTarget");
174         });
175         RETURN_IF_EXCEPTION(throwScope, void());
176 #if PLATFORM(MAC)
177     }
178 #endif
179     initMouseEvent(type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);
180 }
181
182 EventInterface MouseEvent::eventInterface() const
183 {
184     return MouseEventInterfaceType;
185 }
186
187 bool MouseEvent::isMouseEvent() const
188 {
189     return true;
190 }
191
192 bool MouseEvent::isDragEvent() const
193 {
194     // This function is only used to decide to return nullptr for dataTransfer even when m_dataTransfer is non-null.
195     // FIXME: Is that really valuable? Why will m_dataTransfer be non-null but we need to return null for dataTransfer?
196     // Quite peculiar to decide based on the type string; may have been be provided by call to JavaScript constructor.
197     auto& type = this->type();
198     return type == eventNames().dragEvent
199         || type == eventNames().dragendEvent
200         || type == eventNames().dragenterEvent
201         || type == eventNames().dragleaveEvent
202         || type == eventNames().dragoverEvent
203         || type == eventNames().dragstartEvent
204         || type == eventNames().dropEvent;
205 }
206
207 bool MouseEvent::canTriggerActivationBehavior(const Event& event)
208 {
209     return event.type() == eventNames().clickEvent && (!is<MouseEvent>(event) || downcast<MouseEvent>(event).button() != RightButton);
210 }
211
212 int MouseEvent::which() const
213 {
214     // For the DOM, the return values for left, middle and right mouse buttons are 0, 1, 2, respectively.
215     // For the Netscape "which" property, the return values for left, middle and right mouse buttons are 1, 2, 3, respectively.
216     // So we must add 1.
217     if (!m_buttonDown)
218         return 0;
219     return m_button + 1;
220 }
221
222 Node* MouseEvent::toElement() const
223 {
224     // MSIE extension - "the object toward which the user is moving the mouse pointer"
225     if (type() == eventNames().mouseoutEvent || type() == eventNames().mouseleaveEvent) {
226         EventTarget* relatedTarget = this->relatedTarget();
227         return relatedTarget ? relatedTarget->toNode() : nullptr;
228     }
229
230     return target() ? target()->toNode() : nullptr;
231 }
232
233 Node* MouseEvent::fromElement() const
234 {
235     // MSIE extension - "object from which activation or the mouse pointer is exiting during the event" (huh?)
236     if (type() != eventNames().mouseoutEvent && type() != eventNames().mouseleaveEvent) {
237         EventTarget* relatedTarget = this->relatedTarget();
238         return relatedTarget ? relatedTarget->toNode() : nullptr;
239     }
240
241     return target() ? target()->toNode() : nullptr;
242 }
243
244 } // namespace WebCore