f44f3a48c3ae05f458d66be672476cf4b1675aa1
[WebKit-https.git] / WebCore / dom / EventTargetNode.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
6  *           (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "config.h"
26 #include "EventTargetNode.h"
27
28 #include "Document.h"
29 #include "Event.h"
30 #include "EventHandler.h"
31 #include "EventListener.h"
32 #include "EventNames.h"
33 #include "Frame.h"
34 #include "FrameView.h"
35 #include "KeyboardEvent.h"
36 #include "MouseEvent.h"
37 #include "MutationEvent.h"
38 #include "Page.h"
39 #include "PlatformMouseEvent.h"
40 #include "PlatformWheelEvent.h"
41 #include "ProgressEvent.h"
42 #include "RegisteredEventListener.h"
43 #include "TextEvent.h"
44 #include "TextStream.h"
45 #include "WheelEvent.h"
46
47 namespace WebCore {
48
49 using namespace EventNames;
50
51 EventTargetNode::EventTargetNode(Document *doc)
52     : Node(doc)
53     , m_regdListeners(0)
54 {
55 }
56
57 EventTargetNode::~EventTargetNode()
58 {
59     if (m_regdListeners && !m_regdListeners->isEmpty() && !inDocument())
60         document()->unregisterDisconnectedNodeWithEventListeners(this);
61
62     delete m_regdListeners;
63     m_regdListeners = 0;
64 }
65
66 void EventTargetNode::insertedIntoDocument()
67 {
68     EventTarget::insertedIntoDocument(this);
69     Node::insertedIntoDocument();
70 }
71
72 void EventTargetNode::removedFromDocument()
73 {
74     EventTarget::removedFromDocument(this);
75     Node::removedFromDocument();
76 }
77
78 void EventTargetNode::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
79 {
80     EventTarget::addEventListener(this, eventType, listener, useCapture);
81 }
82
83 void EventTargetNode::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
84 {
85     EventTarget::removeEventListener(this, eventType, listener, useCapture);
86 }
87
88 void EventTargetNode::removeAllEventListeners()
89 {
90     EventTarget::removeAllEventListeners(this);
91 }
92
93 void EventTargetNode::handleLocalEvents(Event *evt, bool useCapture)
94 {
95     if (disabled() && evt->isMouseEvent())
96         return;
97
98     EventTarget::handleLocalEvents(this, evt, useCapture);    
99 }
100
101 bool EventTargetNode::dispatchEvent(PassRefPtr<Event> e, ExceptionCode& ec, bool tempEvent)
102 {
103     RefPtr<Event> evt(e);
104     ASSERT(!eventDispatchForbidden());
105     if (!evt || evt->type().isEmpty()) { 
106         ec = UNSPECIFIED_EVENT_TYPE_ERR;
107         return false;
108     }
109
110     EventTargetNode* eventTarget = this;
111     evt->setTarget(eventTargetRespectingSVGTargetRules(eventTarget));
112
113     RefPtr<FrameView> view = document()->view();
114     return dispatchGenericEvent(eventTarget, evt.release(), ec, tempEvent);
115 }
116
117 bool EventTargetNode::dispatchSubtreeModifiedEvent(bool sendChildrenChanged)
118 {
119     ASSERT(!eventDispatchForbidden());
120     
121     // FIXME: Pull this whole if clause out of this function.
122     if (sendChildrenChanged) {
123         notifyNodeListsChildrenChanged();
124         childrenChanged();
125     } else
126         notifyNodeListsAttributeChanged(); // FIXME: Can do better some day. Really only care about the name attribute changing.
127     
128     if (!document()->hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER))
129         return false;
130     ExceptionCode ec = 0;
131     return dispatchEvent(new MutationEvent(DOMSubtreeModifiedEvent,
132                                                true,false,0,String(),String(),String(),0),ec,true);
133 }
134
135 void EventTargetNode::dispatchWindowEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg)
136 {
137     ASSERT(!eventDispatchForbidden());
138     ExceptionCode ec = 0;
139     RefPtr<Event> evt = new Event(eventType, canBubbleArg, cancelableArg);
140     RefPtr<Document> doc = document();
141     evt->setTarget(doc);
142     doc->handleWindowEvent(evt.get(), true);
143     doc->handleWindowEvent(evt.get(), false);
144     
145     if (eventType == loadEvent) {
146         // For onload events, send a separate load event to the enclosing frame only.
147         // This is a DOM extension and is independent of bubbling/capturing rules of
148         // the DOM.
149         Element* ownerElement = doc->ownerElement();
150         if (ownerElement) {
151             RefPtr<Event> ownerEvent = new Event(eventType, false, cancelableArg);
152             ownerEvent->setTarget(ownerElement);
153             ownerElement->dispatchGenericEvent(ownerElement, ownerEvent.release(), ec, true);
154         }
155     }
156 }
157
158 bool EventTargetNode::dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr<Event> underlyingEvent)
159 {
160     ASSERT(!eventDispatchForbidden());
161     ASSERT(eventType == DOMFocusInEvent || eventType == DOMFocusOutEvent || eventType == DOMActivateEvent);
162     
163     bool cancelable = eventType == DOMActivateEvent;
164     
165     ExceptionCode ec = 0;
166     RefPtr<UIEvent> evt = new UIEvent(eventType, true, cancelable, document()->defaultView(), detail);
167     evt->setUnderlyingEvent(underlyingEvent);
168     return dispatchEvent(evt.release(), ec, true);
169 }
170
171 bool EventTargetNode::dispatchKeyEvent(const PlatformKeyboardEvent& key)
172 {
173     ASSERT(!eventDispatchForbidden());
174     ExceptionCode ec = 0;
175     RefPtr<KeyboardEvent> keyboardEvent = new KeyboardEvent(key, document()->defaultView());
176     bool r = dispatchEvent(keyboardEvent,ec,true);
177     
178     // we want to return false if default is prevented (already taken care of)
179     // or if the element is default-handled by the DOM. Otherwise we let it just
180     // let it get handled by AppKit 
181     if (keyboardEvent->defaultHandled())
182         r = false;
183     
184     return r;
185 }
186
187 bool EventTargetNode::dispatchMouseEvent(const PlatformMouseEvent& event, const AtomicString& eventType,
188     int detail, Node* relatedTarget)
189 {
190     ASSERT(!eventDispatchForbidden());
191     
192     IntPoint contentsPos;
193     if (FrameView* view = document()->view())
194         contentsPos = view->windowToContents(event.pos());
195
196     short button = event.button();
197
198     ASSERT(event.eventType() == MouseEventMoved || button != NoButton);
199     
200     return dispatchMouseEvent(eventType, button, detail,
201         contentsPos.x(), contentsPos.y(), event.globalX(), event.globalY(),
202         event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
203         false, relatedTarget);
204 }
205
206 void EventTargetNode::dispatchSimulatedMouseEvent(const AtomicString& eventType,
207     PassRefPtr<Event> underlyingEvent)
208 {
209     ASSERT(!eventDispatchForbidden());
210     
211     if (m_dispatchingSimulatedEvent)
212         return;
213
214     bool ctrlKey = false;
215     bool altKey = false;
216     bool shiftKey = false;
217     bool metaKey = false;
218     if (UIEventWithKeyState* keyStateEvent = findEventWithKeyState(underlyingEvent.get())) {
219         ctrlKey = keyStateEvent->ctrlKey();
220         altKey = keyStateEvent->altKey();
221         shiftKey = keyStateEvent->shiftKey();
222         metaKey = keyStateEvent->metaKey();
223     }
224     
225     m_dispatchingSimulatedEvent = true;
226
227     // Like Gecko, we just pass 0 for everything when we make a fake mouse event.
228     // Internet Explorer instead gives the current mouse position and state.
229     dispatchMouseEvent(eventType, 0, 0, 0, 0, 0, 0,
230         ctrlKey, altKey, shiftKey, metaKey, true, 0, underlyingEvent);
231     
232     m_dispatchingSimulatedEvent = false;
233 }
234
235 void EventTargetNode::dispatchSimulatedClick(PassRefPtr<Event> event, bool sendMouseEvents, bool showPressedLook)
236 {
237     if (m_dispatchingSimulatedEvent)
238         return;
239     
240     // send mousedown and mouseup before the click, if requested
241     if (sendMouseEvents)
242         dispatchSimulatedMouseEvent(mousedownEvent, event.get());
243     setActive(true, showPressedLook);
244     if (sendMouseEvents)
245         dispatchSimulatedMouseEvent(mouseupEvent, event.get());
246     setActive(false);
247
248     // always send click
249     dispatchSimulatedMouseEvent(clickEvent, event);
250 }
251
252 bool EventTargetNode::dispatchMouseEvent(const AtomicString& eventType, int button, int detail,
253     int pageX, int pageY, int screenX, int screenY,
254     bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, 
255     bool isSimulated, Node* relatedTargetArg, PassRefPtr<Event> underlyingEvent)
256 {
257     ASSERT(!eventDispatchForbidden());
258     if (disabled()) // Don't even send DOM events for disabled controls..
259         return true;
260     
261     if (eventType.isEmpty())
262         return false; // Shouldn't happen.
263     
264     // Dispatching the first event can easily result in this node being destroyed.
265     // Since we dispatch up to three events here, we need to make sure we're referenced
266     // so the pointer will be good for the two subsequent ones.
267     RefPtr<Node> protect(this);
268     
269     bool cancelable = eventType != mousemoveEvent;
270     
271     ExceptionCode ec = 0;
272     
273     bool swallowEvent = false;
274     
275     // Attempting to dispatch with a non-EventTarget relatedTarget causes the relatedTarget to be silently ignored.
276     RefPtr<EventTargetNode> relatedTarget = (relatedTargetArg && relatedTargetArg->isEventTargetNode())
277         ? static_cast<EventTargetNode*>(relatedTargetArg) : 0;
278
279     RefPtr<Event> mouseEvent = new MouseEvent(eventType,
280         true, cancelable, document()->defaultView(),
281         detail, screenX, screenY, pageX, pageY,
282         ctrlKey, altKey, shiftKey, metaKey, button,
283         relatedTarget.get(), 0, isSimulated);
284     mouseEvent->setUnderlyingEvent(underlyingEvent.get());
285     
286     dispatchEvent(mouseEvent, ec, true);
287     bool defaultHandled = mouseEvent->defaultHandled();
288     bool defaultPrevented = mouseEvent->defaultPrevented();
289     if (defaultHandled || defaultPrevented)
290         swallowEvent = true;
291     
292     // Special case: If it's a double click event, we also send the dblclick event. This is not part
293     // of the DOM specs, but is used for compatibility with the ondblclick="" attribute.  This is treated
294     // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same.
295     if (eventType == clickEvent && detail == 2) {
296         RefPtr<Event> doubleClickEvent = new MouseEvent(dblclickEvent,
297             true, cancelable, document()->defaultView(),
298             detail, screenX, screenY, pageX, pageY,
299             ctrlKey, altKey, shiftKey, metaKey, button,
300             relatedTarget.get(), 0, isSimulated);
301         doubleClickEvent->setUnderlyingEvent(underlyingEvent.get());
302         if (defaultHandled)
303             doubleClickEvent->setDefaultHandled();
304         dispatchEvent(doubleClickEvent, ec, true);
305         if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented())
306             swallowEvent = true;
307     }
308
309     return swallowEvent;
310 }
311
312 void EventTargetNode::dispatchWheelEvent(PlatformWheelEvent& e)
313 {
314     ASSERT(!eventDispatchForbidden());
315     if (e.deltaX() == 0 && e.deltaY() == 0)
316         return;
317     
318     FrameView* view = document()->view();
319     if (!view)
320         return;
321     
322     IntPoint pos = view->windowToContents(e.pos());
323     
324     RefPtr<WheelEvent> we = new WheelEvent(e.deltaX(), e.deltaY(),
325                                            document()->defaultView(), e.globalX(), e.globalY(), pos.x(), pos.y(),
326                                            e.ctrlKey(), e.altKey(), e.shiftKey(), e.metaKey());
327     ExceptionCode ec = 0;
328     if (!dispatchEvent(we, ec, true))
329         e.accept();
330 }
331
332
333 void EventTargetNode::dispatchFocusEvent()
334 {
335     dispatchHTMLEvent(focusEvent, false, false);
336 }
337
338 void EventTargetNode::dispatchBlurEvent()
339 {
340     dispatchHTMLEvent(blurEvent, false, false);
341 }
342
343 bool EventTargetNode::dispatchHTMLEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg)
344 {
345     ASSERT(!eventDispatchForbidden());
346     ExceptionCode ec = 0;
347     return dispatchEvent(new Event(eventType, canBubbleArg, cancelableArg), ec, true);
348 }
349
350 bool EventTargetNode::dispatchProgressEvent(const AtomicString &eventType, bool lengthComputableArg, unsigned loadedArg, unsigned totalArg)
351 {
352     ASSERT(!eventDispatchForbidden());
353     ExceptionCode ec = 0;
354     return dispatchEvent(new ProgressEvent(eventType, lengthComputableArg, loadedArg, totalArg), ec, true);
355 }
356
357 void EventTargetNode::removeHTMLEventListener(const AtomicString &eventType)
358 {
359     if (!m_regdListeners) // nothing to remove
360         return;
361     
362     RegisteredEventListenerList::Iterator end = m_regdListeners->end();
363     for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
364         if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener()) {
365             it = m_regdListeners->remove(it);
366             // removed last
367             if (m_regdListeners->isEmpty() && !inDocument())
368                 document()->unregisterDisconnectedNodeWithEventListeners(this);
369             return;
370         }
371 }
372
373 void EventTargetNode::setHTMLEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener)
374 {
375     // In case we are the only one holding a reference to it, we don't want removeHTMLEventListener to destroy it.
376     removeHTMLEventListener(eventType);
377     if (listener)
378         addEventListener(eventType, listener.get(), false);
379 }
380
381 EventListener *EventTargetNode::getHTMLEventListener(const AtomicString &eventType)
382 {
383     if (!m_regdListeners)
384         return 0;
385     
386     RegisteredEventListenerList::Iterator end = m_regdListeners->end();
387     for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
388         if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener())
389             return (*it)->listener();
390     return 0;
391 }
392
393 bool EventTargetNode::disabled() const
394 {
395     return false;
396 }
397
398 void EventTargetNode::defaultEventHandler(Event* event)
399 {
400     if (event->target() != this)
401         return;
402     const AtomicString& eventType = event->type();
403     if (eventType == keydownEvent || eventType == keypressEvent) {
404         if (event->isKeyboardEvent())
405             if (Frame* frame = document()->frame())
406                 frame->eventHandler()->defaultKeyboardEventHandler(static_cast<KeyboardEvent*>(event));
407     } else if (eventType == clickEvent) {
408         int detail = event->isUIEvent() ? static_cast<UIEvent*>(event)->detail() : 0;
409         dispatchUIEvent(DOMActivateEvent, detail, event);
410     } else if (eventType == contextmenuEvent) {
411         if (Frame* frame = document()->frame())
412             if (Page* page = frame->page())
413                 page->contextMenuController()->handleContextMenuEvent(event);
414     } else if (eventType == textInputEvent) {
415         if (event->isTextEvent())
416             if (Frame* frame = document()->frame())
417                 frame->eventHandler()->defaultTextInputEventHandler(static_cast<TextEvent*>(event));
418     }
419 }
420
421 #ifndef NDEBUG
422
423 void EventTargetNode::dump(TextStream* stream, DeprecatedString ind) const
424 {
425     if (m_regdListeners)
426         *stream << " #regdListeners=" << m_regdListeners->count(); // ### more detail
427     
428     Node::dump(stream,ind);
429 }
430
431 #endif
432
433 } // namespace WebCore