LayoutTests:
[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  *
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., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  *
22  */
23
24 #include "config.h"
25 #include "EventTargetNode.h"
26
27 #include "ContextMenuController.h"
28 #include "Document.h"
29 #include "Element.h"
30 #include "Event.h"
31 #include "EventHandler.h"
32 #include "EventListener.h"
33 #include "EventNames.h"
34 #include "FocusController.h"
35 #include "Frame.h"
36 #include "FrameView.h"
37 #include "HTMLNames.h"
38 #include "TextStream.h"
39 #include "KeyboardEvent.h"
40 #include "MouseEvent.h"
41 #include "MutationEvent.h"
42 #include "Page.h"
43 #include "PlatformMouseEvent.h"
44 #include "PlatformWheelEvent.h"
45 #include "RegisteredEventListener.h"
46 #include "TextEvent.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     
181     if (inDocument()) {
182         for (Node* n = this; n; n = n->eventParentNode()) {
183             n->ref();
184             nodeChain.prepend(n);
185         } 
186     } else {
187         // if node is not in the document just send event to itself 
188         ref();
189         nodeChain.prepend(this);
190     }
191     
192     DeprecatedPtrListIterator<Node> it(nodeChain);
193     
194     // Before we begin dispatching events, give the target node a chance to do some work prior
195     // to the DOM event handlers getting a crack.
196     void* data = preDispatchEventHandler(evt.get());
197     
198     // trigger any capturing event handlers on our way down
199     evt->setEventPhase(Event::CAPTURING_PHASE);
200     
201     it.toFirst();
202     // Handle window events for capture phase, except load events, this quirk is needed
203     // because Mozilla used to never propagate load events to the window object
204     if (evt->type() != loadEvent && it.current()->isDocumentNode() && !evt->propagationStopped())
205         static_cast<Document*>(it.current())->handleWindowEvent(evt.get(), true);
206     
207     for (; it.current() && it.current() != this && !evt->propagationStopped(); ++it) {
208         evt->setCurrentTarget(EventTargetNodeCast(it.current()));
209         EventTargetNodeCast(it.current())->handleLocalEvents(evt.get(), true);
210     }
211     
212     // dispatch to the actual target node
213     it.toLast();
214     if (!evt->propagationStopped()) {
215         evt->setEventPhase(Event::AT_TARGET);
216         evt->setCurrentTarget(EventTargetNodeCast(it.current()));
217         
218         // We do want capturing event listeners to be invoked here, even though
219         // that violates the specification since Mozilla does it.
220         EventTargetNodeCast(it.current())->handleLocalEvents(evt.get(), true);
221         
222         EventTargetNodeCast(it.current())->handleLocalEvents(evt.get(), false);
223     }
224     --it;
225     
226     // ok, now bubble up again (only non-capturing event handlers will be called)
227     // ### recalculate the node chain here? (e.g. if target node moved in document by previous event handlers)
228     // no. the DOM specs says:
229     // The chain of EventTargets from the event target to the top of the tree
230     // is determined before the initial dispatch of the event.
231     // If modifications occur to the tree during event processing,
232     // event flow will proceed based on the initial state of the tree.
233     //
234     // since the initial dispatch is before the capturing phase,
235     // there's no need to recalculate the node chain.
236     // (tobias)
237     
238     if (evt->bubbles()) {
239         evt->setEventPhase(Event::BUBBLING_PHASE);
240         for (; it.current() && !evt->propagationStopped() && !evt->cancelBubble(); --it) {
241             evt->setCurrentTarget(EventTargetNodeCast(it.current()));
242             EventTargetNodeCast(it.current())->handleLocalEvents(evt.get(), false);
243         }
244         // Handle window events for bubbling phase, except load events, this quirk is needed
245         // because Mozilla used to never propagate load events at all
246
247         it.toFirst();
248         if (evt->type() != loadEvent && it.current()->isDocumentNode() && !evt->propagationStopped() && !evt->cancelBubble()) {
249             evt->setCurrentTarget(EventTargetNodeCast(it.current()));
250             static_cast<Document*>(it.current())->handleWindowEvent(evt.get(), false);
251         } 
252     } 
253     
254     evt->setCurrentTarget(0);
255     evt->setEventPhase(0); // I guess this is correct, the spec does not seem to say
256                            // anything about the default event handler phase.
257     
258     
259     // Now call the post dispatch.
260     postDispatchEventHandler(evt.get(), data);
261     
262     // now we call all default event handlers (this is not part of DOM - it is internal to khtml)
263     
264     it.toLast();
265     if (evt->bubbles())
266         for (; it.current() && !evt->defaultPrevented() && !evt->defaultHandled(); --it)
267             EventTargetNodeCast(it.current())->defaultEventHandler(evt.get());
268     else if (!evt->defaultPrevented() && !evt->defaultHandled())
269         EventTargetNodeCast(it.current())->defaultEventHandler(evt.get());
270     
271     // deref all nodes in chain
272     it.toFirst();
273     for (; it.current(); ++it)
274         it.current()->deref(); // this may delete us
275     
276     Document::updateDocumentsRendering();
277     
278     // If tempEvent is true, this means that the DOM implementation
279     // will not be storing a reference to the event, i.e.  there is no
280     // way to retrieve it from javascript if a script does not already
281     // have a reference to it in a variable.  So there is no need for
282     // the interpreter to keep the event in it's cache
283     Frame *frame = document()->frame();
284     if (tempEvent && frame && frame->scriptProxy())
285         frame->scriptProxy()->finishedWithEvent(evt.get());
286     
287     return !evt->defaultPrevented(); // ### what if defaultPrevented was called before dispatchEvent?
288 }
289
290 bool EventTargetNode::dispatchEvent(PassRefPtr<Event> e, ExceptionCode& ec, bool tempEvent)
291 {
292     return dispatchEvent(e, ec, tempEvent, this);
293 }
294
295 bool EventTargetNode::dispatchEvent(PassRefPtr<Event> e, ExceptionCode& ec, bool tempEvent, EventTarget* target)
296 {
297     RefPtr<Event> evt(e);
298     ASSERT(!eventDispatchForbidden());
299     if (!evt || evt->type().isEmpty()) { 
300         ec = UNSPECIFIED_EVENT_TYPE_ERR;
301         return false;
302     }
303
304     evt->setTarget(target);
305     
306     RefPtr<FrameView> view = document()->view();
307     
308     return dispatchGenericEvent(evt.release(), ec, tempEvent);
309 }
310
311 bool EventTargetNode::dispatchSubtreeModifiedEvent(bool sendChildrenChanged)
312 {
313     ASSERT(!eventDispatchForbidden());
314     
315     // FIXME: Pull this whole if clause out of this function.
316     if (sendChildrenChanged) {
317         notifyNodeListsChildrenChanged();
318         childrenChanged();
319     } else
320         notifyNodeListsAttributeChanged(); // FIXME: Can do better some day. Really only care about the name attribute changing.
321     
322     if (!document()->hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER))
323         return false;
324     ExceptionCode ec = 0;
325     return dispatchEvent(new MutationEvent(DOMSubtreeModifiedEvent,
326                                                true,false,0,String(),String(),String(),0),ec,true);
327 }
328
329 void EventTargetNode::dispatchWindowEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg)
330 {
331     ASSERT(!eventDispatchForbidden());
332     ExceptionCode ec = 0;
333     RefPtr<Event> evt = new Event(eventType, canBubbleArg, cancelableArg);
334     RefPtr<Document> doc = document();
335     evt->setTarget(doc);
336     doc->handleWindowEvent(evt.get(), true);
337     doc->handleWindowEvent(evt.get(), false);
338     
339     if (eventType == loadEvent) {
340         // For onload events, send a separate load event to the enclosing frame only.
341         // This is a DOM extension and is independent of bubbling/capturing rules of
342         // the DOM.
343         Element* ownerElement = doc->ownerElement();
344         if (ownerElement) {
345             RefPtr<Event> ownerEvent = new Event(eventType, false, cancelableArg);
346             ownerEvent->setTarget(ownerElement);
347             ownerElement->dispatchGenericEvent(ownerEvent.release(), ec, true);
348         }
349     }
350 }
351
352 bool EventTargetNode::dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr<Event> underlyingEvent)
353 {
354     ASSERT(!eventDispatchForbidden());
355     ASSERT(eventType == DOMFocusInEvent || eventType == DOMFocusOutEvent || eventType == DOMActivateEvent);
356     
357     bool cancelable = eventType == DOMActivateEvent;
358     
359     ExceptionCode ec = 0;
360     RefPtr<UIEvent> evt = new UIEvent(eventType, true, cancelable, document()->defaultView(), detail);
361     evt->setUnderlyingEvent(underlyingEvent);
362     return dispatchEvent(evt.release(), ec, true);
363 }
364
365 bool EventTargetNode::dispatchKeyEvent(const PlatformKeyboardEvent& key)
366 {
367     ASSERT(!eventDispatchForbidden());
368     ExceptionCode ec = 0;
369     RefPtr<KeyboardEvent> keyboardEvent = new KeyboardEvent(key, document()->defaultView());
370     bool r = dispatchEvent(keyboardEvent,ec,true);
371     
372     // we want to return false if default is prevented (already taken care of)
373     // or if the element is default-handled by the DOM. Otherwise we let it just
374     // let it get handled by AppKit 
375     if (keyboardEvent->defaultHandled())
376         r = false;
377     
378     return r;
379 }
380
381 bool EventTargetNode::dispatchMouseEvent(const PlatformMouseEvent& event, const AtomicString& eventType,
382     int detail, Node* relatedTarget)
383 {
384     ASSERT(!eventDispatchForbidden());
385     
386     IntPoint contentsPos;
387     if (FrameView* view = document()->view())
388         contentsPos = view->windowToContents(event.pos());
389
390     short button = event.button();
391
392     ASSERT(event.eventType() == MouseEventMoved || button != NoButton);
393     
394     return dispatchMouseEvent(eventType, button, detail,
395         contentsPos.x(), contentsPos.y(), event.globalX(), event.globalY(),
396         event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
397         false, relatedTarget);
398 }
399
400 void EventTargetNode::dispatchSimulatedMouseEvent(const AtomicString& eventType,
401     PassRefPtr<Event> underlyingEvent)
402 {
403     ASSERT(!eventDispatchForbidden());
404     
405     if (m_dispatchingSimulatedEvent)
406         return;
407
408     bool ctrlKey = false;
409     bool altKey = false;
410     bool shiftKey = false;
411     bool metaKey = false;
412     if (UIEventWithKeyState* keyStateEvent = findEventWithKeyState(underlyingEvent.get())) {
413         ctrlKey = keyStateEvent->ctrlKey();
414         altKey = keyStateEvent->altKey();
415         shiftKey = keyStateEvent->shiftKey();
416         metaKey = keyStateEvent->metaKey();
417     }
418     
419     m_dispatchingSimulatedEvent = true;
420
421     // Like Gecko, we just pass 0 for everything when we make a fake mouse event.
422     // Internet Explorer instead gives the current mouse position and state.
423     dispatchMouseEvent(eventType, 0, 0, 0, 0, 0, 0,
424         ctrlKey, altKey, shiftKey, metaKey, true, 0, underlyingEvent);
425     
426     m_dispatchingSimulatedEvent = false;
427 }
428
429 void EventTargetNode::dispatchSimulatedClick(PassRefPtr<Event> event, bool sendMouseEvents, bool showPressedLook)
430 {
431     if (m_dispatchingSimulatedEvent)
432         return;
433     
434     // send mousedown and mouseup before the click, if requested
435     if (sendMouseEvents)
436         dispatchSimulatedMouseEvent(mousedownEvent, event.get());
437     setActive(true, showPressedLook);
438     if (sendMouseEvents)
439         dispatchSimulatedMouseEvent(mouseupEvent, event.get());
440     setActive(false);
441
442     // always send click
443     dispatchSimulatedMouseEvent(clickEvent, event);
444 }
445
446 bool EventTargetNode::dispatchMouseEvent(const AtomicString& eventType, int button, int detail,
447     int pageX, int pageY, int screenX, int screenY,
448     bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, 
449     bool isSimulated, Node* relatedTargetArg, PassRefPtr<Event> underlyingEvent)
450 {
451     ASSERT(!eventDispatchForbidden());
452     if (disabled()) // Don't even send DOM events for disabled controls..
453         return true;
454     
455     if (eventType.isEmpty())
456         return false; // Shouldn't happen.
457     
458     // Dispatching the first event can easily result in this node being destroyed.
459     // Since we dispatch up to three events here, we need to make sure we're referenced
460     // so the pointer will be good for the two subsequent ones.
461     RefPtr<Node> protect(this);
462     
463     bool cancelable = eventType != mousemoveEvent;
464     
465     ExceptionCode ec = 0;
466     
467     bool swallowEvent = false;
468     
469     // Attempting to dispatch with a non-EventTarget relatedTarget causes the relatedTarget to be silently ignored.
470     RefPtr<EventTargetNode> relatedTarget = (relatedTargetArg && relatedTargetArg->isEventTargetNode())
471         ? static_cast<EventTargetNode*>(relatedTargetArg) : 0;
472
473     RefPtr<Event> mouseEvent = new MouseEvent(eventType,
474         true, cancelable, document()->defaultView(),
475         detail, screenX, screenY, pageX, pageY,
476         ctrlKey, altKey, shiftKey, metaKey, button,
477         relatedTarget.get(), 0, isSimulated);
478     mouseEvent->setUnderlyingEvent(underlyingEvent.get());
479     
480     dispatchEvent(mouseEvent, ec, true);
481     bool defaultHandled = mouseEvent->defaultHandled();
482     bool defaultPrevented = mouseEvent->defaultPrevented();
483     if (defaultHandled || defaultPrevented)
484         swallowEvent = true;
485     
486     // Special case: If it's a double click event, we also send the dblclick event. This is not part
487     // of the DOM specs, but is used for compatibility with the ondblclick="" attribute.  This is treated
488     // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same.
489     if (eventType == clickEvent && detail == 2) {
490         RefPtr<Event> doubleClickEvent = new MouseEvent(dblclickEvent,
491             true, cancelable, document()->defaultView(),
492             detail, screenX, screenY, pageX, pageY,
493             ctrlKey, altKey, shiftKey, metaKey, button,
494             relatedTarget.get(), 0, isSimulated);
495         doubleClickEvent->setUnderlyingEvent(underlyingEvent.get());
496         if (defaultHandled)
497             doubleClickEvent->setDefaultHandled();
498         dispatchEvent(doubleClickEvent, ec, true);
499         if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented())
500             swallowEvent = true;
501     }
502
503     return swallowEvent;
504 }
505
506 void EventTargetNode::dispatchWheelEvent(PlatformWheelEvent& e)
507 {
508     ASSERT(!eventDispatchForbidden());
509     if (e.deltaX() == 0 && e.deltaY() == 0)
510         return;
511     
512     FrameView* view = document()->view();
513     if (!view)
514         return;
515     
516     IntPoint pos = view->windowToContents(e.pos());
517     
518     RefPtr<WheelEvent> we = new WheelEvent(e.deltaX(), e.deltaY(),
519                                            document()->defaultView(), e.globalX(), e.globalY(), pos.x(), pos.y(),
520                                            e.ctrlKey(), e.altKey(), e.shiftKey(), e.metaKey());
521     ExceptionCode ec = 0;
522     if (!dispatchEvent(we, ec, true))
523         e.accept();
524 }
525
526
527 void EventTargetNode::dispatchFocusEvent()
528 {
529     dispatchHTMLEvent(focusEvent, false, false);
530 }
531
532 void EventTargetNode::dispatchBlurEvent()
533 {
534     dispatchHTMLEvent(blurEvent, false, false);
535 }
536
537 bool EventTargetNode::dispatchHTMLEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg)
538 {
539     ASSERT(!eventDispatchForbidden());
540     ExceptionCode ec = 0;
541     return dispatchEvent(new Event(eventType, canBubbleArg, cancelableArg), ec, true);
542 }
543
544 void EventTargetNode::removeHTMLEventListener(const AtomicString &eventType)
545 {
546     if (!m_regdListeners) // nothing to remove
547         return;
548     
549     RegisteredEventListenerList::Iterator end = m_regdListeners->end();
550     for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
551         if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener()) {
552             it = m_regdListeners->remove(it);
553             // removed last
554             if (m_regdListeners->isEmpty() && !inDocument())
555                 document()->unregisterDisconnectedNodeWithEventListeners(this);
556             return;
557         }
558 }
559
560 void EventTargetNode::setHTMLEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener)
561 {
562     // In case we are the only one holding a reference to it, we don't want removeHTMLEventListener to destroy it.
563     removeHTMLEventListener(eventType);
564     if (listener)
565         addEventListener(eventType, listener.get(), false);
566 }
567
568 EventListener *EventTargetNode::getHTMLEventListener(const AtomicString &eventType)
569 {
570     if (!m_regdListeners)
571         return 0;
572     
573     RegisteredEventListenerList::Iterator end = m_regdListeners->end();
574     for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
575         if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener())
576             return (*it)->listener();
577     return 0;
578 }
579
580 bool EventTargetNode::disabled() const
581 {
582     return false;
583 }
584
585 void EventTargetNode::defaultEventHandler(Event* event)
586 {
587     if (event->target() != this)
588         return;
589     const AtomicString& eventType = event->type();
590     if (eventType == keydownEvent || eventType == keypressEvent) {
591         if (event->isKeyboardEvent())
592             if (Frame* frame = document()->frame())
593                 frame->eventHandler()->defaultKeyboardEventHandler(static_cast<KeyboardEvent*>(event));
594     } else if (eventType == clickEvent) {
595         int detail = event->isUIEvent() ? static_cast<UIEvent*>(event)->detail() : 0;
596         dispatchUIEvent(DOMActivateEvent, detail, event);
597     } else if (eventType == contextmenuEvent) {
598         if (Frame* frame = document()->frame())
599             if (Page* page = frame->page())
600                 page->contextMenuController()->handleContextMenuEvent(event);
601     } else if (eventType == textInputEvent) {
602         if (event->isTextEvent())
603             if (Frame* frame = document()->frame())
604                 frame->eventHandler()->defaultTextInputEventHandler(static_cast<TextEvent*>(event));
605     }
606 }
607
608 #ifndef NDEBUG
609
610 void EventTargetNode::dump(TextStream* stream, DeprecatedString ind) const
611 {
612     if (m_regdListeners)
613         *stream << " #regdListeners=" << m_regdListeners->count(); // ### more detail
614     
615     Node::dump(stream,ind);
616 }
617
618 void forbidEventDispatch()
619 {
620     ++gEventDispatchForbidden;
621 }
622
623 void allowEventDispatch()
624 {
625     if (gEventDispatchForbidden > 0)
626         --gEventDispatchForbidden;
627 }
628
629 bool eventDispatchForbidden()
630 {
631     return gEventDispatchForbidden > 0;
632 }
633
634 #endif
635
636 } // namespace WebCore