Index: Source/core/svg/SVGUseElement.cpp |
diff --git a/Source/core/svg/SVGUseElement.cpp b/Source/core/svg/SVGUseElement.cpp |
index f28c175db978dc501658113c903f2a6b023893f0..79a0ec49af8e8b566a4144712d731b1f437b3907 100644 |
--- a/Source/core/svg/SVGUseElement.cpp |
+++ b/Source/core/svg/SVGUseElement.cpp |
@@ -37,7 +37,6 @@ |
#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" |
@@ -81,24 +80,6 @@ SVGUseElement::~SVGUseElement() |
#endif |
} |
-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().updateRenderTreeIfNeeded(); |
- |
- return m_targetElementInstance.get(); |
-} |
- |
-SVGElementInstance* SVGUseElement::animatedInstanceRoot() const |
-{ |
- // FIXME: Implement me. |
- return 0; |
-} |
- |
bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName) |
{ |
DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); |
@@ -224,7 +205,7 @@ void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName) |
updateRelativeLengthsInformation(); |
if (m_targetElementInstance) { |
ASSERT(m_targetElementInstance->correspondingElement()); |
- transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance->shadowTreeElement(), *m_targetElementInstance->correspondingElement()); |
+ transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_targetElementInstance->correspondingElement()); |
} |
if (renderer) |
RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer); |
@@ -318,10 +299,8 @@ void SVGUseElement::scheduleShadowTreeRecreation() |
void SVGUseElement::clearResourceReferences() |
{ |
- if (m_targetElementInstance) { |
- m_targetElementInstance->detach(); |
+ if (m_targetElementInstance) |
m_targetElementInstance = nullptr; |
- } |
// FIXME: We should try to optimize this, to at least allow partial reclones. |
if (ShadowRoot* shadowTreeRootElement = userAgentShadowRoot()) |
@@ -364,6 +343,21 @@ 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); |
+ 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); |
@@ -379,75 +373,44 @@ 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); |
- |
- // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children |
- bool foundProblem = false; |
- buildInstanceTree(target, m_targetElementInstance.get(), foundProblem, false); |
+ // 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()); |
- 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(), shadowTreeRootElement); |
- |
// 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); |
- |
- // 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. |
- Node* shadowTreeTargetNode = shadowTreeRootElement->firstChild(); |
- if (!shadowTreeTargetNode) { |
+ if (!expandUseElementsInShadowTree(m_targetElementInstance.get())) { |
clearResourceReferences(); |
return; |
} |
- // Now that the shadow tree is completly expanded, we can associate |
- // shadow tree elements <-> instances in the instance tree. |
- associateInstancesWithShadowTreeElements(shadowTreeTargetNode, m_targetElementInstance.get()); |
- |
- SVGElement* shadowTreeTargetElement = toSVGElement(shadowTreeTargetNode); |
- ASSERT(shadowTreeTargetElement->correspondingElement()); |
- transferUseWidthAndHeightIfNeeded(*this, shadowTreeTargetElement, *shadowTreeTargetElement->correspondingElement()); |
+ // Expand all <symbol> elements in the shadow tree. |
+ // Expand means: replace the actual <symbol> element by the <svg> element. |
+ expandSymbolElementsInShadowTree(toSVGElement(shadowTreeRootElement->firstChild())); |
- ASSERT(shadowTreeTargetElement->parentNode() == shadowTreeRootElement); |
+ 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(shadowTreeTargetElement); |
+ ASSERT(m_targetElementInstance->parentNode() == shadowTreeRootElement); |
// Update relative length information. |
updateRelativeLengthsInformation(); |
@@ -501,20 +464,14 @@ RenderObject* SVGUseElement::rendererClipChild() const |
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 targetIsUseElement = isSVGUseElement(*target); |
- SVGElement* newTarget = 0; |
- if (targetIsUseElement) { |
- 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) { |
@@ -522,43 +479,28 @@ void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* ta |
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. |
+ targetInstance->setCorrespondingElement(target); |
- for (SVGElement* element = Traversal<SVGElement>::firstChild(*target); element; element = Traversal<SVGElement>::nextSibling(*element)) { |
+ for (Node* child = target->firstChild(); child; child = child->nextSibling()) { |
// Skip any disallowed element. |
- if (isDisallowedElement(element)) |
+ if (isDisallowedElement(child)) |
continue; |
- // Create SVGElementInstance object, for both container/non-container nodes. |
- RefPtrWillBeRawPtr<SVGElementInstance> instance = SVGElementInstance::create(this, 0, element); |
- SVGElementInstance* instancePtr = instance.get(); |
- targetInstance->appendChild(instance.release()); |
- |
- // 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 (!targetIsUseElement || !newTarget) |
- return; |
- |
- RefPtrWillBeRawPtr<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(referencedScope()); |
Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefString(), *referencedScope()); |
@@ -574,10 +516,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; |
@@ -602,26 +543,7 @@ static inline void removeDisallowedElementsFromSubtree(Element& subtree) |
} |
} |
-void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance, ShadowRoot* shadowTreeRootElement) |
-{ |
- // For instance <use> on <foreignObject> (direct case). |
- if (isDisallowedElement(target)) |
- return; |
- |
- RefPtrWillBeRawPtr<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); |
- |
- shadowTreeRootElement->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 |
@@ -635,23 +557,30 @@ void SVGUseElement::expandUseElementsInShadowTree(Node* element) |
SVGUseElement* use = toSVGUseElement(element); |
ASSERT(!use->resourceIsStillLoading()); |
- ASSERT(referencedScope()); |
- Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefString(), *referencedScope()); |
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 |
RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(referencedScope()->document()); |
- use->cloneChildNodes(cloneParent.get()); |
+ 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)) { |
- RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithChildren(); |
+ if (target) { |
+ RefPtrWillBeRawPtr<Node> newChild = cloneNodeAndAssociate(*target); |
ASSERT(newChild->isSVGElement()); |
transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()), *target); |
cloneParent->appendChild(newChild.release()); |
@@ -665,7 +594,7 @@ void SVGUseElement::expandUseElementsInShadowTree(Node* element) |
if (subtreeContainsDisallowedElement(cloneParent.get())) |
removeDisallowedElementsFromSubtree(*cloneParent); |
- RefPtrWillBeRawPtr<Node> replacingElement(cloneParent.get()); |
+ RefPtrWillBeRawPtr<SVGElement> replacingElement(cloneParent.get()); |
// Replace <use> with referenced content. |
ASSERT(use->parentNode()); |
@@ -674,15 +603,20 @@ 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 (RefPtrWillBeRawPtr<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 (RefPtrWillBeRawPtr<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) |
{ |
ASSERT(element); |
if (isSVGSymbolElement(*element)) { |
@@ -694,13 +628,16 @@ void SVGUseElement::expandSymbolElementsInShadowTree(Node* element) |
// 'svg' element will use values of 100% for these attributes. |
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()) |
- svgElement->appendChild(child->cloneNode(true)); |
+ 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, |
// but instead use cloneNode(deep=true). This is an optimization for the common |
@@ -710,68 +647,21 @@ void SVGUseElement::expandSymbolElementsInShadowTree(Node* element) |
if (subtreeContainsDisallowedElement(svgElement.get())) |
removeDisallowedElementsFromSubtree(*svgElement); |
- RefPtrWillBeRawPtr<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 (RefPtrWillBeRawPtr<Node> sibling = element->nextSibling(); sibling; sibling = sibling->nextSibling()) |
- expandSymbolElementsInShadowTree(sibling.get()); |
} |
- for (RefPtrWillBeRawPtr<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(SVGElement* shadowTreeTargetElement) |
-{ |
- if (!shadowTreeTargetElement) |
- return; |
- |
- SVGElement* originalElement = shadowTreeTargetElement->correspondingElement(); |
- ASSERT(originalElement); |
- if (EventTargetData* data = originalElement->eventTargetData()) |
- data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(shadowTreeTargetElement); |
- |
- for (SVGElement* child = Traversal<SVGElement>::firstChild(*shadowTreeTargetElement); child; child = Traversal<SVGElement>::nextSibling(*child)) |
- transferEventListenersToShadowTree(child); |
-} |
- |
-void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance) |
-{ |
- if (!target || !targetInstance) |
- return; |
- |
- SVGElement* originalElement = targetInstance->correspondingElement(); |
- ASSERT(originalElement); |
- if (isSVGUseElement(*originalElement)) { |
- // <use> gets replaced by <g> |
- ASSERT(AtomicString(target->nodeName()) == SVGNames::gTag); |
- } else if (isSVGSymbolElement(*originalElement)) { |
- // <symbol> gets replaced by <svg> |
- ASSERT(AtomicString(target->nodeName()) == SVGNames::svgTag); |
- } else { |
- ASSERT(AtomicString(target->nodeName()) == originalElement->nodeName()); |
- } |
- |
- SVGElement* element = 0; |
- if (target->isSVGElement()) |
- element = toSVGElement(target); |
- |
- ASSERT(!targetInstance->shadowTreeElement()); |
- targetInstance->setShadowTreeElement(element); |
- element->setCorrespondingElement(originalElement); |
- |
- SVGElement* child = Traversal<SVGElement>::firstChild(*target); |
- for (SVGElementInstance* instance = targetInstance->firstChild(); child && instance; instance = instance->nextSibling()) { |
- associateInstancesWithShadowTreeElements(child, instance); |
- child = Traversal<SVGElement>::nextSibling(*child); |
- } |
-} |
- |
void SVGUseElement::invalidateShadowTree() |
{ |
if (!inActiveDocument() || m_needsShadowTreeRecreation) |
@@ -818,11 +708,7 @@ bool SVGUseElement::selfHasRelativeLengths() const |
if (!m_targetElementInstance) |
return false; |
- SVGElement* element = m_targetElementInstance->shadowTreeElement(); |
- if (!element) |
- return false; |
- |
- return element->hasRelativeLengths(); |
+ return m_targetElementInstance->hasRelativeLengths(); |
} |
void SVGUseElement::notifyFinished(Resource* resource) |
@@ -851,15 +737,15 @@ 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->hasChildren()) |
- instanceTreeIsLoading(instance); |
+ if (element->hasChildren() && instanceTreeIsLoading(element)) |
+ return true; |
} |
return false; |
} |