Reduce uses of PassRefPtr in WebCore/dom - 6
[WebKit-https.git] / Source / WebCore / dom / EventDispatcher.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, 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.
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 "EventDispatcher.h"
28
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>
39
40 namespace WebCore {
41
42 class WindowEventContext {
43 public:
44     WindowEventContext(Node*, const EventContext*);
45
46     DOMWindow* window() const { return m_window.get(); }
47     EventTarget* target() const { return m_target.get(); }
48     bool handleLocalEvents(Event&);
49
50 private:
51     RefPtr<DOMWindow> m_window;
52     RefPtr<EventTarget> m_target;
53 };
54
55 WindowEventContext::WindowEventContext(Node* node, const EventContext* topEventContext)
56 {
57     Node* topLevelContainer = topEventContext ? topEventContext->node() : node;
58     if (!is<Document>(*topLevelContainer))
59         return;
60
61     m_window = downcast<Document>(*topLevelContainer).domWindow();
62     m_target = topEventContext ? topEventContext->target() : node;
63 }
64
65 bool WindowEventContext::handleLocalEvents(Event& event)
66 {
67     if (!m_window)
68         return false;
69
70     event.setTarget(m_target.copyRef());
71     event.setCurrentTarget(m_window.get());
72     m_window->fireEventListeners(event);
73     return true;
74 }
75
76 void EventDispatcher::dispatchScopedEvent(Node& node, Event& event)
77 {
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);
81 }
82
83 static void callDefaultEventHandlersInTheBubblingOrder(Event& event, const EventPath& path)
84 {
85     if (path.isEmpty())
86         return;
87
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());
91
92     if (event.defaultHandled() || !event.bubbles())
93         return;
94
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())
100             return;
101     }
102 }
103
104 static void dispatchEventInDOM(Event& event, const EventPath& path, WindowEventContext& windowEventContext)
105 {
106     // Trigger capturing event handlers, starting at the top and working our way down.
107     event.setEventPhase(Event::CAPTURING_PHASE);
108
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())
113         return;
114
115     for (size_t i = path.size() - 1; i > 0; --i) {
116         const EventContext& eventContext = path.contextAt(i);
117         if (eventContext.currentTargetSameAsTarget())
118             continue;
119         eventContext.handleLocalEvents(event);
120         if (event.propagationStopped())
121             return;
122     }
123
124     event.setEventPhase(Event::AT_TARGET);
125     path.contextAt(0).handleLocalEvents(event);
126     if (event.propagationStopped())
127         return;
128
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);
137         else
138             continue;
139         eventContext.handleLocalEvents(event);
140         if (event.propagationStopped())
141             return;
142     }
143     if (event.bubbles() && !event.cancelBubble()) {
144         event.setEventPhase(Event::BUBBLING_PHASE);
145         if (shouldFireEventAtWindow)
146             windowEventContext.handleLocalEvents(event);
147     }
148 }
149
150 bool EventDispatcher::dispatchEvent(Node* origin, Event& event)
151 {
152     ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
153     ASSERT(origin);
154     RefPtr<Node> node(origin);
155     RefPtr<FrameView> view = node->document().view();
156     EventPath eventPath(*node, event);
157
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));
163 #endif
164
165     ChildNodesLazySnapshot::takeChildNodesLazySnapshot();
166
167     EventTarget* target = EventPath::eventTargetRespectingTargetRules(*node);
168     event.setTarget(target);
169     if (!event.target())
170         return true;
171
172     ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
173
174     WindowEventContext windowEventContext(node.get(), eventPath.lastContextIfExists());
175
176     InputElementClickState clickHandlingState;
177     if (is<HTMLInputElement>(*node))
178         downcast<HTMLInputElement>(*node).willDispatchEvent(event, clickHandlingState);
179
180     if (!event.propagationStopped() && !eventPath.isEmpty()) {
181         event.setEventPath(eventPath);
182         dispatchEventInDOM(event, eventPath, windowEventContext);
183         event.clearEventPath();
184     }
185
186     event.setTarget(EventPath::eventTargetRespectingTargetRules(*node));
187     event.setCurrentTarget(nullptr);
188     event.setEventPhase(0);
189
190     if (clickHandlingState.stateful)
191         downcast<HTMLInputElement>(*node).didDispatchClickEvent(event, clickHandlingState);
192
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);
198
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);
203
204     return !event.defaultPrevented();
205 }
206
207 }