blob: bf9f40bf0f9796c5b60dab82b80b29348bdcf2b1 [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
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, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
7 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8 * Copyright (C) 2011 Google Inc. All rights reserved.
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26#include "config.h"
27#include "core/dom/EventDispatcher.h"
28
29#include "core/dom/ContainerNode.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010030#include "core/dom/EventContext.h"
31#include "core/dom/EventDispatchMediator.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010032#include "core/dom/EventRetargeter.h"
33#include "core/dom/MouseEvent.h"
34#include "core/dom/ScopedEventQueue.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010035#include "core/dom/WindowEventContext.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010036#include "core/inspector/InspectorInstrumentation.h"
37#include "core/page/FrameView.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010038#include "wtf/RefPtr.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010039
40namespace WebCore {
41
42static HashSet<Node*>* gNodesDispatchingSimulatedClicks = 0;
43
44bool EventDispatcher::dispatchEvent(Node* node, PassRefPtr<EventDispatchMediator> mediator)
45{
46 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
47 if (!mediator->event())
48 return true;
49 EventDispatcher dispatcher(node, mediator->event());
50 return mediator->dispatchEvent(&dispatcher);
51}
52
53EventDispatcher::EventDispatcher(Node* node, PassRefPtr<Event> event)
54 : m_node(node)
55 , m_event(event)
56#ifndef NDEBUG
57 , m_eventDispatched(false)
58#endif
59{
60 ASSERT(node);
61 ASSERT(m_event.get());
62 ASSERT(!m_event->type().isNull()); // JavaScript code can create an event with an empty name, but not null.
63 m_view = node->document()->view();
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +010064 EventRetargeter::ensureEventPath(m_node.get(), m_event.get());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010065}
66
67void EventDispatcher::dispatchScopedEvent(Node* node, PassRefPtr<EventDispatchMediator> mediator)
68{
69 // We need to set the target here because it can go away by the time we actually fire the event.
70 mediator->event()->setTarget(EventRetargeter::eventTargetRespectingTargetRules(node));
71 ScopedEventQueue::instance()->enqueueEventDispatchMediator(mediator);
72}
73
74void EventDispatcher::dispatchSimulatedClick(Node* node, Event* underlyingEvent, SimulatedClickMouseEventOptions mouseEventOptions, SimulatedClickVisualOptions visualOptions)
75{
76 if (isDisabledFormControl(node))
77 return;
78
79 if (!gNodesDispatchingSimulatedClicks)
80 gNodesDispatchingSimulatedClicks = new HashSet<Node*>;
81 else if (gNodesDispatchingSimulatedClicks->contains(node))
82 return;
83
84 gNodesDispatchingSimulatedClicks->add(node);
85
86 if (mouseEventOptions == SendMouseOverUpDownEvents)
87 EventDispatcher(node, SimulatedMouseEvent::create(eventNames().mouseoverEvent, node->document()->defaultView(), underlyingEvent)).dispatch();
88
89 if (mouseEventOptions != SendNoEvents)
90 EventDispatcher(node, SimulatedMouseEvent::create(eventNames().mousedownEvent, node->document()->defaultView(), underlyingEvent)).dispatch();
91 node->setActive(true, visualOptions == ShowPressedLook);
92 if (mouseEventOptions != SendNoEvents)
93 EventDispatcher(node, SimulatedMouseEvent::create(eventNames().mouseupEvent, node->document()->defaultView(), underlyingEvent)).dispatch();
94 node->setActive(false);
95
96 // always send click
97 EventDispatcher(node, SimulatedMouseEvent::create(eventNames().clickEvent, node->document()->defaultView(), underlyingEvent)).dispatch();
98
99 gNodesDispatchingSimulatedClicks->remove(node);
100}
101
102bool EventDispatcher::dispatch()
103{
104#ifndef NDEBUG
105 ASSERT(!m_eventDispatched);
106 m_eventDispatched = true;
107#endif
108 ChildNodesLazySnapshot::takeChildNodesLazySnapshot();
109
110 m_event->setTarget(EventRetargeter::eventTargetRespectingTargetRules(m_node.get()));
111 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
112 ASSERT(m_event->target());
113 WindowEventContext windowEventContext(m_event.get(), m_node.get(), topEventContext());
114 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(m_node->document(), *m_event, windowEventContext.window(), m_node.get(), m_event->eventPath());
115
116 void* preDispatchEventHandlerResult;
117 if (dispatchEventPreProcess(preDispatchEventHandlerResult) == ContinueDispatching)
118 if (dispatchEventAtCapturing(windowEventContext) == ContinueDispatching)
119 if (dispatchEventAtTarget() == ContinueDispatching)
120 dispatchEventAtBubbling(windowEventContext);
121 dispatchEventPostProcess(preDispatchEventHandlerResult);
122
123 // Ensure that after event dispatch, the event's target object is the
124 // outermost shadow DOM boundary.
125 m_event->setTarget(windowEventContext.target());
126 m_event->setCurrentTarget(0);
127 InspectorInstrumentation::didDispatchEvent(cookie);
128
129 return !m_event->defaultPrevented();
130}
131
132inline EventDispatchContinuation EventDispatcher::dispatchEventPreProcess(void*& preDispatchEventHandlerResult)
133{
134 // Give the target node a chance to do some work before DOM event handlers get a crack.
135 preDispatchEventHandlerResult = m_node->preDispatchEventHandler(m_event.get());
136 return (m_event->eventPath().isEmpty() || m_event->propagationStopped()) ? DoneDispatching : ContinueDispatching;
137}
138
139inline EventDispatchContinuation EventDispatcher::dispatchEventAtCapturing(WindowEventContext& windowEventContext)
140{
141 // Trigger capturing event handlers, starting at the top and working our way down.
142 m_event->setEventPhase(Event::CAPTURING_PHASE);
143
144 if (windowEventContext.handleLocalEvents(m_event.get()) && m_event->propagationStopped())
145 return DoneDispatching;
146
147 for (size_t i = m_event->eventPath().size() - 1; i > 0; --i) {
148 const EventContext& eventContext = *m_event->eventPath()[i];
149 if (eventContext.currentTargetSameAsTarget())
150 continue;
151 eventContext.handleLocalEvents(m_event.get());
152 if (m_event->propagationStopped())
153 return DoneDispatching;
154 }
155
156 return ContinueDispatching;
157}
158
159inline EventDispatchContinuation EventDispatcher::dispatchEventAtTarget()
160{
161 m_event->setEventPhase(Event::AT_TARGET);
162 m_event->eventPath()[0]->handleLocalEvents(m_event.get());
163 return m_event->propagationStopped() ? DoneDispatching : ContinueDispatching;
164}
165
166inline void EventDispatcher::dispatchEventAtBubbling(WindowEventContext& windowContext)
167{
168 // Trigger bubbling event handlers, starting at the bottom and working our way up.
169 size_t size = m_event->eventPath().size();
170 for (size_t i = 1; i < size; ++i) {
171 const EventContext& eventContext = *m_event->eventPath()[i];
172 if (eventContext.currentTargetSameAsTarget())
173 m_event->setEventPhase(Event::AT_TARGET);
174 else if (m_event->bubbles() && !m_event->cancelBubble())
175 m_event->setEventPhase(Event::BUBBLING_PHASE);
176 else
177 continue;
178 eventContext.handleLocalEvents(m_event.get());
179 if (m_event->propagationStopped())
180 return;
181 }
182 if (m_event->bubbles() && !m_event->cancelBubble()) {
183 m_event->setEventPhase(Event::BUBBLING_PHASE);
184 windowContext.handleLocalEvents(m_event.get());
185 }
186}
187
188inline void EventDispatcher::dispatchEventPostProcess(void* preDispatchEventHandlerResult)
189{
190 m_event->setTarget(EventRetargeter::eventTargetRespectingTargetRules(m_node.get()));
191 m_event->setCurrentTarget(0);
192 m_event->setEventPhase(0);
193
194 // Pass the data from the preDispatchEventHandler to the postDispatchEventHandler.
195 m_node->postDispatchEventHandler(m_event.get(), preDispatchEventHandlerResult);
196
197 // Call default event handlers. While the DOM does have a concept of preventing
198 // default handling, the detail of which handlers are called is an internal
199 // implementation detail and not part of the DOM.
200 if (!m_event->defaultPrevented() && !m_event->defaultHandled()) {
201 // Non-bubbling events call only one default event handler, the one for the target.
Ben Murdoch591b9582013-07-10 11:41:44 +0100202 m_node->willCallDefaultEventHandler(*m_event);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100203 m_node->defaultEventHandler(m_event.get());
204 ASSERT(!m_event->defaultPrevented());
205 if (m_event->defaultHandled())
206 return;
207 // For bubbling events, call default event handlers on the same targets in the
208 // same order as the bubbling phase.
209 if (m_event->bubbles()) {
210 size_t size = m_event->eventPath().size();
211 for (size_t i = 1; i < size; ++i) {
Ben Murdoch591b9582013-07-10 11:41:44 +0100212 m_event->eventPath()[i]->node()->willCallDefaultEventHandler(*m_event);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100213 m_event->eventPath()[i]->node()->defaultEventHandler(m_event.get());
214 ASSERT(!m_event->defaultPrevented());
215 if (m_event->defaultHandled())
216 return;
217 }
218 }
219 }
220}
221
222const EventContext* EventDispatcher::topEventContext()
223{
224 return m_event->eventPath().isEmpty() ? 0 : m_event->eventPath().last().get();
225}
226
227}