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  * Copyright (C) 2012 University of Szeged
      7  * Copyright (C) 2012 Renata Hodovan <reni (at) webkit.org>
      8  *
      9  * This library is free software; you can redistribute it and/or
     10  * modify it under the terms of the GNU Library General Public
     11  * License as published by the Free Software Foundation; either
     12  * version 2 of the License, or (at your option) any later version.
     13  *
     14  * This library is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  * Library General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU Library General Public License
     20  * along with this library; see the file COPYING.LIB.  If not, write to
     21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     22  * Boston, MA 02110-1301, USA.
     23  */
     24 
     25 #include "config.h"
     26 
     27 #include "core/svg/SVGUseElement.h"
     28 
     29 #include "SVGNames.h"
     30 #include "XLinkNames.h"
     31 #include "bindings/v8/ExceptionStatePlaceholder.h"
     32 #include "core/dom/Document.h"
     33 #include "core/dom/Event.h"
     34 #include "core/dom/NodeTraversal.h"
     35 #include "core/dom/shadow/ElementShadow.h"
     36 #include "core/dom/shadow/ShadowRoot.h"
     37 #include "core/loader/cache/DocumentResource.h"
     38 #include "core/loader/cache/FetchRequest.h"
     39 #include "core/loader/cache/ResourceFetcher.h"
     40 #include "core/rendering/svg/RenderSVGResource.h"
     41 #include "core/rendering/svg/RenderSVGTransformableContainer.h"
     42 #include "core/svg/SVGElementInstance.h"
     43 #include "core/svg/SVGGElement.h"
     44 #include "core/svg/SVGLengthContext.h"
     45 #include "core/svg/SVGSVGElement.h"
     46 #include "core/xml/parser/XMLDocumentParser.h"
     47 
     48 // Dump SVGElementInstance object tree - useful to debug instanceRoot problems
     49 // #define DUMP_INSTANCE_TREE
     50 
     51 // Dump the deep-expanded shadow tree (where the renderers are built from)
     52 // #define DUMP_SHADOW_TREE
     53 
     54 namespace WebCore {
     55 
     56 // Animated property definitions
     57 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::xAttr, X, x)
     58 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::yAttr, Y, y)
     59 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::widthAttr, Width, width)
     60 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::heightAttr, Height, height)
     61 DEFINE_ANIMATED_STRING(SVGUseElement, XLinkNames::hrefAttr, Href, href)
     62 DEFINE_ANIMATED_BOOLEAN(SVGUseElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
     63 
     64 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGUseElement)
     65     REGISTER_LOCAL_ANIMATED_PROPERTY(x)
     66     REGISTER_LOCAL_ANIMATED_PROPERTY(y)
     67     REGISTER_LOCAL_ANIMATED_PROPERTY(width)
     68     REGISTER_LOCAL_ANIMATED_PROPERTY(height)
     69     REGISTER_LOCAL_ANIMATED_PROPERTY(href)
     70     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
     71     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement)
     72 END_REGISTER_ANIMATED_PROPERTIES
     73 
     74 inline SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document* document, bool wasInsertedByParser)
     75     : SVGGraphicsElement(tagName, document)
     76     , m_x(LengthModeWidth)
     77     , m_y(LengthModeHeight)
     78     , m_width(LengthModeWidth)
     79     , m_height(LengthModeHeight)
     80     , m_wasInsertedByParser(wasInsertedByParser)
     81     , m_haveFiredLoadEvent(false)
     82     , m_needsShadowTreeRecreation(false)
     83     , m_svgLoadEventTimer(this, &SVGElement::svgLoadEventTimerFired)
     84 {
     85     ASSERT(hasCustomStyleCallbacks());
     86     ASSERT(hasTagName(SVGNames::useTag));
     87     ScriptWrappable::init(this);
     88     registerAnimatedPropertiesForSVGUseElement();
     89 }
     90 
     91 PassRefPtr<SVGUseElement> SVGUseElement::create(const QualifiedName& tagName, Document* document, bool wasInsertedByParser)
     92 {
     93     // Always build a #shadow-root for SVGUseElement.
     94     RefPtr<SVGUseElement> use = adoptRef(new SVGUseElement(tagName, document, wasInsertedByParser));
     95     use->ensureUserAgentShadowRoot();
     96     return use.release();
     97 }
     98 
     99 SVGUseElement::~SVGUseElement()
    100 {
    101     setDocumentResource(0);
    102 
    103     clearResourceReferences();
    104 }
    105 
    106 SVGElementInstance* SVGUseElement::instanceRoot()
    107 {
    108     // If there is no element instance tree, force immediate SVGElementInstance tree
    109     // creation by asking the document to invoke our recalcStyle function - as we can't
    110     // wait for the lazy creation to happen if e.g. JS wants to access the instanceRoot
    111     // object right after creating the element on-the-fly
    112     if (!m_targetElementInstance)
    113         document()->updateStyleIfNeeded();
    114 
    115     return m_targetElementInstance.get();
    116 }
    117 
    118 SVGElementInstance* SVGUseElement::animatedInstanceRoot() const
    119 {
    120     // FIXME: Implement me.
    121     return 0;
    122 }
    123 
    124 bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName)
    125 {
    126     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
    127     if (supportedAttributes.isEmpty()) {
    128         SVGLangSpace::addSupportedAttributes(supportedAttributes);
    129         SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
    130         SVGURIReference::addSupportedAttributes(supportedAttributes);
    131         supportedAttributes.add(SVGNames::xAttr);
    132         supportedAttributes.add(SVGNames::yAttr);
    133         supportedAttributes.add(SVGNames::widthAttr);
    134         supportedAttributes.add(SVGNames::heightAttr);
    135     }
    136     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
    137 }
    138 
    139 void SVGUseElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    140 {
    141     SVGParsingError parseError = NoError;
    142 
    143     if (!isSupportedAttribute(name))
    144         SVGGraphicsElement::parseAttribute(name, value);
    145     else if (name == SVGNames::xAttr)
    146         setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
    147     else if (name == SVGNames::yAttr)
    148         setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
    149     else if (name == SVGNames::widthAttr)
    150         setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError, ForbidNegativeLengths));
    151     else if (name == SVGNames::heightAttr)
    152         setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths));
    153     else if (SVGLangSpace::parseAttribute(name, value)
    154              || SVGExternalResourcesRequired::parseAttribute(name, value)
    155              || SVGURIReference::parseAttribute(name, value)) {
    156     } else
    157         ASSERT_NOT_REACHED();
    158 
    159     reportAttributeParsingError(parseError, name, value);
    160 }
    161 
    162 static inline bool isWellFormedDocument(Document* document)
    163 {
    164     if (document->isSVGDocument() || document->isXHTMLDocument())
    165         return static_cast<XMLDocumentParser*>(document->parser())->wellFormed();
    166     return true;
    167 }
    168 
    169 Node::InsertionNotificationRequest SVGUseElement::insertedInto(ContainerNode* rootParent)
    170 {
    171     // This functions exists to assure assumptions made in the code regarding SVGElementInstance creation/destruction are satisfied.
    172     SVGGraphicsElement::insertedInto(rootParent);
    173     if (!rootParent->inDocument())
    174         return InsertionDone;
    175     ASSERT(!m_targetElementInstance || !isWellFormedDocument(document()));
    176     ASSERT(!hasPendingResources() || !isWellFormedDocument(document()));
    177     if (!m_wasInsertedByParser)
    178         buildPendingResource();
    179     SVGExternalResourcesRequired::insertedIntoDocument(this);
    180     return InsertionDone;
    181 }
    182 
    183 void SVGUseElement::removedFrom(ContainerNode* rootParent)
    184 {
    185     SVGGraphicsElement::removedFrom(rootParent);
    186     if (rootParent->inDocument())
    187         clearResourceReferences();
    188 }
    189 
    190 Document* SVGUseElement::referencedDocument() const
    191 {
    192     if (!isExternalURIReference(hrefCurrentValue(), document()))
    193         return document();
    194     return externalDocument();
    195 }
    196 
    197 Document* SVGUseElement::externalDocument() const
    198 {
    199     if (m_resource && m_resource->isLoaded()) {
    200         // Gracefully handle error condition.
    201         if (m_resource->errorOccurred())
    202             return 0;
    203         ASSERT(m_resource->document());
    204         return m_resource->document();
    205     }
    206     return 0;
    207 }
    208 
    209 void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
    210 {
    211     if (!isSupportedAttribute(attrName)) {
    212         SVGGraphicsElement::svgAttributeChanged(attrName);
    213         return;
    214     }
    215 
    216     SVGElementInstance::InvalidationGuard invalidationGuard(this);
    217 
    218     RenderObject* renderer = this->renderer();
    219     if (attrName == SVGNames::xAttr
    220         || attrName == SVGNames::yAttr
    221         || attrName == SVGNames::widthAttr
    222         || attrName == SVGNames::heightAttr) {
    223         updateRelativeLengthsInformation();
    224         if (renderer)
    225             RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
    226         return;
    227     }
    228 
    229     if (SVGExternalResourcesRequired::handleAttributeChange(this, attrName))
    230         return;
    231 
    232     if (SVGURIReference::isKnownAttribute(attrName)) {
    233         bool isExternalReference = isExternalURIReference(hrefCurrentValue(), document());
    234         if (isExternalReference) {
    235             KURL url = document()->completeURL(hrefCurrentValue());
    236             if (url.hasFragmentIdentifier()) {
    237                 FetchRequest request(ResourceRequest(url.string()), localName());
    238                 setDocumentResource(document()->fetcher()->requestSVGDocument(request));
    239             }
    240         } else {
    241             setDocumentResource(0);
    242         }
    243 
    244         if (!m_wasInsertedByParser)
    245             buildPendingResource();
    246 
    247         return;
    248     }
    249 
    250     if (!renderer)
    251         return;
    252 
    253     if (SVGLangSpace::isKnownAttribute(attrName)
    254         || SVGExternalResourcesRequired::isKnownAttribute(attrName)) {
    255         invalidateShadowTree();
    256         return;
    257     }
    258 
    259     ASSERT_NOT_REACHED();
    260 }
    261 
    262 void SVGUseElement::willRecalcStyle(StyleChange)
    263 {
    264     if (!m_wasInsertedByParser && m_needsShadowTreeRecreation && renderer() && needsStyleRecalc())
    265         buildPendingResource();
    266 }
    267 
    268 #ifdef DUMP_INSTANCE_TREE
    269 static void dumpInstanceTree(unsigned int& depth, String& text, SVGElementInstance* targetInstance)
    270 {
    271     SVGElement* element = targetInstance->correspondingElement();
    272     ASSERT(element);
    273 
    274     if (element->hasTagName(SVGNames::useTag)) {
    275         if (toSVGUseElement(element)->resourceIsStillLoading())
    276             return;
    277     }
    278 
    279     SVGElement* shadowTreeElement = targetInstance->shadowTreeElement();
    280     ASSERT(shadowTreeElement);
    281 
    282     SVGUseElement* directUseElement = targetInstance->directUseElement();
    283     String directUseElementName = directUseElement ? directUseElement->nodeName() : "null";
    284 
    285     String elementId = element->getIdAttribute();
    286     String elementNodeName = element->nodeName();
    287     String shadowTreeElementNodeName = shadowTreeElement->nodeName();
    288     String parentNodeName = element->parentNode() ? element->parentNode()->nodeName() : "null";
    289     String firstChildNodeName = element->firstChild() ? element->firstChild()->nodeName() : "null";
    290 
    291     for (unsigned int i = 0; i < depth; ++i)
    292         text += "  ";
    293 
    294     text += String::format("SVGElementInstance this=%p, (parentNode=%s (%p), firstChild=%s (%p), correspondingElement=%s (%p), directUseElement=%s (%p), shadowTreeElement=%s (%p), id=%s)\n",
    295                            targetInstance, parentNodeName.latin1().data(), element->parentNode(), firstChildNodeName.latin1().data(), element->firstChild(),
    296                            elementNodeName.latin1().data(), element, directUseElementName.latin1().data(), directUseElement, shadowTreeElementNodeName.latin1().data(), shadowTreeElement, elementId.latin1().data());
    297 
    298     for (unsigned int i = 0; i < depth; ++i)
    299         text += "  ";
    300 
    301     const HashSet<SVGElementInstance*>& elementInstances = element->instancesForElement();
    302     text += "Corresponding element is associated with " + String::number(elementInstances.size()) + " instance(s):\n";
    303 
    304     const HashSet<SVGElementInstance*>::const_iterator end = elementInstances.end();
    305     for (HashSet<SVGElementInstance*>::const_iterator it = elementInstances.begin(); it != end; ++it) {
    306         for (unsigned int i = 0; i < depth; ++i)
    307             text += "  ";
    308 
    309         text += String::format(" -> SVGElementInstance this=%p, (refCount: %i, shadowTreeElement in document? %i)\n",
    310                                *it, (*it)->refCount(), (*it)->shadowTreeElement()->inDocument());
    311     }
    312 
    313     ++depth;
    314 
    315     for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
    316         dumpInstanceTree(depth, text, instance);
    317 
    318     --depth;
    319 }
    320 #endif
    321 
    322 static bool isDisallowedElement(Node* node)
    323 {
    324     // Spec: "Any 'svg', 'symbol', 'g', graphics element or other 'use' is potentially a template object that can be re-used
    325     // (i.e., "instanced") in the SVG document via a 'use' element."
    326     // "Graphics Element" is defined as 'circle', 'ellipse', 'image', 'line', 'path', 'polygon', 'polyline', 'rect', 'text'
    327     // Excluded are anything that is used by reference or that only make sense to appear once in a document.
    328     // We must also allow the shadow roots of other use elements.
    329     if (node->isShadowRoot() || node->isTextNode())
    330         return false;
    331 
    332     if (!node->isSVGElement())
    333         return true;
    334 
    335     Element* element = toElement(node);
    336 
    337     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, allowedElementTags, ());
    338     if (allowedElementTags.isEmpty()) {
    339         allowedElementTags.add(SVGNames::aTag);
    340         allowedElementTags.add(SVGNames::circleTag);
    341         allowedElementTags.add(SVGNames::descTag);
    342         allowedElementTags.add(SVGNames::ellipseTag);
    343         allowedElementTags.add(SVGNames::gTag);
    344         allowedElementTags.add(SVGNames::imageTag);
    345         allowedElementTags.add(SVGNames::lineTag);
    346         allowedElementTags.add(SVGNames::metadataTag);
    347         allowedElementTags.add(SVGNames::pathTag);
    348         allowedElementTags.add(SVGNames::polygonTag);
    349         allowedElementTags.add(SVGNames::polylineTag);
    350         allowedElementTags.add(SVGNames::rectTag);
    351         allowedElementTags.add(SVGNames::svgTag);
    352         allowedElementTags.add(SVGNames::switchTag);
    353         allowedElementTags.add(SVGNames::symbolTag);
    354         allowedElementTags.add(SVGNames::textTag);
    355         allowedElementTags.add(SVGNames::textPathTag);
    356         allowedElementTags.add(SVGNames::titleTag);
    357         allowedElementTags.add(SVGNames::trefTag);
    358         allowedElementTags.add(SVGNames::tspanTag);
    359         allowedElementTags.add(SVGNames::useTag);
    360     }
    361     return !allowedElementTags.contains<SVGAttributeHashTranslator>(element->tagQName());
    362 }
    363 
    364 static bool subtreeContainsDisallowedElement(Node* start)
    365 {
    366     if (isDisallowedElement(start))
    367         return true;
    368 
    369     for (Node* cur = start->firstChild(); cur; cur = cur->nextSibling()) {
    370         if (subtreeContainsDisallowedElement(cur))
    371             return true;
    372     }
    373 
    374     return false;
    375 }
    376 
    377 void SVGUseElement::clearResourceReferences()
    378 {
    379     // FIXME: We should try to optimize this, to at least allow partial reclones.
    380     if (ShadowRoot* shadowTreeRootElement = userAgentShadowRoot())
    381         shadowTreeRootElement->removeChildren();
    382 
    383     if (m_targetElementInstance) {
    384         m_targetElementInstance->detach();
    385         m_targetElementInstance = 0;
    386     }
    387 
    388     m_needsShadowTreeRecreation = false;
    389 
    390     ASSERT(document());
    391     document()->accessSVGExtensions()->removeAllTargetReferencesForElement(this);
    392 }
    393 
    394 void SVGUseElement::buildPendingResource()
    395 {
    396     if (!referencedDocument() || isInShadowTree())
    397         return;
    398     clearResourceReferences();
    399     if (!inDocument())
    400         return;
    401 
    402     String id;
    403     Element* target = SVGURIReference::targetElementFromIRIString(hrefCurrentValue(), document(), &id, externalDocument());
    404     if (!target || !target->inDocument()) {
    405         // If we can't find the target of an external element, just give up.
    406         // We can't observe if the target somewhen enters the external document, nor should we do it.
    407         if (externalDocument())
    408             return;
    409         if (id.isEmpty())
    410             return;
    411 
    412         referencedDocument()->accessSVGExtensions()->addPendingResource(id, this);
    413         ASSERT(hasPendingResources());
    414         return;
    415     }
    416 
    417     if (target->isSVGElement()) {
    418         buildShadowAndInstanceTree(toSVGElement(target));
    419         invalidateDependentShadowTrees();
    420     }
    421 
    422     ASSERT(!m_needsShadowTreeRecreation);
    423 }
    424 
    425 void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target)
    426 {
    427     ASSERT(!m_targetElementInstance);
    428 
    429     // Do not build the shadow/instance tree for <use> elements living in a shadow tree.
    430     // The will be expanded soon anyway - see expandUseElementsInShadowTree().
    431     if (isInShadowTree())
    432         return;
    433 
    434     // Do not allow self-referencing.
    435     // 'target' may be null, if it's a non SVG namespaced element.
    436     if (!target || target == this)
    437         return;
    438 
    439     // Why a seperated instance/shadow tree? SVG demands it:
    440     // The instance tree is accesable from JavaScript, and has to
    441     // expose a 1:1 copy of the referenced tree, whereas internally we need
    442     // to alter the tree for correct "use-on-symbol", "use-on-svg" support.
    443 
    444     // Build instance tree. Create root SVGElementInstance object for the first sub-tree node.
    445     //
    446     // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a
    447     // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object
    448     // is the SVGRectElement that corresponds to the referenced 'rect' element.
    449     m_targetElementInstance = SVGElementInstance::create(this, this, target);
    450 
    451     // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
    452     bool foundProblem = false;
    453     buildInstanceTree(target, m_targetElementInstance.get(), foundProblem, false);
    454 
    455     if (instanceTreeIsLoading(m_targetElementInstance.get()))
    456         return;
    457 
    458     // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it!
    459     // Non-appearing <use> content is easier to debug, then half-appearing content.
    460     if (foundProblem) {
    461         clearResourceReferences();
    462         return;
    463     }
    464 
    465     // Assure instance tree building was successfull
    466     ASSERT(m_targetElementInstance);
    467     ASSERT(!m_targetElementInstance->shadowTreeElement());
    468     ASSERT(m_targetElementInstance->correspondingUseElement() == this);
    469     ASSERT(m_targetElementInstance->directUseElement() == this);
    470     ASSERT(m_targetElementInstance->correspondingElement() == target);
    471 
    472     ShadowRoot* shadowTreeRootElement = userAgentShadowRoot();
    473     ASSERT(shadowTreeRootElement);
    474 
    475     // Build shadow tree from instance tree
    476     // This also handles the special cases: <use> on <symbol>, <use> on <svg>.
    477     buildShadowTree(target, m_targetElementInstance.get());
    478 
    479     // Expand all <use> elements in the shadow tree.
    480     // Expand means: replace the actual <use> element by what it references.
    481     expandUseElementsInShadowTree(shadowTreeRootElement);
    482 
    483     // Expand all <symbol> elements in the shadow tree.
    484     // Expand means: replace the actual <symbol> element by the <svg> element.
    485     expandSymbolElementsInShadowTree(shadowTreeRootElement);
    486 
    487     // Now that the shadow tree is completly expanded, we can associate
    488     // shadow tree elements <-> instances in the instance tree.
    489     associateInstancesWithShadowTreeElements(shadowTreeRootElement->firstChild(), m_targetElementInstance.get());
    490 
    491     // If no shadow tree element is present, this means that the reference root
    492     // element was removed, as it is disallowed (ie. <use> on <foreignObject>)
    493     // Do NOT leave an inconsistent instance tree around, instead destruct it.
    494     if (!m_targetElementInstance->shadowTreeElement()) {
    495         clearResourceReferences();
    496         return;
    497     }
    498 
    499     ASSERT(m_targetElementInstance->shadowTreeElement()->parentNode() == shadowTreeRootElement);
    500 
    501     // Transfer event listeners assigned to the referenced element to our shadow tree elements.
    502     transferEventListenersToShadowTree(m_targetElementInstance.get());
    503 
    504     // Update relative length information.
    505     updateRelativeLengthsInformation();
    506 
    507     // Eventually dump instance tree
    508 #ifdef DUMP_INSTANCE_TREE
    509     String text;
    510     unsigned int depth = 0;
    511 
    512     dumpInstanceTree(depth, text, m_targetElementInstance.get());
    513     fprintf(stderr, "\nDumping <use> instance tree:\n%s\n", text.latin1().data());
    514 #endif
    515 
    516     // Eventually dump shadow tree
    517 #ifdef DUMP_SHADOW_TREE
    518     RefPtr<XMLSerializer> serializer = XMLSerializer::create();
    519     String markup = serializer->serializeToString(shadowTreeRootElement, ASSERT_NO_EXCEPTION);
    520     fprintf(stderr, "Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data());
    521 #endif
    522 }
    523 
    524 RenderObject* SVGUseElement::createRenderer(RenderStyle*)
    525 {
    526     return new RenderSVGTransformableContainer(this);
    527 }
    528 
    529 static bool isDirectReference(const Node* node)
    530 {
    531     return node->hasTagName(SVGNames::pathTag)
    532            || node->hasTagName(SVGNames::rectTag)
    533            || node->hasTagName(SVGNames::circleTag)
    534            || node->hasTagName(SVGNames::ellipseTag)
    535            || node->hasTagName(SVGNames::polygonTag)
    536            || node->hasTagName(SVGNames::polylineTag)
    537            || node->hasTagName(SVGNames::textTag);
    538 }
    539 
    540 void SVGUseElement::toClipPath(Path& path)
    541 {
    542     ASSERT(path.isEmpty());
    543 
    544     Node* n = m_targetElementInstance ? m_targetElementInstance->shadowTreeElement() : 0;
    545     if (!n)
    546         return;
    547 
    548     if (n->isSVGElement() && toSVGElement(n)->isSVGGraphicsElement()) {
    549         if (!isDirectReference(n))
    550             // Spec: Indirect references are an error (14.3.5)
    551             document()->accessSVGExtensions()->reportError("Not allowed to use indirect reference in <clip-path>");
    552         else {
    553             toSVGGraphicsElement(n)->toClipPath(path);
    554             // FIXME: Avoid manual resolution of x/y here. Its potentially harmful.
    555             SVGLengthContext lengthContext(this);
    556             path.translate(FloatSize(xCurrentValue().value(lengthContext), yCurrentValue().value(lengthContext)));
    557             path.transform(animatedLocalTransform());
    558         }
    559     }
    560 }
    561 
    562 RenderObject* SVGUseElement::rendererClipChild() const
    563 {
    564     Node* n = m_targetElementInstance ? m_targetElementInstance->shadowTreeElement() : 0;
    565     if (!n)
    566         return 0;
    567 
    568     if (n->isSVGElement() && isDirectReference(n))
    569         return toSVGElement(n)->renderer();
    570 
    571     return 0;
    572 }
    573 
    574 void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* targetInstance, bool& foundProblem, bool foundUse)
    575 {
    576     ASSERT(target);
    577     ASSERT(targetInstance);
    578 
    579     // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
    580     // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
    581     bool targetHasUseTag = target->hasTagName(SVGNames::useTag);
    582     SVGElement* newTarget = 0;
    583     if (targetHasUseTag) {
    584         foundProblem = hasCycleUseReferencing(toSVGUseElement(target), targetInstance, newTarget);
    585         if (foundProblem)
    586             return;
    587 
    588         // We only need to track first degree <use> dependencies. Indirect references are handled
    589         // as the invalidation bubbles up the dependency chain.
    590         if (!foundUse) {
    591             ASSERT(document());
    592             document()->accessSVGExtensions()->addElementReferencingTarget(this, target);
    593             foundUse = true;
    594         }
    595     } else if (isDisallowedElement(target)) {
    596         foundProblem = true;
    597         return;
    598     }
    599 
    600     // A general description from the SVG spec, describing what buildInstanceTree() actually does.
    601     //
    602     // Spec: If the 'use' element references a 'g' which contains two 'rect' elements, then the instance tree
    603     // contains three SVGElementInstance objects, a root SVGElementInstance object whose correspondingElement
    604     // is the SVGGElement object for the 'g', and then two child SVGElementInstance objects, each of which has
    605     // its correspondingElement that is an SVGRectElement object.
    606 
    607     for (Node* node = target->firstChild(); node; node = node->nextSibling()) {
    608         SVGElement* element = 0;
    609         if (node->isSVGElement())
    610             element = toSVGElement(node);
    611 
    612         // Skip any non-svg nodes or any disallowed element.
    613         if (!element || isDisallowedElement(element))
    614             continue;
    615 
    616         // Create SVGElementInstance object, for both container/non-container nodes.
    617         RefPtr<SVGElementInstance> instance = SVGElementInstance::create(this, 0, element);
    618         SVGElementInstance* instancePtr = instance.get();
    619         targetInstance->appendChild(instance.release());
    620 
    621         // Enter recursion, appending new instance tree nodes to the "instance" object.
    622         buildInstanceTree(element, instancePtr, foundProblem, foundUse);
    623         if (foundProblem)
    624             return;
    625     }
    626 
    627     if (!targetHasUseTag || !newTarget)
    628         return;
    629 
    630     RefPtr<SVGElementInstance> newInstance = SVGElementInstance::create(this, toSVGUseElement(target), newTarget);
    631     SVGElementInstance* newInstancePtr = newInstance.get();
    632     targetInstance->appendChild(newInstance.release());
    633     buildInstanceTree(newTarget, newInstancePtr, foundProblem, foundUse);
    634 }
    635 
    636 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, SVGElementInstance* targetInstance, SVGElement*& newTarget)
    637 {
    638     Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefCurrentValue(), referencedDocument());
    639     newTarget = 0;
    640     if (targetElement && targetElement->isSVGElement())
    641         newTarget = toSVGElement(targetElement);
    642 
    643     if (!newTarget)
    644         return false;
    645 
    646     // Shortcut for self-references
    647     if (newTarget == this)
    648         return true;
    649 
    650     AtomicString targetId = newTarget->getIdAttribute();
    651     SVGElementInstance* instance = targetInstance->parentNode();
    652     while (instance) {
    653         SVGElement* element = instance->correspondingElement();
    654 
    655         if (element->hasID() && element->getIdAttribute() == targetId && element->document() == newTarget->document())
    656             return true;
    657 
    658         instance = instance->parentNode();
    659     }
    660     return false;
    661 }
    662 
    663 static inline void removeDisallowedElementsFromSubtree(Element* subtree)
    664 {
    665     ASSERT(!subtree->inDocument());
    666     Element* element = ElementTraversal::firstWithin(subtree);
    667     while (element) {
    668         if (isDisallowedElement(element)) {
    669             Element* next = ElementTraversal::nextSkippingChildren(element, subtree);
    670             // The subtree is not in document so this won't generate events that could mutate the tree.
    671             element->parentNode()->removeChild(element);
    672             element = next;
    673         } else
    674             element = ElementTraversal::next(element, subtree);
    675     }
    676 }
    677 
    678 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance)
    679 {
    680     // For instance <use> on <foreignObject> (direct case).
    681     if (isDisallowedElement(target))
    682         return;
    683 
    684     RefPtr<Element> newChild = targetInstance->correspondingElement()->cloneElementWithChildren();
    685 
    686     // We don't walk the target tree element-by-element, and clone each element,
    687     // but instead use cloneElementWithChildren(). This is an optimization for the common
    688     // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
    689     // Though if there are disallowed elements in the subtree, we have to remove them.
    690     // For instance: <use> on <g> containing <foreignObject> (indirect case).
    691     if (subtreeContainsDisallowedElement(newChild.get()))
    692         removeDisallowedElementsFromSubtree(newChild.get());
    693 
    694     userAgentShadowRoot()->appendChild(newChild.release());
    695 }
    696 
    697 void SVGUseElement::expandUseElementsInShadowTree(Node* element)
    698 {
    699     // Why expand the <use> elements in the shadow tree here, and not just
    700     // do this directly in buildShadowTree, if we encounter a <use> element?
    701     //
    702     // Short answer: Because we may miss to expand some elements. Ie. if a <symbol>
    703     // contains <use> tags, we'd miss them. So once we're done with settin' up the
    704     // actual shadow tree (after the special case modification for svg/symbol) we have
    705     // to walk it completely and expand all <use> elements.
    706     if (element->hasTagName(SVGNames::useTag)) {
    707         SVGUseElement* use = toSVGUseElement(element);
    708         ASSERT(!use->resourceIsStillLoading());
    709 
    710         Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefCurrentValue(), referencedDocument());
    711         SVGElement* target = 0;
    712         if (targetElement && targetElement->isSVGElement())
    713             target = toSVGElement(targetElement);
    714 
    715         // Don't ASSERT(target) here, it may be "pending", too.
    716         // Setup sub-shadow tree root node
    717         RefPtr<SVGGElement> cloneParent = SVGGElement::create(SVGNames::gTag, referencedDocument());
    718         use->cloneChildNodes(cloneParent.get());
    719 
    720         // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
    721         // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
    722         transferUseAttributesToReplacedElement(use, cloneParent.get());
    723 
    724         if (target && !isDisallowedElement(target)) {
    725             RefPtr<Element> newChild = target->cloneElementWithChildren();
    726             ASSERT(newChild->isSVGElement());
    727             cloneParent->appendChild(newChild.release());
    728         }
    729 
    730         // We don't walk the target tree element-by-element, and clone each element,
    731         // but instead use cloneElementWithChildren(). This is an optimization for the common
    732         // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
    733         // Though if there are disallowed elements in the subtree, we have to remove them.
    734         // For instance: <use> on <g> containing <foreignObject> (indirect case).
    735         if (subtreeContainsDisallowedElement(cloneParent.get()))
    736             removeDisallowedElementsFromSubtree(cloneParent.get());
    737 
    738         RefPtr<Node> replacingElement(cloneParent.get());
    739 
    740         // Replace <use> with referenced content.
    741         ASSERT(use->parentNode());
    742         use->parentNode()->replaceChild(cloneParent.release(), use);
    743 
    744         // Expand the siblings because the *element* is replaced and we will
    745         // lose the sibling chain when we are back from recursion.
    746         element = replacingElement.get();
    747         for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = sibling->nextSibling())
    748             expandUseElementsInShadowTree(sibling.get());
    749     }
    750 
    751     for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
    752         expandUseElementsInShadowTree(child.get());
    753 }
    754 
    755 void SVGUseElement::expandSymbolElementsInShadowTree(Node* element)
    756 {
    757     if (element->hasTagName(SVGNames::symbolTag)) {
    758         // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
    759         // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
    760         // always have explicit values for attributes width and height. If attributes width and/or
    761         // height are provided on the 'use' element, then these attributes will be transferred to
    762         // the generated 'svg'. If attributes width and/or height are not specified, the generated
    763         // 'svg' element will use values of 100% for these attributes.
    764         RefPtr<SVGSVGElement> svgElement = SVGSVGElement::create(SVGNames::svgTag, referencedDocument());
    765 
    766         // Transfer all data (attributes, etc.) from <symbol> to the new <svg> element.
    767         svgElement->cloneDataFromElement(*toElement(element));
    768 
    769         // Only clone symbol children, and add them to the new <svg> element
    770         for (Node* child = element->firstChild(); child; child = child->nextSibling()) {
    771             RefPtr<Node> newChild = child->cloneNode(true);
    772             svgElement->appendChild(newChild.release());
    773         }
    774 
    775         // We don't walk the target tree element-by-element, and clone each element,
    776         // but instead use cloneNode(deep=true). This is an optimization for the common
    777         // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
    778         // Though if there are disallowed elements in the subtree, we have to remove them.
    779         // For instance: <use> on <g> containing <foreignObject> (indirect case).
    780         if (subtreeContainsDisallowedElement(svgElement.get()))
    781             removeDisallowedElementsFromSubtree(svgElement.get());
    782 
    783         RefPtr<Node> replacingElement(svgElement.get());
    784 
    785         // Replace <symbol> with <svg>.
    786         element->parentNode()->replaceChild(svgElement.release(), element);
    787 
    788         // Expand the siblings because the *element* is replaced and we will
    789         // lose the sibling chain when we are back from recursion.
    790         element = replacingElement.get();
    791         for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = sibling->nextSibling())
    792             expandSymbolElementsInShadowTree(sibling.get());
    793     }
    794 
    795     for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
    796         expandSymbolElementsInShadowTree(child.get());
    797 }
    798 
    799 void SVGUseElement::transferEventListenersToShadowTree(SVGElementInstance* target)
    800 {
    801     if (!target)
    802         return;
    803 
    804     SVGElement* originalElement = target->correspondingElement();
    805     ASSERT(originalElement);
    806 
    807     if (SVGElement* shadowTreeElement = target->shadowTreeElement()) {
    808         if (EventTargetData* data = originalElement->eventTargetData())
    809             data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(shadowTreeElement);
    810     }
    811 
    812     for (SVGElementInstance* instance = target->firstChild(); instance; instance = instance->nextSibling())
    813         transferEventListenersToShadowTree(instance);
    814 }
    815 
    816 void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance)
    817 {
    818     if (!target || !targetInstance)
    819         return;
    820 
    821     SVGElement* originalElement = targetInstance->correspondingElement();
    822 
    823     if (originalElement->hasTagName(SVGNames::useTag)) {
    824         // <use> gets replaced by <g>
    825         ASSERT(target->nodeName() == SVGNames::gTag);
    826     } else if (originalElement->hasTagName(SVGNames::symbolTag)) {
    827         // <symbol> gets replaced by <svg>
    828         ASSERT(target->nodeName() == SVGNames::svgTag);
    829     } else
    830         ASSERT(target->nodeName() == originalElement->nodeName());
    831 
    832     SVGElement* element = 0;
    833     if (target->isSVGElement())
    834         element = toSVGElement(target);
    835 
    836     ASSERT(!targetInstance->shadowTreeElement());
    837     targetInstance->setShadowTreeElement(element);
    838     element->setCorrespondingElement(originalElement);
    839 
    840     Node* node = target->firstChild();
    841     for (SVGElementInstance* instance = targetInstance->firstChild(); node && instance; instance = instance->nextSibling()) {
    842         // Skip any non-svg elements in shadow tree
    843         while (node && !node->isSVGElement())
    844            node = node->nextSibling();
    845 
    846         if (!node)
    847             break;
    848 
    849         associateInstancesWithShadowTreeElements(node, instance);
    850         node = node->nextSibling();
    851     }
    852 }
    853 
    854 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element) const
    855 {
    856     if (!m_targetElementInstance) {
    857         ASSERT(!inDocument());
    858         return 0;
    859     }
    860 
    861     return instanceForShadowTreeElement(element, m_targetElementInstance.get());
    862 }
    863 
    864 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element, SVGElementInstance* instance) const
    865 {
    866     ASSERT(element);
    867     ASSERT(instance);
    868 
    869     // We're dispatching a mutation event during shadow tree construction
    870     // this instance hasn't yet been associated to a shadowTree element.
    871     if (!instance->shadowTreeElement())
    872         return 0;
    873 
    874     if (element == instance->shadowTreeElement())
    875         return instance;
    876 
    877     for (SVGElementInstance* current = instance->firstChild(); current; current = current->nextSibling()) {
    878         if (SVGElementInstance* search = instanceForShadowTreeElement(element, current))
    879             return search;
    880     }
    881 
    882     return 0;
    883 }
    884 
    885 void SVGUseElement::invalidateShadowTree()
    886 {
    887     if (!renderer() || m_needsShadowTreeRecreation)
    888         return;
    889     m_needsShadowTreeRecreation = true;
    890     setNeedsStyleRecalc();
    891     invalidateDependentShadowTrees();
    892 }
    893 
    894 void SVGUseElement::invalidateDependentShadowTrees()
    895 {
    896     // Recursively invalidate dependent <use> shadow trees
    897     const HashSet<SVGElementInstance*>& instances = instancesForElement();
    898     const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
    899     for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
    900         if (SVGUseElement* element = (*it)->correspondingUseElement()) {
    901             ASSERT(element->inDocument());
    902             element->invalidateShadowTree();
    903         }
    904     }
    905 }
    906 
    907 void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement* from, SVGElement* to) const
    908 {
    909     ASSERT(from);
    910     ASSERT(to);
    911 
    912     to->cloneDataFromElement(*from);
    913 
    914     to->removeAttribute(SVGNames::xAttr);
    915     to->removeAttribute(SVGNames::yAttr);
    916     to->removeAttribute(SVGNames::widthAttr);
    917     to->removeAttribute(SVGNames::heightAttr);
    918     to->removeAttribute(XLinkNames::hrefAttr);
    919 }
    920 
    921 bool SVGUseElement::selfHasRelativeLengths() const
    922 {
    923     if (xCurrentValue().isRelative()
    924         || yCurrentValue().isRelative()
    925         || widthCurrentValue().isRelative()
    926         || heightCurrentValue().isRelative())
    927         return true;
    928 
    929     if (!m_targetElementInstance)
    930         return false;
    931 
    932     SVGElement* element = m_targetElementInstance->correspondingElement();
    933     if (!element)
    934         return false;
    935 
    936     return toSVGElement(element)->hasRelativeLengths();
    937 }
    938 
    939 void SVGUseElement::notifyFinished(Resource* resource)
    940 {
    941     if (!inDocument())
    942         return;
    943 
    944     invalidateShadowTree();
    945     if (resource->errorOccurred())
    946         dispatchEvent(Event::create(eventNames().errorEvent, false, false));
    947     else if (!resource->wasCanceled())
    948         SVGExternalResourcesRequired::dispatchLoadEvent(this);
    949 }
    950 
    951 bool SVGUseElement::resourceIsStillLoading()
    952 {
    953     if (m_resource && m_resource->isLoading())
    954         return true;
    955     return false;
    956 }
    957 
    958 bool SVGUseElement::instanceTreeIsLoading(SVGElementInstance* targetElementInstance)
    959 {
    960     for (SVGElementInstance* instance = targetElementInstance->firstChild(); instance; instance = instance->nextSibling()) {
    961         if (SVGUseElement* use = instance->correspondingUseElement()) {
    962             if (use->resourceIsStillLoading())
    963                 return true;
    964         }
    965         if (instance->hasChildNodes())
    966             instanceTreeIsLoading(instance);
    967     }
    968     return false;
    969 }
    970 
    971 void SVGUseElement::finishParsingChildren()
    972 {
    973     SVGGraphicsElement::finishParsingChildren();
    974     SVGExternalResourcesRequired::finishParsingChildren();
    975     if (m_wasInsertedByParser) {
    976         buildPendingResource();
    977         m_wasInsertedByParser = false;
    978     }
    979 }
    980 
    981 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource)
    982 {
    983     if (m_resource == resource)
    984         return;
    985 
    986     if (m_resource)
    987         m_resource->removeClient(this);
    988 
    989     m_resource = resource;
    990     if (m_resource)
    991         m_resource->addClient(this);
    992 }
    993 
    994 }
    995