mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1089880 (Part 1) - Add a HAS_TRANSPARENCY notification to ImageLib. r=tn
This commit is contained in:
parent
a0cb0e0b94
commit
5376541aef
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -284,6 +284,12 @@ Decoder::PostSize(int32_t aWidth,
|
||||
mProgress |= FLAG_HAS_SIZE;
|
||||
}
|
||||
|
||||
void
|
||||
Decoder::PostHasTransparency()
|
||||
{
|
||||
mProgress |= FLAG_HAS_TRANSPARENCY;
|
||||
}
|
||||
|
||||
void
|
||||
Decoder::PostFrameStart()
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user