mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 1191114 (Part 1) - Always detect HAS_TRANSPARENCY during the metadata decode. r=tn
--HG-- extra : rebase_source : 97c8568f33abd1f2a8d9ef5679ce3ac904f0758f
This commit is contained in:
parent
f63a930fb6
commit
c012dc0aa9
@ -369,6 +369,15 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
return;
|
||||
}
|
||||
|
||||
// We treat BMPs as transparent if they're 32bpp and alpha is enabled, but
|
||||
// also if they use RLE encoding, because the 'delta' mode can skip pixels
|
||||
// and cause implicit transparency.
|
||||
if ((mBIH.compression == BMPINFOHEADER::RLE8) ||
|
||||
(mBIH.compression == BMPINFOHEADER::RLE4) ||
|
||||
(mBIH.bpp == 32 && mUseAlphaData)) {
|
||||
PostHasTransparency();
|
||||
}
|
||||
|
||||
// We have the size. If we're doing a metadata decode, we're done.
|
||||
if (IsMetadataDecode()) {
|
||||
return;
|
||||
|
@ -50,6 +50,8 @@ mailing address.
|
||||
#include <algorithm>
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
@ -161,6 +163,27 @@ nsGIFDecoder2::BeginGIF()
|
||||
PostSize(mGIFStruct.screen_width, mGIFStruct.screen_height);
|
||||
}
|
||||
|
||||
void
|
||||
nsGIFDecoder2::CheckForTransparency(IntRect aFrameRect)
|
||||
{
|
||||
// Check if the image has a transparent color in its palette.
|
||||
if (mGIFStruct.is_transparent) {
|
||||
PostHasTransparency();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mGIFStruct.images_decoded > 0) {
|
||||
return; // We only care about first frame padding below.
|
||||
}
|
||||
|
||||
// If we need padding on the first frame, that means we don't draw into part
|
||||
// of the image at all. Report that as transparency.
|
||||
IntRect imageRect(0, 0, mGIFStruct.screen_width, mGIFStruct.screen_height);
|
||||
if (!imageRect.IsEqualEdges(aFrameRect)) {
|
||||
PostHasTransparency();
|
||||
}
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
nsresult
|
||||
nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
|
||||
@ -170,13 +193,14 @@ nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
|
||||
gfx::SurfaceFormat format;
|
||||
if (mGIFStruct.is_transparent) {
|
||||
format = gfx::SurfaceFormat::B8G8R8A8;
|
||||
PostHasTransparency();
|
||||
} else {
|
||||
format = gfx::SurfaceFormat::B8G8R8X8;
|
||||
}
|
||||
|
||||
nsIntRect frameRect(mGIFStruct.x_offset, mGIFStruct.y_offset,
|
||||
mGIFStruct.width, mGIFStruct.height);
|
||||
IntRect frameRect(mGIFStruct.x_offset, mGIFStruct.y_offset,
|
||||
mGIFStruct.width, mGIFStruct.height);
|
||||
|
||||
CheckForTransparency(frameRect);
|
||||
|
||||
// Use correct format, RGB for first frame, PAL for following frames
|
||||
// and include transparency to allow for optimization of opaque images
|
||||
@ -186,12 +210,6 @@ nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
|
||||
rv = AllocateFrame(mGIFStruct.images_decoded, GetSize(),
|
||||
frameRect, format, aDepth);
|
||||
} else {
|
||||
if (!nsIntRect(nsIntPoint(), GetSize()).IsEqualEdges(frameRect)) {
|
||||
// We need padding on the first frame, which means that we don't draw into
|
||||
// part of the image at all. Report that as transparency.
|
||||
PostHasTransparency();
|
||||
}
|
||||
|
||||
// Regardless of depth of input, the first frame is decoded into 24bit RGB.
|
||||
rv = AllocateFrame(mGIFStruct.images_decoded, GetSize(),
|
||||
frameRect, format);
|
||||
@ -689,12 +707,6 @@ nsGIFDecoder2::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
mGIFStruct.screen_height = GETINT16(q + 2);
|
||||
mGIFStruct.global_colormap_depth = (q[4]&0x07) + 1;
|
||||
|
||||
if (IsMetadataDecode()) {
|
||||
MOZ_ASSERT(!mGIFOpen, "Gif should not be open at this point");
|
||||
PostSize(mGIFStruct.screen_width, mGIFStruct.screen_height);
|
||||
return;
|
||||
}
|
||||
|
||||
// screen_bgcolor is not used
|
||||
//mGIFStruct.screen_bgcolor = q[5];
|
||||
// q[6] = Pixel Aspect Ratio
|
||||
@ -731,6 +743,9 @@ nsGIFDecoder2::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
case gif_image_start:
|
||||
switch (*q) {
|
||||
case GIF_TRAILER:
|
||||
if (IsMetadataDecode()) {
|
||||
return;
|
||||
}
|
||||
mGIFStruct.state = gif_done;
|
||||
break;
|
||||
|
||||
@ -943,6 +958,9 @@ nsGIFDecoder2::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
|
||||
// If we were doing a metadata decode, we're done.
|
||||
if (IsMetadataDecode()) {
|
||||
IntRect frameRect(mGIFStruct.x_offset, mGIFStruct.y_offset,
|
||||
mGIFStruct.width, mGIFStruct.height);
|
||||
CheckForTransparency(frameRect);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ private:
|
||||
bool DoLzw(const uint8_t* q);
|
||||
bool SetHold(const uint8_t* buf, uint32_t count,
|
||||
const uint8_t* buf2 = nullptr, uint32_t count2 = 0);
|
||||
void CheckForTransparency(gfx::IntRect aFrameRect);
|
||||
|
||||
inline int ClearCode() const { return 1 << mGIFStruct.datasize; }
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
@ -136,6 +138,20 @@ nsPNGDecoder::~nsPNGDecoder()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPNGDecoder::CheckForTransparency(SurfaceFormat aFormat,
|
||||
const IntRect& aFrameRect)
|
||||
{
|
||||
// Check if the image has a transparent color in its palette.
|
||||
if (aFormat == SurfaceFormat::B8G8R8A8) {
|
||||
PostHasTransparency();
|
||||
}
|
||||
|
||||
// PNGs shouldn't have first-frame padding.
|
||||
MOZ_ASSERT_IF(mNumFrames == 0,
|
||||
IntRect(IntPoint(), GetSize()).IsEqualEdges(aFrameRect));
|
||||
}
|
||||
|
||||
// CreateFrame() is used for both simple and animated images
|
||||
nsresult
|
||||
nsPNGDecoder::CreateFrame(png_uint_32 aXOffset, png_uint_32 aYOffset,
|
||||
@ -145,17 +161,8 @@ nsPNGDecoder::CreateFrame(png_uint_32 aXOffset, png_uint_32 aYOffset,
|
||||
MOZ_ASSERT(HasSize());
|
||||
MOZ_ASSERT(!IsMetadataDecode());
|
||||
|
||||
if (aFormat == gfx::SurfaceFormat::B8G8R8A8) {
|
||||
PostHasTransparency();
|
||||
}
|
||||
|
||||
nsIntRect frameRect(aXOffset, aYOffset, aWidth, aHeight);
|
||||
if (mNumFrames == 0 &&
|
||||
!nsIntRect(nsIntPoint(), GetSize()).IsEqualEdges(frameRect)) {
|
||||
// We need padding on the first frame, which means that we don't draw into
|
||||
// part of the image at all. Report that as transparency.
|
||||
PostHasTransparency();
|
||||
}
|
||||
IntRect frameRect(aXOffset, aYOffset, aWidth, aHeight);
|
||||
CheckForTransparency(aFormat, frameRect);
|
||||
|
||||
// XXX(seth): Some tests depend on the first frame of PNGs being B8G8R8A8.
|
||||
// This is something we should fix.
|
||||
@ -268,7 +275,7 @@ nsPNGDecoder::InitInternal()
|
||||
|
||||
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
|
||||
// Ignore unused chunks
|
||||
if (mCMSMode == eCMSMode_Off) {
|
||||
if (mCMSMode == eCMSMode_Off || IsMetadataDecode()) {
|
||||
png_set_keep_unknown_chunks(mPNG, 1, color_chunks, 2);
|
||||
}
|
||||
|
||||
@ -486,12 +493,6 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||
png_longjmp(decoder->mPNG, 1);
|
||||
}
|
||||
|
||||
if (decoder->IsMetadataDecode()) {
|
||||
// We have the size, so we don't need to decode any further.
|
||||
decoder->mSuccessfulEarlyFinish = true;
|
||||
png_longjmp(decoder->mPNG, 1);
|
||||
}
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE) {
|
||||
png_set_expand(png_ptr);
|
||||
}
|
||||
@ -594,6 +595,16 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||
png_longjmp(decoder->mPNG, 1); // invalid number of channels
|
||||
}
|
||||
|
||||
if (decoder->IsMetadataDecode()) {
|
||||
decoder->CheckForTransparency(decoder->format,
|
||||
IntRect(0, 0, width, height));
|
||||
|
||||
// We have the size and transparency information we're looking for, so we
|
||||
// don't need to decode any further.
|
||||
decoder->mSuccessfulEarlyFinish = true;
|
||||
png_longjmp(decoder->mPNG, 1);
|
||||
}
|
||||
|
||||
#ifdef PNG_APNG_SUPPORTED
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) {
|
||||
png_set_progressive_frame_fn(png_ptr, nsPNGDecoder::frame_info_callback,
|
||||
|
@ -35,6 +35,9 @@ public:
|
||||
gfx::SurfaceFormat aFormat);
|
||||
void EndImageFrame();
|
||||
|
||||
void CheckForTransparency(gfx::SurfaceFormat aFormat,
|
||||
const gfx::IntRect& aFrameRect);
|
||||
|
||||
// Check if PNG is valid ICO (32bpp RGBA)
|
||||
// http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
|
||||
bool IsValidICO() const
|
||||
|
@ -48,8 +48,12 @@ function testFiles() {
|
||||
// GIFs with padding on the first frame are always transparent.
|
||||
yield ["first-frame-padding.gif", true];
|
||||
|
||||
// JPEGs and BMPs are never transparent.
|
||||
// JPEGs are never transparent.
|
||||
yield ["damon.jpg", false];
|
||||
|
||||
// Most BMPs are not transparent. (The TestMetadata GTest, which will
|
||||
// eventually replace this test totally, has coverage for the kinds that can be
|
||||
// transparent.)
|
||||
yield ["opaque.bmp", false];
|
||||
|
||||
// ICO files which contain BMPs have an additional type of transparency - the
|
||||
|
Loading…
Reference in New Issue
Block a user