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/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 35 namespace WebCore { 36 37 MouseEventInit::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 51 PassRefPtr<MouseEvent> MouseEvent::create(const AtomicString& type, const MouseEventInit& initializer) 52 { 53 return adoptRef(new MouseEvent(type, initializer)); 54 } 55 56 PassRefPtr<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 60 bool isMouseEnterOrLeave = eventType == eventNames().mouseenterEvent || eventType == eventNames().mouseleaveEvent; 61 bool isCancelable = eventType != eventNames().mousemoveEvent && !isMouseEnterOrLeave; 62 bool isBubbling = !isMouseEnterOrLeave; 63 64 return MouseEvent::create(eventType, isBubbling, isCancelable, view, 65 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 71 PassRefPtr<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 84 PassRefPtr<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 96 MouseEvent::MouseEvent() 97 : m_button(0) 98 , m_buttonDown(false) 99 { 100 ScriptWrappable::init(this); 101 } 102 103 MouseEvent::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 121 MouseEvent::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 135 MouseEvent::~MouseEvent() 136 { 137 } 138 139 void 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 164 const AtomicString& MouseEvent::interfaceName() const 165 { 166 return eventNames().interfaceForMouseEvent; 167 } 168 169 bool MouseEvent::isMouseEvent() const 170 { 171 return true; 172 } 173 174 bool 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 181 int MouseEvent::which() const 182 { 183 // For the DOM, the return values for left, middle and right mouse buttons are 0, 1, 2, respectively. 184 // For the Netscape "which" property, the return values for left, middle and right mouse buttons are 1, 2, 3, respectively. 185 // So we must add 1. 186 if (!m_buttonDown) 187 return 0; 188 return m_button + 1; 189 } 190 191 Node* MouseEvent::toElement() const 192 { 193 // MSIE extension - "the object toward which the user is moving the mouse pointer" 194 if (type() == eventNames().mouseoutEvent || type() == eventNames().mouseleaveEvent) 195 return relatedTarget() ? relatedTarget()->toNode() : 0; 196 197 return target() ? target()->toNode() : 0; 198 } 199 200 Node* MouseEvent::fromElement() const 201 { 202 // MSIE extension - "object from which activation or the mouse pointer is exiting during the event" (huh?) 203 if (type() != eventNames().mouseoutEvent && type() != eventNames().mouseleaveEvent) 204 return relatedTarget() ? relatedTarget()->toNode() : 0; 205 206 return target() ? target()->toNode() : 0; 207 } 208 209 PassRefPtr<SimulatedMouseEvent> SimulatedMouseEvent::create(const AtomicString& eventType, PassRefPtr<AbstractView> view, PassRefPtr<Event> underlyingEvent) 210 { 211 return adoptRef(new SimulatedMouseEvent(eventType, view, underlyingEvent)); 212 } 213 214 SimulatedMouseEvent::~SimulatedMouseEvent() 215 { 216 } 217 218 SimulatedMouseEvent::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()) { 232 MouseEvent* mouseEvent = toMouseEvent(this->underlyingEvent()); 233 m_screenLocation = mouseEvent->screenLocation(); 234 initCoordinates(mouseEvent->clientLocation()); 235 } 236 } 237 238 PassRefPtr<MouseEventDispatchMediator> MouseEventDispatchMediator::create(PassRefPtr<MouseEvent> mouseEvent, MouseEventType mouseEventType) 239 { 240 return adoptRef(new MouseEventDispatchMediator(mouseEvent, mouseEventType)); 241 } 242 243 MouseEventDispatchMediator::MouseEventDispatchMediator(PassRefPtr<MouseEvent> mouseEvent, MouseEventType mouseEventType) 244 : EventDispatchMediator(mouseEvent), m_mouseEventType(mouseEventType) 245 { 246 } 247 248 MouseEvent* MouseEventDispatchMediator::event() const 249 { 250 return toMouseEvent(EventDispatchMediator::event()); 251 } 252 253 bool 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 294