Bug 1089880 (Part 1) - Add a HAS_TRANSPARENCY notification to ImageLib. r=tn

This commit is contained in:
Seth Fowler 2014-11-17 11:16:45 -08:00
parent a0cb0e0b94
commit 5376541aef
12 changed files with 75 additions and 18 deletions

View File

@ -12,6 +12,7 @@
#include "ImageLogging.h"
#include "mozilla/Endian.h"
#include "mozilla/Likely.h"
#include "nsBMPDecoder.h"
#include "nsIInputStream.h"
@ -658,10 +659,10 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
memset(start, 0, pixelCount * sizeof(uint32_t));
PostHasTransparency();
mHaveAlphaData = true;
}
SetPixel(d, p[2], p[1], p[0], mHaveAlphaData ?
p[3] : 0xFF);
SetPixel(d, p[2], p[1], p[0], mHaveAlphaData ? p[3] : 0xFF);
} else {
SetPixel(d, p[2], p[1], p[0]);
}
@ -789,6 +790,9 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
mCurPos += byte;
// Delta encoding makes it possible to skip pixels
// making the image transparent.
if (MOZ_UNLIKELY(!mHaveAlphaData)) {
PostHasTransparency();
}
mUseAlphaData = mHaveAlphaData = true;
if (mCurPos > mBIH.width) {
mCurPos = mBIH.width;
@ -804,6 +808,9 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
mState = eRLEStateInitial;
// Delta encoding makes it possible to skip pixels
// making the image transparent.
if (MOZ_UNLIKELY(!mHaveAlphaData)) {
PostHasTransparency();
}
mUseAlphaData = mHaveAlphaData = true;
mCurLine -= std::min<int32_t>(byte, mCurLine);
break;

View File

@ -164,15 +164,16 @@ nsGIFDecoder2::BeginGIF()
void
nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
{
MOZ_ASSERT(HasSize());
gfx::SurfaceFormat format;
if (mGIFStruct.is_transparent) {
format = gfx::SurfaceFormat::B8G8R8A8;
PostHasTransparency();
} else {
format = gfx::SurfaceFormat::B8G8R8X8;
}
MOZ_ASSERT(HasSize());
// Use correct format, RGB for first frame, PAL for following frames
// and include transparency to allow for optimization of opaque images
if (mGIFStruct.images_decoded) {
@ -189,6 +190,11 @@ nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
mGIFStruct.y_offset,
mGIFStruct.width,
mGIFStruct.height))) {
// 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, image is decoded into 24bit RGB
NeedNewFrame(mGIFStruct.images_decoded, mGIFStruct.x_offset,
mGIFStruct.y_offset, mGIFStruct.width, mGIFStruct.height,

View File

@ -542,6 +542,8 @@ nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
return;
}
uint8_t sawTransparency = 0;
while (mCurLine > 0 && aCount > 0) {
uint32_t toCopy = std::min(rowSize - mRowBytes, aCount);
if (toCopy) {
@ -567,6 +569,7 @@ nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
uint8_t* p_end = mRow + rowSize;
while (p < p_end) {
uint8_t idx = *p++;
sawTransparency |= idx;
for (uint8_t bit = 0x80; bit && decoded<decoded_end; bit >>= 1) {
// Clear pixel completely for transparency.
if (idx & bit) {
@ -577,6 +580,12 @@ nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
}
}
}
// If any bits are set in sawTransparency, then we know at least one
// pixel was transparent.
if (sawTransparency) {
PostHasTransparency();
}
}
}
}

View File

@ -145,9 +145,14 @@ void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
int32_t width, int32_t height,
gfx::SurfaceFormat format)
{
MOZ_ASSERT(HasSize());
if (format == gfx::SurfaceFormat::B8G8R8A8) {
PostHasTransparency();
}
// Our first full frame is automatically created by the image decoding
// infrastructure. Just use it as long as it matches up.
MOZ_ASSERT(HasSize());
nsIntRect neededRect(x_offset, y_offset, width, height);
nsRefPtr<imgFrame> currentFrame = GetCurrentFrame();
if (mNumFrames != 0 || !currentFrame->GetRect().IsEqualEdges(neededRect)) {

View File

@ -14,7 +14,7 @@ interface imgIRequest;
[ptr] native nsIntRect(nsIntRect);
[scriptable, builtinclass, uuid(ac65c702-7771-4f6d-b18b-1c7d806ce3c1)]
[scriptable, builtinclass, uuid(03da5641-a333-454a-a859-036d0bb683b7)]
interface imgINotificationObserver : nsISupports
{
const long SIZE_AVAILABLE = 1;
@ -25,6 +25,7 @@ interface imgINotificationObserver : nsISupports
const long DISCARD = 6;
const long UNLOCKED_DRAW = 7;
const long IS_ANIMATED = 8;
const long HAS_TRANSPARENCY = 9;
[noscript] void notify(in imgIRequest aProxy, in long aType, [const] in nsIntRect aRect);
};

View File

@ -284,6 +284,12 @@ Decoder::PostSize(int32_t aWidth,
mProgress |= FLAG_HAS_SIZE;
}
void
Decoder::PostHasTransparency()
{
mProgress |= FLAG_HAS_TRANSPARENCY;
}
void
Decoder::PostFrameStart()
{

View File

@ -188,6 +188,9 @@ protected:
int32_t aHeight,
Orientation aOrientation = Orientation());
// Called by decoders if they determine that the image has transparency.
void PostHasTransparency();
// Called by decoders when they begin a frame. Informs the image, sends
// notifications, and does internal book-keeping.
void PostFrameStart();

View File

@ -79,6 +79,11 @@ CheckProgressConsistency(Progress aProgress)
}
if (aProgress & FLAG_IS_ANIMATED) {
MOZ_ASSERT(aProgress & FLAG_DECODE_STARTED);
MOZ_ASSERT(aProgress & FLAG_HAS_SIZE);
}
if (aProgress & FLAG_HAS_TRANSPARENCY) {
MOZ_ASSERT(aProgress & FLAG_DECODE_STARTED);
MOZ_ASSERT(aProgress & FLAG_HAS_SIZE);
}
if (aProgress & FLAG_IS_MULTIPART) {
// No preconditions.
@ -330,7 +335,9 @@ ProgressTracker::SyncNotifyInternal(ProxyArray& aProxies,
if (aProgress & FLAG_FRAME_STOPPED)
NOTIFY_IMAGE_OBSERVERS(aProxies, OnStopFrame());
// OnImageIsAnimated
if (aProgress & FLAG_HAS_TRANSPARENCY)
NOTIFY_IMAGE_OBSERVERS(aProxies, OnImageHasTransparency());
if (aProgress & FLAG_IS_ANIMATED)
NOTIFY_IMAGE_OBSERVERS(aProxies, OnImageIsAnimated());
}

View File

@ -36,9 +36,10 @@ enum {
FLAG_ONLOAD_BLOCKED = 1u << 6,
FLAG_ONLOAD_UNBLOCKED = 1u << 7,
FLAG_IS_ANIMATED = 1u << 8,
FLAG_IS_MULTIPART = 1u << 9,
FLAG_MULTIPART_STOPPED = 1u << 10,
FLAG_HAS_ERROR = 1u << 11 // STATUS_ERROR
FLAG_HAS_TRANSPARENCY = 1u << 9,
FLAG_IS_MULTIPART = 1u << 10,
FLAG_MULTIPART_STOPPED = 1u << 11,
FLAG_HAS_ERROR = 1u << 12 // STATUS_ERROR
};
typedef uint32_t Progress;

View File

@ -1111,6 +1111,7 @@ VectorImage::OnSVGDocumentLoaded()
// Tell *our* observers that we're done loading.
if (mProgressTracker) {
mProgressTracker->SyncNotifyProgress(FLAG_HAS_SIZE |
FLAG_HAS_TRANSPARENCY |
FLAG_FRAME_STOPPED |
FLAG_DECODE_STOPPED |
FLAG_ONLOAD_UNBLOCKED,

View File

@ -816,6 +816,16 @@ void imgRequestProxy::OnUnlockedDraw()
}
}
void imgRequestProxy::OnImageHasTransparency()
{
LOG_FUNC(GetImgLog(), "imgRequestProxy::OnImageHasTransparency");
if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->Notify(this, imgINotificationObserver::HAS_TRANSPARENCY, nullptr);
}
}
void imgRequestProxy::OnImageIsAnimated()
{
LOG_FUNC(GetImgLog(), "imgRequestProxy::OnImageIsAnimated");

View File

@ -149,14 +149,15 @@ protected:
// class) ProgressTracker is the only class allowed to send us
// notifications.
void OnStartDecode ();
void OnStartContainer ();
void OnFrameUpdate (const nsIntRect * aRect);
void OnStopFrame ();
void OnStopDecode ();
void OnDiscard ();
void OnUnlockedDraw ();
void OnImageIsAnimated ();
void OnStartDecode();
void OnStartContainer();
void OnFrameUpdate(const nsIntRect* aRect);
void OnStopFrame();
void OnStopDecode();
void OnDiscard();
void OnUnlockedDraw();
void OnImageHasTransparency();
void OnImageIsAnimated();
/* non-virtual sort-of-nsIRequestObserver methods */
void OnStartRequest();