Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / svg / SVGUseElement.cpp
index 6917554..f228ee6 100644 (file)
 
 #include "core/svg/SVGUseElement.h"
 
-#include "SVGNames.h"
-#include "XLinkNames.h"
-#include "bindings/v8/ExceptionStatePlaceholder.h"
+#include "bindings/core/v8/ExceptionStatePlaceholder.h"
+#include "core/XLinkNames.h"
 #include "core/dom/Document.h"
 #include "core/dom/ElementTraversal.h"
 #include "core/events/Event.h"
 #include "core/dom/shadow/ElementShadow.h"
 #include "core/dom/shadow/ShadowRoot.h"
-#include "core/fetch/DocumentResource.h"
 #include "core/fetch/FetchRequest.h"
 #include "core/fetch/ResourceFetcher.h"
-#include "core/rendering/svg/RenderSVGResource.h"
 #include "core/rendering/svg/RenderSVGTransformableContainer.h"
-#include "core/svg/SVGElementInstance.h"
 #include "core/svg/SVGGElement.h"
 #include "core/svg/SVGLengthContext.h"
 #include "core/svg/SVGSVGElement.h"
 #include "core/xml/parser/XMLDocumentParser.h"
 
-// Dump SVGElementInstance object tree - useful to debug instanceRoot problems
-// #define DUMP_INSTANCE_TREE
-
-// Dump the deep-expanded shadow tree (where the renderers are built from)
-// #define DUMP_SHADOW_TREE
-
-namespace WebCore {
-
-// Animated property definitions
-DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::xAttr, X, x)
-DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::yAttr, Y, y)
-DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::widthAttr, Width, width)
-DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::heightAttr, Height, height)
-DEFINE_ANIMATED_STRING(SVGUseElement, XLinkNames::hrefAttr, Href, href)
-DEFINE_ANIMATED_BOOLEAN(SVGUseElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
-
-BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGUseElement)
-    REGISTER_LOCAL_ANIMATED_PROPERTY(x)
-    REGISTER_LOCAL_ANIMATED_PROPERTY(y)
-    REGISTER_LOCAL_ANIMATED_PROPERTY(width)
-    REGISTER_LOCAL_ANIMATED_PROPERTY(height)
-    REGISTER_LOCAL_ANIMATED_PROPERTY(href)
-    REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
-    REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement)
-END_REGISTER_ANIMATED_PROPERTIES
-
-inline SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document& document, bool wasInsertedByParser)
-    : SVGGraphicsElement(tagName, document)
-    , m_x(LengthModeWidth)
-    , m_y(LengthModeHeight)
-    , m_width(LengthModeWidth)
-    , m_height(LengthModeHeight)
-    , m_wasInsertedByParser(wasInsertedByParser)
+namespace blink {
+
+inline SVGUseElement::SVGUseElement(Document& document)
+    : SVGGraphicsElement(SVGNames::useTag, document)
+    , SVGURIReference(this)
+    , m_x(SVGAnimatedLength::create(this, SVGNames::xAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths))
+    , m_y(SVGAnimatedLength::create(this, SVGNames::yAttr, SVGLength::create(LengthModeHeight), AllowNegativeLengths))
+    , m_width(SVGAnimatedLength::create(this, SVGNames::widthAttr, SVGLength::create(LengthModeWidth), ForbidNegativeLengths))
+    , m_height(SVGAnimatedLength::create(this, SVGNames::heightAttr, SVGLength::create(LengthModeHeight), ForbidNegativeLengths))
     , m_haveFiredLoadEvent(false)
     , m_needsShadowTreeRecreation(false)
     , m_svgLoadEventTimer(this, &SVGElement::svgLoadEventTimerFired)
 {
     ASSERT(hasCustomStyleCallbacks());
-    ASSERT(hasTagName(SVGNames::useTag));
-    ScriptWrappable::init(this);
-    registerAnimatedPropertiesForSVGUseElement();
+
+    addToPropertyMap(m_x);
+    addToPropertyMap(m_y);
+    addToPropertyMap(m_width);
+    addToPropertyMap(m_height);
 }
 
-PassRefPtr<SVGUseElement> SVGUseElement::create(const QualifiedName& tagName, Document& document, bool wasInsertedByParser)
+PassRefPtrWillBeRawPtr<SVGUseElement> SVGUseElement::create(Document& document)
 {
-    // Always build a #shadow-root for SVGUseElement.
-    RefPtr<SVGUseElement> use = adoptRef(new SVGUseElement(tagName, document, wasInsertedByParser));
+    // Always build a user agent #shadow-root for SVGUseElement.
+    RefPtrWillBeRawPtr<SVGUseElement> use = adoptRefWillBeNoop(new SVGUseElement(document));
     use->ensureUserAgentShadowRoot();
     return use.release();
 }
@@ -99,34 +73,15 @@ PassRefPtr<SVGUseElement> SVGUseElement::create(const QualifiedName& tagName, Do
 SVGUseElement::~SVGUseElement()
 {
     setDocumentResource(0);
-
+#if !ENABLE(OILPAN)
     clearResourceReferences();
-}
-
-SVGElementInstance* SVGUseElement::instanceRoot()
-{
-    // If there is no element instance tree, force immediate SVGElementInstance tree
-    // creation by asking the document to invoke our recalcStyle function - as we can't
-    // wait for the lazy creation to happen if e.g. JS wants to access the instanceRoot
-    // object right after creating the element on-the-fly
-    if (!m_targetElementInstance)
-        document().updateStyleIfNeeded();
-
-    return m_targetElementInstance.get();
-}
-
-SVGElementInstance* SVGUseElement::animatedInstanceRoot() const
-{
-    // FIXME: Implement me.
-    return 0;
+#endif
 }
 
 bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName)
 {
     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
     if (supportedAttributes.isEmpty()) {
-        SVGLangSpace::addSupportedAttributes(supportedAttributes);
-        SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
         SVGURIReference::addSupportedAttributes(supportedAttributes);
         supportedAttributes.add(SVGNames::xAttr);
         supportedAttributes.add(SVGNames::yAttr);
@@ -138,33 +93,17 @@ bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName)
 
 void SVGUseElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
 {
-    SVGParsingError parseError = NoError;
-
-    if (!isSupportedAttribute(name))
-        SVGGraphicsElement::parseAttribute(name, value);
-    else if (name == SVGNames::xAttr)
-        setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
-    else if (name == SVGNames::yAttr)
-        setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
-    else if (name == SVGNames::widthAttr)
-        setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError, ForbidNegativeLengths));
-    else if (name == SVGNames::heightAttr)
-        setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths));
-    else if (SVGLangSpace::parseAttribute(name, value)
-             || SVGExternalResourcesRequired::parseAttribute(name, value)
-             || SVGURIReference::parseAttribute(name, value)) {
-    } else
-        ASSERT_NOT_REACHED();
-
-    reportAttributeParsingError(parseError, name, value);
+    parseAttributeNew(name, value);
 }
 
+#if ENABLE(ASSERT)
 static inline bool isWellFormedDocument(Document* document)
 {
-    if (document->isSVGDocument() || document->isXHTMLDocument())
+    if (document->isXMLDocument())
         return static_cast<XMLDocumentParser*>(document->parser())->wellFormed();
     return true;
 }
+#endif
 
 Node::InsertionNotificationRequest SVGUseElement::insertedInto(ContainerNode* rootParent)
 {
@@ -174,9 +113,9 @@ Node::InsertionNotificationRequest SVGUseElement::insertedInto(ContainerNode* ro
         return InsertionDone;
     ASSERT(!m_targetElementInstance || !isWellFormedDocument(&document()));
     ASSERT(!hasPendingResources() || !isWellFormedDocument(&document()));
-    if (!m_wasInsertedByParser)
-        buildPendingResource();
-    SVGExternalResourcesRequired::insertedIntoDocument(this);
+    invalidateShadowTree();
+    if (!isStructurallyExternal())
+        sendSVGLoadEventIfPossibleAsynchronously();
     return InsertionDone;
 }
 
@@ -187,10 +126,10 @@ void SVGUseElement::removedFrom(ContainerNode* rootParent)
         clearResourceReferences();
 }
 
-Document* SVGUseElement::referencedDocument() const
+TreeScope* SVGUseElement::referencedScope() const
 {
-    if (!isExternalURIReference(hrefCurrentValue(), document()))
-        return &document();
+    if (!isExternalURIReference(hrefString(), document()))
+        return &treeScope();
     return externalDocument();
 }
 
@@ -206,6 +145,31 @@ Document* SVGUseElement::externalDocument() const
     return 0;
 }
 
+void transferUseWidthAndHeightIfNeeded(const SVGUseElement& use, SVGElement* shadowElement, const SVGElement& originalElement)
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, hundredPercentString, ("100%", AtomicString::ConstructFromLiteral));
+    ASSERT(shadowElement);
+    if (isSVGSymbolElement(*shadowElement)) {
+        // Spec (<use> on <symbol>): This generated 'svg' will always have explicit values for attributes width and height.
+        // If attributes width and/or height are provided on the 'use' element, then these attributes
+        // will be transferred to the generated 'svg'. If attributes width and/or height are not specified,
+        // the generated 'svg' element will use values of 100% for these attributes.
+        shadowElement->setAttribute(SVGNames::widthAttr, use.width()->isSpecified() ? AtomicString(use.width()->currentValue()->valueAsString()) : hundredPercentString);
+        shadowElement->setAttribute(SVGNames::heightAttr, use.height()->isSpecified() ? AtomicString(use.height()->currentValue()->valueAsString()) : hundredPercentString);
+    } else if (isSVGSVGElement(*shadowElement)) {
+        // Spec (<use> on <svg>): If attributes width and/or height are provided on the 'use' element, then these
+        // values will override the corresponding attributes on the 'svg' in the generated tree.
+        if (use.width()->isSpecified())
+            shadowElement->setAttribute(SVGNames::widthAttr, AtomicString(use.width()->currentValue()->valueAsString()));
+        else
+            shadowElement->setAttribute(SVGNames::widthAttr, originalElement.getAttribute(SVGNames::widthAttr));
+        if (use.height()->isSpecified())
+            shadowElement->setAttribute(SVGNames::heightAttr, AtomicString(use.height()->currentValue()->valueAsString()));
+        else
+            shadowElement->setAttribute(SVGNames::heightAttr, originalElement.getAttribute(SVGNames::heightAttr));
+    }
+}
+
 void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
 {
     if (!isSupportedAttribute(attrName)) {
@@ -213,7 +177,7 @@ void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
         return;
     }
 
-    SVGElementInstance::InvalidationGuard invalidationGuard(this);
+    SVGElement::InvalidationGuard invalidationGuard(this);
 
     RenderObject* renderer = this->renderer();
     if (attrName == SVGNames::xAttr
@@ -221,28 +185,28 @@ void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
         || attrName == SVGNames::widthAttr
         || attrName == SVGNames::heightAttr) {
         updateRelativeLengthsInformation();
+        if (m_targetElementInstance) {
+            ASSERT(m_targetElementInstance->correspondingElement());
+            transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_targetElementInstance->correspondingElement());
+        }
         if (renderer)
-            RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
+            markForLayoutAndParentResourceInvalidation(renderer);
         return;
     }
 
-    if (SVGExternalResourcesRequired::handleAttributeChange(this, attrName))
-        return;
-
     if (SVGURIReference::isKnownAttribute(attrName)) {
-        bool isExternalReference = isExternalURIReference(hrefCurrentValue(), document());
+        bool isExternalReference = isExternalURIReference(hrefString(), document());
         if (isExternalReference) {
-            KURL url = document().completeURL(hrefCurrentValue());
+            KURL url = document().completeURL(hrefString());
             if (url.hasFragmentIdentifier()) {
-                FetchRequest request(ResourceRequest(url.string()), localName());
+                FetchRequest request(ResourceRequest(url), localName());
                 setDocumentResource(document().fetcher()->fetchSVGDocument(request));
             }
         } else {
             setDocumentResource(0);
         }
 
-        if (!m_wasInsertedByParser)
-            buildPendingResource();
+        invalidateShadowTree();
 
         return;
     }
@@ -250,82 +214,9 @@ void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
     if (!renderer)
         return;
 
-    if (SVGLangSpace::isKnownAttribute(attrName)
-        || SVGExternalResourcesRequired::isKnownAttribute(attrName)) {
-        invalidateShadowTree();
-        return;
-    }
-
     ASSERT_NOT_REACHED();
 }
 
-void SVGUseElement::attach(const AttachContext& context)
-{
-    if (m_needsShadowTreeRecreation)
-        buildPendingResource();
-    SVGGraphicsElement::attach(context);
-}
-
-void SVGUseElement::willRecalcStyle(StyleRecalcChange)
-{
-    if (!m_wasInsertedByParser && m_needsShadowTreeRecreation && renderer() && needsStyleRecalc())
-        buildPendingResource();
-}
-
-#ifdef DUMP_INSTANCE_TREE
-static void dumpInstanceTree(unsigned int& depth, String& text, SVGElementInstance* targetInstance)
-{
-    SVGElement* element = targetInstance->correspondingElement();
-    ASSERT(element);
-
-    if (element->hasTagName(SVGNames::useTag)) {
-        if (toSVGUseElement(element)->resourceIsStillLoading())
-            return;
-    }
-
-    SVGElement* shadowTreeElement = targetInstance->shadowTreeElement();
-    ASSERT(shadowTreeElement);
-
-    SVGUseElement* directUseElement = targetInstance->directUseElement();
-    String directUseElementName = directUseElement ? directUseElement->nodeName() : "null";
-
-    String elementId = element->getIdAttribute();
-    String elementNodeName = element->nodeName();
-    String shadowTreeElementNodeName = shadowTreeElement->nodeName();
-    String parentNodeName = element->parentNode() ? element->parentNode()->nodeName() : "null";
-    String firstChildNodeName = element->firstChild() ? element->firstChild()->nodeName() : "null";
-
-    for (unsigned int i = 0; i < depth; ++i)
-        text += "  ";
-
-    text += String::format("SVGElementInstance this=%p, (parentNode=%s (%p), firstChild=%s (%p), correspondingElement=%s (%p), directUseElement=%s (%p), shadowTreeElement=%s (%p), id=%s)\n",
-                           targetInstance, parentNodeName.latin1().data(), element->parentNode(), firstChildNodeName.latin1().data(), element->firstChild(),
-                           elementNodeName.latin1().data(), element, directUseElementName.latin1().data(), directUseElement, shadowTreeElementNodeName.latin1().data(), shadowTreeElement, elementId.latin1().data());
-
-    for (unsigned int i = 0; i < depth; ++i)
-        text += "  ";
-
-    const HashSet<SVGElementInstance*>& elementInstances = element->instancesForElement();
-    text += "Corresponding element is associated with " + String::number(elementInstances.size()) + " instance(s):\n";
-
-    const HashSet<SVGElementInstance*>::const_iterator end = elementInstances.end();
-    for (HashSet<SVGElementInstance*>::const_iterator it = elementInstances.begin(); it != end; ++it) {
-        for (unsigned int i = 0; i < depth; ++i)
-            text += "  ";
-
-        text += String::format(" -> SVGElementInstance this=%p, (refCount: %i, shadowTreeElement in document? %i)\n",
-                               *it, (*it)->refCount(), (*it)->shadowTreeElement()->inDocument());
-    }
-
-    ++depth;
-
-    for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
-        dumpInstanceTree(depth, text, instance);
-
-    --depth;
-}
-#endif
-
 static bool isDisallowedElement(Node* node)
 {
     // Spec: "Any 'svg', 'symbol', 'g', graphics element or other 'use' is potentially a template object that can be re-used
@@ -380,32 +271,39 @@ static bool subtreeContainsDisallowedElement(Node* start)
     return false;
 }
 
+void SVGUseElement::scheduleShadowTreeRecreation()
+{
+    if (!referencedScope() || inUseShadowTree())
+        return;
+    m_needsShadowTreeRecreation = true;
+    document().scheduleUseShadowTreeUpdate(*this);
+}
+
 void SVGUseElement::clearResourceReferences()
 {
+    if (m_targetElementInstance)
+        m_targetElementInstance = nullptr;
+
     // FIXME: We should try to optimize this, to at least allow partial reclones.
     if (ShadowRoot* shadowTreeRootElement = userAgentShadowRoot())
         shadowTreeRootElement->removeChildren();
 
-    if (m_targetElementInstance) {
-        m_targetElementInstance->detach();
-        m_targetElementInstance = 0;
-    }
-
     m_needsShadowTreeRecreation = false;
+    document().unscheduleUseShadowTreeUpdate(*this);
 
-    document().accessSVGExtensions()->removeAllTargetReferencesForElement(this);
+    removeAllOutgoingReferences();
 }
 
 void SVGUseElement::buildPendingResource()
 {
-    if (!referencedDocument() || isInShadowTree())
+    if (!referencedScope() || inUseShadowTree())
         return;
     clearResourceReferences();
     if (!inDocument())
         return;
 
-    String id;
-    Element* target = SVGURIReference::targetElementFromIRIString(hrefCurrentValue(), document(), &id, externalDocument());
+    AtomicString id;
+    Element* target = SVGURIReference::targetElementFromIRIString(hrefString(), treeScope(), &id, externalDocument());
     if (!target || !target->inDocument()) {
         // If we can't find the target of an external element, just give up.
         // We can't observe if the target somewhen enters the external document, nor should we do it.
@@ -414,7 +312,7 @@ void SVGUseElement::buildPendingResource()
         if (id.isEmpty())
             return;
 
-        referencedDocument()->accessSVGExtensions()->addPendingResource(id, this);
+        referencedScope()->document().accessSVGExtensions().addPendingResource(id, this);
         ASSERT(hasPendingResources());
         return;
     }
@@ -427,13 +325,31 @@ void SVGUseElement::buildPendingResource()
     ASSERT(!m_needsShadowTreeRecreation);
 }
 
+static PassRefPtrWillBeRawPtr<Node> cloneNodeAndAssociate(Node& toClone)
+{
+    RefPtrWillBeRawPtr<Node> clone = toClone.cloneNode(false);
+    if (!clone->isSVGElement())
+        return clone.release();
+
+    SVGElement& svgElement = toSVGElement(toClone);
+    ASSERT(!svgElement.correspondingElement());
+    toSVGElement(clone.get())->setCorrespondingElement(&svgElement);
+    if (EventTargetData* data = toClone.eventTargetData())
+        data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(clone.get());
+    TrackExceptionState exceptionState;
+    for (Node* node = toClone.firstChild(); node && !exceptionState.hadException(); node = node->nextSibling())
+        clone->appendChild(cloneNodeAndAssociate(*node), exceptionState);
+    return clone.release();
+}
+
 void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target)
 {
     ASSERT(!m_targetElementInstance);
 
-    // Do not build the shadow/instance tree for <use> elements living in a shadow tree.
-    // The will be expanded soon anyway - see expandUseElementsInShadowTree().
-    if (isInShadowTree())
+    // <use> creates a "user agent" shadow root. Do not build the shadow/instance tree for <use>
+    // elements living in a user agent shadow tree because they will get expanded in a second
+    // pass -- see expandUseElementsInShadowTree().
+    if (inUseShadowTree())
         return;
 
     // Do not allow self-referencing.
@@ -441,89 +357,47 @@ void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target)
     if (!target || target == this)
         return;
 
-    // Why a seperated instance/shadow tree? SVG demands it:
-    // The instance tree is accesable from JavaScript, and has to
-    // expose a 1:1 copy of the referenced tree, whereas internally we need
-    // to alter the tree for correct "use-on-symbol", "use-on-svg" support.
-
-    // Build instance tree. Create root SVGElementInstance object for the first sub-tree node.
-    //
-    // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a
-    // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object
-    // is the SVGRectElement that corresponds to the referenced 'rect' element.
-    m_targetElementInstance = SVGElementInstance::create(this, this, target);
+    // Set up root SVG element in shadow tree.
+    RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithoutChildren();
+    m_targetElementInstance = toSVGElement(newChild.get());
+    ShadowRoot* shadowTreeRootElement = userAgentShadowRoot();
+    shadowTreeRootElement->appendChild(newChild.release());
 
-    // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
-    bool foundProblem = false;
-    buildInstanceTree(target, m_targetElementInstance.get(), foundProblem, false);
-
-    if (instanceTreeIsLoading(m_targetElementInstance.get()))
-        return;
+    // Clone the target subtree into the shadow tree, not handling <use> and <symbol> yet.
 
     // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it!
     // Non-appearing <use> content is easier to debug, then half-appearing content.
-    if (foundProblem) {
+    if (!buildShadowTree(target, m_targetElementInstance.get(), false)) {
         clearResourceReferences();
         return;
     }
 
-    // Assure instance tree building was successfull
+    if (instanceTreeIsLoading(m_targetElementInstance.get()))
+        return;
+
+    // Assure shadow tree building was successfull
     ASSERT(m_targetElementInstance);
-    ASSERT(!m_targetElementInstance->shadowTreeElement());
     ASSERT(m_targetElementInstance->correspondingUseElement() == this);
-    ASSERT(m_targetElementInstance->directUseElement() == this);
     ASSERT(m_targetElementInstance->correspondingElement() == target);
 
-    ShadowRoot* shadowTreeRootElement = userAgentShadowRoot();
-    ASSERT(shadowTreeRootElement);
-
-    // Build shadow tree from instance tree
-    // This also handles the special cases: <use> on <symbol>, <use> on <svg>.
-    buildShadowTree(target, m_targetElementInstance.get());
-
     // Expand all <use> elements in the shadow tree.
     // Expand means: replace the actual <use> element by what it references.
-    expandUseElementsInShadowTree(shadowTreeRootElement);
-
-    // Expand all <symbol> elements in the shadow tree.
-    // Expand means: replace the actual <symbol> element by the <svg> element.
-    expandSymbolElementsInShadowTree(shadowTreeRootElement);
-
-    // Now that the shadow tree is completly expanded, we can associate
-    // shadow tree elements <-> instances in the instance tree.
-    associateInstancesWithShadowTreeElements(shadowTreeRootElement->firstChild(), m_targetElementInstance.get());
-
-    // If no shadow tree element is present, this means that the reference root
-    // element was removed, as it is disallowed (ie. <use> on <foreignObject>)
-    // Do NOT leave an inconsistent instance tree around, instead destruct it.
-    if (!m_targetElementInstance->shadowTreeElement()) {
+    if (!expandUseElementsInShadowTree(m_targetElementInstance.get())) {
         clearResourceReferences();
         return;
     }
 
-    ASSERT(m_targetElementInstance->shadowTreeElement()->parentNode() == shadowTreeRootElement);
+    // Expand all <symbol> elements in the shadow tree.
+    // Expand means: replace the actual <symbol> element by the <svg> element.
+    expandSymbolElementsInShadowTree(toSVGElement(shadowTreeRootElement->firstChild()));
+
+    m_targetElementInstance = toSVGElement(shadowTreeRootElement->firstChild());
+    transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_targetElementInstance->correspondingElement());
 
-    // Transfer event listeners assigned to the referenced element to our shadow tree elements.
-    transferEventListenersToShadowTree(m_targetElementInstance.get());
+    ASSERT(m_targetElementInstance->parentNode() == shadowTreeRootElement);
 
     // Update relative length information.
     updateRelativeLengthsInformation();
-
-    // Eventually dump instance tree
-#ifdef DUMP_INSTANCE_TREE
-    String text;
-    unsigned int depth = 0;
-
-    dumpInstanceTree(depth, text, m_targetElementInstance.get());
-    fprintf(stderr, "\nDumping <use> instance tree:\n%s\n", text.latin1().data());
-#endif
-
-    // Eventually dump shadow tree
-#ifdef DUMP_SHADOW_TREE
-    RefPtr<XMLSerializer> serializer = XMLSerializer::create();
-    String markup = serializer->serializeToString(shadowTreeRootElement, ASSERT_NO_EXCEPTION);
-    fprintf(stderr, "Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data());
-#endif
 }
 
 RenderObject* SVGUseElement::createRenderer(RenderStyle*)
@@ -531,116 +405,92 @@ RenderObject* SVGUseElement::createRenderer(RenderStyle*)
     return new RenderSVGTransformableContainer(this);
 }
 
-static bool isDirectReference(const Node* node)
+static bool isDirectReference(const SVGElement& element)
 {
-    return node->hasTagName(SVGNames::pathTag)
-           || node->hasTagName(SVGNames::rectTag)
-           || node->hasTagName(SVGNames::circleTag)
-           || node->hasTagName(SVGNames::ellipseTag)
-           || node->hasTagName(SVGNames::polygonTag)
-           || node->hasTagName(SVGNames::polylineTag)
-           || node->hasTagName(SVGNames::textTag);
+    return isSVGPathElement(element)
+        || isSVGRectElement(element)
+        || isSVGCircleElement(element)
+        || isSVGEllipseElement(element)
+        || isSVGPolygonElement(element)
+        || isSVGPolylineElement(element)
+        || isSVGTextElement(element);
 }
 
 void SVGUseElement::toClipPath(Path& path)
 {
     ASSERT(path.isEmpty());
 
-    Node* n = m_targetElementInstance ? m_targetElementInstance->shadowTreeElement() : 0;
-    if (!n)
+    Node* n = userAgentShadowRoot()->firstChild();
+    if (!n || !n->isSVGElement())
         return;
+    SVGElement& element = toSVGElement(*n);
 
-    if (n->isSVGElement() && toSVGElement(n)->isSVGGraphicsElement()) {
-        if (!isDirectReference(n)) {
+    if (element.isSVGGraphicsElement()) {
+        if (!isDirectReference(element)) {
             // Spec: Indirect references are an error (14.3.5)
-            document().accessSVGExtensions()->reportError("Not allowed to use indirect reference in <clip-path>");
+            document().accessSVGExtensions().reportError("Not allowed to use indirect reference in <clip-path>");
         } else {
-            toSVGGraphicsElement(n)->toClipPath(path);
+            toSVGGraphicsElement(element).toClipPath(path);
             // FIXME: Avoid manual resolution of x/y here. Its potentially harmful.
             SVGLengthContext lengthContext(this);
-            path.translate(FloatSize(xCurrentValue().value(lengthContext), yCurrentValue().value(lengthContext)));
-            path.transform(animatedLocalTransform());
+            path.translate(FloatSize(m_x->currentValue()->value(lengthContext), m_y->currentValue()->value(lengthContext)));
+            path.transform(calculateAnimatedLocalTransform());
         }
     }
 }
 
 RenderObject* SVGUseElement::rendererClipChild() const
 {
-    Node* n = m_targetElementInstance ? m_targetElementInstance->shadowTreeElement() : 0;
-    if (!n)
-        return 0;
-
-    if (n->isSVGElement() && isDirectReference(n))
-        return toSVGElement(n)->renderer();
+    if (Node* n = userAgentShadowRoot()->firstChild()) {
+        if (n->isSVGElement() && isDirectReference(toSVGElement(*n)))
+            return n->renderer();
+    }
 
     return 0;
 }
 
-void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* targetInstance, bool& foundProblem, bool foundUse)
+bool SVGUseElement::buildShadowTree(SVGElement* target, SVGElement* targetInstance, bool foundUse)
 {
     ASSERT(target);
     ASSERT(targetInstance);
 
     // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
     // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
-    bool targetHasUseTag = target->hasTagName(SVGNames::useTag);
-    SVGElement* newTarget = 0;
-    if (targetHasUseTag) {
-        foundProblem = hasCycleUseReferencing(toSVGUseElement(target), targetInstance, newTarget);
-        if (foundProblem)
-            return;
-
+    if (isSVGUseElement(*target)) {
         // We only need to track first degree <use> dependencies. Indirect references are handled
         // as the invalidation bubbles up the dependency chain.
-        if (!foundUse) {
-            document().accessSVGExtensions()->addElementReferencingTarget(this, target);
+        if (!foundUse && !isStructurallyExternal()) {
+            addReferenceTo(target);
             foundUse = true;
         }
     } else if (isDisallowedElement(target)) {
-        foundProblem = true;
-        return;
+        return false;
     }
 
-    // A general description from the SVG spec, describing what buildInstanceTree() actually does.
-    //
-    // Spec: If the 'use' element references a 'g' which contains two 'rect' elements, then the instance tree
-    // contains three SVGElementInstance objects, a root SVGElementInstance object whose correspondingElement
-    // is the SVGGElement object for the 'g', and then two child SVGElementInstance objects, each of which has
-    // its correspondingElement that is an SVGRectElement object.
-
-    for (Node* node = target->firstChild(); node; node = node->nextSibling()) {
-        SVGElement* element = 0;
-        if (node->isSVGElement())
-            element = toSVGElement(node);
-
-        // Skip any non-svg nodes or any disallowed element.
-        if (!element || isDisallowedElement(element))
-            continue;
+    targetInstance->setCorrespondingElement(target);
+    if (EventTargetData* data = target->eventTargetData())
+        data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(targetInstance);
 
-        // Create SVGElementInstance object, for both container/non-container nodes.
-        RefPtr<SVGElementInstance> instance = SVGElementInstance::create(this, 0, element);
-        SVGElementInstance* instancePtr = instance.get();
-        targetInstance->appendChild(instance.release());
+    for (Node* child = target->firstChild(); child; child = child->nextSibling()) {
+        // Skip any disallowed element.
+        if (isDisallowedElement(child))
+            continue;
 
-        // Enter recursion, appending new instance tree nodes to the "instance" object.
-        buildInstanceTree(element, instancePtr, foundProblem, foundUse);
-        if (foundProblem)
-            return;
+        RefPtrWillBeRawPtr<Node> newChild = child->cloneNode(false);
+        targetInstance->appendChild(newChild.get());
+        if (newChild->isSVGElement()) {
+            // Enter recursion, appending new instance tree nodes to the "instance" object.
+            if (!buildShadowTree(toSVGElement(child), toSVGElement(newChild), foundUse))
+                return false;
+        }
     }
-
-    if (!targetHasUseTag || !newTarget)
-        return;
-
-    RefPtr<SVGElementInstance> newInstance = SVGElementInstance::create(this, toSVGUseElement(target), newTarget);
-    SVGElementInstance* newInstancePtr = newInstance.get();
-    targetInstance->appendChild(newInstance.release());
-    buildInstanceTree(newTarget, newInstancePtr, foundProblem, foundUse);
+    return true;
 }
 
-bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, SVGElementInstance* targetInstance, SVGElement*& newTarget)
+bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, ContainerNode* targetInstance, SVGElement*& newTarget)
 {
-    ASSERT(referencedDocument());
-    Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefCurrentValue(), *referencedDocument());
+    ASSERT(referencedScope());
+    Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefString(), *referencedScope());
     newTarget = 0;
     if (targetElement && targetElement->isSVGElement())
         newTarget = toSVGElement(targetElement);
@@ -653,10 +503,9 @@ bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, SVGElementInstanc
         return true;
 
     AtomicString targetId = newTarget->getIdAttribute();
-    SVGElementInstance* instance = targetInstance->parentNode();
-    while (instance) {
-        SVGElement* element = instance->correspondingElement();
-
+    ContainerNode* instance = targetInstance->parentNode();
+    while (instance && instance->isSVGElement()) {
+        SVGElement* element = toSVGElement(instance);
         if (element->hasID() && element->getIdAttribute() == targetId && element->document() == newTarget->document())
             return true;
 
@@ -665,71 +514,62 @@ bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, SVGElementInstanc
     return false;
 }
 
-static inline void removeDisallowedElementsFromSubtree(Element* subtree)
+static inline void removeDisallowedElementsFromSubtree(Element& subtree)
 {
-    ASSERT(!subtree->inDocument());
+    ASSERT(!subtree.inDocument());
     Element* element = ElementTraversal::firstWithin(subtree);
     while (element) {
         if (isDisallowedElement(element)) {
-            Element* next = ElementTraversal::nextSkippingChildren(element, subtree);
+            Element* next = ElementTraversal::nextSkippingChildren(*element, &subtree);
             // The subtree is not in document so this won't generate events that could mutate the tree.
             element->parentNode()->removeChild(element);
             element = next;
-        } else
-            element = ElementTraversal::next(element, subtree);
+        } else {
+            element = ElementTraversal::next(*element, &subtree);
+        }
     }
 }
 
-void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance)
-{
-    // For instance <use> on <foreignObject> (direct case).
-    if (isDisallowedElement(target))
-        return;
-
-    RefPtr<Element> newChild = targetInstance->correspondingElement()->cloneElementWithChildren();
-
-    // We don't walk the target tree element-by-element, and clone each element,
-    // but instead use cloneElementWithChildren(). This is an optimization for the common
-    // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
-    // Though if there are disallowed elements in the subtree, we have to remove them.
-    // For instance: <use> on <g> containing <foreignObject> (indirect case).
-    if (subtreeContainsDisallowedElement(newChild.get()))
-        removeDisallowedElementsFromSubtree(newChild.get());
-
-    userAgentShadowRoot()->appendChild(newChild.release());
-}
-
-void SVGUseElement::expandUseElementsInShadowTree(Node* element)
+bool SVGUseElement::expandUseElementsInShadowTree(SVGElement* element)
 {
+    ASSERT(element);
     // Why expand the <use> elements in the shadow tree here, and not just
     // do this directly in buildShadowTree, if we encounter a <use> element?
     //
-    // Short answer: Because we may miss to expand some elements. Ie. if a <symbol>
-    // contains <use> tags, we'd miss them. So once we're done with settin' up the
+    // Short answer: Because we may miss to expand some elements. For example, if a <symbol>
+    // contains <use> tags, we'd miss them. So once we're done with setting up the
     // actual shadow tree (after the special case modification for svg/symbol) we have
     // to walk it completely and expand all <use> elements.
-    if (element->hasTagName(SVGNames::useTag)) {
+    if (isSVGUseElement(*element)) {
         SVGUseElement* use = toSVGUseElement(element);
         ASSERT(!use->resourceIsStillLoading());
 
-        ASSERT(referencedDocument());
-        Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefCurrentValue(), *referencedDocument());
         SVGElement* target = 0;
-        if (targetElement && targetElement->isSVGElement())
-            target = toSVGElement(targetElement);
+        if (hasCycleUseReferencing(toSVGUseElement(use->correspondingElement()), use, target))
+            return false;
 
+        if (target && isDisallowedElement(target))
+            return false;
         // Don't ASSERT(target) here, it may be "pending", too.
         // Setup sub-shadow tree root node
-        RefPtr<SVGGElement> cloneParent = SVGGElement::create(SVGNames::gTag, *referencedDocument());
-        use->cloneChildNodes(cloneParent.get());
+        RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(referencedScope()->document());
+        cloneParent->setCorrespondingElement(use->correspondingElement());
+
+        // Move already cloned elements to the new <g> element
+        for (Node* child = use->firstChild(); child; ) {
+            Node* nextChild = child->nextSibling();
+            cloneParent->appendChild(child);
+            child = nextChild;
+        }
 
         // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
         // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
         transferUseAttributesToReplacedElement(use, cloneParent.get());
 
-        if (target && !isDisallowedElement(target)) {
-            RefPtr<Element> newChild = target->cloneElementWithChildren();
+        if (target) {
+            RefPtrWillBeRawPtr<Node> newChild = cloneNodeAndAssociate(*target);
             ASSERT(newChild->isSVGElement());
+            transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()), *target);
             cloneParent->appendChild(newChild.release());
         }
 
@@ -739,9 +579,9 @@ void SVGUseElement::expandUseElementsInShadowTree(Node* element)
         // Though if there are disallowed elements in the subtree, we have to remove them.
         // For instance: <use> on <g> containing <foreignObject> (indirect case).
         if (subtreeContainsDisallowedElement(cloneParent.get()))
-            removeDisallowedElementsFromSubtree(cloneParent.get());
+            removeDisallowedElementsFromSubtree(*cloneParent);
 
-        RefPtr<Node> replacingElement(cloneParent.get());
+        RefPtrWillBeRawPtr<SVGElement> replacingElement(cloneParent.get());
 
         // Replace <use> with referenced content.
         ASSERT(use->parentNode());
@@ -750,33 +590,40 @@ void SVGUseElement::expandUseElementsInShadowTree(Node* element)
         // Expand the siblings because the *element* is replaced and we will
         // lose the sibling chain when we are back from recursion.
         element = replacingElement.get();
-        for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = sibling->nextSibling())
-            expandUseElementsInShadowTree(sibling.get());
+        for (RefPtrWillBeRawPtr<SVGElement> sibling = Traversal<SVGElement>::nextSibling(*element); sibling; sibling = Traversal<SVGElement>::nextSibling(*sibling)) {
+            if (!expandUseElementsInShadowTree(sibling.get()))
+                return false;
+        }
     }
 
-    for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
-        expandUseElementsInShadowTree(child.get());
+    for (RefPtrWillBeRawPtr<SVGElement> child = Traversal<SVGElement>::firstChild(*element); child; child = Traversal<SVGElement>::nextSibling(*child)) {
+        if (!expandUseElementsInShadowTree(child.get()))
+            return false;
+    }
+    return true;
 }
 
-void SVGUseElement::expandSymbolElementsInShadowTree(Node* element)
+void SVGUseElement::expandSymbolElementsInShadowTree(SVGElement* element)
 {
-    if (element->hasTagName(SVGNames::symbolTag)) {
+    ASSERT(element);
+    if (isSVGSymbolElement(*element)) {
         // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
         // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
         // always have explicit values for attributes width and height. If attributes width and/or
         // height are provided on the 'use' element, then these attributes will be transferred to
         // the generated 'svg'. If attributes width and/or height are not specified, the generated
         // 'svg' element will use values of 100% for these attributes.
-        ASSERT(referencedDocument());
-        RefPtr<SVGSVGElement> svgElement = SVGSVGElement::create(SVGNames::svgTag, *referencedDocument());
-
+        ASSERT(referencedScope());
+        RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(referencedScope()->document());
         // Transfer all data (attributes, etc.) from <symbol> to the new <svg> element.
-        svgElement->cloneDataFromElement(*toElement(element));
-
-        // Only clone symbol children, and add them to the new <svg> element
-        for (Node* child = element->firstChild(); child; child = child->nextSibling()) {
-            RefPtr<Node> newChild = child->cloneNode(true);
-            svgElement->appendChild(newChild.release());
+        svgElement->cloneDataFromElement(*element);
+        svgElement->setCorrespondingElement(element->correspondingElement());
+
+        // Move already cloned elements to the new <svg> element
+        for (Node* child = element->firstChild(); child; ) {
+            Node* nextChild = child->nextSibling();
+            svgElement->appendChild(child);
+            child = nextChild;
         }
 
         // We don't walk the target tree element-by-element, and clone each element,
@@ -785,125 +632,37 @@ void SVGUseElement::expandSymbolElementsInShadowTree(Node* element)
         // Though if there are disallowed elements in the subtree, we have to remove them.
         // For instance: <use> on <g> containing <foreignObject> (indirect case).
         if (subtreeContainsDisallowedElement(svgElement.get()))
-            removeDisallowedElementsFromSubtree(svgElement.get());
+            removeDisallowedElementsFromSubtree(*svgElement);
 
-        RefPtr<Node> replacingElement(svgElement.get());
+        RefPtrWillBeRawPtr<SVGElement> replacingElement(svgElement.get());
 
         // Replace <symbol> with <svg>.
+        ASSERT(element->parentNode());
         element->parentNode()->replaceChild(svgElement.release(), element);
 
         // Expand the siblings because the *element* is replaced and we will
         // lose the sibling chain when we are back from recursion.
         element = replacingElement.get();
-        for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = sibling->nextSibling())
-            expandSymbolElementsInShadowTree(sibling.get());
     }
 
-    for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
+    for (RefPtrWillBeRawPtr<SVGElement> child = Traversal<SVGElement>::firstChild(*element); child; child = Traversal<SVGElement>::nextSibling(*child))
         expandSymbolElementsInShadowTree(child.get());
 }
 
-void SVGUseElement::transferEventListenersToShadowTree(SVGElementInstance* target)
-{
-    if (!target)
-        return;
-
-    SVGElement* originalElement = target->correspondingElement();
-    ASSERT(originalElement);
-
-    if (SVGElement* shadowTreeElement = target->shadowTreeElement()) {
-        if (EventTargetData* data = originalElement->eventTargetData())
-            data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(shadowTreeElement);
-    }
-
-    for (SVGElementInstance* instance = target->firstChild(); instance; instance = instance->nextSibling())
-        transferEventListenersToShadowTree(instance);
-}
-
-void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance)
-{
-    if (!target || !targetInstance)
-        return;
-
-    SVGElement* originalElement = targetInstance->correspondingElement();
-
-    if (originalElement->hasTagName(SVGNames::useTag)) {
-        // <use> gets replaced by <g>
-        ASSERT(target->nodeName() == SVGNames::gTag);
-    } else if (originalElement->hasTagName(SVGNames::symbolTag)) {
-        // <symbol> gets replaced by <svg>
-        ASSERT(target->nodeName() == SVGNames::svgTag);
-    } else
-        ASSERT(target->nodeName() == originalElement->nodeName());
-
-    SVGElement* element = 0;
-    if (target->isSVGElement())
-        element = toSVGElement(target);
-
-    ASSERT(!targetInstance->shadowTreeElement());
-    targetInstance->setShadowTreeElement(element);
-    element->setCorrespondingElement(originalElement);
-
-    Node* node = target->firstChild();
-    for (SVGElementInstance* instance = targetInstance->firstChild(); node && instance; instance = instance->nextSibling()) {
-        // Skip any non-svg elements in shadow tree
-        while (node && !node->isSVGElement())
-           node = node->nextSibling();
-
-        if (!node)
-            break;
-
-        associateInstancesWithShadowTreeElements(node, instance);
-        node = node->nextSibling();
-    }
-}
-
-SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element) const
-{
-    if (!m_targetElementInstance) {
-        ASSERT(!inDocument());
-        return 0;
-    }
-
-    return instanceForShadowTreeElement(element, m_targetElementInstance.get());
-}
-
-SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element, SVGElementInstance* instance) const
-{
-    ASSERT(element);
-    ASSERT(instance);
-
-    // We're dispatching a mutation event during shadow tree construction
-    // this instance hasn't yet been associated to a shadowTree element.
-    if (!instance->shadowTreeElement())
-        return 0;
-
-    if (element == instance->shadowTreeElement())
-        return instance;
-
-    for (SVGElementInstance* current = instance->firstChild(); current; current = current->nextSibling()) {
-        if (SVGElementInstance* search = instanceForShadowTreeElement(element, current))
-            return search;
-    }
-
-    return 0;
-}
-
 void SVGUseElement::invalidateShadowTree()
 {
     if (!inActiveDocument() || m_needsShadowTreeRecreation)
         return;
-    m_needsShadowTreeRecreation = true;
-    setNeedsStyleRecalc();
+    scheduleShadowTreeRecreation();
     invalidateDependentShadowTrees();
 }
 
 void SVGUseElement::invalidateDependentShadowTrees()
 {
     // Recursively invalidate dependent <use> shadow trees
-    const HashSet<SVGElementInstance*>& instances = instancesForElement();
-    const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
-    for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
+    const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = instancesForElement();
+    const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end();
+    for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) {
         if (SVGUseElement* element = (*it)->correspondingUseElement()) {
             ASSERT(element->inDocument());
             element->invalidateShadowTree();
@@ -927,20 +686,16 @@ void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement* from, SVG
 
 bool SVGUseElement::selfHasRelativeLengths() const
 {
-    if (xCurrentValue().isRelative()
-        || yCurrentValue().isRelative()
-        || widthCurrentValue().isRelative()
-        || heightCurrentValue().isRelative())
+    if (m_x->currentValue()->isRelative()
+        || m_y->currentValue()->isRelative()
+        || m_width->currentValue()->isRelative()
+        || m_height->currentValue()->isRelative())
         return true;
 
     if (!m_targetElementInstance)
         return false;
 
-    SVGElement* element = m_targetElementInstance->correspondingElement();
-    if (!element)
-        return false;
-
-    return element->hasRelativeLengths();
+    return m_targetElementInstance->hasRelativeLengths();
 }
 
 void SVGUseElement::notifyFinished(Resource* resource)
@@ -951,8 +706,15 @@ void SVGUseElement::notifyFinished(Resource* resource)
     invalidateShadowTree();
     if (resource->errorOccurred())
         dispatchEvent(Event::create(EventTypeNames::error));
-    else if (!resource->wasCanceled())
-        SVGExternalResourcesRequired::dispatchLoadEvent(this);
+    else if (!resource->wasCanceled()) {
+        if (m_haveFiredLoadEvent)
+            return;
+        if (!isStructurallyExternal())
+            return;
+        ASSERT(!m_haveFiredLoadEvent);
+        m_haveFiredLoadEvent = true;
+        sendSVGLoadEventIfPossibleAsynchronously();
+    }
 }
 
 bool SVGUseElement::resourceIsStillLoading()
@@ -962,29 +724,19 @@ bool SVGUseElement::resourceIsStillLoading()
     return false;
 }
 
-bool SVGUseElement::instanceTreeIsLoading(SVGElementInstance* targetElementInstance)
+bool SVGUseElement::instanceTreeIsLoading(SVGElement* targetInstance)
 {
-    for (SVGElementInstance* instance = targetElementInstance->firstChild(); instance; instance = instance->nextSibling()) {
-        if (SVGUseElement* use = instance->correspondingUseElement()) {
+    for (SVGElement* element = Traversal<SVGElement>::firstChild(*targetInstance); element; element = Traversal<SVGElement>::nextSibling(*element)) {
+        if (SVGUseElement* use = element->correspondingUseElement()) {
             if (use->resourceIsStillLoading())
                 return true;
         }
-        if (instance->hasChildNodes())
-            instanceTreeIsLoading(instance);
+        if (element->hasChildren() && instanceTreeIsLoading(element))
+            return true;
     }
     return false;
 }
 
-void SVGUseElement::finishParsingChildren()
-{
-    SVGGraphicsElement::finishParsingChildren();
-    SVGExternalResourcesRequired::finishParsingChildren();
-    if (m_wasInsertedByParser) {
-        buildPendingResource();
-        m_wasInsertedByParser = false;
-    }
-}
-
 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource)
 {
     if (m_resource == resource)
@@ -998,4 +750,10 @@ void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource)
         m_resource->addClient(this);
 }
 
+void SVGUseElement::trace(Visitor* visitor)
+{
+    visitor->trace(m_targetElementInstance);
+    SVGGraphicsElement::trace(visitor);
+}
+
 }