예제 #1
0
bool SVGLengthContext::determineViewport(FloatSize& viewportSize) const
{
    if (!m_context)
        return false;

    // If an overriden viewport is given, it has precedence.
    if (!m_overridenViewport.isEmpty()) {
        viewportSize = m_overridenViewport.size();
        return true;
    }

    // Root <svg> element lengths are resolved against the top level viewport.
    if (m_context->isOutermostSVGSVGElement()) {
        viewportSize = toSVGSVGElement(m_context)->currentViewportSize();
        return true;
    }

    // Take size from nearest viewport element.
    SVGElement* viewportElement = m_context->viewportElement();
    if (!isSVGSVGElement(viewportElement))
        return false;

    const SVGSVGElement& svg = toSVGSVGElement(*viewportElement);
    viewportSize = svg.currentViewBoxRect().size();
    if (viewportSize.isEmpty())
        viewportSize = svg.currentViewportSize();

    return true;
}
예제 #2
0
bool SVGLengthContext::determineViewport(float& width, float& height) const
{
    if (!m_context)
        return false;

    // If an overriden viewport is given, it has precedence.
    if (!m_overridenViewport.isEmpty()) {
        width = m_overridenViewport.width();
        height = m_overridenViewport.height();
        return true;
    }

    // SVGLengthContext should NEVER be used to resolve width/height values for <svg> elements,
    // as they require special treatment, due the relationship with the CSS width/height properties.
    ASSERT(m_context->document().documentElement() != m_context);

    // Take size from nearest viewport element.
    SVGElement* viewportElement = m_context->viewportElement();
    if (!viewportElement || !isSVGSVGElement(viewportElement))
        return false;
    
    const SVGSVGElement* svg = toSVGSVGElement(viewportElement);
    FloatSize viewportSize = svg->currentViewBoxRect().size();
    if (viewportSize.isEmpty())
        viewportSize = svg->currentViewportSize();

    width = viewportSize.width();
    height = viewportSize.height();
    return true;
}
static bool isViewportElement(const Element& element)
{
    return (isSVGSVGElement(element)
        || isSVGSymbolElement(element)
        || isSVGForeignObjectElement(element)
        || isSVGImageElement(element));
}
void LayoutSVGViewportContainer::determineIfLayoutSizeChanged()
{
    ASSERT(element());
    if (!isSVGSVGElement(*element()))
        return;

    m_isLayoutSizeChanged = toSVGSVGElement(element())->hasRelativeLengths() && selfNeedsLayout();
}
AffineTransform LayoutSVGViewportContainer::viewportTransform() const
{
    ASSERT(element());
    if (isSVGSVGElement(*element())) {
        SVGSVGElement* svg = toSVGSVGElement(element());
        return svg->viewBoxToViewTransform(m_viewport.width(), m_viewport.height());
    }

    return AffineTransform();
}
예제 #6
0
SVGSVGElement* SVGElement::ownerSVGElement() const
{
    ContainerNode* n = parentOrShadowHostNode();
    while (n) {
        if (isSVGSVGElement(*n))
            return toSVGSVGElement(n);

        n = n->parentOrShadowHostNode();
    }

    return nullptr;
}
예제 #7
0
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 LayoutSVGViewportContainer::calcViewport()
{
    SVGElement* element = this->element();
    ASSERT(element);
    if (!isSVGSVGElement(*element))
        return;
    SVGSVGElement* svg = toSVGSVGElement(element);
    FloatRect oldViewport = m_viewport;

    SVGLengthContext lengthContext(element);
    m_viewport = FloatRect(svg->x()->currentValue()->value(lengthContext), svg->y()->currentValue()->value(lengthContext), svg->width()->currentValue()->value(lengthContext), svg->height()->currentValue()->value(lengthContext));

    if (oldViewport != m_viewport) {
        setNeedsBoundariesUpdate();
        setNeedsTransformUpdate();
    }
}
예제 #9
0
bool RenderTreeBuilder::shouldCreateRenderer() const
{
    if (!m_renderingParent)
        return false;
    if (m_node->isSVGElement()) {
        // SVG elements only render when inside <svg>, or if the element is an <svg> itself.
        if (!isSVGSVGElement(*m_node) && !m_renderingParent->isSVGElement())
            return false;
        if (!toSVGElement(m_node)->isValid())
            return false;
    }
    RenderObject* parentRenderer = this->parentRenderer();
    if (!parentRenderer)
        return false;
    if (!parentRenderer->canHaveChildren())
        return false;
    return true;
}
예제 #10
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));
  }
}
예제 #11
0
bool SVGElement::isOutermostSVGSVGElement() const
{
    if (!isSVGSVGElement(*this))
        return false;

    // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc.
    if (!parentNode())
        return true;

    // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element.
    if (isSVGForeignObjectElement(*parentNode()))
        return true;

    // If we're living in a shadow tree, we're a <svg> element that got created as replacement
    // for a <symbol> element or a cloned <svg> element in the referenced tree. In that case
    // we're always an inner <svg> element.
    if (inUseShadowTree() && parentOrShadowHostElement() && parentOrShadowHostElement()->isSVGElement())
        return false;

    // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
    return !parentNode()->isSVGElement();
}
예제 #12
0
bool LayoutTreeBuilderForElement::shouldCreateLayoutObject() const
{
    if (!m_layoutObjectParent)
        return false;

    // FIXME: Should the following be in SVGElement::layoutObjectIsNeeded()?
    if (m_node->isSVGElement()) {
        // SVG elements only render when inside <svg>, or if the element is an <svg> itself.
        if (!isSVGSVGElement(*m_node) && (!m_layoutObjectParent->node() || !m_layoutObjectParent->node()->isSVGElement()))
            return false;
        if (!toSVGElement(m_node)->isValid())
            return false;
    }

    LayoutObject* parentLayoutObject = this->parentLayoutObject();
    if (!parentLayoutObject)
        return false;
    if (!parentLayoutObject->canHaveChildren())
        return false;

    return m_node->layoutObjectIsNeeded(style());
}
예제 #13
0
void SVGElement::updateRelativeLengthsInformation(bool clientHasRelativeLengths, SVGElement* clientElement)
{
    ASSERT(clientElement);

    // If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now.
    if (!inDocument())
        return;

    // An element wants to notify us that its own relative lengths state changed.
    // Register it in the relative length map, and register us in the parent relative length map.
    // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree.
    for (ContainerNode* currentNode = this; currentNode && currentNode->isSVGElement(); currentNode = currentNode->parentNode()) {
        SVGElement* currentElement = toSVGElement(currentNode);
        ASSERT(!currentElement->m_inRelativeLengthClientsInvalidation);

        bool hadRelativeLengths = currentElement->hasRelativeLengths();
        if (clientHasRelativeLengths)
            currentElement->m_elementsWithRelativeLengths.add(clientElement);
        else
            currentElement->m_elementsWithRelativeLengths.remove(clientElement);

        // If the relative length state hasn't changed, we can stop propagating the notification.
        if (hadRelativeLengths == currentElement->hasRelativeLengths())
            return;

        clientElement = currentElement;
        clientHasRelativeLengths = clientElement->hasRelativeLengths();
    }

    // Register root SVG elements for top level viewport change notifications.
    if (isSVGSVGElement(*clientElement)) {
        SVGDocumentExtensions& svgExtensions = accessDocumentSVGExtensions();
        if (clientElement->hasRelativeLengths())
            svgExtensions.addSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement));
        else
            svgExtensions.removeSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement));
    }
}
예제 #14
0
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));
    }
}
예제 #15
0
SVGSVGElement* SVGDocumentExtensions::rootElement(const Document& document)
{
    Element* elem = document.documentElement();
    return isSVGSVGElement(elem) ? toSVGSVGElement(elem) : 0;
}