VectorImage::Draw(gfxContext* aContext, const nsIntSize& aSize, const ImageRegion& aRegion, uint32_t aWhichFrame, SamplingFilter aSamplingFilter, const Maybe<SVGImageContext>& aSVGContext, uint32_t aFlags) { if (aWhichFrame > FRAME_MAX_VALUE) { return DrawResult::BAD_ARGS; } if (!aContext) { return DrawResult::BAD_ARGS; } if (mError) { return DrawResult::BAD_IMAGE; } if (!mIsFullyLoaded) { return DrawResult::NOT_READY; } if (mIsDrawing) { NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw"); return DrawResult::TEMPORARY_ERROR; } if (mAnimationConsumers == 0 && mProgressTracker) { mProgressTracker->OnUnlockedDraw(); } AutoRestore<bool> autoRestoreIsDrawing(mIsDrawing); mIsDrawing = true; Maybe<SVGImageContext> svgContext; // If FLAG_FORCE_PRESERVEASPECTRATIO_NONE bit is set, that mean we should // overwrite SVG preserveAspectRatio attibute of this image with none, and // always stretch this image to viewport non-uniformly. // And we can do this only if the caller pass in the the SVG viewport, via // aSVGContext. if ((aFlags & FLAG_FORCE_PRESERVEASPECTRATIO_NONE) && aSVGContext.isSome()) { Maybe<SVGPreserveAspectRatio> aspectRatio = Some(SVGPreserveAspectRatio(SVG_PRESERVEASPECTRATIO_NONE, SVG_MEETORSLICE_UNKNOWN)); svgContext = Some(SVGImageContext(aSVGContext->GetViewportSize(), aspectRatio)); } else { svgContext = aSVGContext; } float animTime = (aWhichFrame == FRAME_FIRST) ? 0.0f : mSVGDocumentWrapper->GetCurrentTime(); AutoSVGRenderingState autoSVGState(svgContext, animTime, mSVGDocumentWrapper->GetRootSVGElem()); SVGDrawingParameters params(aContext, aSize, aRegion, aSamplingFilter, svgContext, animTime, aFlags); // If we have an prerasterized version of this image that matches the // drawing parameters, use that. RefPtr<gfxDrawable> svgDrawable = LookupCachedSurface(params); if (svgDrawable) { Show(svgDrawable, params); return DrawResult::SUCCESS; } // We didn't get a hit in the surface cache, so we'll need to rerasterize. CreateSurfaceAndShow(params); return DrawResult::SUCCESS; }
VectorImage::Draw(gfxContext* aContext, const nsIntSize& aSize, const ImageRegion& aRegion, uint32_t aWhichFrame, Filter aFilter, const Maybe<SVGImageContext>& aSVGContext, uint32_t aFlags) { if (aWhichFrame > FRAME_MAX_VALUE) { return DrawResult::BAD_ARGS; } if (!aContext) { return DrawResult::BAD_ARGS; } if (mError) { return DrawResult::BAD_IMAGE; } if (!mIsFullyLoaded) { return DrawResult::NOT_READY; } if (mIsDrawing) { NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw"); return DrawResult::TEMPORARY_ERROR; } if (mAnimationConsumers == 0 && mProgressTracker) { mProgressTracker->OnUnlockedDraw(); } AutoRestore<bool> autoRestoreIsDrawing(mIsDrawing); mIsDrawing = true; Maybe<SVGImageContext> svgContext; // If FLAG_FORCE_PRESERVEASPECTRATIO_NONE bit is set, that mean we should // overwrite SVG preserveAspectRatio attibute of this image with none, and // always stretch this image to viewport non-uniformly. // And we can do this only if the caller pass in the the SVG viewport, via // aSVGContext. if ((aFlags & FLAG_FORCE_PRESERVEASPECTRATIO_NONE) && aSVGContext.isSome()) { Maybe<SVGPreserveAspectRatio> aspectRatio = Some(SVGPreserveAspectRatio(SVG_PRESERVEASPECTRATIO_NONE, SVG_MEETORSLICE_UNKNOWN)); svgContext = Some(SVGImageContext(aSVGContext->GetViewportSize(), aspectRatio)); } else { svgContext = aSVGContext; } float animTime = (aWhichFrame == FRAME_FIRST) ? 0.0f : mSVGDocumentWrapper->GetCurrentTime(); AutoSVGRenderingState autoSVGState(svgContext, animTime, mSVGDocumentWrapper->GetRootSVGElem()); SVGDrawingParameters params(aContext, aSize, aRegion, aFilter, svgContext, animTime, aFlags); if (aFlags & FLAG_BYPASS_SURFACE_CACHE) { CreateSurfaceAndShow(params); return DrawResult::SUCCESS; } LookupResult result = SurfaceCache::Lookup(ImageKey(this), VectorSurfaceKey(params.size, params.svgContext, params.animationTime)); // Draw. if (result) { RefPtr<SourceSurface> surface = result.DrawableRef()->GetSurface(); if (surface) { RefPtr<gfxDrawable> svgDrawable = new gfxSurfaceDrawable(surface, result.DrawableRef()->GetSize()); Show(svgDrawable, params); return DrawResult::SUCCESS; } // We lost our surface due to some catastrophic event. RecoverFromLossOfSurfaces(); } CreateSurfaceAndShow(params); return DrawResult::SUCCESS; }
DrawResult ClippedImage::DrawSingleTile(gfxContext* aContext, const nsIntSize& aSize, const ImageRegion& aRegion, uint32_t aWhichFrame, SamplingFilter aSamplingFilter, const Maybe<SVGImageContext>& aSVGContext, uint32_t aFlags) { MOZ_ASSERT(!MustCreateSurface(aContext, aSize, aRegion, aFlags), "Shouldn't need to create a surface"); gfxRect clip(mClip.x, mClip.y, mClip.width, mClip.height); nsIntSize size(aSize), innerSize(aSize); bool needScale = false; if (mSVGViewportSize && !mSVGViewportSize->IsEmpty()) { innerSize = *mSVGViewportSize; needScale = true; } else if (NS_SUCCEEDED(InnerImage()->GetWidth(&innerSize.width)) && NS_SUCCEEDED(InnerImage()->GetHeight(&innerSize.height))) { needScale = true; } else { MOZ_ASSERT_UNREACHABLE( "If ShouldClip() led us to draw then we should never get here"); } if (needScale) { double scaleX = aSize.width / clip.width; double scaleY = aSize.height / clip.height; // Map the clip and size to the scale requested by the caller. clip.Scale(scaleX, scaleY); size = innerSize; size.Scale(scaleX, scaleY); } // We restrict our drawing to only the clipping region, and translate so that // the clipping region is placed at the position the caller expects. ImageRegion region(aRegion); region.MoveBy(clip.x, clip.y); region = region.Intersect(clip); gfxContextMatrixAutoSaveRestore saveMatrix(aContext); aContext->Multiply(gfxMatrix::Translation(-clip.x, -clip.y)); auto unclipViewport = [&](const SVGImageContext& aOldContext) { // Map the viewport to the inner image. Note that we don't take the aSize // parameter of imgIContainer::Draw into account, just the clipping region. // The size in pixels at which the output will ultimately be drawn is // irrelevant here since the purpose of the SVG viewport size is to // determine what *region* of the SVG document will be drawn. CSSIntSize vSize(aOldContext.GetViewportSize()); vSize.width = ceil(vSize.width * double(innerSize.width) / mClip.width); vSize.height = ceil(vSize.height * double(innerSize.height) / mClip.height); return SVGImageContext(vSize, aOldContext.GetPreserveAspectRatio()); }; return InnerImage()->Draw(aContext, size, region, aWhichFrame, aSamplingFilter, aSVGContext.map(unclipViewport), aFlags); }