File indexing completed on 2024-04-28 15:24:43

0001 /*
0002     Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
0003                   2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
0004 
0005     This file is part of the KDE project
0006 
0007     This library is free software; you can redistribute it and/or
0008     modify it under the terms of the GNU Library General Public
0009     License as published by the Free Software Foundation; either
0010     version 2 of the License, or (at your option) any later version.
0011 
0012     This library is distributed in the hope that it will be useful,
0013     but WITHOUT ANY WARRANTY; without even the implied warranty of
0014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015     Library General Public License for more details.
0016 
0017     You should have received a copy of the GNU Library General Public License
0018     along with this library; see the file COPYING.LIB.  If not, write to
0019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020     Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #include "wtf/Platform.h"
0024 
0025 // Dump SVGElementInstance object tree - useful to debug instanceRoot problems
0026 // #define DUMP_INSTANCE_TREE
0027 
0028 // Dump the deep-expanded shadow tree (where the renderers are built from)
0029 // #define DUMP_SHADOW_TREE
0030 
0031 #if ENABLE(SVG)
0032 #include "SVGUseElement.h"
0033 
0034 #include "css/cssstyleselector.h"
0035 /*#include "CString.h"*/
0036 #include "Document.h"
0037 /*#include "Event.h"
0038 #include "HTMLNames.h"*/
0039 #include "RenderSVGTransformableContainer.h"
0040 #include "SVGElementInstance.h"
0041 #include "SVGElementInstanceList.h"
0042 #include "SVGGElement.h"
0043 #include "SVGLength.h"
0044 #include "SVGNames.h"
0045 #include "SVGPreserveAspectRatio.h"
0046 /*#include "SVGSMILElement.h"*/
0047 #include "SVGSVGElement.h"
0048 #include "SVGSymbolElement.h"
0049 #include "XLinkNames.h"
0050 /*#include "XMLSerializer.h"*/
0051 #include <wtf/OwnPtr.h>
0052 
0053 namespace WebCore
0054 {
0055 
0056 SVGUseElement::SVGUseElement(const QualifiedName &tagName, Document *doc)
0057     : SVGStyledTransformableElement(tagName, doc)
0058     , SVGTests()
0059     , SVGLangSpace()
0060     , SVGExternalResourcesRequired()
0061     , SVGURIReference()
0062     , m_x(this, LengthModeWidth)
0063     , m_y(this, LengthModeHeight)
0064     , m_width(this, LengthModeWidth)
0065     , m_height(this, LengthModeHeight)
0066 {
0067 }
0068 
0069 SVGUseElement::~SVGUseElement()
0070 {
0071 }
0072 
0073 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, X, x, SVGNames::xAttr, m_x)
0074 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, Y, y, SVGNames::yAttr, m_y)
0075 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, Width, width, SVGNames::widthAttr, m_width)
0076 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, Height, height, SVGNames::heightAttr, m_height)
0077 
0078 SVGElementInstance *SVGUseElement::instanceRoot() const
0079 {
0080     return m_targetElementInstance.get();
0081 }
0082 
0083 SVGElementInstance *SVGUseElement::animatedInstanceRoot() const
0084 {
0085     // FIXME: Implement me.
0086     return nullptr;
0087 }
0088 
0089 void SVGUseElement::parseMappedAttribute(MappedAttribute *attr)
0090 {
0091     if (attr->name() == SVGNames::xAttr) {
0092         setXBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
0093     } else if (attr->name() == SVGNames::yAttr) {
0094         setYBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
0095     } else if (attr->name() == SVGNames::widthAttr) {
0096         setWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
0097         if (width().value() < 0.0) {
0098             document()->accessSVGExtensions()->reportError("A negative value for use attribute <width> is not allowed");
0099         }
0100     } else if (attr->name() == SVGNames::heightAttr) {
0101         setHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
0102         if (height().value() < 0.0) {
0103             document()->accessSVGExtensions()->reportError("A negative value for use attribute <height> is not allowed");
0104         }
0105     } else {
0106         if (SVGTests::parseMappedAttribute(attr)) {
0107             return;
0108         }
0109         if (SVGLangSpace::parseMappedAttribute(attr)) {
0110             return;
0111         }
0112         if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) {
0113             return;
0114         }
0115         if (SVGURIReference::parseMappedAttribute(attr)) {
0116             return;
0117         }
0118         SVGStyledTransformableElement::parseMappedAttribute(attr);
0119     }
0120 }
0121 
0122 void SVGUseElement::insertedIntoDocument()
0123 {
0124     SVGElement::insertedIntoDocument();
0125     buildPendingResource();
0126 }
0127 
0128 void SVGUseElement::removedFromDocument()
0129 {
0130     m_targetElementInstance = nullptr;
0131     m_shadowTreeRootElement = nullptr;
0132     SVGElement::removedFromDocument();
0133 }
0134 
0135 void SVGUseElement::svgAttributeChanged(const QualifiedName &attrName)
0136 {
0137     SVGStyledTransformableElement::svgAttributeChanged(attrName);
0138 
0139     if (!attached()) {
0140         return;
0141     }
0142 
0143     if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
0144             attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr ||
0145             SVGTests::isKnownAttribute(attrName) ||
0146             SVGLangSpace::isKnownAttribute(attrName) ||
0147             SVGExternalResourcesRequired::isKnownAttribute(attrName) ||
0148             SVGURIReference::isKnownAttribute(attrName) ||
0149             SVGStyledTransformableElement::isKnownAttribute(attrName)) {
0150         // TODO: Now that we're aware of the attribute name, we can finally optimize
0151         // updating <use> attributes - to not reclone every time.
0152         buildPendingResource();
0153 
0154         if (m_shadowTreeRootElement) {
0155             m_shadowTreeRootElement->setChanged();
0156         }
0157     }
0158 }
0159 
0160 void SVGUseElement::childrenChanged(bool changedByParser, Node *beforeChange, Node *afterChange, int childCountDelta)
0161 {
0162     Q_UNUSED(changedByParser);
0163     Q_UNUSED(beforeChange);
0164     Q_UNUSED(afterChange);
0165     Q_UNUSED(childCountDelta);
0166     SVGElement::childrenChanged(/*changedByParser, beforeChange, afterChange, childCountDelta*/);
0167 
0168     if (!attached()) {
0169         return;
0170     }
0171 
0172     buildPendingResource();
0173 
0174     if (m_shadowTreeRootElement) {
0175         m_shadowTreeRootElement->setChanged();
0176     }
0177 }
0178 
0179 void SVGUseElement::recalcStyle(StyleChange change)
0180 {
0181     SVGStyledElement::recalcStyle(change);
0182 
0183     // The shadow tree root element is NOT a direct child element of us.
0184     // So we have to take care it receives style updates, manually.
0185     if (!m_shadowTreeRootElement || !m_shadowTreeRootElement->attached()) {
0186         return;
0187     }
0188 
0189     // Mimic Element::recalcStyle(). The main difference is that we don't call attach() on the
0190     // shadow tree root element, but call attachShadowTree() here. Calling attach() will crash
0191     // as the shadow tree root element has no (direct) parent node. Yes, shadow trees are tricky.
0192     if (change >= Inherit || m_shadowTreeRootElement->changed()) {
0193         RenderStyle *newStyle = document()->styleSelector()->styleForElement(m_shadowTreeRootElement.get());
0194         newStyle->ref();
0195         StyleChange ch = m_shadowTreeRootElement->diff((m_shadowTreeRootElement->renderer() ? m_shadowTreeRootElement->renderer()->style() : nullptr)/*renderStyle()*/, newStyle);
0196         if (ch == Detach) {
0197             ASSERT(m_shadowTreeRootElement->attached());
0198             m_shadowTreeRootElement->detach();
0199             attachShadowTree();
0200 
0201             // attach recalulates the style for all children. No need to do it twice.
0202             m_shadowTreeRootElement->setChanged(false);
0203             m_shadowTreeRootElement->setHasChangedChild(false);
0204             newStyle->deref();
0205             return;
0206         }
0207 
0208         newStyle->deref();
0209     }
0210 
0211     // Only change==Detach needs special treatment, for anything else recalcStyle() works.
0212     m_shadowTreeRootElement->recalcStyle(change);
0213 }
0214 
0215 #ifdef DUMP_INSTANCE_TREE
0216 void dumpInstanceTree(unsigned int &depth, String &text, SVGElementInstance *targetInstance)
0217 {
0218     SVGElement *element = targetInstance->correspondingElement();
0219     ASSERT(element);
0220 
0221     String elementId = element->getIDAttribute();
0222     String elementNodeName = element->nodeName();
0223     String parentNodeName = element->parentNode() ? element->parentNode()->nodeName() : "null";
0224     String firstChildNodeName = element->firstChild() ? element->firstChild()->nodeName() : "null";
0225 
0226     for (unsigned int i = 0; i < depth; ++i) {
0227         text += "  ";
0228     }
0229 
0230     text += String::format("SVGElementInstance (parentNode=%s, firstChild=%s, correspondingElement=%s, id=%s)\n",
0231                            parentNodeName.latin1().data(), firstChildNodeName.latin1().data(), elementNodeName.latin1().data(), elementId.latin1().data());
0232 
0233     depth++;
0234 
0235     for (SVGElementInstance *instance = targetInstance->firstChild(); instance; instance = instance->nextSibling()) {
0236         dumpInstanceTree(depth, text, instance);
0237     }
0238 
0239     depth--;
0240 }
0241 #endif
0242 
0243 static bool isDisallowedElement(Node *element)
0244 {
0245     Q_UNUSED(element);
0246 #if ENABLE(SVG_FOREIGN_OBJECT)
0247     // <foreignObject> should never be contained in a <use> tree. Too dangerous side effects possible.
0248     if (element->hasTagName(SVGNames::foreignObjectTag)) {
0249         return true;
0250     }
0251 #endif
0252 #if ENABLE(SVG_ANIMATION)
0253     if (SVGSMILElement::isSMILElement(element)) {
0254         return true;
0255     }
0256 #endif
0257 
0258     return false;
0259 }
0260 
0261 static bool subtreeContainsDisallowedElement(Node *start)
0262 {
0263     if (isDisallowedElement(start)) {
0264         return true;
0265     }
0266 
0267     for (Node *cur = start->firstChild(); cur; cur = cur->nextSibling()) {
0268         if (subtreeContainsDisallowedElement(cur)) {
0269             return true;
0270         }
0271     }
0272 
0273     return false;
0274 }
0275 
0276 void SVGUseElement::buildPendingResource()
0277 {
0278     String id = SVGURIReference::getTarget(href());
0279     Element *targetElement = document()->getElementById(id);
0280 
0281     if (!targetElement) {
0282         // TODO: We want to deregister as pending resource, if our href() changed!
0283         // TODO: Move to svgAttributeChanged, once we're fixing use & the new dynamic update concept.
0284         document()->accessSVGExtensions()->addPendingResource(id, this);
0285         return;
0286     }
0287 
0288     // Do not build the shadow/instance tree for <use> elements living in a shadow tree.
0289     // The will be expanded soon anyway - see expandUseElementsInShadowTree().
0290     Node *parent = parentNode();
0291     while (parent) {
0292         if (parent->isShadowNode()) {
0293             return;
0294         }
0295 
0296         parent = parent->parentNode();
0297     }
0298 
0299     SVGElement *target = nullptr;
0300     if (targetElement && targetElement->isSVGElement()) {
0301         target = static_cast<SVGElement *>(targetElement);
0302     }
0303 
0304     // Do not allow self-referencing.
0305     // 'target' may be null, if it's a non SVG namespaced element.
0306     if (!target || target == this) {
0307         m_targetElementInstance = nullptr;
0308         m_shadowTreeRootElement = nullptr;
0309         return;
0310     }
0311 
0312     // Why a separated instance/shadow tree? SVG demands it:
0313     // The instance tree is accesable from JavaScript, and has to
0314     // expose a 1:1 copy of the referenced tree, whereas internally we need
0315     // to alter the tree for correct "use-on-symbol", "use-on-svg" support.
0316 
0317     // Build instance tree. Create root SVGElementInstance object for the first sub-tree node.
0318     //
0319     // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a
0320     // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object
0321     // is the SVGRectElement that corresponds to the referenced 'rect' element.
0322     m_targetElementInstance = new SVGElementInstance(this, target);
0323 
0324     // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
0325     bool foundProblem = false;
0326     buildInstanceTree(target, m_targetElementInstance.get(), foundProblem);
0327 
0328     // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it!
0329     // Non-appearing <use> content is easier to debug, then half-appearing content.
0330     if (foundProblem) {
0331         m_targetElementInstance = nullptr;
0332         m_shadowTreeRootElement = nullptr;
0333         return;
0334     }
0335 
0336     // Assure instance tree building was successful
0337     ASSERT(m_targetElementInstance);
0338     ASSERT(m_targetElementInstance->correspondingUseElement() == this);
0339 
0340     // Setup shadow tree root node
0341     m_shadowTreeRootElement = new SVGGElement(SVGNames::gTag, document());
0342     m_shadowTreeRootElement->setInDocument();
0343     m_shadowTreeRootElement->setShadowParentNode(this);
0344 
0345     // Spec: An additional transformation translate(x,y) is appended to the end
0346     // (i.e., right-side) of the transform attribute on the generated 'g', where x
0347     // and y represent the values of the x and y attributes on the 'use' element.
0348     if (x().value() != 0.0 || y().value() != 0.0) {
0349         String transformString = String::format("translate(%f, %f)", x().value(), y().value());
0350         m_shadowTreeRootElement->setAttribute(SVGNames::transformAttr, transformString);
0351     }
0352 
0353     // Build shadow tree from instance tree
0354     // This also handles the special cases: <use> on <symbol>, <use> on <svg>.
0355     buildShadowTree(target, m_targetElementInstance.get());
0356 
0357 #if ENABLE(SVG) && ENABLE(SVG_USE)
0358     // Expand all <use> elements in the shadow tree.
0359     // Expand means: replace the actual <use> element by what it references.
0360     expandUseElementsInShadowTree(m_shadowTreeRootElement.get());
0361 
0362     // Expand all <symbol> elements in the shadow tree.
0363     // Expand means: replace the actual <symbol> element by the <svg> element.
0364     expandSymbolElementsInShadowTree(m_shadowTreeRootElement.get());
0365 
0366 #endif
0367 
0368     // Now that the shadow tree is completely expanded, we can associate
0369     // shadow tree elements <-> instances in the instance tree.
0370     associateInstancesWithShadowTreeElements(m_shadowTreeRootElement->firstChild(), m_targetElementInstance.get());
0371 
0372     // Eventually dump instance tree
0373 #ifdef DUMP_INSTANCE_TREE
0374     String text;
0375     unsigned int depth = 0;
0376 
0377     dumpInstanceTree(depth, text, m_targetElementInstance.get());
0378     fprintf(stderr, "\nDumping <use> instance tree:\n%s\n", text.latin1().data());
0379 #endif
0380 
0381     // Eventually dump shadow tree
0382 #ifdef DUMP_SHADOW_TREE
0383     ExceptionCode ec = 0;
0384 
0385     PassRefPtr<XMLSerializer> serializer = XMLSerializer::create();
0386 
0387     String markup = serializer->serializeToString(m_shadowTreeRootElement.get(), ec);
0388     ASSERT(ec == 0);
0389 
0390     fprintf(stderr, "Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data());
0391 #endif
0392 
0393     // The DOM side is setup properly. Now we have to attach the root shadow
0394     // tree element manually - using attach() won't work for "shadow nodes".
0395     attachShadowTree();
0396 }
0397 
0398 RenderObject *SVGUseElement::createRenderer(RenderArena *arena, RenderStyle *)
0399 {
0400     return new(arena) RenderSVGTransformableContainer(this);
0401 }
0402 
0403 void SVGUseElement::attach()
0404 {
0405     SVGStyledTransformableElement::attach();
0406 
0407     // If we're a pending resource, this doesn't have any effect.
0408     attachShadowTree();
0409 }
0410 
0411 void SVGUseElement::detach()
0412 {
0413     if (m_shadowTreeRootElement) {
0414         m_shadowTreeRootElement->detach();
0415     }
0416 
0417     SVGStyledTransformableElement::detach();
0418 }
0419 
0420 static bool isDirectReference(Node *n)
0421 {
0422     return n->hasTagName(SVGNames::pathTag) ||
0423            n->hasTagName(SVGNames::rectTag) ||
0424            n->hasTagName(SVGNames::circleTag) ||
0425            n->hasTagName(SVGNames::ellipseTag) ||
0426            n->hasTagName(SVGNames::polygonTag) ||
0427            n->hasTagName(SVGNames::polylineTag) ||
0428            n->hasTagName(SVGNames::textTag);
0429 }
0430 
0431 Path SVGUseElement::toClipPath() const
0432 {
0433     if (!m_shadowTreeRootElement) {
0434         const_cast<SVGUseElement *>(this)->buildPendingResource();
0435     }
0436 
0437     if (!m_shadowTreeRootElement) {
0438         return Path();
0439     }
0440 
0441     Node *n = m_shadowTreeRootElement->firstChild();
0442     if (n->isSVGElement() && static_cast<SVGElement *>(n)->isStyledTransformable()) {
0443         if (!isDirectReference(n))
0444             // Spec: Indirect references are an error (14.3.5)
0445         {
0446             document()->accessSVGExtensions()->reportError("Not allowed to use indirect reference in <clip-path>");
0447         } else {
0448             return static_cast<SVGStyledTransformableElement *>(n)->toClipPath();
0449         }
0450     }
0451 
0452     return Path();
0453 }
0454 
0455 void SVGUseElement::buildInstanceTree(SVGElement *target, SVGElementInstance *targetInstance, bool &foundProblem)
0456 {
0457     ASSERT(target);
0458     ASSERT(targetInstance);
0459 
0460     // A general description from the SVG spec, describing what buildInstanceTree() actually does.
0461     //
0462     // Spec: If the 'use' element references a 'g' which contains two 'rect' elements, then the instance tree
0463     // contains three SVGElementInstance objects, a root SVGElementInstance object whose correspondingElement
0464     // is the SVGGElement object for the 'g', and then two child SVGElementInstance objects, each of which has
0465     // its correspondingElement that is an SVGRectElement object.
0466 
0467     for (Node *node = target->firstChild(); node; node = node->nextSibling()) {
0468         SVGElement *element = nullptr;
0469         if (node->isSVGElement()) {
0470             element = static_cast<SVGElement *>(node);
0471         }
0472 
0473         // Skip any non-svg nodes or any disallowed element.
0474         if (!element || isDisallowedElement(element)) {
0475             continue;
0476         }
0477 
0478         // Create SVGElementInstance object, for both container/non-container nodes.
0479         SVGElementInstance *instancePtr = new SVGElementInstance(this, element);
0480 
0481         RefPtr<SVGElementInstance> instance = instancePtr;
0482         targetInstance->appendChild(instance.release());
0483 
0484         // Enter recursion, appending new instance tree nodes to the "instance" object.
0485         if (element->hasChildNodes()) {
0486             buildInstanceTree(element, instancePtr, foundProblem);
0487         }
0488 
0489         // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
0490         // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
0491         if (element->hasTagName(SVGNames::useTag)) {
0492             handleDeepUseReferencing(element, instancePtr, foundProblem);
0493         }
0494     }
0495 
0496     // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
0497     // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
0498     if (target->hasTagName(SVGNames::useTag)) {
0499         handleDeepUseReferencing(target, targetInstance, foundProblem);
0500     }
0501 }
0502 
0503 void SVGUseElement::handleDeepUseReferencing(SVGElement *use, SVGElementInstance *targetInstance, bool &foundProblem)
0504 {
0505     String id = SVGURIReference::getTarget(use->href());
0506     Element *targetElement = document()->getElementById(id);
0507     SVGElement *target = nullptr;
0508     if (targetElement && targetElement->isSVGElement()) {
0509         target = static_cast<SVGElement *>(targetElement);
0510     }
0511 
0512     if (!target) {
0513         return;
0514     }
0515 
0516     // Cycle detection first!
0517     foundProblem = (target == this);
0518 
0519     // Shortcut for self-references
0520     if (foundProblem) {
0521         return;
0522     }
0523 
0524     SVGElementInstance *instance = targetInstance->parentNode();
0525     while (instance) {
0526         SVGElement *element = instance->correspondingElement();
0527 
0528         if (element->getIDAttribute() == id) {
0529             foundProblem = true;
0530             return;
0531         }
0532 
0533         instance = instance->parentNode();
0534     }
0535 
0536     // Create an instance object, even if we're dealing with a cycle
0537     SVGElementInstance *newInstance = new SVGElementInstance(this, target);
0538     targetInstance->appendChild(newInstance);
0539 
0540     // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
0541     buildInstanceTree(target, newInstance, foundProblem);
0542 }
0543 
0544 void SVGUseElement::alterShadowTreeForSVGTag(SVGElement *target)
0545 {
0546     String widthString = String::number(width().value());
0547     String heightString = String::number(height().value());
0548 
0549     if (hasAttribute(SVGNames::widthAttr)) {
0550         target->setAttribute(SVGNames::widthAttr, widthString);
0551     }
0552 
0553     if (hasAttribute(SVGNames::heightAttr)) {
0554         target->setAttribute(SVGNames::heightAttr, heightString);
0555     }
0556 }
0557 
0558 void SVGUseElement::removeDisallowedElementsFromSubtree(Node *subtree)
0559 {
0560     Q_UNUSED(subtree);
0561     // Implement me: khtml, NodeImpl::traverseNextSibling
0562     /*ASSERT(!subtree->inDocument());
0563     ExceptionCode ec;
0564     Node* node = subtree->firstChild();
0565     while (node) {
0566         if (isDisallowedElement(node)) {
0567             Node* next = node->traverseNextSibling(subtree);
0568             // The subtree is not in document so this won't generate events that could mutate the tree.
0569             node->parent()->removeChild(node, ec);
0570             node = next;
0571         } else
0572             node = node->traverseNextNode(subtree);
0573     }*/
0574 }
0575 
0576 void SVGUseElement::buildShadowTree(SVGElement *target, SVGElementInstance *targetInstance)
0577 {
0578     // For instance <use> on <foreignObject> (direct case).
0579     if (isDisallowedElement(target)) {
0580         return;
0581     }
0582 
0583     PassRefPtr<NodeImpl> newChild = targetInstance->correspondingElement()->cloneNode(true);
0584 
0585     // We don't walk the target tree element-by-element, and clone each element,
0586     // but instead use cloneNode(deep=true). This is an optimization for the common
0587     // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
0588     // Though if there are disallowed elements in the subtree, we have to remove them.
0589     // For instance: <use> on <g> containing <foreignObject> (indirect case).
0590     if (subtreeContainsDisallowedElement(newChild.get())) {
0591         removeDisallowedElementsFromSubtree(newChild.get());
0592     }
0593 
0594     SVGElement *newChildPtr = nullptr;
0595     if (newChild->isSVGElement()) {
0596         newChildPtr = static_cast<SVGElement *>(newChild.get());
0597     }
0598     ASSERT(newChildPtr);
0599 
0600     /*ExceptionCode*//*khtml*/int ec = 0;
0601     m_shadowTreeRootElement->appendChild(newChild.releaseRef(), ec);
0602     ASSERT(ec == 0);
0603 
0604     // Handle use referencing <svg> special case
0605     if (target->hasTagName(SVGNames::svgTag)) {
0606         alterShadowTreeForSVGTag(newChildPtr);
0607     }
0608 }
0609 
0610 #if ENABLE(SVG) && ENABLE(SVG_USE)
0611 void SVGUseElement::expandUseElementsInShadowTree(Node *element)
0612 {
0613     // Why expand the <use> elements in the shadow tree here, and not just
0614     // do this directly in buildShadowTree, if we encounter a <use> element?
0615     //
0616     // Short answer: Because we may miss to expand some elements. Ie. if a <symbol>
0617     // contains <use> tags, we'd miss them. So once we're done with settin' up the
0618     // actual shadow tree (after the special case modification for svg/symbol) we have
0619     // to walk it completely and expand all <use> elements.
0620     if (element->hasTagName(SVGNames::useTag)) {
0621         SVGUseElement *use = static_cast<SVGUseElement *>(element);
0622 
0623         String id = SVGURIReference::getTarget(use->href());
0624         Element *targetElement = document()->getElementById(id);
0625         SVGElement *target = 0;
0626         if (targetElement && targetElement->isSVGElement()) {
0627             target = static_cast<SVGElement *>(targetElement);
0628         }
0629 
0630         // Don't ASSERT(target) here, it may be "pending", too.
0631         if (target) {
0632             // Setup sub-shadow tree root node
0633             RefPtr<SVGElement> cloneParent = new SVGGElement(SVGNames::gTag, document());
0634 
0635             // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
0636             // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
0637             transferUseAttributesToReplacedElement(use, cloneParent.get());
0638 
0639             // Spec: An additional transformation translate(x,y) is appended to the end
0640             // (i.e., right-side) of the transform attribute on the generated 'g', where x
0641             // and y represent the values of the x and y attributes on the 'use' element.
0642             if (use->x().value() != 0.0 || use->y().value() != 0.0) {
0643                 if (!cloneParent->hasAttribute(SVGNames::transformAttr)) {
0644                     String transformString = String::format("translate(%f, %f)", use->x().value(), use->y().value());
0645                     cloneParent->setAttribute(SVGNames::transformAttr, transformString);
0646                 } else {
0647                     String transformString = String::format(" translate(%f, %f)", use->x().value(), use->y().value());
0648                     const AtomicString &transformAttribute = cloneParent->getAttribute(SVGNames::transformAttr);
0649                     cloneParent->setAttribute(SVGNames::transformAttr, transformAttribute + transformString);
0650                 }
0651             }
0652 
0653             ExceptionCode ec = 0;
0654 
0655             // For instance <use> on <foreignObject> (direct case).
0656             if (isDisallowedElement(target)) {
0657                 // We still have to setup the <use> replacment (<g>). Otherwhise
0658                 // associateInstancesWithShadowTreeElements() makes wrong assumptions.
0659                 // Replace <use> with referenced content.
0660                 ASSERT(use->parentNode());
0661                 use->parentNode()->replaceChild(cloneParent.release(), use, ec);
0662                 ASSERT(ec == 0);
0663                 return;
0664             }
0665 
0666             RefPtr<Node> newChild = target->cloneNode(true);
0667 
0668             // We don't walk the target tree element-by-element, and clone each element,
0669             // but instead use cloneNode(deep=true). This is an optimization for the common
0670             // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
0671             // Though if there are disallowed elements in the subtree, we have to remove them.
0672             // For instance: <use> on <g> containing <foreignObject> (indirect case).
0673             if (subtreeContainsDisallowedElement(newChild.get())) {
0674                 removeDisallowedElementsFromSubtree(newChild.get());
0675             }
0676 
0677             SVGElement *newChildPtr = 0;
0678             if (newChild->isSVGElement()) {
0679                 newChildPtr = static_cast<SVGElement *>(newChild.get());
0680             }
0681             ASSERT(newChildPtr);
0682 
0683             cloneParent->appendChild(newChild.release(), ec);
0684             ASSERT(ec == 0);
0685 
0686             // Replace <use> with referenced content.
0687             ASSERT(use->parentNode());
0688             use->parentNode()->replaceChild(cloneParent.release(), use, ec);
0689             ASSERT(ec == 0);
0690 
0691             // Handle use referencing <svg> special case
0692             if (target->hasTagName(SVGNames::svgTag)) {
0693                 alterShadowTreeForSVGTag(newChildPtr);
0694             }
0695 
0696             // Immediately stop here, and restart expanding.
0697             expandUseElementsInShadowTree(m_shadowTreeRootElement.get());
0698             return;
0699         }
0700     }
0701 
0702     for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling()) {
0703         expandUseElementsInShadowTree(child.get());
0704     }
0705 }
0706 
0707 void SVGUseElement::expandSymbolElementsInShadowTree(Node *element)
0708 {
0709     if (element->hasTagName(SVGNames::symbolTag)) {
0710         // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
0711         // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
0712         // always have explicit values for attributes width and height. If attributes width and/or
0713         // height are provided on the 'use' element, then these attributes will be transferred to
0714         // the generated 'svg'. If attributes width and/or height are not specified, the generated
0715         // 'svg' element will use values of 100% for these attributes.
0716         RefPtr<SVGSVGElement> svgElement = new SVGSVGElement(SVGNames::svgTag, document());
0717 
0718         // Transfer all attributes from <symbol> to the new <svg> element
0719         svgElement->attributes()->setAttributes(*element->attributes());
0720 
0721         // Explicitly re-set width/height values
0722         String widthString = String::number(width().value());
0723         String heightString = String::number(height().value());
0724 
0725         svgElement->setAttribute(SVGNames::widthAttr, hasAttribute(SVGNames::widthAttr) ? widthString : "100%");
0726         svgElement->setAttribute(SVGNames::heightAttr, hasAttribute(SVGNames::heightAttr) ? heightString : "100%");
0727 
0728         ExceptionCode ec = 0;
0729 
0730         // Only clone symbol children, and add them to the new <svg> element
0731         for (Node *child = element->firstChild(); child; child = child->nextSibling()) {
0732             RefPtr<Node> newChild = child->cloneNode(true);
0733             svgElement->appendChild(newChild.release(), ec);
0734             ASSERT(ec == 0);
0735         }
0736 
0737         // We don't walk the target tree element-by-element, and clone each element,
0738         // but instead use cloneNode(deep=true). This is an optimization for the common
0739         // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
0740         // Though if there are disallowed elements in the subtree, we have to remove them.
0741         // For instance: <use> on <g> containing <foreignObject> (indirect case).
0742         if (subtreeContainsDisallowedElement(svgElement.get())) {
0743             removeDisallowedElementsFromSubtree(svgElement.get());
0744         }
0745 
0746         // Replace <symbol> with <svg>.
0747         ASSERT(element->parentNode());
0748         element->parentNode()->replaceChild(svgElement.release(), element, ec);
0749         ASSERT(ec == 0);
0750 
0751         // Immediately stop here, and restart expanding.
0752         expandSymbolElementsInShadowTree(m_shadowTreeRootElement.get());
0753         return;
0754     }
0755 
0756     for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling()) {
0757         expandSymbolElementsInShadowTree(child.get());
0758     }
0759 }
0760 
0761 #endif
0762 
0763 void SVGUseElement::attachShadowTree()
0764 {
0765     if (!m_shadowTreeRootElement || m_shadowTreeRootElement->attached() || /*khtml !document()->shouldCreateRenderers() ||*/ !attached() || !renderer()) {
0766         return;
0767     }
0768 
0769     // Inspired by RenderTextControl::createSubtreeIfNeeded().
0770     if (renderer()->childAllowed()/*canHaveChildren()*/ && childShouldCreateRenderer(m_shadowTreeRootElement.get())) {
0771         RenderStyle *style = m_shadowTreeRootElement->styleForRenderer(renderer());
0772         style->ref();
0773 
0774         if (m_shadowTreeRootElement->rendererIsNeeded(style)) {
0775             m_shadowTreeRootElement->setRenderer(m_shadowTreeRootElement->createRenderer(document()->renderArena(), style));
0776             if (RenderObject *shadowRenderer = m_shadowTreeRootElement->renderer()) {
0777                 shadowRenderer->setStyle(style);
0778                 renderer()->addChild(shadowRenderer, m_shadowTreeRootElement->nextRenderer());
0779                 m_shadowTreeRootElement->setAttached();
0780             }
0781         }
0782 
0783         style->deref();
0784 
0785         // This will take care of attaching all shadow tree child nodes.
0786         for (Node *child = m_shadowTreeRootElement->firstChild(); child; child = child->nextSibling()) {
0787             child->attach();
0788         }
0789     }
0790 }
0791 
0792 void SVGUseElement::associateInstancesWithShadowTreeElements(Node *target, SVGElementInstance *targetInstance)
0793 {
0794     if (!target || !targetInstance) {
0795         return;
0796     }
0797 
0798     SVGElement *originalElement = targetInstance->correspondingElement();
0799 
0800     if (originalElement->hasTagName(SVGNames::useTag)) {
0801 #if ENABLE(SVG) && ENABLE(SVG_USE)
0802         // <use> gets replaced by <g>
0803         /*ASSERT(target->nodeName() == SVGNames::gTag);*/
0804 #else
0805         /*ASSERT(target->nodeName() == SVGNames::gTag || target->nodeName() == SVGNames::useTag);*/
0806 #endif
0807     } else if (originalElement->hasTagName(SVGNames::symbolTag)) {
0808         // <symbol> gets replaced by <svg>
0809 #if ENABLE(SVG) && ENABLE(SVG_USE) && ENABLE(SVG_FOREIGN_OBJECT)
0810         ASSERT(target->nodeName() == SVGNames::svgTag);
0811 #endif
0812     } else {
0813         ASSERT(target->nodeName() == originalElement->nodeName());
0814     }
0815 
0816     SVGElement *element = nullptr;
0817     if (target->isSVGElement()) {
0818         element = static_cast<SVGElement *>(target);
0819     }
0820 
0821     ASSERT(!targetInstance->shadowTreeElement());
0822     targetInstance->setShadowTreeElement(element);
0823 
0824     Node *node = target->firstChild();
0825     for (SVGElementInstance *instance = targetInstance->firstChild(); node && instance; instance = instance->nextSibling()) {
0826         // Skip any non-svg elements in shadow tree
0827         while (node && !node->isSVGElement()) {
0828             node = node->nextSibling();
0829         }
0830 
0831         associateInstancesWithShadowTreeElements(node, instance);
0832         node = node->nextSibling();
0833     }
0834 }
0835 
0836 SVGElementInstance *SVGUseElement::instanceForShadowTreeElement(Node *element) const
0837 {
0838     return instanceForShadowTreeElement(element, m_targetElementInstance.get());
0839 }
0840 
0841 SVGElementInstance *SVGUseElement::instanceForShadowTreeElement(Node *element, SVGElementInstance *instance) const
0842 {
0843     ASSERT(element);
0844     ASSERT(instance);
0845     ASSERT(instance->shadowTreeElement());
0846 
0847     if (element == instance->shadowTreeElement()) {
0848         return instance;
0849     }
0850 
0851     for (SVGElementInstance *current = instance->firstChild(); current; current = current->nextSibling()) {
0852         SVGElementInstance *search = instanceForShadowTreeElement(element, current);
0853         if (search) {
0854             return search;
0855         }
0856     }
0857 
0858     return nullptr;
0859 }
0860 
0861 void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement *from, SVGElement *to) const
0862 {
0863     Q_UNUSED(from);
0864     Q_UNUSED(to);
0865     // Implement me: khtml
0866     /*ASSERT(from);
0867     ASSERT(to);
0868 
0869     to->attributes()->setAttributes(*from->attributes());
0870 
0871     ExceptionCode ec = 0;
0872 
0873     to->removeAttribute(SVGNames::xAttr, ec);
0874     ASSERT(ec == 0);
0875 
0876     to->removeAttribute(SVGNames::yAttr, ec);
0877     ASSERT(ec == 0);
0878 
0879     to->removeAttribute(SVGNames::widthAttr, ec);
0880     ASSERT(ec == 0);
0881 
0882     to->removeAttribute(SVGNames::heightAttr, ec);
0883     ASSERT(ec == 0);
0884 
0885     to->removeAttribute(XLinkNames::hrefAttr, ec);
0886     ASSERT(ec == 0);*/
0887 }
0888 
0889 }
0890 
0891 #endif // ENABLE(SVG)