2001-03-10 01:11:54 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public
|
|
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS
|
|
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
|
|
* implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
|
|
|
*
|
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 2001 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Stuart Parmenter <pavlov@netscape.com>
|
|
|
|
* Chris Saari <saari@netscape.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "imgContainer.h"
|
|
|
|
|
|
|
|
#include "nsIServiceManager.h"
|
2001-03-24 02:44:26 +00:00
|
|
|
#include "nsIInterfaceRequestor.h"
|
2001-03-10 01:11:54 +00:00
|
|
|
#include "gfxIImageFrame.h"
|
2001-03-24 02:44:26 +00:00
|
|
|
#include "nsIImage.h"
|
2001-04-26 07:11:52 +00:00
|
|
|
#include "nsMemory.h"
|
2001-03-10 01:11:54 +00:00
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
NS_IMPL_ISUPPORTS3(imgContainer, imgIContainer, nsITimerCallback,imgIDecoderObserver)
|
2001-03-10 01:11:54 +00:00
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
//******************************************************************************
|
2001-04-16 23:13:01 +00:00
|
|
|
imgContainer::imgContainer() :
|
|
|
|
mSize(0,0)
|
2001-03-10 01:11:54 +00:00
|
|
|
{
|
|
|
|
NS_INIT_ISUPPORTS();
|
|
|
|
/* member initializers and constructor code */
|
2001-03-24 02:44:26 +00:00
|
|
|
mCurrentDecodingFrameIndex = 0;
|
|
|
|
mCurrentAnimationFrameIndex = 0;
|
2001-03-10 01:11:54 +00:00
|
|
|
mCurrentFrameIsFinishedDecoding = PR_FALSE;
|
|
|
|
mDoneDecoding = PR_FALSE;
|
2001-03-13 23:33:11 +00:00
|
|
|
mAnimating = PR_FALSE;
|
2001-04-16 22:02:39 +00:00
|
|
|
mAnimationMode = 0;
|
2001-03-25 11:57:25 +00:00
|
|
|
mObserver = nsnull;
|
2001-03-10 01:11:54 +00:00
|
|
|
}
|
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
imgContainer::~imgContainer()
|
|
|
|
{
|
|
|
|
if (mTimer)
|
|
|
|
mTimer->Cancel();
|
2001-03-24 02:44:26 +00:00
|
|
|
|
|
|
|
/* destructor code */
|
|
|
|
mFrames.Clear();
|
2001-03-10 01:11:54 +00:00
|
|
|
}
|
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* void init (in nscoord aWidth, in nscoord aHeight, in imgIContainerObserver aObserver); */
|
|
|
|
NS_IMETHODIMP imgContainer::Init(nscoord aWidth, nscoord aHeight, imgIContainerObserver *aObserver)
|
|
|
|
{
|
|
|
|
if (aWidth <= 0 || aHeight <= 0) {
|
2001-03-22 10:26:36 +00:00
|
|
|
NS_WARNING("error - negative image size\n");
|
2001-03-10 01:11:54 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
mSize.SizeTo(aWidth, aHeight);
|
|
|
|
|
2001-03-27 02:42:51 +00:00
|
|
|
mObserver = getter_AddRefs(NS_GetWeakReference(aObserver));
|
2001-03-10 01:11:54 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* readonly attribute gfx_format preferredAlphaChannelFormat; */
|
|
|
|
NS_IMETHODIMP imgContainer::GetPreferredAlphaChannelFormat(gfx_format *aFormat)
|
|
|
|
{
|
|
|
|
/* default.. platform's should probably overwrite this */
|
|
|
|
*aFormat = gfxIFormats::RGB_A8;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* readonly attribute nscoord width; */
|
|
|
|
NS_IMETHODIMP imgContainer::GetWidth(nscoord *aWidth)
|
|
|
|
{
|
|
|
|
*aWidth = mSize.width;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* readonly attribute nscoord height; */
|
|
|
|
NS_IMETHODIMP imgContainer::GetHeight(nscoord *aHeight)
|
|
|
|
{
|
|
|
|
*aHeight = mSize.height;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* readonly attribute gfxIImageFrame currentFrame; */
|
|
|
|
NS_IMETHODIMP imgContainer::GetCurrentFrame(gfxIImageFrame * *aCurrentFrame)
|
|
|
|
{
|
2001-04-26 07:11:52 +00:00
|
|
|
if (mCompositingFrame)
|
2001-03-13 23:33:11 +00:00
|
|
|
return mCompositingFrame->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)aCurrentFrame); // addrefs again
|
|
|
|
else
|
2001-03-24 02:44:26 +00:00
|
|
|
return this->GetFrameAt(mCurrentAnimationFrameIndex, aCurrentFrame);
|
2001-03-10 01:11:54 +00:00
|
|
|
}
|
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* readonly attribute unsigned long numFrames; */
|
|
|
|
NS_IMETHODIMP imgContainer::GetNumFrames(PRUint32 *aNumFrames)
|
|
|
|
{
|
|
|
|
return mFrames.Count(aNumFrames);
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* gfxIImageFrame getFrameAt (in unsigned long index); */
|
|
|
|
NS_IMETHODIMP imgContainer::GetFrameAt(PRUint32 index, gfxIImageFrame **_retval)
|
|
|
|
{
|
|
|
|
nsISupports *sup = mFrames.ElementAt(index); // addrefs
|
|
|
|
if (!sup)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
rv = sup->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)_retval); // addrefs again
|
|
|
|
|
|
|
|
NS_RELEASE(sup);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* void appendFrame (in gfxIImageFrame item); */
|
|
|
|
NS_IMETHODIMP imgContainer::AppendFrame(gfxIImageFrame *item)
|
|
|
|
{
|
2001-03-13 23:33:11 +00:00
|
|
|
// If we don't have a composite frame already allocated, make sure that our container
|
|
|
|
// 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.
|
|
|
|
// XXX IMPORTANT: this means that the frame should be initialized BEFORE appending to container
|
2001-03-24 02:44:26 +00:00
|
|
|
PRUint32 numFrames;
|
|
|
|
this->GetNumFrames(&numFrames);
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
if(!mCompositingFrame) {
|
2001-03-14 01:14:33 +00:00
|
|
|
nsRect frameRect;
|
|
|
|
item->GetRect(frameRect);
|
2001-03-24 02:44:26 +00:00
|
|
|
// We used to create a compositing frame if any frame was smaller than the logical
|
|
|
|
// image size. You could create a single frame that was 10x10 in the middle of
|
|
|
|
// an 20x20 logical screen and have the extra screen space filled by the image
|
|
|
|
// background color. However, it turns out that neither NS4.x nor IE correctly
|
|
|
|
// support this, and as a result there are many GIFs out there that look "wrong"
|
|
|
|
// when this is correctly supported. So for now, we only create a compositing frame
|
|
|
|
// if we have more than one frame in the image.
|
|
|
|
if(/*(frameRect.x != 0) ||
|
2001-03-14 01:14:33 +00:00
|
|
|
(frameRect.y != 0) ||
|
|
|
|
(frameRect.width != mSize.width) ||
|
2001-03-24 02:44:26 +00:00
|
|
|
(frameRect.height != mSize.height) ||*/
|
|
|
|
(numFrames >= 1)) // Not sure if I want to create a composite frame for every anim. Could be smarter.
|
2001-03-13 23:33:11 +00:00
|
|
|
{
|
|
|
|
mCompositingFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
|
2001-04-26 07:11:52 +00:00
|
|
|
mCompositingFrame->Init(0, 0, mSize.width, mSize.height, gfxIFormats::RGB_A1);
|
2001-03-24 02:44:26 +00:00
|
|
|
nsCOMPtr<nsIImage> img(do_GetInterface(mCompositingFrame));
|
|
|
|
img->SetDecodedRect(0, 0, mSize.width, mSize.height);
|
|
|
|
|
|
|
|
nsCOMPtr<gfxIImageFrame> firstFrame;
|
|
|
|
this->GetFrameAt(0, getter_AddRefs(firstFrame));
|
2001-04-26 07:11:52 +00:00
|
|
|
|
|
|
|
gfx_color backgroundColor, transColor;
|
|
|
|
if(NS_SUCCEEDED(firstFrame->GetTransparentColor(&transColor))) {
|
|
|
|
mCompositingFrame->SetTransparentColor(transColor);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(NS_SUCCEEDED(firstFrame->GetBackgroundColor(&backgroundColor))) {
|
|
|
|
mCompositingFrame->SetBackgroundColor(backgroundColor);
|
|
|
|
FillWithColor(mCompositingFrame, backgroundColor);
|
|
|
|
}
|
|
|
|
|
|
|
|
ZeroMask(mCompositingFrame);
|
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
firstFrame->DrawTo(mCompositingFrame, 0, 0, mSize.width, mSize.height);
|
2001-04-26 07:11:52 +00:00
|
|
|
BuildCompositeMask(mCompositingFrame, firstFrame);
|
2001-03-13 23:33:11 +00:00
|
|
|
}
|
|
|
|
}
|
2001-03-10 01:11:54 +00:00
|
|
|
// If this is our second frame, init a timer so we don't display
|
|
|
|
// the next frame until the delay timer has expired for the current
|
|
|
|
// frame.
|
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
if (!mTimer && (numFrames >= 1)) {
|
2001-03-10 01:11:54 +00:00
|
|
|
PRInt32 timeout;
|
|
|
|
nsCOMPtr<gfxIImageFrame> currentFrame;
|
2001-03-24 02:44:26 +00:00
|
|
|
this->GetFrameAt(mCurrentDecodingFrameIndex, getter_AddRefs(currentFrame));
|
2001-03-10 01:11:54 +00:00
|
|
|
currentFrame->GetTimeout(&timeout);
|
2001-04-14 00:40:47 +00:00
|
|
|
if (timeout > 0) { // -1 means display this frame forever
|
2001-03-10 01:11:54 +00:00
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
if(mAnimating) {
|
|
|
|
// Since we have more than one frame we need a timer
|
|
|
|
mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
|
|
|
mTimer->Init(
|
|
|
|
NS_STATIC_CAST(nsITimerCallback*, this),
|
|
|
|
timeout, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK);
|
|
|
|
}
|
2001-03-10 01:11:54 +00:00
|
|
|
}
|
|
|
|
}
|
2001-03-13 23:33:11 +00:00
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
if (numFrames > 0) mCurrentDecodingFrameIndex++;
|
2001-03-10 01:11:54 +00:00
|
|
|
|
|
|
|
mCurrentFrameIsFinishedDecoding = PR_FALSE;
|
|
|
|
|
|
|
|
return mFrames.AppendElement(NS_STATIC_CAST(nsISupports*, item));
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* void removeFrame (in gfxIImageFrame item); */
|
|
|
|
NS_IMETHODIMP imgContainer::RemoveFrame(gfxIImageFrame *item)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* void endFrameDecode (in gfxIImageFrame item, in unsigned long timeout); */
|
|
|
|
NS_IMETHODIMP imgContainer::EndFrameDecode(PRUint32 aFrameNum, PRUint32 aTimeout)
|
|
|
|
{
|
|
|
|
// It is now okay to start the timer for the next frame in the animation
|
|
|
|
mCurrentFrameIsFinishedDecoding = PR_TRUE;
|
2001-03-13 23:33:11 +00:00
|
|
|
|
|
|
|
nsCOMPtr<gfxIImageFrame> currentFrame;
|
2001-03-24 02:44:26 +00:00
|
|
|
this->GetFrameAt(aFrameNum-1, getter_AddRefs(currentFrame));
|
2001-04-16 09:17:59 +00:00
|
|
|
NS_ASSERTION(currentFrame, "Received an EndFrameDecode call with an invalid frame number");
|
|
|
|
if (!currentFrame) return NS_ERROR_UNEXPECTED;
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
currentFrame->SetTimeout(aTimeout);
|
|
|
|
|
2001-04-16 22:02:39 +00:00
|
|
|
StartAnimation();
|
2001-03-10 01:11:54 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* void decodingComplete (); */
|
|
|
|
NS_IMETHODIMP imgContainer::DecodingComplete(void)
|
|
|
|
{
|
|
|
|
mDoneDecoding = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* nsIEnumerator enumerate (); */
|
|
|
|
NS_IMETHODIMP imgContainer::Enumerate(nsIEnumerator **_retval)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void clear (); */
|
|
|
|
NS_IMETHODIMP imgContainer::Clear()
|
|
|
|
{
|
|
|
|
return mFrames.Clear();
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
2001-04-16 22:02:39 +00:00
|
|
|
NS_IMETHODIMP imgContainer::GetAnimationMode(PRUint16 *aAnimationMode)
|
|
|
|
{
|
|
|
|
if (!aAnimationMode) return NS_ERROR_NULL_POINTER;
|
|
|
|
*aAnimationMode = mAnimationMode;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP imgContainer::SetAnimationMode(PRUint16 aAnimationMode)
|
|
|
|
{
|
|
|
|
mAnimationMode = aAnimationMode;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-04-26 07:11:52 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* void startAnimation () */
|
|
|
|
NS_IMETHODIMP imgContainer::StartAnimation()
|
|
|
|
{
|
2001-04-16 22:02:39 +00:00
|
|
|
if (mAnimationMode == 1) // don't animate
|
|
|
|
{
|
|
|
|
mAnimating = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
mAnimating = PR_TRUE;
|
|
|
|
|
2001-03-10 01:11:54 +00:00
|
|
|
if (mTimer)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
PRUint32 numFrames;
|
|
|
|
this->GetNumFrames(&numFrames);
|
|
|
|
|
|
|
|
if (numFrames > 1) {
|
|
|
|
PRInt32 timeout;
|
|
|
|
nsCOMPtr<gfxIImageFrame> currentFrame;
|
|
|
|
this->GetCurrentFrame(getter_AddRefs(currentFrame));
|
|
|
|
if (currentFrame) {
|
|
|
|
currentFrame->GetTimeout(&timeout);
|
2001-04-14 00:40:47 +00:00
|
|
|
if (timeout > 0) { // -1 means display this frame forever
|
2001-03-10 01:11:54 +00:00
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
mAnimating = PR_TRUE;
|
|
|
|
if(!mTimer) mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
|
|
|
|
2001-03-10 01:11:54 +00:00
|
|
|
mTimer->Init(NS_STATIC_CAST(nsITimerCallback*, this),
|
|
|
|
timeout, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// XXX hack.. the timer notify code will do the right thing, so just get that started
|
2001-03-13 23:33:11 +00:00
|
|
|
mAnimating = PR_TRUE;
|
|
|
|
if(!mTimer) mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
|
|
|
|
2001-03-10 01:11:54 +00:00
|
|
|
mTimer->Init(NS_STATIC_CAST(nsITimerCallback*, this),
|
|
|
|
100, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* void stopAnimation (); */
|
|
|
|
NS_IMETHODIMP imgContainer::StopAnimation()
|
|
|
|
{
|
2001-03-13 23:33:11 +00:00
|
|
|
mAnimating = PR_FALSE;
|
|
|
|
|
2001-03-10 01:11:54 +00:00
|
|
|
if (!mTimer)
|
|
|
|
return NS_OK;
|
|
|
|
|
2001-03-22 10:26:36 +00:00
|
|
|
mTimer->Cancel();
|
2001-03-10 01:11:54 +00:00
|
|
|
|
|
|
|
mTimer = nsnull;
|
|
|
|
|
|
|
|
// don't bother trying to change the frame (to 0, etc.) here.
|
|
|
|
// No one is listening.
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
2001-03-10 01:11:54 +00:00
|
|
|
/* attribute long loopCount; */
|
|
|
|
NS_IMETHODIMP imgContainer::GetLoopCount(PRInt32 *aLoopCount)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
NS_IMETHODIMP imgContainer::SetLoopCount(PRInt32 aLoopCount)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(void) imgContainer::Notify(nsITimer *timer)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mTimer == timer, "uh");
|
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
if(!mAnimating || !mTimer)
|
2001-03-13 23:33:11 +00:00
|
|
|
return;
|
2001-03-27 02:42:51 +00:00
|
|
|
|
|
|
|
nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver));
|
|
|
|
if (!observer) {
|
|
|
|
// the imgRequest that owns us is dead, we should die now too.
|
|
|
|
this->StopAnimation();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-03-10 01:11:54 +00:00
|
|
|
nsCOMPtr<gfxIImageFrame> nextFrame;
|
|
|
|
PRInt32 timeout = 100;
|
2001-03-24 02:44:26 +00:00
|
|
|
PRUint32 numFrames;
|
|
|
|
GetNumFrames(&numFrames);
|
|
|
|
if(!numFrames)
|
|
|
|
return;
|
|
|
|
|
2001-03-10 01:11:54 +00:00
|
|
|
// If we're done decoding the next frame, go ahead and display it now and reinit
|
|
|
|
// the timer with the next frame's delay time.
|
2001-03-24 02:44:26 +00:00
|
|
|
PRUint32 previousAnimationFrameIndex = mCurrentAnimationFrameIndex;
|
2001-03-10 01:11:54 +00:00
|
|
|
if (mCurrentFrameIsFinishedDecoding && !mDoneDecoding) {
|
|
|
|
// If we have the next frame in the sequence set the timer callback from it
|
2001-03-24 02:44:26 +00:00
|
|
|
GetFrameAt(mCurrentAnimationFrameIndex+1, getter_AddRefs(nextFrame));
|
2001-03-10 01:11:54 +00:00
|
|
|
if (nextFrame) {
|
|
|
|
// Go to next frame in sequence
|
|
|
|
nextFrame->GetTimeout(&timeout);
|
2001-03-24 02:44:26 +00:00
|
|
|
mCurrentAnimationFrameIndex++;
|
2001-03-10 01:11:54 +00:00
|
|
|
} else {
|
|
|
|
// twiddle our thumbs
|
2001-03-24 02:44:26 +00:00
|
|
|
GetFrameAt(mCurrentAnimationFrameIndex, getter_AddRefs(nextFrame));
|
|
|
|
if(!nextFrame) return;
|
|
|
|
|
2001-03-10 01:11:54 +00:00
|
|
|
nextFrame->GetTimeout(&timeout);
|
|
|
|
}
|
|
|
|
} else if (mDoneDecoding){
|
2001-03-24 02:44:26 +00:00
|
|
|
if ((numFrames-1) == mCurrentAnimationFrameIndex) {
|
2001-04-16 22:02:39 +00:00
|
|
|
// If animation mode is "loop once", it's time to stop animating
|
|
|
|
if (mAnimationMode == 2) {
|
|
|
|
this->StopAnimation();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
// Go back to the beginning of the animation
|
2001-03-10 01:11:54 +00:00
|
|
|
GetFrameAt(0, getter_AddRefs(nextFrame));
|
2001-03-24 02:44:26 +00:00
|
|
|
if(!nextFrame) return;
|
|
|
|
|
|
|
|
mCurrentAnimationFrameIndex = 0;
|
2001-03-10 01:11:54 +00:00
|
|
|
nextFrame->GetTimeout(&timeout);
|
|
|
|
} else {
|
2001-03-24 02:44:26 +00:00
|
|
|
mCurrentAnimationFrameIndex++;
|
|
|
|
GetFrameAt(mCurrentAnimationFrameIndex, getter_AddRefs(nextFrame));
|
|
|
|
if(!nextFrame) return;
|
|
|
|
|
2001-03-10 01:11:54 +00:00
|
|
|
nextFrame->GetTimeout(&timeout);
|
|
|
|
}
|
|
|
|
} else {
|
2001-03-24 02:44:26 +00:00
|
|
|
GetFrameAt(mCurrentAnimationFrameIndex, getter_AddRefs(nextFrame));
|
|
|
|
if(!nextFrame) return;
|
2001-03-10 01:11:54 +00:00
|
|
|
}
|
2001-03-24 02:44:26 +00:00
|
|
|
|
2001-04-14 00:40:47 +00:00
|
|
|
if(timeout > 0)
|
2001-03-24 02:44:26 +00:00
|
|
|
mTimer->SetDelay(timeout);
|
|
|
|
else
|
|
|
|
this->StopAnimation();
|
2001-03-13 23:33:11 +00:00
|
|
|
|
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
nsRect dirtyRect;
|
2001-03-27 02:42:51 +00:00
|
|
|
|
2001-03-24 02:44:26 +00:00
|
|
|
// update the composited frame
|
|
|
|
if(mCompositingFrame && (previousAnimationFrameIndex != mCurrentAnimationFrameIndex)) {
|
|
|
|
nsCOMPtr<gfxIImageFrame> frameToUse;
|
|
|
|
DoComposite(getter_AddRefs(frameToUse), &dirtyRect, previousAnimationFrameIndex, mCurrentAnimationFrameIndex);
|
2001-03-13 23:33:11 +00:00
|
|
|
|
|
|
|
// do notification to FE to draw this frame, but hand it the compositing frame
|
2001-03-27 02:42:51 +00:00
|
|
|
observer->FrameChanged(this, nsnull, mCompositingFrame, &dirtyRect);
|
2001-03-24 02:44:26 +00:00
|
|
|
}
|
|
|
|
else {
|
2001-03-14 01:14:33 +00:00
|
|
|
nextFrame->GetRect(dirtyRect);
|
2001-03-10 01:11:54 +00:00
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
// do notification to FE to draw this frame
|
2001-03-27 02:42:51 +00:00
|
|
|
observer->FrameChanged(this, nsnull, nextFrame, &dirtyRect);
|
2001-03-13 23:33:11 +00:00
|
|
|
}
|
2001-03-10 01:11:54 +00:00
|
|
|
|
|
|
|
}
|
2001-03-13 23:33:11 +00:00
|
|
|
//******************************************************************************
|
|
|
|
// DoComposite gets called when the timer for animation get fired and we have to
|
|
|
|
// update the composited frame of the animation.
|
|
|
|
void imgContainer::DoComposite(gfxIImageFrame** aFrameToUse, nsRect* aDirtyRect, PRInt32 aPrevFrame, PRInt32 aNextFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aDirtyRect, "DoComposite aDirtyRect is null");
|
|
|
|
NS_ASSERTION(mCompositingFrame, "DoComposite mCompositingFrame is null");
|
|
|
|
|
|
|
|
*aFrameToUse = nsnull;
|
|
|
|
|
|
|
|
PRUint32 numFrames;
|
|
|
|
this->GetNumFrames(&numFrames);
|
|
|
|
PRInt32 nextFrameIndex = aNextFrame;
|
|
|
|
PRInt32 prevFrameIndex = aPrevFrame;
|
|
|
|
|
|
|
|
if(nextFrameIndex >= numFrames) nextFrameIndex = numFrames-1;
|
|
|
|
if(prevFrameIndex >= numFrames) prevFrameIndex = numFrames-1;
|
|
|
|
|
|
|
|
nsCOMPtr<gfxIImageFrame> prevFrame;
|
|
|
|
this->GetFrameAt(prevFrameIndex, getter_AddRefs(prevFrame));
|
2001-04-26 07:11:52 +00:00
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
PRInt32 prevFrameDisposalMethod;
|
2001-04-26 07:11:52 +00:00
|
|
|
if(nextFrameIndex == 0)
|
|
|
|
prevFrameDisposalMethod = 2;
|
|
|
|
else
|
|
|
|
prevFrame->GetFrameDisposalMethod(&prevFrameDisposalMethod);
|
2001-03-13 23:33:11 +00:00
|
|
|
|
|
|
|
nsCOMPtr<gfxIImageFrame> nextFrame;
|
|
|
|
this->GetFrameAt(nextFrameIndex, getter_AddRefs(nextFrame));
|
|
|
|
|
|
|
|
PRInt32 x;
|
|
|
|
PRInt32 y;
|
|
|
|
PRInt32 width;
|
|
|
|
PRInt32 height;
|
|
|
|
nextFrame->GetX(&x);
|
|
|
|
nextFrame->GetY(&y);
|
|
|
|
nextFrame->GetWidth(&width);
|
|
|
|
nextFrame->GetHeight(&height);
|
2001-04-26 07:11:52 +00:00
|
|
|
|
|
|
|
gfx_color color = 0;
|
|
|
|
gfx_color trans = 0;
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
switch (prevFrameDisposalMethod) {
|
2001-03-24 02:44:26 +00:00
|
|
|
default:
|
2001-03-13 23:33:11 +00:00
|
|
|
case 0: // DISPOSE_NOT_SPECIFIED
|
2001-04-26 07:11:52 +00:00
|
|
|
mCompositingFrame->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)aFrameToUse); // addrefs again
|
|
|
|
|
|
|
|
nextFrame->DrawTo(mCompositingFrame, x, y, width, height);
|
|
|
|
break;
|
2001-03-13 23:33:11 +00:00
|
|
|
case 1: // DISPOSE_KEEP Leave previous frame in the framebuffer
|
|
|
|
mCompositingFrame->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)aFrameToUse); // addrefs again
|
2001-04-26 07:11:52 +00:00
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
nextFrame->DrawTo(mCompositingFrame, x, y, width, height);
|
2001-04-26 07:11:52 +00:00
|
|
|
BuildCompositeMask(mCompositingFrame, nextFrame);
|
2001-03-13 23:33:11 +00:00
|
|
|
break;
|
|
|
|
case 2: // DISPOSE_OVERWRITE_BGCOLOR Overwrite with background color
|
2001-04-26 07:11:52 +00:00
|
|
|
mCompositingFrame->QueryInterface(NS_GET_IID(gfxIImageFrame), (void**)aFrameToUse); // addrefs again
|
2001-03-13 23:33:11 +00:00
|
|
|
|
2001-04-26 07:11:52 +00:00
|
|
|
// Not actually getting the background color here, and instead filling with
|
|
|
|
// 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
|
|
|
|
// it would blit incorrectly. Windows needs masked out bits to be zeroed out too.
|
|
|
|
//nextFrame->GetBackgroundColor(&color);
|
|
|
|
FillWithColor(mCompositingFrame, color);
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
// blit next frame into this clean slate
|
|
|
|
nextFrame->DrawTo(mCompositingFrame, x, y, width, height);
|
2001-04-26 07:11:52 +00:00
|
|
|
|
|
|
|
ZeroMask(mCompositingFrame);
|
|
|
|
BuildCompositeMask(mCompositingFrame, nextFrame);
|
2001-03-13 23:33:11 +00:00
|
|
|
break;
|
|
|
|
case 4: // DISPOSE_OVERWRITE_PREVIOUS Save-under
|
|
|
|
//XXX Reblit previous composite into frame buffer
|
|
|
|
//
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-04-26 07:11:52 +00:00
|
|
|
(*aDirtyRect).x = 0;
|
|
|
|
(*aDirtyRect).y = 0;
|
|
|
|
(*aDirtyRect).width = mSize.width;
|
|
|
|
(*aDirtyRect).height = mSize.height;
|
|
|
|
|
2001-03-13 23:33:11 +00:00
|
|
|
// Get the next frame's disposal method, if it is it DISPOSE_OVER, save off
|
2001-04-26 07:11:52 +00:00
|
|
|
// this mCompositeFrame for reblitting when this timer gets fired again
|
2001-03-13 23:33:11 +00:00
|
|
|
PRInt32 nextFrameDisposalMethod;
|
|
|
|
nextFrame->GetFrameDisposalMethod(&nextFrameDisposalMethod);
|
|
|
|
//XXX if(nextFrameDisposalMethod == 4)
|
|
|
|
// blit mPreviousCompositeFrame with this frame
|
2001-03-22 10:26:36 +00:00
|
|
|
}
|
2001-03-24 02:44:26 +00:00
|
|
|
//******************************************************************************
|
|
|
|
/* void onStartDecode (in imgIRequest aRequest, in nsISupports cx); */
|
|
|
|
NS_IMETHODIMP imgContainer::OnStartDecode(imgIRequest *aRequest, nsISupports *cx)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* void onStartContainer (in imgIRequest aRequest, in nsISupports cx, in imgIContainer aContainer); */
|
|
|
|
NS_IMETHODIMP imgContainer::OnStartContainer(imgIRequest *aRequest, nsISupports *cx, imgIContainer *aContainer)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* void onStartFrame (in imgIRequest aRequest, in nsISupports cx, in gfxIImageFrame aFrame); */
|
|
|
|
NS_IMETHODIMP imgContainer::OnStartFrame(imgIRequest *aRequest, nsISupports *cx, gfxIImageFrame *aFrame)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* [noscript] void onDataAvailable (in imgIRequest aRequest, in nsISupports cx, in gfxIImageFrame aFrame, [const] in nsRect aRect); */
|
|
|
|
NS_IMETHODIMP imgContainer::OnDataAvailable(imgIRequest *aRequest, nsISupports *cx, gfxIImageFrame *aFrame, const nsRect * aRect)
|
|
|
|
{
|
|
|
|
if(mCompositingFrame && !mCurrentDecodingFrameIndex) {
|
|
|
|
// Update the composite frame
|
|
|
|
PRInt32 x;
|
|
|
|
aFrame->GetX(&x);
|
|
|
|
aFrame->DrawTo(mCompositingFrame, x, aRect->y, aRect->width, aRect->height);
|
2001-04-26 07:11:52 +00:00
|
|
|
BuildCompositeMask(mCompositingFrame, aFrame);
|
2001-03-24 02:44:26 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* void onStopFrame (in imgIRequest aRequest, in nsISupports cx, in gfxIImageFrame aFrame); */
|
|
|
|
NS_IMETHODIMP imgContainer::OnStopFrame(imgIRequest *aRequest, nsISupports *cx, gfxIImageFrame *aFrame)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* void onStopContainer (in imgIRequest aRequest, in nsISupports cx, in imgIContainer aContainer); */
|
|
|
|
NS_IMETHODIMP imgContainer::OnStopContainer(imgIRequest *aRequest, nsISupports *cx, imgIContainer *aContainer)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* void onStopDecode (in imgIRequest aRequest, in nsISupports cx, in nsresult status, in wstring statusArg); */
|
|
|
|
NS_IMETHODIMP imgContainer::OnStopDecode(imgIRequest *aRequest, nsISupports *cx, nsresult status, const PRUnichar *statusArg)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* [noscript] void frameChanged (in imgIContainer aContainer, in nsISupports aCX, in gfxIImageFrame aFrame, in nsRect aDirtyRect); */
|
|
|
|
NS_IMETHODIMP imgContainer::FrameChanged(imgIContainer *aContainer, nsISupports *aCX, gfxIImageFrame *aFrame, nsRect * aDirtyRect)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2001-04-26 07:11:52 +00:00
|
|
|
//******************************************************************************
|
|
|
|
// Yet another thing that should be in a GIF specific container.
|
|
|
|
// Fill aFrame with color. Does not change the mask.
|
|
|
|
void imgContainer::FillWithColor(gfxIImageFrame *aFrame, gfx_color color)
|
|
|
|
{
|
|
|
|
if(!aFrame) return;
|
|
|
|
|
|
|
|
nsresult res;
|
|
|
|
aFrame->LockImageData();
|
|
|
|
|
|
|
|
PRUint32 bpr;
|
|
|
|
aFrame->GetImageBytesPerRow(&bpr);
|
|
|
|
|
|
|
|
nscoord width;
|
|
|
|
nscoord height;
|
|
|
|
aFrame->GetWidth(&width);
|
|
|
|
aFrame->GetHeight(&height);
|
|
|
|
|
|
|
|
PRUint8* imageData;
|
|
|
|
PRUint32 imageDataLength;
|
|
|
|
aFrame->GetImageData(&imageData, &imageDataLength);
|
|
|
|
|
|
|
|
PRUint8* foo = (PRUint8*) nsMemory::Alloc(imageDataLength);
|
|
|
|
gfx_color backgroundColor = color;
|
|
|
|
|
|
|
|
gfx_format format;
|
|
|
|
aFrame->GetFormat(&format);
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
case gfxIFormats::RGB_A1:
|
|
|
|
case gfxIFormats::BGR_A1:
|
|
|
|
{
|
|
|
|
PRUint32 iwidth = width;
|
|
|
|
PRUint32 iheight = height;
|
|
|
|
|
|
|
|
for(PRUint32 y=0; y<iheight; y++) {
|
|
|
|
PRUint8* rgbRowIndex = foo;
|
|
|
|
for (PRUint32 x=0; x<iwidth; x++) {
|
|
|
|
#ifdef XP_WIN
|
|
|
|
*rgbRowIndex++ = (backgroundColor & 0x00FF0000) >> 16;
|
|
|
|
*rgbRowIndex++ = (backgroundColor & 0x0000FF00) >> 8;
|
|
|
|
*rgbRowIndex++ = backgroundColor & 0x000000FF;
|
|
|
|
#else
|
|
|
|
#ifdef XP_MAC
|
|
|
|
*rgbRowIndex++ = 0;
|
|
|
|
#endif
|
|
|
|
*rgbRowIndex++ = backgroundColor & 0x000000FF;
|
|
|
|
*rgbRowIndex++ = (backgroundColor & 0x0000FF00) >> 8;
|
|
|
|
*rgbRowIndex++ = (backgroundColor & 0x00FF0000) >> 16;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
aFrame->SetImageData(foo, bpr, y*bpr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
aFrame->UnlockImageData();
|
|
|
|
nsMemory::Free(foo);
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
// Yet another thing that should be in a GIF specific container.
|
|
|
|
// This takes the mask information from the passed in aOverlayFrame and inserts
|
|
|
|
// that information into the aCompositingFrame's mask at the proper offsets. It
|
|
|
|
// does *not* rebuild the entire mask.
|
|
|
|
void imgContainer::BuildCompositeMask(gfxIImageFrame *aCompositingFrame, gfxIImageFrame *aOverlayFrame)
|
|
|
|
{
|
|
|
|
if(!aCompositingFrame || !aOverlayFrame) return;
|
|
|
|
|
|
|
|
nsresult res;
|
|
|
|
PRUint8* compositingAlphaData;
|
|
|
|
PRUint32 compositingAlphaDataLength;
|
|
|
|
aCompositingFrame->LockAlphaData();
|
|
|
|
res = aCompositingFrame->GetAlphaData(&compositingAlphaData, &compositingAlphaDataLength);
|
|
|
|
if(!compositingAlphaData || !compositingAlphaDataLength || !NS_SUCCEEDED(res)) {
|
|
|
|
aCompositingFrame->UnlockAlphaData();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The current frame of the animation (overlay frame) is what
|
|
|
|
// determines the transparent color.
|
|
|
|
gfx_color color;
|
|
|
|
if(!NS_SUCCEEDED(aOverlayFrame->GetTransparentColor(&color))) {
|
|
|
|
//XXX setting the entire mask on here is probably the wrong thing
|
|
|
|
//we should probably just set the region of the overlay frame
|
|
|
|
//to 255, but for the moment I can't find a case where this gives
|
|
|
|
//incorrect behavior
|
|
|
|
memset(compositingAlphaData, 255, compositingAlphaDataLength);
|
|
|
|
aCompositingFrame->UnlockAlphaData();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
aOverlayFrame->LockAlphaData();
|
|
|
|
|
|
|
|
PRUint32 abprComposite;
|
|
|
|
aCompositingFrame->GetAlphaBytesPerRow(&abprComposite);
|
|
|
|
|
|
|
|
PRUint32 abprOverlay;
|
|
|
|
aOverlayFrame->GetAlphaBytesPerRow(&abprOverlay);
|
|
|
|
|
|
|
|
nscoord widthComposite, widthOverlay;
|
|
|
|
nscoord heightComposite, heightOverlay;
|
|
|
|
aCompositingFrame->GetWidth(&widthComposite);
|
|
|
|
aCompositingFrame->GetHeight(&heightComposite);
|
|
|
|
aOverlayFrame->GetWidth(&widthOverlay);
|
|
|
|
aOverlayFrame->GetHeight(&heightOverlay);
|
|
|
|
|
|
|
|
PRInt32 overlayXOffset, overlayYOffset;
|
|
|
|
aOverlayFrame->GetX(&overlayXOffset);
|
|
|
|
aOverlayFrame->GetY(&overlayYOffset);
|
|
|
|
|
|
|
|
PRUint8* overlayAlphaData;
|
|
|
|
PRUint32 overlayAlphaDataLength;
|
|
|
|
res = aOverlayFrame->GetAlphaData(&overlayAlphaData, &overlayAlphaDataLength);
|
|
|
|
|
|
|
|
gfx_format format;
|
|
|
|
aCompositingFrame->GetFormat(&format);
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
case gfxIFormats::RGB_A1:
|
|
|
|
case gfxIFormats::BGR_A1:
|
|
|
|
{
|
|
|
|
|
|
|
|
for(PRUint32 y=overlayYOffset, i=0;
|
|
|
|
i<heightOverlay && y<heightComposite;
|
|
|
|
y++, i++) {
|
|
|
|
|
|
|
|
PRInt32 offset;
|
|
|
|
|
|
|
|
#ifdef XP_WIN // Windows has the funky bottom up data storage we need to account for
|
|
|
|
offset = ((heightComposite - 1) * abprComposite) - y*abprComposite;
|
|
|
|
#else
|
|
|
|
offset = y*abprComposite;
|
|
|
|
#endif
|
|
|
|
PRUint8* alphaLine = compositingAlphaData + offset;
|
|
|
|
|
|
|
|
#ifdef XP_WIN // Windows has the funky bottom up data storage we need to account for
|
|
|
|
offset = ((heightOverlay - 1) * abprOverlay) - i*abprOverlay;
|
|
|
|
#else
|
|
|
|
offset = i*abprOverlay;
|
|
|
|
#endif
|
|
|
|
PRUint8* overlayLine = overlayAlphaData + offset;
|
|
|
|
for (PRUint32 x=overlayXOffset, j=0;
|
|
|
|
j<widthOverlay && x<widthComposite;
|
|
|
|
x++, j++) {
|
|
|
|
|
|
|
|
if (overlayLine[j>>3] & (1<<((7-j)&0x7)))
|
|
|
|
alphaLine[x>>3] |= 1<<((7-x)&0x7);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
aCompositingFrame->UnlockAlphaData();
|
|
|
|
aOverlayFrame->UnlockAlphaData();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
void imgContainer::ZeroMask(gfxIImageFrame *aCompositingFrame)
|
|
|
|
{
|
|
|
|
if(!aCompositingFrame) return;
|
|
|
|
PRUint8* compositingAlphaData;
|
|
|
|
PRUint32 compositingAlphaDataLength;
|
|
|
|
aCompositingFrame->LockAlphaData();
|
|
|
|
nsresult res = aCompositingFrame->GetAlphaData(&compositingAlphaData, &compositingAlphaDataLength);
|
|
|
|
if(NS_SUCCEEDED(res) && compositingAlphaData && compositingAlphaDataLength)
|
|
|
|
memset(compositingAlphaData, 0, compositingAlphaDataLength);
|
|
|
|
|
|
|
|
aCompositingFrame->UnlockAlphaData();
|
|
|
|
return;
|
|
|
|
}
|