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