コード例 #1
0
ファイル: SVGUseElement.cpp プロジェクト: mirror/chromium
void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName) {
  if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
      attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr) {
    SVGElement::InvalidationGuard invalidationGuard(this);

    if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr) {
      invalidateSVGPresentationAttributeStyle();
      setNeedsStyleRecalc(LocalStyleChange,
                          StyleChangeReasonForTracing::fromAttribute(attrName));
    }

    updateRelativeLengthsInformation();
    if (m_targetElementInstance) {
      ASSERT(m_targetElementInstance->correspondingElement());
      transferUseWidthAndHeightIfNeeded(
          *this, *m_targetElementInstance,
          *m_targetElementInstance->correspondingElement());
    }

    LayoutObject* object = this->layoutObject();
    if (object)
      markForLayoutAndParentResourceInvalidation(object);
    return;
  }

  if (SVGURIReference::isKnownAttribute(attrName)) {
    SVGElement::InvalidationGuard invalidationGuard(this);
    updateTargetReference();
    invalidateShadowTree();
    return;
  }

  SVGGraphicsElement::svgAttributeChanged(attrName);
}
コード例 #2
0
void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target)
{
    ASSERT(!m_targetElementInstance);
    ASSERT(!m_needsShadowTreeRecreation);

    // <use> creates a "user agent" shadow root. Do not build the shadow/instance tree for <use>
    // elements living in a user agent shadow tree because they will get expanded in a second
    // pass -- see expandUseElementsInShadowTree().
    if (inUseShadowTree())
        return;

    // Do not allow self-referencing.
    // 'target' may be null, if it's a non SVG namespaced element.
    if (!target || target == this || isDisallowedElement(target))
        return;

    // Set up root SVG element in shadow tree.
    RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithoutChildren();
    m_targetElementInstance = toSVGElement(newChild.get());
    ShadowRoot* shadowTreeRootElement = userAgentShadowRoot();
    shadowTreeRootElement->appendChild(newChild.release());

    // Clone the target subtree into the shadow tree, not handling <use> and <symbol> yet.

    // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it!
    // Non-appearing <use> content is easier to debug, then half-appearing content.
    if (!buildShadowTree(target, m_targetElementInstance.get(), false)) {
        clearShadowTree();
        return;
    }

    if (instanceTreeIsLoading(m_targetElementInstance.get()))
        return;

    // Assure shadow tree building was successfull
    ASSERT(m_targetElementInstance);
    ASSERT(m_targetElementInstance->correspondingUseElement() == this);
    ASSERT(m_targetElementInstance->correspondingElement() == target);

    // Expand all <use> elements in the shadow tree.
    // Expand means: replace the actual <use> element by what it references.
    if (!expandUseElementsInShadowTree(m_targetElementInstance.get())) {
        clearShadowTree();
        return;
    }

    // Expand all <symbol> elements in the shadow tree.
    // Expand means: replace the actual <symbol> element by the <svg> element.
    expandSymbolElementsInShadowTree(toSVGElement(shadowTreeRootElement->firstChild()));

    m_targetElementInstance = toSVGElement(shadowTreeRootElement->firstChild());
    transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_targetElementInstance->correspondingElement());

    ASSERT(m_targetElementInstance->parentNode() == shadowTreeRootElement);

    // Update relative length information.
    updateRelativeLengthsInformation();
}
コード例 #3
0
void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
{
    if (attrName == SVGNames::xAttr
        || attrName == SVGNames::yAttr
        || attrName == SVGNames::widthAttr
        || attrName == SVGNames::heightAttr) {
        SVGElement::InvalidationGuard invalidationGuard(this);

        if (attrName == SVGNames::xAttr
            || attrName == SVGNames::yAttr) {
            invalidateSVGPresentationAttributeStyle();
            setNeedsStyleRecalc(LocalStyleChange,
                StyleChangeReasonForTracing::fromAttribute(attrName));
        }

        updateRelativeLengthsInformation();
        if (m_targetElementInstance) {
            ASSERT(m_targetElementInstance->correspondingElement());
            transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_targetElementInstance->correspondingElement());
        }

        LayoutObject* object = this->layoutObject();
        if (object)
            markForLayoutAndParentResourceInvalidation(object);
        return;
    }

    if (SVGURIReference::isKnownAttribute(attrName)) {
        SVGElement::InvalidationGuard invalidationGuard(this);
        if (isStructurallyExternal()) {
            KURL url = document().completeURL(hrefString());
            const KURL& existingURL = m_resource ? m_resource->url() : KURL();
            if (url.hasFragmentIdentifier() && !equalIgnoringFragmentIdentifier(url, existingURL)) {
                FetchRequest request(ResourceRequest(url), localName());
                setDocumentResource(DocumentResource::fetchSVGDocument(request, document().fetcher()));
            }
        } else {
            setDocumentResource(nullptr);
        }

        invalidateShadowTree();

        return;
    }

    SVGGraphicsElement::svgAttributeChanged(attrName);
}
コード例 #4
0
bool SVGUseElement::expandUseElementsInShadowTree(SVGElement* element)
{
    ASSERT(element);
    // Why expand the <use> elements in the shadow tree here, and not just
    // do this directly in buildShadowTree, if we encounter a <use> element?
    //
    // Short answer: Because we may miss to expand some elements. For example, if a <symbol>
    // contains <use> tags, we'd miss them. So once we're done with setting up the
    // actual shadow tree (after the special case modification for svg/symbol) we have
    // to walk it completely and expand all <use> elements.
    if (isSVGUseElement(*element)) {
        SVGUseElement* use = toSVGUseElement(element);
        ASSERT(!use->resourceIsStillLoading());

        SVGElement* target = 0;
        if (hasCycleUseReferencing(toSVGUseElement(use->correspondingElement()), use, target))
            return false;

        if (target && isDisallowedElement(target))
            return false;
        // Don't ASSERT(target) here, it may be "pending", too.
        // Setup sub-shadow tree root node
        RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(referencedScope()->document());
        cloneParent->setCorrespondingElement(use->correspondingElement());

        // Move already cloned elements to the new <g> element
        for (RefPtrWillBeRawPtr<Node> child = use->firstChild(); child; ) {
            RefPtrWillBeRawPtr<Node> nextChild = child->nextSibling();
            cloneParent->appendChild(child);
            child = nextChild.release();
        }

        // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
        // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
        transferUseAttributesToReplacedElement(use, cloneParent.get());

        if (target) {
            RefPtrWillBeRawPtr<Node> newChild = cloneNodeAndAssociate(*target);
            ASSERT(newChild->isSVGElement());
            transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()), *target);
            cloneParent->appendChild(newChild.release());
        }

        // We don't walk the target tree element-by-element, and clone each element,
        // but instead use cloneElementWithChildren(). 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(cloneParent.get()))
            removeDisallowedElementsFromSubtree(*cloneParent);

        RefPtrWillBeRawPtr<SVGElement> replacingElement(cloneParent.get());

        // Replace <use> with referenced content.
        ASSERT(use->parentNode());
        use->parentNode()->replaceChild(cloneParent.release(), use);

        // 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)) {
            if (!expandUseElementsInShadowTree(sibling.get()))
                return false;
        }
    }

    for (RefPtrWillBeRawPtr<SVGElement> child = Traversal<SVGElement>::firstChild(*element); child; child = Traversal<SVGElement>::nextSibling(*child)) {
        if (!expandUseElementsInShadowTree(child.get()))
            return false;
    }
    return true;
}