JSValue jsSVGImageElementXmlspace(ExecState* exec, const Identifier&, const PropertySlot& slot) { JSSVGImageElement* castedThis = static_cast<JSSVGImageElement*>(asObject(slot.slotBase())); UNUSED_PARAM(exec); SVGImageElement* imp = static_cast<SVGImageElement*>(castedThis->impl()); return jsString(exec, imp->xmlspace()); }
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); }
void RenderSVGImage::layout() { ASSERT(needsLayout()); LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); SVGImageElement* image = static_cast<SVGImageElement*>(node()); if (m_needsTransformUpdate) { m_localTransform = image->animatedLocalTransform(); m_needsTransformUpdate = false; } // minimum height setHeight(errorOccurred() ? intrinsicSize().height() : 0); calcWidth(); calcHeight(); m_localBounds = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image)); m_cachedLocalRepaintRect = FloatRect(); repainter.repaintAfterLayout(); setNeedsLayout(false); }
JSValue jsSVGImageElementRequiredExtensions(ExecState* exec, const Identifier&, const PropertySlot& slot) { JSSVGImageElement* castedThis = static_cast<JSSVGImageElement*>(asObject(slot.slotBase())); UNUSED_PARAM(exec); SVGImageElement* imp = static_cast<SVGImageElement*>(castedThis->impl()); return toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->requiredExtensions()), imp); }
void RenderSVGImage::layout() { ASSERT(needsLayout()); LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); SVGImageElement* image = static_cast<SVGImageElement*>(node()); bool updateCachedBoundariesInParents = false; if (m_needsTransformUpdate) { m_localTransform = image->animatedLocalTransform(); m_needsTransformUpdate = false; updateCachedBoundariesInParents = true; } // FIXME: Optimize caching the repaint rects. FloatRect oldBoundaries = m_localBounds; m_localBounds = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image)); m_cachedLocalRepaintRect = FloatRect(); if (!updateCachedBoundariesInParents) updateCachedBoundariesInParents = oldBoundaries != m_localBounds; // Invalidate all resources of this client if our layout changed. if (m_everHadLayout && selfNeedsLayout()) SVGResourcesCache::clientLayoutChanged(this); // If our bounds changed, notify the parents. if (updateCachedBoundariesInParents) RenderSVGModelObject::setNeedsBoundariesUpdate(); repainter.repaintAfterLayout(); setNeedsLayout(false); }
void RenderSVGImage::paint(PaintInfo& paintInfo, const LayoutPoint&) { if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || !m_imageResource->hasImage()) return; FloatRect boundingBox = repaintRectInLocalCoordinates(); if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo)) return; PaintInfo childPaintInfo(paintInfo); bool drawsOutline = style()->outlineWidth() && (childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline); if (drawsOutline || childPaintInfo.phase == PaintPhaseForeground) { GraphicsContextStateSaver stateSaver(*childPaintInfo.context); childPaintInfo.applyTransform(m_localTransform); if (childPaintInfo.phase == PaintPhaseForeground) { SVGRenderingContext renderingContext(this, childPaintInfo); if (renderingContext.isRenderingPrepared()) { RefPtr<Image> image = m_imageResource->image(); FloatRect destRect = m_objectBoundingBox; FloatRect srcRect(0, 0, image->width(), image->height()); SVGImageElement* imageElement = static_cast<SVGImageElement*>(node()); imageElement->preserveAspectRatio().transformRect(destRect, srcRect); childPaintInfo.context->drawImage(image.get(), ColorSpaceDeviceRGB, destRect, srcRect); } } if (drawsOutline) paintOutline(childPaintInfo.context, IntRect(boundingBox)); } }
void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) { if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN) return; paintInfo.context->save(); paintInfo.context->concatCTM(localToParentTransform()); if (paintInfo.phase == PaintPhaseForeground) { SVGResourceFilter* filter = 0; PaintInfo savedInfo(paintInfo); if (prepareToRenderSVGContent(this, paintInfo, m_localBounds, filter)) { FloatRect destRect = m_localBounds; FloatRect srcRect(0, 0, image()->width(), image()->height()); SVGImageElement* imageElt = static_cast<SVGImageElement*>(node()); if (imageElt->preserveAspectRatio().align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) imageElt->preserveAspectRatio().transformRect(destRect, srcRect); paintInfo.context->drawImage(image(), DeviceColorSpace, destRect, srcRect); } finishRenderSVGContent(this, paintInfo, filter, savedInfo.context); } if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth()) paintOutline(paintInfo.context, 0, 0, width(), height(), style()); paintInfo.context->restore(); }
JSValue jsSVGImageElementFarthestViewportElement(ExecState* exec, const Identifier&, const PropertySlot& slot) { JSSVGImageElement* castedThis = static_cast<JSSVGImageElement*>(asObject(slot.slotBase())); UNUSED_PARAM(exec); SVGImageElement* imp = static_cast<SVGImageElement*>(castedThis->impl()); return toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->farthestViewportElement())); }
void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) { if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN) return; paintInfo.context->save(); paintInfo.context->concatCTM(localTransform()); if (paintInfo.phase == PaintPhaseForeground) { SVGResourceFilter* filter = 0; PaintInfo savedInfo(paintInfo); prepareToRenderSVGContent(this, paintInfo, m_localBounds, filter); FloatRect destRect = m_localBounds; FloatRect srcRect(0, 0, image()->width(), image()->height()); SVGImageElement* imageElt = static_cast<SVGImageElement*>(node()); if (imageElt->preserveAspectRatio()->align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) adjustRectsForAspectRatio(destRect, srcRect, imageElt->preserveAspectRatio()); paintInfo.context->drawImage(image(), destRect, srcRect); finishRenderSVGContent(this, paintInfo, m_localBounds, filter, savedInfo.context); } paintInfo.context->restore(); }
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; }
JSValue jsSVGImageElementExternalResourcesRequired(ExecState* exec, const Identifier&, const PropertySlot& slot) { JSSVGImageElement* castedThis = static_cast<JSSVGImageElement*>(asObject(slot.slotBase())); UNUSED_PARAM(exec); SVGImageElement* imp = static_cast<SVGImageElement*>(castedThis->impl()); RefPtr<SVGAnimatedBoolean> obj = imp->externalResourcesRequiredAnimated(); return toJS(exec, castedThis->globalObject(), obj.get(), imp); }
JSValue jsSVGImageElementTransform(ExecState* exec, const Identifier&, const PropertySlot& slot) { JSSVGImageElement* castedThis = static_cast<JSSVGImageElement*>(asObject(slot.slotBase())); UNUSED_PARAM(exec); SVGImageElement* imp = static_cast<SVGImageElement*>(castedThis->impl()); RefPtr<SVGAnimatedTransformList> obj = imp->transformAnimated(); return toJS(exec, castedThis->globalObject(), obj.get(), imp); }
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 = static_cast<SVGImageElement*>(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 = static_cast<SVGImageElement*>(node()); imageElement->preserveAspectRatio().transformRect(destRect, srcRect); paintInfo.context->drawImage(image.get(), ColorSpaceDeviceRGB, destRect, srcRect); }
void nsSVGImageFrame::ReflowSVG() { NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingReflowSVG(this), "This call is probably a wasteful mistake"); MOZ_ASSERT(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY), "ReflowSVG mechanism not designed for this"); if (!nsSVGUtils::NeedsReflowSVG(this)) { return; } float x, y, width, height; SVGImageElement *element = static_cast<SVGImageElement*>(mContent); element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); Rect extent(x, y, width, height); if (!extent.IsEmpty()) { mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent, PresContext()->AppUnitsPerCSSPixel()); } else { mRect.SetEmpty(); } if (mState & NS_FRAME_FIRST_REFLOW) { // Make sure we have our filter property (if any) before calling // FinishAndStoreOverflow (subsequent filter changes are handled off // nsChangeHint_UpdateEffects): nsSVGEffects::UpdateEffects(this); if (!mReflowCallbackPosted) { nsIPresShell* shell = PresContext()->PresShell(); mReflowCallbackPosted = true; shell->PostReflowCallback(this); } } nsRect overflow = nsRect(nsPoint(0,0), mRect.Size()); nsOverflowAreas overflowAreas(overflow, overflow); FinishAndStoreOverflow(overflowAreas, mRect.Size()); mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN); // Invalidate, but only if this is not our first reflow (since if it is our // first reflow then we haven't had our first paint yet). if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { InvalidateFrame(); } }
JSValue JSC_HOST_CALL jsSVGImageElementPrototypeFunctionGetPresentationAttribute(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { UNUSED_PARAM(args); if (!thisValue.inherits(&JSSVGImageElement::s_info)) return throwError(exec, TypeError); JSSVGImageElement* castedThisObj = static_cast<JSSVGImageElement*>(asObject(thisValue)); SVGImageElement* imp = static_cast<SVGImageElement*>(castedThisObj->impl()); const UString& name = args.at(0).toString(exec); JSC::JSValue result = toJS(exec, castedThisObj->globalObject(), WTF::getPtr(imp->getPresentationAttribute(name))); return result; }
JSValue JSC_HOST_CALL jsSVGImageElementPrototypeFunctionHasExtension(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { UNUSED_PARAM(args); if (!thisValue.inherits(&JSSVGImageElement::s_info)) return throwError(exec, TypeError); JSSVGImageElement* castedThisObj = static_cast<JSSVGImageElement*>(asObject(thisValue)); SVGImageElement* imp = static_cast<SVGImageElement*>(castedThisObj->impl()); const UString& extension = args.at(0).toString(exec); JSC::JSValue result = jsBoolean(imp->hasExtension(extension)); return result; }
gfx::Matrix nsSVGImageFrame::GetVectorImageTransform() { float x, y, width, height; SVGImageElement *element = static_cast<SVGImageElement*>(mContent); element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); // No viewBoxTM needed here -- our height/width overrides any concept of // "native size" that the SVG image has, and it will handle viewBox and // preserveAspectRatio on its own once we give it a region to draw into. return gfx::Matrix::Translation(x, y); }
gfx::Matrix nsSVGImageFrame::GetRasterImageTransform(int32_t aNativeWidth, int32_t aNativeHeight) { float x, y, width, height; SVGImageElement *element = static_cast<SVGImageElement*>(mContent); element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); Matrix viewBoxTM = SVGContentUtils::GetViewBoxTransform(width, height, 0, 0, aNativeWidth, aNativeHeight, element->mPreserveAspectRatio); return viewBoxTM * gfx::Matrix::Translation(x, y); }
bool RenderSVGImage::updateImageViewport() { SVGImageElement* image = static_cast<SVGImageElement*>(node()); FloatRect oldBoundaries = m_objectBoundingBox; SVGLengthContext lengthContext(image); m_objectBoundingBox = FloatRect(image->x().value(lengthContext), image->y().value(lengthContext), image->width().value(lengthContext), image->height().value(lengthContext)); if (oldBoundaries == m_objectBoundingBox) return false; m_imageResource->setContainerSizeForRenderer(enclosingIntRect(m_objectBoundingBox).size()); m_needsBoundariesUpdate = true; return 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); }
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); }
nsIFrame* nsSVGImageFrame::GetFrameForPoint(const gfxPoint& aPoint) { if (!(GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD) && !GetHitTestFlags()) { return nullptr; } Rect rect; SVGImageElement *element = static_cast<SVGImageElement*>(mContent); element->GetAnimatedLengthValues(&rect.x, &rect.y, &rect.width, &rect.height, nullptr); if (!rect.Contains(ToPoint(aPoint))) { return nullptr; } // Special case for raster images -- we only want to accept points that fall // in the underlying image's (scaled to fit) native bounds. That region // doesn't necessarily map to our <image> element's [x,y,width,height] if the // raster image's aspect ratio is being preserved. We have to look up the // native image size & our viewBox transform in order to filter out points // that fall outside that area. (This special case doesn't apply to vector // images because they don't limit their drawing to explicit "native // bounds" -- they have an infinite canvas on which to place content.) if (StyleDisplay()->IsScrollableOverflow() && mImageContainer) { if (mImageContainer->GetType() == imgIContainer::TYPE_RASTER) { int32_t nativeWidth, nativeHeight; if (NS_FAILED(mImageContainer->GetWidth(&nativeWidth)) || NS_FAILED(mImageContainer->GetHeight(&nativeHeight)) || nativeWidth == 0 || nativeHeight == 0) { return nullptr; } Matrix viewBoxTM = SVGContentUtils::GetViewBoxTransform(rect.width, rect.height, 0, 0, nativeWidth, nativeHeight, element->mPreserveAspectRatio); if (!nsSVGUtils::HitTestRect(viewBoxTM, 0, 0, nativeWidth, nativeHeight, aPoint.x - rect.x, aPoint.y - rect.y)) { return nullptr; } } } return this; }
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); }
nsresult nsSVGImageFrame::AttributeChanged(int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType) { if (aNameSpaceID == kNameSpaceID_None) { if (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y || aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height) { nsLayoutUtils::PostRestyleEvent( mContent->AsElement(), nsRestyleHint(0), nsChangeHint_InvalidateRenderingObservers); nsSVGUtils::ScheduleReflowSVG(this); return NS_OK; } else if (aAttribute == nsGkAtoms::preserveAspectRatio) { // We don't paint the content of the image using display lists, therefore // we have to invalidate for this children-only transform changes since // there is no layer tree to notice that the transform changed and // recomposite. InvalidateFrame(); return NS_OK; } } if (aNameSpaceID == kNameSpaceID_XLink && aAttribute == nsGkAtoms::href) { // Prevent setting image.src by exiting early if (nsContentUtils::IsImageSrcSetDisabled()) { return NS_OK; } SVGImageElement *element = static_cast<SVGImageElement*>(mContent); if (element->mStringAttributes[SVGImageElement::HREF].IsExplicitlySet()) { element->LoadSVGImage(true, true); } else { element->CancelImageRequests(true); } } return nsSVGImageFrameBase::AttributeChanged(aNameSpaceID, aAttribute, aModType); }
JSValue JSC_HOST_CALL jsSVGImageElementPrototypeFunctionGetScreenCTM(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { UNUSED_PARAM(args); if (!thisValue.inherits(&JSSVGImageElement::s_info)) return throwError(exec, TypeError); JSSVGImageElement* castedThisObj = static_cast<JSSVGImageElement*>(asObject(thisValue)); SVGImageElement* imp = static_cast<SVGImageElement*>(castedThisObj->impl()); JSC::JSValue result = toJS(exec, castedThisObj->globalObject(), JSSVGStaticPODTypeWrapper<TransformationMatrix>::create(imp->getScreenCTM()).get(), imp); return result; }
void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) { if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || !m_imageResource->hasImage()) return; FloatRect boundingBox = repaintRectInLocalCoordinates(); if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo)) return; PaintInfo childPaintInfo(paintInfo); bool drawsOutline = style()->outlineWidth() && (childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline); if (drawsOutline || childPaintInfo.phase == PaintPhaseForeground) { childPaintInfo.context->save(); childPaintInfo.applyTransform(m_localTransform); if (childPaintInfo.phase == PaintPhaseForeground) { PaintInfo savedInfo(childPaintInfo); if (SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo)) { Image* image = m_imageResource->image(); FloatRect destRect = m_localBounds; FloatRect srcRect(0, 0, image->width(), image->height()); SVGImageElement* imageElement = static_cast<SVGImageElement*>(node()); if (imageElement->preserveAspectRatio().align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) imageElement->preserveAspectRatio().transformRect(destRect, srcRect); childPaintInfo.context->drawImage(image, DeviceColorSpace, destRect, srcRect); } SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, savedInfo.context); } if (drawsOutline) paintOutline(childPaintInfo.context, static_cast<int>(boundingBox.x()), static_cast<int>(boundingBox.y()), static_cast<int>(boundingBox.width()), static_cast<int>(boundingBox.height())); childPaintInfo.context->restore(); } }
AffineTransform RenderSVGImage::translationForAttributes() { SVGImageElement *image = static_cast<SVGImageElement*>(node()); return AffineTransform().translate(image->x().value(), image->y().value()); }
//---------------------------------------------------------------------- // nsISVGChildFrame methods: nsresult nsSVGImageFrame::PaintSVG(gfxContext& aContext, const gfxMatrix& aTransform, const nsIntRect *aDirtyRect) { nsresult rv = NS_OK; if (!StyleVisibility()->IsVisible()) return NS_OK; float x, y, width, height; SVGImageElement *imgElem = static_cast<SVGImageElement*>(mContent); imgElem->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); NS_ASSERTION(width > 0 && height > 0, "Should only be painting things with valid width/height"); if (!mImageContainer) { nsCOMPtr<imgIRequest> currentRequest; nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent); if (imageLoader) imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, getter_AddRefs(currentRequest)); if (currentRequest) currentRequest->GetImage(getter_AddRefs(mImageContainer)); } if (mImageContainer) { gfxContextAutoSaveRestore autoRestorer(&aContext); if (StyleDisplay()->IsScrollableOverflow()) { gfxRect clipRect = nsSVGUtils::GetClipRectForFrame(this, x, y, width, height); nsSVGUtils::SetClipRect(&aContext, aTransform, clipRect); } if (!TransformContextForPainting(&aContext, aTransform)) { return NS_ERROR_FAILURE; } // fill-opacity doesn't affect <image>, so if we're allowed to // optimize group opacity, the opacity used for compositing the // image into the current canvas is just the group opacity. float opacity = 1.0f; if (nsSVGUtils::CanOptimizeOpacity(this)) { opacity = StyleDisplay()->mOpacity; } if (opacity != 1.0f || StyleDisplay()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) { aContext.PushGroup(gfxContentType::COLOR_ALPHA); } nscoord appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel(); nsRect dirtyRect; // only used if aDirtyRect is non-null if (aDirtyRect) { NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() || (mState & NS_FRAME_IS_NONDISPLAY), "Display lists handle dirty rect intersection test"); dirtyRect = aDirtyRect->ToAppUnits(appUnitsPerDevPx); // Adjust dirtyRect to match our local coordinate system. nsRect rootRect = nsSVGUtils::TransformFrameRectToOuterSVG(mRect, aTransform, PresContext()); dirtyRect.MoveBy(-rootRect.TopLeft()); } // XXXbholley - I don't think huge images in SVGs are common enough to // warrant worrying about the responsiveness impact of doing synchronous // decodes. The extra code complexity of determinining when we want to // force sync probably just isn't worth it, so always pass FLAG_SYNC_DECODE uint32_t drawFlags = imgIContainer::FLAG_SYNC_DECODE; if (mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) { // Package up the attributes of this image element which can override the // attributes of mImageContainer's internal SVG document. The 'width' & // 'height' values we're passing in here are in CSS units (though they // come from width/height *attributes* in SVG). They influence the region // of the SVG image's internal document that is visible, in combination // with preserveAspectRatio and viewBox. SVGImageContext context(CSSIntSize(width, height), Some(imgElem->mPreserveAspectRatio.GetAnimValue())); // For the actual draw operation to draw crisply (and at the right size), // our destination rect needs to be |width|x|height|, *in dev pixels*. LayoutDeviceSize devPxSize(width, height); nsRect destRect(nsPoint(), LayoutDevicePixel::ToAppUnits(devPxSize, appUnitsPerDevPx)); // Note: Can't use DrawSingleUnscaledImage for the TYPE_VECTOR case. // That method needs our image to have a fixed native width & height, // and that's not always true for TYPE_VECTOR images. nsLayoutUtils::DrawSingleImage( aContext, PresContext(), mImageContainer, nsLayoutUtils::GetGraphicsFilterForFrame(this), destRect, aDirtyRect ? dirtyRect : destRect, &context, drawFlags); } else { // mImageContainer->GetType() == TYPE_RASTER nsLayoutUtils::DrawSingleUnscaledImage( aContext, PresContext(), mImageContainer, nsLayoutUtils::GetGraphicsFilterForFrame(this), nsPoint(0, 0), aDirtyRect ? &dirtyRect : nullptr, drawFlags); } if (opacity != 1.0f || StyleDisplay()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) { aContext.PopGroupToSource(); aContext.SetOperator(gfxContext::OPERATOR_OVER); aContext.Paint(opacity); } // gfxContextAutoSaveRestore goes out of scope & cleans up our gfxContext } return rv; }