DrawResult ClippedImage::DrawSingleTile(gfxContext* aContext, const nsIntSize& aSize, const ImageRegion& aRegion, uint32_t aWhichFrame, GraphicsFilter aFilter, 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); if (NS_SUCCEEDED(InnerImage()->GetWidth(&innerSize.width)) && NS_SUCCEEDED(InnerImage()->GetHeight(&innerSize.height))) { 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); } else { MOZ_ASSERT(false, "If ShouldClip() led us to draw then we should never get here"); } // 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)); return InnerImage()->Draw(aContext, size, region, aWhichFrame, aFilter, aSVGContext.map(UnclipViewport, make_pair(innerSize, mClip.Size())), aFlags); }
ClippedImage::Draw(gfxContext* aContext, const nsIntSize& aSize, const ImageRegion& aRegion, uint32_t aWhichFrame, SamplingFilter aSamplingFilter, const Maybe<SVGImageContext>& aSVGContext, uint32_t aFlags, float aOpacity) { if (!ShouldClip()) { return InnerImage()->Draw(aContext, aSize, aRegion, aWhichFrame, aSamplingFilter, aSVGContext, aFlags, aOpacity); } // Check for tiling. If we need to tile then we need to create a // gfxCallbackDrawable to handle drawing for us. if (MustCreateSurface(aContext, aSize, aRegion, aFlags)) { // Create a temporary surface containing a single tile of this image. // GetFrame will call DrawSingleTile internally. DrawResult result; RefPtr<SourceSurface> surface; Tie(result, surface) = GetFrameInternal(aSize, aSVGContext, aWhichFrame, aFlags, aOpacity); if (!surface) { MOZ_ASSERT(result != DrawResult::SUCCESS); return result; } // Create a drawable from that surface. RefPtr<gfxSurfaceDrawable> drawable = new gfxSurfaceDrawable(surface, aSize); // Draw. gfxUtils::DrawPixelSnapped(aContext, drawable, aSize, aRegion, SurfaceFormat::B8G8R8A8, aSamplingFilter, aOpacity); return result; } return DrawSingleTile(aContext, aSize, aRegion, aWhichFrame, aSamplingFilter, aSVGContext, aFlags, aOpacity); }
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); }