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());
}
Beispiel #4
0
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));
    }
}