From a140512abd031c568a354b9548cc13c5daa98bd7 Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Thu, 13 May 2021 16:24:08 +0000 Subject: [PATCH] Bug 1704792 - Part 7. Integrate use of ImageIntRegion with WebRender display lists. r=jrmuizel This patch hooks up the ImageIntRegion to the blob recording and makes any necessary adjusts to the display list creation to take advantage of it. Differential Revision: https://phabricator.services.mozilla.com/D114986 --- image/SourceSurfaceBlobImage.cpp | 40 +++++++++++++++++++---------- image/SourceSurfaceBlobImage.h | 3 +++ image/VectorImage.cpp | 15 +++++++---- layout/painting/nsImageRenderer.cpp | 29 +++++++++++++-------- layout/svg/SVGImageFrame.cpp | 2 +- 5 files changed, 59 insertions(+), 30 deletions(-) diff --git a/image/SourceSurfaceBlobImage.cpp b/image/SourceSurfaceBlobImage.cpp index 150283fcb322..631951b5c726 100644 --- a/image/SourceSurfaceBlobImage.cpp +++ b/image/SourceSurfaceBlobImage.cpp @@ -22,10 +22,12 @@ namespace mozilla::image { SourceSurfaceBlobImage::SourceSurfaceBlobImage( image::SVGDocumentWrapper* aSVGDocumentWrapper, - const Maybe& aSVGContext, const IntSize& aSize, + const Maybe& aSVGContext, + const Maybe& aRegion, const IntSize& aSize, uint32_t aWhichFrame, uint32_t aImageFlags) : mSVGDocumentWrapper(aSVGDocumentWrapper), mSVGContext(aSVGContext), + mRegion(aRegion), mSize(aSize), mWhichFrame(aWhichFrame), mImageFlags(aImageFlags) { @@ -138,7 +140,10 @@ Maybe SourceSurfaceBlobImage::RecordDrawing( // re-record the SVG image draw commands. auto* rootManager = aManager->GetRenderRootStateManager(); auto* wrBridge = aManager->WrBridge(); - IntRect imageRect(IntPoint(0, 0), mSize); + + IntRect imageRect = + mRegion ? mRegion->Rect() : IntRect(IntPoint(0, 0), mSize); + IntRect imageRectOrigin = imageRect - imageRect.TopLeft(); std::vector> fonts; bool validFonts = true; @@ -166,7 +171,7 @@ Maybe SourceSurfaceBlobImage::RecordDrawing( RefPtr dummyDt = Factory::CreateDrawTarget( BackendType::SKIA, IntSize(1, 1), SurfaceFormat::OS_RGBA); RefPtr dt = - Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageRect); + Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageRectOrigin); if (!dt || !dt->IsValid()) { return Nothing(); @@ -179,9 +184,15 @@ Maybe SourceSurfaceBlobImage::RecordDrawing( ? 0.0f : mSVGDocumentWrapper->GetCurrentTimeAsFloat(); - SVGDrawingParameters params( - nullptr, mSize, mSize, ImageRegion::Create(mSize), - SamplingFilter::POINT, mSVGContext, animTime, mImageFlags, 1.0); + auto region = + mRegion + ? mRegion->ToImageRegion() + : ImageRegion::Create(gfxRect(imageRect.x, imageRect.y, + imageRect.width, imageRect.height)); + + SVGDrawingParameters params(nullptr, mSize, mSize, region, + SamplingFilter::POINT, mSVGContext, animTime, + mImageFlags, 1.0); AutoRestoreSVGState autoRestore(params, mSVGDocumentWrapper, contextPaint); @@ -195,13 +206,16 @@ Maybe SourceSurfaceBlobImage::RecordDrawing( // Draw using the drawable the caller provided. RefPtr ctx = gfxContext::CreateOrNull(dt); MOZ_ASSERT(ctx); // Already checked the draw target above. - gfxUtils::DrawPixelSnapped( - ctx, svgDrawable, SizeDouble(mSize), - image::ImageRegion::Create(ThebesRect(imageRect)), - SurfaceFormat::OS_RGBA, SamplingFilter::POINT, mImageFlags); + + ctx->SetMatrix( + ctx->CurrentMatrix().PreTranslate(-imageRect.x, -imageRect.y)); + + gfxUtils::DrawPixelSnapped(ctx, svgDrawable, SizeDouble(mSize), region, + SurfaceFormat::OS_RGBA, SamplingFilter::POINT, + mImageFlags); } - recorder->FlushItem(imageRect); + recorder->FlushItem(imageRectOrigin); recorder->Finish(); if (!validFonts) { @@ -214,10 +228,10 @@ Maybe SourceSurfaceBlobImage::RecordDrawing( wr::BlobImageKey key = aBlobKey ? aBlobKey.value() : wr::BlobImageKey{wrBridge->GetNextImageKey()}; - wr::ImageDescriptor descriptor(mSize, 0, SurfaceFormat::OS_RGBA, + wr::ImageDescriptor descriptor(imageRect.Size(), 0, SurfaceFormat::OS_RGBA, wr::OpacityType::HasAlphaChannel); - ImageIntRect visibleRect(0, 0, mSize.width, mSize.height); + auto visibleRect = ImageIntRect::FromUnknownRect(imageRectOrigin); if (aBlobKey) { if (!aResources.UpdateBlobImage(key, descriptor, bytes, visibleRect, visibleRect)) { diff --git a/image/SourceSurfaceBlobImage.h b/image/SourceSurfaceBlobImage.h index f3d1cb12e0b9..71e9e7227b32 100644 --- a/image/SourceSurfaceBlobImage.h +++ b/image/SourceSurfaceBlobImage.h @@ -11,6 +11,7 @@ #include "mozilla/SVGImageContext.h" #include "mozilla/gfx/2D.h" #include "mozilla/layers/WebRenderLayerManager.h" +#include "ImageRegion.h" #include @@ -79,6 +80,7 @@ class SourceSurfaceBlobImage final : public gfx::SourceSurface { SourceSurfaceBlobImage(SVGDocumentWrapper* aSVGDocumentWrapper, const Maybe& aSVGContext, + const Maybe& aRegion, const gfx::IntSize& aSize, uint32_t aWhichFrame, uint32_t aImageFlags); @@ -116,6 +118,7 @@ class SourceSurfaceBlobImage final : public gfx::SourceSurface { RefPtr mSVGDocumentWrapper; Maybe mSVGContext; + Maybe mRegion; gfx::IntSize mSize; uint32_t mWhichFrame; uint32_t mImageFlags; diff --git a/image/VectorImage.cpp b/image/VectorImage.cpp index cab8c99da52e..3e5946813583 100644 --- a/image/VectorImage.cpp +++ b/image/VectorImage.cpp @@ -735,21 +735,26 @@ VectorImage::GetFrameInternal(const IntSize& aSize, ? 0.0f : mSVGDocumentWrapper->GetCurrentTimeAsFloat(); + // If we aren't given a region, create one that covers the whole SVG image. + ImageRegion region = + aRegion ? aRegion->ToImageRegion() : ImageRegion::Create(decodeSize); + // By using a null gfxContext, we ensure that we will always attempt to // create a surface, even if we aren't capable of caching it (e.g. due to our // flags, having an animation, etc). Otherwise CreateSurface will assume that // the caller is capable of drawing directly to its own draw target if we // cannot cache. - SVGDrawingParameters params( - nullptr, decodeSize, aSize, ImageRegion::Create(decodeSize), - SamplingFilter::POINT, aSVGContext, animTime, aFlags, 1.0); + SVGDrawingParameters params(nullptr, decodeSize, aSize, region, + SamplingFilter::POINT, aSVGContext, animTime, + aFlags, 1.0); // Blob recorded vector images just create a simple surface responsible for // generating blob keys and recording bindings. The recording won't happen // until the caller requests the key after GetImageContainerAtSize. if (aFlags & FLAG_RECORD_BLOB) { - RefPtr surface = new SourceSurfaceBlobImage( - mSVGDocumentWrapper, aSVGContext, decodeSize, whichFrame, aFlags); + RefPtr surface = + new SourceSurfaceBlobImage(mSVGDocumentWrapper, aSVGContext, aRegion, + decodeSize, whichFrame, aFlags); return MakeTuple(ImgDrawResult::SUCCESS, decodeSize, std::move(surface)); } diff --git a/layout/painting/nsImageRenderer.cpp b/layout/painting/nsImageRenderer.cpp index 3682ec642f51..76589678f5b0 100644 --- a/layout/painting/nsImageRenderer.cpp +++ b/layout/painting/nsImageRenderer.cpp @@ -581,6 +581,11 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems( } case StyleImage::Tag::Rect: case StyleImage::Tag::Url: { + ExtendMode extendMode = mExtendMode; + if (aDest.Contains(aFill)) { + extendMode = ExtendMode::CLAMP; + } + uint32_t containerFlags = imgIContainer::FLAG_ASYNC_NOTIFY; if (mFlags & (nsImageRenderer::FLAG_PAINTING_TO_WINDOW | nsImageRenderer::FLAG_HIGH_QUALITY_SCALING)) { @@ -589,7 +594,7 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems( if (mFlags & nsImageRenderer::FLAG_SYNC_DECODE_IMAGES) { containerFlags |= imgIContainer::FLAG_SYNC_DECODE; } - if (mExtendMode == ExtendMode::CLAMP && + if (extendMode == ExtendMode::CLAMP && StaticPrefs::image_svg_blob_image() && mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) { containerFlags |= imgIContainer::FLAG_RECORD_BLOB; @@ -607,13 +612,19 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems( mForFrame->PresContext()->AppUnitsPerDevPixel(); LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(aDest, appUnitsPerDevPixel); + LayoutDeviceRect clipRect = + LayoutDeviceRect::FromAppUnits(aFill, appUnitsPerDevPixel); auto stretchSize = wr::ToLayoutSize(destRect.Size()); gfx::IntSize decodeSize = nsLayoutUtils::ComputeImageContainerDrawingParameters( - mImageContainer, mForFrame, destRect, destRect, aSc, + mImageContainer, mForFrame, destRect, clipRect, aSc, containerFlags, svgContext, region); + if (extendMode != ExtendMode::CLAMP) { + region = Nothing(); + } + RefPtr container; drawResult = mImageContainer->GetImageContainerAtSize( aManager->LayerManager(), decodeSize, svgContext, region, @@ -624,11 +635,9 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems( } if (containerFlags & imgIContainer::FLAG_RECORD_BLOB) { - MOZ_ASSERT(mExtendMode == ExtendMode::CLAMP); - LayoutDeviceRect clipRect = - LayoutDeviceRect::FromAppUnits(aFill, appUnitsPerDevPixel); + MOZ_ASSERT(extendMode == ExtendMode::CLAMP); aManager->CommandBuilder().PushBlobImage( - aItem, container, aBuilder, aResources, destRect, clipRect); + aItem, container, aBuilder, aResources, clipRect, clipRect); break; } @@ -644,11 +653,9 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems( } wr::LayoutRect dest = wr::ToLayoutRect(destRect); + wr::LayoutRect clip = wr::ToLayoutRect(clipRect); - wr::LayoutRect clip = wr::ToLayoutRect( - LayoutDeviceRect::FromAppUnits(aFill, appUnitsPerDevPixel)); - - if (mExtendMode == ExtendMode::CLAMP) { + if (extendMode == ExtendMode::CLAMP) { // The image is not repeating. Just push as a regular image. aBuilder.PushImage(dest, clip, !aItem->BackfaceIsHidden(), rendering, key.value()); @@ -662,7 +669,7 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems( appUnitsPerDevPixel); wr::LayoutRect fill = wr::ToLayoutRect(fillRect); - switch (mExtendMode) { + switch (extendMode) { case ExtendMode::REPEAT_Y: fill.origin.x = dest.origin.x; fill.size.width = dest.size.width; diff --git a/layout/svg/SVGImageFrame.cpp b/layout/svg/SVGImageFrame.cpp index ffcefcaf8a61..3c96f5ed6d58 100644 --- a/layout/svg/SVGImageFrame.cpp +++ b/layout/svg/SVGImageFrame.cpp @@ -614,7 +614,7 @@ bool SVGImageFrame::CreateWebRenderCommands( Maybe region; IntSize decodeSize = nsLayoutUtils::ComputeImageContainerDrawingParameters( - mImageContainer, this, destRect, destRect, aSc, flags, svgContext, + mImageContainer, this, destRect, clipRect, aSc, flags, svgContext, region); RefPtr container;