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