Home | History | Annotate | Download | only in svg
      1 /*
      2     Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3                   2004, 2005, 2006, 2007 Rob Buis <buis (at) kde.org>
      4     Copyright (C) Research In Motion Limited 2009-2010. 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 "SVGUseElement.h"
     26 
     27 #include "CSSStyleSelector.h"
     28 #include "CString.h"
     29 #include "Document.h"
     30 #include "Event.h"
     31 #include "EventListener.h"
     32 #include "HTMLNames.h"
     33 #include "MappedAttribute.h"
     34 #include "NodeRenderStyle.h"
     35 #include "RegisteredEventListener.h"
     36 #include "RenderSVGShadowTreeRootContainer.h"
     37 #include "SVGElementInstance.h"
     38 #include "SVGElementInstanceList.h"
     39 #include "SVGGElement.h"
     40 #include "SVGLength.h"
     41 #include "SVGPreserveAspectRatio.h"
     42 #include "SVGShadowTreeElements.h"
     43 #include "SVGSMILElement.h"
     44 #include "SVGSVGElement.h"
     45 #include "SVGSymbolElement.h"
     46 #include "XLinkNames.h"
     47 #include "XMLSerializer.h"
     48 
     49 // Dump SVGElementInstance object tree - useful to debug instanceRoot problems
     50 // #define DUMP_INSTANCE_TREE
     51 
     52 // Dump the deep-expanded shadow tree (where the renderers are built from)
     53 // #define DUMP_SHADOW_TREE
     54 
     55 namespace WebCore {
     56 
     57 SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document* doc)
     58     : SVGStyledTransformableElement(tagName, doc)
     59     , SVGTests()
     60     , SVGLangSpace()
     61     , SVGExternalResourcesRequired()
     62     , SVGURIReference()
     63     , m_x(LengthModeWidth)
     64     , m_y(LengthModeHeight)
     65     , m_width(LengthModeWidth)
     66     , m_height(LengthModeHeight)
     67     , m_isPendingResource(false)
     68     , m_needsShadowTreeRecreation(false)
     69 {
     70 }
     71 
     72 SVGUseElement::~SVGUseElement()
     73 {
     74 }
     75 
     76 SVGElementInstance* SVGUseElement::instanceRoot() const
     77 {
     78     // If there is no element instance tree, force immediate SVGElementInstance tree
     79     // creation by asking the document to invoke our recalcStyle function - as we can't
     80     // wait for the lazy creation to happen if e.g. JS wants to access the instanceRoot
     81     // object right after creating the element on-the-fly
     82     if (!m_targetElementInstance)
     83         document()->updateLayoutIgnorePendingStylesheets();
     84 
     85     return m_targetElementInstance.get();
     86 }
     87 
     88 SVGElementInstance* SVGUseElement::animatedInstanceRoot() const
     89 {
     90     // FIXME: Implement me.
     91     return 0;
     92 }
     93 
     94 void SVGUseElement::parseMappedAttribute(MappedAttribute* attr)
     95 {
     96     if (attr->name() == SVGNames::xAttr)
     97         setXBaseValue(SVGLength(LengthModeWidth, attr->value()));
     98     else if (attr->name() == SVGNames::yAttr)
     99         setYBaseValue(SVGLength(LengthModeHeight, attr->value()));
    100     else if (attr->name() == SVGNames::widthAttr) {
    101         setWidthBaseValue(SVGLength(LengthModeWidth, attr->value()));
    102         if (widthBaseValue().value(this) < 0.0)
    103             document()->accessSVGExtensions()->reportError("A negative value for use attribute <width> is not allowed");
    104     } else if (attr->name() == SVGNames::heightAttr) {
    105         setHeightBaseValue(SVGLength(LengthModeHeight, attr->value()));
    106         if (heightBaseValue().value(this) < 0.0)
    107             document()->accessSVGExtensions()->reportError("A negative value for use attribute <height> is not allowed");
    108     } else {
    109         if (SVGTests::parseMappedAttribute(attr))
    110             return;
    111         if (SVGLangSpace::parseMappedAttribute(attr))
    112             return;
    113         if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
    114             return;
    115         if (SVGURIReference::parseMappedAttribute(attr))
    116             return;
    117         SVGStyledTransformableElement::parseMappedAttribute(attr);
    118     }
    119 }
    120 
    121 void SVGUseElement::insertedIntoDocument()
    122 {
    123     // This functions exists to assure assumptions made in the code regarding SVGElementInstance creation/destruction are satisfied.
    124     SVGElement::insertedIntoDocument();
    125     ASSERT(!m_targetElementInstance);
    126     ASSERT(!m_isPendingResource);
    127 }
    128 
    129 void SVGUseElement::removedFromDocument()
    130 {
    131     m_targetElementInstance = 0;
    132     SVGElement::removedFromDocument();
    133 }
    134 
    135 void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
    136 {
    137     SVGStyledTransformableElement::svgAttributeChanged(attrName);
    138 
    139     if (!renderer())
    140         return;
    141 
    142     if (SVGURIReference::isKnownAttribute(attrName)) {
    143         if (m_isPendingResource) {
    144             document()->accessSVGExtensions()->removePendingResource(m_resourceId);
    145             m_resourceId = String();
    146             m_isPendingResource = false;
    147         }
    148 
    149         invalidateShadowTree();
    150         return;
    151     }
    152 
    153     if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr) {
    154         updateContainerOffsets();
    155         return;
    156     }
    157 
    158     if (attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr) {
    159         updateContainerSizes();
    160         return;
    161     }
    162 
    163     // Be very careful here, if svgAttributeChanged() has been called because a SVG CSS property changed, we do NOT want to reclone the tree!
    164     if (SVGStyledElement::isKnownAttribute(attrName)) {
    165         setNeedsStyleRecalc();
    166         return;
    167     }
    168 
    169     if (SVGTests::isKnownAttribute(attrName)
    170         || SVGLangSpace::isKnownAttribute(attrName)
    171         || SVGExternalResourcesRequired::isKnownAttribute(attrName)
    172         || SVGStyledTransformableElement::isKnownAttribute(attrName)) {
    173         invalidateShadowTree();
    174     }
    175 }
    176 
    177 void SVGUseElement::synchronizeProperty(const QualifiedName& attrName)
    178 {
    179     SVGStyledTransformableElement::synchronizeProperty(attrName);
    180 
    181     if (attrName == anyQName()) {
    182         synchronizeX();
    183         synchronizeY();
    184         synchronizeWidth();
    185         synchronizeHeight();
    186         synchronizeExternalResourcesRequired();
    187         synchronizeHref();
    188         return;
    189     }
    190 
    191     if (attrName == SVGNames::xAttr)
    192         synchronizeX();
    193     else if (attrName == SVGNames::yAttr)
    194         synchronizeY();
    195     else if (attrName == SVGNames::widthAttr)
    196         synchronizeWidth();
    197     else if (attrName == SVGNames::heightAttr)
    198         synchronizeHeight();
    199     else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
    200         synchronizeExternalResourcesRequired();
    201     else if (SVGURIReference::isKnownAttribute(attrName))
    202         synchronizeHref();
    203 }
    204 
    205 static void updateContainerSize(SVGUseElement* useElement, SVGElementInstance* targetInstance)
    206 {
    207     // Depth-first used to write the method in early exit style, no particular other reason.
    208     for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
    209         updateContainerSize(useElement, instance);
    210 
    211     SVGElement* correspondingElement = targetInstance->correspondingElement();
    212     ASSERT(correspondingElement);
    213 
    214     bool isSymbolTag = correspondingElement->hasTagName(SVGNames::symbolTag);
    215     if (!correspondingElement->hasTagName(SVGNames::svgTag) && !isSymbolTag)
    216         return;
    217 
    218     SVGElement* shadowTreeElement = targetInstance->shadowTreeElement();
    219     ASSERT(shadowTreeElement);
    220     ASSERT(shadowTreeElement->hasTagName(SVGNames::svgTag));
    221 
    222     // Spec (<use> on <symbol>): This generated 'svg' will always have explicit values for attributes width and height.
    223     // If attributes width and/or height are provided on the 'use' element, then these attributes
    224     // will be transferred to the generated 'svg'. If attributes width and/or height are not specified,
    225     // the generated 'svg' element will use values of 100% for these attributes.
    226 
    227     // Spec (<use> on <svg>): If attributes width and/or height are provided on the 'use' element, then these
    228     // values will override the corresponding attributes on the 'svg' in the generated tree.
    229 
    230     if (useElement->hasAttribute(SVGNames::widthAttr))
    231         shadowTreeElement->setAttribute(SVGNames::widthAttr, useElement->getAttribute(SVGNames::widthAttr));
    232     else if (isSymbolTag && shadowTreeElement->hasAttribute(SVGNames::widthAttr))
    233         shadowTreeElement->setAttribute(SVGNames::widthAttr, "100%");
    234 
    235     if (useElement->hasAttribute(SVGNames::heightAttr))
    236         shadowTreeElement->setAttribute(SVGNames::heightAttr, useElement->getAttribute(SVGNames::heightAttr));
    237     else if (isSymbolTag && shadowTreeElement->hasAttribute(SVGNames::heightAttr))
    238         shadowTreeElement->setAttribute(SVGNames::heightAttr, "100%");
    239 }
    240 
    241 void SVGUseElement::updateContainerSizes()
    242 {
    243     if (!m_targetElementInstance)
    244         return;
    245 
    246     // Update whole subtree, scanning for shadow container elements, that correspond to <svg>/<symbol> tags
    247     updateContainerSize(this, m_targetElementInstance.get());
    248 
    249     if (renderer())
    250         renderer()->setNeedsLayout(true);
    251 }
    252 
    253 static void updateContainerOffset(SVGElementInstance* targetInstance)
    254 {
    255     // Depth-first used to write the method in early exit style, no particular other reason.
    256     for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
    257         updateContainerOffset(instance);
    258 
    259     SVGElement* correspondingElement = targetInstance->correspondingElement();
    260     ASSERT(correspondingElement);
    261 
    262     if (!correspondingElement->hasTagName(SVGNames::useTag))
    263         return;
    264 
    265     SVGElement* shadowTreeElement = targetInstance->shadowTreeElement();
    266     ASSERT(shadowTreeElement);
    267     ASSERT(shadowTreeElement->hasTagName(SVGNames::gTag));
    268 
    269     if (!static_cast<SVGGElement*>(shadowTreeElement)->isShadowTreeContainerElement())
    270         return;
    271 
    272     // Spec: An additional transformation translate(x,y) is appended to the end
    273     // (i.e., right-side) of the transform attribute on the generated 'g', where x
    274     // and y represent the values of the x and y attributes on the 'use' element.
    275     SVGUseElement* useElement = static_cast<SVGUseElement*>(correspondingElement);
    276     SVGShadowTreeContainerElement* containerElement = static_cast<SVGShadowTreeContainerElement*>(shadowTreeElement);
    277     containerElement->setContainerOffset(useElement->x(), useElement->y());
    278 }
    279 
    280 void SVGUseElement::updateContainerOffsets()
    281 {
    282     if (!m_targetElementInstance)
    283         return;
    284 
    285     // Update root container offset (not reachable through instance tree)
    286     SVGElement* shadowRoot = m_targetElementInstance->shadowTreeElement();
    287     ASSERT(shadowRoot);
    288 
    289     Node* parentNode = shadowRoot->parentNode();
    290     ASSERT(parentNode);
    291     ASSERT(parentNode->isSVGElement());
    292     ASSERT(parentNode->hasTagName(SVGNames::gTag));
    293     ASSERT(static_cast<SVGGElement*>(parentNode)->isShadowTreeContainerElement());
    294 
    295     SVGShadowTreeContainerElement* containerElement = static_cast<SVGShadowTreeContainerElement*>(parentNode);
    296     containerElement->setContainerOffset(x(), y());
    297 
    298     // Update whole subtree, scanning for shadow container elements, marking a cloned use subtree
    299     updateContainerOffset(m_targetElementInstance.get());
    300 
    301     if (renderer())
    302         renderer()->setNeedsLayout(true);
    303 }
    304 
    305 void SVGUseElement::recalcStyle(StyleChange change)
    306 {
    307     // Eventually mark shadow root element needing style recalc
    308     if (needsStyleRecalc() && m_targetElementInstance) {
    309         if (SVGElement* shadowRoot = m_targetElementInstance->shadowTreeElement())
    310             shadowRoot->setNeedsStyleRecalc();
    311     }
    312 
    313     SVGStyledTransformableElement::recalcStyle(change);
    314 
    315     bool needsStyleUpdate = !m_needsShadowTreeRecreation;
    316     if (m_needsShadowTreeRecreation) {
    317         static_cast<RenderSVGShadowTreeRootContainer*>(renderer())->markShadowTreeForRecreation();
    318         m_needsShadowTreeRecreation = false;
    319     }
    320 
    321     RenderSVGShadowTreeRootContainer* shadowRoot = static_cast<RenderSVGShadowTreeRootContainer*>(renderer());
    322     if (!shadowRoot)
    323         return;
    324 
    325     shadowRoot->updateFromElement();
    326 
    327     if (!needsStyleUpdate)
    328         return;
    329 
    330     shadowRoot->updateStyle(change);
    331 }
    332 
    333 #ifdef DUMP_INSTANCE_TREE
    334 void dumpInstanceTree(unsigned int& depth, String& text, SVGElementInstance* targetInstance)
    335 {
    336     SVGElement* element = targetInstance->correspondingElement();
    337     ASSERT(element);
    338 
    339     SVGElement* shadowTreeElement = targetInstance->shadowTreeElement();
    340     ASSERT(shadowTreeElement);
    341 
    342     String elementId = element->getIDAttribute();
    343     String elementNodeName = element->nodeName();
    344     String shadowTreeElementNodeName = shadowTreeElement->nodeName();
    345     String parentNodeName = element->parentNode() ? element->parentNode()->nodeName() : "null";
    346     String firstChildNodeName = element->firstChild() ? element->firstChild()->nodeName() : "null";
    347 
    348     for (unsigned int i = 0; i < depth; ++i)
    349         text += "  ";
    350 
    351     text += String::format("SVGElementInstance this=%p, (parentNode=%s (%p), firstChild=%s (%p), correspondingElement=%s (%p), shadowTreeElement=%s (%p), id=%s)\n",
    352                            targetInstance, parentNodeName.latin1().data(), element->parentNode(), firstChildNodeName.latin1().data(), element->firstChild(),
    353                            elementNodeName.latin1().data(), element, shadowTreeElementNodeName.latin1().data(), shadowTreeElement, elementId.latin1().data());
    354 
    355     for (unsigned int i = 0; i < depth; ++i)
    356         text += "  ";
    357 
    358     const HashSet<SVGElementInstance*>& elementInstances = element->instancesForElement();
    359     text += String::format("Corresponding element is associated with %i instance(s):\n", elementInstances.size());
    360 
    361     const HashSet<SVGElementInstance*>::const_iterator end = elementInstances.end();
    362     for (HashSet<SVGElementInstance*>::const_iterator it = elementInstances.begin(); it != end; ++it) {
    363         for (unsigned int i = 0; i < depth; ++i)
    364             text += "  ";
    365 
    366         text += String::format(" -> SVGElementInstance this=%p, (refCount: %i, shadowTreeElement in document? %i)\n",
    367                                *it, (*it)->refCount(), (*it)->shadowTreeElement()->inDocument());
    368     }
    369 
    370     ++depth;
    371 
    372     for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
    373         dumpInstanceTree(depth, text, instance);
    374 
    375     --depth;
    376 }
    377 #endif
    378 
    379 static bool isDisallowedElement(Node* element)
    380 {
    381 #if ENABLE(SVG_FOREIGN_OBJECT)
    382     // <foreignObject> should never be contained in a <use> tree. Too dangerous side effects possible.
    383     if (element->hasTagName(SVGNames::foreignObjectTag))
    384         return true;
    385 #endif
    386 #if ENABLE(SVG_ANIMATION)
    387     if (SVGSMILElement::isSMILElement(element))
    388         return true;
    389 #endif
    390 
    391     return false;
    392 }
    393 
    394 static bool subtreeContainsDisallowedElement(Node* start)
    395 {
    396     if (isDisallowedElement(start))
    397         return true;
    398 
    399     for (Node* cur = start->firstChild(); cur; cur = cur->nextSibling()) {
    400         if (subtreeContainsDisallowedElement(cur))
    401             return true;
    402     }
    403 
    404     return false;
    405 }
    406 
    407 void SVGUseElement::buildPendingResource()
    408 {
    409     // If we're called the first time (during shadow tree root creation from RenderSVGShadowTreeRootContainer)
    410     // we either determine that our target is available or not - then we add ourselves to the pending resource list
    411     // Once the pending resource appears, it will call buildPendingResource(), so we're called a second time.
    412     String id = SVGURIReference::getTarget(href());
    413     Element* targetElement = document()->getElementById(id);
    414     ASSERT(!m_targetElementInstance);
    415 
    416     if (!targetElement) {
    417         if (m_isPendingResource)
    418             return;
    419 
    420         m_isPendingResource = true;
    421         m_resourceId = id;
    422         document()->accessSVGExtensions()->addPendingResource(id, this);
    423         return;
    424     }
    425 
    426     if (m_isPendingResource) {
    427         ASSERT(!m_targetElementInstance);
    428         m_isPendingResource = false;
    429         invalidateShadowTree();
    430     }
    431 }
    432 
    433 void SVGUseElement::buildShadowAndInstanceTree(SVGShadowTreeRootElement* shadowRoot)
    434 {
    435     String id = SVGURIReference::getTarget(href());
    436     Element* targetElement = document()->getElementById(id);
    437     ASSERT(targetElement);
    438 
    439     // Do not build the shadow/instance tree for <use> elements living in a shadow tree.
    440     // The will be expanded soon anyway - see expandUseElementsInShadowTree().
    441     Node* parent = parentNode();
    442     while (parent) {
    443         if (parent->isShadowNode())
    444             return;
    445 
    446         parent = parent->parentNode();
    447     }
    448 
    449     SVGElement* target = 0;
    450     if (targetElement && targetElement->isSVGElement())
    451         target = static_cast<SVGElement*>(targetElement);
    452 
    453     if (m_targetElementInstance)
    454         m_targetElementInstance = 0;
    455 
    456     // Do not allow self-referencing.
    457     // 'target' may be null, if it's a non SVG namespaced element.
    458     if (!target || target == this)
    459         return;
    460 
    461     // Why a seperated instance/shadow tree? SVG demands it:
    462     // The instance tree is accesable from JavaScript, and has to
    463     // expose a 1:1 copy of the referenced tree, whereas internally we need
    464     // to alter the tree for correct "use-on-symbol", "use-on-svg" support.
    465 
    466     // Build instance tree. Create root SVGElementInstance object for the first sub-tree node.
    467     //
    468     // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a
    469     // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object
    470     // is the SVGRectElement that corresponds to the referenced 'rect' element.
    471     m_targetElementInstance = SVGElementInstance::create(this, target);
    472 
    473     // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
    474     bool foundProblem = false;
    475     buildInstanceTree(target, m_targetElementInstance.get(), foundProblem);
    476 
    477     // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it!
    478     // Non-appearing <use> content is easier to debug, then half-appearing content.
    479     if (foundProblem) {
    480         m_targetElementInstance = 0;
    481         return;
    482     }
    483 
    484     // Assure instance tree building was successfull
    485     ASSERT(m_targetElementInstance);
    486     ASSERT(!m_targetElementInstance->shadowTreeElement());
    487     ASSERT(m_targetElementInstance->correspondingUseElement() == this);
    488     ASSERT(m_targetElementInstance->correspondingElement() == target);
    489 
    490     // Build shadow tree from instance tree
    491     // This also handles the special cases: <use> on <symbol>, <use> on <svg>.
    492     buildShadowTree(shadowRoot, target, m_targetElementInstance.get());
    493 
    494 #if ENABLE(SVG) && ENABLE(SVG_USE)
    495     // Expand all <use> elements in the shadow tree.
    496     // Expand means: replace the actual <use> element by what it references.
    497     expandUseElementsInShadowTree(shadowRoot, shadowRoot);
    498 
    499     // Expand all <symbol> elements in the shadow tree.
    500     // Expand means: replace the actual <symbol> element by the <svg> element.
    501     expandSymbolElementsInShadowTree(shadowRoot, shadowRoot);
    502 #endif
    503 
    504     // Now that the shadow tree is completly expanded, we can associate
    505     // shadow tree elements <-> instances in the instance tree.
    506     associateInstancesWithShadowTreeElements(shadowRoot->firstChild(), m_targetElementInstance.get());
    507 
    508     // If no shadow tree element is present, this means that the reference root
    509     // element was removed, as it is disallowed (ie. <use> on <foreignObject>)
    510     // Do NOT leave an inconsistent instance tree around, instead destruct it.
    511     if (!m_targetElementInstance->shadowTreeElement()) {
    512         shadowRoot->removeAllChildren();
    513         m_targetElementInstance = 0;
    514         return;
    515     }
    516 
    517     // Consistency checks - this is assumed in updateContainerOffset().
    518     ASSERT(m_targetElementInstance->shadowTreeElement()->parentNode() == shadowRoot);
    519 
    520     // Eventually dump instance tree
    521 #ifdef DUMP_INSTANCE_TREE
    522     String text;
    523     unsigned int depth = 0;
    524 
    525     dumpInstanceTree(depth, text, m_targetElementInstance.get());
    526     fprintf(stderr, "\nDumping <use> instance tree:\n%s\n", text.latin1().data());
    527 #endif
    528 
    529     // Eventually dump shadow tree
    530 #ifdef DUMP_SHADOW_TREE
    531     ExceptionCode ec = 0;
    532 
    533     PassRefPtr<XMLSerializer> serializer = XMLSerializer::create();
    534 
    535     String markup = serializer->serializeToString(shadowRoot, ec);
    536     ASSERT(!ec);
    537 
    538     fprintf(stderr, "Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data());
    539 #endif
    540 
    541     // Transfer event listeners assigned to the referenced element to our shadow tree elements.
    542     transferEventListenersToShadowTree(m_targetElementInstance.get());
    543 
    544     // Update container offset/size
    545     updateContainerOffsets();
    546     updateContainerSizes();
    547 }
    548 
    549 RenderObject* SVGUseElement::createRenderer(RenderArena* arena, RenderStyle*)
    550 {
    551     return new (arena) RenderSVGShadowTreeRootContainer(this);
    552 }
    553 
    554 static void updateFromElementCallback(Node* node)
    555 {
    556     if (RenderObject* renderer = node->renderer())
    557         renderer->updateFromElement();
    558 }
    559 
    560 void SVGUseElement::attach()
    561 {
    562     SVGStyledTransformableElement::attach();
    563 
    564     if (renderer())
    565         queuePostAttachCallback(updateFromElementCallback, this);
    566 }
    567 
    568 void SVGUseElement::detach()
    569 {
    570     SVGStyledTransformableElement::detach();
    571     m_targetElementInstance = 0;
    572 }
    573 
    574 static bool isDirectReference(Node* n)
    575 {
    576     return n->hasTagName(SVGNames::pathTag) ||
    577            n->hasTagName(SVGNames::rectTag) ||
    578            n->hasTagName(SVGNames::circleTag) ||
    579            n->hasTagName(SVGNames::ellipseTag) ||
    580            n->hasTagName(SVGNames::polygonTag) ||
    581            n->hasTagName(SVGNames::polylineTag) ||
    582            n->hasTagName(SVGNames::textTag);
    583 }
    584 
    585 Path SVGUseElement::toClipPath() const
    586 {
    587     Node* n = m_targetElementInstance ? m_targetElementInstance->shadowTreeElement() : 0;
    588     if (!n)
    589         return Path();
    590 
    591     if (n->isSVGElement() && static_cast<SVGElement*>(n)->isStyledTransformable()) {
    592         if (!isDirectReference(n))
    593             // Spec: Indirect references are an error (14.3.5)
    594             document()->accessSVGExtensions()->reportError("Not allowed to use indirect reference in <clip-path>");
    595         else
    596             return static_cast<SVGStyledTransformableElement*>(n)->toClipPath();
    597     }
    598 
    599     return Path();
    600 }
    601 
    602 void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* targetInstance, bool& foundProblem)
    603 {
    604     ASSERT(target);
    605     ASSERT(targetInstance);
    606 
    607     // A general description from the SVG spec, describing what buildInstanceTree() actually does.
    608     //
    609     // Spec: If the 'use' element references a 'g' which contains two 'rect' elements, then the instance tree
    610     // contains three SVGElementInstance objects, a root SVGElementInstance object whose correspondingElement
    611     // is the SVGGElement object for the 'g', and then two child SVGElementInstance objects, each of which has
    612     // its correspondingElement that is an SVGRectElement object.
    613 
    614     for (Node* node = target->firstChild(); node; node = node->nextSibling()) {
    615         SVGElement* element = 0;
    616         if (node->isSVGElement())
    617             element = static_cast<SVGElement*>(node);
    618 
    619         // Skip any non-svg nodes or any disallowed element.
    620         if (!element || isDisallowedElement(element))
    621             continue;
    622 
    623         // Create SVGElementInstance object, for both container/non-container nodes.
    624         RefPtr<SVGElementInstance> instance = SVGElementInstance::create(this, element);
    625         SVGElementInstance* instancePtr = instance.get();
    626         targetInstance->appendChild(instance.release());
    627 
    628         // Enter recursion, appending new instance tree nodes to the "instance" object.
    629         buildInstanceTree(element, instancePtr, foundProblem);
    630     }
    631 
    632     // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
    633     // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
    634     if (target->hasTagName(SVGNames::useTag))
    635         handleDeepUseReferencing(static_cast<SVGUseElement*>(target), targetInstance, foundProblem);
    636 }
    637 
    638 void SVGUseElement::handleDeepUseReferencing(SVGUseElement* use, SVGElementInstance* targetInstance, bool& foundProblem)
    639 {
    640     String id = SVGURIReference::getTarget(use->href());
    641     Element* targetElement = document()->getElementById(id);
    642     SVGElement* target = 0;
    643     if (targetElement && targetElement->isSVGElement())
    644         target = static_cast<SVGElement*>(targetElement);
    645 
    646     if (!target)
    647         return;
    648 
    649     // Cycle detection first!
    650     foundProblem = (target == this);
    651 
    652     // Shortcut for self-references
    653     if (foundProblem)
    654         return;
    655 
    656     SVGElementInstance* instance = targetInstance->parentNode();
    657     while (instance) {
    658         SVGElement* element = instance->correspondingElement();
    659 
    660         if (element->getIDAttribute() == id) {
    661             foundProblem = true;
    662             return;
    663         }
    664 
    665         instance = instance->parentNode();
    666     }
    667 
    668     // Create an instance object, even if we're dealing with a cycle
    669     RefPtr<SVGElementInstance> newInstance = SVGElementInstance::create(this, target);
    670     SVGElementInstance* newInstancePtr = newInstance.get();
    671     targetInstance->appendChild(newInstance.release());
    672 
    673     // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
    674     buildInstanceTree(target, newInstancePtr, foundProblem);
    675 }
    676 
    677 void SVGUseElement::removeDisallowedElementsFromSubtree(Node* subtree)
    678 {
    679     ASSERT(!subtree->inDocument());
    680     ExceptionCode ec;
    681     Node* node = subtree->firstChild();
    682     while (node) {
    683         if (isDisallowedElement(node)) {
    684             Node* next = node->traverseNextSibling(subtree);
    685             // The subtree is not in document so this won't generate events that could mutate the tree.
    686             node->parent()->removeChild(node, ec);
    687             node = next;
    688         } else
    689             node = node->traverseNextNode(subtree);
    690     }
    691 }
    692 
    693 void SVGUseElement::buildShadowTree(SVGShadowTreeRootElement* shadowRoot, SVGElement* target, SVGElementInstance* targetInstance)
    694 {
    695     // For instance <use> on <foreignObject> (direct case).
    696     if (isDisallowedElement(target))
    697         return;
    698 
    699     RefPtr<Element> newChild = targetInstance->correspondingElement()->cloneElementWithChildren();
    700 
    701     // We don't walk the target tree element-by-element, and clone each element,
    702     // but instead use cloneElementWithChildren(). This is an optimization for the common
    703     // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
    704     // Though if there are disallowed elements in the subtree, we have to remove them.
    705     // For instance: <use> on <g> containing <foreignObject> (indirect case).
    706     if (subtreeContainsDisallowedElement(newChild.get()))
    707         removeDisallowedElementsFromSubtree(newChild.get());
    708 
    709     SVGElement* newChildPtr = 0;
    710     if (newChild->isSVGElement())
    711         newChildPtr = static_cast<SVGElement*>(newChild.get());
    712     ASSERT(newChildPtr);
    713 
    714     ExceptionCode ec = 0;
    715     shadowRoot->appendChild(newChild.release(), ec);
    716     ASSERT(!ec);
    717 }
    718 
    719 #if ENABLE(SVG) && ENABLE(SVG_USE)
    720 void SVGUseElement::expandUseElementsInShadowTree(SVGShadowTreeRootElement* shadowRoot, Node* element)
    721 {
    722     // Why expand the <use> elements in the shadow tree here, and not just
    723     // do this directly in buildShadowTree, if we encounter a <use> element?
    724     //
    725     // Short answer: Because we may miss to expand some elements. Ie. if a <symbol>
    726     // contains <use> tags, we'd miss them. So once we're done with settin' up the
    727     // actual shadow tree (after the special case modification for svg/symbol) we have
    728     // to walk it completely and expand all <use> elements.
    729     if (element->hasTagName(SVGNames::useTag)) {
    730         SVGUseElement* use = static_cast<SVGUseElement*>(element);
    731 
    732         String id = SVGURIReference::getTarget(use->href());
    733         Element* targetElement = document()->getElementById(id);
    734         SVGElement* target = 0;
    735         if (targetElement && targetElement->isSVGElement())
    736             target = static_cast<SVGElement*>(targetElement);
    737 
    738         // Don't ASSERT(target) here, it may be "pending", too.
    739         if (target) {
    740             // Setup sub-shadow tree root node
    741             RefPtr<SVGShadowTreeContainerElement> cloneParent = new SVGShadowTreeContainerElement(document());
    742 
    743             // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
    744             // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
    745             transferUseAttributesToReplacedElement(use, cloneParent.get());
    746 
    747             ExceptionCode ec = 0;
    748 
    749             // For instance <use> on <foreignObject> (direct case).
    750             if (isDisallowedElement(target)) {
    751                 // We still have to setup the <use> replacment (<g>). Otherwhise
    752                 // associateInstancesWithShadowTreeElements() makes wrong assumptions.
    753                 // Replace <use> with referenced content.
    754                 ASSERT(use->parentNode());
    755                 use->parentNode()->replaceChild(cloneParent.release(), use, ec);
    756                 ASSERT(!ec);
    757                 return;
    758             }
    759 
    760             RefPtr<Element> newChild = target->cloneElementWithChildren();
    761 
    762             // We don't walk the target tree element-by-element, and clone each element,
    763             // but instead use cloneElementWithChildren(). This is an optimization for the common
    764             // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
    765             // Though if there are disallowed elements in the subtree, we have to remove them.
    766             // For instance: <use> on <g> containing <foreignObject> (indirect case).
    767             if (subtreeContainsDisallowedElement(newChild.get()))
    768                 removeDisallowedElementsFromSubtree(newChild.get());
    769 
    770             SVGElement* newChildPtr = 0;
    771             if (newChild->isSVGElement())
    772                 newChildPtr = static_cast<SVGElement*>(newChild.get());
    773             ASSERT(newChildPtr);
    774 
    775             cloneParent->appendChild(newChild.release(), ec);
    776             ASSERT(!ec);
    777 
    778             // Replace <use> with referenced content.
    779             ASSERT(use->parentNode());
    780             use->parentNode()->replaceChild(cloneParent.release(), use, ec);
    781             ASSERT(!ec);
    782 
    783             // Immediately stop here, and restart expanding.
    784             expandUseElementsInShadowTree(shadowRoot, shadowRoot);
    785             return;
    786         }
    787     }
    788 
    789     for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
    790         expandUseElementsInShadowTree(shadowRoot, child.get());
    791 }
    792 
    793 void SVGUseElement::expandSymbolElementsInShadowTree(SVGShadowTreeRootElement* shadowRoot, Node* element)
    794 {
    795     if (element->hasTagName(SVGNames::symbolTag)) {
    796         // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
    797         // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
    798         // always have explicit values for attributes width and height. If attributes width and/or
    799         // height are provided on the 'use' element, then these attributes will be transferred to
    800         // the generated 'svg'. If attributes width and/or height are not specified, the generated
    801         // 'svg' element will use values of 100% for these attributes.
    802         RefPtr<SVGSVGElement> svgElement = new SVGSVGElement(SVGNames::svgTag, document());
    803 
    804         // Transfer all attributes from <symbol> to the new <svg> element
    805         svgElement->attributes()->setAttributes(*element->attributes());
    806 
    807         // Only clone symbol children, and add them to the new <svg> element
    808         ExceptionCode ec = 0;
    809         for (Node* child = element->firstChild(); child; child = child->nextSibling()) {
    810             RefPtr<Node> newChild = child->cloneNode(true);
    811             svgElement->appendChild(newChild.release(), ec);
    812             ASSERT(!ec);
    813         }
    814 
    815         // We don't walk the target tree element-by-element, and clone each element,
    816         // but instead use cloneNode(deep=true). This is an optimization for the common
    817         // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
    818         // Though if there are disallowed elements in the subtree, we have to remove them.
    819         // For instance: <use> on <g> containing <foreignObject> (indirect case).
    820         if (subtreeContainsDisallowedElement(svgElement.get()))
    821             removeDisallowedElementsFromSubtree(svgElement.get());
    822 
    823         // Replace <symbol> with <svg>.
    824         ASSERT(element->parentNode());
    825         element->parentNode()->replaceChild(svgElement.release(), element, ec);
    826         ASSERT(!ec);
    827 
    828         // Immediately stop here, and restart expanding.
    829         expandSymbolElementsInShadowTree(shadowRoot, shadowRoot);
    830         return;
    831     }
    832 
    833     for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
    834         expandSymbolElementsInShadowTree(shadowRoot, child.get());
    835 }
    836 
    837 #endif
    838 
    839 void SVGUseElement::transferEventListenersToShadowTree(SVGElementInstance* target)
    840 {
    841     if (!target)
    842         return;
    843 
    844     SVGElement* originalElement = target->correspondingElement();
    845     ASSERT(originalElement);
    846 
    847     if (SVGElement* shadowTreeElement = target->shadowTreeElement()) {
    848         if (EventTargetData* d = originalElement->eventTargetData()) {
    849             EventListenerMap& map = d->eventListenerMap;
    850             EventListenerMap::iterator end = map.end();
    851             for (EventListenerMap::iterator it = map.begin(); it != end; ++it) {
    852                 EventListenerVector& entry = *it->second;
    853                 for (size_t i = 0; i < entry.size(); ++i) {
    854                     // Event listeners created from markup have already been transfered to the shadow tree during cloning.
    855                     if (entry[i].listener->wasCreatedFromMarkup())
    856                         continue;
    857                     shadowTreeElement->addEventListener(it->first, entry[i].listener, entry[i].useCapture);
    858                 }
    859             }
    860         }
    861     }
    862 
    863     for (SVGElementInstance* instance = target->firstChild(); instance; instance = instance->nextSibling())
    864         transferEventListenersToShadowTree(instance);
    865 }
    866 
    867 void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance)
    868 {
    869     if (!target || !targetInstance)
    870         return;
    871 
    872     SVGElement* originalElement = targetInstance->correspondingElement();
    873 
    874     if (originalElement->hasTagName(SVGNames::useTag)) {
    875 #if ENABLE(SVG) && ENABLE(SVG_USE)
    876         // <use> gets replaced by <g>
    877         ASSERT(target->nodeName() == SVGNames::gTag);
    878 #else
    879         ASSERT(target->nodeName() == SVGNames::gTag || target->nodeName() == SVGNames::useTag);
    880 #endif
    881     } else if (originalElement->hasTagName(SVGNames::symbolTag)) {
    882         // <symbol> gets replaced by <svg>
    883 #if ENABLE(SVG) && ENABLE(SVG_USE) && ENABLE(SVG_FOREIGN_OBJECT)
    884         ASSERT(target->nodeName() == SVGNames::svgTag);
    885 #endif
    886     } else
    887         ASSERT(target->nodeName() == originalElement->nodeName());
    888 
    889     SVGElement* element = 0;
    890     if (target->isSVGElement())
    891         element = static_cast<SVGElement*>(target);
    892 
    893     ASSERT(!targetInstance->shadowTreeElement());
    894     targetInstance->setShadowTreeElement(element);
    895 
    896     Node* node = target->firstChild();
    897     for (SVGElementInstance* instance = targetInstance->firstChild(); node && instance; instance = instance->nextSibling()) {
    898         // Skip any non-svg elements in shadow tree
    899         while (node && !node->isSVGElement())
    900            node = node->nextSibling();
    901 
    902         associateInstancesWithShadowTreeElements(node, instance);
    903         node = node->nextSibling();
    904     }
    905 }
    906 
    907 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element) const
    908 {
    909     if (!m_targetElementInstance) {
    910         ASSERT(!inDocument());
    911         return 0;
    912     }
    913 
    914     return instanceForShadowTreeElement(element, m_targetElementInstance.get());
    915 }
    916 
    917 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element, SVGElementInstance* instance) const
    918 {
    919     ASSERT(element);
    920     ASSERT(instance);
    921 
    922     // We're dispatching a mutation event during shadow tree construction
    923     // this instance hasn't yet been associated to a shadowTree element.
    924     if (!instance->shadowTreeElement())
    925         return 0;
    926 
    927     if (element == instance->shadowTreeElement())
    928         return instance;
    929 
    930     for (SVGElementInstance* current = instance->firstChild(); current; current = current->nextSibling()) {
    931         if (SVGElementInstance* search = instanceForShadowTreeElement(element, current))
    932             return search;
    933     }
    934 
    935     return 0;
    936 }
    937 
    938 void SVGUseElement::invalidateShadowTree()
    939 {
    940     m_needsShadowTreeRecreation = true;
    941     setNeedsStyleRecalc();
    942 }
    943 
    944 void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement* from, SVGElement* to) const
    945 {
    946     ASSERT(from);
    947     ASSERT(to);
    948 
    949     to->attributes()->setAttributes(*from->attributes());
    950 
    951     ExceptionCode ec = 0;
    952 
    953     to->removeAttribute(SVGNames::xAttr, ec);
    954     ASSERT(!ec);
    955 
    956     to->removeAttribute(SVGNames::yAttr, ec);
    957     ASSERT(!ec);
    958 
    959     to->removeAttribute(SVGNames::widthAttr, ec);
    960     ASSERT(!ec);
    961 
    962     to->removeAttribute(SVGNames::heightAttr, ec);
    963     ASSERT(!ec);
    964 
    965     to->removeAttribute(XLinkNames::hrefAttr, ec);
    966     ASSERT(!ec);
    967 }
    968 
    969 bool SVGUseElement::hasRelativeValues() const
    970 {
    971     return x().isRelative() || y().isRelative() || width().isRelative() || height().isRelative();
    972 }
    973 
    974 }
    975 
    976 #endif // ENABLE(SVG)
    977