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