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, 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/events/EventDispatcher.h"
28
29#include "core/dom/ContainerNode.h"
30#include "core/events/EventDispatchMediator.h"
31#include "core/events/MouseEvent.h"
32#include "core/events/ScopedEventQueue.h"
33#include "core/events/WindowEventContext.h"
34#include "core/frame/FrameView.h"
35#include "core/inspector/InspectorInstrumentation.h"
36#include "core/inspector/InspectorTraceEvents.h"
37#include "platform/EventDispatchForbiddenScope.h"
38#include "platform/TraceEvent.h"
39#include "wtf/RefPtr.h"
40
41namespace blink {
42
43bool EventDispatcher::dispatchEvent(Node* node, PassRefPtrWillBeRawPtr<EventDispatchMediator> mediator)
44{
45    TRACE_EVENT0("blink", "EventDispatcher::dispatchEvent");
46    ASSERT(!EventDispatchForbiddenScope::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, PassRefPtrWillBeRawPtr<Event> event)
54    : m_node(node)
55    , m_event(event)
56#if ENABLE(ASSERT)
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();
64    m_event->ensureEventPath().resetWith(m_node.get());
65}
66
67void EventDispatcher::dispatchScopedEvent(Node* node, PassRefPtrWillBeRawPtr<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(EventPath::eventTargetRespectingTargetRules(node));
71    ScopedEventQueue::instance()->enqueueEventDispatchMediator(mediator);
72}
73
74void EventDispatcher::dispatchSimulatedClick(Node* node, Event* underlyingEvent, SimulatedClickMouseEventOptions mouseEventOptions)
75{
76    // This persistent vector doesn't cause leaks, because added Nodes are removed
77    // before dispatchSimulatedClick() returns. This vector is here just to prevent
78    // the code from running into an infinite recursion of dispatchSimulatedClick().
79    DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<WillBeHeapHashSet<RawPtrWillBeMember<Node> > >, nodesDispatchingSimulatedClicks, (adoptPtrWillBeNoop(new WillBeHeapHashSet<RawPtrWillBeMember<Node> >())));
80
81    if (isDisabledFormControl(node))
82        return;
83
84    if (nodesDispatchingSimulatedClicks->contains(node))
85        return;
86
87    nodesDispatchingSimulatedClicks->add(node);
88
89    if (mouseEventOptions == SendMouseOverUpDownEvents)
90        EventDispatcher(node, SimulatedMouseEvent::create(EventTypeNames::mouseover, node->document().domWindow(), underlyingEvent)).dispatch();
91
92    if (mouseEventOptions != SendNoEvents) {
93        EventDispatcher(node, SimulatedMouseEvent::create(EventTypeNames::mousedown, node->document().domWindow(), underlyingEvent)).dispatch();
94        node->setActive(true);
95        EventDispatcher(node, SimulatedMouseEvent::create(EventTypeNames::mouseup, node->document().domWindow(), underlyingEvent)).dispatch();
96    }
97    // Some elements (e.g. the color picker) may set active state to true before
98    // calling this method and expect the state to be reset during the call.
99    node->setActive(false);
100
101    // always send click
102    EventDispatcher(node, SimulatedMouseEvent::create(EventTypeNames::click, node->document().domWindow(), underlyingEvent)).dispatch();
103
104    nodesDispatchingSimulatedClicks->remove(node);
105}
106
107bool EventDispatcher::dispatch()
108{
109    TRACE_EVENT0("blink", "EventDispatcher::dispatch");
110
111#if ENABLE(ASSERT)
112    ASSERT(!m_eventDispatched);
113    m_eventDispatched = true;
114#endif
115
116    m_event->setTarget(EventPath::eventTargetRespectingTargetRules(m_node.get()));
117    ASSERT(!EventDispatchForbiddenScope::isEventDispatchForbidden());
118    ASSERT(m_event->target());
119    WindowEventContext windowEventContext(m_event.get(), m_node.get(), topNodeEventContext());
120    TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "EventDispatch", "data", InspectorEventDispatchEvent::data(*m_event));
121    // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
122    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(&m_node->document(), *m_event, windowEventContext.window(), m_node.get(), m_event->eventPath());
123
124    void* preDispatchEventHandlerResult;
125    if (dispatchEventPreProcess(preDispatchEventHandlerResult) == ContinueDispatching)
126        if (dispatchEventAtCapturing(windowEventContext) == ContinueDispatching)
127            if (dispatchEventAtTarget() == ContinueDispatching)
128                dispatchEventAtBubbling(windowEventContext);
129    dispatchEventPostProcess(preDispatchEventHandlerResult);
130
131    // Ensure that after event dispatch, the event's target object is the
132    // outermost shadow DOM boundary.
133    m_event->setTarget(windowEventContext.target());
134    m_event->setCurrentTarget(0);
135    InspectorInstrumentation::didDispatchEvent(cookie);
136    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", "data", InspectorUpdateCountersEvent::data());
137
138    return !m_event->defaultPrevented();
139}
140
141inline EventDispatchContinuation EventDispatcher::dispatchEventPreProcess(void*& preDispatchEventHandlerResult)
142{
143    // Give the target node a chance to do some work before DOM event handlers get a crack.
144    preDispatchEventHandlerResult = m_node->preDispatchEventHandler(m_event.get());
145    return (m_event->eventPath().isEmpty() || m_event->propagationStopped()) ? DoneDispatching : ContinueDispatching;
146}
147
148inline EventDispatchContinuation EventDispatcher::dispatchEventAtCapturing(WindowEventContext& windowEventContext)
149{
150    // Trigger capturing event handlers, starting at the top and working our way down.
151    m_event->setEventPhase(Event::CAPTURING_PHASE);
152
153    if (windowEventContext.handleLocalEvents(m_event.get()) && m_event->propagationStopped())
154        return DoneDispatching;
155
156    for (size_t i = m_event->eventPath().size() - 1; i > 0; --i) {
157        const NodeEventContext& eventContext = m_event->eventPath()[i];
158        if (eventContext.currentTargetSameAsTarget())
159            continue;
160        eventContext.handleLocalEvents(m_event.get());
161        if (m_event->propagationStopped())
162            return DoneDispatching;
163    }
164
165    return ContinueDispatching;
166}
167
168inline EventDispatchContinuation EventDispatcher::dispatchEventAtTarget()
169{
170    m_event->setEventPhase(Event::AT_TARGET);
171    m_event->eventPath()[0].handleLocalEvents(m_event.get());
172    return m_event->propagationStopped() ? DoneDispatching : ContinueDispatching;
173}
174
175inline void EventDispatcher::dispatchEventAtBubbling(WindowEventContext& windowContext)
176{
177    // Trigger bubbling event handlers, starting at the bottom and working our way up.
178    size_t size = m_event->eventPath().size();
179    for (size_t i = 1; i < size; ++i) {
180        const NodeEventContext& eventContext = m_event->eventPath()[i];
181        if (eventContext.currentTargetSameAsTarget())
182            m_event->setEventPhase(Event::AT_TARGET);
183        else if (m_event->bubbles() && !m_event->cancelBubble())
184            m_event->setEventPhase(Event::BUBBLING_PHASE);
185        else
186            continue;
187        eventContext.handleLocalEvents(m_event.get());
188        if (m_event->propagationStopped())
189            return;
190    }
191    if (m_event->bubbles() && !m_event->cancelBubble()) {
192        m_event->setEventPhase(Event::BUBBLING_PHASE);
193        windowContext.handleLocalEvents(m_event.get());
194    }
195}
196
197inline void EventDispatcher::dispatchEventPostProcess(void* preDispatchEventHandlerResult)
198{
199    m_event->setTarget(EventPath::eventTargetRespectingTargetRules(m_node.get()));
200    m_event->setCurrentTarget(0);
201    m_event->setEventPhase(0);
202
203    // Pass the data from the preDispatchEventHandler to the postDispatchEventHandler.
204    m_node->postDispatchEventHandler(m_event.get(), preDispatchEventHandlerResult);
205
206    // Call default event handlers. While the DOM does have a concept of preventing
207    // default handling, the detail of which handlers are called is an internal
208    // implementation detail and not part of the DOM.
209    if (!m_event->defaultPrevented() && !m_event->defaultHandled()) {
210        // Non-bubbling events call only one default event handler, the one for the target.
211        m_node->willCallDefaultEventHandler(*m_event);
212        m_node->defaultEventHandler(m_event.get());
213        ASSERT(!m_event->defaultPrevented());
214        if (m_event->defaultHandled())
215            return;
216        // For bubbling events, call default event handlers on the same targets in the
217        // same order as the bubbling phase.
218        if (m_event->bubbles()) {
219            size_t size = m_event->eventPath().size();
220            for (size_t i = 1; i < size; ++i) {
221                m_event->eventPath()[i].node()->willCallDefaultEventHandler(*m_event);
222                m_event->eventPath()[i].node()->defaultEventHandler(m_event.get());
223                ASSERT(!m_event->defaultPrevented());
224                if (m_event->defaultHandled())
225                    return;
226            }
227        }
228    }
229}
230
231const NodeEventContext* EventDispatcher::topNodeEventContext()
232{
233    return m_event->eventPath().isEmpty() ? 0 : &m_event->eventPath().last();
234}
235
236}
237