• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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