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; }
LayoutUnit RenderSVGRoot::computeReplacedLogicalHeight() const { SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); // When we're embedded through SVGImage (border-image/background-image/<html:img>/...) we're forced to resize to a specific size. if (!m_containerSize.isEmpty()) return m_containerSize.height(); if (style()->logicalHeight().isSpecified() || style()->logicalMaxHeight().isSpecified()) return RenderReplaced::computeReplacedLogicalHeight(); if (svg->heightAttributeEstablishesViewport()) { Length height = svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties); if (height.isPercent()) { RenderBlock* cb = containingBlock(); ASSERT(cb); while (cb->isAnonymous()) { cb = cb->containingBlock(); cb->addPercentHeightDescendant(const_cast<RenderSVGRoot*>(this)); } } else RenderBlock::removePercentHeightDescendant(const_cast<RenderSVGRoot*>(this)); return resolveLengthAttributeForSVG(height, style()->effectiveZoom(), containingBlock()->availableLogicalHeight(IncludeMarginBorderPadding), view()); } // SVG embedded through object/embed/iframe. if (isEmbeddedThroughFrameContainingSVGDocument()) return document()->frame()->ownerRenderer()->availableLogicalHeight(IncludeMarginBorderPadding); // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG. return RenderReplaced::computeReplacedLogicalHeight(); }
FloatSize LayoutSVGRoot::calculateIntrinsicSize() const { SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); return FloatSize(floatValueForLength(svg->intrinsicWidth(), 0), floatValueForLength(svg->intrinsicHeight(), 0)); }
void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const { // Spec: http://www.w3.org/TR/SVG/coords.html#IntrinsicSizing // SVG needs to specify how to calculate some intrinsic sizing properties to enable inclusion within other languages. // The intrinsic width and height of the viewport of SVG content must be determined from the ‘width’ and ‘height’ attributes. SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); // The intrinsic aspect ratio of the viewport of SVG content is necessary for example, when including SVG from an ‘object’ // element in HTML styled with CSS. It is possible (indeed, common) for an SVG graphic to have an intrinsic aspect ratio but // not to have an intrinsic width or height. The intrinsic aspect ratio must be calculated based upon the following rules: // - The aspect ratio is calculated by dividing a width by a height. // - If the ‘width’ and ‘height’ of the rootmost ‘svg’ element are both specified with unit identifiers (in, mm, cm, pt, pc, // px, em, ex) or in user units, then the aspect ratio is calculated from the ‘width’ and ‘height’ attributes after // resolving both values to user units. intrinsicSize.setWidth(floatValueForLength(svg->intrinsicWidth(), 0)); intrinsicSize.setHeight(floatValueForLength(svg->intrinsicHeight(), 0)); if (!intrinsicSize.isEmpty()) { intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); } else { // - If either/both of the ‘width’ and ‘height’ of the rootmost ‘svg’ element are in percentage units (or omitted), the // aspect ratio is calculated from the width and height values of the ‘viewBox’ specified for the current SVG document // fragment. If the ‘viewBox’ is not correctly specified, or set to 'none', the intrinsic aspect ratio cannot be // calculated and is considered unspecified. FloatSize viewBoxSize = svg->viewBox()->currentValue()->value().size(); if (!viewBoxSize.isEmpty()) { // The viewBox can only yield an intrinsic ratio, not an intrinsic size. intrinsicRatio = viewBoxSize.width() / static_cast<double>(viewBoxSize.height()); } } }
bool RenderSVGRoot::hasRelativeLogicalHeight() const { SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); return svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties).isPercent(); }
void RenderSVGViewportContainer::determineIfLayoutSizeChanged() { if (!node()->hasTagName(SVGNames::svgTag)) return; m_isLayoutSizeChanged = toSVGSVGElement(node())->hasRelativeLengths() && selfNeedsLayout(); }
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; }
void LayoutSVGViewportContainer::determineIfLayoutSizeChanged() { ASSERT(element()); if (!isSVGSVGElement(*element())) return; m_isLayoutSizeChanged = toSVGSVGElement(element())->hasRelativeLengths() && selfNeedsLayout(); }
SVGSVGElement* SVGDocument::rootElement() const { Element* elem = documentElement(); if (elem && elem->hasTagName(SVGNames::svgTag)) return toSVGSVGElement(elem); return 0; }
void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. if (pixelSnappedBorderBoxRect().isEmpty()) return; // Don't paint, if the context explicitly disabled it. if (paintInfo.context->paintingDisabled()) return; // SVG outlines are painted during PaintPhaseForeground. if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) return; // An empty viewBox also disables rendering. // (http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute) SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); if (svg->hasEmptyViewBox()) return; // Don't paint if we don't have kids, except if we have filters we should paint those. if (!firstChild()) { SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); if (!resources || !resources->filter()) return; } // Make a copy of the PaintInfo because applyTransform will modify the damage rect. PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); // Apply initial viewport clip if (shouldApplyViewportClip()) childPaintInfo.context->clip(pixelSnappedIntRect(overflowClipRect(paintOffset))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset); childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()) * localToBorderBoxTransform()); // SVGRenderingContext must be destroyed before we restore the childPaintInfo.context, because a filter may have // changed the context and it is only reverted when the SVGRenderingContext destructor finishes applying the filter. { SVGRenderingContext renderingContext; bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) { renderingContext.prepareToRenderSVGContent(this, childPaintInfo); continueRendering = renderingContext.isRenderingPrepared(); } if (continueRendering) RenderBox::paint(childPaintInfo, LayoutPoint()); } childPaintInfo.context->restore(); }
AffineTransform RenderSVGViewportContainer::viewportTransform() const { if (node()->hasTagName(SVGNames::svgTag)) { SVGSVGElement* svg = toSVGSVGElement(node()); return svg->viewBoxToViewTransform(m_viewport.width(), m_viewport.height()); } return AffineTransform(); }
AffineTransform LayoutSVGViewportContainer::viewportTransform() const { ASSERT(element()); if (isSVGSVGElement(*element())) { SVGSVGElement* svg = toSVGSVGElement(element()); return svg->viewBoxToViewTransform(m_viewport.width(), m_viewport.height()); } return AffineTransform(); }
void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewBox disables rendering. if (node()->hasTagName(SVGNames::svgTag)) { if (toSVGSVGElement(node())->hasEmptyViewBox()) return; } RenderSVGContainer::paint(paintInfo, paintOffset); }
SVGSVGElement* SVGElement::ownerSVGElement() const { ContainerNode* n = parentOrShadowHostNode(); while (n) { if (isSVGSVGElement(*n)) return toSVGSVGElement(n); n = n->parentOrShadowHostNode(); } return nullptr; }
// RenderBox methods will expect coordinates w/o any transforms in coordinates // relative to our borderBox origin. This method gives us exactly that. void RenderSVGRoot::buildLocalToBorderBoxTransform() { SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); float scale = style()->effectiveZoom(); FloatPoint translate = svg->currentTranslate(); LayoutSize borderAndPadding(borderLeft() + paddingLeft(), borderTop() + paddingTop()); m_localToBorderBoxTransform = svg->viewBoxToViewTransform(contentWidth() / scale, contentHeight() / scale); if (borderAndPadding.isEmpty() && scale == 1 && translate == FloatPoint::zero()) return; m_localToBorderBoxTransform = AffineTransform(scale, 0, 0, scale, borderAndPadding.width() + translate.x(), borderAndPadding.height() + translate.y()) * m_localToBorderBoxTransform; }
// LayoutBox methods will expect coordinates w/o any transforms in coordinates // relative to our borderBox origin. This method gives us exactly that. void LayoutSVGRoot::buildLocalToBorderBoxTransform() { SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); float scale = style()->effectiveZoom(); FloatPoint translate = svg->currentTranslate(); LayoutSize borderAndPadding(borderLeft() + paddingLeft(), borderTop() + paddingTop()); m_localToBorderBoxTransform = svg->viewBoxToViewTransform(contentWidth() / scale, contentHeight() / scale); AffineTransform viewToBorderBoxTransform(scale, 0, 0, scale, borderAndPadding.width() + translate.x(), borderAndPadding.height() + translate.y()); m_localToBorderBoxTransform.preMultiply(viewToBorderBoxTransform); }
SVGSVGElement* SVGElement::ownerSVGElement() const { ContainerNode* n = parentOrShadowHostNode(); while (n) { if (n->hasTagName(SVGNames::svgTag)) return toSVGSVGElement(n); n = n->parentOrShadowHostNode(); } return 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)); } }
void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const { // Spec: http://www.w3.org/TR/SVG/coords.html#IntrinsicSizing // SVG needs to specify how to calculate some intrinsic sizing properties to enable inclusion within other languages. // The intrinsic width and height of the viewport of SVG content must be determined from the ‘width’ and ‘height’ attributes. // If either of these are not specified, a value of '100%' must be assumed. Note: the ‘width’ and ‘height’ attributes are not // the same as the CSS width and height properties. Specifically, percentage values do not provide an intrinsic width or height, // and do not indicate a percentage of the containing block. Rather, once the viewport is established, they indicate the portion // of the viewport that is actually covered by image data. SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); Length intrinsicWidthAttribute = svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties); Length intrinsicHeightAttribute = svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties); // The intrinsic aspect ratio of the viewport of SVG content is necessary for example, when including SVG from an ‘object’ // element in HTML styled with CSS. It is possible (indeed, common) for an SVG graphic to have an intrinsic aspect ratio but // not to have an intrinsic width or height. The intrinsic aspect ratio must be calculated based upon the following rules: // - The aspect ratio is calculated by dividing a width by a height. // - If the ‘width’ and ‘height’ of the rootmost ‘svg’ element are both specified with unit identifiers (in, mm, cm, pt, pc, // px, em, ex) or in user units, then the aspect ratio is calculated from the ‘width’ and ‘height’ attributes after // resolving both values to user units. if (intrinsicWidthAttribute.isFixed() || intrinsicHeightAttribute.isFixed()) { if (intrinsicWidthAttribute.isFixed()) intrinsicSize.setWidth(floatValueForLength(intrinsicWidthAttribute, 0)); if (intrinsicHeightAttribute.isFixed()) intrinsicSize.setHeight(floatValueForLength(intrinsicHeightAttribute, 0)); if (!intrinsicSize.isEmpty()) intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); return; } // - If either/both of the ‘width’ and ‘height’ of the rootmost ‘svg’ element are in percentage units (or omitted), the // aspect ratio is calculated from the width and height values of the ‘viewBox’ specified for the current SVG document // fragment. If the ‘viewBox’ is not correctly specified, or set to 'none', the intrinsic aspect ratio cannot be // calculated and is considered unspecified. intrinsicSize = svg->viewBox().size(); if (!intrinsicSize.isEmpty()) { // The viewBox can only yield an intrinsic ratio, not an intrinsic size. intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); intrinsicSize = FloatSize(); return; } // If our intrinsic size is in percentage units, return those to the caller through the intrinsicSize. Notify the caller // about the special situation, by setting isPercentageIntrinsicSize=true, so it knows how to interpret the return values. if (intrinsicWidthAttribute.isPercent() && intrinsicHeightAttribute.isPercent()) { isPercentageIntrinsicSize = true; intrinsicSize = FloatSize(intrinsicWidthAttribute.percent(), intrinsicHeightAttribute.percent()); } }
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(); } }
void RenderSVGRoot::layout() { StackStats::LayoutCheckPoint layoutCheckPoint; ASSERT(needsLayout()); m_resourcesNeedingToInvalidateClients.clear(); // Arbitrary affine transforms are incompatible with LayoutState. LayoutStateDisabler layoutStateDisabler(view()); bool needsLayout = selfNeedsLayout(); LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && needsLayout); LayoutSize oldSize = size(); updateLogicalWidth(); updateLogicalHeight(); buildLocalToBorderBoxTransform(); SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); m_isLayoutSizeChanged = needsLayout || (svg->hasRelativeLengths() && oldSize != size()); SVGRenderSupport::layoutChildren(this, needsLayout || SVGRenderSupport::filtersForceContainerLayout(this)); if (!m_resourcesNeedingToInvalidateClients.isEmpty()) { // Invalidate resource clients, which may mark some nodes for layout. HashSet<RenderSVGResourceContainer*>::iterator end = m_resourcesNeedingToInvalidateClients.end(); for (HashSet<RenderSVGResourceContainer*>::iterator it = m_resourcesNeedingToInvalidateClients.begin(); it != end; ++it) (*it)->removeAllClientsFromCache(); m_isLayoutSizeChanged = false; SVGRenderSupport::layoutChildren(this, false); } // At this point LayoutRepainter already grabbed the old bounds, // recalculate them now so repaintAfterLayout() uses the new bounds. if (m_needsBoundariesOrTransformUpdate) { updateCachedBoundaries(); m_needsBoundariesOrTransformUpdate = false; } updateLayerTransform(); repainter.repaintAfterLayout(); setNeedsLayout(false); }
void RenderSVGRoot::layout() { ASSERT(needsLayout()); // Arbitrary affine transforms are incompatible with LayoutState. LayoutStateDisabler layoutStateDisabler(*this); bool needsLayout = selfNeedsLayout(); LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && needsLayout); LayoutSize oldSize = size(); updateLogicalWidth(); updateLogicalHeight(); buildLocalToBorderBoxTransform(); SVGRenderSupport::layoutResourcesIfNeeded(this); SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); m_isLayoutSizeChanged = needsLayout || (svg->hasRelativeLengths() && oldSize != size()); SVGRenderSupport::layoutChildren(this, needsLayout || SVGRenderSupport::filtersForceContainerLayout(this)); // At this point LayoutRepainter already grabbed the old bounds, // recalculate them now so repaintAfterLayout() uses the new bounds. if (m_needsBoundariesOrTransformUpdate) { updateCachedBoundaries(); m_needsBoundariesOrTransformUpdate = false; } m_overflow.clear(); addVisualEffectOverflow(); if (!shouldApplyViewportClip()) { FloatRect contentRepaintRect = repaintRectInLocalCoordinates(); contentRepaintRect = m_localToBorderBoxTransform.mapRect(contentRepaintRect); addVisualOverflow(enclosingLayoutRect(contentRepaintRect)); } updateLayerTransform(); m_hasBoxDecorations = isDocumentElement() ? calculateHasBoxDecorations() : hasBoxDecorations(); invalidateBackgroundObscurationStatus(); repainter.repaintAfterLayout(); clearNeedsLayout(); }
void SVGRootPainter::paintReplaced(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. if (pixelSnappedSize(paintOffset).isEmpty()) return; // SVG outlines are painted during PaintPhaseForeground. if (shouldPaintSelfOutline(paintInfo.phase)) return; // An empty viewBox also disables rendering. // (http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute) SVGSVGElement* svg = toSVGSVGElement(m_layoutSVGRoot.node()); DCHECK(svg); if (svg->hasEmptyViewBox()) return; // Apply initial viewport clip. Optional<BoxClipper> boxClipper; if (m_layoutSVGRoot.shouldApplyViewportClip()) { // TODO(pdr): Clip the paint info cull rect here. boxClipper.emplace(m_layoutSVGRoot, paintInfo, paintOffset, ForceContentsClip); } PaintInfo paintInfoBeforeFiltering(paintInfo); AffineTransform transformToBorderBox = transformToPixelSnappedBorderBox(paintOffset); paintInfoBeforeFiltering.updateCullRect(transformToBorderBox); SVGTransformContext transformContext(paintInfoBeforeFiltering.context, m_layoutSVGRoot, transformToBorderBox); SVGPaintContext paintContext(m_layoutSVGRoot, paintInfoBeforeFiltering); if (paintContext.paintInfo().phase == PaintPhaseForeground && !paintContext.applyClipMaskAndFilterIfNecessary()) return; BoxPainter(m_layoutSVGRoot).paint(paintContext.paintInfo(), LayoutPoint()); PaintTiming& timing = PaintTiming::from(m_layoutSVGRoot.node()->document().topDocument()); timing.markFirstContentfulPaint(); }
void RenderSVGRoot::layout() { ASSERT(needsLayout()); // Arbitrary affine transforms are incompatible with LayoutState. ForceHorriblySlowRectMapping slowRectMapping(*this); bool needsLayout = selfNeedsLayout(); LayoutSize oldSize = size(); updateLogicalWidth(); updateLogicalHeight(); buildLocalToBorderBoxTransform(); SVGRenderSupport::layoutResourcesIfNeeded(this); SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); m_isLayoutSizeChanged = needsLayout || (svg->hasRelativeLengths() && oldSize != size()); SVGRenderSupport::layoutChildren(this, needsLayout || SVGRenderSupport::filtersForceContainerLayout(this)); if (m_needsBoundariesOrTransformUpdate) { updateCachedBoundaries(); m_needsBoundariesOrTransformUpdate = false; } m_overflow.clear(); addVisualEffectOverflow(); if (!shouldApplyViewportClip()) { FloatRect contentRepaintRect = paintInvalidationRectInLocalCoordinates(); contentRepaintRect = m_localToBorderBoxTransform.mapRect(contentRepaintRect); addVisualOverflow(enclosingLayoutRect(contentRepaintRect)); } updateLayerTransformAfterLayout(); m_hasBoxDecorationBackground = isDocumentElement() ? calculateHasBoxDecorations() : hasBoxDecorationBackground(); invalidateBackgroundObscurationStatus(); clearNeedsLayout(); }
LayoutUnit RenderSVGRoot::computeReplacedLogicalHeight() const { SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); // When we're embedded through SVGImage (border-image/background-image/<html:img>/...) we're forced to resize to a specific size. if (!m_containerSize.isEmpty()) return m_containerSize.height(); if (isEmbeddedThroughFrameContainingSVGDocument()) return containingBlock()->availableLogicalHeight(IncludeMarginBorderPadding); if (style()->logicalHeight().isSpecified() || style()->logicalMaxHeight().isSpecified()) return RenderReplaced::computeReplacedLogicalHeight(); if (svg->hasIntrinsicHeight()) return resolveLengthAttributeForSVG(svg->intrinsicHeight(), style()->effectiveZoom(), containingBlock()->availableLogicalHeight(IncludeMarginBorderPadding).toFloat()); // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG. return RenderReplaced::computeReplacedLogicalHeight(); }
LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const { SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); // When we're embedded through SVGImage (border-image/background-image/<html:img>/...) we're forced to resize to a specific size. if (!m_containerSize.isEmpty()) return m_containerSize.width(); if (style()->logicalWidth().isSpecified() || style()->logicalMaxWidth().isSpecified()) return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred); if (svg->widthAttributeEstablishesViewport()) return resolveLengthAttributeForSVG(svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties), style()->effectiveZoom(), containingBlock()->availableLogicalWidth(), view()); // SVG embedded through object/embed/iframe. if (isEmbeddedThroughFrameContainingSVGDocument()) return document()->frame()->ownerRenderer()->availableLogicalWidth(); // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG. return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred); }
void LayoutSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const { // https://www.w3.org/TR/SVG/coords.html#IntrinsicSizing intrinsicSize = calculateIntrinsicSize(); if (!isHorizontalWritingMode()) intrinsicSize = intrinsicSize.transposedSize(); if (!intrinsicSize.isEmpty()) { intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); } else { SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); FloatSize viewBoxSize = svg->viewBox()->currentValue()->value().size(); if (!viewBoxSize.isEmpty()) { // The viewBox can only yield an intrinsic ratio, not an intrinsic size. intrinsicRatio = viewBoxSize.width() / static_cast<double>(viewBoxSize.height()); if (!isHorizontalWritingMode()) intrinsicRatio = 1 / intrinsicRatio; } } }
SVGSVGElement& RenderSVGRoot::svgSVGElement() const { return toSVGSVGElement(nodeForNonAnonymous()); }
bool SVGDocument::childShouldCreateRenderer(const NodeRenderingContext& childContext) const { if (childContext.node()->hasTagName(SVGNames::svgTag)) return toSVGSVGElement(childContext.node())->isValid(); return true; }
void commitChange() override { ASSERT(contextElement()); toSVGSVGElement(contextElement())->updateUserTransform(); }