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, 2013, 2015 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) 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
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.
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.
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.
27 #include "EventDispatcher.h"
29 #include "EventContext.h"
30 #include "EventPath.h"
31 #include "FrameView.h"
32 #include "HTMLInputElement.h"
33 #include "MouseEvent.h"
34 #include "PseudoElement.h"
35 #include "ScopedEventQueue.h"
36 #include "ShadowRoot.h"
37 #include "TouchEvent.h"
38 #include <wtf/NeverDestroyed.h>
42 class WindowEventContext {
44 WindowEventContext(Node*, const EventContext*);
46 DOMWindow* window() const { return m_window.get(); }
47 EventTarget* target() const { return m_target.get(); }
48 bool handleLocalEvents(Event&);
51 RefPtr<DOMWindow> m_window;
52 RefPtr<EventTarget> m_target;
55 WindowEventContext::WindowEventContext(Node* node, const EventContext* topEventContext)
57 Node* topLevelContainer = topEventContext ? topEventContext->node() : node;
58 if (!is<Document>(*topLevelContainer))
61 m_window = downcast<Document>(*topLevelContainer).domWindow();
62 m_target = topEventContext ? topEventContext->target() : node;
65 bool WindowEventContext::handleLocalEvents(Event& event)
70 event.setTarget(m_target.copyRef());
71 event.setCurrentTarget(m_window.get());
72 m_window->fireEventListeners(event);
76 void EventDispatcher::dispatchScopedEvent(Node& node, Event& event)
78 // We need to set the target here because it can go away by the time we actually fire the event.
79 event.setTarget(EventPath::eventTargetRespectingTargetRules(node));
80 ScopedEventQueue::singleton().enqueueEvent(event);
83 static void callDefaultEventHandlersInTheBubblingOrder(Event& event, const EventPath& path)
88 // Non-bubbling events call only one default event handler, the one for the target.
89 path.contextAt(0).node()->defaultEventHandler(&event);
90 ASSERT(!event.defaultPrevented());
92 if (event.defaultHandled() || !event.bubbles())
95 size_t size = path.size();
96 for (size_t i = 1; i < size; ++i) {
97 path.contextAt(i).node()->defaultEventHandler(&event);
98 ASSERT(!event.defaultPrevented());
99 if (event.defaultHandled())
104 static void dispatchEventInDOM(Event& event, const EventPath& path, WindowEventContext& windowEventContext)
106 // Trigger capturing event handlers, starting at the top and working our way down.
107 event.setEventPhase(Event::CAPTURING_PHASE);
109 // We don't dispatch load events to the window. This quirk was originally
110 // added because Mozilla doesn't propagate load events to the window object.
111 bool shouldFireEventAtWindow = event.type() != eventNames().loadEvent;
112 if (shouldFireEventAtWindow && windowEventContext.handleLocalEvents(event) && event.propagationStopped())
115 for (size_t i = path.size() - 1; i > 0; --i) {
116 const EventContext& eventContext = path.contextAt(i);
117 if (eventContext.currentTargetSameAsTarget())
119 eventContext.handleLocalEvents(event);
120 if (event.propagationStopped())
124 event.setEventPhase(Event::AT_TARGET);
125 path.contextAt(0).handleLocalEvents(event);
126 if (event.propagationStopped())
129 // Trigger bubbling event handlers, starting at the bottom and working our way up.
130 size_t size = path.size();
131 for (size_t i = 1; i < size; ++i) {
132 const EventContext& eventContext = path.contextAt(i);
133 if (eventContext.currentTargetSameAsTarget())
134 event.setEventPhase(Event::AT_TARGET);
135 else if (event.bubbles() && !event.cancelBubble())
136 event.setEventPhase(Event::BUBBLING_PHASE);
139 eventContext.handleLocalEvents(event);
140 if (event.propagationStopped())
143 if (event.bubbles() && !event.cancelBubble()) {
144 event.setEventPhase(Event::BUBBLING_PHASE);
145 if (shouldFireEventAtWindow)
146 windowEventContext.handleLocalEvents(event);
150 bool EventDispatcher::dispatchEvent(Node* origin, Event& event)
152 ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
154 RefPtr<Node> node(origin);
155 RefPtr<FrameView> view = node->document().view();
156 EventPath eventPath(*node, event);
158 if (EventTarget* relatedTarget = event.relatedTarget())
159 eventPath.setRelatedTarget(*node, *relatedTarget);
160 #if ENABLE(TOUCH_EVENTS)
161 if (is<TouchEvent>(event))
162 eventPath.retargetTouchLists(downcast<TouchEvent>(event));
165 ChildNodesLazySnapshot::takeChildNodesLazySnapshot();
167 EventTarget* target = EventPath::eventTargetRespectingTargetRules(*node);
168 event.setTarget(target);
172 ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
174 WindowEventContext windowEventContext(node.get(), eventPath.lastContextIfExists());
176 InputElementClickState clickHandlingState;
177 if (is<HTMLInputElement>(*node))
178 downcast<HTMLInputElement>(*node).willDispatchEvent(event, clickHandlingState);
180 if (!event.propagationStopped() && !eventPath.isEmpty()) {
181 event.setEventPath(eventPath);
182 dispatchEventInDOM(event, eventPath, windowEventContext);
183 event.clearEventPath();
186 event.setTarget(EventPath::eventTargetRespectingTargetRules(*node));
187 event.setCurrentTarget(nullptr);
188 event.setEventPhase(0);
190 if (clickHandlingState.stateful)
191 downcast<HTMLInputElement>(*node).didDispatchClickEvent(event, clickHandlingState);
193 // Call default event handlers. While the DOM does have a concept of preventing
194 // default handling, the detail of which handlers are called is an internal
195 // implementation detail and not part of the DOM.
196 if (!event.defaultPrevented() && !event.defaultHandled())
197 callDefaultEventHandlersInTheBubblingOrder(event, eventPath);
199 // Ensure that after event dispatch, the event's target object is the
200 // outermost shadow DOM boundary.
201 event.setTarget(windowEventContext.target());
202 event.setCurrentTarget(nullptr);
204 return !event.defaultPrevented();