1/*
2 * Copyright (C) 2010 Google Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27#include "config.h"
28#include "EventContext.h"
29
30#include "ContainerNode.h"
31#include "DOMWindow.h"
32#include "Event.h"
33
34#if ENABLE(SVG)
35#include "SVGElementInstance.h"
36#include "SVGUseElement.h"
37#endif
38
39namespace WebCore {
40
41EventContext::EventContext(ContainerNode* ancestor, EventTarget* target)
42 : m_ancestor(ancestor)
43 , m_target(target)
44{
45}
46
47ContainerNode* EventContext::ancestor() const
48{
49 return m_ancestor.get();
50}
51
52EventTarget* EventContext::target() const
53{
54 return m_target.get();
55}
56
57static inline EventTarget* eventTargetRespectingSVGTargetRules(Node* referenceNode)
58{
59 ASSERT(referenceNode);
60
61#if ENABLE(SVG)
62 if (!referenceNode->isSVGElement())
63 return referenceNode;
64
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->isShadowNode() || !n->isSVGElement())
69 continue;
70
71 ContainerNode* shadowTreeParentElement = n->shadowParentNode();
72 ASSERT(shadowTreeParentElement->hasTagName(SVGNames::useTag));
73
74 if (SVGElementInstance* instance = static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode))
75 return instance;
76 }
77#endif
78
79 return referenceNode;
80}
81
82void EventContext::handleLocalEvents(Event* event) const
83{
84 event->setTarget(target());
85 event->setCurrentTarget(eventTargetRespectingSVGTargetRules(ancestor()));
86 m_ancestor->handleLocalEvents(event);
87}
88
89WindowEventContext::WindowEventContext(Event* event, Node* node, const Vector<EventContext>& ancestors)
90{
91 // We don't dispatch load events to the window. That quirk was originally
92 // added because Mozilla doesn't propagate load events to the window object.
93 if (event->type() == eventNames().loadEvent)
94 return;
95
96 EventTarget* targetForWindowEvents = node;
97 Node* topLevelContainer = node;
98 if (!ancestors.isEmpty()) {
99 topLevelContainer = ancestors.last().ancestor();
100 targetForWindowEvents = ancestors.last().target();
101 }
102 if (!topLevelContainer->isDocumentNode())
103 return;
104
105 m_window = static_cast<Document*>(topLevelContainer)->domWindow();
106 m_target = targetForWindowEvents;
107}
108
109DOMWindow* WindowEventContext::window() const
110{
111 return m_window.get();
112}
113
114EventTarget* WindowEventContext::target() const
115{
116 return m_target.get();
117}
118
119bool WindowEventContext::handleLocalEvents(Event* event)
120{
121 if (!m_window)
122 return false;
123
124 event->setTarget(target());
125 event->setCurrentTarget(window());
126 m_window->fireEventListeners(event);
127 return true;
128}
129
130}