Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann (at) 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 #include "core/svg/SVGElementInstance.h"
     25 
     26 #include "core/dom/ContainerNodeAlgorithms.h"
     27 #include "core/events/Event.h"
     28 #include "core/events/EventListener.h"
     29 #include "core/events/ThreadLocalEventNames.h"
     30 #include "core/svg/SVGElement.h"
     31 #include "core/svg/SVGElementInstanceList.h"
     32 #include "core/svg/SVGUseElement.h"
     33 
     34 #include "wtf/RefCountedLeakCounter.h"
     35 
     36 namespace WebCore {
     37 
     38 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, instanceCounter, ("WebCoreSVGElementInstance"));
     39 
     40 // EventTarget API
     41 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), abort);
     42 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), blur);
     43 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), change);
     44 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), click);
     45 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), contextmenu);
     46 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dblclick);
     47 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), error);
     48 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), focus);
     49 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), input);
     50 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), keydown);
     51 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), keypress);
     52 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), keyup);
     53 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), load);
     54 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mousedown);
     55 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseenter);
     56 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseleave);
     57 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mousemove);
     58 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseout);
     59 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseover);
     60 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseup);
     61 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mousewheel);
     62 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), wheel);
     63 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), beforecut);
     64 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), cut);
     65 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), beforecopy);
     66 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), copy);
     67 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), beforepaste);
     68 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), paste);
     69 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragenter);
     70 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragover);
     71 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragleave);
     72 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), drop);
     73 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragstart);
     74 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), drag);
     75 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragend);
     76 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), reset);
     77 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), resize);
     78 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), scroll);
     79 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), search);
     80 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), select);
     81 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), selectstart);
     82 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), submit);
     83 DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), unload);
     84 
     85 PassRefPtr<SVGElementInstance> SVGElementInstance::create(SVGUseElement* correspondingUseElement, SVGUseElement* directUseElement, PassRefPtr<SVGElement> originalElement)
     86 {
     87     return adoptRef(new SVGElementInstance(correspondingUseElement, directUseElement, originalElement));
     88 }
     89 
     90 SVGElementInstance::SVGElementInstance(SVGUseElement* correspondingUseElement, SVGUseElement* directUseElement, PassRefPtr<SVGElement> originalElement)
     91     : m_parentInstance(0)
     92     , m_correspondingUseElement(correspondingUseElement)
     93     , m_directUseElement(directUseElement)
     94     , m_element(originalElement)
     95     , m_previousSibling(0)
     96     , m_nextSibling(0)
     97     , m_firstChild(0)
     98     , m_lastChild(0)
     99 {
    100     ASSERT(m_correspondingUseElement);
    101     ASSERT(m_element);
    102     ScriptWrappable::init(this);
    103 
    104     // Register as instance for passed element.
    105     m_element->mapInstanceToElement(this);
    106 
    107 #ifndef NDEBUG
    108     instanceCounter.increment();
    109 #endif
    110 }
    111 
    112 SVGElementInstance::~SVGElementInstance()
    113 {
    114     // Call detach because we may be deleted directly if we are a child of a detached instance.
    115     detach();
    116 
    117 #ifndef NDEBUG
    118     instanceCounter.decrement();
    119 #endif
    120 
    121     m_element = 0;
    122 }
    123 
    124 // It's important not to inline removedLastRef, because we don't want to inline the code to
    125 // delete an SVGElementInstance at each deref call site.
    126 void SVGElementInstance::removedLastRef()
    127 {
    128 #if SECURITY_ASSERT_ENABLED
    129     m_deletionHasBegun = true;
    130 #endif
    131     delete this;
    132 }
    133 
    134 void SVGElementInstance::detach()
    135 {
    136     // Clear all pointers. When the node is detached from the shadow DOM it should be removed but,
    137     // due to ref counting, it may not be. So clear everything to avoid dangling pointers.
    138 
    139     for (SVGElementInstance* node = firstChild(); node; node = node->nextSibling())
    140         node->detach();
    141 
    142     // Deregister as instance for passed element, if we haven't already.
    143     if (m_element->instancesForElement().contains(this))
    144         m_element->removeInstanceMapping(this);
    145     // DO NOT clear ref to m_element because JavaScriptCore uses it for garbage collection
    146 
    147     m_shadowTreeElement = 0;
    148 
    149     m_directUseElement = 0;
    150     m_correspondingUseElement = 0;
    151 
    152     removeDetachedChildrenInContainer<SVGElementInstance, SVGElementInstance>(*this);
    153 }
    154 
    155 PassRefPtr<SVGElementInstanceList> SVGElementInstance::childNodes()
    156 {
    157     return SVGElementInstanceList::create(this);
    158 }
    159 
    160 void SVGElementInstance::setShadowTreeElement(SVGElement* element)
    161 {
    162     ASSERT(element);
    163     m_shadowTreeElement = element;
    164 }
    165 
    166 void SVGElementInstance::appendChild(PassRefPtr<SVGElementInstance> child)
    167 {
    168     appendChildToContainer<SVGElementInstance, SVGElementInstance>(*child, *this);
    169 }
    170 
    171 void SVGElementInstance::invalidateAllInstancesOfElement(SVGElement* element)
    172 {
    173     if (!element || !element->inDocument())
    174         return;
    175 
    176     if (element->instanceUpdatesBlocked())
    177         return;
    178 
    179     const HashSet<SVGElementInstance*>& set = element->instancesForElement();
    180     if (set.isEmpty())
    181         return;
    182 
    183     // Mark all use elements referencing 'element' for rebuilding
    184     const HashSet<SVGElementInstance*>::const_iterator end = set.end();
    185     for (HashSet<SVGElementInstance*>::const_iterator it = set.begin(); it != end; ++it) {
    186         ASSERT((*it)->shadowTreeElement());
    187         ASSERT((*it)->shadowTreeElement()->correspondingElement());
    188         ASSERT((*it)->shadowTreeElement()->correspondingElement() == (*it)->correspondingElement());
    189         ASSERT((*it)->correspondingElement() == element);
    190         (*it)->shadowTreeElement()->setCorrespondingElement(0);
    191 
    192         if (SVGUseElement* element = (*it)->correspondingUseElement()) {
    193             ASSERT(element->inDocument());
    194             element->invalidateShadowTree();
    195         }
    196     }
    197 
    198     element->document().updateStyleIfNeeded();
    199 }
    200 
    201 const AtomicString& SVGElementInstance::interfaceName() const
    202 {
    203     return EventTargetNames::SVGElementInstance;
    204 }
    205 
    206 ExecutionContext* SVGElementInstance::executionContext() const
    207 {
    208     return &m_element->document();
    209 }
    210 
    211 bool SVGElementInstance::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
    212 {
    213     return m_element->addEventListener(eventType, listener, useCapture);
    214 }
    215 
    216 bool SVGElementInstance::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
    217 {
    218     return m_element->removeEventListener(eventType, listener, useCapture);
    219 }
    220 
    221 void SVGElementInstance::removeAllEventListeners()
    222 {
    223     m_element->removeAllEventListeners();
    224 }
    225 
    226 Node* SVGElementInstance::toNode()
    227 {
    228     return shadowTreeElement();
    229 }
    230 
    231 Document* SVGElementInstance::ownerDocument() const
    232 {
    233     return m_element ? m_element->ownerDocument() : 0;
    234 }
    235 
    236 bool SVGElementInstance::dispatchEvent(PassRefPtr<Event> event)
    237 {
    238     SVGElement* element = shadowTreeElement();
    239     if (!element)
    240         return false;
    241 
    242     return element->dispatchEvent(event);
    243 }
    244 
    245 EventTargetData* SVGElementInstance::eventTargetData()
    246 {
    247     // Since no event listeners are added to an SVGElementInstance, we don't have eventTargetData.
    248     return 0;
    249 }
    250 
    251 EventTargetData& SVGElementInstance::ensureEventTargetData()
    252 {
    253     // EventTarget would use these methods if we were actually using its add/removeEventListener logic.
    254     // As we're forwarding those calls to the correspondingElement(), no one should ever call this function.
    255     ASSERT_NOT_REACHED();
    256     return *eventTargetData();
    257 }
    258 
    259 SVGElementInstance::InstanceUpdateBlocker::InstanceUpdateBlocker(SVGElement* targetElement)
    260     : m_targetElement(targetElement)
    261 {
    262     if (m_targetElement)
    263         m_targetElement->setInstanceUpdatesBlocked(true);
    264 }
    265 
    266 SVGElementInstance::InstanceUpdateBlocker::~InstanceUpdateBlocker()
    267 {
    268     if (m_targetElement)
    269         m_targetElement->setInstanceUpdatesBlocked(false);
    270 }
    271 
    272 }
    273