static bool isViewportElement(const Element& element) { return (isSVGSVGElement(element) || isSVGSymbolElement(element) || isSVGForeignObjectElement(element) || isSVGImageElement(element)); }
SVGElement* SVGElement::viewportElement() const { // This function needs shadow tree support - as LayoutSVGContainer uses this function // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise. ContainerNode* n = parentOrShadowHostNode(); while (n) { if (isSVGSVGElement(*n) || isSVGImageElement(*n) || isSVGSymbolElement(*n)) return toSVGElement(n); n = n->parentOrShadowHostNode(); } return nullptr; }
void SVGUseElement::expandSymbolElementsInShadowTree(SVGElement* element) { ASSERT(element); if (isSVGSymbolElement(*element)) { // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree, // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will // always have explicit values for attributes width and height. If attributes width and/or // height are provided on the 'use' element, then these attributes will be transferred to // the generated 'svg'. If attributes width and/or height are not specified, the generated // 'svg' element will use values of 100% for these attributes. ASSERT(referencedScope()); RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(referencedScope()->document()); // Transfer all data (attributes, etc.) from <symbol> to the new <svg> element. svgElement->cloneDataFromElement(*element); svgElement->setCorrespondingElement(element->correspondingElement()); // Move already cloned elements to the new <svg> element for (RefPtrWillBeRawPtr<Node> child = element->firstChild(); child; ) { RefPtrWillBeRawPtr<Node> nextChild = child->nextSibling(); svgElement->appendChild(child); child = nextChild.release(); } // 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 // 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(svgElement.get())) removeDisallowedElementsFromSubtree(*svgElement); 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<SVGElement> sibling = Traversal<SVGElement>::nextSibling(*element); sibling; sibling = Traversal<SVGElement>::nextSibling(*sibling)) expandSymbolElementsInShadowTree(sibling.get()); } for (RefPtrWillBeRawPtr<SVGElement> child = Traversal<SVGElement>::firstChild(*element); child; child = Traversal<SVGElement>::nextSibling(*child)) expandSymbolElementsInShadowTree(child.get()); }
static void transferUseWidthAndHeightIfNeeded( const SVGUseElement& use, SVGElement& shadowElement, const SVGElement& originalElement) { DEFINE_STATIC_LOCAL(const AtomicString, hundredPercentString, ("100%")); // Use |originalElement| for checking the element type, because we will // have replaced a <symbol> with an <svg> in the instance tree. if (isSVGSymbolElement(originalElement)) { // Spec (<use> on <symbol>): This generated 'svg' will always have // explicit values for attributes width and height. If attributes // width and/or height are provided on the 'use' element, then these // attributes will be transferred to the generated 'svg'. If attributes // width and/or height are not specified, the generated 'svg' element // will use values of 100% for these attributes. shadowElement.setAttribute( SVGNames::widthAttr, use.width()->isSpecified() ? AtomicString(use.width()->currentValue()->valueAsString()) : hundredPercentString); shadowElement.setAttribute( SVGNames::heightAttr, use.height()->isSpecified() ? AtomicString(use.height()->currentValue()->valueAsString()) : hundredPercentString); } else if (isSVGSVGElement(originalElement)) { // Spec (<use> on <svg>): If attributes width and/or height are // provided on the 'use' element, then these values will override the // corresponding attributes on the 'svg' in the generated tree. shadowElement.setAttribute( SVGNames::widthAttr, use.width()->isSpecified() ? AtomicString(use.width()->currentValue()->valueAsString()) : originalElement.getAttribute(SVGNames::widthAttr)); shadowElement.setAttribute( SVGNames::heightAttr, use.height()->isSpecified() ? AtomicString(use.height()->currentValue()->valueAsString()) : originalElement.getAttribute(SVGNames::heightAttr)); } }
void transferUseWidthAndHeightIfNeeded(const SVGUseElement& use, SVGElement* shadowElement, const SVGElement& originalElement) { DEFINE_STATIC_LOCAL(const AtomicString, hundredPercentString, ("100%", AtomicString::ConstructFromLiteral)); ASSERT(shadowElement); if (isSVGSymbolElement(*shadowElement)) { // Spec (<use> on <symbol>): This generated 'svg' will always have explicit values for attributes width and height. // If attributes width and/or height are provided on the 'use' element, then these attributes // will be transferred to the generated 'svg'. If attributes width and/or height are not specified, // the generated 'svg' element will use values of 100% for these attributes. shadowElement->setAttribute(SVGNames::widthAttr, use.width()->isSpecified() ? AtomicString(use.width()->currentValue()->valueAsString()) : hundredPercentString); shadowElement->setAttribute(SVGNames::heightAttr, use.height()->isSpecified() ? AtomicString(use.height()->currentValue()->valueAsString()) : hundredPercentString); } else if (isSVGSVGElement(*shadowElement)) { // Spec (<use> on <svg>): If attributes width and/or height are provided on the 'use' element, then these // values will override the corresponding attributes on the 'svg' in the generated tree. if (use.width()->isSpecified()) shadowElement->setAttribute(SVGNames::widthAttr, AtomicString(use.width()->currentValue()->valueAsString())); else shadowElement->setAttribute(SVGNames::widthAttr, originalElement.getAttribute(SVGNames::widthAttr)); if (use.height()->isSpecified()) shadowElement->setAttribute(SVGNames::heightAttr, AtomicString(use.height()->currentValue()->valueAsString())); else shadowElement->setAttribute(SVGNames::heightAttr, originalElement.getAttribute(SVGNames::heightAttr)); } }