Unify SVG's animation and target tracking systems.
[WebKit-https.git] / Source / WebCore / svg / SVGElementInstance.cpp
1 /*
2  * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
4  * Copyright (C) 2011 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23
24 #if ENABLE(SVG)
25 #include "SVGElementInstance.h"
26
27 #include "ContainerNodeAlgorithms.h"
28 #include "Event.h"
29 #include "EventException.h"
30 #include "EventListener.h"
31 #include "EventNames.h"
32 #include "FrameView.h"
33 #include "SVGDocumentExtensions.h"
34 #include "SVGElementInstanceList.h"
35 #include "SVGUseElement.h"
36
37 #include <wtf/RefCountedLeakCounter.h>
38
39 namespace WebCore {
40
41 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, instanceCounter, ("WebCoreSVGElementInstance"));
42
43 SVGElementInstance::SVGElementInstance(SVGUseElement* correspondingUseElement, SVGUseElement* directUseElement, PassRefPtr<SVGElement> originalElement)
44     : m_correspondingUseElement(correspondingUseElement)
45     , m_directUseElement(directUseElement)
46     , m_element(originalElement)
47     , m_previousSibling(0)
48     , m_nextSibling(0)
49     , m_firstChild(0)
50     , m_lastChild(0)
51 {
52     ASSERT(m_correspondingUseElement);
53     ASSERT(m_element);
54
55     // Register as instance for passed element.
56     m_element->mapInstanceToElement(this);
57
58 #ifndef NDEBUG
59     instanceCounter.increment();
60 #endif
61 }
62
63 SVGElementInstance::~SVGElementInstance()
64 {
65     // Call detach because we may be deleted directly if we are a child of a detached instance.
66     detach();
67
68 #ifndef NDEBUG
69     instanceCounter.decrement();
70 #endif
71
72     m_element = 0;
73 }
74
75 // It's important not to inline removedLastRef, because we don't want to inline the code to
76 // delete an SVGElementInstance at each deref call site.
77 void SVGElementInstance::removedLastRef()
78 {
79 #ifndef NDEBUG
80     m_deletionHasBegun = true;
81 #endif
82     delete this;
83 }
84
85 void SVGElementInstance::detach()
86 {
87     // Clear all pointers. When the node is detached from the shadow DOM it should be removed but,
88     // due to ref counting, it may not be. So clear everything to avoid dangling pointers.
89
90     for (SVGElementInstance* node = firstChild(); node; node = node->nextSibling())
91         node->detach();
92
93     // Deregister as instance for passed element, if we haven't already.
94     if (m_element->instancesForElement().contains(this))
95         m_element->removeInstanceMapping(this);
96     // DO NOT clear ref to m_element because JavaScriptCore uses it for garbage collection
97
98     m_shadowTreeElement = 0;
99
100     m_directUseElement = 0;
101     m_correspondingUseElement = 0;
102
103     removeAllChildrenInContainer<SVGElementInstance, SVGElementInstance>(this);
104 }
105
106 PassRefPtr<SVGElementInstanceList> SVGElementInstance::childNodes()
107 {
108     return SVGElementInstanceList::create(this);
109 }
110
111 void SVGElementInstance::setShadowTreeElement(SVGElement* element)
112 {
113     ASSERT(element);
114     m_shadowTreeElement = element;
115 }
116
117 void SVGElementInstance::appendChild(PassRefPtr<SVGElementInstance> child)
118 {
119     appendChildToContainer<SVGElementInstance, SVGElementInstance>(child.get(), this);
120 }
121
122 void SVGElementInstance::invalidateAllInstancesOfElement(SVGElement* element)
123 {
124     if (!element || !element->inDocument())
125         return;
126
127     if (element->isStyled() && static_cast<SVGStyledElement*>(element)->instanceUpdatesBlocked())
128         return;
129
130     const HashSet<SVGElementInstance*>& set = element->instancesForElement();
131     if (set.isEmpty())
132         return;
133
134     // Mark all use elements referencing 'element' for rebuilding
135     const HashSet<SVGElementInstance*>::const_iterator end = set.end();
136     for (HashSet<SVGElementInstance*>::const_iterator it = set.begin(); it != end; ++it) {
137         ASSERT((*it)->shadowTreeElement());
138         ASSERT((*it)->shadowTreeElement()->correspondingElement());
139         ASSERT((*it)->shadowTreeElement()->correspondingElement() == (*it)->correspondingElement());
140         ASSERT((*it)->correspondingElement() == element);
141         (*it)->shadowTreeElement()->setCorrespondingElement(0);
142
143         if (SVGUseElement* element = (*it)->correspondingUseElement()) {
144             ASSERT(element->inDocument());
145             element->invalidateShadowTree();
146         }
147     }
148
149     element->document()->updateStyleIfNeeded();
150 }
151
152 const AtomicString& SVGElementInstance::interfaceName() const
153 {
154     return eventNames().interfaceForSVGElementInstance;
155 }
156
157 ScriptExecutionContext* SVGElementInstance::scriptExecutionContext() const
158 {
159     return m_element->document();
160 }
161
162 bool SVGElementInstance::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
163 {
164     return m_element->addEventListener(eventType, listener, useCapture);
165 }
166
167 bool SVGElementInstance::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
168 {
169     return m_element->removeEventListener(eventType, listener, useCapture);
170 }
171
172 void SVGElementInstance::removeAllEventListeners()
173 {
174     m_element->removeAllEventListeners();
175 }
176
177 bool SVGElementInstance::dispatchEvent(PassRefPtr<Event> event)
178 {
179     SVGElement* element = shadowTreeElement();
180     if (!element)
181         return false;
182
183     return element->dispatchEvent(event);
184 }
185
186 EventTargetData* SVGElementInstance::eventTargetData()
187 {
188     // EventTarget would use these methods if we were actually using its add/removeEventListener logic.
189     // As we're forwarding those calls to the correspondingElement(), no one should ever call this function.
190     ASSERT_NOT_REACHED();
191     return 0;
192 }
193
194 EventTargetData* SVGElementInstance::ensureEventTargetData()
195 {
196     // EventTarget would use these methods if we were actually using its add/removeEventListener logic.
197     // As we're forwarding those calls to the correspondingElement(), no one should ever call this function.
198     ASSERT_NOT_REACHED();
199     return 0;
200 }
201
202 SVGElementInstance::InstanceUpdateBlocker::InstanceUpdateBlocker(SVGElement* targetElement)
203     : m_targetElement(targetElement->isStyled() ? static_cast<SVGStyledElement*>(targetElement) : 0)
204 {
205     if (m_targetElement)
206         m_targetElement->setInstanceUpdatesBlocked(true);
207 }
208
209 SVGElementInstance::InstanceUpdateBlocker::~InstanceUpdateBlocker()
210 {
211     if (m_targetElement)
212         m_targetElement->setInstanceUpdatesBlocked(false);
213 }
214    
215 }
216
217 #endif