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; }
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(); }
SVGSVGElement* SVGElement::ownerSVGElement() const { ContainerNode* n = parentOrShadowHostNode(); while (n) { if (isSVGSVGElement(*n)) return toSVGSVGElement(n); n = n->parentOrShadowHostNode(); } return nullptr; }
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(); } }
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; }
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)); } }
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(); }
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()); }
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)); } }
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)); } }
SVGSVGElement* SVGDocumentExtensions::rootElement(const Document& document) { Element* elem = document.documentElement(); return isSVGSVGElement(elem) ? toSVGSVGElement(elem) : 0; }