bool SVGImage::currentFrameHasSingleSecurityOrigin() const { if (!m_page) return true; LocalFrame* frame = toLocalFrame(m_page->mainFrame()); RELEASE_ASSERT(frame->document()->loadEventFinished()); SVGSVGElement* rootElement = frame->document()->accessSVGExtensions().rootElement(); if (!rootElement) return true; // Don't allow foreignObject elements or images that are not known to be // single-origin since these can leak cross-origin information. for (Node* node = rootElement; node; node = ComposedTreeTraversal::next(*node)) { if (isSVGForeignObjectElement(*node)) return false; if (isSVGImageElement(*node)) { if (!toSVGImageElement(*node).currentFrameHasSingleSecurityOrigin()) return false; } else if (isSVGFEImageElement(*node)) { if (!toSVGFEImageElement(*node).currentFrameHasSingleSecurityOrigin()) return false; } } // Because SVG image rendering disallows external resources and links, these // images effectively are restricted to a single security origin. return true; }
void LayoutSVGImage::layout() { ASSERT(needsLayout()); LayoutAnalyzer::Scope analyzer(*this); updateBoundingBox(); bool transformOrBoundariesUpdate = m_needsTransformUpdate || m_needsBoundariesUpdate; if (m_needsTransformUpdate) { m_localTransform = toSVGImageElement(element())->calculateAnimatedLocalTransform(); m_needsTransformUpdate = false; } if (m_needsBoundariesUpdate) { m_paintInvalidationBoundingBox = m_objectBoundingBox; SVGLayoutSupport::intersectPaintInvalidationRectWithResources(this, m_paintInvalidationBoundingBox); m_needsBoundariesUpdate = false; } // Invalidate all resources of this client if our layout changed. if (everHadLayout() && selfNeedsLayout()) SVGResourcesCache::clientLayoutChanged(this); // If our bounds changed, notify the parents. if (transformOrBoundariesUpdate) LayoutSVGModelObject::setNeedsBoundariesUpdate(); clearNeedsLayout(); }
void SVGImagePainter::paintForeground(const PaintInfo& paintInfo) { const LayoutImageResource* imageResource = m_layoutSVGImage.imageResource(); IntSize imageViewportSize = expandedIntSize(computeImageViewportSize()); if (imageViewportSize.isEmpty()) return; RefPtr<Image> image = imageResource->image( imageViewportSize, m_layoutSVGImage.style()->effectiveZoom()); FloatRect destRect = m_layoutSVGImage.objectBoundingBox(); FloatRect srcRect(0, 0, image->width(), image->height()); SVGImageElement* imageElement = toSVGImageElement(m_layoutSVGImage.element()); imageElement->preserveAspectRatio()->currentValue()->transformRect(destRect, srcRect); InterpolationQuality interpolationQuality = InterpolationDefault; interpolationQuality = ImageQualityController::imageQualityController() ->chooseInterpolationQuality( m_layoutSVGImage, image.get(), image.get(), LayoutSize(destRect.size())); InterpolationQuality previousInterpolationQuality = paintInfo.context.imageInterpolationQuality(); paintInfo.context.setImageInterpolationQuality(interpolationQuality); paintInfo.context.drawImage(image.get(), destRect, &srcRect); paintInfo.context.setImageInterpolationQuality(previousInterpolationQuality); }
bool RenderSVGImage::updateImageViewport() { SVGImageElement* image = toSVGImageElement(element()); FloatRect oldBoundaries = m_objectBoundingBox; bool updatedViewport = false; SVGLengthContext lengthContext(image); m_objectBoundingBox = FloatRect(image->x()->currentValue()->value(lengthContext), image->y()->currentValue()->value(lengthContext), image->width()->currentValue()->value(lengthContext), image->height()->currentValue()->value(lengthContext)); bool boundsChanged = oldBoundaries != m_objectBoundingBox; // Images with preserveAspectRatio=none should force non-uniform scaling. This can be achieved // by setting the image's container size to its intrinsic size. // See: http://www.w3.org/TR/SVG/single-page.html, 7.8 The ‘preserveAspectRatio’ attribute. IntSize newViewportSize; if (image->preserveAspectRatio()->currentValue()->align() == SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) { LayoutSize intrinsicSize = m_imageResource->intrinsicSize(style()->effectiveZoom()); if (intrinsicSize != m_imageResource->imageSize(style()->effectiveZoom())) { newViewportSize = roundedIntSize(intrinsicSize); updatedViewport = true; } } else if (boundsChanged) { newViewportSize = enclosingIntRect(m_objectBoundingBox).size(); updatedViewport = true; } if (updatedViewport) m_imageResource->setContainerSizeForRenderer(newViewportSize); m_needsBoundariesUpdate |= boundsChanged; return updatedViewport; }
FloatSize SVGImagePainter::computeImageViewportSize() const { DCHECK(m_layoutSVGImage.imageResource()->hasImage()); if (toSVGImageElement(m_layoutSVGImage.element()) ->preserveAspectRatio() ->currentValue() ->align() != SVGPreserveAspectRatio::kSvgPreserveaspectratioNone) return m_layoutSVGImage.objectBoundingBox().size(); ImageResourceContent* cachedImage = m_layoutSVGImage.imageResource()->cachedImage(); // Images with preserveAspectRatio=none should force non-uniform scaling. This // can be achieved by setting the image's container size to its viewport size // (i.e. concrete object size returned by the default sizing algorithm.) See // https://www.w3.org/TR/SVG/single-page.html#coords-PreserveAspectRatioAttribute // and https://drafts.csswg.org/css-images-3/#default-sizing. // Avoid returning the size of the broken image. if (cachedImage->errorOccurred()) return FloatSize(); if (cachedImage->getImage()->isSVGImage()) return toSVGImage(cachedImage->getImage()) ->concreteObjectSize(m_layoutSVGImage.objectBoundingBox().size()); return FloatSize(cachedImage->getImage()->size()); }
void RenderSVGImage::layout() { ASSERT(needsLayout()); LayoutRectRecorder recorder(*this); LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this) && selfNeedsLayout()); updateImageViewport(); bool transformOrBoundariesUpdate = m_needsTransformUpdate || m_needsBoundariesUpdate; if (m_needsTransformUpdate) { m_localTransform = toSVGImageElement(element())->animatedLocalTransform(); m_needsTransformUpdate = false; } if (m_needsBoundariesUpdate) { m_repaintBoundingBox = m_objectBoundingBox; SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox); m_needsBoundariesUpdate = false; } // Invalidate all resources of this client if our layout changed. if (everHadLayout() && selfNeedsLayout()) SVGResourcesCache::clientLayoutChanged(this); // If our bounds changed, notify the parents. if (transformOrBoundariesUpdate) RenderSVGModelObject::setNeedsBoundariesUpdate(); repainter.repaintAfterLayout(); clearNeedsLayout(); }
bool SVGImage::currentFrameHasSingleSecurityOrigin() const { if (!m_page) return true; Frame* frame = m_page->mainFrame(); RELEASE_ASSERT(frame->document()->loadEventFinished()); SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement(); if (!rootElement) return true; // Don't allow foreignObject elements or images that are not known to be // single-origin since these can leak cross-origin information. ComposedTreeWalker walker(rootElement); while (Node* node = walker.get()) { if (node->hasTagName(SVGNames::foreignObjectTag)) return false; if (node->hasTagName(SVGNames::imageTag)) return toSVGImageElement(node)->currentFrameHasSingleSecurityOrigin(); if (node->hasTagName(SVGNames::feImageTag)) return toSVGFEImageElement(node)->currentFrameHasSingleSecurityOrigin(); walker.next(); } // Because SVG image rendering disallows external resources and links, these // images effectively are restricted to a single security origin. return true; }
void LayoutSVGImage::layout() { ASSERT(needsLayout()); LayoutAnalyzer::Scope analyzer(*this); // Invalidate all resources of this client if our layout changed. if (everHadLayout() && selfNeedsLayout()) SVGResourcesCache::clientLayoutChanged(this); updateBoundingBox(); bool updateParentBoundaries = false; if (m_needsTransformUpdate) { m_localTransform = toSVGImageElement(element())->calculateTransform( SVGElement::IncludeMotionTransform); m_needsTransformUpdate = false; updateParentBoundaries = true; } if (m_needsBoundariesUpdate) { m_localVisualRect = m_objectBoundingBox; SVGLayoutSupport::adjustVisualRectWithResources(this, m_localVisualRect); m_needsBoundariesUpdate = false; updateParentBoundaries = true; } // If our bounds changed, notify the parents. if (updateParentBoundaries) LayoutSVGModelObject::setNeedsBoundariesUpdate(); ASSERT(!m_needsBoundariesUpdate); ASSERT(!m_needsTransformUpdate); clearNeedsLayout(); }
void SVGImageLoader::dispatchLoadEvent() { if (image()->errorOccurred()) { element()->dispatchEvent(Event::create(EventTypeNames::error)); } else { SVGImageElement* imageElement = toSVGImageElement(element()); imageElement->sendSVGLoadEventToSelfAndAncestorChainIfPossible(); } }
void SVGImageLoader::dispatchLoadEvent() { if (image()->errorOccurred()) element()->dispatchEvent(Event::create(eventNames().errorEvent, false, false)); else { SVGImageElement* imageElement = toSVGImageElement(element()); if (imageElement->externalResourcesRequiredBaseValue()) imageElement->sendSVGLoadEventIfPossible(true); } }
void RenderSVGImage::paintForeground(PaintInfo& paintInfo) { RefPtr<Image> image = m_imageResource->image(); FloatRect destRect = m_objectBoundingBox; FloatRect srcRect(0, 0, image->width(), image->height()); SVGImageElement* imageElement = toSVGImageElement(element()); imageElement->preserveAspectRatioCurrentValue().transformRect(destRect, srcRect); bool useLowQualityScaling = false; if (style()->svgStyle()->bufferedRendering() != BR_STATIC) useLowQualityScaling = ImageQualityController::imageQualityController()->shouldPaintAtLowQuality(paintInfo.context, this, image.get(), image.get(), LayoutSize(destRect.size())); paintInfo.context->drawImage(image.get(), destRect, srcRect, CompositeSourceOver, DoNotRespectImageOrientation, useLowQualityScaling); }
FloatSize LayoutSVGImage::computeImageViewportSize(ImageResource& cachedImage) const { if (toSVGImageElement(element())->preserveAspectRatio()->currentValue()->align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) return m_objectBoundingBox.size(); // Images with preserveAspectRatio=none should force non-uniform // scaling. This can be achieved by setting the image's container size to // its viewport size (i.e. if a viewBox is available - use that - else use intrinsic size.) // See: http://www.w3.org/TR/SVG/single-page.html, 7.8 The 'preserveAspectRatio' attribute. Length intrinsicWidth; Length intrinsicHeight; FloatSize intrinsicRatio; cachedImage.computeIntrinsicDimensions(intrinsicWidth, intrinsicHeight, intrinsicRatio); return intrinsicRatio; }
void SVGImagePainter::paintForeground(const PaintInfo& paintInfo) { RefPtr<Image> image = m_layoutSVGImage.imageResource()->image(); FloatRect destRect = m_layoutSVGImage.objectBoundingBox(); FloatRect srcRect(0, 0, image->width(), image->height()); SVGImageElement* imageElement = toSVGImageElement(m_layoutSVGImage.element()); imageElement->preserveAspectRatio()->currentValue()->transformRect(destRect, srcRect); InterpolationQuality interpolationQuality = InterpolationDefault; interpolationQuality = ImageQualityController::imageQualityController()->chooseInterpolationQuality(paintInfo.context, &m_layoutSVGImage, image.get(), image.get(), LayoutSize(destRect.size())); InterpolationQuality previousInterpolationQuality = paintInfo.context->imageInterpolationQuality(); paintInfo.context->setImageInterpolationQuality(interpolationQuality); paintInfo.context->drawImage(image.get(), destRect, srcRect, SkXfermode::kSrcOver_Mode); paintInfo.context->setImageInterpolationQuality(previousInterpolationQuality); }
void SVGImagePainter::paintForeground(const PaintInfo& paintInfo) { RefPtr<Image> image = m_renderSVGImage.imageResource()->image(); FloatRect destRect = m_renderSVGImage.objectBoundingBox(); FloatRect srcRect(0, 0, image->width(), image->height()); SVGImageElement* imageElement = toSVGImageElement(m_renderSVGImage.element()); imageElement->preserveAspectRatio()->currentValue()->transformRect(destRect, srcRect); InterpolationQuality interpolationQuality = InterpolationDefault; if (m_renderSVGImage.style()->svgStyle().bufferedRendering() != BR_STATIC) interpolationQuality = ImageQualityController::imageQualityController()->chooseInterpolationQuality(paintInfo.context, &m_renderSVGImage, image.get(), image.get(), LayoutSize(destRect.size())); InterpolationQuality previousInterpolationQuality = paintInfo.context->imageInterpolationQuality(); paintInfo.context->setImageInterpolationQuality(interpolationQuality); paintInfo.context->drawImage(image.get(), destRect, srcRect, CompositeSourceOver); paintInfo.context->setImageInterpolationQuality(previousInterpolationQuality); }
SVGImageElement& RenderSVGImage::imageElement() const { return toSVGImageElement(RenderSVGModelObject::element()); }