webengine/osswebengine/WebCore/platform/symbian/bitmap/AnimationDecoderWrapped.cpp
changeset 11 c8a366e56285
child 15 60c5402cb945
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/platform/symbian/bitmap/AnimationDecoderWrapped.cpp	Thu Sep 24 12:53:48 2009 +0300
@@ -0,0 +1,747 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+
+/*
+ *  This class is wrapped by a proxy CAnimationDecoder
+ *  
+ *  We needed to wrap animation decoding in a proxy because sometimes the cache gets cleared when decoding
+ *  is in progress; when that happens the animation gets deleted while it's in the middle (which causes all sorts
+ *  of crashes and memory stomping).  Now, the cache can delete the proxy while the animation is decoding; the proxy
+ *  will pass on the delete request to the decoder which will cleanup (delete itself) when it's safe to do so.
+ *  
+ */
+
+// INCLUDE FILES
+#include "config.h"
+#include "AnimationDecoderWrapped.h"
+#include "MaskedBitmap.h"
+#include "ImageObserver.h"
+#include "SyncDecodeThread.h"
+#include "Oma2Agent.h"
+using namespace ContentAccess;
+
+namespace TBidirectionalState {
+    class TRunInfo;
+};
+
+#include <eikenv.h>
+
+// constants
+
+// Private namespace for constants and functions
+namespace
+  {
+  // Panic function
+  void Panic( TInt aPanicCode ) { User::Panic( _L("AnimationDecoder"), aPanicCode ); }
+  }
+
+using namespace WebCore;
+CSynDecodeThread *CAnimationDecoderWrapped::iSyncDecodeThread  = NULL;
+
+// ============================ MEMBER FUNCTIONS ===============================
+// -----------------------------------------------------------------------------
+//
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+CAnimationDecoderWrapped::CAnimationDecoderWrapped( ImageObserver* aObs )
+    :CActive( CActive::EPriorityIdle )
+    , iObserver(aObs)
+    , iLoopCount( -1 )
+    , iCurLoopCount( -1 )
+    , iSyncBitmapHandle(-1)
+    , iSyncMaskHandle(-1)
+    , iDecodeInProgress(ETrue)
+    , iIsInvalid(EFalse)
+    , iCanBeDeleted(ETrue)
+{
+    if (CActiveScheduler::Current())
+        CActiveScheduler::Add( this );    
+}
+
+// -----------------------------------------------------------------------------
+//
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+CAnimationDecoderWrapped* CAnimationDecoderWrapped::NewL( ImageObserver* aObs )
+{
+    CAnimationDecoderWrapped* self = new (ELeave) CAnimationDecoderWrapped( aObs );
+    CleanupStack::PushL( self );
+    self->ConstructL( );
+    CleanupStack::Pop(); // self
+    return self;
+}
+
+// -----------------------------------------------------------------------------
+//
+// Symbian constructor can leave.
+// -----------------------------------------------------------------------------
+void CAnimationDecoderWrapped::ConstructL( )
+  {
+  }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+CAnimationDecoderWrapped::~CAnimationDecoderWrapped()
+{
+    Cancel();
+
+    if( iDecoder ) {
+        // animated images still being decoded.
+        iDecoder->Cancel();
+        delete iDecoder, iDecoder = NULL;
+    }
+
+    delete iAnimationBitmap, iAnimationBitmap = NULL;
+    delete iDestination, iDestination = NULL;
+    if(iDrmContent) 
+    {
+        delete iDrmContent;
+        iDrmContent = NULL;
+    }
+}
+
+/**
+ * Invalidate
+ * 
+ * Mark the object invalid (to be deleted); used when it gets cleared from the cache
+ */
+void CAnimationDecoderWrapped::Invalidate()
+{
+    iIsInvalid = ETrue;
+    if (iCanBeDeleted)
+        delete this;
+}
+
+// -----------------------------------------------------------------------------
+// OpenAndDecodeSyncL
+// -----------------------------------------------------------------------------
+void CAnimationDecoderWrapped::OpenAndDecodeSyncL( const TDesC8& aData )
+{    
+    iSizeAvailable = EFalse;
+    iRawDataComplete = ETrue;
+    delete iDestination;
+    iDestination = NULL;
+    
+    if(!iSyncDecodeThread) { // first time, create decoder thread
+        iSyncDecodeThread = CSynDecodeThread::NewL();
+    }
+    
+    if (iSyncDecodeThread->Decode(aData) == KErrNone) {
+        iSyncDecodeThread->Handle(iSyncBitmapHandle, iSyncMaskHandle); 
+        Destination(); // duplicate bitmap handles
+        iSizeAvailable = ETrue;
+    }        
+}
+
+CMaskedBitmap* CAnimationDecoderWrapped::Destination() 
+{ 
+    if (iDestination) {
+        return iDestination; 
+    }
+        
+    if (iSyncBitmapHandle != -1 && iSyncMaskHandle != -1) {
+        CFbsBitmap* bitmap = new CFbsBitmap();
+        bitmap->Duplicate(iSyncBitmapHandle);
+        CFbsBitmap* mask = new CFbsBitmap();
+        mask->Duplicate(iSyncMaskHandle);
+
+        iDestination = new CMaskedBitmap(bitmap, mask);
+        iDestination->SetFrameIndex(0);
+        iDestination->SetFrameDelay(0);
+        iSyncBitmapHandle = -1;
+        iSyncMaskHandle = -1;
+    }
+    
+    return iDestination;
+}
+//=============================================================================
+// DecodeDRMImageContentL : Function for handling the DRM image content
+//=============================================================================
+HBufC8* CAnimationDecoderWrapped::DecodeDRMImageContentL(const TDesC8& aData)
+{
+    // input buffers for image conversion
+    HBufC8* bufInput = HBufC8::NewLC( aData.Length() + 1 );
+    TPtr8 ptrInput = bufInput->Des();
+    //Reader intends to view content
+    ptrInput.Append( EView );
+    ptrInput.Append( aData );
+
+    // output buffer for image conversion
+    HBufC8* animatedDRMdata = HBufC8::NewLC( aData.Length() + 256 );
+    TPtr8 ptrOutput = animatedDRMdata->Des();
+
+  //Find DRM agent
+    TAgent agentDRM;
+    
+    RArray<ContentAccess::TAgent> agents;
+    ContentAccess::CManager* manager = CManager::NewLC();
+    manager->ListAgentsL( agents );
+    for ( TInt i = 0; i < agents.Count(); i++ )
+      {
+    if ( agents[i].Name().Compare( KOmaDrm2AgentName ) == 0)
+      {
+       agentDRM = agents[i];
+       //convert the DRM image
+       manager->AgentSpecificCommand( agentDRM, EDecryptOma1DcfBuffer, ptrInput,ptrOutput);
+       break;
+      }
+    }
+
+    CleanupStack::PopAndDestroy(manager);
+    //keep animatedDRMdata to return
+    CleanupStack::Pop(animatedDRMdata);
+    CleanupStack::PopAndDestroy(bufInput);
+
+    return animatedDRMdata;
+    }
+// -----------------------------------------------------------------------------
+// OpenL
+// -----------------------------------------------------------------------------
+void CAnimationDecoderWrapped::OpenL( const TDesC8& aData, TDesC* aMIMEType, TBool aIsComplete )
+{
+    iCanBeDeleted = EFalse;
+    if(!iObserver) {
+        OpenAndDecodeSyncL(aData);
+        iCanBeDeleted = ETrue;
+        if (iIsInvalid)
+            delete this;
+        return;
+    }
+        
+    
+    delete iDestination;
+    iDestination = NULL;
+    iDestination = CMaskedBitmap::NewL();
+
+    HBufC8* mime = 0;
+    TPtrC8 buffer(aData.Ptr(),aData.Length());
+    if (aMIMEType) {
+        // it is safer to ignore the server supplied mime type and just recognize
+        // the image type from the data headers. this does not work for all formats though
+        if ( *aMIMEType==KMimeWBMP || *aMIMEType==KMimeOTA || *aMIMEType==KMimeWMF){
+            // convert to 8 bit
+            mime = HBufC8::NewLC(aMIMEType->Length());
+            mime->Des().Copy(*aMIMEType);
+        }
+        if( *aMIMEType==KMimeDRM )
+        {
+        iDrmContent = DecodeDRMImageContentL(aData);
+        
+        TInt drmContentLength = iDrmContent->Des().Length();
+        buffer.Set( (const TUint8*)iDrmContent->Des().Ptr(), drmContentLength);
+        }
+    }
+         
+    if( !iDecoder )
+        iDecoder = CBufferedImageDecoder::NewL(CEikonEnv::Static()->FsSession());
+
+    if (mime){
+        if (iDecoder) {
+            iDecoder->OpenL(buffer,*mime,CImageDecoder::EOptionNone);
+            CleanupStack::PopAndDestroy(); // mime
+        }
+    }
+    else {
+        if (iDecoder) {
+            iDecoder->OpenL(buffer,CImageDecoder::EOptionNone);
+        }
+    }
+
+    iRawDataComplete = aIsComplete;
+
+    if(iDecoder && iDecoder->ValidDecoder()  && iDecoder->IsImageHeaderProcessingComplete()) {
+        StartDecodingL();
+    }
+    else {
+        // remove me when incremental image rendering gets supported
+        iCanBeDeleted = ETrue;
+        if (iIsInvalid)
+            delete this;
+        User::Leave( KErrCorrupt );
+    }
+
+    //If it is an animated image, let's figure out loop count
+    if(IsAnimation()) {
+        // first see if have a netscape 2.0 extension header 
+        const TUint8 extString[] = { 'N', 'E', 'T', 'S', 'C', 'A', 'P','E','2','.','0','\3','\1' };
+        const TInt sizeofextString = sizeof(extString);
+        TPtrC8 rawDataPtr((TUint8*)aData.Ptr(), aData.Length());
+        TInt offset = rawDataPtr.Find(extString, sizeofextString);
+        if(offset != KErrNotFound) {
+            // found a header, get the loop count -
+            // (the loop count is in the 2 bytes following the header string listed above,
+            // stored low byte then high byte)
+            iLoopCount = (TInt16)((rawDataPtr[offset+sizeofextString+1] * 256) + rawDataPtr[offset+sizeofextString]);
+            if(iLoopCount != 0) {
+                ++iLoopCount;  // +1 to make it 1 based rather than 0 based 
+            }
+            else{
+            // 0 indicates infinite - map to internal loop count infinite value 
+                iLoopCount = -1;
+            }
+        }
+        else {
+            // no header found, assume 1x thru loop 
+            iLoopCount = 1;
+        }
+        iCurLoopCount = iLoopCount;
+    }
+    iCanBeDeleted = ETrue;
+    if (iIsInvalid)
+        delete this;
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::AddDataL
+// New chunk of raw data
+//
+// -----------------------------------------------------------------------------
+//
+void CAnimationDecoderWrapped::AddDataL(
+    const TDesC8& aNextChunk,
+    TBool aIsComplete )
+{
+    iRawDataComplete = aIsComplete;
+
+    if( iDecoder ) {
+        iDecoder->AppendDataL(aNextChunk);
+        if( iDecoder->ValidDecoder() ) {
+            //  if the image conversion is busy , then just appending the
+            // data should be sufficient
+            if(iStatus == KRequestPending) {
+                // more image data
+                iDecoder->ContinueConvert( &iStatus );
+                SetActive();
+            }
+        }
+        else {
+            iDecoder->ContinueOpenL() ;
+            if(iDecoder->ValidDecoder()  && iDecoder->IsImageHeaderProcessingComplete()){
+                StartDecodingL();
+            }
+        }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CImageLoader::StartDecodingL
+//
+// -----------------------------------------------------------------------------
+//
+void CAnimationDecoderWrapped::StartDecodingL()
+{
+    // Check frame count
+    iAnimationFrameCount = iDecoder->FrameCount();
+    iAnimation = iAnimationFrameCount > 1;
+    iFrameInfo = iDecoder->FrameInfo( 0 );
+    iSizeAvailable = ETrue;
+
+    if (iFrameInfo.iFlags & TFrameInfo::ETransparencyPossible){
+        // we only support gray2 and gray256 tiling
+        TDisplayMode maskmode = ( (iFrameInfo.iFlags & TFrameInfo::EAlphaChannel) && (iFrameInfo.iFlags & TFrameInfo::ECanDither)) ? EGray256 : EGray2;
+        TInt error = iDestination->Create( iFrameInfo.iOverallSizeInPixels, DisplayMode(), maskmode );
+
+        if (!error)
+            LoadFrame(0);
+        else
+            RunError(KErrNoMemory);
+    }
+    else {
+        TInt error = iDestination->Create( iFrameInfo.iOverallSizeInPixels, DisplayMode() );
+        if (!error)
+            LoadFrame(0);
+        else
+            RunError(KErrNoMemory);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::MaskDisplayMode
+// -----------------------------------------------------------------------------
+TDisplayMode CAnimationDecoderWrapped::MaskDisplayMode() const
+{
+    if( iFrameInfo.iFlags & TFrameInfo::ETransparencyPossible ){
+        if( iFrameInfo.iFlags & TFrameInfo::EAlphaChannel && (iFrameInfo.iFlags & TFrameInfo::ECanDither))
+            return EGray256;
+    return EGray2;
+    }
+    return ENone;
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::AnimationFrameDelay
+// -----------------------------------------------------------------------------
+TTimeIntervalMicroSeconds32 CAnimationDecoderWrapped::AnimationFrameDelay( TInt aAnimationFrameIndex ) const
+{
+    __ASSERT_ALWAYS( aAnimationFrameIndex >= 0 &&
+    aAnimationFrameIndex < iAnimationFrameCount, Panic( KErrArgument ) );
+
+    return I64INT( iDecoder->FrameInfo( aAnimationFrameIndex ).iDelay.Int64() );
+}
+
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::DoCancel
+// -----------------------------------------------------------------------------
+void CAnimationDecoderWrapped::DoCancel()
+{
+    iDecoder->Cancel();
+    // Delete all processed bitmaps
+    ErrorCleanup();
+    // Complete with cancel
+    iImageState = EInactive;
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::RunL
+// -----------------------------------------------------------------------------
+void CAnimationDecoderWrapped::RunL()
+{
+    // Yeah, we check this a lot in this function but it helps prevent stuff from happening that doesn't need to
+    if (iIsInvalid) {
+        delete this;
+        return;
+    }
+    iCanBeDeleted = EFalse;
+    __ASSERT_DEBUG( iDestination, Panic( KErrGeneral ) );
+    // don't kick off the image decoding until the preview mode is over
+    if (iStatus==KErrUnderflow) {
+        if (!IsAnimation())
+            iObserver->partialImage();
+        iCanBeDeleted = ETrue;
+        if (iIsInvalid)
+            delete this;
+        return;
+    }
+    else if( iStatus == KErrCorrupt ) {
+        RunError( iStatus.Int() );
+        iCanBeDeleted = ETrue;
+        if (iIsInvalid)
+            delete this;
+        return;
+    }
+    User::LeaveIfError( iStatus.Int() );
+    switch( iImageState ) {
+        case EStartLoad:
+            {
+            // start loading the bitmaps
+            StartLoadL();
+            break;
+            }
+        case ECompleteLoad:
+            {
+            // complete loading the bitmaps
+            CompleteLoadL();
+            break;
+            }
+        default:
+            {
+            iCanBeDeleted = ETrue;
+            Panic( KErrTotalLossOfPrecision );
+            }
+    }
+    iCanBeDeleted = ETrue;
+    if (iIsInvalid)
+        delete this;
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::RunError
+// -----------------------------------------------------------------------------
+TInt CAnimationDecoderWrapped::RunError( TInt aError )
+{
+    // Delete all processed bitmaps
+    ErrorCleanup();
+    // Complete with error
+    iImageState = EInactive;
+    iObserver->decoderError(aError);
+    return KErrNone;
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::LoadFrame
+// -----------------------------------------------------------------------------
+TInt CAnimationDecoderWrapped::LoadFrame( TInt aFrameIndex )
+{
+    if( IsBusy() )
+        return KErrNotReady;
+
+    if( aFrameIndex < 0 || aFrameIndex >= iDecoder->FrameCount() )
+        return KErrArgument;
+
+    iFrameIndex = aFrameIndex;
+    // Start the active object
+    iImageState = EStartLoad;
+    SelfComplete();
+    return KErrNone;
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::StartLoadL
+// -----------------------------------------------------------------------------
+void CAnimationDecoderWrapped::StartLoadL()
+{
+    __ASSERT_DEBUG( !iAnimationBitmap, Panic( KErrGeneral ) );
+
+    if( iAnimation ) {
+        // Start animation from first frame by default
+        iAnimationFrameIndex = 0;
+
+        // Check is animation can be continued on top of destination bitmap
+        if( iDestination->FrameIndex() < iFrameIndex )
+          iAnimationFrameIndex = iDestination->FrameIndex() + 1;
+
+        StartLoadAnimationBitmapL( iAnimationFrameIndex );
+    }
+    else // normal image
+        StartLoadNormalBitmap( iFrameIndex );
+    
+    iDecodeInProgress = EFalse;    
+    iImageState = ECompleteLoad;
+    SetActive();
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::StartLoadNormalBitmap
+// -----------------------------------------------------------------------------
+void CAnimationDecoderWrapped::StartLoadNormalBitmap( TInt aFrameIndex )
+{
+    CFbsBitmap& dstBitmap = iDestination->BitmapModifyable();
+    CFbsBitmap& dstMask = iDestination->MaskModifyable();
+
+    if( MaskDisplayMode() != ENone && dstMask.Handle() )
+        iDecoder->Convert( &iStatus, dstBitmap, dstMask, aFrameIndex );
+    else {
+        dstMask.Reset();
+        iDecoder->Convert( &iStatus, dstBitmap, aFrameIndex );
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::StartLoadAnimationBitmapL
+// -----------------------------------------------------------------------------
+void CAnimationDecoderWrapped::StartLoadAnimationBitmapL( TInt aFrameIndex )
+{
+    __ASSERT_DEBUG( !iAnimationBitmap, Panic( KErrGeneral ) );
+
+    // Create animation bitmap
+    iAnimationBitmap = CMaskedBitmap::NewL();
+    CFbsBitmap& animBitmap = iAnimationBitmap->BitmapModifyable();
+    CFbsBitmap& animMask = iAnimationBitmap->MaskModifyable();
+
+    TFrameInfo frameInfo( iDecoder->FrameInfo( aFrameIndex ) );
+    User::LeaveIfError( animBitmap.Create(
+    frameInfo.iOverallSizeInPixels, EColor16M ) );
+
+    TDisplayMode maskDisplayMode( ENone );
+
+    if( frameInfo.iFlags & TFrameInfo::ETransparencyPossible ) {
+        if( frameInfo.iFlags & TFrameInfo::EAlphaChannel && (frameInfo.iFlags & TFrameInfo::ECanDither)) 
+            maskDisplayMode = EGray256;
+        maskDisplayMode = EGray2;
+
+        User::LeaveIfError( animMask.Create( frameInfo.iOverallSizeInPixels, maskDisplayMode ) );
+        iDecoder->Convert( &iStatus, animBitmap, animMask, aFrameIndex );
+    }
+    else
+        iDecoder->Convert( &iStatus, animBitmap, aFrameIndex );
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::CompleteLoadL
+// -----------------------------------------------------------------------------
+void CAnimationDecoderWrapped::CompleteLoadL()
+{
+    TSize frameSize = iFrameInfo.iOverallSizeInPixels;
+    int sizeinBytes = frameSize.iWidth * frameSize.iHeight * 2;
+    if( iAnimationBitmap ){
+        // Copy animation bitmap to destination
+        BuildAnimationFrameL();
+        delete iAnimationBitmap;
+        iAnimationBitmap = NULL;
+
+        iDestination->SetFrameIndex( iAnimationFrameIndex );
+        iDestination->SetFrameDelay( AnimationFrameDelay( iAnimationFrameIndex ) );
+
+        if( iAnimationFrameIndex < iFrameIndex ) {
+            // re-start the active object and load next frame
+            iAnimationFrameIndex++;
+            iImageState = EStartLoad;
+            SelfComplete();
+        }
+        else {
+            // Animation ready
+            iImageState = EInactive;
+            iObserver->animationFrameReady(sizeinBytes);
+        }
+    }
+    else {
+        // Save source info destination
+        iDestination->SetFrameIndex( iFrameIndex );
+        iDestination->SetFrameDelay( 0 );
+        //Compress non-animated images via FBServ (losslessly, idle priority) 
+        iDestination->CompressInBackground();     
+
+        // Normal image ready
+        //iDestination = NULL;
+        iImageState = EInactive;
+        iObserver->imageReady(sizeinBytes);
+        delete iDecoder, iDecoder = NULL;
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::BuildAnimationFrameL
+// -----------------------------------------------------------------------------
+void CAnimationDecoderWrapped::BuildAnimationFrameL()
+    {
+    __ASSERT_DEBUG( iAnimationBitmap, Panic( KErrGeneral ) );
+    const CFbsBitmap& animBitmap = iAnimationBitmap->Bitmap();
+    const CFbsBitmap& animMask = iAnimationBitmap->Mask();
+    __ASSERT_DEBUG( animBitmap.Handle(), Panic( KErrGeneral ) );
+
+
+    //If the first frame starts from position(0,0), copy directly to the destination bitmap 
+    //otherwise frame has to be appropriately positioned in the destination bitmap  
+    TPoint aStartPoint(0,0);
+    if( (iAnimationFrameIndex==0) && (iFrameInfo.iFrameCoordsInPixels.iTl==aStartPoint) )
+    {
+        // First frame can be directly put into destination
+        User::LeaveIfError( iDestination->Copy( animBitmap, animMask, ETrue ) );
+    }
+    else {
+        CFbsBitmap& prevBitmap = iDestination->BitmapModifyable();
+        CFbsBitmap& prevMask = iDestination->MaskModifyable();
+
+        // Other frames must be build on top of previous frames
+        __ASSERT_DEBUG( prevBitmap.Handle(), Panic( KErrGeneral ) );
+
+        // Create bitmap device to destination bitmap
+        CFbsBitGc* bitGc;
+        CFbsBitmapDevice* bitDevice = CFbsBitmapDevice::NewL( &prevBitmap );
+        CleanupStack::PushL( bitDevice );
+        User::LeaveIfError( bitDevice->CreateContext( bitGc ) );
+        CleanupStack::PushL( bitGc );
+
+        // Restore area in destination bitmap if needed
+        TRect restoreRect;
+        TBool restoreToBackground( EFalse );
+        
+        TInt aFrameNo = (iAnimationFrameIndex >= 1)?(iAnimationFrameIndex):1;
+        TFrameInfo prevFrameInfo(iDecoder->FrameInfo(aFrameNo - 1));
+        
+        //TFrameInfo prevFrameInfo( iDecoder->FrameInfo( iAnimationFrameIndex - 1 ) );
+        
+        if( (prevFrameInfo.iFlags & TFrameInfo::ERestoreToBackground )|| (iAnimationFrameIndex ==0)) 
+        {
+            restoreToBackground = ETrue;
+            restoreRect = prevFrameInfo.iFrameCoordsInPixels;
+            bitGc->SetPenColor( prevFrameInfo.iBackgroundColor );
+            bitGc->SetBrushColor( prevFrameInfo.iBackgroundColor );
+            bitGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+            if(iAnimationFrameIndex ==0){
+              bitGc->Clear();     
+            }
+            else{
+               bitGc->DrawRect( restoreRect );  
+            }
+            bitGc->SetBrushStyle( CGraphicsContext::ENullBrush );
+         }
+        // Copy animation frame to destination bitmap
+        TFrameInfo frameInfo( iDecoder->FrameInfo( iAnimationFrameIndex) );
+        if( animMask.Handle() ) {
+            bitGc->BitBltMasked( frameInfo.iFrameCoordsInPixels.iTl, &animBitmap,
+            animBitmap.SizeInPixels(), &animMask, EFalse );
+        }
+        else {
+            bitGc->BitBlt( frameInfo.iFrameCoordsInPixels.iTl, &animBitmap,
+            animBitmap.SizeInPixels() );
+        }
+        CleanupStack::PopAndDestroy( 2 ); // bitmapCtx, bitmapDev
+
+        // Combine masks if any
+        if( prevMask.Handle() && animMask.Handle() ) {
+            bitDevice = CFbsBitmapDevice::NewL( &prevMask );
+            CleanupStack::PushL( bitDevice );
+            User::LeaveIfError( bitDevice->CreateContext( bitGc ) );
+            CleanupStack::PushL( bitGc );
+
+            if( restoreToBackground ) {
+                bitGc->SetBrushColor( KRgbBlack );
+                bitGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+                if(iAnimationFrameIndex ==0){
+                   bitGc->Clear();    
+                 }
+                 else{
+                   bitGc->DrawRect( restoreRect );  
+                 }
+                bitGc->SetBrushStyle( CGraphicsContext::ENullBrush );
+            }
+            CFbsBitmap* tmpMask = new(ELeave) CFbsBitmap;
+            CleanupStack::PushL( tmpMask );
+            User::LeaveIfError( tmpMask->Create( prevMask.SizeInPixels(), prevMask.DisplayMode() ) );
+            CFbsBitmapDevice* tmpMaskDev = CFbsBitmapDevice::NewL( tmpMask );
+            CleanupStack::PushL( tmpMaskDev );
+            CFbsBitGc* tmpMaskGc;
+            User::LeaveIfError( tmpMaskDev->CreateContext( tmpMaskGc ) );
+            CleanupStack::PushL( tmpMaskGc );
+
+            tmpMaskGc->BitBlt( TPoint( 0, 0 ), &prevMask, frameInfo.iFrameCoordsInPixels );
+
+            bitGc->BitBltMasked( frameInfo.iFrameCoordsInPixels.iTl, &animMask,
+            animMask.SizeInPixels(), tmpMask, ETrue );
+
+            CleanupStack::PopAndDestroy( 5 ); //tmpMask, tmpMaskDev, tmpMaskGc, bitGc, bitDevice
+        }
+    else
+        prevMask.Reset(); // Mask not valid anymore -> reset
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::ErrorCleanup
+// -----------------------------------------------------------------------------
+void CAnimationDecoderWrapped::ErrorCleanup()
+{
+    if( iAnimationBitmap ) {
+        delete iAnimationBitmap;
+        iAnimationBitmap = NULL;
+    }
+
+    if( iDestination ) {
+        delete iDestination;
+        iDestination = NULL;
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CAnimationDecoderWrapped::SelfComplete
+// -----------------------------------------------------------------------------
+void CAnimationDecoderWrapped::SelfComplete( TInt aError )
+{
+    SetActive();
+    iStatus = KRequestPending;
+    TRequestStatus* status = &iStatus;
+    User::RequestComplete( status, aError );
+}
+
+
+
+//  End of File