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