Bug 1045929 (Part 2) - Implement downscale-during-decode for JPEG images. r=tn

This commit is contained in:
Seth Fowler 2015-01-20 03:06:37 -08:00
parent 7cd4579890
commit d472d2fbf5
3 changed files with 57 additions and 7 deletions

View File

@ -139,6 +139,20 @@ nsJPEGDecoder::SpeedHistogram()
return Telemetry::IMAGE_DECODE_SPEED_JPEG;
}
nsresult
nsJPEGDecoder::SetTargetSize(const nsIntSize& aSize)
{
// Make sure the size is reasonable.
if (MOZ_UNLIKELY(aSize.width <= 0 || aSize.height <= 0)) {
return NS_ERROR_FAILURE;
}
// Create a downscaler that we'll filter our output through.
mDownscaler.emplace(aSize);
return NS_OK;
}
void
nsJPEGDecoder::InitInternal()
{
@ -394,6 +408,17 @@ nsJPEGDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
return;
}
if (mDownscaler) {
nsresult rv = mDownscaler->BeginFrame(GetSize(),
mImageData,
/* aHasAlpha = */ false);
if (NS_FAILED(rv)) {
mState = JPEG_ERROR;
return;
}
}
PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
(" JPEGDecoderAccounting: nsJPEGDecoder::"
"Write -- created image frame with %ux%u pixels",
@ -512,6 +537,7 @@ nsJPEGDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
break;
mInfo.output_scanline = 0;
mDownscaler->ResetForNextProgressivePass();
}
}
@ -591,9 +617,15 @@ nsJPEGDecoder::OutputScanlines(bool* suspend)
const uint32_t top = mInfo.output_scanline;
while ((mInfo.output_scanline < mInfo.output_height)) {
// Use the Cairo image buffer as scanline buffer
uint32_t* imageRow = ((uint32_t*)mImageData) +
(mInfo.output_scanline * mInfo.output_width);
uint32_t* imageRow = nullptr;
if (mDownscaler) {
imageRow = reinterpret_cast<uint32_t*>(mDownscaler->RowBuffer());
} else {
imageRow = reinterpret_cast<uint32_t*>(mImageData) +
(mInfo.output_scanline * mInfo.output_width);
}
MOZ_ASSERT(imageRow, "Should have a row buffer here");
if (mInfo.out_color_space == MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB) {
// Special case: scanline will be directly converted into packed ARGB
@ -601,6 +633,9 @@ nsJPEGDecoder::OutputScanlines(bool* suspend)
*suspend = true; // suspend
break;
}
if (mDownscaler) {
mDownscaler->CommitRow();
}
continue; // all done for this row!
}
@ -676,13 +711,22 @@ nsJPEGDecoder::OutputScanlines(bool* suspend)
sampleRow[2]);
sampleRow += 3;
}
if (mDownscaler) {
mDownscaler->CommitRow();
}
}
if (top != mInfo.output_scanline) {
nsIntRect r(0, top, mInfo.output_width, mInfo.output_scanline-top);
PostInvalidation(r);
PostInvalidation(nsIntRect(0, top,
mInfo.output_width,
mInfo.output_scanline - top),
mDownscaler ? Some(mDownscaler->TakeInvalidRect())
: Nothing());
}
MOZ_ASSERT(!mDownscaler || !mDownscaler->HasInvalidation(),
"Didn't send downscaler's invalidation");
}

View File

@ -15,6 +15,7 @@
#include "Decoder.h"
#include "Downscaler.h"
#include "nsAutoPtr.h"
#include "nsIInputStream.h"
@ -55,6 +56,8 @@ public:
nsJPEGDecoder(RasterImage* aImage, Decoder::DecodeStyle aDecodeStyle);
virtual ~nsJPEGDecoder();
virtual nsresult SetTargetSize(const nsIntSize& aSize) MOZ_OVERRIDE;
virtual void InitInternal() MOZ_OVERRIDE;
virtual void WriteInternal(const char* aBuffer, uint32_t aCount) MOZ_OVERRIDE;
virtual void FinishInternal() MOZ_OVERRIDE;
@ -66,6 +69,8 @@ protected:
Orientation ReadOrientationFromEXIF();
void OutputScanlines(bool* suspend);
Maybe<Downscaler> mDownscaler;
public:
struct jpeg_decompress_struct mInfo;
struct jpeg_source_mgr mSourceMgr;

View File

@ -34,8 +34,9 @@ ImageFactory::Initialize()
static bool
ShouldDownscaleDuringDecode(const nsCString& aMimeType)
{
// Not enabled for anything yet.
return false;
return aMimeType.EqualsLiteral(IMAGE_JPEG) ||
aMimeType.EqualsLiteral(IMAGE_JPG) ||
aMimeType.EqualsLiteral(IMAGE_PJPEG);
}
static uint32_t