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