fixing bug 106623 r=bryner sr=hyatt

This commit is contained in:
pavlov%netscape.com 2001-10-25 07:44:55 +00:00
parent 0f2fca64d1
commit 48bd1210b0
2 changed files with 81 additions and 70 deletions

View File

@ -36,18 +36,18 @@ NS_IMPL_ISUPPORTS3(imgContainer, imgIContainer, nsITimerCallback, imgIDecoderObs
//****************************************************************************** //******************************************************************************
imgContainer::imgContainer() : imgContainer::imgContainer() :
mSize(0,0) mSize(0,0),
mObserver(nsnull),
mCurrentDecodingFrameIndex(0),
mCurrentAnimationFrameIndex(0),
mCurrentFrameIsFinishedDecoding(PR_FALSE),
mDoneDecoding(PR_FALSE),
mAnimating(PR_FALSE),
mAnimationMode(0),
mLoopCount(-1)
{ {
NS_INIT_ISUPPORTS(); NS_INIT_ISUPPORTS();
/* member initializers and constructor code */ /* member initializers and constructor code */
mCurrentDecodingFrameIndex = 0;
mCurrentAnimationFrameIndex = 0;
mCurrentFrameIsFinishedDecoding = PR_FALSE;
mDoneDecoding = PR_FALSE;
mAnimating = PR_FALSE;
mAnimationMode = 0;
mObserver = nsnull;
mLoopCount = -1;
} }
//****************************************************************************** //******************************************************************************
@ -55,7 +55,7 @@ imgContainer::~imgContainer()
{ {
if (mTimer) if (mTimer)
mTimer->Cancel(); mTimer->Cancel();
/* destructor code */ /* destructor code */
mFrames.Clear(); mFrames.Clear();
} }
@ -105,13 +105,7 @@ NS_IMETHODIMP imgContainer::GetHeight(nscoord *aHeight)
/* readonly attribute gfxIImageFrame currentFrame; */ /* readonly attribute gfxIImageFrame currentFrame; */
NS_IMETHODIMP imgContainer::GetCurrentFrame(gfxIImageFrame * *aCurrentFrame) NS_IMETHODIMP imgContainer::GetCurrentFrame(gfxIImageFrame * *aCurrentFrame)
{ {
if (mCompositingFrame) { return inlinedGetCurrentFrame(aCurrentFrame);
*aCurrentFrame = mCompositingFrame;
NS_ADDREF(*aCurrentFrame);
return NS_OK;
}
return this->GetFrameAt(mCurrentAnimationFrameIndex, aCurrentFrame);
} }
//****************************************************************************** //******************************************************************************
@ -125,16 +119,7 @@ NS_IMETHODIMP imgContainer::GetNumFrames(PRUint32 *aNumFrames)
/* gfxIImageFrame getFrameAt (in unsigned long index); */ /* gfxIImageFrame getFrameAt (in unsigned long index); */
NS_IMETHODIMP imgContainer::GetFrameAt(PRUint32 index, gfxIImageFrame **_retval) NS_IMETHODIMP imgContainer::GetFrameAt(PRUint32 index, gfxIImageFrame **_retval)
{ {
nsISupports *sup = mFrames.ElementAt(index); // addrefs return inlinedGetFrameAt(index, _retval);
if (!sup)
return NS_ERROR_FAILURE;
nsresult rv;
rv = sup->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)_retval); // addrefs again
NS_RELEASE(sup);
return rv;
} }
//****************************************************************************** //******************************************************************************
@ -145,10 +130,9 @@ NS_IMETHODIMP imgContainer::AppendFrame(gfxIImageFrame *item)
// size is the same the frame size. Otherwise, we'll either need the composite frame // size is the same the frame size. Otherwise, we'll either need the composite frame
// for animation compositing (GIF) or for filling in with a background color. // for animation compositing (GIF) or for filling in with a background color.
// XXX IMPORTANT: this means that the frame should be initialized BEFORE appending to container // XXX IMPORTANT: this means that the frame should be initialized BEFORE appending to container
PRUint32 numFrames; PRUint32 numFrames = inlinedGetNumFrames();
this->GetNumFrames(&numFrames);
if(!mCompositingFrame) { if (!mCompositingFrame) {
nsRect frameRect; nsRect frameRect;
item->GetRect(frameRect); item->GetRect(frameRect);
// We used to create a compositing frame if any frame was smaller than the logical // We used to create a compositing frame if any frame was smaller than the logical
@ -174,14 +158,14 @@ NS_IMETHODIMP imgContainer::AppendFrame(gfxIImageFrame *item)
} }
nsCOMPtr<gfxIImageFrame> firstFrame; nsCOMPtr<gfxIImageFrame> firstFrame;
this->GetFrameAt(0, getter_AddRefs(firstFrame)); inlinedGetFrameAt(0, getter_AddRefs(firstFrame));
gfx_color backgroundColor, transColor; gfx_color backgroundColor, transColor;
if(NS_SUCCEEDED(firstFrame->GetTransparentColor(&transColor))) { if (NS_SUCCEEDED(firstFrame->GetTransparentColor(&transColor))) {
mCompositingFrame->SetTransparentColor(transColor); mCompositingFrame->SetTransparentColor(transColor);
} }
if(NS_SUCCEEDED(firstFrame->GetBackgroundColor(&backgroundColor))) { if (NS_SUCCEEDED(firstFrame->GetBackgroundColor(&backgroundColor))) {
mCompositingFrame->SetBackgroundColor(backgroundColor); mCompositingFrame->SetBackgroundColor(backgroundColor);
FillWithColor(mCompositingFrame, backgroundColor); FillWithColor(mCompositingFrame, backgroundColor);
} }
@ -199,16 +183,15 @@ NS_IMETHODIMP imgContainer::AppendFrame(gfxIImageFrame *item)
if (!mTimer && (numFrames >= 1)) { if (!mTimer && (numFrames >= 1)) {
PRInt32 timeout; PRInt32 timeout;
nsCOMPtr<gfxIImageFrame> currentFrame; nsCOMPtr<gfxIImageFrame> currentFrame;
this->GetFrameAt(mCurrentDecodingFrameIndex, getter_AddRefs(currentFrame)); inlinedGetFrameAt(mCurrentDecodingFrameIndex, getter_AddRefs(currentFrame));
currentFrame->GetTimeout(&timeout); currentFrame->GetTimeout(&timeout);
if (timeout > 0) { // -1 means display this frame forever if (timeout > 0) { // -1 means display this frame forever
if(mAnimating) { if (mAnimating) {
// Since we have more than one frame we need a timer // Since we have more than one frame we need a timer
mTimer = do_CreateInstance("@mozilla.org/timer;1"); mTimer = do_CreateInstance("@mozilla.org/timer;1");
mTimer->Init( mTimer->Init(NS_STATIC_CAST(nsITimerCallback*, this),
NS_STATIC_CAST(nsITimerCallback*, this), timeout, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK);
timeout, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK);
} }
} }
} }
@ -235,7 +218,7 @@ NS_IMETHODIMP imgContainer::EndFrameDecode(PRUint32 aFrameNum, PRUint32 aTimeout
mCurrentFrameIsFinishedDecoding = PR_TRUE; mCurrentFrameIsFinishedDecoding = PR_TRUE;
nsCOMPtr<gfxIImageFrame> currentFrame; nsCOMPtr<gfxIImageFrame> currentFrame;
this->GetFrameAt(aFrameNum-1, getter_AddRefs(currentFrame)); inlinedGetFrameAt(aFrameNum-1, getter_AddRefs(currentFrame));
NS_ASSERTION(currentFrame, "Received an EndFrameDecode call with an invalid frame number"); NS_ASSERTION(currentFrame, "Received an EndFrameDecode call with an invalid frame number");
if (!currentFrame) return NS_ERROR_UNEXPECTED; if (!currentFrame) return NS_ERROR_UNEXPECTED;
@ -255,7 +238,7 @@ NS_IMETHODIMP imgContainer::DecodingComplete(void)
mFrames.Count(&numFrames); mFrames.Count(&numFrames);
if (numFrames == 1) { if (numFrames == 1) {
nsCOMPtr<gfxIImageFrame> currentFrame; nsCOMPtr<gfxIImageFrame> currentFrame;
GetFrameAt(0, getter_AddRefs(currentFrame)); inlinedGetFrameAt(0, getter_AddRefs(currentFrame));
currentFrame->SetMutable(PR_FALSE); currentFrame->SetMutable(PR_FALSE);
} }
return NS_OK; return NS_OK;
@ -303,19 +286,18 @@ NS_IMETHODIMP imgContainer::StartAnimation()
if (mTimer) if (mTimer)
return NS_OK; return NS_OK;
PRUint32 numFrames; PRUint32 numFrames = inlinedGetNumFrames();
this->GetNumFrames(&numFrames);
if (numFrames > 1) { if (numFrames > 1) {
PRInt32 timeout; PRInt32 timeout;
nsCOMPtr<gfxIImageFrame> currentFrame; nsCOMPtr<gfxIImageFrame> currentFrame;
this->GetCurrentFrame(getter_AddRefs(currentFrame)); inlinedGetCurrentFrame(getter_AddRefs(currentFrame));
if (currentFrame) { if (currentFrame) {
currentFrame->GetTimeout(&timeout); currentFrame->GetTimeout(&timeout);
if (timeout > 0) { // -1 means display this frame forever if (timeout > 0) { // -1 means display this frame forever
mAnimating = PR_TRUE; mAnimating = PR_TRUE;
if(!mTimer) mTimer = do_CreateInstance("@mozilla.org/timer;1"); if (!mTimer) mTimer = do_CreateInstance("@mozilla.org/timer;1");
mTimer->Init(NS_STATIC_CAST(nsITimerCallback*, this), mTimer->Init(NS_STATIC_CAST(nsITimerCallback*, this),
timeout, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK); timeout, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK);
@ -323,8 +305,8 @@ NS_IMETHODIMP imgContainer::StartAnimation()
} else { } else {
// XXX hack.. the timer notify code will do the right thing, so just get that started // XXX hack.. the timer notify code will do the right thing, so just get that started
mAnimating = PR_TRUE; mAnimating = PR_TRUE;
if(!mTimer) mTimer = do_CreateInstance("@mozilla.org/timer;1"); if (!mTimer) mTimer = do_CreateInstance("@mozilla.org/timer;1");
mTimer->Init(NS_STATIC_CAST(nsITimerCallback*, this), mTimer->Init(NS_STATIC_CAST(nsITimerCallback*, this),
100, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK); 100, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK);
} }
@ -389,8 +371,7 @@ NS_IMETHODIMP_(void) imgContainer::Notify(nsITimer *timer)
nsCOMPtr<gfxIImageFrame> nextFrame; nsCOMPtr<gfxIImageFrame> nextFrame;
PRInt32 timeout = 100; PRInt32 timeout = 100;
PRUint32 numFrames; PRUint32 numFrames = inlinedGetNumFrames();
GetNumFrames(&numFrames);
if(!numFrames) if(!numFrames)
return; return;
@ -399,14 +380,14 @@ NS_IMETHODIMP_(void) imgContainer::Notify(nsITimer *timer)
PRUint32 previousAnimationFrameIndex = mCurrentAnimationFrameIndex; PRUint32 previousAnimationFrameIndex = mCurrentAnimationFrameIndex;
if (mCurrentFrameIsFinishedDecoding && !mDoneDecoding) { if (mCurrentFrameIsFinishedDecoding && !mDoneDecoding) {
// If we have the next frame in the sequence set the timer callback from it // If we have the next frame in the sequence set the timer callback from it
GetFrameAt(mCurrentAnimationFrameIndex+1, getter_AddRefs(nextFrame)); inlinedGetFrameAt(mCurrentAnimationFrameIndex+1, getter_AddRefs(nextFrame));
if (nextFrame) { if (nextFrame) {
// Go to next frame in sequence // Go to next frame in sequence
nextFrame->GetTimeout(&timeout); nextFrame->GetTimeout(&timeout);
mCurrentAnimationFrameIndex++; mCurrentAnimationFrameIndex++;
} else { } else {
// twiddle our thumbs // twiddle our thumbs
GetFrameAt(mCurrentAnimationFrameIndex, getter_AddRefs(nextFrame)); inlinedGetFrameAt(mCurrentAnimationFrameIndex, getter_AddRefs(nextFrame));
if(!nextFrame) return; if(!nextFrame) return;
nextFrame->GetTimeout(&timeout); nextFrame->GetTimeout(&timeout);
@ -420,7 +401,7 @@ NS_IMETHODIMP_(void) imgContainer::Notify(nsITimer *timer)
} }
// Go back to the beginning of the animation // Go back to the beginning of the animation
GetFrameAt(0, getter_AddRefs(nextFrame)); inlinedGetFrameAt(0, getter_AddRefs(nextFrame));
if(!nextFrame) return; if(!nextFrame) return;
mCurrentAnimationFrameIndex = 0; mCurrentAnimationFrameIndex = 0;
@ -429,13 +410,13 @@ NS_IMETHODIMP_(void) imgContainer::Notify(nsITimer *timer)
mLoopCount--; mLoopCount--;
} else { } else {
mCurrentAnimationFrameIndex++; mCurrentAnimationFrameIndex++;
GetFrameAt(mCurrentAnimationFrameIndex, getter_AddRefs(nextFrame)); inlinedGetFrameAt(mCurrentAnimationFrameIndex, getter_AddRefs(nextFrame));
if(!nextFrame) return; if(!nextFrame) return;
nextFrame->GetTimeout(&timeout); nextFrame->GetTimeout(&timeout);
} }
} else { } else {
GetFrameAt(mCurrentAnimationFrameIndex, getter_AddRefs(nextFrame)); inlinedGetFrameAt(mCurrentAnimationFrameIndex, getter_AddRefs(nextFrame));
if(!nextFrame) return; if(!nextFrame) return;
} }
@ -472,8 +453,7 @@ void imgContainer::DoComposite(gfxIImageFrame** aFrameToUse, nsRect* aDirtyRect,
*aFrameToUse = nsnull; *aFrameToUse = nsnull;
PRUint32 numFrames; PRUint32 numFrames = inlinedGetNumFrames();
this->GetNumFrames(&numFrames);
PRInt32 nextFrameIndex = aNextFrame; PRInt32 nextFrameIndex = aNextFrame;
PRInt32 prevFrameIndex = aPrevFrame; PRInt32 prevFrameIndex = aPrevFrame;
@ -481,7 +461,7 @@ void imgContainer::DoComposite(gfxIImageFrame** aFrameToUse, nsRect* aDirtyRect,
if(prevFrameIndex >= numFrames) prevFrameIndex = numFrames-1; if(prevFrameIndex >= numFrames) prevFrameIndex = numFrames-1;
nsCOMPtr<gfxIImageFrame> prevFrame; nsCOMPtr<gfxIImageFrame> prevFrame;
this->GetFrameAt(prevFrameIndex, getter_AddRefs(prevFrame)); inlinedGetFrameAt(prevFrameIndex, getter_AddRefs(prevFrame));
PRInt32 prevFrameDisposalMethod; PRInt32 prevFrameDisposalMethod;
if(nextFrameIndex == 0) if(nextFrameIndex == 0)
@ -490,7 +470,7 @@ void imgContainer::DoComposite(gfxIImageFrame** aFrameToUse, nsRect* aDirtyRect,
prevFrame->GetFrameDisposalMethod(&prevFrameDisposalMethod); prevFrame->GetFrameDisposalMethod(&prevFrameDisposalMethod);
nsCOMPtr<gfxIImageFrame> nextFrame; nsCOMPtr<gfxIImageFrame> nextFrame;
this->GetFrameAt(nextFrameIndex, getter_AddRefs(nextFrame)); inlinedGetFrameAt(nextFrameIndex, getter_AddRefs(nextFrame));
PRInt32 x; PRInt32 x;
PRInt32 y; PRInt32 y;
@ -507,19 +487,24 @@ void imgContainer::DoComposite(gfxIImageFrame** aFrameToUse, nsRect* aDirtyRect,
switch (prevFrameDisposalMethod) { switch (prevFrameDisposalMethod) {
default: default:
case 0: // DISPOSE_NOT_SPECIFIED case 0: // DISPOSE_NOT_SPECIFIED
mCompositingFrame->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)aFrameToUse); // addrefs again *aFrameToUse = mCompositingFrame;
NS_ADDREF(*aFrameToUse);
nextFrame->DrawTo(mCompositingFrame, x, y, width, height); nextFrame->DrawTo(mCompositingFrame, x, y, width, height);
break; break;
case 1: // DISPOSE_KEEP Leave previous frame in the framebuffer case 1: // DISPOSE_KEEP Leave previous frame in the framebuffer
mCompositingFrame->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)aFrameToUse); // addrefs again *aFrameToUse = mCompositingFrame;
NS_ADDREF(*aFrameToUse);
nextFrame->DrawTo(mCompositingFrame, x, y, width, height); nextFrame->DrawTo(mCompositingFrame, x, y, width, height);
BuildCompositeMask(mCompositingFrame, nextFrame); BuildCompositeMask(mCompositingFrame, nextFrame);
break; break;
case 2: // DISPOSE_OVERWRITE_BGCOLOR Overwrite with background color case 2: // DISPOSE_OVERWRITE_BGCOLOR Overwrite with background color
mCompositingFrame->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)aFrameToUse); // addrefs again *aFrameToUse = mCompositingFrame;
NS_ADDREF(*aFrameToUse);
// Not actually getting the background color here, and instead filling with // Not actually getting the background color here, and instead filling with
// zeros fixes cases where the animation is transparent, but has a different // zeros fixes cases where the animation is transparent, but has a different
// background color and so on Windows, we would correctly build the bit mask, but // background color and so on Windows, we would correctly build the bit mask, but
@ -532,11 +517,12 @@ void imgContainer::DoComposite(gfxIImageFrame** aFrameToUse, nsRect* aDirtyRect,
ZeroMask(mCompositingFrame); ZeroMask(mCompositingFrame);
BuildCompositeMask(mCompositingFrame, nextFrame); BuildCompositeMask(mCompositingFrame, nextFrame);
break; break;
case 4: // DISPOSE_OVERWRITE_PREVIOUS Save-under case 4: // DISPOSE_OVERWRITE_PREVIOUS Save-under
//XXX Reblit previous composite into frame buffer //XXX Reblit previous composite into frame buffer
// //
break; break;
} }
(*aDirtyRect).x = 0; (*aDirtyRect).x = 0;

View File

@ -66,9 +66,34 @@ public:
virtual ~imgContainer(); virtual ~imgContainer();
private: private:
inline PRUint32 inlinedGetNumFrames() {
PRUint32 nframes;
mFrames.Count(&nframes);
return nframes;
}
inline nsresult inlinedGetFrameAt(PRUint32 index, gfxIImageFrame **_retval) {
*_retval = NS_STATIC_CAST(gfxIImageFrame*, mFrames.ElementAt(index));
if (!*_retval) return NS_ERROR_FAILURE;
return NS_OK;
}
inline nsresult inlinedGetCurrentFrame(gfxIImageFrame **_retval) {
if (mCompositingFrame) {
*_retval = mCompositingFrame;
NS_ADDREF(*_retval);
return NS_OK;
}
return inlinedGetFrameAt(mCurrentAnimationFrameIndex, _retval);
}
/* additional members */ /* additional members */
nsSupportsArray mFrames; nsSupportsArray mFrames;
nsSize mSize; nsSize mSize;
nsWeakPtr mObserver;
PRUint32 mCurrentDecodingFrameIndex; // 0 to numFrames-1 PRUint32 mCurrentDecodingFrameIndex; // 0 to numFrames-1
PRUint32 mCurrentAnimationFrameIndex; // 0 to numFrames-1 PRUint32 mCurrentAnimationFrameIndex; // 0 to numFrames-1
PRBool mCurrentFrameIsFinishedDecoding; PRBool mCurrentFrameIsFinishedDecoding;
@ -76,12 +101,12 @@ private:
PRBool mAnimating; PRBool mAnimating;
PRUint16 mAnimationMode; PRUint16 mAnimationMode;
PRInt32 mLoopCount; PRInt32 mLoopCount;
nsWeakPtr mObserver; private:
// GIF specific bits // GIF specific bits
nsCOMPtr<nsITimer> mTimer; nsCOMPtr<nsITimer> mTimer;
// GIF animations will use the mCompositingFrame to composite images // GIF animations will use the mCompositingFrame to composite images
// and just hand this back to the caller when it is time to draw the frame. // and just hand this back to the caller when it is time to draw the frame.
nsCOMPtr<gfxIImageFrame> mCompositingFrame; nsCOMPtr<gfxIImageFrame> mCompositingFrame;