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 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 "ContainerNode.h"
30 #include "EventContext.h"
31 #include "FocusEvent.h"
32 #include "FrameView.h"
33 #include "HTMLInputElement.h"
34 #include "HTMLMediaElement.h"
35 #include "InsertionPoint.h"
36 #include "InspectorInstrumentation.h"
37 #include "MouseEvent.h"
38 #include "PseudoElement.h"
39 #include "ScopedEventQueue.h"
40 #include "ShadowRoot.h"
41 #include "TouchEvent.h"
42 #include <wtf/RefPtr.h>
45 #include "SVGElementInstance.h"
47 #include "SVGUseElement.h"
52 class WindowEventContext {
54 WindowEventContext(PassRefPtr<Node>, const EventContext*);
56 DOMWindow* window() const { return m_window.get(); }
57 EventTarget* target() const { return m_target.get(); }
58 bool handleLocalEvents(Event&);
61 RefPtr<DOMWindow> m_window;
62 RefPtr<EventTarget> m_target;
65 WindowEventContext::WindowEventContext(PassRefPtr<Node> node, const EventContext* topEventContext)
67 Node* topLevelContainer = topEventContext ? topEventContext->node() : node.get();
68 if (!topLevelContainer->isDocumentNode())
71 m_window = toDocument(topLevelContainer)->domWindow();
72 m_target = topEventContext ? topEventContext->target() : node.get();
75 bool WindowEventContext::handleLocalEvents(Event& event)
80 event.setTarget(m_target.get());
81 event.setCurrentTarget(m_window.get());
82 m_window->fireEventListeners(&event);
88 EventPath(Node& origin, Event&);
90 bool isEmpty() const { return m_path.isEmpty(); }
91 size_t size() const { return m_path.size(); }
92 const EventContext& contextAt(size_t i) const { return *m_path[i]; }
93 EventContext& contextAt(size_t i) { return *m_path[i]; }
95 #if ENABLE(TOUCH_EVENTS)
96 void updateTouchLists(const TouchEvent&);
98 void setRelatedTarget(EventTarget&);
100 bool hasEventListeners(const AtomicString& eventType) const;
102 EventContext* lastContextIfExists() { return m_path.isEmpty() ? 0 : m_path.last().get(); }
105 #if ENABLE(TOUCH_EVENTS)
106 void updateTouchListsInEventPath(const TouchList*, TouchEventContext::TouchListType);
109 Vector<std::unique_ptr<EventContext>, 32> m_path;
112 class EventRelatedNodeResolver {
114 EventRelatedNodeResolver(Node& relatedNode)
115 : m_relatedNode(relatedNode)
116 , m_relatedNodeTreeScope(relatedNode.treeScope())
117 , m_relatedNodeInCurrentTreeScope(nullptr)
118 , m_currentTreeScope(nullptr)
119 #if ENABLE(TOUCH_EVENTS)
121 , m_touchListType(TouchEventContext::NotTouchList)
126 #if ENABLE(TOUCH_EVENTS)
127 EventRelatedNodeResolver(Touch& touch, TouchEventContext::TouchListType touchListType)
128 : m_relatedNode(*touch.target()->toNode())
129 , m_relatedNodeTreeScope(m_relatedNode.treeScope())
130 , m_relatedNodeInCurrentTreeScope(nullptr)
131 , m_currentTreeScope(nullptr)
133 , m_touchListType(touchListType)
135 ASSERT(touch.target()->toNode());
139 #if ENABLE(TOUCH_EVENTS)
140 Touch* touch() const { return m_touch; }
141 TouchEventContext::TouchListType touchListType() const { return m_touchListType; }
144 Node* moveToParentOrShadowHost(Node& newTarget)
146 TreeScope& newTreeScope = newTarget.treeScope();
147 if (&newTreeScope == m_currentTreeScope)
148 return m_relatedNodeInCurrentTreeScope;
150 if (m_currentTreeScope) {
151 ASSERT(m_currentTreeScope->rootNode()->isShadowRoot());
152 ASSERT(&newTarget == toShadowRoot(m_currentTreeScope->rootNode())->hostElement());
153 ASSERT(m_currentTreeScope->parentTreeScope() == &newTreeScope);
156 if (m_relatedNodeInCurrentTreeScope) { // relatedNode is under the current tree scope
157 ASSERT(m_currentTreeScope);
158 m_relatedNodeInCurrentTreeScope = &newTarget;
159 } else if (&newTreeScope == &m_relatedNodeTreeScope) // relatedNode is in the current tree scope;
160 m_relatedNodeInCurrentTreeScope = &m_relatedNode;
161 // Otherwise, we haven't reached the tree scope that contains relatedNode yet.
163 m_currentTreeScope = &newTreeScope;
165 return m_relatedNodeInCurrentTreeScope;
170 const TreeScope& m_relatedNodeTreeScope;
171 Node* m_relatedNodeInCurrentTreeScope;
172 TreeScope* m_currentTreeScope;
173 #if ENABLE(TOUCH_EVENTS)
175 TouchEventContext::TouchListType m_touchListType;
179 inline EventTarget& eventTargetRespectingTargetRules(Node& referenceNode)
181 if (referenceNode.isPseudoElement()) {
182 EventTarget* hostElement = toPseudoElement(referenceNode).hostElement();
188 if (!referenceNode.isSVGElement() || !referenceNode.isInShadowTree())
189 return referenceNode;
191 // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included
192 // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects
193 Node* rootNode = referenceNode.treeScope().rootNode();
194 Element* shadowHostElement = rootNode->isShadowRoot() ? toShadowRoot(rootNode)->hostElement() : 0;
195 // At this time, SVG nodes are not supported in non-<use> shadow trees.
196 if (!shadowHostElement || !shadowHostElement->hasTagName(SVGNames::useTag))
197 return referenceNode;
198 SVGUseElement* useElement = toSVGUseElement(shadowHostElement);
199 if (SVGElementInstance* instance = useElement->instanceForShadowTreeElement(&referenceNode))
203 return referenceNode;
206 void EventDispatcher::dispatchScopedEvent(Node& node, PassRefPtr<Event> event)
208 // We need to set the target here because it can go away by the time we actually fire the event.
209 event->setTarget(&eventTargetRespectingTargetRules(node));
210 ScopedEventQueue::instance().enqueueEvent(event);
213 void EventDispatcher::dispatchSimulatedClick(Element* element, Event* underlyingEvent, SimulatedClickMouseEventOptions mouseEventOptions, SimulatedClickVisualOptions visualOptions)
215 if (element->isDisabledFormControl())
218 DEFINE_STATIC_LOCAL(HashSet<Element*>, elementsDispatchingSimulatedClicks, ());
219 if (!elementsDispatchingSimulatedClicks.add(element).isNewEntry)
222 if (mouseEventOptions == SendMouseOverUpDownEvents)
223 dispatchEvent(element, SimulatedMouseEvent::create(eventNames().mouseoverEvent, element->document().defaultView(), underlyingEvent));
225 if (mouseEventOptions != SendNoEvents)
226 dispatchEvent(element, SimulatedMouseEvent::create(eventNames().mousedownEvent, element->document().defaultView(), underlyingEvent));
227 element->setActive(true, visualOptions == ShowPressedLook);
228 if (mouseEventOptions != SendNoEvents)
229 dispatchEvent(element, SimulatedMouseEvent::create(eventNames().mouseupEvent, element->document().defaultView(), underlyingEvent));
230 element->setActive(false);
233 dispatchEvent(element, SimulatedMouseEvent::create(eventNames().clickEvent, element->document().defaultView(), underlyingEvent));
235 elementsDispatchingSimulatedClicks.remove(element);
238 static void callDefaultEventHandlersInTheBubblingOrder(Event& event, const EventPath& path)
240 // Non-bubbling events call only one default event handler, the one for the target.
241 path.contextAt(0).node()->defaultEventHandler(&event);
242 ASSERT(!event.defaultPrevented());
244 if (event.defaultHandled() || !event.bubbles())
247 size_t size = path.size();
248 for (size_t i = 1; i < size; ++i) {
249 path.contextAt(i).node()->defaultEventHandler(&event);
250 ASSERT(!event.defaultPrevented());
251 if (event.defaultHandled())
256 static void dispatchEventInDOM(Event& event, const EventPath& path, WindowEventContext& windowEventContext)
258 // Trigger capturing event handlers, starting at the top and working our way down.
259 event.setEventPhase(Event::CAPTURING_PHASE);
261 // We don't dispatch load events to the window. This quirk was originally
262 // added because Mozilla doesn't propagate load events to the window object.
263 bool shouldFireEventAtWindow = event.type() != eventNames().loadEvent;
264 if (shouldFireEventAtWindow && windowEventContext.handleLocalEvents(event) && event.propagationStopped())
267 for (size_t i = path.size() - 1; i > 0; --i) {
268 const EventContext& eventContext = path.contextAt(i);
269 if (eventContext.currentTargetSameAsTarget())
271 eventContext.handleLocalEvents(event);
272 if (event.propagationStopped())
276 event.setEventPhase(Event::AT_TARGET);
277 path.contextAt(0).handleLocalEvents(event);
278 if (event.propagationStopped())
281 // Trigger bubbling event handlers, starting at the bottom and working our way up.
282 size_t size = path.size();
283 for (size_t i = 1; i < size; ++i) {
284 const EventContext& eventContext = path.contextAt(i);
285 if (eventContext.currentTargetSameAsTarget())
286 event.setEventPhase(Event::AT_TARGET);
287 else if (event.bubbles() && !event.cancelBubble())
288 event.setEventPhase(Event::BUBBLING_PHASE);
291 eventContext.handleLocalEvents(event);
292 if (event.propagationStopped())
295 if (event.bubbles() && !event.cancelBubble()) {
296 event.setEventPhase(Event::BUBBLING_PHASE);
297 if (shouldFireEventAtWindow)
298 windowEventContext.handleLocalEvents(event);
302 bool EventDispatcher::dispatchEvent(Node* origin, PassRefPtr<Event> prpEvent)
304 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
309 RefPtr<Node> node(origin);
310 RefPtr<Event> event(prpEvent);
311 RefPtr<FrameView> view = node->document().view();
312 EventPath eventPath(*node, *event);
314 if (EventTarget* relatedTarget = event->relatedTarget())
315 eventPath.setRelatedTarget(*relatedTarget);
316 #if ENABLE(TOUCH_EVENTS)
317 if (event->isTouchEvent())
318 eventPath.updateTouchLists(*toTouchEvent(event.get()));
321 ChildNodesLazySnapshot::takeChildNodesLazySnapshot();
323 event->setTarget(&eventTargetRespectingTargetRules(*node));
324 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
325 ASSERT(event->target());
326 WindowEventContext windowEventContext(node.get(), eventPath.lastContextIfExists());
328 InputElementClickState clickHandlingState;
329 if (isHTMLInputElement(node.get()))
330 toHTMLInputElement(*node).willDispatchEvent(*event, clickHandlingState);
332 if (!event->propagationStopped() && !eventPath.isEmpty())
333 dispatchEventInDOM(*event, eventPath, windowEventContext);
335 event->setTarget(&eventTargetRespectingTargetRules(*node));
336 event->setCurrentTarget(0);
337 event->setEventPhase(0);
339 if (clickHandlingState.stateful)
340 toHTMLInputElement(*node).didDispatchClickEvent(*event, clickHandlingState);
342 // Call default event handlers. While the DOM does have a concept of preventing
343 // default handling, the detail of which handlers are called is an internal
344 // implementation detail and not part of the DOM.
345 if (!event->defaultPrevented() && !event->defaultHandled())
346 callDefaultEventHandlersInTheBubblingOrder(*event, eventPath);
348 // Ensure that after event dispatch, the event's target object is the
349 // outermost shadow DOM boundary.
350 event->setTarget(windowEventContext.target());
351 event->setCurrentTarget(0);
353 return !event->defaultPrevented();
356 static inline bool shouldEventCrossShadowBoundary(Event& event, ShadowRoot& shadowRoot, EventTarget& target)
358 Node* targetNode = target.toNode();
359 #if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO)
360 // Video-only full screen is a mode where we use the shadow DOM as an implementation
361 // detail that should not be detectable by the web content.
363 if (Element* element = targetNode->document().webkitCurrentFullScreenElement()) {
364 // FIXME: We assume that if the full screen element is a media element that it's
365 // the video-only full screen. Both here and elsewhere. But that is probably wrong.
366 if (element->isMediaElement() && shadowRoot.hostElement() == element)
372 // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
373 // Changing this breaks existing sites.
374 // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
375 const AtomicString& eventType = event.type();
376 bool targetIsInShadowRoot = targetNode && targetNode->treeScope().rootNode() == &shadowRoot;
377 return !targetIsInShadowRoot
378 || !(eventType == eventNames().abortEvent
379 || eventType == eventNames().changeEvent
380 || eventType == eventNames().errorEvent
381 || eventType == eventNames().loadEvent
382 || eventType == eventNames().resetEvent
383 || eventType == eventNames().resizeEvent
384 || eventType == eventNames().scrollEvent
385 || eventType == eventNames().selectEvent
386 || eventType == eventNames().selectstartEvent);
389 static Node* nodeOrHostIfPseudoElement(Node* node)
391 return node->isPseudoElement() ? toPseudoElement(node)->hostElement() : node;
394 EventPath::EventPath(Node& targetNode, Event& event)
396 bool inDocument = targetNode.inDocument();
397 bool isSVGElement = targetNode.isSVGElement();
398 bool isMouseOrFocusEvent = event.isMouseEvent() || event.isFocusEvent();
399 #if ENABLE(TOUCH_EVENTS)
400 bool isTouchEvent = event.isTouchEvent();
402 EventTarget* target = 0;
404 Node* node = nodeOrHostIfPseudoElement(&targetNode);
406 if (!target || !isSVGElement) // FIXME: This code doesn't make sense once we've climbed out of the SVG subtree in a HTML document.
407 target = &eventTargetRespectingTargetRules(*node);
408 for (; node; node = node->parentNode()) {
409 EventTarget& currentTarget = eventTargetRespectingTargetRules(*node);
410 if (isMouseOrFocusEvent)
411 m_path.append(std::make_unique<MouseOrFocusEventContext>(node, ¤tTarget, target));
412 #if ENABLE(TOUCH_EVENTS)
413 else if (isTouchEvent)
414 m_path.append(std::make_unique<TouchEventContext>(node, ¤tTarget, target));
417 m_path.append(std::make_unique<EventContext>(node, ¤tTarget, target));
420 if (node->isShadowRoot())
423 if (!node || !shouldEventCrossShadowBoundary(event, *toShadowRoot(node), *target))
425 node = toShadowRoot(node)->hostElement();
429 #if ENABLE(TOUCH_EVENTS)
430 static void addRelatedNodeResolversForTouchList(Vector<EventRelatedNodeResolver, 16>& touchTargetResolvers, TouchList* touchList, TouchEventContext::TouchListType type)
432 const size_t touchListSize = touchList->length();
433 for (size_t i = 0; i < touchListSize; ++i)
434 touchTargetResolvers.append(EventRelatedNodeResolver(*touchList->item(i), type));
437 void EventPath::updateTouchLists(const TouchEvent& touchEvent)
439 Vector<EventRelatedNodeResolver, 16> touchTargetResolvers;
440 const size_t touchNodeCount = touchEvent.touches()->length() + touchEvent.targetTouches()->length() + touchEvent.changedTouches()->length();
441 touchTargetResolvers.reserveInitialCapacity(touchNodeCount);
443 addRelatedNodeResolversForTouchList(touchTargetResolvers, touchEvent.touches(), TouchEventContext::Touches);
444 addRelatedNodeResolversForTouchList(touchTargetResolvers, touchEvent.targetTouches(), TouchEventContext::TargetTouches);
445 addRelatedNodeResolversForTouchList(touchTargetResolvers, touchEvent.changedTouches(), TouchEventContext::ChangedTouches);
447 ASSERT(touchTargetResolvers.size() == touchNodeCount);
448 size_t eventPathSize = m_path.size();
449 for (size_t i = 0; i < eventPathSize; ++i) {
450 TouchEventContext& context = toTouchEventContext(*m_path[i]);
451 Node& nodeToMoveTo = *context.node();
452 for (size_t resolverIndex = 0; resolverIndex < touchNodeCount; ++resolverIndex) {
453 EventRelatedNodeResolver& currentResolver = touchTargetResolvers[resolverIndex];
454 Node* nodeInCurrentTreeScope = currentResolver.moveToParentOrShadowHost(nodeToMoveTo);
455 ASSERT(currentResolver.touch());
456 context.touchList(currentResolver.touchListType())->append(currentResolver.touch()->cloneWithNewTarget(nodeInCurrentTreeScope));
462 void EventPath::setRelatedTarget(EventTarget& relatedTarget)
464 Node* relatedNode = relatedTarget.toNode();
468 EventRelatedNodeResolver resolver(*relatedNode);
470 size_t eventPathSize = m_path.size();
471 for (size_t i = 0; i < eventPathSize; i++)
472 toMouseOrFocusEventContext(*m_path[i]).setRelatedTarget(resolver.moveToParentOrShadowHost(*m_path[i]->node()));
475 bool EventPath::hasEventListeners(const AtomicString& eventType) const
477 for (size_t i = 0; i < m_path.size(); i++) {
478 if (m_path[i]->node()->hasEventListeners(eventType))