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, 2005, 2006, 2008, 2013 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 "PlatformMouseEvent.h" 32#include <wtf/CurrentTime.h> 33 34namespace WebCore { 35 36MouseEventInit::MouseEventInit() 37 : screenX(0) 38 , screenY(0) 39 , clientX(0) 40 , clientY(0) 41 , ctrlKey(false) 42 , altKey(false) 43 , shiftKey(false) 44 , metaKey(false) 45 , button(0) 46 , relatedTarget(0) 47{ 48} 49 50PassRefPtr<MouseEvent> MouseEvent::create(const AtomicString& type, const MouseEventInit& initializer) 51{ 52 return adoptRef(new MouseEvent(type, initializer)); 53} 54 55PassRefPtr<MouseEvent> MouseEvent::create(const AtomicString& eventType, PassRefPtr<AbstractView> view, const PlatformMouseEvent& event, int detail, PassRefPtr<Node> relatedTarget) 56{ 57 ASSERT(event.type() == PlatformEvent::MouseMoved || event.button() != NoButton); 58 59 bool isMouseEnterOrLeave = eventType == eventNames().mouseenterEvent || eventType == eventNames().mouseleaveEvent; 60 bool isCancelable = eventType != eventNames().mousemoveEvent && !isMouseEnterOrLeave; 61 bool canBubble = !isMouseEnterOrLeave; 62 63 return MouseEvent::create(eventType, canBubble, isCancelable, event.timestamp(), view, 64 detail, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(), 65#if ENABLE(POINTER_LOCK) 66 event.movementDelta().x(), event.movementDelta().y(), 67#endif 68 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), event.button(), 69 relatedTarget); 70} 71 72PassRefPtr<MouseEvent> MouseEvent::create(const AtomicString& type, bool canBubble, bool cancelable, double timestamp, PassRefPtr<AbstractView> view, 73 int detail, int screenX, int screenY, int pageX, int pageY, 74#if ENABLE(POINTER_LOCK) 75 int movementX, int movementY, 76#endif 77 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button, 78 PassRefPtr<EventTarget> relatedTarget) 79 80{ 81 return MouseEvent::create(type, canBubble, cancelable, timestamp, view, 82 detail, screenX, screenY, pageX, pageY, 83#if ENABLE(POINTER_LOCK) 84 movementX, movementY, 85#endif 86 ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget, 0, false); 87} 88 89PassRefPtr<MouseEvent> MouseEvent::create(const AtomicString& type, bool canBubble, bool cancelable, double timestamp, PassRefPtr<AbstractView> view, 90 int detail, int screenX, int screenY, int pageX, int pageY, 91#if ENABLE(POINTER_LOCK) 92 int movementX, int movementY, 93#endif 94 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button, 95 PassRefPtr<EventTarget> relatedTarget, PassRefPtr<DataTransfer> dataTransfer, bool isSimulated) 96{ 97 return adoptRef(new MouseEvent(type, canBubble, cancelable, timestamp, view, 98 detail, screenX, screenY, pageX, pageY, 99#if ENABLE(POINTER_LOCK) 100 movementX, movementY, 101#endif 102 ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget, dataTransfer, isSimulated)); 103} 104 105MouseEvent::MouseEvent() 106 : m_button(0) 107 , m_buttonDown(false) 108{ 109} 110 111MouseEvent::MouseEvent(const AtomicString& eventType, bool canBubble, bool cancelable, double timestamp, PassRefPtr<AbstractView> view, 112 int detail, int screenX, int screenY, int pageX, int pageY, 113#if ENABLE(POINTER_LOCK) 114 int movementX, int movementY, 115#endif 116 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, 117 unsigned short button, PassRefPtr<EventTarget> relatedTarget, 118 PassRefPtr<DataTransfer> dataTransfer, bool isSimulated) 119 : MouseRelatedEvent(eventType, canBubble, cancelable, timestamp, view, detail, IntPoint(screenX, screenY), 120 IntPoint(pageX, pageY), 121#if ENABLE(POINTER_LOCK) 122 IntPoint(movementX, movementY), 123#endif 124 ctrlKey, altKey, shiftKey, metaKey, isSimulated) 125 , m_button(button == (unsigned short)-1 ? 0 : button) 126 , m_buttonDown(button != (unsigned short)-1) 127 , m_relatedTarget(relatedTarget) 128 , m_dataTransfer(dataTransfer) 129{ 130} 131 132MouseEvent::MouseEvent(const AtomicString& eventType, const MouseEventInit& initializer) 133 : MouseRelatedEvent(eventType, initializer.bubbles, initializer.cancelable, currentTime(), initializer.view, initializer.detail, IntPoint(initializer.screenX, initializer.screenY), 134 IntPoint(0 /* pageX */, 0 /* pageY */), 135#if ENABLE(POINTER_LOCK) 136 IntPoint(0 /* movementX */, 0 /* movementY */), 137#endif 138 initializer.ctrlKey, initializer.altKey, initializer.shiftKey, initializer.metaKey, false /* isSimulated */) 139 , m_button(initializer.button == (unsigned short)-1 ? 0 : initializer.button) 140 , m_buttonDown(initializer.button != (unsigned short)-1) 141 , m_relatedTarget(initializer.relatedTarget) 142 , m_dataTransfer(0 /* dataTransfer */) 143{ 144 initCoordinates(IntPoint(initializer.clientX, initializer.clientY)); 145} 146 147MouseEvent::~MouseEvent() 148{ 149} 150 151void MouseEvent::initMouseEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<AbstractView> view, 152 int detail, int screenX, int screenY, int clientX, int clientY, 153 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, 154 unsigned short button, PassRefPtr<EventTarget> relatedTarget) 155{ 156 if (dispatched()) 157 return; 158 159 initUIEvent(type, canBubble, cancelable, view, detail); 160 161 m_screenLocation = IntPoint(screenX, screenY); 162 m_ctrlKey = ctrlKey; 163 m_altKey = altKey; 164 m_shiftKey = shiftKey; 165 m_metaKey = metaKey; 166 m_button = button == (unsigned short)-1 ? 0 : button; 167 m_buttonDown = button != (unsigned short)-1; 168 m_relatedTarget = relatedTarget; 169 170 initCoordinates(IntPoint(clientX, clientY)); 171 172 // FIXME: m_isSimulated is not set to false here. 173 // FIXME: m_dataTransfer is not set to 0 here. 174} 175 176EventInterface MouseEvent::eventInterface() const 177{ 178 return MouseEventInterfaceType; 179} 180 181bool MouseEvent::isMouseEvent() const 182{ 183 return true; 184} 185 186bool MouseEvent::isDragEvent() const 187{ 188 const AtomicString& t = type(); 189 return t == eventNames().dragenterEvent || t == eventNames().dragoverEvent || t == eventNames().dragleaveEvent || t == eventNames().dropEvent 190 || t == eventNames().dragstartEvent|| t == eventNames().dragEvent || t == eventNames().dragendEvent; 191} 192 193int MouseEvent::which() const 194{ 195 // For the DOM, the return values for left, middle and right mouse buttons are 0, 1, 2, respectively. 196 // For the Netscape "which" property, the return values for left, middle and right mouse buttons are 1, 2, 3, respectively. 197 // So we must add 1. 198 if (!m_buttonDown) 199 return 0; 200 return m_button + 1; 201} 202 203Node* MouseEvent::toElement() const 204{ 205 // MSIE extension - "the object toward which the user is moving the mouse pointer" 206 if (type() == eventNames().mouseoutEvent || type() == eventNames().mouseleaveEvent) { 207 EventTarget* relatedTarget = this->relatedTarget(); 208 return relatedTarget ? relatedTarget->toNode() : nullptr; 209 } 210 211 return target() ? target()->toNode() : nullptr; 212} 213 214Node* MouseEvent::fromElement() const 215{ 216 // MSIE extension - "object from which activation or the mouse pointer is exiting during the event" (huh?) 217 if (type() != eventNames().mouseoutEvent && type() != eventNames().mouseleaveEvent) { 218 EventTarget* relatedTarget = this->relatedTarget(); 219 return relatedTarget ? relatedTarget->toNode() : nullptr; 220 } 221 222 return target() ? target()->toNode() : nullptr; 223} 224 225// FIXME: Fix positioning. e.g. We need to consider border/padding. 226// https://bugs.webkit.org/show_bug.cgi?id=93696 227inline static int adjustedClientX(int innerClientX, HTMLIFrameElement* iframe, FrameView* frameView) 228{ 229 return iframe->offsetLeft() - frameView->scrollX() + innerClientX; 230} 231 232inline static int adjustedClientY(int innerClientY, HTMLIFrameElement* iframe, FrameView* frameView) 233{ 234 return iframe->offsetTop() - frameView->scrollY() + innerClientY; 235} 236 237PassRefPtr<Event> MouseEvent::cloneFor(HTMLIFrameElement* iframe) const 238{ 239 ASSERT(iframe); 240 RefPtr<MouseEvent> clonedMouseEvent = MouseEvent::create(); 241 Frame* frame = iframe->document().frame(); 242 FrameView* frameView = frame ? frame->view() : 0; 243 clonedMouseEvent->initMouseEvent(type(), bubbles(), cancelable(), 244 iframe->document().defaultView(), 245 detail(), screenX(), screenY(), 246 frameView ? adjustedClientX(clientX(), iframe, frameView) : 0, 247 frameView ? adjustedClientY(clientY(), iframe, frameView) : 0, 248 ctrlKey(), altKey(), shiftKey(), metaKey(), 249 button(), 250 // Nullifies relatedTarget. 251 0); 252 return clonedMouseEvent.release(); 253} 254 255PassRefPtr<SimulatedMouseEvent> SimulatedMouseEvent::create(const AtomicString& eventType, PassRefPtr<AbstractView> view, PassRefPtr<Event> underlyingEvent, Element* target) 256{ 257 return adoptRef(new SimulatedMouseEvent(eventType, view, underlyingEvent, target)); 258} 259 260SimulatedMouseEvent::~SimulatedMouseEvent() 261{ 262} 263 264SimulatedMouseEvent::SimulatedMouseEvent(const AtomicString& eventType, PassRefPtr<AbstractView> view, PassRefPtr<Event> underlyingEvent, Element* target) 265 : MouseEvent(eventType, true, true, underlyingEvent ? underlyingEvent->timeStamp() : currentTime(), view, 0, 0, 0, 0, 0, 266#if ENABLE(POINTER_LOCK) 267 0, 0, 268#endif 269 false, false, false, false, 0, 0, 0, true) 270{ 271 if (UIEventWithKeyState* keyStateEvent = findEventWithKeyState(underlyingEvent.get())) { 272 m_ctrlKey = keyStateEvent->ctrlKey(); 273 m_altKey = keyStateEvent->altKey(); 274 m_shiftKey = keyStateEvent->shiftKey(); 275 m_metaKey = keyStateEvent->metaKey(); 276 } 277 setUnderlyingEvent(underlyingEvent); 278 279 if (this->underlyingEvent() && this->underlyingEvent()->isMouseEvent()) { 280 MouseEvent* mouseEvent = toMouseEvent(this->underlyingEvent()); 281 m_screenLocation = mouseEvent->screenLocation(); 282 initCoordinates(mouseEvent->clientLocation()); 283 } else if (target) { 284 m_screenLocation = target->screenRect().center(); 285 initCoordinates(LayoutPoint(target->clientRect().center())); 286 } 287} 288 289} // namespace WebCore 290