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
6 * rights reserved.
7 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
8 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved.
9 * (http://www.torchmobile.com/)
10 * Copyright (C) 2011 Google Inc. All rights reserved.
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
26 */
27
28 #include "third_party/blink/renderer/core/dom/events/event_dispatcher.h"
29
30 #include "base/memory/scoped_refptr.h"
31 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
32 #include "third_party/blink/renderer/core/dom/container_node.h"
33 #include "third_party/blink/renderer/core/dom/document.h"
34 #include "third_party/blink/renderer/core/dom/element.h"
35 #include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
36 #include "third_party/blink/renderer/core/dom/events/event_path.h"
37 #include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h"
38 #include "third_party/blink/renderer/core/dom/events/window_event_context.h"
39 #include "third_party/blink/renderer/core/events/keyboard_event.h"
40 #include "third_party/blink/renderer/core/events/mouse_event.h"
41 #include "third_party/blink/renderer/core/frame/ad_tracker.h"
42 #include "third_party/blink/renderer/core/frame/deprecation.h"
43 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
44 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
45 #include "third_party/blink/renderer/core/frame/settings.h"
46 #include "third_party/blink/renderer/core/html/html_element.h"
47 #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
48 #include "third_party/blink/renderer/core/page/page.h"
49 #include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
50 #include "third_party/blink/renderer/core/timing/event_timing.h"
51 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
52 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
53
54 namespace blink {
55
DispatchEvent(Node & node,Event & event)56 DispatchEventResult EventDispatcher::DispatchEvent(Node& node, Event& event) {
57 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("blink.debug"),
58 "EventDispatcher::dispatchEvent");
59 #if DCHECK_IS_ON()
60 DCHECK(!EventDispatchForbiddenScope::IsEventDispatchForbidden());
61 #endif
62 EventDispatcher dispatcher(node, event);
63 return event.DispatchEvent(dispatcher);
64 }
65
EventDispatcher(Node & node,Event & event)66 EventDispatcher::EventDispatcher(Node& node, Event& event)
67 : node_(&node), event_(&event) {
68 view_ = node.GetDocument().View();
69 event_->InitEventPath(*node_);
70 }
71
DispatchScopedEvent(Node & node,Event & event)72 void EventDispatcher::DispatchScopedEvent(Node& node, Event& event) {
73 // We need to set the target here because it can go away by the time we
74 // actually fire the event.
75 event.SetTarget(&EventPath::EventTargetRespectingTargetRules(node));
76 ScopedEventQueue::Instance()->EnqueueEvent(event);
77 }
78
DispatchSimulatedClick(Node & node,const Event * underlying_event,SimulatedClickMouseEventOptions mouse_event_options,SimulatedClickCreationScope creation_scope)79 void EventDispatcher::DispatchSimulatedClick(
80 Node& node,
81 const Event* underlying_event,
82 SimulatedClickMouseEventOptions mouse_event_options,
83 SimulatedClickCreationScope creation_scope) {
84 // This persistent vector doesn't cause leaks, because added Nodes are removed
85 // before dispatchSimulatedClick() returns. This vector is here just to
86 // prevent the code from running into an infinite recursion of
87 // dispatchSimulatedClick().
88 DEFINE_STATIC_LOCAL(Persistent<HeapHashSet<Member<Node>>>,
89 nodes_dispatching_simulated_clicks,
90 (MakeGarbageCollected<HeapHashSet<Member<Node>>>()));
91
92 if (IsDisabledFormControl(&node))
93 return;
94
95 if (nodes_dispatching_simulated_clicks->Contains(&node))
96 return;
97
98 nodes_dispatching_simulated_clicks->insert(&node);
99
100 if (mouse_event_options == kSendMouseOverUpDownEvents)
101 EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseover,
102 node.GetDocument().domWindow(),
103 underlying_event, creation_scope))
104 .Dispatch();
105
106 Element* element = DynamicTo<Element>(node);
107 if (mouse_event_options != kSendNoEvents) {
108 EventDispatcher(node, *MouseEvent::Create(event_type_names::kMousedown,
109 node.GetDocument().domWindow(),
110 underlying_event, creation_scope))
111 .Dispatch();
112 if (element)
113 element->SetActive(true);
114 EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseup,
115 node.GetDocument().domWindow(),
116 underlying_event, creation_scope))
117 .Dispatch();
118 }
119 // Some elements (e.g. the color picker) may set active state to true before
120 // calling this method and expect the state to be reset during the call.
121 if (element)
122 element->SetActive(false);
123
124 // always send click
125 EventDispatcher(node, *MouseEvent::Create(event_type_names::kClick,
126 node.GetDocument().domWindow(),
127 underlying_event, creation_scope))
128 .Dispatch();
129
130 nodes_dispatching_simulated_clicks->erase(&node);
131 }
132
133 // https://dom.spec.whatwg.org/#dispatching-events
Dispatch()134 DispatchEventResult EventDispatcher::Dispatch() {
135 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("blink.debug"),
136 "EventDispatcher::dispatch");
137
138 #if DCHECK_IS_ON()
139 DCHECK(!event_dispatched_);
140 event_dispatched_ = true;
141 #endif
142 if (GetEvent().GetEventPath().IsEmpty()) {
143 // eventPath() can be empty if relatedTarget retargeting has shrunk the
144 // path.
145 return DispatchEventResult::kNotCanceled;
146 }
147 std::unique_ptr<EventTiming> eventTiming;
148 LocalFrame* frame = node_->GetDocument().GetFrame();
149 if (frame && frame->DomWindow())
150 eventTiming = EventTiming::Create(frame->DomWindow(), *event_);
151 event_->GetEventPath().EnsureWindowEventContext();
152
153 const bool is_click =
154 event_->IsMouseEvent() && event_->type() == event_type_names::kClick;
155
156 if (is_click && event_->isTrusted()) {
157 Document& document = node_->GetDocument();
158 if (frame) {
159 // A genuine mouse click cannot be triggered by script so we don't expect
160 // there are any script in the stack.
161 DCHECK(!frame->GetAdTracker() ||
162 !frame->GetAdTracker()->IsAdScriptInStack(
163 AdTracker::StackType::kBottomAndTop));
164 if (frame->IsAdSubframe()) {
165 UseCounter::Count(document, WebFeature::kAdClick);
166 }
167 }
168 }
169
170 // 6. Let isActivationEvent be true, if event is a MouseEvent object and
171 // event's type attribute is "click", and false otherwise.
172 //
173 // We need to include non-standard textInput event for HTMLInputElement.
174 const bool is_activation_event =
175 is_click || event_->type() == event_type_names::kTextInput;
176
177 // 7. Let activationTarget be target, if isActivationEvent is true and target
178 // has activation behavior, and null otherwise.
179 Node* activation_target =
180 is_activation_event && node_->HasActivationBehavior() ? node_ : nullptr;
181
182 // A part of step 9 loop.
183 if (is_activation_event && !activation_target && event_->bubbles()) {
184 wtf_size_t size = event_->GetEventPath().size();
185 for (wtf_size_t i = 1; i < size; ++i) {
186 Node& target = event_->GetEventPath()[i].GetNode();
187 if (target.HasActivationBehavior()) {
188 activation_target = ⌖
189 break;
190 }
191 }
192 }
193
194 event_->SetTarget(&EventPath::EventTargetRespectingTargetRules(*node_));
195 #if DCHECK_IS_ON()
196 DCHECK(!EventDispatchForbiddenScope::IsEventDispatchForbidden());
197 #endif
198 DCHECK(event_->target());
199 TRACE_EVENT1("devtools.timeline", "EventDispatch", "data",
200 inspector_event_dispatch_event::Data(*event_));
201 EventDispatchHandlingState* pre_dispatch_event_handler_result = nullptr;
202 if (DispatchEventPreProcess(activation_target,
203 pre_dispatch_event_handler_result) ==
204 kContinueDispatching) {
205 if (DispatchEventAtCapturing() == kContinueDispatching) {
206 if (DispatchEventAtTarget() == kContinueDispatching)
207 DispatchEventAtBubbling();
208 }
209 }
210 DispatchEventPostProcess(activation_target,
211 pre_dispatch_event_handler_result);
212 if (eventTiming)
213 eventTiming->DidDispatchEvent(*event_);
214
215 return EventTarget::GetDispatchEventResult(*event_);
216 }
217
DispatchEventPreProcess(Node * activation_target,EventDispatchHandlingState * & pre_dispatch_event_handler_result)218 inline EventDispatchContinuation EventDispatcher::DispatchEventPreProcess(
219 Node* activation_target,
220 EventDispatchHandlingState*& pre_dispatch_event_handler_result) {
221 // 11. If activationTarget is non-null and activationTarget has
222 // legacy-pre-activation behavior, then run activationTarget's
223 // legacy-pre-activation behavior.
224 if (activation_target) {
225 pre_dispatch_event_handler_result =
226 activation_target->PreDispatchEventHandler(*event_);
227 }
228
229 return (event_->GetEventPath().IsEmpty() || event_->PropagationStopped())
230 ? kDoneDispatching
231 : kContinueDispatching;
232 }
233
DispatchEventAtCapturing()234 inline EventDispatchContinuation EventDispatcher::DispatchEventAtCapturing() {
235 // Trigger capturing event handlers, starting at the top and working our way
236 // down.
237 event_->SetEventPhase(Event::kCapturingPhase);
238
239 if (event_->GetEventPath().GetWindowEventContext().HandleLocalEvents(
240 *event_) &&
241 event_->PropagationStopped())
242 return kDoneDispatching;
243
244 for (wtf_size_t i = event_->GetEventPath().size() - 1; i > 0; --i) {
245 const NodeEventContext& event_context = event_->GetEventPath()[i];
246 if (event_context.CurrentTargetSameAsTarget()) {
247 event_->SetEventPhase(Event::kAtTarget);
248 event_->SetFireOnlyCaptureListenersAtTarget(true);
249 event_context.HandleLocalEvents(*event_);
250 event_->SetFireOnlyCaptureListenersAtTarget(false);
251 } else {
252 event_->SetEventPhase(Event::kCapturingPhase);
253 event_context.HandleLocalEvents(*event_);
254 }
255 if (event_->PropagationStopped())
256 return kDoneDispatching;
257 }
258
259 return kContinueDispatching;
260 }
261
DispatchEventAtTarget()262 inline EventDispatchContinuation EventDispatcher::DispatchEventAtTarget() {
263 event_->SetEventPhase(Event::kAtTarget);
264 event_->GetEventPath()[0].HandleLocalEvents(*event_);
265 return event_->PropagationStopped() ? kDoneDispatching : kContinueDispatching;
266 }
267
DispatchEventAtBubbling()268 inline void EventDispatcher::DispatchEventAtBubbling() {
269 // Trigger bubbling event handlers, starting at the bottom and working our way
270 // up.
271 wtf_size_t size = event_->GetEventPath().size();
272 for (wtf_size_t i = 1; i < size; ++i) {
273 const NodeEventContext& event_context = event_->GetEventPath()[i];
274 if (event_context.CurrentTargetSameAsTarget()) {
275 // TODO(hayato): Need to check cancelBubble() also here?
276 event_->SetEventPhase(Event::kAtTarget);
277 event_->SetFireOnlyNonCaptureListenersAtTarget(true);
278 event_context.HandleLocalEvents(*event_);
279 event_->SetFireOnlyNonCaptureListenersAtTarget(false);
280 } else if (event_->bubbles() && !event_->cancelBubble()) {
281 event_->SetEventPhase(Event::kBubblingPhase);
282 event_context.HandleLocalEvents(*event_);
283 } else {
284 continue;
285 }
286 if (event_->PropagationStopped())
287 return;
288 }
289 if (event_->bubbles() && !event_->cancelBubble()) {
290 event_->SetEventPhase(Event::kBubblingPhase);
291 event_->GetEventPath().GetWindowEventContext().HandleLocalEvents(*event_);
292 }
293 }
294
DispatchEventPostProcess(Node * activation_target,EventDispatchHandlingState * pre_dispatch_event_handler_result)295 inline void EventDispatcher::DispatchEventPostProcess(
296 Node* activation_target,
297 EventDispatchHandlingState* pre_dispatch_event_handler_result) {
298 event_->SetTarget(&EventPath::EventTargetRespectingTargetRules(*node_));
299 // https://dom.spec.whatwg.org/#concept-event-dispatch
300 // 14. Unset event’s dispatch flag, stop propagation flag, and stop immediate
301 // propagation flag.
302 event_->SetStopPropagation(false);
303 event_->SetStopImmediatePropagation(false);
304 // 15. Set event’s eventPhase attribute to NONE.
305 event_->SetEventPhase(0);
306 // TODO(rakina): investigate this and move it to the bottom of step 16
307 // 17. Set event’s currentTarget attribute to null.
308 event_->SetCurrentTarget(nullptr);
309
310 auto* mouse_event = DynamicTo<MouseEvent>(event_);
311 bool is_click =
312 mouse_event && mouse_event->type() == event_type_names::kClick;
313 if (is_click) {
314 // Fire an accessibility event indicating a node was clicked on. This is
315 // safe if event_->target()->ToNode() returns null.
316 if (AXObjectCache* cache = node_->GetDocument().ExistingAXObjectCache())
317 cache->HandleClicked(event_->target()->ToNode());
318
319 // Pass the data from the PreDispatchEventHandler to the
320 // PostDispatchEventHandler.
321 // This may dispatch an event, and node_ and event_ might be altered.
322 if (activation_target) {
323 activation_target->PostDispatchEventHandler(
324 *event_, pre_dispatch_event_handler_result);
325 }
326 // TODO(tkent): Is it safe to kick DefaultEventHandler() with such altered
327 // event_?
328 }
329
330 // The DOM Events spec says that events dispatched by JS (other than "click")
331 // should not have their default handlers invoked.
332 bool is_trusted_or_click = event_->isTrusted() || is_click;
333
334 // For Android WebView (distinguished by wideViewportQuirkEnabled)
335 // enable untrusted events for mouse down on select elements because
336 // fastclick.js seems to generate these. crbug.com/642698
337 // TODO(dtapuska): Change this to a target SDK quirk crbug.com/643705
338 if (!is_trusted_or_click && event_->IsMouseEvent() &&
339 event_->type() == event_type_names::kMousedown &&
340 IsA<HTMLSelectElement>(*node_)) {
341 if (Settings* settings = node_->GetDocument().GetSettings()) {
342 is_trusted_or_click = settings->GetWideViewportQuirkEnabled();
343 }
344 }
345
346 // Call default event handlers. While the DOM does have a concept of
347 // preventing default handling, the detail of which handlers are called is an
348 // internal implementation detail and not part of the DOM.
349 if (!event_->defaultPrevented() && !event_->DefaultHandled() &&
350 is_trusted_or_click) {
351 // Non-bubbling events call only one default event handler, the one for the
352 // target.
353 node_->DefaultEventHandler(*event_);
354 DCHECK(!event_->defaultPrevented());
355 // For bubbling events, call default event handlers on the same targets in
356 // the same order as the bubbling phase.
357 if (!event_->DefaultHandled() && event_->bubbles()) {
358 wtf_size_t size = event_->GetEventPath().size();
359 for (wtf_size_t i = 1; i < size; ++i) {
360 event_->GetEventPath()[i].GetNode().DefaultEventHandler(*event_);
361 DCHECK(!event_->defaultPrevented());
362 if (event_->DefaultHandled())
363 break;
364 }
365 }
366 }
367
368 auto* keyboard_event = DynamicTo<KeyboardEvent>(event_);
369 if (Page* page = node_->GetDocument().GetPage()) {
370 if (page->GetSettings().GetSpatialNavigationEnabled() &&
371 is_trusted_or_click && keyboard_event &&
372 keyboard_event->key() == "Enter" &&
373 event_->type() == event_type_names::kKeyup) {
374 page->GetSpatialNavigationController().ResetEnterKeyState();
375 }
376 }
377
378 // Track the usage of sending a mousedown event to a select element to force
379 // it to open. This measures a possible breakage of not allowing untrusted
380 // events to open select boxes.
381 if (!event_->isTrusted() && event_->IsMouseEvent() &&
382 event_->type() == event_type_names::kMousedown &&
383 IsA<HTMLSelectElement>(*node_)) {
384 UseCounter::Count(node_->GetDocument(),
385 WebFeature::kUntrustedMouseDownEventDispatchedToSelect);
386 }
387 // 16. If target's root is a shadow root, then set event's target attribute
388 // and event's relatedTarget to null.
389 event_->SetTarget(event_->GetEventPath().GetWindowEventContext().Target());
390 if (!event_->target())
391 event_->SetRelatedTargetIfExists(nullptr);
392 }
393
394 } // namespace blink
395