1 /* 2 * Copyright (C) 2001 Peter Kelly (pmk (at) post.com) 3 * Copyright (C) 2001 Tobias Anton (anton (at) stud.fbi.fh-darmstadt.de) 4 * Copyright (C) 2006 Samuel Weinig (sam.weinig (at) 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/DataTransfer.h" 27 #include "core/dom/Element.h" 28 #include "core/events/EventDispatcher.h" 29 #include "platform/PlatformMouseEvent.h" 30 31 namespace blink { 32 33 MouseEventInit::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 47 PassRefPtrWillBeRawPtr<MouseEvent> MouseEvent::create(const AtomicString& type, const MouseEventInit& initializer) 48 { 49 return adoptRefWillBeNoop(new MouseEvent(type, initializer)); 50 } 51 52 PassRefPtrWillBeRawPtr<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, event.syntheticEventType()); 66 } 67 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, PlatformMouseEvent::SyntheticEventType syntheticEventType) 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, dataTransfer, isSimulated, syntheticEventType)); 78 } 79 80 MouseEvent::MouseEvent() 81 : m_button(0) 82 , m_buttonDown(false) 83 { 84 } 85 86 MouseEvent::MouseEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtrWillBeRawPtr<AbstractView> view, 87 int detail, int screenX, int screenY, int pageX, int pageY, 88 int movementX, int movementY, 89 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, 90 unsigned short button, PassRefPtrWillBeRawPtr<EventTarget> relatedTarget, 91 PassRefPtrWillBeRawPtr<DataTransfer> dataTransfer, bool isSimulated, PlatformMouseEvent::SyntheticEventType syntheticEventType) 92 : MouseRelatedEvent(eventType, canBubble, cancelable, view, detail, IntPoint(screenX, screenY), 93 IntPoint(pageX, pageY), 94 IntPoint(movementX, movementY), 95 ctrlKey, altKey, shiftKey, metaKey, isSimulated) 96 , m_button(button == (unsigned short)-1 ? 0 : button) 97 , m_buttonDown(button != (unsigned short)-1) 98 , m_relatedTarget(relatedTarget) 99 , m_dataTransfer(dataTransfer) 100 , m_syntheticEventType(syntheticEventType) 101 { 102 } 103 104 MouseEvent::MouseEvent(const AtomicString& eventType, const MouseEventInit& initializer) 105 : MouseRelatedEvent(eventType, initializer.bubbles, initializer.cancelable, initializer.view, initializer.detail, IntPoint(initializer.screenX, initializer.screenY), 106 IntPoint(0 /* pageX */, 0 /* pageY */), 107 IntPoint(0 /* movementX */, 0 /* movementY */), 108 initializer.ctrlKey, initializer.altKey, initializer.shiftKey, initializer.metaKey, false /* isSimulated */) 109 , m_button(initializer.button == (unsigned short)-1 ? 0 : initializer.button) 110 , m_buttonDown(initializer.button != (unsigned short)-1) 111 , m_relatedTarget(initializer.relatedTarget) 112 , m_dataTransfer(nullptr) 113 { 114 initCoordinates(IntPoint(initializer.clientX, initializer.clientY)); 115 } 116 117 MouseEvent::~MouseEvent() 118 { 119 } 120 121 void MouseEvent::initMouseEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtrWillBeRawPtr<AbstractView> view, 122 int detail, int screenX, int screenY, int clientX, int clientY, 123 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, 124 unsigned short button, PassRefPtrWillBeRawPtr<EventTarget> relatedTarget) 125 { 126 if (dispatched()) 127 return; 128 129 initUIEvent(type, canBubble, cancelable, view, detail); 130 131 m_screenLocation = IntPoint(screenX, screenY); 132 m_ctrlKey = ctrlKey; 133 m_altKey = altKey; 134 m_shiftKey = shiftKey; 135 m_metaKey = metaKey; 136 m_button = button == (unsigned short)-1 ? 0 : button; 137 m_buttonDown = button != (unsigned short)-1; 138 m_relatedTarget = relatedTarget; 139 140 initCoordinates(IntPoint(clientX, clientY)); 141 142 // FIXME: m_isSimulated is not set to false here. 143 // FIXME: m_dataTransfer is not set to nullptr here. 144 } 145 146 const AtomicString& MouseEvent::interfaceName() const 147 { 148 return EventNames::MouseEvent; 149 } 150 151 bool MouseEvent::isMouseEvent() const 152 { 153 return true; 154 } 155 156 bool MouseEvent::isDragEvent() const 157 { 158 const AtomicString& t = type(); 159 return t == EventTypeNames::dragenter || t == EventTypeNames::dragover || t == EventTypeNames::dragleave || t == EventTypeNames::drop 160 || t == EventTypeNames::dragstart|| t == EventTypeNames::drag || t == EventTypeNames::dragend; 161 } 162 163 int MouseEvent::which() const 164 { 165 // For the DOM, the return values for left, middle and right mouse buttons are 0, 1, 2, respectively. 166 // For the Netscape "which" property, the return values for left, middle and right mouse buttons are 1, 2, 3, respectively. 167 // So we must add 1. 168 if (!m_buttonDown) 169 return 0; 170 return m_button + 1; 171 } 172 173 Node* MouseEvent::toElement() const 174 { 175 // MSIE extension - "the object toward which the user is moving the mouse pointer" 176 if (type() == EventTypeNames::mouseout || type() == EventTypeNames::mouseleave) 177 return relatedTarget() ? relatedTarget()->toNode() : 0; 178 179 return target() ? target()->toNode() : 0; 180 } 181 182 Node* MouseEvent::fromElement() const 183 { 184 // MSIE extension - "object from which activation or the mouse pointer is exiting during the event" (huh?) 185 if (type() != EventTypeNames::mouseout && type() != EventTypeNames::mouseleave) 186 return relatedTarget() ? relatedTarget()->toNode() : 0; 187 188 return target() ? target()->toNode() : 0; 189 } 190 191 void MouseEvent::trace(Visitor* visitor) 192 { 193 visitor->trace(m_relatedTarget); 194 visitor->trace(m_dataTransfer); 195 MouseRelatedEvent::trace(visitor); 196 } 197 198 PassRefPtrWillBeRawPtr<SimulatedMouseEvent> SimulatedMouseEvent::create(const AtomicString& eventType, PassRefPtrWillBeRawPtr<AbstractView> view, PassRefPtrWillBeRawPtr<Event> underlyingEvent) 199 { 200 return adoptRefWillBeNoop(new SimulatedMouseEvent(eventType, view, underlyingEvent)); 201 } 202 203 SimulatedMouseEvent::~SimulatedMouseEvent() 204 { 205 } 206 207 SimulatedMouseEvent::SimulatedMouseEvent(const AtomicString& eventType, PassRefPtrWillBeRawPtr<AbstractView> view, PassRefPtrWillBeRawPtr<Event> underlyingEvent) 208 : MouseEvent(eventType, true, true, view, 0, 0, 0, 0, 0, 0, 0, false, false, false, false, 0, 209 nullptr, nullptr, true, PlatformMouseEvent::RealOrIndistinguishable) 210 { 211 if (UIEventWithKeyState* keyStateEvent = findEventWithKeyState(underlyingEvent.get())) { 212 m_ctrlKey = keyStateEvent->ctrlKey(); 213 m_altKey = keyStateEvent->altKey(); 214 m_shiftKey = keyStateEvent->shiftKey(); 215 m_metaKey = keyStateEvent->metaKey(); 216 } 217 setUnderlyingEvent(underlyingEvent); 218 219 if (this->underlyingEvent() && this->underlyingEvent()->isMouseEvent()) { 220 MouseEvent* mouseEvent = toMouseEvent(this->underlyingEvent()); 221 m_screenLocation = mouseEvent->screenLocation(); 222 initCoordinates(mouseEvent->clientLocation()); 223 } 224 } 225 226 void SimulatedMouseEvent::trace(Visitor* visitor) 227 { 228 MouseEvent::trace(visitor); 229 } 230 231 PassRefPtrWillBeRawPtr<MouseEventDispatchMediator> MouseEventDispatchMediator::create(PassRefPtrWillBeRawPtr<MouseEvent> mouseEvent, MouseEventType mouseEventType) 232 { 233 return adoptRefWillBeNoop(new MouseEventDispatchMediator(mouseEvent, mouseEventType)); 234 } 235 236 MouseEventDispatchMediator::MouseEventDispatchMediator(PassRefPtrWillBeRawPtr<MouseEvent> mouseEvent, MouseEventType mouseEventType) 237 : EventDispatchMediator(mouseEvent), m_mouseEventType(mouseEventType) 238 { 239 } 240 241 MouseEvent* MouseEventDispatchMediator::event() const 242 { 243 return toMouseEvent(EventDispatchMediator::event()); 244 } 245 246 bool MouseEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const 247 { 248 if (isSyntheticMouseEvent()) { 249 event()->eventPath().adjustForRelatedTarget(dispatcher->node(), event()->relatedTarget()); 250 return dispatcher->dispatch(); 251 } 252 253 if (isDisabledFormControl(dispatcher->node())) 254 return false; 255 256 if (event()->type().isEmpty()) 257 return true; // Shouldn't happen. 258 259 ASSERT(!event()->target() || event()->target() != event()->relatedTarget()); 260 261 EventTarget* relatedTarget = event()->relatedTarget(); 262 event()->eventPath().adjustForRelatedTarget(dispatcher->node(), relatedTarget); 263 264 dispatcher->dispatch(); 265 bool swallowEvent = event()->defaultHandled() || event()->defaultPrevented(); 266 267 if (event()->type() != EventTypeNames::click || event()->detail() != 2) 268 return !swallowEvent; 269 270 // Special case: If it's a double click event, we also send the dblclick event. This is not part 271 // of the DOM specs, but is used for compatibility with the ondblclick="" attribute. This is treated 272 // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same. 273 RefPtrWillBeRawPtr<MouseEvent> doubleClickEvent = MouseEvent::create(); 274 doubleClickEvent->initMouseEvent(EventTypeNames::dblclick, event()->bubbles(), event()->cancelable(), event()->view(), 275 event()->detail(), event()->screenX(), event()->screenY(), event()->clientX(), event()->clientY(), 276 event()->ctrlKey(), event()->altKey(), event()->shiftKey(), event()->metaKey(), 277 event()->button(), relatedTarget); 278 if (event()->defaultHandled()) 279 doubleClickEvent->setDefaultHandled(); 280 EventDispatcher::dispatchEvent(dispatcher->node(), MouseEventDispatchMediator::create(doubleClickEvent)); 281 if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented()) 282 return false; 283 return !swallowEvent; 284 } 285 286 } // namespace blink 287