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 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/Clipboard.h" 27#include "core/dom/Element.h" 28#include "core/events/EventDispatcher.h" 29#include "platform/PlatformMouseEvent.h" 30 31namespace WebCore { 32 33MouseEventInit::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 47PassRefPtrWillBeRawPtr<MouseEvent> MouseEvent::create(const AtomicString& type, const MouseEventInit& initializer) 48{ 49 return adoptRefWillBeNoop(new MouseEvent(type, initializer)); 50} 51 52PassRefPtrWillBeRawPtr<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); 66} 67 68PassRefPtrWillBeRawPtr<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<Clipboard> clipboard, bool isSimulated) 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, clipboard, isSimulated)); 78} 79 80MouseEvent::MouseEvent() 81 : m_button(0) 82 , m_buttonDown(false) 83{ 84 ScriptWrappable::init(this); 85} 86 87MouseEvent::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<Clipboard> clipboard, 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_clipboard(clipboard) 101{ 102 ScriptWrappable::init(this); 103} 104 105MouseEvent::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_clipboard(nullptr /* clipboard */) 114{ 115 ScriptWrappable::init(this); 116 initCoordinates(IntPoint(initializer.clientX, initializer.clientY)); 117} 118 119MouseEvent::~MouseEvent() 120{ 121} 122 123void 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) 127{ 128 if (dispatched()) 129 return; 130 131 initUIEvent(type, canBubble, cancelable, view, detail); 132 133 m_screenLocation = IntPoint(screenX, screenY); 134 m_ctrlKey = ctrlKey; 135 m_altKey = altKey; 136 m_shiftKey = shiftKey; 137 m_metaKey = metaKey; 138 m_button = button == (unsigned short)-1 ? 0 : button; 139 m_buttonDown = button != (unsigned short)-1; 140 m_relatedTarget = relatedTarget; 141 142 initCoordinates(IntPoint(clientX, clientY)); 143 144 // FIXME: m_isSimulated is not set to false here. 145 // FIXME: m_clipboard is not set to 0 here. 146} 147 148const AtomicString& MouseEvent::interfaceName() const 149{ 150 return EventNames::MouseEvent; 151} 152 153bool MouseEvent::isMouseEvent() const 154{ 155 return true; 156} 157 158bool MouseEvent::isDragEvent() const 159{ 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; 163} 164 165int MouseEvent::which() const 166{ 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. 169 // So we must add 1. 170 if (!m_buttonDown) 171 return 0; 172 return m_button + 1; 173} 174 175Node* MouseEvent::toElement() const 176{ 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; 180 181 return target() ? target()->toNode() : 0; 182} 183 184Node* MouseEvent::fromElement() const 185{ 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; 189 190 return target() ? target()->toNode() : 0; 191} 192 193void MouseEvent::trace(Visitor* visitor) 194{ 195 visitor->trace(m_relatedTarget); 196 visitor->trace(m_clipboard); 197 MouseRelatedEvent::trace(visitor); 198} 199 200PassRefPtrWillBeRawPtr<SimulatedMouseEvent> SimulatedMouseEvent::create(const AtomicString& eventType, PassRefPtrWillBeRawPtr<AbstractView> view, PassRefPtrWillBeRawPtr<Event> underlyingEvent) 201{ 202 return adoptRefWillBeNoop(new SimulatedMouseEvent(eventType, view, underlyingEvent)); 203} 204 205SimulatedMouseEvent::~SimulatedMouseEvent() 206{ 207} 208 209SimulatedMouseEvent::SimulatedMouseEvent(const AtomicString& eventType, PassRefPtrWillBeRawPtr<AbstractView> view, PassRefPtrWillBeRawPtr<Event> underlyingEvent) 210 : MouseEvent(eventType, true, true, view, 0, 0, 0, 0, 0, 211 0, 0, 212 false, false, false, false, 0, nullptr, nullptr, true) 213{ 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(); 219 } 220 setUnderlyingEvent(underlyingEvent); 221 222 if (this->underlyingEvent() && this->underlyingEvent()->isMouseEvent()) { 223 MouseEvent* mouseEvent = toMouseEvent(this->underlyingEvent()); 224 m_screenLocation = mouseEvent->screenLocation(); 225 initCoordinates(mouseEvent->clientLocation()); 226 } 227} 228 229void SimulatedMouseEvent::trace(Visitor* visitor) 230{ 231 MouseEvent::trace(visitor); 232} 233 234PassRefPtrWillBeRawPtr<MouseEventDispatchMediator> MouseEventDispatchMediator::create(PassRefPtrWillBeRawPtr<MouseEvent> mouseEvent, MouseEventType mouseEventType) 235{ 236 return adoptRefWillBeNoop(new MouseEventDispatchMediator(mouseEvent, mouseEventType)); 237} 238 239MouseEventDispatchMediator::MouseEventDispatchMediator(PassRefPtrWillBeRawPtr<MouseEvent> mouseEvent, MouseEventType mouseEventType) 240 : EventDispatchMediator(mouseEvent), m_mouseEventType(mouseEventType) 241{ 242} 243 244MouseEvent* MouseEventDispatchMediator::event() const 245{ 246 return toMouseEvent(EventDispatchMediator::event()); 247} 248 249bool MouseEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const 250{ 251 if (isSyntheticMouseEvent()) { 252 event()->eventPath().adjustForRelatedTarget(dispatcher->node(), event()->relatedTarget()); 253 return dispatcher->dispatch(); 254 } 255 256 if (isDisabledFormControl(dispatcher->node())) 257 return false; 258 259 if (event()->type().isEmpty()) 260 return true; // Shouldn't happen. 261 262 ASSERT(!event()->target() || event()->target() != event()->relatedTarget()); 263 264 EventTarget* relatedTarget = event()->relatedTarget(); 265 event()->eventPath().adjustForRelatedTarget(dispatcher->node(), relatedTarget); 266 267 dispatcher->dispatch(); 268 bool swallowEvent = event()->defaultHandled() || event()->defaultPrevented(); 269 270 if (event()->type() != EventTypeNames::click || event()->detail() != 2) 271 return !swallowEvent; 272 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()) 285 return false; 286 return !swallowEvent; 287} 288 289} // namespace WebCore 290