4eaa0c36261848977b4f4eabb8d953c4f54d60ed
[WebKit-https.git] / WebCore / dom / EventTargetNode.cpp
1 /*
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2001 Dirk Mueller (mueller@kde.org)
7  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  *
24  */
25
26 #include "config.h"
27 #include "EventTargetNode.h"
28
29 #include "Document.h"
30 #include "Element.h"
31 #include "Event.h"
32 #include "EventListener.h"
33 #include "EventNames.h"
34 #include "Frame.h"
35 #include "HTMLNames.h"
36 #include "TextStream.h"
37 #include "KeyboardEvent.h"
38 #include "MouseEvent.h"
39 #include "MutationEvent.h"
40 #include "PlatformMouseEvent.h"
41 #include "PlatformWheelEvent.h"
42 #include "RegisteredEventListener.h"
43 #include "UIEvent.h"
44 #include "WheelEvent.h"
45 #include "kjs_proxy.h"
46
47 namespace WebCore {
48
49 using namespace EventNames;
50 using namespace HTMLNames;
51
52 #ifndef NDEBUG
53 static int gEventDispatchForbidden = 0;
54 #endif
55
56 EventTargetNode::EventTargetNode(Document *doc)
57     : Node(doc)
58     , m_regdListeners(0)
59 {
60 }
61
62 EventTargetNode::~EventTargetNode()
63 {
64     if (m_regdListeners && !m_regdListeners->isEmpty() && !inDocument())
65         document()->unregisterDisconnectedNodeWithEventListeners(this);
66     delete m_regdListeners;
67 }
68
69 void EventTargetNode::insertedIntoDocument()
70 {
71     if (m_regdListeners && !m_regdListeners->isEmpty())
72         document()->unregisterDisconnectedNodeWithEventListeners(this);
73     
74     Node::insertedIntoDocument();
75 }
76
77 void EventTargetNode::removedFromDocument()
78 {
79     if (m_regdListeners && !m_regdListeners->isEmpty())
80         document()->registerDisconnectedNodeWithEventListeners(this);
81
82     Node::removedFromDocument();
83 }
84
85 void EventTargetNode::addEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener, const bool useCapture)
86 {
87     if (!document()->attached())
88         return;
89     
90     Document::ListenerType type = static_cast<Document::ListenerType>(0);
91     if (eventType == DOMSubtreeModifiedEvent)
92         type = Document::DOMSUBTREEMODIFIED_LISTENER;
93     else if (eventType == DOMNodeInsertedEvent)
94         type = Document::DOMNODEINSERTED_LISTENER;
95     else if (eventType == DOMNodeRemovedEvent)
96         type = Document::DOMNODEREMOVED_LISTENER;
97     else if (eventType == DOMNodeRemovedFromDocumentEvent)
98         type = Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER;
99     else if (eventType == DOMNodeInsertedIntoDocumentEvent)
100         type = Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER;
101     else if (eventType == DOMAttrModifiedEvent)
102         type = Document::DOMATTRMODIFIED_LISTENER;
103     else if (eventType == DOMCharacterDataModifiedEvent)
104         type = Document::DOMCHARACTERDATAMODIFIED_LISTENER;
105     else if (eventType == overflowchangedEvent)
106         type = Document::OVERFLOWCHANGED_LISTENER;
107         
108     if (type)
109         document()->addListenerType(type);
110     
111     if (!m_regdListeners)
112         m_regdListeners = new RegisteredEventListenerList;
113     
114     // Remove existing identical listener set with identical arguments.
115     // The DOM2 spec says that "duplicate instances are discarded" in this case.
116     removeEventListener(eventType, listener.get(), useCapture);
117     
118     // adding the first one
119     if (m_regdListeners->isEmpty() && !inDocument())
120         document()->registerDisconnectedNodeWithEventListeners(this);
121     
122     m_regdListeners->append(new RegisteredEventListener(eventType, listener.get(), useCapture));
123 }
124
125 void EventTargetNode::removeEventListener(const AtomicString &eventType, EventListener *listener, bool useCapture)
126 {
127     if (!m_regdListeners) // nothing to remove
128         return;
129     
130     RegisteredEventListener rl(eventType, listener, useCapture);
131     
132     RegisteredEventListenerList::Iterator end = m_regdListeners->end();
133     for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
134         if (*(*it).get() == rl) {
135             (*it)->setRemoved(true);
136             
137             it = m_regdListeners->remove(it);
138             // removed last
139             if (m_regdListeners->isEmpty() && !inDocument())
140                 document()->unregisterDisconnectedNodeWithEventListeners(this);
141             return;
142         }
143 }
144
145 void EventTargetNode::removeAllEventListeners()
146 {
147     delete m_regdListeners;
148     m_regdListeners = 0;
149 }
150
151 void EventTargetNode::handleLocalEvents(Event *evt, bool useCapture)
152 {
153     if (!m_regdListeners)
154         return;
155     
156     if (disabled() && evt->isMouseEvent())
157         return;
158     
159     RegisteredEventListenerList listenersCopy = *m_regdListeners;
160     RegisteredEventListenerList::Iterator end = listenersCopy.end();    
161     
162     for (RegisteredEventListenerList::Iterator it = listenersCopy.begin(); it != end; ++it)
163         if ((*it)->eventType() == evt->type() && (*it)->useCapture() == useCapture && !(*it)->removed())
164             (*it)->listener()->handleEvent(evt, false);
165 }
166
167 bool EventTargetNode::dispatchGenericEvent(PassRefPtr<Event> e, ExceptionCode&, bool tempEvent)
168 {
169     RefPtr<Event> evt(e);
170     assert(!eventDispatchForbidden());
171     assert(evt->target());
172     assert(!evt->type().isNull()); // JavaScript code could create an event with an empty name
173     
174     // work out what nodes to send event to
175     DeprecatedPtrList<Node> nodeChain;
176     Node *n;
177     for (n = this; n; n = n->parentNode()) {
178         n->ref();
179         nodeChain.prepend(n);
180     }
181     
182     DeprecatedPtrListIterator<Node> it(nodeChain);
183     
184     // Before we begin dispatching events, give the target node a chance to do some work prior
185     // to the DOM event handlers getting a crack.
186     void* data = preDispatchEventHandler(evt.get());
187     
188     // trigger any capturing event handlers on our way down
189     evt->setEventPhase(Event::CAPTURING_PHASE);
190     
191     it.toFirst();
192     // Handle window events for capture phase, except load events, this quirk is needed
193     // because Mozilla used to never propagate load events to the window object
194     if (evt->type() != loadEvent && it.current()->isDocumentNode() && !evt->propagationStopped())
195         static_cast<Document*>(it.current())->handleWindowEvent(evt.get(), true);
196     
197     for (; it.current() && it.current() != this && !evt->propagationStopped(); ++it) {
198         evt->setCurrentTarget(it.current());
199         EventTargetNodeCast(it.current())->handleLocalEvents(evt.get(), true);
200     }
201     
202     // dispatch to the actual target node
203     it.toLast();
204     if (!evt->propagationStopped()) {
205         evt->setEventPhase(Event::AT_TARGET);
206         evt->setCurrentTarget(it.current());
207         
208         // We do want capturing event listeners to be invoked here, even though
209         // that violates the specification since Mozilla does it.
210         EventTargetNodeCast(it.current())->handleLocalEvents(evt.get(), true);
211         
212         EventTargetNodeCast(it.current())->handleLocalEvents(evt.get(), false);
213     }
214     --it;
215     
216     // ok, now bubble up again (only non-capturing event handlers will be called)
217     // ### recalculate the node chain here? (e.g. if target node moved in document by previous event handlers)
218     // no. the DOM specs says:
219     // The chain of EventTargets from the event target to the top of the tree
220     // is determined before the initial dispatch of the event.
221     // If modifications occur to the tree during event processing,
222     // event flow will proceed based on the initial state of the tree.
223     //
224     // since the initial dispatch is before the capturing phase,
225     // there's no need to recalculate the node chain.
226     // (tobias)
227     
228     if (evt->bubbles()) {
229         evt->setEventPhase(Event::BUBBLING_PHASE);
230         for (; it.current() && !evt->propagationStopped() && !evt->getCancelBubble(); --it) {
231             evt->setCurrentTarget(it.current());
232             EventTargetNodeCast(it.current())->handleLocalEvents(evt.get(), false);
233         }
234         // Handle window events for bubbling phase, except load events, this quirk is needed
235         // because Mozilla used to never propagate load events at all
236
237         it.toFirst();
238         if (evt->type() != loadEvent && it.current()->isDocumentNode() && !evt->propagationStopped() && !evt->getCancelBubble()) {
239             evt->setCurrentTarget(it.current());
240             static_cast<Document*>(it.current())->handleWindowEvent(evt.get(), false);
241         } 
242     } 
243     
244     evt->setCurrentTarget(0);
245     evt->setEventPhase(0); // I guess this is correct, the spec does not seem to say
246                            // anything about the default event handler phase.
247     
248     
249     // Now call the post dispatch.
250     postDispatchEventHandler(evt.get(), data);
251     
252     // now we call all default event handlers (this is not part of DOM - it is internal to khtml)
253     
254     it.toLast();
255     if (evt->bubbles())
256         for (; it.current() && !evt->defaultPrevented() && !evt->defaultHandled(); --it)
257             EventTargetNodeCast(it.current())->defaultEventHandler(evt.get());
258     else if (!evt->defaultPrevented() && !evt->defaultHandled())
259         EventTargetNodeCast(it.current())->defaultEventHandler(evt.get());
260     
261     // deref all nodes in chain
262     it.toFirst();
263     for (; it.current(); ++it)
264         it.current()->deref(); // this may delete us
265     
266     Document::updateDocumentsRendering();
267     
268     // If tempEvent is true, this means that the DOM implementation
269     // will not be storing a reference to the event, i.e.  there is no
270     // way to retrieve it from javascript if a script does not already
271     // have a reference to it in a variable.  So there is no need for
272     // the interpreter to keep the event in it's cache
273     Frame *frame = document()->frame();
274     if (tempEvent && frame && frame->jScript())
275         frame->jScript()->finishedWithEvent(evt.get());
276     
277     return !evt->defaultPrevented(); // ### what if defaultPrevented was called before dispatchEvent?
278 }
279
280 bool EventTargetNode::dispatchEvent(PassRefPtr<Event> e, ExceptionCode& ec, bool tempEvent)
281 {
282     RefPtr<Event> evt(e);
283     assert(!eventDispatchForbidden());
284     if (!evt || evt->type().isEmpty()) { 
285         ec = UNSPECIFIED_EVENT_TYPE_ERR;
286         return false;
287     }
288     evt->setTarget(this);
289     
290     RefPtr<FrameView> view = document()->view();
291     
292     return dispatchGenericEvent(evt.release(), ec, tempEvent);
293 }
294
295 bool EventTargetNode::dispatchSubtreeModifiedEvent(bool sendChildrenChanged)
296 {
297     assert(!eventDispatchForbidden());
298     
299     // FIXME: Pull this whole if clause out of this function.
300     if (sendChildrenChanged) {
301         notifyNodeListsChildrenChanged();
302         childrenChanged();
303     } else
304         notifyNodeListsAttributeChanged(); // FIXME: Can do better some day. Really only care about the name attribute changing.
305     
306     if (!document()->hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER))
307         return false;
308     ExceptionCode ec = 0;
309     return dispatchEvent(new MutationEvent(DOMSubtreeModifiedEvent,
310                                                true,false,0,String(),String(),String(),0),ec,true);
311 }
312
313 void EventTargetNode::dispatchWindowEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg)
314 {
315     assert(!eventDispatchForbidden());
316     ExceptionCode ec = 0;
317     RefPtr<Event> evt = new Event(eventType, canBubbleArg, cancelableArg);
318     RefPtr<Document> doc = document();
319     evt->setTarget(doc.get());
320     doc->handleWindowEvent(evt.get(), true);
321     doc->handleWindowEvent(evt.get(), false);
322     
323     if (eventType == loadEvent) {
324         // For onload events, send a separate load event to the enclosing frame only.
325         // This is a DOM extension and is independent of bubbling/capturing rules of
326         // the DOM.
327         Element* ownerElement = doc->ownerElement();
328         if (ownerElement) {
329             RefPtr<Event> ownerEvent = new Event(eventType, false, cancelableArg);
330             ownerEvent->setTarget(ownerElement);
331             ownerElement->dispatchGenericEvent(ownerEvent.release(), ec, true);
332         }
333     }
334 }
335
336 bool EventTargetNode::dispatchUIEvent(const AtomicString &eventType, int detail)
337 {
338     assert(!eventDispatchForbidden());
339     assert(eventType == DOMFocusInEvent || eventType == DOMFocusOutEvent || eventType == DOMActivateEvent);
340     
341     bool cancelable = eventType == DOMActivateEvent;
342     
343     ExceptionCode ec = 0;
344     UIEvent* evt = new UIEvent(eventType, true, cancelable, document()->defaultView(), detail);
345     return dispatchEvent(evt, ec, true);
346 }
347
348 bool EventTargetNode::dispatchKeyEvent(const PlatformKeyboardEvent& key)
349 {
350     assert(!eventDispatchForbidden());
351     ExceptionCode ec = 0;
352     RefPtr<KeyboardEvent> keyboardEvent = new KeyboardEvent(key, document()->defaultView());
353     bool r = dispatchEvent(keyboardEvent,ec,true);
354     
355     // we want to return false if default is prevented (already taken care of)
356     // or if the element is default-handled by the DOM. Otherwise we let it just
357     // let it get handled by AppKit 
358     if (keyboardEvent->defaultHandled())
359         r = false;
360     
361     return r;
362 }
363
364 bool EventTargetNode::dispatchMouseEvent(const PlatformMouseEvent& _mouse, const AtomicString& eventType,
365                                              int detail, Node* relatedTarget)
366 {
367     assert(!eventDispatchForbidden());
368     
369     IntPoint contentsPos;
370     if (FrameView* view = document()->view())
371         contentsPos = view->viewportToContents(_mouse.pos());
372     
373     return dispatchMouseEvent(eventType, _mouse.button(), detail,
374                               contentsPos.x(), contentsPos.y(), _mouse.globalX(), _mouse.globalY(),
375                               _mouse.ctrlKey(), _mouse.altKey(), _mouse.shiftKey(), _mouse.metaKey(),
376                               false, relatedTarget);
377 }
378
379 bool EventTargetNode::dispatchSimulatedMouseEvent(const AtomicString &eventType)
380 {
381     assert(!eventDispatchForbidden());
382     // Like Gecko, we just pass 0 for everything when we make a fake mouse event.
383     // Internet Explorer instead gives the current mouse position and state.
384     return dispatchMouseEvent(eventType, 0, 0, 0, 0, 0, 0, false, false, false, false, true);
385 }
386
387 bool EventTargetNode::dispatchMouseEvent(const AtomicString& eventType, int button, int detail,
388                                              int pageX, int pageY, int screenX, int screenY,
389                                              bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, 
390                                              bool isSimulated, Node* relatedTargetArg)
391 {
392     assert(!eventDispatchForbidden());
393     if (disabled()) // Don't even send DOM events for disabled controls..
394         return true;
395     
396     if (eventType.isEmpty())
397         return false; // Shouldn't happen.
398     
399     // Dispatching the first event can easily result in this node being destroyed.
400     // Since we dispatch up to three events here, we need to make sure we're referenced
401     // so the pointer will be good for the two subsequent ones.
402     RefPtr<Node> protect(this);
403     
404     bool cancelable = eventType != mousemoveEvent;
405     
406     ExceptionCode ec = 0;
407     
408     bool swallowEvent = false;
409     
410     // Attempting to dispatch with a non-EventTarget relatedTarget causes the relatedTarget to be silently ignored.
411     EventTargetNode *relatedTarget = (relatedTargetArg && relatedTargetArg->isEventTargetNode()) ? static_cast<EventTargetNode*>(relatedTargetArg) : 0;
412
413     RefPtr<Event> me = new MouseEvent(eventType, true, cancelable, document()->defaultView(),
414                                               detail, screenX, screenY, pageX, pageY,
415                                               ctrlKey, altKey, shiftKey, metaKey, button,
416                                               relatedTarget, 0, isSimulated);
417     
418     dispatchEvent(me, ec, true);
419     bool defaultHandled = me->defaultHandled();
420     bool defaultPrevented = me->defaultPrevented();
421     if (defaultHandled || defaultPrevented)
422         swallowEvent = true;
423     
424     // Special case: If it's a double click event, we also send the dblclick event. This is not part
425     // of the DOM specs, but is used for compatibility with the ondblclick="" attribute.  This is treated
426     // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same.
427     if (eventType == clickEvent && detail == 2) {
428         me = new MouseEvent(dblclickEvent, true, cancelable, document()->defaultView(),
429                                 detail, screenX, screenY, pageX, pageY,
430                                 ctrlKey, altKey, shiftKey, metaKey, button,
431                                 relatedTarget, 0, isSimulated);
432         if (defaultHandled)
433             me->setDefaultHandled();
434         dispatchEvent(me, ec, true);
435         if (me->defaultHandled() || me->defaultPrevented())
436             swallowEvent = true;
437     }
438     
439     // Also send a DOMActivate event, which causes things like form submissions to occur.
440     if (eventType == clickEvent && !defaultPrevented)
441         dispatchUIEvent(DOMActivateEvent, detail);
442     
443     return swallowEvent;
444 }
445
446 void EventTargetNode::dispatchWheelEvent(PlatformWheelEvent& e)
447 {
448     assert(!eventDispatchForbidden());
449     if (e.deltaX() == 0 && e.deltaY() == 0)
450         return;
451     
452     FrameView* view = document()->view();
453     if (!view)
454         return;
455     
456     IntPoint pos = view->viewportToContents(e.pos());
457     
458     RefPtr<WheelEvent> we = new WheelEvent(e.deltaX(), e.deltaY(),
459                                            document()->defaultView(), e.globalX(), e.globalY(), pos.x(), pos.y(),
460                                            e.ctrlKey(), e.altKey(), e.shiftKey(), e.metaKey());
461     ExceptionCode ec = 0;
462     if (!dispatchEvent(we, ec, true))
463         e.accept();
464 }
465
466
467 void EventTargetNode::dispatchFocusEvent()
468 {
469     dispatchHTMLEvent(focusEvent, false, false);
470 }
471
472 void EventTargetNode::dispatchBlurEvent()
473 {
474     dispatchHTMLEvent(blurEvent, false, false);
475 }
476
477 bool EventTargetNode::dispatchHTMLEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg)
478 {
479     assert(!eventDispatchForbidden());
480     ExceptionCode ec = 0;
481     return dispatchEvent(new Event(eventType, canBubbleArg, cancelableArg), ec, true);
482 }
483
484 void EventTargetNode::removeHTMLEventListener(const AtomicString &eventType)
485 {
486     if (!m_regdListeners) // nothing to remove
487         return;
488     
489     RegisteredEventListenerList::Iterator end = m_regdListeners->end();
490     for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
491         if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener()) {
492             it = m_regdListeners->remove(it);
493             // removed last
494             if (m_regdListeners->isEmpty() && !inDocument())
495                 document()->unregisterDisconnectedNodeWithEventListeners(this);
496             return;
497         }
498 }
499
500 void EventTargetNode::setHTMLEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener)
501 {
502     // In case we are the only one holding a reference to it, we don't want removeHTMLEventListener to destroy it.
503     removeHTMLEventListener(eventType);
504     if (listener)
505         addEventListener(eventType, listener.get(), false);
506 }
507
508 EventListener *EventTargetNode::getHTMLEventListener(const AtomicString &eventType)
509 {
510     if (!m_regdListeners)
511         return 0;
512     
513     RegisteredEventListenerList::Iterator end = m_regdListeners->end();
514     for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
515         if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener())
516             return (*it)->listener();
517     return 0;
518 }
519
520 bool EventTargetNode::disabled() const
521 {
522     return false;
523 }
524
525 void EventTargetNode::defaultEventHandler(Event *evt)
526 {
527 }
528
529 #ifndef NDEBUG
530
531 void EventTargetNode::dump(TextStream* stream, DeprecatedString ind) const
532 {
533     if (m_regdListeners)
534         *stream << " #regdListeners=" << m_regdListeners->count(); // ### more detail
535     
536     Node::dump(stream,ind);
537 }
538
539 void forbidEventDispatch()
540 {
541     ++gEventDispatchForbidden;
542 }
543
544 void allowEventDispatch()
545 {
546     if (gEventDispatchForbidden > 0)
547         --gEventDispatchForbidden;
548 }
549
550 bool eventDispatchForbidden()
551 {
552     return gEventDispatchForbidden > 0;
553 }
554
555 #endif
556
557 } // namespace WebCore