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 "bindings/core/v8/ExceptionStatePlaceholder.h"
     30 #include "core/XLinkNames.h"
     31 #include "core/dom/Document.h"
     32 #include "core/dom/ElementTraversal.h"
     33 #include "core/events/Event.h"
     34 #include "core/dom/shadow/ElementShadow.h"
     35 #include "core/dom/shadow/ShadowRoot.h"
     36 #include "core/fetch/FetchRequest.h"
     37 #include "core/fetch/ResourceFetcher.h"
     38 #include "core/rendering/svg/RenderSVGResource.h"
     39 #include "core/rendering/svg/RenderSVGTransformableContainer.h"
     40 #include "core/svg/SVGGElement.h"
     41 #include "core/svg/SVGLengthContext.h"
     42 #include "core/svg/SVGSVGElement.h"
     43 #include "core/xml/parser/XMLDocumentParser.h"
     44 
     45 namespace blink {
     46 
     47 inline SVGUseElement::SVGUseElement(Document& document)
     48     : SVGGraphicsElement(SVGNames::useTag, document)
     49     , SVGURIReference(this)
     50     , m_x(SVGAnimatedLength::create(this, SVGNames::xAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths))
     51     , m_y(SVGAnimatedLength::create(this, SVGNames::yAttr, SVGLength::create(LengthModeHeight), AllowNegativeLengths))
     52     , m_width(SVGAnimatedLength::create(this, SVGNames::widthAttr, SVGLength::create(LengthModeWidth), ForbidNegativeLengths))
     53     , m_height(SVGAnimatedLength::create(this, SVGNames::heightAttr, SVGLength::create(LengthModeHeight), ForbidNegativeLengths))
     54     , m_haveFiredLoadEvent(false)
     55     , m_needsShadowTreeRecreation(false)
     56     , m_svgLoadEventTimer(this, &SVGElement::svgLoadEventTimerFired)
     57 {
     58     ASSERT(hasCustomStyleCallbacks());
     59 
     60     addToPropertyMap(m_x);
     61     addToPropertyMap(m_y);
     62     addToPropertyMap(m_width);
     63     addToPropertyMap(m_height);
     64 }
     65 
     66 PassRefPtrWillBeRawPtr<SVGUseElement> SVGUseElement::create(Document& document)
     67 {
     68     // Always build a user agent #shadow-root for SVGUseElement.
     69     RefPtrWillBeRawPtr<SVGUseElement> use = adoptRefWillBeNoop(new SVGUseElement(document));
     70     use->ensureUserAgentShadowRoot();
     71     return use.release();
     72 }
     73 
     74 SVGUseElement::~SVGUseElement()
     75 {
     76     setDocumentResource(0);
     77 #if !ENABLE(OILPAN)
     78     clearResourceReferences();
     79 #endif
     80 }
     81 
     82 bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName)
     83 {
     84     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
     85     if (supportedAttributes.isEmpty()) {
     86         SVGURIReference::addSupportedAttributes(supportedAttributes);
     87         supportedAttributes.add(SVGNames::xAttr);
     88         supportedAttributes.add(SVGNames::yAttr);
     89         supportedAttributes.add(SVGNames::widthAttr);
     90         supportedAttributes.add(SVGNames::heightAttr);
     91     }
     92     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
     93 }
     94 
     95 void SVGUseElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
     96 {
     97     parseAttributeNew(name, value);
     98 }
     99 
    100 #if ENABLE(ASSERT)
    101 static inline bool isWellFormedDocument(Document* document)
    102 {
    103     if (document->isXMLDocument())
    104         return static_cast<XMLDocumentParser*>(document->parser())->wellFormed();
    105     return true;
    106 }
    107 #endif
    108 
    109 Node::InsertionNotificationRequest SVGUseElement::insertedInto(ContainerNode* rootParent)
    110 {
    111     // This functions exists to assure assumptions made in the code regarding SVGElementInstance creation/destruction are satisfied.
    112     SVGGraphicsElement::insertedInto(rootParent);
    113     if (!rootParent->inDocument())
    114         return InsertionDone;
    115     ASSERT(!m_targetElementInstance || !isWellFormedDocument(&document()));
    116     ASSERT(!hasPendingResources() || !isWellFormedDocument(&document()));
    117     invalidateShadowTree();
    118     if (!isStructurallyExternal())
    119         sendSVGLoadEventIfPossibleAsynchronously();
    120     return InsertionDone;
    121 }
    122 
    123 void SVGUseElement::removedFrom(ContainerNode* rootParent)
    124 {
    125     SVGGraphicsElement::removedFrom(rootParent);
    126     if (rootParent->inDocument())
    127         clearResourceReferences();
    128 }
    129 
    130 TreeScope* SVGUseElement::referencedScope() const
    131 {
    132     if (!isExternalURIReference(hrefString(), document()))
    133         return &treeScope();
    134     return externalDocument();
    135 }
    136 
    137 Document* SVGUseElement::externalDocument() const
    138 {
    139     if (m_resource && m_resource->isLoaded()) {
    140         // Gracefully handle error condition.
    141         if (m_resource->errorOccurred())
    142             return 0;
    143         ASSERT(m_resource->document());
    144         return m_resource->document();
    145     }
    146     return 0;
    147 }
    148 
    149 void transferUseWidthAndHeightIfNeeded(const SVGUseElement& use, SVGElement* shadowElement, const SVGElement& originalElement)
    150 {
    151     DEFINE_STATIC_LOCAL(const AtomicString, hundredPercentString, ("100%", AtomicString::ConstructFromLiteral));
    152     ASSERT(shadowElement);
    153     if (isSVGSymbolElement(*shadowElement)) {
    154         // Spec (<use> on <symbol>): This generated 'svg' will always have explicit values for attributes width and height.
    155         // If attributes width and/or height are provided on the 'use' element, then these attributes
    156         // will be transferred to the generated 'svg'. If attributes width and/or height are not specified,
    157         // the generated 'svg' element will use values of 100% for these attributes.
    158         shadowElement->setAttribute(SVGNames::widthAttr, use.width()->isSpecified() ? AtomicString(use.width()->currentValue()->valueAsString()) : hundredPercentString);
    159         shadowElement->setAttribute(SVGNames::heightAttr, use.height()->isSpecified() ? AtomicString(use.height()->currentValue()->valueAsString()) : hundredPercentString);
    160     } else if (isSVGSVGElement(*shadowElement)) {
    161         // Spec (<use> on <svg>): If attributes width and/or height are provided on the 'use' element, then these
    162         // values will override the corresponding attributes on the 'svg' in the generated tree.
    163         if (use.width()->isSpecified())
    164             shadowElement->setAttribute(SVGNames::widthAttr, AtomicString(use.width()->currentValue()->valueAsString()));
    165         else
    166             shadowElement->setAttribute(SVGNames::widthAttr, originalElement.getAttribute(SVGNames::widthAttr));
    167         if (use.height()->isSpecified())
    168             shadowElement->setAttribute(SVGNames::heightAttr, AtomicString(use.height()->currentValue()->valueAsString()));
    169         else
    170             shadowElement->setAttribute(SVGNames::heightAttr, originalElement.getAttribute(SVGNames::heightAttr));
    171     }
    172 }
    173 
    174 void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
    175 {
    176     if (!isSupportedAttribute(attrName)) {
    177         SVGGraphicsElement::svgAttributeChanged(attrName);
    178         return;
    179     }
    180 
    181     SVGElement::InvalidationGuard invalidationGuard(this);
    182 
    183     RenderObject* renderer = this->renderer();
    184     if (attrName == SVGNames::xAttr
    185         || attrName == SVGNames::yAttr
    186         || attrName == SVGNames::widthAttr
    187         || attrName == SVGNames::heightAttr) {
    188         updateRelativeLengthsInformation();
    189         if (m_targetElementInstance) {
    190             ASSERT(m_targetElementInstance->correspondingElement());
    191             transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_targetElementInstance->correspondingElement());
    192         }
    193         if (renderer)
    194             RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
    195         return;
    196     }
    197 
    198     if (SVGURIReference::isKnownAttribute(attrName)) {
    199         bool isExternalReference = isExternalURIReference(hrefString(), document());
    200         if (isExternalReference) {
    201             KURL url = document().completeURL(hrefString());
    202             if (url.hasFragmentIdentifier()) {
    203                 FetchRequest request(ResourceRequest(url), localName());
    204                 setDocumentResource(document().fetcher()->fetchSVGDocument(request));
    205             }
    206         } else {
    207             setDocumentResource(0);
    208         }
    209 
    210         invalidateShadowTree();
    211 
    212         return;
    213     }
    214 
    215     if (!renderer)
    216         return;
    217 
    218     ASSERT_NOT_REACHED();
    219 }
    220 
    221 static bool isDisallowedElement(Node* node)
    222 {
    223     // Spec: "Any 'svg', 'symbol', 'g', graphics element or other 'use' is potentially a template object that can be re-used
    224     // (i.e., "instanced") in the SVG document via a 'use' element."
    225     // "Graphics Element" is defined as 'circle', 'ellipse', 'image', 'line', 'path', 'polygon', 'polyline', 'rect', 'text'
    226     // Excluded are anything that is used by reference or that only make sense to appear once in a document.
    227     // We must also allow the shadow roots of other use elements.
    228     if (node->isShadowRoot() || node->isTextNode())
    229         return false;
    230 
    231     if (!node->isSVGElement())
    232         return true;
    233 
    234     Element* element = toElement(node);
    235 
    236     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, allowedElementTags, ());
    237     if (allowedElementTags.isEmpty()) {
    238         allowedElementTags.add(SVGNames::aTag);
    239         allowedElementTags.add(SVGNames::circleTag);
    240         allowedElementTags.add(SVGNames::descTag);
    241         allowedElementTags.add(SVGNames::ellipseTag);
    242         allowedElementTags.add(SVGNames::gTag);
    243         allowedElementTags.add(SVGNames::imageTag);
    244         allowedElementTags.add(SVGNames::lineTag);
    245         allowedElementTags.add(SVGNames::metadataTag);
    246         allowedElementTags.add(SVGNames::pathTag);
    247         allowedElementTags.add(SVGNames::polygonTag);
    248         allowedElementTags.add(SVGNames::polylineTag);
    249         allowedElementTags.add(SVGNames::rectTag);
    250         allowedElementTags.add(SVGNames::svgTag);
    251         allowedElementTags.add(SVGNames::switchTag);
    252         allowedElementTags.add(SVGNames::symbolTag);
    253         allowedElementTags.add(SVGNames::textTag);
    254         allowedElementTags.add(SVGNames::textPathTag);
    255         allowedElementTags.add(SVGNames::titleTag);
    256         allowedElementTags.add(SVGNames::tspanTag);
    257         allowedElementTags.add(SVGNames::useTag);
    258     }
    259     return !allowedElementTags.contains<SVGAttributeHashTranslator>(element->tagQName());
    260 }
    261 
    262 static bool subtreeContainsDisallowedElement(Node* start)
    263 {
    264     if (isDisallowedElement(start))
    265         return true;
    266 
    267     for (Node* cur = start->firstChild(); cur; cur = cur->nextSibling()) {
    268         if (subtreeContainsDisallowedElement(cur))
    269             return true;
    270     }
    271 
    272     return false;
    273 }
    274 
    275 void SVGUseElement::scheduleShadowTreeRecreation()
    276 {
    277     if (!referencedScope() || inUseShadowTree())
    278         return;
    279     m_needsShadowTreeRecreation = true;
    280     document().scheduleUseShadowTreeUpdate(*this);
    281 }
    282 
    283 void SVGUseElement::clearResourceReferences()
    284 {
    285     if (m_targetElementInstance)
    286         m_targetElementInstance = nullptr;
    287 
    288     // FIXME: We should try to optimize this, to at least allow partial reclones.
    289     if (ShadowRoot* shadowTreeRootElement = userAgentShadowRoot())
    290         shadowTreeRootElement->removeChildren();
    291 
    292     m_needsShadowTreeRecreation = false;
    293     document().unscheduleUseShadowTreeUpdate(*this);
    294 
    295     removeAllOutgoingReferences();
    296 }
    297 
    298 void SVGUseElement::buildPendingResource()
    299 {
    300     if (!referencedScope() || inUseShadowTree())
    301         return;
    302     clearResourceReferences();
    303     if (!inDocument())
    304         return;
    305 
    306     AtomicString id;
    307     Element* target = SVGURIReference::targetElementFromIRIString(hrefString(), treeScope(), &id, externalDocument());
    308     if (!target || !target->inDocument()) {
    309         // If we can't find the target of an external element, just give up.
    310         // We can't observe if the target somewhen enters the external document, nor should we do it.
    311         if (externalDocument())
    312             return;
    313         if (id.isEmpty())
    314             return;
    315 
    316         referencedScope()->document().accessSVGExtensions().addPendingResource(id, this);
    317         ASSERT(hasPendingResources());
    318         return;
    319     }
    320 
    321     if (target->isSVGElement()) {
    322         buildShadowAndInstanceTree(toSVGElement(target));
    323         invalidateDependentShadowTrees();
    324     }
    325 
    326     ASSERT(!m_needsShadowTreeRecreation);
    327 }
    328 
    329 static PassRefPtrWillBeRawPtr<Node> cloneNodeAndAssociate(Node& toClone)
    330 {
    331     RefPtrWillBeRawPtr<Node> clone = toClone.cloneNode(false);
    332     if (!clone->isSVGElement())
    333         return clone.release();
    334 
    335     SVGElement& svgElement = toSVGElement(toClone);
    336     ASSERT(!svgElement.correspondingElement());
    337     toSVGElement(clone.get())->setCorrespondingElement(&svgElement);
    338     if (EventTargetData* data = toClone.eventTargetData())
    339         data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(clone.get());
    340     TrackExceptionState exceptionState;
    341     for (Node* node = toClone.firstChild(); node && !exceptionState.hadException(); node = node->nextSibling())
    342         clone->appendChild(cloneNodeAndAssociate(*node), exceptionState);
    343     return clone.release();
    344 }
    345 
    346 void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target)
    347 {
    348     ASSERT(!m_targetElementInstance);
    349 
    350     // <use> creates a "user agent" shadow root. Do not build the shadow/instance tree for <use>
    351     // elements living in a user agent shadow tree because they will get expanded in a second
    352     // pass -- see expandUseElementsInShadowTree().
    353     if (inUseShadowTree())
    354         return;
    355 
    356     // Do not allow self-referencing.
    357     // 'target' may be null, if it's a non SVG namespaced element.
    358     if (!target || target == this)
    359         return;
    360 
    361     // Set up root SVG element in shadow tree.
    362     RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithoutChildren();
    363     m_targetElementInstance = toSVGElement(newChild.get());
    364     ShadowRoot* shadowTreeRootElement = userAgentShadowRoot();
    365     shadowTreeRootElement->appendChild(newChild.release());
    366 
    367     // Clone the target subtree into the shadow tree, not handling <use> and <symbol> yet.
    368 
    369     // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it!
    370     // Non-appearing <use> content is easier to debug, then half-appearing content.
    371     if (!buildShadowTree(target, m_targetElementInstance.get(), false)) {
    372         clearResourceReferences();
    373         return;
    374     }
    375 
    376     if (instanceTreeIsLoading(m_targetElementInstance.get()))
    377         return;
    378 
    379     // Assure shadow tree building was successfull
    380     ASSERT(m_targetElementInstance);
    381     ASSERT(m_targetElementInstance->correspondingUseElement() == this);
    382     ASSERT(m_targetElementInstance->correspondingElement() == target);
    383 
    384     // Expand all <use> elements in the shadow tree.
    385     // Expand means: replace the actual <use> element by what it references.
    386     if (!expandUseElementsInShadowTree(m_targetElementInstance.get())) {
    387         clearResourceReferences();
    388         return;
    389     }
    390 
    391     // Expand all <symbol> elements in the shadow tree.
    392     // Expand means: replace the actual <symbol> element by the <svg> element.
    393     expandSymbolElementsInShadowTree(toSVGElement(shadowTreeRootElement->firstChild()));
    394 
    395     m_targetElementInstance = toSVGElement(shadowTreeRootElement->firstChild());
    396     transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_targetElementInstance->correspondingElement());
    397 
    398     ASSERT(m_targetElementInstance->parentNode() == shadowTreeRootElement);
    399 
    400     // Update relative length information.
    401     updateRelativeLengthsInformation();
    402 }
    403 
    404 RenderObject* SVGUseElement::createRenderer(RenderStyle*)
    405 {
    406     return new RenderSVGTransformableContainer(this);
    407 }
    408 
    409 static bool isDirectReference(const SVGElement& element)
    410 {
    411     return isSVGPathElement(element)
    412         || isSVGRectElement(element)
    413         || isSVGCircleElement(element)
    414         || isSVGEllipseElement(element)
    415         || isSVGPolygonElement(element)
    416         || isSVGPolylineElement(element)
    417         || isSVGTextElement(element);
    418 }
    419 
    420 void SVGUseElement::toClipPath(Path& path)
    421 {
    422     ASSERT(path.isEmpty());
    423 
    424     Node* n = userAgentShadowRoot()->firstChild();
    425     if (!n || !n->isSVGElement())
    426         return;
    427     SVGElement& element = toSVGElement(*n);
    428 
    429     if (element.isSVGGraphicsElement()) {
    430         if (!isDirectReference(element)) {
    431             // Spec: Indirect references are an error (14.3.5)
    432             document().accessSVGExtensions().reportError("Not allowed to use indirect reference in <clip-path>");
    433         } else {
    434             toSVGGraphicsElement(element).toClipPath(path);
    435             // FIXME: Avoid manual resolution of x/y here. Its potentially harmful.
    436             SVGLengthContext lengthContext(this);
    437             path.translate(FloatSize(m_x->currentValue()->value(lengthContext), m_y->currentValue()->value(lengthContext)));
    438             path.transform(animatedLocalTransform());
    439         }
    440     }
    441 }
    442 
    443 RenderObject* SVGUseElement::rendererClipChild() const
    444 {
    445     if (Node* n = userAgentShadowRoot()->firstChild()) {
    446         if (n->isSVGElement() && isDirectReference(toSVGElement(*n)))
    447             return n->renderer();
    448     }
    449 
    450     return 0;
    451 }
    452 
    453 bool SVGUseElement::buildShadowTree(SVGElement* target, SVGElement* targetInstance, bool foundUse)
    454 {
    455     ASSERT(target);
    456     ASSERT(targetInstance);
    457 
    458     // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
    459     // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
    460     if (isSVGUseElement(*target)) {
    461         // We only need to track first degree <use> dependencies. Indirect references are handled
    462         // as the invalidation bubbles up the dependency chain.
    463         if (!foundUse && !isStructurallyExternal()) {
    464             addReferenceTo(target);
    465             foundUse = true;
    466         }
    467     } else if (isDisallowedElement(target)) {
    468         return false;
    469     }
    470 
    471     targetInstance->setCorrespondingElement(target);
    472     if (EventTargetData* data = target->eventTargetData())
    473         data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(targetInstance);
    474 
    475     for (Node* child = target->firstChild(); child; child = child->nextSibling()) {
    476         // Skip any disallowed element.
    477         if (isDisallowedElement(child))
    478             continue;
    479 
    480         RefPtrWillBeRawPtr<Node> newChild = child->cloneNode(false);
    481         targetInstance->appendChild(newChild.get());
    482         if (newChild->isSVGElement()) {
    483             // Enter recursion, appending new instance tree nodes to the "instance" object.
    484             if (!buildShadowTree(toSVGElement(child), toSVGElement(newChild), foundUse))
    485                 return false;
    486         }
    487     }
    488     return true;
    489 }
    490 
    491 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, ContainerNode* targetInstance, SVGElement*& newTarget)
    492 {
    493     ASSERT(referencedScope());
    494     Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefString(), *referencedScope());
    495     newTarget = 0;
    496     if (targetElement && targetElement->isSVGElement())
    497         newTarget = toSVGElement(targetElement);
    498 
    499     if (!newTarget)
    500         return false;
    501 
    502     // Shortcut for self-references
    503     if (newTarget == this)
    504         return true;
    505 
    506     AtomicString targetId = newTarget->getIdAttribute();
    507     ContainerNode* instance = targetInstance->parentNode();
    508     while (instance && instance->isSVGElement()) {
    509         SVGElement* element = toSVGElement(instance);
    510         if (element->hasID() && element->getIdAttribute() == targetId && element->document() == newTarget->document())
    511             return true;
    512 
    513         instance = instance->parentNode();
    514     }
    515     return false;
    516 }
    517 
    518 static inline void removeDisallowedElementsFromSubtree(Element& subtree)
    519 {
    520     ASSERT(!subtree.inDocument());
    521     Element* element = ElementTraversal::firstWithin(subtree);
    522     while (element) {
    523         if (isDisallowedElement(element)) {
    524             Element* next = ElementTraversal::nextSkippingChildren(*element, &subtree);
    525             // The subtree is not in document so this won't generate events that could mutate the tree.
    526             element->parentNode()->removeChild(element);
    527             element = next;
    528         } else {
    529             element = ElementTraversal::next(*element, &subtree);
    530         }
    531     }
    532 }
    533 
    534 bool SVGUseElement::expandUseElementsInShadowTree(SVGElement* element)
    535 {
    536     ASSERT(element);
    537     // Why expand the <use> elements in the shadow tree here, and not just
    538     // do this directly in buildShadowTree, if we encounter a <use> element?
    539     //
    540     // Short answer: Because we may miss to expand some elements. For example, if a <symbol>
    541     // contains <use> tags, we'd miss them. So once we're done with setting up the
    542     // actual shadow tree (after the special case modification for svg/symbol) we have
    543     // to walk it completely and expand all <use> elements.
    544     if (isSVGUseElement(*element)) {
    545         SVGUseElement* use = toSVGUseElement(element);
    546         ASSERT(!use->resourceIsStillLoading());
    547 
    548         SVGElement* target = 0;
    549         if (hasCycleUseReferencing(toSVGUseElement(use->correspondingElement()), use, target))
    550             return false;
    551 
    552         if (target && isDisallowedElement(target))
    553             return false;
    554         // Don't ASSERT(target) here, it may be "pending", too.
    555         // Setup sub-shadow tree root node
    556         RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(referencedScope()->document());
    557         cloneParent->setCorrespondingElement(use->correspondingElement());
    558 
    559         // Move already cloned elements to the new <g> element
    560         for (Node* child = use->firstChild(); child; ) {
    561             Node* nextChild = child->nextSibling();
    562             cloneParent->appendChild(child);
    563             child = nextChild;
    564         }
    565 
    566         // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
    567         // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
    568         transferUseAttributesToReplacedElement(use, cloneParent.get());
    569 
    570         if (target) {
    571             RefPtrWillBeRawPtr<Node> newChild = cloneNodeAndAssociate(*target);
    572             ASSERT(newChild->isSVGElement());
    573             transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()), *target);
    574             cloneParent->appendChild(newChild.release());
    575         }
    576 
    577         // We don't walk the target tree element-by-element, and clone each element,
    578         // but instead use cloneElementWithChildren(). This is an optimization for the common
    579         // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
    580         // Though if there are disallowed elements in the subtree, we have to remove them.
    581         // For instance: <use> on <g> containing <foreignObject> (indirect case).
    582         if (subtreeContainsDisallowedElement(cloneParent.get()))
    583             removeDisallowedElementsFromSubtree(*cloneParent);
    584 
    585         RefPtrWillBeRawPtr<SVGElement> replacingElement(cloneParent.get());
    586 
    587         // Replace <use> with referenced content.
    588         ASSERT(use->parentNode());
    589         use->parentNode()->replaceChild(cloneParent.release(), use);
    590 
    591         // Expand the siblings because the *element* is replaced and we will
    592         // lose the sibling chain when we are back from recursion.
    593         element = replacingElement.get();
    594         for (RefPtrWillBeRawPtr<SVGElement> sibling = Traversal<SVGElement>::nextSibling(*element); sibling; sibling = Traversal<SVGElement>::nextSibling(*sibling)) {
    595             if (!expandUseElementsInShadowTree(sibling.get()))
    596                 return false;
    597         }
    598     }
    599 
    600     for (RefPtrWillBeRawPtr<SVGElement> child = Traversal<SVGElement>::firstChild(*element); child; child = Traversal<SVGElement>::nextSibling(*child)) {
    601         if (!expandUseElementsInShadowTree(child.get()))
    602             return false;
    603     }
    604     return true;
    605 }
    606 
    607 void SVGUseElement::expandSymbolElementsInShadowTree(SVGElement* element)
    608 {
    609     ASSERT(element);
    610     if (isSVGSymbolElement(*element)) {
    611         // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
    612         // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
    613         // always have explicit values for attributes width and height. If attributes width and/or
    614         // height are provided on the 'use' element, then these attributes will be transferred to
    615         // the generated 'svg'. If attributes width and/or height are not specified, the generated
    616         // 'svg' element will use values of 100% for these attributes.
    617         ASSERT(referencedScope());
    618         RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(referencedScope()->document());
    619         // Transfer all data (attributes, etc.) from <symbol> to the new <svg> element.
    620         svgElement->cloneDataFromElement(*element);
    621         svgElement->setCorrespondingElement(element->correspondingElement());
    622 
    623         // Move already cloned elements to the new <svg> element
    624         for (Node* child = element->firstChild(); child; ) {
    625             Node* nextChild = child->nextSibling();
    626             svgElement->appendChild(child);
    627             child = nextChild;
    628         }
    629 
    630         // We don't walk the target tree element-by-element, and clone each element,
    631         // but instead use cloneNode(deep=true). This is an optimization for the common
    632         // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
    633         // Though if there are disallowed elements in the subtree, we have to remove them.
    634         // For instance: <use> on <g> containing <foreignObject> (indirect case).
    635         if (subtreeContainsDisallowedElement(svgElement.get()))
    636             removeDisallowedElementsFromSubtree(*svgElement);
    637 
    638         RefPtrWillBeRawPtr<SVGElement> replacingElement(svgElement.get());
    639 
    640         // Replace <symbol> with <svg>.
    641         ASSERT(element->parentNode());
    642         element->parentNode()->replaceChild(svgElement.release(), element);
    643 
    644         // Expand the siblings because the *element* is replaced and we will
    645         // lose the sibling chain when we are back from recursion.
    646         element = replacingElement.get();
    647     }
    648 
    649     for (RefPtrWillBeRawPtr<SVGElement> child = Traversal<SVGElement>::firstChild(*element); child; child = Traversal<SVGElement>::nextSibling(*child))
    650         expandSymbolElementsInShadowTree(child.get());
    651 }
    652 
    653 void SVGUseElement::invalidateShadowTree()
    654 {
    655     if (!inActiveDocument() || m_needsShadowTreeRecreation)
    656         return;
    657     scheduleShadowTreeRecreation();
    658     invalidateDependentShadowTrees();
    659 }
    660 
    661 void SVGUseElement::invalidateDependentShadowTrees()
    662 {
    663     // Recursively invalidate dependent <use> shadow trees
    664     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = instancesForElement();
    665     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end();
    666     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) {
    667         if (SVGUseElement* element = (*it)->correspondingUseElement()) {
    668             ASSERT(element->inDocument());
    669             element->invalidateShadowTree();
    670         }
    671     }
    672 }
    673 
    674 void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement* from, SVGElement* to) const
    675 {
    676     ASSERT(from);
    677     ASSERT(to);
    678 
    679     to->cloneDataFromElement(*from);
    680 
    681     to->removeAttribute(SVGNames::xAttr);
    682     to->removeAttribute(SVGNames::yAttr);
    683     to->removeAttribute(SVGNames::widthAttr);
    684     to->removeAttribute(SVGNames::heightAttr);
    685     to->removeAttribute(XLinkNames::hrefAttr);
    686 }
    687 
    688 bool SVGUseElement::selfHasRelativeLengths() const
    689 {
    690     if (m_x->currentValue()->isRelative()
    691         || m_y->currentValue()->isRelative()
    692         || m_width->currentValue()->isRelative()
    693         || m_height->currentValue()->isRelative())
    694         return true;
    695 
    696     if (!m_targetElementInstance)
    697         return false;
    698 
    699     return m_targetElementInstance->hasRelativeLengths();
    700 }
    701 
    702 void SVGUseElement::notifyFinished(Resource* resource)
    703 {
    704     if (!inDocument())
    705         return;
    706 
    707     invalidateShadowTree();
    708     if (resource->errorOccurred())
    709         dispatchEvent(Event::create(EventTypeNames::error));
    710     else if (!resource->wasCanceled()) {
    711         if (m_haveFiredLoadEvent)
    712             return;
    713         if (!isStructurallyExternal())
    714             return;
    715         ASSERT(!m_haveFiredLoadEvent);
    716         m_haveFiredLoadEvent = true;
    717         sendSVGLoadEventIfPossibleAsynchronously();
    718     }
    719 }
    720 
    721 bool SVGUseElement::resourceIsStillLoading()
    722 {
    723     if (m_resource && m_resource->isLoading())
    724         return true;
    725     return false;
    726 }
    727 
    728 bool SVGUseElement::instanceTreeIsLoading(SVGElement* targetInstance)
    729 {
    730     for (SVGElement* element = Traversal<SVGElement>::firstChild(*targetInstance); element; element = Traversal<SVGElement>::nextSibling(*element)) {
    731         if (SVGUseElement* use = element->correspondingUseElement()) {
    732             if (use->resourceIsStillLoading())
    733                 return true;
    734         }
    735         if (element->hasChildren() && instanceTreeIsLoading(element))
    736             return true;
    737     }
    738     return false;
    739 }
    740 
    741 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource)
    742 {
    743     if (m_resource == resource)
    744         return;
    745 
    746     if (m_resource)
    747         m_resource->removeClient(this);
    748 
    749     m_resource = resource;
    750     if (m_resource)
    751         m_resource->addClient(this);
    752 }
    753 
    754 void SVGUseElement::trace(Visitor* visitor)
    755 {
    756     visitor->trace(m_targetElementInstance);
    757     SVGGraphicsElement::trace(visitor);
    758 }
    759 
    760 }
    761