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 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 "FocusEvent.h"
31#include "FrameView.h"
32#include "HTMLInputElement.h"
33#include "HTMLMediaElement.h"
34#include "InsertionPoint.h"
35#include "InspectorInstrumentation.h"
36#include "MouseEvent.h"
37#include "PseudoElement.h"
38#include "ScopedEventQueue.h"
39#include "ShadowRoot.h"
40#include "SVGElementInstance.h"
41#include "SVGNames.h"
42#include "SVGUseElement.h"
43#include "TouchEvent.h"
44
45namespace WebCore {
46
47class WindowEventContext {
48public:
49    WindowEventContext(PassRefPtr<Node>, const EventContext*);
50
51    DOMWindow* window() const { return m_window.get(); }
52    EventTarget* target() const { return m_target.get(); }
53    bool handleLocalEvents(Event&);
54
55private:
56    RefPtr<DOMWindow> m_window;
57    RefPtr<EventTarget> m_target;
58};
59
60WindowEventContext::WindowEventContext(PassRefPtr<Node> node, const EventContext* topEventContext)
61{
62    Node* topLevelContainer = topEventContext ? topEventContext->node() : node.get();
63    if (!topLevelContainer->isDocumentNode())
64        return;
65
66    m_window = toDocument(topLevelContainer)->domWindow();
67    m_target = topEventContext ? topEventContext->target() : node.get();
68}
69
70bool WindowEventContext::handleLocalEvents(Event& event)
71{
72    if (!m_window)
73        return false;
74
75    event.setTarget(m_target.get());
76    event.setCurrentTarget(m_window.get());
77    m_window->fireEventListeners(&event);
78    return true;
79}
80
81class EventPath {
82public:
83    EventPath(Node& origin, Event&);
84
85    bool isEmpty() const { return m_path.isEmpty(); }
86    size_t size() const { return m_path.size(); }
87    const EventContext& contextAt(size_t i) const { return *m_path[i]; }
88    EventContext& contextAt(size_t i) { return *m_path[i]; }
89
90#if ENABLE(TOUCH_EVENTS)
91    bool updateTouchLists(const TouchEvent&);
92#endif
93    void setRelatedTarget(Node& origin, EventTarget&);
94
95    bool hasEventListeners(const AtomicString& eventType) const;
96
97    EventContext* lastContextIfExists() { return m_path.isEmpty() ? 0 : m_path.last().get(); }
98
99private:
100#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
101    void updateTouchListsInEventPath(const TouchList*, TouchEventContext::TouchListType);
102#endif
103
104    Vector<std::unique_ptr<EventContext>, 32> m_path;
105};
106
107class EventRelatedNodeResolver {
108public:
109    EventRelatedNodeResolver(Node& relatedNode)
110        : m_relatedNode(relatedNode)
111        , m_relatedNodeTreeScope(relatedNode.treeScope())
112        , m_relatedNodeInCurrentTreeScope(nullptr)
113        , m_currentTreeScope(nullptr)
114#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
115        , m_touch(0)
116        , m_touchListType(TouchEventContext::NotTouchList)
117#endif
118    {
119    }
120
121#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
122    EventRelatedNodeResolver(Touch& touch, TouchEventContext::TouchListType touchListType)
123        : m_relatedNode(*touch.target()->toNode())
124        , m_relatedNodeTreeScope(m_relatedNode.treeScope())
125        , m_relatedNodeInCurrentTreeScope(nullptr)
126        , m_currentTreeScope(nullptr)
127        , m_touch(&touch)
128        , m_touchListType(touchListType)
129    {
130        ASSERT(touch.target()->toNode());
131    }
132#endif
133
134#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
135    Touch* touch() const { return m_touch; }
136    TouchEventContext::TouchListType touchListType() const { return m_touchListType; }
137#endif
138
139    Node* moveToParentOrShadowHost(Node& newTarget)
140    {
141        TreeScope& newTreeScope = newTarget.treeScope();
142        if (&newTreeScope == m_currentTreeScope)
143            return m_relatedNodeInCurrentTreeScope;
144
145        if (m_currentTreeScope) {
146            ASSERT(m_currentTreeScope->rootNode().isShadowRoot());
147            ASSERT(&newTarget == toShadowRoot(m_currentTreeScope->rootNode()).hostElement());
148            ASSERT(m_currentTreeScope->parentTreeScope() == &newTreeScope);
149        }
150
151        if (&newTreeScope == &m_relatedNodeTreeScope)
152            m_relatedNodeInCurrentTreeScope = &m_relatedNode;
153        else if (m_relatedNodeInCurrentTreeScope) {
154            ASSERT(m_currentTreeScope);
155            m_relatedNodeInCurrentTreeScope = &newTarget;
156        } else {
157            if (!m_currentTreeScope) {
158                TreeScope* newTreeScopeAncestor = &newTreeScope;
159                do {
160                    m_relatedNodeInCurrentTreeScope = findHostOfTreeScopeInTargetTreeScope(m_relatedNodeTreeScope, *newTreeScopeAncestor);
161                    newTreeScopeAncestor = newTreeScopeAncestor->parentTreeScope();
162                    if (newTreeScopeAncestor == &m_relatedNodeTreeScope) {
163                        m_relatedNodeInCurrentTreeScope = &m_relatedNode;
164                        break;
165                    }
166                } while (newTreeScopeAncestor && !m_relatedNodeInCurrentTreeScope);
167            }
168            ASSERT(m_relatedNodeInCurrentTreeScope || findHostOfTreeScopeInTargetTreeScope(newTreeScope, m_relatedNodeTreeScope)
169                || &newTreeScope.documentScope() != &m_relatedNodeTreeScope.documentScope());
170        }
171
172        m_currentTreeScope = &newTreeScope;
173
174        return m_relatedNodeInCurrentTreeScope;
175    }
176
177    static Node* findHostOfTreeScopeInTargetTreeScope(const TreeScope& startingTreeScope, const TreeScope& targetScope)
178    {
179        ASSERT(&targetScope != &startingTreeScope);
180        Node* previousHost = nullptr;
181        for (const TreeScope* scope = &startingTreeScope; scope; scope = scope->parentTreeScope()) {
182            if (scope == &targetScope) {
183                ASSERT(previousHost);
184                ASSERT_WITH_SECURITY_IMPLICATION(&previousHost->treeScope() == &targetScope);
185                return previousHost;
186            }
187            if (scope->rootNode().isShadowRoot())
188                previousHost = toShadowRoot(scope->rootNode()).hostElement();
189            else
190                ASSERT_WITH_SECURITY_IMPLICATION(!scope->parentTreeScope());
191        }
192        return nullptr;
193    }
194
195private:
196    Node& m_relatedNode;
197    const TreeScope& m_relatedNodeTreeScope;
198    Node* m_relatedNodeInCurrentTreeScope;
199    TreeScope* m_currentTreeScope;
200#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
201    Touch* m_touch;
202    TouchEventContext::TouchListType m_touchListType;
203#endif
204};
205
206inline EventTarget& eventTargetRespectingTargetRules(Node& referenceNode)
207{
208    if (referenceNode.isPseudoElement()) {
209        EventTarget* hostElement = toPseudoElement(referenceNode).hostElement();
210        ASSERT(hostElement);
211        return *hostElement;
212    }
213
214    if (!referenceNode.isSVGElement() || !referenceNode.isInShadowTree())
215        return referenceNode;
216
217    // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included
218    // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects
219    auto& rootNode = referenceNode.treeScope().rootNode();
220    Element* shadowHostElement = rootNode.isShadowRoot() ? toShadowRoot(rootNode).hostElement() : nullptr;
221    // At this time, SVG nodes are not supported in non-<use> shadow trees.
222    if (!shadowHostElement || !shadowHostElement->hasTagName(SVGNames::useTag))
223        return referenceNode;
224    SVGUseElement* useElement = toSVGUseElement(shadowHostElement);
225    if (SVGElementInstance* instance = useElement->instanceForShadowTreeElement(&referenceNode))
226        return *instance;
227
228    return referenceNode;
229}
230
231void EventDispatcher::dispatchScopedEvent(Node& node, PassRefPtr<Event> event)
232{
233    // We need to set the target here because it can go away by the time we actually fire the event.
234    event->setTarget(&eventTargetRespectingTargetRules(node));
235    ScopedEventQueue::instance().enqueueEvent(event);
236}
237
238void EventDispatcher::dispatchSimulatedClick(Element* element, Event* underlyingEvent, SimulatedClickMouseEventOptions mouseEventOptions, SimulatedClickVisualOptions visualOptions)
239{
240    if (element->isDisabledFormControl())
241        return;
242
243    DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<Element*>, elementsDispatchingSimulatedClicks, ());
244    if (!elementsDispatchingSimulatedClicks.add(element).isNewEntry)
245        return;
246
247    if (mouseEventOptions == SendMouseOverUpDownEvents)
248        dispatchEvent(element, SimulatedMouseEvent::create(eventNames().mouseoverEvent, element->document().defaultView(), underlyingEvent, element));
249
250    if (mouseEventOptions != SendNoEvents)
251        dispatchEvent(element, SimulatedMouseEvent::create(eventNames().mousedownEvent, element->document().defaultView(), underlyingEvent, element));
252    element->setActive(true, visualOptions == ShowPressedLook);
253    if (mouseEventOptions != SendNoEvents)
254        dispatchEvent(element, SimulatedMouseEvent::create(eventNames().mouseupEvent, element->document().defaultView(), underlyingEvent, element));
255    element->setActive(false);
256
257    // always send click
258    dispatchEvent(element, SimulatedMouseEvent::create(eventNames().clickEvent, element->document().defaultView(), underlyingEvent, element));
259
260    elementsDispatchingSimulatedClicks.remove(element);
261}
262
263static void callDefaultEventHandlersInTheBubblingOrder(Event& event, const EventPath& path)
264{
265    if (path.isEmpty())
266        return;
267
268    // Non-bubbling events call only one default event handler, the one for the target.
269    path.contextAt(0).node()->defaultEventHandler(&event);
270    ASSERT(!event.defaultPrevented());
271
272    if (event.defaultHandled() || !event.bubbles())
273        return;
274
275    size_t size = path.size();
276    for (size_t i = 1; i < size; ++i) {
277        path.contextAt(i).node()->defaultEventHandler(&event);
278        ASSERT(!event.defaultPrevented());
279        if (event.defaultHandled())
280            return;
281    }
282}
283
284static void dispatchEventInDOM(Event& event, const EventPath& path, WindowEventContext& windowEventContext)
285{
286    // Trigger capturing event handlers, starting at the top and working our way down.
287    event.setEventPhase(Event::CAPTURING_PHASE);
288
289    // We don't dispatch load events to the window. This quirk was originally
290    // added because Mozilla doesn't propagate load events to the window object.
291    bool shouldFireEventAtWindow = event.type() != eventNames().loadEvent;
292    if (shouldFireEventAtWindow && windowEventContext.handleLocalEvents(event) && event.propagationStopped())
293        return;
294
295    for (size_t i = path.size() - 1; i > 0; --i) {
296        const EventContext& eventContext = path.contextAt(i);
297        if (eventContext.currentTargetSameAsTarget())
298            continue;
299        eventContext.handleLocalEvents(event);
300        if (event.propagationStopped())
301            return;
302    }
303
304    event.setEventPhase(Event::AT_TARGET);
305    path.contextAt(0).handleLocalEvents(event);
306    if (event.propagationStopped())
307        return;
308
309    // Trigger bubbling event handlers, starting at the bottom and working our way up.
310    size_t size = path.size();
311    for (size_t i = 1; i < size; ++i) {
312        const EventContext& eventContext = path.contextAt(i);
313        if (eventContext.currentTargetSameAsTarget())
314            event.setEventPhase(Event::AT_TARGET);
315        else if (event.bubbles() && !event.cancelBubble())
316            event.setEventPhase(Event::BUBBLING_PHASE);
317        else
318            continue;
319        eventContext.handleLocalEvents(event);
320        if (event.propagationStopped())
321            return;
322    }
323    if (event.bubbles() && !event.cancelBubble()) {
324        event.setEventPhase(Event::BUBBLING_PHASE);
325        if (shouldFireEventAtWindow)
326            windowEventContext.handleLocalEvents(event);
327    }
328}
329
330bool EventDispatcher::dispatchEvent(Node* origin, PassRefPtr<Event> prpEvent)
331{
332    ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
333    if (!prpEvent)
334        return true;
335
336    ASSERT(origin);
337    RefPtr<Node> node(origin);
338    RefPtr<Event> event(prpEvent);
339    RefPtr<FrameView> view = node->document().view();
340    EventPath eventPath(*node, *event);
341
342    if (EventTarget* relatedTarget = event->relatedTarget())
343        eventPath.setRelatedTarget(*node, *relatedTarget);
344#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
345    if (event->isTouchEvent()) {
346        if (!eventPath.updateTouchLists(*toTouchEvent(event.get())))
347            return true;
348    }
349#endif
350
351    ChildNodesLazySnapshot::takeChildNodesLazySnapshot();
352
353    event->setTarget(&eventTargetRespectingTargetRules(*node));
354    ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
355    ASSERT(event->target());
356    WindowEventContext windowEventContext(node.get(), eventPath.lastContextIfExists());
357
358    InputElementClickState clickHandlingState;
359    if (isHTMLInputElement(node.get()))
360        toHTMLInputElement(*node).willDispatchEvent(*event, clickHandlingState);
361
362    if (!event->propagationStopped() && !eventPath.isEmpty())
363        dispatchEventInDOM(*event, eventPath, windowEventContext);
364
365    event->setTarget(&eventTargetRespectingTargetRules(*node));
366    event->setCurrentTarget(0);
367    event->setEventPhase(0);
368
369    if (clickHandlingState.stateful)
370        toHTMLInputElement(*node).didDispatchClickEvent(*event, clickHandlingState);
371
372    // Call default event handlers. While the DOM does have a concept of preventing
373    // default handling, the detail of which handlers are called is an internal
374    // implementation detail and not part of the DOM.
375    if (!event->defaultPrevented() && !event->defaultHandled())
376        callDefaultEventHandlersInTheBubblingOrder(*event, eventPath);
377
378    // Ensure that after event dispatch, the event's target object is the
379    // outermost shadow DOM boundary.
380    event->setTarget(windowEventContext.target());
381    event->setCurrentTarget(0);
382
383    return !event->defaultPrevented();
384}
385
386static inline bool shouldEventCrossShadowBoundary(Event& event, ShadowRoot& shadowRoot, EventTarget& target)
387{
388    Node* targetNode = target.toNode();
389#if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO)
390    // Video-only full screen is a mode where we use the shadow DOM as an implementation
391    // detail that should not be detectable by the web content.
392    if (targetNode) {
393        if (Element* element = targetNode->document().webkitCurrentFullScreenElement()) {
394            // FIXME: We assume that if the full screen element is a media element that it's
395            // the video-only full screen. Both here and elsewhere. But that is probably wrong.
396            if (element->isMediaElement() && shadowRoot.hostElement() == element)
397                return false;
398        }
399    }
400#endif
401
402    // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
403    // Changing this breaks existing sites.
404    // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
405    const AtomicString& eventType = event.type();
406    bool targetIsInShadowRoot = targetNode && &targetNode->treeScope().rootNode() == &shadowRoot;
407    return !targetIsInShadowRoot
408        || !(eventType == eventNames().abortEvent
409            || eventType == eventNames().changeEvent
410            || eventType == eventNames().errorEvent
411            || eventType == eventNames().loadEvent
412            || eventType == eventNames().resetEvent
413            || eventType == eventNames().resizeEvent
414            || eventType == eventNames().scrollEvent
415            || eventType == eventNames().selectEvent
416            || eventType == eventNames().selectstartEvent);
417}
418
419static Node* nodeOrHostIfPseudoElement(Node* node)
420{
421    return node->isPseudoElement() ? toPseudoElement(node)->hostElement() : node;
422}
423
424EventPath::EventPath(Node& targetNode, Event& event)
425{
426    bool inDocument = targetNode.inDocument();
427    bool isSVGElement = targetNode.isSVGElement();
428    bool isMouseOrFocusEvent = event.isMouseEvent() || event.isFocusEvent();
429#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
430    bool isTouchEvent = event.isTouchEvent();
431#endif
432    EventTarget* target = 0;
433
434    Node* node = nodeOrHostIfPseudoElement(&targetNode);
435    while (node) {
436        if (!target || !isSVGElement) // FIXME: This code doesn't make sense once we've climbed out of the SVG subtree in a HTML document.
437            target = &eventTargetRespectingTargetRules(*node);
438        for (; node; node = node->parentNode()) {
439            EventTarget& currentTarget = eventTargetRespectingTargetRules(*node);
440            if (isMouseOrFocusEvent)
441                m_path.append(std::make_unique<MouseOrFocusEventContext>(node, &currentTarget, target));
442#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
443            else if (isTouchEvent)
444                m_path.append(std::make_unique<TouchEventContext>(node, &currentTarget, target));
445#endif
446            else
447                m_path.append(std::make_unique<EventContext>(node, &currentTarget, target));
448            if (!inDocument)
449                return;
450            if (node->isShadowRoot())
451                break;
452        }
453        if (!node || !shouldEventCrossShadowBoundary(event, *toShadowRoot(node), *target))
454            return;
455        node = toShadowRoot(node)->hostElement();
456    }
457}
458
459#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
460static void addRelatedNodeResolversForTouchList(Vector<EventRelatedNodeResolver, 16>& touchTargetResolvers, TouchList* touchList, TouchEventContext::TouchListType type)
461{
462    const size_t touchListSize = touchList->length();
463    for (size_t i = 0; i < touchListSize; ++i)
464        touchTargetResolvers.append(EventRelatedNodeResolver(*touchList->item(i), type));
465}
466
467bool EventPath::updateTouchLists(const TouchEvent& touchEvent)
468{
469    if (!touchEvent.touches() || !touchEvent.targetTouches() || !touchEvent.changedTouches())
470        return false;
471
472    Vector<EventRelatedNodeResolver, 16> touchTargetResolvers;
473    const size_t touchNodeCount = touchEvent.touches()->length() + touchEvent.targetTouches()->length() + touchEvent.changedTouches()->length();
474    touchTargetResolvers.reserveInitialCapacity(touchNodeCount);
475
476    addRelatedNodeResolversForTouchList(touchTargetResolvers, touchEvent.touches(), TouchEventContext::Touches);
477    addRelatedNodeResolversForTouchList(touchTargetResolvers, touchEvent.targetTouches(), TouchEventContext::TargetTouches);
478    addRelatedNodeResolversForTouchList(touchTargetResolvers, touchEvent.changedTouches(), TouchEventContext::ChangedTouches);
479
480    ASSERT(touchTargetResolvers.size() == touchNodeCount);
481    size_t eventPathSize = m_path.size();
482    for (size_t i = 0; i < eventPathSize; ++i) {
483        TouchEventContext& context = toTouchEventContext(*m_path[i]);
484        Node& nodeToMoveTo = *context.node();
485        for (size_t resolverIndex = 0; resolverIndex < touchNodeCount; ++resolverIndex) {
486            EventRelatedNodeResolver& currentResolver = touchTargetResolvers[resolverIndex];
487            Node* nodeInCurrentTreeScope = currentResolver.moveToParentOrShadowHost(nodeToMoveTo);
488            ASSERT(currentResolver.touch());
489            context.touchList(currentResolver.touchListType())->append(currentResolver.touch()->cloneWithNewTarget(nodeInCurrentTreeScope));
490        }
491    }
492    return true;
493}
494#endif
495
496void EventPath::setRelatedTarget(Node& origin, EventTarget& relatedTarget)
497{
498    Node* relatedNode = relatedTarget.toNode();
499    if (!relatedNode)
500        return;
501
502    EventRelatedNodeResolver resolver(*relatedNode);
503
504    bool originIsRelatedTarget = &origin == relatedNode;
505    Node& rootNodeInOriginTreeScope = origin.treeScope().rootNode();
506
507    size_t eventPathSize = m_path.size();
508    size_t i = 0;
509    while (i < eventPathSize) {
510        Node* contextNode = m_path[i]->node();
511        Node* currentRelatedNode = resolver.moveToParentOrShadowHost(*contextNode);
512        if (!originIsRelatedTarget && m_path[i]->target() == currentRelatedNode)
513            break;
514        toMouseOrFocusEventContext(*m_path[i]).setRelatedTarget(currentRelatedNode);
515        i++;
516        if (originIsRelatedTarget && &rootNodeInOriginTreeScope == contextNode)
517            break;
518    }
519    m_path.shrink(i);
520}
521
522bool EventPath::hasEventListeners(const AtomicString& eventType) const
523{
524    for (size_t i = 0; i < m_path.size(); i++) {
525        if (m_path[i]->node()->hasEventListeners(eventType))
526            return true;
527    }
528
529    return false;
530}
531
532}
533