2 Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
5 This file is part of the KDE project
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
25 // Dump SVGElementInstance object tree - useful to debug instanceRoot problems
26 // #define DUMP_INSTANCE_TREE
28 // Dump the deep-expanded shadow tree (where the renderes are built from)
29 // #define DUMP_SHADOW_TREE
32 #include "SVGUseElement.h"
34 #include "CSSStyleSelector.h"
38 #include "HTMLNames.h"
39 #include "RenderSVGTransformableContainer.h"
40 #include "SVGElementInstance.h"
41 #include "SVGElementInstanceList.h"
42 #include "SVGGElement.h"
43 #include "SVGLength.h"
45 #include "SVGPreserveAspectRatio.h"
46 #include "SVGSVGElement.h"
47 #include "SVGSymbolElement.h"
48 #include "XLinkNames.h"
49 #include "XMLSerializer.h"
50 #include <wtf/OwnPtr.h>
54 SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document* doc)
55 : SVGStyledTransformableElement(tagName, doc)
58 , SVGExternalResourcesRequired()
60 , m_x(this, LengthModeWidth)
61 , m_y(this, LengthModeHeight)
62 , m_width(this, LengthModeWidth)
63 , m_height(this, LengthModeHeight)
67 SVGUseElement::~SVGUseElement()
71 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, X, x, SVGNames::xAttr.localName(), m_x)
72 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, Y, y, SVGNames::yAttr.localName(), m_y)
73 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, Width, width, SVGNames::widthAttr.localName(), m_width)
74 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, Height, height, SVGNames::heightAttr.localName(), m_height)
76 SVGElementInstance* SVGUseElement::instanceRoot() const
78 return m_targetElementInstance.get();
81 SVGElementInstance* SVGUseElement::animatedInstanceRoot() const
83 // FIXME: Implement me.
87 void SVGUseElement::parseMappedAttribute(MappedAttribute* attr)
89 if (attr->name() == SVGNames::xAttr)
90 setXBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
91 else if (attr->name() == SVGNames::yAttr)
92 setYBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
93 else if (attr->name() == SVGNames::widthAttr) {
94 setWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
95 if (width().value() < 0.0)
96 document()->accessSVGExtensions()->reportError("A negative value for use attribute <width> is not allowed");
97 } else if (attr->name() == SVGNames::heightAttr) {
98 setHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
99 if (height().value() < 0.0)
100 document()->accessSVGExtensions()->reportError("A negative value for use attribute <height> is not allowed");
102 if (SVGTests::parseMappedAttribute(attr))
104 if (SVGLangSpace::parseMappedAttribute(attr))
106 if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
108 if (SVGURIReference::parseMappedAttribute(attr))
110 SVGStyledTransformableElement::parseMappedAttribute(attr);
114 void SVGUseElement::insertedIntoDocument()
116 SVGElement::insertedIntoDocument();
118 String id = SVGURIReference::getTarget(href());
119 Element* targetElement = document()->getElementById(id);
120 if (!targetElement) {
121 document()->accessSVGExtensions()->addPendingResource(id, this);
125 buildPendingResource();
128 void SVGUseElement::removedFromDocument()
130 SVGElement::removedFromDocument();
132 m_targetElementInstance = 0;
133 m_shadowTreeRootElement = 0;
136 void SVGUseElement::attributeChanged(Attribute* attr, bool preserveDecls)
138 // Avoid calling SVGStyledElement::attributeChanged(), as it always calls notifyAttributeChange.
139 SVGElement::attributeChanged(attr, preserveDecls);
144 // Only update the tree if x/y/width/height or xlink:href changed.
145 if (attr->name() == SVGNames::xAttr || attr->name() == SVGNames::yAttr ||
146 attr->name() == SVGNames::widthAttr || attr->name() == SVGNames::heightAttr ||
147 attr->name().matches(XLinkNames::hrefAttr))
148 buildPendingResource();
149 else if (m_shadowTreeRootElement)
150 m_shadowTreeRootElement->setChanged();
153 void SVGUseElement::notifyAttributeChange() const
158 // NOTE: A lot of room for improvments here. This is too slow.
159 // It has to be done correctly, by implementing attributeChanged().
160 const_cast<SVGUseElement*>(this)->buildPendingResource();
162 if (m_shadowTreeRootElement)
163 m_shadowTreeRootElement->setChanged();
166 void SVGUseElement::recalcStyle(StyleChange change)
168 SVGStyledElement::recalcStyle(change);
170 // The shadow tree root element is NOT a direct child element of us.
171 // So we have to take care it receives style updates, manually.
172 if (!m_shadowTreeRootElement || !m_shadowTreeRootElement->attached())
175 // Mimic Element::recalcStyle(). The main difference is that we don't call attach() on the
176 // shadow tree root element, but call attachShadowTree() here. Calling attach() will crash
177 // as the shadow tree root element has no (direct) parent node. Yes, shadow trees are tricky.
178 if (change >= Inherit || m_shadowTreeRootElement->changed()) {
179 RenderStyle* newStyle = document()->styleSelector()->styleForElement(m_shadowTreeRootElement.get());
180 StyleChange ch = m_shadowTreeRootElement->diff(m_shadowTreeRootElement->renderStyle(), newStyle);
182 ASSERT(m_shadowTreeRootElement->attached());
183 m_shadowTreeRootElement->detach();
186 // attach recalulates the style for all children. No need to do it twice.
187 m_shadowTreeRootElement->setChanged(NoStyleChange);
188 m_shadowTreeRootElement->setHasChangedChild(false);
189 newStyle->deref(document()->renderArena());
193 newStyle->deref(document()->renderArena());
196 // Only change==Detach needs special treatment, for anything else recalcStyle() works.
197 m_shadowTreeRootElement->recalcStyle(change);
200 #ifdef DUMP_INSTANCE_TREE
201 void dumpInstanceTree(unsigned int& depth, String& text, SVGElementInstance* targetInstance)
203 SVGElement* element = targetInstance->correspondingElement();
206 String elementId = element->getIDAttribute();
207 String elementNodeName = element->nodeName();
208 String parentNodeName = element->parentNode() ? element->parentNode()->nodeName() : "null";
209 String firstChildNodeName = element->firstChild() ? element->firstChild()->nodeName() : "null";
211 for (unsigned int i = 0; i < depth; ++i)
214 text += String::format("SVGElementInstance (parentNode=%s, firstChild=%s, correspondingElement=%s, id=%s)\n",
215 parentNodeName.latin1().data(), firstChildNodeName.latin1().data(), elementNodeName.latin1().data(), elementId.latin1().data());
219 for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
220 dumpInstanceTree(depth, text, instance);
226 static bool isDisallowedElement(Node* element)
228 // <foreignObject> should never be contained in a <use> tree. Too dangerous side effects possible.
229 if (element->hasTagName(SVGNames::foreignObjectTag))
235 static bool subtreeContainsDisallowedElement(Node* start)
237 if (isDisallowedElement(start))
240 for (Node* cur = start->firstChild(); cur; cur = cur->nextSibling()) {
241 if (subtreeContainsDisallowedElement(cur))
248 void SVGUseElement::buildPendingResource()
250 // Do not build the shadow/instance tree for <use> elements living in a shadow tree.
251 // The will be expanded soon anyway - see expandUseElementsInShadowTree().
252 Node* parent = parentNode();
254 if (parent->isShadowNode())
257 parent = parent->parentNode();
260 String id = SVGURIReference::getTarget(href());
261 Element* targetElement = document()->getElementById(id);
262 SVGElement* target = 0;
263 if (targetElement && targetElement->isSVGElement())
264 target = static_cast<SVGElement*>(targetElement);
266 // Do not allow self-referencing.
267 // 'target' may be null, if it's a non SVG namespaced element.
268 if (!target || target == this) {
269 m_targetElementInstance = 0;
270 m_shadowTreeRootElement = 0;
274 // Why a seperated instance/shadow tree? SVG demands it:
275 // The instance tree is accesable from JavaScript, and has to
276 // expose a 1:1 copy of the referenced tree, whereas internally we need
277 // to alter the tree for correct "use-on-symbol", "use-on-svg" support.
279 // Build instance tree. Create root SVGElementInstance object for the first sub-tree node.
281 // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a
282 // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object
283 // is the SVGRectElement that corresponds to the referenced 'rect' element.
284 m_targetElementInstance = new SVGElementInstance(this, target);
286 // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
287 bool foundProblem = false;
288 buildInstanceTree(target, m_targetElementInstance.get(), foundProblem);
290 // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it!
291 // Non-appearing <use> content is easier to debug, then half-appearing content.
293 m_targetElementInstance = 0;
294 m_shadowTreeRootElement = 0;
298 // Assure instance tree building was successfull
299 ASSERT(m_targetElementInstance);
300 ASSERT(m_targetElementInstance->correspondingUseElement() == this);
302 // Setup shadow tree root node
303 m_shadowTreeRootElement = new SVGGElement(SVGNames::gTag, document());
304 m_shadowTreeRootElement->setInDocument();
305 m_shadowTreeRootElement->setShadowParentNode(this);
307 // Spec: An additional transformation translate(x,y) is appended to the end
308 // (i.e., right-side) of the transform attribute on the generated 'g', where x
309 // and y represent the values of the x and y attributes on the 'use' element.
310 if (x().value() != 0.0 || y().value() != 0.0) {
311 String transformString = String::format("translate(%f, %f)", x().value(), y().value());
312 m_shadowTreeRootElement->setAttribute(SVGNames::transformAttr, transformString);
315 // Build shadow tree from instance tree
316 // This also handles the special cases: <use> on <symbol>, <use> on <svg>.
317 buildShadowTree(target, m_targetElementInstance.get());
319 #if ENABLE(SVG) && ENABLE(SVG_USE)
320 // Expand all <use> elements in the shadow tree.
321 // Expand means: replace the actual <use> element by what it references.
322 expandUseElementsInShadowTree(m_shadowTreeRootElement.get());
324 // Expand all <symbol> elements in the shadow tree.
325 // Expand means: replace the actual <symbol> element by the <svg> element.
326 expandSymbolElementsInShadowTree(m_shadowTreeRootElement.get());
330 // Now that the shadow tree is completly expanded, we can associate
331 // shadow tree elements <-> instances in the instance tree.
332 associateInstancesWithShadowTreeElements(m_shadowTreeRootElement->firstChild(), m_targetElementInstance.get());
334 // Eventually dump instance tree
335 #ifdef DUMP_INSTANCE_TREE
337 unsigned int depth = 0;
339 dumpInstanceTree(depth, text, m_targetElementInstance.get());
340 fprintf(stderr, "\nDumping <use> instance tree:\n%s\n", text.latin1().data());
343 // Eventually dump shadow tree
344 #ifdef DUMP_SHADOW_TREE
345 ExceptionCode ec = 0;
346 OwnPtr<XMLSerializer> serializer(new XMLSerializer());
348 String markup = serializer->serializeToString(m_shadowTreeRootElement.get(), ec);
351 fprintf(stderr, "Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data());
354 // The DOM side is setup properly. Now we have to attach the root shadow
355 // tree element manually - using attach() won't work for "shadow nodes".
359 RenderObject* SVGUseElement::createRenderer(RenderArena* arena, RenderStyle*)
361 return new (arena) RenderSVGTransformableContainer(this);
364 void SVGUseElement::attach()
366 SVGStyledTransformableElement::attach();
368 // If we're a pending resource, this doesn't have any effect.
372 void SVGUseElement::detach()
374 SVGStyledTransformableElement::detach();
376 if (m_shadowTreeRootElement)
377 m_shadowTreeRootElement->detach();
380 void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* targetInstance, bool& foundProblem)
383 ASSERT(targetInstance);
385 // A general description from the SVG spec, describing what buildInstanceTree() actually does.
387 // Spec: If the 'use' element references a 'g' which contains two 'rect' elements, then the instance tree
388 // contains three SVGElementInstance objects, a root SVGElementInstance object whose correspondingElement
389 // is the SVGGElement object for the 'g', and then two child SVGElementInstance objects, each of which has
390 // its correspondingElement that is an SVGRectElement object.
392 for (Node* node = target->firstChild(); node; node = node->nextSibling()) {
393 SVGElement* element = 0;
394 if (node->isSVGElement())
395 element = static_cast<SVGElement*>(node);
397 // Skip any non-svg nodes or any disallowed element.
398 if (!element || isDisallowedElement(element))
401 // Create SVGElementInstance object, for both container/non-container nodes.
402 SVGElementInstance* instancePtr = new SVGElementInstance(this, element);
404 RefPtr<SVGElementInstance> instance = instancePtr;
405 targetInstance->appendChild(instance.release());
407 // Enter recursion, appending new instance tree nodes to the "instance" object.
408 if (element->hasChildNodes())
409 buildInstanceTree(element, instancePtr, foundProblem);
411 // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
412 // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
413 if (element->hasTagName(SVGNames::useTag))
414 handleDeepUseReferencing(element, instancePtr, foundProblem);
417 // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
418 // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
419 if (target->hasTagName(SVGNames::useTag))
420 handleDeepUseReferencing(target, targetInstance, foundProblem);
423 void SVGUseElement::handleDeepUseReferencing(SVGElement* use, SVGElementInstance* targetInstance, bool& foundProblem)
425 String id = SVGURIReference::getTarget(use->href());
426 Element* targetElement = document()->getElementById(id);
427 SVGElement* target = 0;
428 if (targetElement && targetElement->isSVGElement())
429 target = static_cast<SVGElement*>(targetElement);
434 // Cycle detection first!
435 foundProblem = (target == this);
437 // Shortcut for self-references
441 SVGElementInstance* instance = targetInstance->parentNode();
443 SVGElement* element = instance->correspondingElement();
445 if (element->getIDAttribute() == id) {
450 instance = instance->parentNode();
453 // Create an instance object, even if we're dealing with a cycle
454 SVGElementInstance* newInstance = new SVGElementInstance(this, target);
455 targetInstance->appendChild(newInstance);
457 // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
458 buildInstanceTree(target, newInstance, foundProblem);
461 void SVGUseElement::alterShadowTreeForSVGTag(SVGElement* target)
463 String widthString = String::number(width().value());
464 String heightString = String::number(height().value());
466 if (hasAttribute(SVGNames::widthAttr))
467 target->setAttribute(SVGNames::widthAttr, widthString);
469 if (hasAttribute(SVGNames::heightAttr))
470 target->setAttribute(SVGNames::heightAttr, heightString);
473 void SVGUseElement::removeDisallowedElementsFromSubtree(Node* element)
475 ExceptionCode ec = 0;
477 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling()) {
478 if (isDisallowedElement(child.get())) {
479 ASSERT(child->parent());
480 child->parent()->removeChild(child.get(), ec);
486 if (child->hasChildNodes())
487 removeDisallowedElementsFromSubtree(child.get());
491 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance)
493 // For instance <use> on <foreignObject> (direct case).
494 if (isDisallowedElement(target))
497 RefPtr<Node> newChild = targetInstance->correspondingElement()->cloneNode(true);
499 // We don't walk the target tree element-by-element, and clone each element,
500 // but instead use cloneNode(deep=true). This is an optimization for the common
501 // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
502 // Though if there are disallowed elements in the subtree, we have to remove them.
503 // For instance: <use> on <g> containing <foreignObject> (indirect case).
504 if (subtreeContainsDisallowedElement(newChild.get()))
505 removeDisallowedElementsFromSubtree(newChild.get());
507 SVGElement* newChildPtr = 0;
508 if (newChild->isSVGElement())
509 newChildPtr = static_cast<SVGElement*>(newChild.get());
512 ExceptionCode ec = 0;
513 m_shadowTreeRootElement->appendChild(newChild.release(), ec);
516 // Handle use referencing <svg> special case
517 if (target->hasTagName(SVGNames::svgTag))
518 alterShadowTreeForSVGTag(newChildPtr);
521 #if ENABLE(SVG) && ENABLE(SVG_USE)
522 void SVGUseElement::expandUseElementsInShadowTree(Node* element)
524 // Why expand the <use> elements in the shadow tree here, and not just
525 // do this directly in buildShadowTree, if we encounter a <use> element?
527 // Short answer: Because we may miss to expand some elements. Ie. if a <symbol>
528 // contains <use> tags, we'd miss them. So once we're done with settin' up the
529 // actual shadow tree (after the special case modification for svg/symbol) we have
530 // to walk it completely and expand all <use> elements.
531 if (element->hasTagName(SVGNames::useTag)) {
532 SVGUseElement* use = static_cast<SVGUseElement*>(element);
534 String id = SVGURIReference::getTarget(use->href());
535 Element* targetElement = document()->getElementById(id);
536 SVGElement* target = 0;
537 if (targetElement && targetElement->isSVGElement())
538 target = static_cast<SVGElement*>(targetElement);
540 // Don't ASSERT(target) here, it may be "pending", too.
542 // Setup sub-shadow tree root node
543 RefPtr<SVGElement> cloneParent = new SVGGElement(SVGNames::gTag, document());
545 // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
546 // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
547 transferUseAttributesToReplacedElement(use, cloneParent.get());
549 // Spec: An additional transformation translate(x,y) is appended to the end
550 // (i.e., right-side) of the transform attribute on the generated 'g', where x
551 // and y represent the values of the x and y attributes on the 'use' element.
552 if (use->x().value() != 0.0 || use->y().value() != 0.0) {
553 if (!cloneParent->hasAttribute(SVGNames::transformAttr)) {
554 String transformString = String::format("translate(%f, %f)", use->x().value(), use->y().value());
555 cloneParent->setAttribute(SVGNames::transformAttr, transformString);
557 String transformString = String::format(" translate(%f, %f)", use->x().value(), use->y().value());
558 const AtomicString& transformAttribute = cloneParent->getAttribute(SVGNames::transformAttr);
559 cloneParent->setAttribute(SVGNames::transformAttr, transformAttribute + transformString);
563 ExceptionCode ec = 0;
565 // For instance <use> on <foreignObject> (direct case).
566 if (isDisallowedElement(target)) {
567 // We still have to setup the <use> replacment (<g>). Otherwhise
568 // associateInstancesWithShadowTreeElements() makes wrong assumptions.
569 // Replace <use> with referenced content.
570 ASSERT(use->parentNode());
571 use->parentNode()->replaceChild(cloneParent.release(), use, ec);
576 RefPtr<Node> newChild = target->cloneNode(true);
578 // We don't walk the target tree element-by-element, and clone each element,
579 // but instead use cloneNode(deep=true). This is an optimization for the common
580 // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
581 // Though if there are disallowed elements in the subtree, we have to remove them.
582 // For instance: <use> on <g> containing <foreignObject> (indirect case).
583 if (subtreeContainsDisallowedElement(newChild.get()))
584 removeDisallowedElementsFromSubtree(newChild.get());
586 SVGElement* newChildPtr = 0;
587 if (newChild->isSVGElement())
588 newChildPtr = static_cast<SVGElement*>(newChild.get());
591 cloneParent->appendChild(newChild.release(), ec);
594 // Replace <use> with referenced content.
595 ASSERT(use->parentNode());
596 use->parentNode()->replaceChild(cloneParent.release(), use, ec);
599 // Handle use referencing <svg> special case
600 if (target->hasTagName(SVGNames::svgTag))
601 alterShadowTreeForSVGTag(newChildPtr);
603 // Immediately stop here, and restart expanding.
604 expandUseElementsInShadowTree(m_shadowTreeRootElement.get());
609 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
610 expandUseElementsInShadowTree(child.get());
613 void SVGUseElement::expandSymbolElementsInShadowTree(Node* element)
615 if (element->hasTagName(SVGNames::symbolTag)) {
616 // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
617 // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
618 // always have explicit values for attributes width and height. If attributes width and/or
619 // height are provided on the 'use' element, then these attributes will be transferred to
620 // the generated 'svg'. If attributes width and/or height are not specified, the generated
621 // 'svg' element will use values of 100% for these attributes.
622 RefPtr<SVGSVGElement> svgElement = new SVGSVGElement(SVGNames::svgTag, document());
624 // Transfer all attributes from <symbol> to the new <svg> element
625 *svgElement->attributes() = *element->attributes();
627 // Explicitly re-set width/height values
628 String widthString = String::number(width().value());
629 String heightString = String::number(height().value());
631 svgElement->setAttribute(SVGNames::widthAttr, hasAttribute(SVGNames::widthAttr) ? widthString : "100%");
632 svgElement->setAttribute(SVGNames::heightAttr, hasAttribute(SVGNames::heightAttr) ? heightString : "100%");
634 ExceptionCode ec = 0;
636 // Only clone symbol children, and add them to the new <svg> element
637 for (Node* child = element->firstChild(); child; child = child->nextSibling()) {
638 RefPtr<Node> newChild = child->cloneNode(true);
639 svgElement->appendChild(newChild.release(), ec);
643 // We don't walk the target tree element-by-element, and clone each element,
644 // but instead use cloneNode(deep=true). This is an optimization for the common
645 // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
646 // Though if there are disallowed elements in the subtree, we have to remove them.
647 // For instance: <use> on <g> containing <foreignObject> (indirect case).
648 if (subtreeContainsDisallowedElement(svgElement.get()))
649 removeDisallowedElementsFromSubtree(svgElement.get());
651 // Replace <symbol> with <svg>.
652 ASSERT(element->parentNode());
653 element->parentNode()->replaceChild(svgElement.release(), element, ec);
656 // Immediately stop here, and restart expanding.
657 expandSymbolElementsInShadowTree(m_shadowTreeRootElement.get());
661 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
662 expandSymbolElementsInShadowTree(child.get());
667 void SVGUseElement::attachShadowTree()
669 if (!m_shadowTreeRootElement || m_shadowTreeRootElement->attached() || !document()->shouldCreateRenderers() || !attached() || !renderer())
672 // Inspired by RenderTextControl::createSubtreeIfNeeded().
673 if (renderer()->canHaveChildren() && childShouldCreateRenderer(m_shadowTreeRootElement.get())) {
674 RenderStyle* style = m_shadowTreeRootElement->styleForRenderer(renderer());
676 if (m_shadowTreeRootElement->rendererIsNeeded(style)) {
677 m_shadowTreeRootElement->setRenderer(m_shadowTreeRootElement->createRenderer(document()->renderArena(), style));
678 if (RenderObject* shadowRenderer = m_shadowTreeRootElement->renderer()) {
679 shadowRenderer->setStyle(style);
680 renderer()->addChild(shadowRenderer, m_shadowTreeRootElement->nextRenderer());
681 m_shadowTreeRootElement->setAttached();
685 style->deref(document()->renderArena());
687 // This will take care of attaching all shadow tree child nodes.
688 for (Node* child = m_shadowTreeRootElement->firstChild(); child; child = child->nextSibling())
693 void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance)
695 if (!target || !targetInstance)
698 SVGElement* originalElement = targetInstance->correspondingElement();
700 if (originalElement->hasTagName(SVGNames::useTag)) {
701 #if ENABLE(SVG) && ENABLE(SVG_USE)
702 // <use> gets replaced by <g>
703 ASSERT(target->nodeName() == SVGNames::gTag);
705 ASSERT(target->nodeName() == SVGNames::gTag || target->nodeName() == SVGNames::useTag);
707 } else if (originalElement->hasTagName(SVGNames::symbolTag)) {
708 // <symbol> gets replaced by <svg>
709 ASSERT(target->nodeName() == SVGNames::svgTag);
711 ASSERT(target->nodeName() == originalElement->nodeName());
713 SVGElement* element = 0;
714 if (target->isSVGElement())
715 element = static_cast<SVGElement*>(target);
717 ASSERT(!targetInstance->shadowTreeElement());
718 targetInstance->setShadowTreeElement(element);
720 Node* node = target->firstChild();
721 for (SVGElementInstance* instance = targetInstance->firstChild(); node && instance; instance = instance->nextSibling()) {
722 // Skip any non-svg elements in shadow tree
723 while (node && !node->isSVGElement())
724 node = node->nextSibling();
726 associateInstancesWithShadowTreeElements(node, instance);
727 node = node->nextSibling();
731 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element) const
733 return instanceForShadowTreeElement(element, m_targetElementInstance.get());
736 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element, SVGElementInstance* instance) const
740 ASSERT(instance->shadowTreeElement());
742 if (element == instance->shadowTreeElement())
745 for (SVGElementInstance* current = instance->firstChild(); current; current = current->nextSibling()) {
746 SVGElementInstance* search = instanceForShadowTreeElement(element, current);
754 void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement* from, SVGElement* to) const
759 *to->attributes() = *from->attributes();
761 ExceptionCode ec = 0;
763 to->removeAttribute(SVGNames::xAttr, ec);
766 to->removeAttribute(SVGNames::yAttr, ec);
769 to->removeAttribute(SVGNames::widthAttr, ec);
772 to->removeAttribute(SVGNames::heightAttr, ec);
775 to->removeAttribute(XLinkNames::hrefAttr, ec);
781 #endif // ENABLE(SVG)