1/*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB.  If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#ifndef EventRetargeter_h
21#define EventRetargeter_h
22
23#include "ContainerNode.h"
24#include "EventContext.h"
25#include "ShadowRoot.h"
26#include <wtf/HashMap.h>
27#include <wtf/PassRefPtr.h>
28#include <wtf/RefPtr.h>
29
30#if ENABLE(SVG)
31#include "SVGElementInstance.h"
32#include "SVGNames.h"
33#include "SVGUseElement.h"
34#endif
35
36namespace WebCore {
37
38class EventTarget;
39class FocusEvent;
40class MouseEvent;
41class Node;
42#if ENABLE(TOUCH_EVENTS)
43class TouchEvent;
44#endif
45class TreeScope;
46
47enum EventDispatchBehavior {
48    RetargetEvent,
49    StayInsideShadowDOM
50};
51
52class EventRetargeter {
53public:
54    static void calculateEventPath(Node*, Event*, EventPath&);
55    static void adjustForMouseEvent(Node*, const MouseEvent&, EventPath&);
56    static void adjustForFocusEvent(Node*, const FocusEvent&, EventPath&);
57#if ENABLE(TOUCH_EVENTS)
58    typedef Vector<RefPtr<TouchList> > EventPathTouchLists;
59    static void adjustForTouchEvent(Node*, const TouchEvent&, EventPath&);
60#endif
61    static EventTarget* eventTargetRespectingTargetRules(Node* referenceNode);
62
63private:
64    typedef Vector<RefPtr<Node> > AdjustedNodes;
65    typedef HashMap<TreeScope*, Node*> RelatedNodeMap;
66    enum EventWithRelatedTargetDispatchBehavior {
67        StopAtBoundaryIfNeeded,
68        DoesNotStopAtBoundary
69    };
70    static void adjustForRelatedTarget(const Node*, EventTarget* relatedTarget, EventPath&);
71    static void calculateAdjustedNodes(const Node*, const Node* relatedNode, EventWithRelatedTargetDispatchBehavior, EventPath&, AdjustedNodes&);
72    static void buildRelatedNodeMap(const Node*, RelatedNodeMap&);
73    static Node* findRelatedNode(TreeScope*, RelatedNodeMap&);
74#if ENABLE(TOUCH_EVENTS)
75    static void adjustTouchList(const Node*, const TouchList*, const EventPath&, EventPathTouchLists&);
76#endif
77};
78
79inline EventTarget* EventRetargeter::eventTargetRespectingTargetRules(Node* referenceNode)
80{
81    ASSERT(referenceNode);
82
83    if (referenceNode->isPseudoElement())
84        return referenceNode->parentNode();
85
86#if ENABLE(SVG)
87    if (!referenceNode->isSVGElement() || !referenceNode->isInShadowTree())
88        return referenceNode;
89
90    // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included
91    // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects
92    Node* rootNode = referenceNode->treeScope()->rootNode();
93    Element* shadowHostElement = rootNode->isShadowRoot() ? toShadowRoot(rootNode)->host() : 0;
94    // At this time, SVG nodes are not supported in non-<use> shadow trees.
95    if (!shadowHostElement || !shadowHostElement->hasTagName(SVGNames::useTag))
96        return referenceNode;
97    SVGUseElement* useElement = static_cast<SVGUseElement*>(shadowHostElement);
98    if (SVGElementInstance* instance = useElement->instanceForShadowTreeElement(referenceNode))
99        return instance;
100#endif
101
102    return referenceNode;
103}
104
105}
106
107#endif // EventRetargeter_h
108