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 "SVGElementInstanceList.h"
34#include "SVGUseElement.h"
35
36#include <wtf/RefCountedLeakCounter.h>
37
38namespace WebCore {
39
40#ifndef NDEBUG
41static WTF::RefCountedLeakCounter instanceCounter("WebCoreSVGElementInstance");
42#endif
43
44SVGElementInstance::SVGElementInstance(SVGUseElement* correspondingUseElement, SVGUseElement* directUseElement, PassRefPtr<SVGElement> originalElement)
45    : m_correspondingUseElement(correspondingUseElement)
46    , m_directUseElement(directUseElement)
47    , m_element(originalElement)
48    , m_previousSibling(0)
49    , m_nextSibling(0)
50    , m_firstChild(0)
51    , m_lastChild(0)
52{
53    ASSERT(m_correspondingUseElement);
54    ASSERT(m_element);
55
56    // Register as instance for passed element.
57    m_element->mapInstanceToElement(this);
58
59#ifndef NDEBUG
60    instanceCounter.increment();
61#endif
62}
63
64SVGElementInstance::~SVGElementInstance()
65{
66#ifndef NDEBUG
67    instanceCounter.decrement();
68#endif
69
70    // Deregister as instance for passed element.
71    m_element->removeInstanceMapping(this);
72
73    removeAllChildrenInContainer<SVGElementInstance, SVGElementInstance>(this);
74}
75
76PassRefPtr<SVGElementInstanceList> SVGElementInstance::childNodes()
77{
78    return SVGElementInstanceList::create(this);
79}
80
81void SVGElementInstance::setShadowTreeElement(SVGElement* element)
82{
83    ASSERT(element);
84    m_shadowTreeElement = element;
85}
86
87void SVGElementInstance::appendChild(PassRefPtr<SVGElementInstance> child)
88{
89    appendChildToContainer<SVGElementInstance, SVGElementInstance>(child.get(), this);
90}
91
92void SVGElementInstance::invalidateAllInstancesOfElement(SVGElement* element)
93{
94    if (!element || !element->inDocument())
95        return;
96
97    if (element->isStyled() && static_cast<SVGStyledElement*>(element)->instanceUpdatesBlocked())
98        return;
99
100    const HashSet<SVGElementInstance*>& set = element->instancesForElement();
101    if (set.isEmpty())
102        return;
103
104    // Mark all use elements referencing 'element' for rebuilding
105    const HashSet<SVGElementInstance*>::const_iterator end = set.end();
106    for (HashSet<SVGElementInstance*>::const_iterator it = set.begin(); it != end; ++it) {
107        ASSERT((*it)->correspondingElement() == element);
108        if (SVGUseElement* element = (*it)->correspondingUseElement())
109            element->invalidateShadowTree();
110    }
111
112    // Be sure to rebuild use trees, if needed
113    element->document()->updateLayoutIgnorePendingStylesheets();
114}
115
116ScriptExecutionContext* SVGElementInstance::scriptExecutionContext() const
117{
118    return m_element->document();
119}
120
121bool SVGElementInstance::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
122{
123    return m_element->addEventListener(eventType, listener, useCapture);
124}
125
126bool SVGElementInstance::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
127{
128    return m_element->removeEventListener(eventType, listener, useCapture);
129}
130
131void SVGElementInstance::removeAllEventListeners()
132{
133    m_element->removeAllEventListeners();
134}
135
136bool SVGElementInstance::dispatchEvent(PassRefPtr<Event> event)
137{
138    SVGElement* element = shadowTreeElement();
139    if (!element)
140        return false;
141
142    return element->dispatchEvent(event);
143}
144
145EventTargetData* SVGElementInstance::eventTargetData()
146{
147    // EventTarget would use these methods if we were actually using its add/removeEventListener logic.
148    // As we're forwarding those calls to the correspondingElement(), no one should ever call this function.
149    ASSERT_NOT_REACHED();
150    return 0;
151}
152
153EventTargetData* SVGElementInstance::ensureEventTargetData()
154{
155    // EventTarget would use these methods if we were actually using its add/removeEventListener logic.
156    // As we're forwarding those calls to the correspondingElement(), no one should ever call this function.
157    ASSERT_NOT_REACHED();
158    return 0;
159}
160
161}
162
163#endif
164