24 #include "wtf/Platform.h"
35 #include "css/cssstyleselector.h"
40 #include "RenderSVGTransformableContainer.h"
52 #include <wtf/OwnPtr.h>
56 SVGUseElement::SVGUseElement(
const QualifiedName& tagName, Document* doc)
57 : SVGStyledTransformableElement(tagName, doc)
60 , SVGExternalResourcesRequired()
62 , m_x(this, LengthModeWidth)
63 , m_y(this, LengthModeHeight)
64 , m_width(this, LengthModeWidth)
65 , m_height(this, LengthModeHeight)
69 SVGUseElement::~SVGUseElement()
73 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, X, x,
SVGNames::xAttr, m_x)
74 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, Y, y, SVGNames::
yAttr, m_y)
75 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, Width, width, SVGNames::
widthAttr, m_width)
76 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, Height, height, SVGNames::
heightAttr, m_height)
78 SVGElementInstance* SVGUseElement::instanceRoot()
const
80 return m_targetElementInstance.get();
83 SVGElementInstance* SVGUseElement::animatedInstanceRoot()
const
89 void SVGUseElement::parseMappedAttribute(MappedAttribute* attr)
92 setXBaseValue(SVGLength(
this, LengthModeWidth, attr->value()));
94 setYBaseValue(SVGLength(
this, LengthModeHeight, attr->value()));
96 setWidthBaseValue(SVGLength(
this, LengthModeWidth, attr->value()));
97 if (width().value() < 0.0)
98 document()->accessSVGExtensions()->reportError(
"A negative value for use attribute <width> is not allowed");
100 setHeightBaseValue(SVGLength(
this, LengthModeHeight, attr->value()));
101 if (height().value() < 0.0)
102 document()->accessSVGExtensions()->reportError(
"A negative value for use attribute <height> is not allowed");
104 if (SVGTests::parseMappedAttribute(attr))
106 if (SVGLangSpace::parseMappedAttribute(attr))
108 if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
110 if (SVGURIReference::parseMappedAttribute(attr))
112 SVGStyledTransformableElement::parseMappedAttribute(attr);
116 void SVGUseElement::insertedIntoDocument()
118 SVGElement::insertedIntoDocument();
119 buildPendingResource();
122 void SVGUseElement::removedFromDocument()
124 m_targetElementInstance = 0;
125 m_shadowTreeRootElement = 0;
126 SVGElement::removedFromDocument();
129 void SVGUseElement::svgAttributeChanged(
const QualifiedName& attrName)
131 SVGStyledTransformableElement::svgAttributeChanged(attrName);
138 SVGTests::isKnownAttribute(attrName) ||
139 SVGLangSpace::isKnownAttribute(attrName) ||
140 SVGExternalResourcesRequired::isKnownAttribute(attrName) ||
141 SVGURIReference::isKnownAttribute(attrName) ||
142 SVGStyledTransformableElement::isKnownAttribute(attrName)) {
145 buildPendingResource();
147 if (m_shadowTreeRootElement)
148 m_shadowTreeRootElement->setChanged();
152 void SVGUseElement::childrenChanged(
bool changedByParser, Node* beforeChange, Node* afterChange,
int childCountDelta)
154 Q_UNUSED(changedByParser);
155 Q_UNUSED(beforeChange);
156 Q_UNUSED(afterChange);
157 Q_UNUSED(childCountDelta);
158 SVGElement::childrenChanged();
163 buildPendingResource();
165 if (m_shadowTreeRootElement)
166 m_shadowTreeRootElement->setChanged();
169 void SVGUseElement::recalcStyle(StyleChange change)
171 SVGStyledElement::recalcStyle(change);
175 if (!m_shadowTreeRootElement || !m_shadowTreeRootElement->attached())
181 if (change >= Inherit || m_shadowTreeRootElement->changed()) {
182 RenderStyle* newStyle = document()->styleSelector()->styleForElement(m_shadowTreeRootElement.get());
184 StyleChange ch = m_shadowTreeRootElement->diff((m_shadowTreeRootElement->renderer() ? m_shadowTreeRootElement->renderer()->style() : 0), newStyle);
186 ASSERT(m_shadowTreeRootElement->attached());
187 m_shadowTreeRootElement->detach();
191 m_shadowTreeRootElement->setChanged(
false);
192 m_shadowTreeRootElement->setHasChangedChild(
false);
201 m_shadowTreeRootElement->recalcStyle(change);
204 #ifdef DUMP_INSTANCE_TREE
205 void dumpInstanceTree(
unsigned int& depth,
String& text, SVGElementInstance* targetInstance)
207 SVGElement* element = targetInstance->correspondingElement();
210 String elementId = element->getIDAttribute();
211 String elementNodeName = element->nodeName();
212 String parentNodeName = element->parentNode() ? element->parentNode()->nodeName() :
"null";
213 String firstChildNodeName = element->firstChild() ? element->firstChild()->nodeName() :
"null";
215 for (
unsigned int i = 0; i < depth; ++i)
218 text += String::format(
"SVGElementInstance (parentNode=%s, firstChild=%s, correspondingElement=%s, id=%s)\n",
219 parentNodeName.latin1().data(), firstChildNodeName.latin1().data(), elementNodeName.latin1().data(), elementId.latin1().data());
223 for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
224 dumpInstanceTree(depth, text, instance);
230 static bool isDisallowedElement(Node* element)
233 #if ENABLE(SVG_FOREIGN_OBJECT)
238 #if ENABLE(SVG_ANIMATION)
239 if (SVGSMILElement::isSMILElement(element))
246 static bool subtreeContainsDisallowedElement(Node* start)
248 if (isDisallowedElement(start))
251 for (Node* cur = start->firstChild(); cur; cur = cur->nextSibling()) {
252 if (subtreeContainsDisallowedElement(cur))
259 void SVGUseElement::buildPendingResource()
261 String id = SVGURIReference::getTarget(href());
262 Element* targetElement = document()->getElementById(
id);
264 if (!targetElement) {
267 document()->accessSVGExtensions()->addPendingResource(
id,
this);
273 Node* parent = parentNode();
275 if (parent->isShadowNode())
278 parent = parent->parentNode();
281 SVGElement* target = 0;
282 if (targetElement && targetElement->isSVGElement())
283 target = static_cast<SVGElement*>(targetElement);
287 if (!target || target ==
this) {
288 m_targetElementInstance = 0;
289 m_shadowTreeRootElement = 0;
303 m_targetElementInstance =
new SVGElementInstance(
this, target);
306 bool foundProblem =
false;
307 buildInstanceTree(target, m_targetElementInstance.get(), foundProblem);
312 m_targetElementInstance = 0;
313 m_shadowTreeRootElement = 0;
318 ASSERT(m_targetElementInstance);
319 ASSERT(m_targetElementInstance->correspondingUseElement() ==
this);
322 m_shadowTreeRootElement =
new SVGGElement(
SVGNames::gTag, document());
323 m_shadowTreeRootElement->setInDocument();
324 m_shadowTreeRootElement->setShadowParentNode(
this);
329 if (x().value() != 0.0 || y().value() != 0.0) {
330 String transformString = String::format(
"translate(%f, %f)", x().value(), y().value());
336 buildShadowTree(target, m_targetElementInstance.get());
338 #if ENABLE(SVG) && ENABLE(SVG_USE)
341 expandUseElementsInShadowTree(m_shadowTreeRootElement.get());
345 expandSymbolElementsInShadowTree(m_shadowTreeRootElement.get());
351 associateInstancesWithShadowTreeElements(m_shadowTreeRootElement->firstChild(), m_targetElementInstance.get());
354 #ifdef DUMP_INSTANCE_TREE
356 unsigned int depth = 0;
358 dumpInstanceTree(depth, text, m_targetElementInstance.get());
359 fprintf(stderr,
"\nDumping <use> instance tree:\n%s\n", text.latin1().data());
363 #ifdef DUMP_SHADOW_TREE
364 ExceptionCode ec = 0;
366 PassRefPtr<XMLSerializer> serializer = XMLSerializer::create();
368 String markup = serializer->serializeToString(m_shadowTreeRootElement.get(), ec);
371 fprintf(stderr,
"Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data());
379 RenderObject* SVGUseElement::createRenderer(RenderArena* arena, RenderStyle*)
381 return new (arena) RenderSVGTransformableContainer(
this);
384 void SVGUseElement::attach()
386 SVGStyledTransformableElement::attach();
392 void SVGUseElement::detach()
394 if (m_shadowTreeRootElement)
395 m_shadowTreeRootElement->detach();
397 SVGStyledTransformableElement::detach();
400 static bool isDirectReference(Node* n)
411 Path SVGUseElement::toClipPath()
const
413 if (!m_shadowTreeRootElement)
414 const_cast<SVGUseElement*
>(
this)->buildPendingResource();
416 if (!m_shadowTreeRootElement)
419 Node* n = m_shadowTreeRootElement->firstChild();
420 if (n->isSVGElement() &&
static_cast<SVGElement*
>(n)->isStyledTransformable()) {
421 if (!isDirectReference(n))
423 document()->accessSVGExtensions()->reportError(
"Not allowed to use indirect reference in <clip-path>");
425 return static_cast<SVGStyledTransformableElement*
>(n)->toClipPath();
431 void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* targetInstance,
bool& foundProblem)
434 ASSERT(targetInstance);
443 for (Node* node = target->firstChild(); node; node = node->nextSibling()) {
444 SVGElement* element = 0;
445 if (node->isSVGElement())
446 element = static_cast<SVGElement*>(node);
449 if (!element || isDisallowedElement(element))
453 SVGElementInstance* instancePtr =
new SVGElementInstance(
this, element);
455 RefPtr<SVGElementInstance> instance = instancePtr;
456 targetInstance->appendChild(instance.release());
459 if (element->hasChildNodes())
460 buildInstanceTree(element, instancePtr, foundProblem);
465 handleDeepUseReferencing(element, instancePtr, foundProblem);
471 handleDeepUseReferencing(target, targetInstance, foundProblem);
474 void SVGUseElement::handleDeepUseReferencing(SVGElement* use, SVGElementInstance* targetInstance,
bool& foundProblem)
476 String id = SVGURIReference::getTarget(use->href());
477 Element* targetElement = document()->getElementById(
id);
478 SVGElement* target = 0;
479 if (targetElement && targetElement->isSVGElement())
480 target = static_cast<SVGElement*>(targetElement);
486 foundProblem = (target ==
this);
492 SVGElementInstance* instance = targetInstance->parentNode();
494 SVGElement* element = instance->correspondingElement();
496 if (element->getIDAttribute() == id) {
501 instance = instance->parentNode();
505 SVGElementInstance* newInstance =
new SVGElementInstance(
this, target);
506 targetInstance->appendChild(newInstance);
509 buildInstanceTree(target, newInstance, foundProblem);
512 void SVGUseElement::alterShadowTreeForSVGTag(SVGElement* target)
514 String widthString = String::number(width().value());
515 String heightString = String::number(height().value());
524 void SVGUseElement::removeDisallowedElementsFromSubtree(Node* subtree)
542 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance)
545 if (isDisallowedElement(target))
548 PassRefPtr<NodeImpl> newChild = targetInstance->correspondingElement()->cloneNode(
true);
555 if (subtreeContainsDisallowedElement(newChild.get()))
556 removeDisallowedElementsFromSubtree(newChild.get());
558 SVGElement* newChildPtr = 0;
559 if (newChild->isSVGElement())
560 newChildPtr = static_cast<SVGElement*>(newChild.get());
564 m_shadowTreeRootElement->appendChild(newChild.releaseRef(), ec);
569 alterShadowTreeForSVGTag(newChildPtr);
572 #if ENABLE(SVG) && ENABLE(SVG_USE)
573 void SVGUseElement::expandUseElementsInShadowTree(Node* element)
583 SVGUseElement* use =
static_cast<SVGUseElement*
>(element);
585 String id = SVGURIReference::getTarget(use->href());
586 Element* targetElement = document()->getElementById(
id);
587 SVGElement* target = 0;
588 if (targetElement && targetElement->isSVGElement())
589 target = static_cast<SVGElement*>(targetElement);
594 RefPtr<SVGElement> cloneParent =
new SVGGElement(
SVGNames::gTag, document());
598 transferUseAttributesToReplacedElement(use, cloneParent.get());
603 if (use->x().value() != 0.0 || use->y().value() != 0.0) {
605 String transformString = String::format(
"translate(%f, %f)", use->x().value(), use->y().value());
608 String transformString = String::format(
" translate(%f, %f)", use->x().value(), use->y().value());
614 ExceptionCode ec = 0;
617 if (isDisallowedElement(target)) {
621 ASSERT(use->parentNode());
622 use->parentNode()->replaceChild(cloneParent.release(), use, ec);
627 RefPtr<Node> newChild = target->cloneNode(
true);
634 if (subtreeContainsDisallowedElement(newChild.get()))
635 removeDisallowedElementsFromSubtree(newChild.get());
637 SVGElement* newChildPtr = 0;
638 if (newChild->isSVGElement())
639 newChildPtr = static_cast<SVGElement*>(newChild.get());
642 cloneParent->appendChild(newChild.release(), ec);
646 ASSERT(use->parentNode());
647 use->parentNode()->replaceChild(cloneParent.release(), use, ec);
652 alterShadowTreeForSVGTag(newChildPtr);
655 expandUseElementsInShadowTree(m_shadowTreeRootElement.get());
660 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
661 expandUseElementsInShadowTree(child.get());
664 void SVGUseElement::expandSymbolElementsInShadowTree(Node* element)
673 RefPtr<SVGSVGElement> svgElement =
new SVGSVGElement(
SVGNames::svgTag, document());
676 svgElement->attributes()->setAttributes(*element->attributes());
679 String widthString = String::number(width().value());
680 String heightString = String::number(height().value());
685 ExceptionCode ec = 0;
688 for (Node* child = element->firstChild(); child; child = child->nextSibling()) {
689 RefPtr<Node> newChild = child->cloneNode(
true);
690 svgElement->appendChild(newChild.release(), ec);
699 if (subtreeContainsDisallowedElement(svgElement.get()))
700 removeDisallowedElementsFromSubtree(svgElement.get());
703 ASSERT(element->parentNode());
704 element->parentNode()->replaceChild(svgElement.release(), element, ec);
708 expandSymbolElementsInShadowTree(m_shadowTreeRootElement.get());
712 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
713 expandSymbolElementsInShadowTree(child.get());
718 void SVGUseElement::attachShadowTree()
720 if (!m_shadowTreeRootElement || m_shadowTreeRootElement->attached() || !attached() || !renderer())
724 if (renderer()->childAllowed() && childShouldCreateRenderer(m_shadowTreeRootElement.get())) {
725 RenderStyle* style = m_shadowTreeRootElement->styleForRenderer(renderer());
728 if (m_shadowTreeRootElement->rendererIsNeeded(style)) {
729 m_shadowTreeRootElement->setRenderer(m_shadowTreeRootElement->createRenderer(document()->renderArena(), style));
730 if (RenderObject* shadowRenderer = m_shadowTreeRootElement->renderer()) {
731 shadowRenderer->setStyle(style);
732 renderer()->addChild(shadowRenderer, m_shadowTreeRootElement->nextRenderer());
733 m_shadowTreeRootElement->setAttached();
740 for (Node* child = m_shadowTreeRootElement->firstChild(); child; child = child->nextSibling())
745 void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance)
747 if (!target || !targetInstance)
750 SVGElement* originalElement = targetInstance->correspondingElement();
753 #if ENABLE(SVG) && ENABLE(SVG_USE)
761 #if ENABLE(SVG) && ENABLE(SVG_USE) && ENABLE(SVG_FOREIGN_OBJECT)
765 ASSERT(target->nodeName() == originalElement->nodeName());
767 SVGElement* element = 0;
768 if (target->isSVGElement())
769 element = static_cast<SVGElement*>(target);
771 ASSERT(!targetInstance->shadowTreeElement());
772 targetInstance->setShadowTreeElement(element);
774 Node* node = target->firstChild();
775 for (SVGElementInstance* instance = targetInstance->firstChild(); node && instance; instance = instance->nextSibling()) {
777 while (node && !node->isSVGElement())
778 node = node->nextSibling();
780 associateInstancesWithShadowTreeElements(node, instance);
781 node = node->nextSibling();
785 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element)
const
787 return instanceForShadowTreeElement(element, m_targetElementInstance.get());
790 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element, SVGElementInstance* instance)
const
794 ASSERT(instance->shadowTreeElement());
796 if (element == instance->shadowTreeElement())
799 for (SVGElementInstance* current = instance->firstChild(); current; current = current->nextSibling()) {
800 SVGElementInstance* search = instanceForShadowTreeElement(element, current);
808 void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement* from, SVGElement* to)
const
838 #endif // ENABLE(SVG)
DOM::QualifiedName widthAttr
DOM::QualifiedName useTag
DOM::QualifiedName svgTag
DOM::QualifiedName polylineTag
DOM::QualifiedName polygonTag
DOM::QualifiedName transformAttr
DOM::QualifiedName circleTag
DOM::QualifiedName ellipseTag
DOM::QualifiedName rectTag
DOM::QualifiedName pathTag
DOM::QualifiedName heightAttr
DOM::QualifiedName foreignObjectTag
DOM::QualifiedName symbolTag
DOM::QualifiedName textTag