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 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 "EventDispatcher.h"
28
29 #include "Event.h"
30 #include "EventContext.h"
31 #include "EventTarget.h"
32 #include "FrameView.h"
33 #include "InspectorInstrumentation.h"
34 #include "MouseEvent.h"
35 #include "Node.h"
36 #include "ScopedEventQueue.h"
37
38 #if ENABLE(SVG)
39 #include "SVGElementInstance.h"
40 #include "SVGNames.h"
41 #include "SVGUseElement.h"
42 #endif
43
44 #include "UIEvent.h"
45 #include "UIEventWithKeyState.h"
46 #include "WindowEventContext.h"
47
48 #include <wtf/RefPtr.h>
49
50 namespace WebCore {
51
52 static HashSet<Node*>* gNodesDispatchingSimulatedClicks = 0;
53
dispatchEvent(Node * node,const EventDispatchMediator & mediator)54 bool EventDispatcher::dispatchEvent(Node* node, const EventDispatchMediator& mediator)
55 {
56 ASSERT(!eventDispatchForbidden());
57
58 EventDispatcher dispatcher(node);
59 return mediator.dispatchEvent(&dispatcher);
60 }
61
findElementInstance(Node * referenceNode)62 static EventTarget* findElementInstance(Node* referenceNode)
63 {
64 #if ENABLE(SVG)
65 // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included
66 // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects
67 for (Node* n = referenceNode; n; n = n->parentNode()) {
68 if (!n->isSVGShadowRoot() || !n->isSVGElement())
69 continue;
70
71 Element* shadowTreeParentElement = n->svgShadowHost();
72 ASSERT(shadowTreeParentElement->hasTagName(SVGNames::useTag));
73
74 if (SVGElementInstance* instance = static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode))
75 return instance;
76 }
77 #else
78 // SVG elements with SVG disabled should not be possible.
79 ASSERT_NOT_REACHED();
80 #endif
81
82 return referenceNode;
83 }
84
eventTargetRespectingSVGTargetRules(Node * referenceNode)85 inline static EventTarget* eventTargetRespectingSVGTargetRules(Node* referenceNode)
86 {
87 ASSERT(referenceNode);
88
89 return referenceNode->isSVGElement() ? findElementInstance(referenceNode) : referenceNode;
90 }
91
dispatchScopedEvent(Node * node,PassRefPtr<Event> event)92 void EventDispatcher::dispatchScopedEvent(Node* node, PassRefPtr<Event> event)
93 {
94 // We need to set the target here because it can go away by the time we actually fire the event.
95 event->setTarget(eventTargetRespectingSVGTargetRules(node));
96
97 ScopedEventQueue::instance()->enqueueEvent(event);
98 }
99
dispatchSimulatedClick(Node * node,PassRefPtr<Event> underlyingEvent,bool sendMouseEvents,bool showPressedLook)100 void EventDispatcher::dispatchSimulatedClick(Node* node, PassRefPtr<Event> underlyingEvent, bool sendMouseEvents, bool showPressedLook)
101 {
102 if (node->disabled())
103 return;
104
105 EventDispatcher dispatcher(node);
106
107 if (!gNodesDispatchingSimulatedClicks)
108 gNodesDispatchingSimulatedClicks = new HashSet<Node*>;
109 else if (gNodesDispatchingSimulatedClicks->contains(node))
110 return;
111
112 gNodesDispatchingSimulatedClicks->add(node);
113
114 // send mousedown and mouseup before the click, if requested
115 if (sendMouseEvents)
116 dispatcher.dispatchEvent(SimulatedMouseEvent::create(eventNames().mousedownEvent, node->document()->defaultView(), underlyingEvent));
117 node->setActive(true, showPressedLook);
118 if (sendMouseEvents)
119 dispatcher.dispatchEvent(SimulatedMouseEvent::create(eventNames().mouseupEvent, node->document()->defaultView(), underlyingEvent));
120 node->setActive(false);
121
122 // always send click
123 dispatcher.dispatchEvent(SimulatedMouseEvent::create(eventNames().clickEvent, node->document()->defaultView(), underlyingEvent));
124
125 gNodesDispatchingSimulatedClicks->remove(node);
126 }
127
isShadowRootOrSVGShadowRoot(const Node * node)128 static inline bool isShadowRootOrSVGShadowRoot(const Node* node)
129 {
130 return node->isShadowRoot() || node->isSVGShadowRoot();
131 }
132
adjustToShadowBoundaries(PassRefPtr<Node> relatedTarget,const Vector<Node * > relatedTargetAncestors)133 PassRefPtr<EventTarget> EventDispatcher::adjustToShadowBoundaries(PassRefPtr<Node> relatedTarget, const Vector<Node*> relatedTargetAncestors)
134 {
135 Vector<EventContext>::const_iterator lowestCommonBoundary = m_ancestors.end();
136 // Assume divergent boundary is the relatedTarget itself (in other words, related target ancestor chain does not cross any shadow DOM boundaries).
137 Vector<Node*>::const_iterator firstDivergentBoundary = relatedTargetAncestors.begin();
138
139 Vector<EventContext>::const_iterator targetAncestor = m_ancestors.end();
140 // Walk down from the top, looking for lowest common ancestor, also monitoring shadow DOM boundaries.
141 bool diverged = false;
142 for (Vector<Node*>::const_iterator i = relatedTargetAncestors.end() - 1; i >= relatedTargetAncestors.begin(); --i) {
143 if (diverged) {
144 if (isShadowRootOrSVGShadowRoot(*i)) {
145 firstDivergentBoundary = i + 1;
146 break;
147 }
148 continue;
149 }
150
151 if (targetAncestor == m_ancestors.begin()) {
152 diverged = true;
153 continue;
154 }
155
156 targetAncestor--;
157
158 if (isShadowRootOrSVGShadowRoot(*i))
159 lowestCommonBoundary = targetAncestor;
160
161 if ((*i) != (*targetAncestor).node())
162 diverged = true;
163 }
164
165 if (!diverged) {
166 // The relatedTarget is an ancestor or shadowHost of the target.
167 if (m_node->shadowHost() == relatedTarget.get())
168 lowestCommonBoundary = m_ancestors.begin();
169 } else if ((*firstDivergentBoundary) == m_node.get()) {
170 // Since ancestors does not contain target itself, we must account
171 // for the possibility that target is a shadowHost of relatedTarget
172 // and thus serves as the lowestCommonBoundary.
173 // Luckily, in this case the firstDivergentBoundary is target.
174 lowestCommonBoundary = m_ancestors.begin();
175 }
176
177 // Trim ancestors to lowestCommonBoundary to keep events inside of the common shadow DOM subtree.
178 if (lowestCommonBoundary != m_ancestors.end())
179 m_ancestors.shrink(lowestCommonBoundary - m_ancestors.begin());
180 // Set event's related target to the first encountered shadow DOM boundary in the divergent subtree.
181 return firstDivergentBoundary != relatedTargetAncestors.begin() ? *firstDivergentBoundary : relatedTarget;
182 }
183
ancestorsCrossShadowBoundaries(const Vector<EventContext> & ancestors)184 inline static bool ancestorsCrossShadowBoundaries(const Vector<EventContext>& ancestors)
185 {
186 return ancestors.isEmpty() || ancestors.first().node() == ancestors.last().node();
187 }
188
189 // FIXME: Once https://bugs.webkit.org/show_bug.cgi?id=52963 lands, this should
190 // be greatly improved. See https://bugs.webkit.org/show_bug.cgi?id=54025.
adjustRelatedTarget(Event * event,PassRefPtr<EventTarget> prpRelatedTarget)191 PassRefPtr<EventTarget> EventDispatcher::adjustRelatedTarget(Event* event, PassRefPtr<EventTarget> prpRelatedTarget)
192 {
193 if (!prpRelatedTarget)
194 return 0;
195
196 RefPtr<Node> relatedTarget = prpRelatedTarget->toNode();
197 if (!relatedTarget)
198 return 0;
199
200 Node* target = m_node.get();
201 if (!target)
202 return prpRelatedTarget;
203
204 ensureEventAncestors(event);
205
206 // Calculate early if the common boundary is even possible by looking at
207 // ancestors size and if the retargeting has occured (indicating the presence of shadow DOM boundaries).
208 // If there are no boundaries detected, the target and related target can't have a common boundary.
209 bool noCommonBoundary = ancestorsCrossShadowBoundaries(m_ancestors);
210
211 Vector<Node*> relatedTargetAncestors;
212 Node* outermostShadowBoundary = relatedTarget.get();
213 for (Node* n = outermostShadowBoundary; n; n = n->parentOrHostNode()) {
214 if (isShadowRootOrSVGShadowRoot(n))
215 outermostShadowBoundary = n->parentOrHostNode();
216 if (!noCommonBoundary)
217 relatedTargetAncestors.append(n);
218 }
219
220 // Short-circuit the fast case when we know there is no need to calculate a common boundary.
221 if (noCommonBoundary)
222 return outermostShadowBoundary;
223
224 return adjustToShadowBoundaries(relatedTarget.release(), relatedTargetAncestors);
225 }
226
EventDispatcher(Node * node)227 EventDispatcher::EventDispatcher(Node* node)
228 : m_node(node)
229 , m_ancestorsInitialized(false)
230 {
231 ASSERT(node);
232 m_view = node->document()->view();
233 }
234
ensureEventAncestors(Event * event)235 void EventDispatcher::ensureEventAncestors(Event* event)
236 {
237 EventDispatchBehavior behavior = determineDispatchBehavior(event);
238
239 if (!m_node->inDocument())
240 return;
241
242 if (m_ancestorsInitialized)
243 return;
244
245 m_ancestorsInitialized = true;
246
247 Node* ancestor = m_node.get();
248 EventTarget* target = eventTargetRespectingSVGTargetRules(ancestor);
249 bool shouldSkipNextAncestor = false;
250 while (true) {
251 bool isSVGShadowRoot = ancestor->isSVGShadowRoot();
252 if (isSVGShadowRoot || ancestor->isShadowRoot()) {
253 if (behavior == StayInsideShadowDOM)
254 return;
255 #if ENABLE(SVG)
256 ancestor = isSVGShadowRoot ? ancestor->svgShadowHost() : ancestor->shadowHost();
257 #else
258 ancestor = ancestor->shadowHost();
259 #endif
260 if (!shouldSkipNextAncestor)
261 target = ancestor;
262 } else
263 ancestor = ancestor->parentNodeGuaranteedHostFree();
264
265 if (!ancestor)
266 return;
267
268 #if ENABLE(SVG)
269 // Skip SVGShadowTreeRootElement.
270 shouldSkipNextAncestor = ancestor->isSVGShadowRoot();
271 if (shouldSkipNextAncestor)
272 continue;
273 #endif
274 // FIXME: Unroll the extra loop inside eventTargetRespectingSVGTargetRules into this loop.
275 m_ancestors.append(EventContext(ancestor, eventTargetRespectingSVGTargetRules(ancestor), target));
276 }
277 }
278
dispatchEvent(PassRefPtr<Event> event)279 bool EventDispatcher::dispatchEvent(PassRefPtr<Event> event)
280 {
281 event->setTarget(eventTargetRespectingSVGTargetRules(m_node.get()));
282
283 ASSERT(!eventDispatchForbidden());
284 ASSERT(event->target());
285 ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null.
286
287 RefPtr<EventTarget> originalTarget = event->target();
288 ensureEventAncestors(event.get());
289
290 WindowEventContext windowContext(event.get(), m_node.get(), topEventContext());
291
292 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(m_node->document(), *event, windowContext.window(), m_node.get(), m_ancestors);
293
294 // Give the target node a chance to do some work before DOM event handlers get a crack.
295 void* data = m_node->preDispatchEventHandler(event.get());
296 if (event->propagationStopped())
297 goto doneDispatching;
298
299 // Trigger capturing event handlers, starting at the top and working our way down.
300 event->setEventPhase(Event::CAPTURING_PHASE);
301
302 if (windowContext.handleLocalEvents(event.get()) && event->propagationStopped())
303 goto doneDispatching;
304
305 for (size_t i = m_ancestors.size(); i; --i) {
306 m_ancestors[i - 1].handleLocalEvents(event.get());
307 if (event->propagationStopped())
308 goto doneDispatching;
309 }
310
311 event->setEventPhase(Event::AT_TARGET);
312 event->setTarget(originalTarget.get());
313 event->setCurrentTarget(eventTargetRespectingSVGTargetRules(m_node.get()));
314 m_node->handleLocalEvents(event.get());
315 if (event->propagationStopped())
316 goto doneDispatching;
317
318 if (event->bubbles() && !event->cancelBubble()) {
319 // Trigger bubbling event handlers, starting at the bottom and working our way up.
320 event->setEventPhase(Event::BUBBLING_PHASE);
321
322 size_t size = m_ancestors.size();
323 for (size_t i = 0; i < size; ++i) {
324 m_ancestors[i].handleLocalEvents(event.get());
325 if (event->propagationStopped() || event->cancelBubble())
326 goto doneDispatching;
327 }
328 windowContext.handleLocalEvents(event.get());
329 }
330
331 doneDispatching:
332 event->setTarget(originalTarget.get());
333 event->setCurrentTarget(0);
334 event->setEventPhase(0);
335
336 // Pass the data from the preDispatchEventHandler to the postDispatchEventHandler.
337 m_node->postDispatchEventHandler(event.get(), data);
338
339 // Call default event handlers. While the DOM does have a concept of preventing
340 // default handling, the detail of which handlers are called is an internal
341 // implementation detail and not part of the DOM.
342 if (!event->defaultPrevented() && !event->defaultHandled()) {
343 // Non-bubbling events call only one default event handler, the one for the target.
344 m_node->defaultEventHandler(event.get());
345 ASSERT(!event->defaultPrevented());
346 if (event->defaultHandled())
347 goto doneWithDefault;
348 // For bubbling events, call default event handlers on the same targets in the
349 // same order as the bubbling phase.
350 if (event->bubbles()) {
351 size_t size = m_ancestors.size();
352 for (size_t i = 0; i < size; ++i) {
353 m_ancestors[i].node()->defaultEventHandler(event.get());
354 ASSERT(!event->defaultPrevented());
355 if (event->defaultHandled())
356 goto doneWithDefault;
357 }
358 }
359 }
360
361 doneWithDefault:
362
363 // Ensure that after event dispatch, the event's target object is the
364 // outermost shadow DOM boundary.
365 event->setTarget(windowContext.target());
366 event->setCurrentTarget(0);
367 InspectorInstrumentation::didDispatchEvent(cookie);
368
369 return !event->defaultPrevented();
370 }
371
topEventContext()372 const EventContext* EventDispatcher::topEventContext()
373 {
374 return m_ancestors.isEmpty() ? 0 : &m_ancestors.last();
375 }
376
determineDispatchBehavior(Event * event)377 EventDispatchBehavior EventDispatcher::determineDispatchBehavior(Event* event)
378 {
379 // Per XBL 2.0 spec, mutation events should never cross shadow DOM boundary:
380 // http://dev.w3.org/2006/xbl2/#event-flow-and-targeting-across-shadow-s
381 if (event->isMutationEvent())
382 return StayInsideShadowDOM;
383
384 // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
385 // Changing this breaks existing sites.
386 // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
387 if (event->type() == eventNames().selectstartEvent)
388 return StayInsideShadowDOM;
389
390 return RetargetEvent;
391 }
392
393 }
394
395