webengine/osswebengine/WebCore/platform/symbian/bitmap/AnimationDecoderWrapped.cpp
changeset 11 c8a366e56285
child 15 60c5402cb945
equal deleted inserted replaced
10:a359256acfc6 11:c8a366e56285
       
     1 /*
       
     2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 /*
       
    20  *  This class is wrapped by a proxy CAnimationDecoder
       
    21  *  
       
    22  *  We needed to wrap animation decoding in a proxy because sometimes the cache gets cleared when decoding
       
    23  *  is in progress; when that happens the animation gets deleted while it's in the middle (which causes all sorts
       
    24  *  of crashes and memory stomping).  Now, the cache can delete the proxy while the animation is decoding; the proxy
       
    25  *  will pass on the delete request to the decoder which will cleanup (delete itself) when it's safe to do so.
       
    26  *  
       
    27  */
       
    28 
       
    29 // INCLUDE FILES
       
    30 #include "config.h"
       
    31 #include "AnimationDecoderWrapped.h"
       
    32 #include "MaskedBitmap.h"
       
    33 #include "ImageObserver.h"
       
    34 #include "SyncDecodeThread.h"
       
    35 #include "Oma2Agent.h"
       
    36 using namespace ContentAccess;
       
    37 
       
    38 namespace TBidirectionalState {
       
    39     class TRunInfo;
       
    40 };
       
    41 
       
    42 #include <eikenv.h>
       
    43 
       
    44 // constants
       
    45 
       
    46 // Private namespace for constants and functions
       
    47 namespace
       
    48   {
       
    49   // Panic function
       
    50   void Panic( TInt aPanicCode ) { User::Panic( _L("AnimationDecoder"), aPanicCode ); }
       
    51   }
       
    52 
       
    53 using namespace WebCore;
       
    54 CSynDecodeThread *CAnimationDecoderWrapped::iSyncDecodeThread  = NULL;
       
    55 
       
    56 // ============================ MEMBER FUNCTIONS ===============================
       
    57 // -----------------------------------------------------------------------------
       
    58 //
       
    59 // C++ default constructor can NOT contain any code, that
       
    60 // might leave.
       
    61 // -----------------------------------------------------------------------------
       
    62 CAnimationDecoderWrapped::CAnimationDecoderWrapped( ImageObserver* aObs )
       
    63     :CActive( CActive::EPriorityIdle )
       
    64     , iObserver(aObs)
       
    65     , iLoopCount( -1 )
       
    66     , iCurLoopCount( -1 )
       
    67     , iSyncBitmapHandle(-1)
       
    68     , iSyncMaskHandle(-1)
       
    69     , iDecodeInProgress(ETrue)
       
    70     , iIsInvalid(EFalse)
       
    71     , iCanBeDeleted(ETrue)
       
    72 {
       
    73     if (CActiveScheduler::Current())
       
    74         CActiveScheduler::Add( this );    
       
    75 }
       
    76 
       
    77 // -----------------------------------------------------------------------------
       
    78 //
       
    79 // Two-phased constructor.
       
    80 // -----------------------------------------------------------------------------
       
    81 CAnimationDecoderWrapped* CAnimationDecoderWrapped::NewL( ImageObserver* aObs )
       
    82 {
       
    83     CAnimationDecoderWrapped* self = new (ELeave) CAnimationDecoderWrapped( aObs );
       
    84     CleanupStack::PushL( self );
       
    85     self->ConstructL( );
       
    86     CleanupStack::Pop(); // self
       
    87     return self;
       
    88 }
       
    89 
       
    90 // -----------------------------------------------------------------------------
       
    91 //
       
    92 // Symbian constructor can leave.
       
    93 // -----------------------------------------------------------------------------
       
    94 void CAnimationDecoderWrapped::ConstructL( )
       
    95   {
       
    96   }
       
    97 
       
    98 // -----------------------------------------------------------------------------
       
    99 // Destructor
       
   100 // -----------------------------------------------------------------------------
       
   101 CAnimationDecoderWrapped::~CAnimationDecoderWrapped()
       
   102 {
       
   103     Cancel();
       
   104 
       
   105     if( iDecoder ) {
       
   106         // animated images still being decoded.
       
   107         iDecoder->Cancel();
       
   108         delete iDecoder, iDecoder = NULL;
       
   109     }
       
   110 
       
   111     delete iAnimationBitmap, iAnimationBitmap = NULL;
       
   112     delete iDestination, iDestination = NULL;
       
   113     if(iDrmContent) 
       
   114     {
       
   115         delete iDrmContent;
       
   116         iDrmContent = NULL;
       
   117     }
       
   118 }
       
   119 
       
   120 /**
       
   121  * Invalidate
       
   122  * 
       
   123  * Mark the object invalid (to be deleted); used when it gets cleared from the cache
       
   124  */
       
   125 void CAnimationDecoderWrapped::Invalidate()
       
   126 {
       
   127     iIsInvalid = ETrue;
       
   128     if (iCanBeDeleted)
       
   129         delete this;
       
   130 }
       
   131 
       
   132 // -----------------------------------------------------------------------------
       
   133 // OpenAndDecodeSyncL
       
   134 // -----------------------------------------------------------------------------
       
   135 void CAnimationDecoderWrapped::OpenAndDecodeSyncL( const TDesC8& aData )
       
   136 {    
       
   137     iSizeAvailable = EFalse;
       
   138     iRawDataComplete = ETrue;
       
   139     delete iDestination;
       
   140     iDestination = NULL;
       
   141     
       
   142     if(!iSyncDecodeThread) { // first time, create decoder thread
       
   143         iSyncDecodeThread = CSynDecodeThread::NewL();
       
   144     }
       
   145     
       
   146     if (iSyncDecodeThread->Decode(aData) == KErrNone) {
       
   147         iSyncDecodeThread->Handle(iSyncBitmapHandle, iSyncMaskHandle); 
       
   148         Destination(); // duplicate bitmap handles
       
   149         iSizeAvailable = ETrue;
       
   150     }        
       
   151 }
       
   152 
       
   153 CMaskedBitmap* CAnimationDecoderWrapped::Destination() 
       
   154 { 
       
   155     if (iDestination) {
       
   156         return iDestination; 
       
   157     }
       
   158         
       
   159     if (iSyncBitmapHandle != -1 && iSyncMaskHandle != -1) {
       
   160         CFbsBitmap* bitmap = new CFbsBitmap();
       
   161         bitmap->Duplicate(iSyncBitmapHandle);
       
   162         CFbsBitmap* mask = new CFbsBitmap();
       
   163         mask->Duplicate(iSyncMaskHandle);
       
   164 
       
   165         iDestination = new CMaskedBitmap(bitmap, mask);
       
   166         iDestination->SetFrameIndex(0);
       
   167         iDestination->SetFrameDelay(0);
       
   168         iSyncBitmapHandle = -1;
       
   169         iSyncMaskHandle = -1;
       
   170     }
       
   171     
       
   172     return iDestination;
       
   173 }
       
   174 //=============================================================================
       
   175 // DecodeDRMImageContentL : Function for handling the DRM image content
       
   176 //=============================================================================
       
   177 HBufC8* CAnimationDecoderWrapped::DecodeDRMImageContentL(const TDesC8& aData)
       
   178 {
       
   179     // input buffers for image conversion
       
   180     HBufC8* bufInput = HBufC8::NewLC( aData.Length() + 1 );
       
   181     TPtr8 ptrInput = bufInput->Des();
       
   182     //Reader intends to view content
       
   183     ptrInput.Append( EView );
       
   184     ptrInput.Append( aData );
       
   185 
       
   186     // output buffer for image conversion
       
   187     HBufC8* animatedDRMdata = HBufC8::NewLC( aData.Length() + 256 );
       
   188     TPtr8 ptrOutput = animatedDRMdata->Des();
       
   189 
       
   190   //Find DRM agent
       
   191     TAgent agentDRM;
       
   192     
       
   193     RArray<ContentAccess::TAgent> agents;
       
   194     ContentAccess::CManager* manager = CManager::NewLC();
       
   195     manager->ListAgentsL( agents );
       
   196     for ( TInt i = 0; i < agents.Count(); i++ )
       
   197       {
       
   198     if ( agents[i].Name().Compare( KOmaDrm2AgentName ) == 0)
       
   199       {
       
   200        agentDRM = agents[i];
       
   201        //convert the DRM image
       
   202        manager->AgentSpecificCommand( agentDRM, EDecryptOma1DcfBuffer, ptrInput,ptrOutput);
       
   203        break;
       
   204       }
       
   205     }
       
   206 
       
   207     CleanupStack::PopAndDestroy(manager);
       
   208     //keep animatedDRMdata to return
       
   209     CleanupStack::Pop(animatedDRMdata);
       
   210     CleanupStack::PopAndDestroy(bufInput);
       
   211 
       
   212     return animatedDRMdata;
       
   213     }
       
   214 // -----------------------------------------------------------------------------
       
   215 // OpenL
       
   216 // -----------------------------------------------------------------------------
       
   217 void CAnimationDecoderWrapped::OpenL( const TDesC8& aData, TDesC* aMIMEType, TBool aIsComplete )
       
   218 {
       
   219     iCanBeDeleted = EFalse;
       
   220     if(!iObserver) {
       
   221         OpenAndDecodeSyncL(aData);
       
   222         iCanBeDeleted = ETrue;
       
   223         if (iIsInvalid)
       
   224             delete this;
       
   225         return;
       
   226     }
       
   227         
       
   228     
       
   229     delete iDestination;
       
   230     iDestination = NULL;
       
   231     iDestination = CMaskedBitmap::NewL();
       
   232 
       
   233     HBufC8* mime = 0;
       
   234     TPtrC8 buffer(aData.Ptr(),aData.Length());
       
   235     if (aMIMEType) {
       
   236         // it is safer to ignore the server supplied mime type and just recognize
       
   237         // the image type from the data headers. this does not work for all formats though
       
   238         if ( *aMIMEType==KMimeWBMP || *aMIMEType==KMimeOTA || *aMIMEType==KMimeWMF){
       
   239             // convert to 8 bit
       
   240             mime = HBufC8::NewLC(aMIMEType->Length());
       
   241             mime->Des().Copy(*aMIMEType);
       
   242         }
       
   243         if( *aMIMEType==KMimeDRM )
       
   244         {
       
   245         iDrmContent = DecodeDRMImageContentL(aData);
       
   246         
       
   247         TInt drmContentLength = iDrmContent->Des().Length();
       
   248         buffer.Set( (const TUint8*)iDrmContent->Des().Ptr(), drmContentLength);
       
   249         }
       
   250     }
       
   251          
       
   252     if( !iDecoder )
       
   253         iDecoder = CBufferedImageDecoder::NewL(CEikonEnv::Static()->FsSession());
       
   254 
       
   255     if (mime){
       
   256         if (iDecoder) {
       
   257             iDecoder->OpenL(buffer,*mime,CImageDecoder::EOptionNone);
       
   258             CleanupStack::PopAndDestroy(); // mime
       
   259         }
       
   260     }
       
   261     else {
       
   262         if (iDecoder) {
       
   263             iDecoder->OpenL(buffer,CImageDecoder::EOptionNone);
       
   264         }
       
   265     }
       
   266 
       
   267     iRawDataComplete = aIsComplete;
       
   268 
       
   269     if(iDecoder && iDecoder->ValidDecoder()  && iDecoder->IsImageHeaderProcessingComplete()) {
       
   270         StartDecodingL();
       
   271     }
       
   272     else {
       
   273         // remove me when incremental image rendering gets supported
       
   274         iCanBeDeleted = ETrue;
       
   275         if (iIsInvalid)
       
   276             delete this;
       
   277         User::Leave( KErrCorrupt );
       
   278     }
       
   279 
       
   280     //If it is an animated image, let's figure out loop count
       
   281     if(IsAnimation()) {
       
   282         // first see if have a netscape 2.0 extension header 
       
   283         const TUint8 extString[] = { 'N', 'E', 'T', 'S', 'C', 'A', 'P','E','2','.','0','\3','\1' };
       
   284         const TInt sizeofextString = sizeof(extString);
       
   285         TPtrC8 rawDataPtr((TUint8*)aData.Ptr(), aData.Length());
       
   286         TInt offset = rawDataPtr.Find(extString, sizeofextString);
       
   287         if(offset != KErrNotFound) {
       
   288             // found a header, get the loop count -
       
   289             // (the loop count is in the 2 bytes following the header string listed above,
       
   290             // stored low byte then high byte)
       
   291             iLoopCount = (TInt16)((rawDataPtr[offset+sizeofextString+1] * 256) + rawDataPtr[offset+sizeofextString]);
       
   292             if(iLoopCount != 0) {
       
   293                 ++iLoopCount;  // +1 to make it 1 based rather than 0 based 
       
   294             }
       
   295             else{
       
   296             // 0 indicates infinite - map to internal loop count infinite value 
       
   297                 iLoopCount = -1;
       
   298             }
       
   299         }
       
   300         else {
       
   301             // no header found, assume 1x thru loop 
       
   302             iLoopCount = 1;
       
   303         }
       
   304         iCurLoopCount = iLoopCount;
       
   305     }
       
   306     iCanBeDeleted = ETrue;
       
   307     if (iIsInvalid)
       
   308         delete this;
       
   309 }
       
   310 
       
   311 // -----------------------------------------------------------------------------
       
   312 // CAnimationDecoderWrapped::AddDataL
       
   313 // New chunk of raw data
       
   314 //
       
   315 // -----------------------------------------------------------------------------
       
   316 //
       
   317 void CAnimationDecoderWrapped::AddDataL(
       
   318     const TDesC8& aNextChunk,
       
   319     TBool aIsComplete )
       
   320 {
       
   321     iRawDataComplete = aIsComplete;
       
   322 
       
   323     if( iDecoder ) {
       
   324         iDecoder->AppendDataL(aNextChunk);
       
   325         if( iDecoder->ValidDecoder() ) {
       
   326             //  if the image conversion is busy , then just appending the
       
   327             // data should be sufficient
       
   328             if(iStatus == KRequestPending) {
       
   329                 // more image data
       
   330                 iDecoder->ContinueConvert( &iStatus );
       
   331                 SetActive();
       
   332             }
       
   333         }
       
   334         else {
       
   335             iDecoder->ContinueOpenL() ;
       
   336             if(iDecoder->ValidDecoder()  && iDecoder->IsImageHeaderProcessingComplete()){
       
   337                 StartDecodingL();
       
   338             }
       
   339         }
       
   340     }
       
   341 }
       
   342 
       
   343 // -----------------------------------------------------------------------------
       
   344 // CImageLoader::StartDecodingL
       
   345 //
       
   346 // -----------------------------------------------------------------------------
       
   347 //
       
   348 void CAnimationDecoderWrapped::StartDecodingL()
       
   349 {
       
   350     // Check frame count
       
   351     iAnimationFrameCount = iDecoder->FrameCount();
       
   352     iAnimation = iAnimationFrameCount > 1;
       
   353     iFrameInfo = iDecoder->FrameInfo( 0 );
       
   354     iSizeAvailable = ETrue;
       
   355 
       
   356     if (iFrameInfo.iFlags & TFrameInfo::ETransparencyPossible){
       
   357         // we only support gray2 and gray256 tiling
       
   358         TDisplayMode maskmode = ( (iFrameInfo.iFlags & TFrameInfo::EAlphaChannel) && (iFrameInfo.iFlags & TFrameInfo::ECanDither)) ? EGray256 : EGray2;
       
   359         TInt error = iDestination->Create( iFrameInfo.iOverallSizeInPixels, DisplayMode(), maskmode );
       
   360 
       
   361         if (!error)
       
   362             LoadFrame(0);
       
   363         else
       
   364             RunError(KErrNoMemory);
       
   365     }
       
   366     else {
       
   367         TInt error = iDestination->Create( iFrameInfo.iOverallSizeInPixels, DisplayMode() );
       
   368         if (!error)
       
   369             LoadFrame(0);
       
   370         else
       
   371             RunError(KErrNoMemory);
       
   372     }
       
   373 }
       
   374 
       
   375 // -----------------------------------------------------------------------------
       
   376 // CAnimationDecoderWrapped::MaskDisplayMode
       
   377 // -----------------------------------------------------------------------------
       
   378 TDisplayMode CAnimationDecoderWrapped::MaskDisplayMode() const
       
   379 {
       
   380     if( iFrameInfo.iFlags & TFrameInfo::ETransparencyPossible ){
       
   381         if( iFrameInfo.iFlags & TFrameInfo::EAlphaChannel && (iFrameInfo.iFlags & TFrameInfo::ECanDither))
       
   382             return EGray256;
       
   383     return EGray2;
       
   384     }
       
   385     return ENone;
       
   386 }
       
   387 
       
   388 // -----------------------------------------------------------------------------
       
   389 // CAnimationDecoderWrapped::AnimationFrameDelay
       
   390 // -----------------------------------------------------------------------------
       
   391 TTimeIntervalMicroSeconds32 CAnimationDecoderWrapped::AnimationFrameDelay( TInt aAnimationFrameIndex ) const
       
   392 {
       
   393     __ASSERT_ALWAYS( aAnimationFrameIndex >= 0 &&
       
   394     aAnimationFrameIndex < iAnimationFrameCount, Panic( KErrArgument ) );
       
   395 
       
   396     return I64INT( iDecoder->FrameInfo( aAnimationFrameIndex ).iDelay.Int64() );
       
   397 }
       
   398 
       
   399 
       
   400 // -----------------------------------------------------------------------------
       
   401 // CAnimationDecoderWrapped::DoCancel
       
   402 // -----------------------------------------------------------------------------
       
   403 void CAnimationDecoderWrapped::DoCancel()
       
   404 {
       
   405     iDecoder->Cancel();
       
   406     // Delete all processed bitmaps
       
   407     ErrorCleanup();
       
   408     // Complete with cancel
       
   409     iImageState = EInactive;
       
   410 }
       
   411 
       
   412 // -----------------------------------------------------------------------------
       
   413 // CAnimationDecoderWrapped::RunL
       
   414 // -----------------------------------------------------------------------------
       
   415 void CAnimationDecoderWrapped::RunL()
       
   416 {
       
   417     // Yeah, we check this a lot in this function but it helps prevent stuff from happening that doesn't need to
       
   418     if (iIsInvalid) {
       
   419         delete this;
       
   420         return;
       
   421     }
       
   422     iCanBeDeleted = EFalse;
       
   423     __ASSERT_DEBUG( iDestination, Panic( KErrGeneral ) );
       
   424     // don't kick off the image decoding until the preview mode is over
       
   425     if (iStatus==KErrUnderflow) {
       
   426         if (!IsAnimation())
       
   427             iObserver->partialImage();
       
   428         iCanBeDeleted = ETrue;
       
   429         if (iIsInvalid)
       
   430             delete this;
       
   431         return;
       
   432     }
       
   433     else if( iStatus == KErrCorrupt ) {
       
   434         RunError( iStatus.Int() );
       
   435         iCanBeDeleted = ETrue;
       
   436         if (iIsInvalid)
       
   437             delete this;
       
   438         return;
       
   439     }
       
   440     User::LeaveIfError( iStatus.Int() );
       
   441     switch( iImageState ) {
       
   442         case EStartLoad:
       
   443             {
       
   444             // start loading the bitmaps
       
   445             StartLoadL();
       
   446             break;
       
   447             }
       
   448         case ECompleteLoad:
       
   449             {
       
   450             // complete loading the bitmaps
       
   451             CompleteLoadL();
       
   452             break;
       
   453             }
       
   454         default:
       
   455             {
       
   456             iCanBeDeleted = ETrue;
       
   457             Panic( KErrTotalLossOfPrecision );
       
   458             }
       
   459     }
       
   460     iCanBeDeleted = ETrue;
       
   461     if (iIsInvalid)
       
   462         delete this;
       
   463 }
       
   464 
       
   465 // -----------------------------------------------------------------------------
       
   466 // CAnimationDecoderWrapped::RunError
       
   467 // -----------------------------------------------------------------------------
       
   468 TInt CAnimationDecoderWrapped::RunError( TInt aError )
       
   469 {
       
   470     // Delete all processed bitmaps
       
   471     ErrorCleanup();
       
   472     // Complete with error
       
   473     iImageState = EInactive;
       
   474     iObserver->decoderError(aError);
       
   475     return KErrNone;
       
   476 }
       
   477 
       
   478 // -----------------------------------------------------------------------------
       
   479 // CAnimationDecoderWrapped::LoadFrame
       
   480 // -----------------------------------------------------------------------------
       
   481 TInt CAnimationDecoderWrapped::LoadFrame( TInt aFrameIndex )
       
   482 {
       
   483     if( IsBusy() )
       
   484         return KErrNotReady;
       
   485 
       
   486     if( aFrameIndex < 0 || aFrameIndex >= iDecoder->FrameCount() )
       
   487         return KErrArgument;
       
   488 
       
   489     iFrameIndex = aFrameIndex;
       
   490     // Start the active object
       
   491     iImageState = EStartLoad;
       
   492     SelfComplete();
       
   493     return KErrNone;
       
   494 }
       
   495 
       
   496 // -----------------------------------------------------------------------------
       
   497 // CAnimationDecoderWrapped::StartLoadL
       
   498 // -----------------------------------------------------------------------------
       
   499 void CAnimationDecoderWrapped::StartLoadL()
       
   500 {
       
   501     __ASSERT_DEBUG( !iAnimationBitmap, Panic( KErrGeneral ) );
       
   502 
       
   503     if( iAnimation ) {
       
   504         // Start animation from first frame by default
       
   505         iAnimationFrameIndex = 0;
       
   506 
       
   507         // Check is animation can be continued on top of destination bitmap
       
   508         if( iDestination->FrameIndex() < iFrameIndex )
       
   509           iAnimationFrameIndex = iDestination->FrameIndex() + 1;
       
   510 
       
   511         StartLoadAnimationBitmapL( iAnimationFrameIndex );
       
   512     }
       
   513     else // normal image
       
   514         StartLoadNormalBitmap( iFrameIndex );
       
   515     
       
   516     iDecodeInProgress = EFalse;    
       
   517     iImageState = ECompleteLoad;
       
   518     SetActive();
       
   519 }
       
   520 
       
   521 // -----------------------------------------------------------------------------
       
   522 // CAnimationDecoderWrapped::StartLoadNormalBitmap
       
   523 // -----------------------------------------------------------------------------
       
   524 void CAnimationDecoderWrapped::StartLoadNormalBitmap( TInt aFrameIndex )
       
   525 {
       
   526     CFbsBitmap& dstBitmap = iDestination->BitmapModifyable();
       
   527     CFbsBitmap& dstMask = iDestination->MaskModifyable();
       
   528 
       
   529     if( MaskDisplayMode() != ENone && dstMask.Handle() )
       
   530         iDecoder->Convert( &iStatus, dstBitmap, dstMask, aFrameIndex );
       
   531     else {
       
   532         dstMask.Reset();
       
   533         iDecoder->Convert( &iStatus, dstBitmap, aFrameIndex );
       
   534     }
       
   535 }
       
   536 
       
   537 // -----------------------------------------------------------------------------
       
   538 // CAnimationDecoderWrapped::StartLoadAnimationBitmapL
       
   539 // -----------------------------------------------------------------------------
       
   540 void CAnimationDecoderWrapped::StartLoadAnimationBitmapL( TInt aFrameIndex )
       
   541 {
       
   542     __ASSERT_DEBUG( !iAnimationBitmap, Panic( KErrGeneral ) );
       
   543 
       
   544     // Create animation bitmap
       
   545     iAnimationBitmap = CMaskedBitmap::NewL();
       
   546     CFbsBitmap& animBitmap = iAnimationBitmap->BitmapModifyable();
       
   547     CFbsBitmap& animMask = iAnimationBitmap->MaskModifyable();
       
   548 
       
   549     TFrameInfo frameInfo( iDecoder->FrameInfo( aFrameIndex ) );
       
   550     User::LeaveIfError( animBitmap.Create(
       
   551     frameInfo.iOverallSizeInPixels, EColor16M ) );
       
   552 
       
   553     TDisplayMode maskDisplayMode( ENone );
       
   554 
       
   555     if( frameInfo.iFlags & TFrameInfo::ETransparencyPossible ) {
       
   556         if( frameInfo.iFlags & TFrameInfo::EAlphaChannel && (frameInfo.iFlags & TFrameInfo::ECanDither)) 
       
   557             maskDisplayMode = EGray256;
       
   558         maskDisplayMode = EGray2;
       
   559 
       
   560         User::LeaveIfError( animMask.Create( frameInfo.iOverallSizeInPixels, maskDisplayMode ) );
       
   561         iDecoder->Convert( &iStatus, animBitmap, animMask, aFrameIndex );
       
   562     }
       
   563     else
       
   564         iDecoder->Convert( &iStatus, animBitmap, aFrameIndex );
       
   565 }
       
   566 
       
   567 // -----------------------------------------------------------------------------
       
   568 // CAnimationDecoderWrapped::CompleteLoadL
       
   569 // -----------------------------------------------------------------------------
       
   570 void CAnimationDecoderWrapped::CompleteLoadL()
       
   571 {
       
   572     TSize frameSize = iFrameInfo.iOverallSizeInPixels;
       
   573     int sizeinBytes = frameSize.iWidth * frameSize.iHeight * 2;
       
   574     if( iAnimationBitmap ){
       
   575         // Copy animation bitmap to destination
       
   576         BuildAnimationFrameL();
       
   577         delete iAnimationBitmap;
       
   578         iAnimationBitmap = NULL;
       
   579 
       
   580         iDestination->SetFrameIndex( iAnimationFrameIndex );
       
   581         iDestination->SetFrameDelay( AnimationFrameDelay( iAnimationFrameIndex ) );
       
   582 
       
   583         if( iAnimationFrameIndex < iFrameIndex ) {
       
   584             // re-start the active object and load next frame
       
   585             iAnimationFrameIndex++;
       
   586             iImageState = EStartLoad;
       
   587             SelfComplete();
       
   588         }
       
   589         else {
       
   590             // Animation ready
       
   591             iImageState = EInactive;
       
   592             iObserver->animationFrameReady(sizeinBytes);
       
   593         }
       
   594     }
       
   595     else {
       
   596         // Save source info destination
       
   597         iDestination->SetFrameIndex( iFrameIndex );
       
   598         iDestination->SetFrameDelay( 0 );
       
   599         //Compress non-animated images via FBServ (losslessly, idle priority) 
       
   600         iDestination->CompressInBackground();     
       
   601 
       
   602         // Normal image ready
       
   603         //iDestination = NULL;
       
   604         iImageState = EInactive;
       
   605         iObserver->imageReady(sizeinBytes);
       
   606         delete iDecoder, iDecoder = NULL;
       
   607     }
       
   608 }
       
   609 
       
   610 // -----------------------------------------------------------------------------
       
   611 // CAnimationDecoderWrapped::BuildAnimationFrameL
       
   612 // -----------------------------------------------------------------------------
       
   613 void CAnimationDecoderWrapped::BuildAnimationFrameL()
       
   614     {
       
   615     __ASSERT_DEBUG( iAnimationBitmap, Panic( KErrGeneral ) );
       
   616     const CFbsBitmap& animBitmap = iAnimationBitmap->Bitmap();
       
   617     const CFbsBitmap& animMask = iAnimationBitmap->Mask();
       
   618     __ASSERT_DEBUG( animBitmap.Handle(), Panic( KErrGeneral ) );
       
   619 
       
   620 
       
   621     //If the first frame starts from position(0,0), copy directly to the destination bitmap 
       
   622     //otherwise frame has to be appropriately positioned in the destination bitmap  
       
   623     TPoint aStartPoint(0,0);
       
   624     if( (iAnimationFrameIndex==0) && (iFrameInfo.iFrameCoordsInPixels.iTl==aStartPoint) )
       
   625     {
       
   626         // First frame can be directly put into destination
       
   627         User::LeaveIfError( iDestination->Copy( animBitmap, animMask, ETrue ) );
       
   628     }
       
   629     else {
       
   630         CFbsBitmap& prevBitmap = iDestination->BitmapModifyable();
       
   631         CFbsBitmap& prevMask = iDestination->MaskModifyable();
       
   632 
       
   633         // Other frames must be build on top of previous frames
       
   634         __ASSERT_DEBUG( prevBitmap.Handle(), Panic( KErrGeneral ) );
       
   635 
       
   636         // Create bitmap device to destination bitmap
       
   637         CFbsBitGc* bitGc;
       
   638         CFbsBitmapDevice* bitDevice = CFbsBitmapDevice::NewL( &prevBitmap );
       
   639         CleanupStack::PushL( bitDevice );
       
   640         User::LeaveIfError( bitDevice->CreateContext( bitGc ) );
       
   641         CleanupStack::PushL( bitGc );
       
   642 
       
   643         // Restore area in destination bitmap if needed
       
   644         TRect restoreRect;
       
   645         TBool restoreToBackground( EFalse );
       
   646         
       
   647         TInt aFrameNo = (iAnimationFrameIndex >= 1)?(iAnimationFrameIndex):1;
       
   648         TFrameInfo prevFrameInfo(iDecoder->FrameInfo(aFrameNo - 1));
       
   649         
       
   650         //TFrameInfo prevFrameInfo( iDecoder->FrameInfo( iAnimationFrameIndex - 1 ) );
       
   651         
       
   652         if( (prevFrameInfo.iFlags & TFrameInfo::ERestoreToBackground )|| (iAnimationFrameIndex ==0)) 
       
   653         {
       
   654             restoreToBackground = ETrue;
       
   655             restoreRect = prevFrameInfo.iFrameCoordsInPixels;
       
   656             bitGc->SetPenColor( prevFrameInfo.iBackgroundColor );
       
   657             bitGc->SetBrushColor( prevFrameInfo.iBackgroundColor );
       
   658             bitGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
       
   659             if(iAnimationFrameIndex ==0){
       
   660               bitGc->Clear();     
       
   661             }
       
   662             else{
       
   663                bitGc->DrawRect( restoreRect );  
       
   664             }
       
   665             bitGc->SetBrushStyle( CGraphicsContext::ENullBrush );
       
   666          }
       
   667         // Copy animation frame to destination bitmap
       
   668         TFrameInfo frameInfo( iDecoder->FrameInfo( iAnimationFrameIndex) );
       
   669         if( animMask.Handle() ) {
       
   670             bitGc->BitBltMasked( frameInfo.iFrameCoordsInPixels.iTl, &animBitmap,
       
   671             animBitmap.SizeInPixels(), &animMask, EFalse );
       
   672         }
       
   673         else {
       
   674             bitGc->BitBlt( frameInfo.iFrameCoordsInPixels.iTl, &animBitmap,
       
   675             animBitmap.SizeInPixels() );
       
   676         }
       
   677         CleanupStack::PopAndDestroy( 2 ); // bitmapCtx, bitmapDev
       
   678 
       
   679         // Combine masks if any
       
   680         if( prevMask.Handle() && animMask.Handle() ) {
       
   681             bitDevice = CFbsBitmapDevice::NewL( &prevMask );
       
   682             CleanupStack::PushL( bitDevice );
       
   683             User::LeaveIfError( bitDevice->CreateContext( bitGc ) );
       
   684             CleanupStack::PushL( bitGc );
       
   685 
       
   686             if( restoreToBackground ) {
       
   687                 bitGc->SetBrushColor( KRgbBlack );
       
   688                 bitGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
       
   689                 if(iAnimationFrameIndex ==0){
       
   690                    bitGc->Clear();    
       
   691                  }
       
   692                  else{
       
   693                    bitGc->DrawRect( restoreRect );  
       
   694                  }
       
   695                 bitGc->SetBrushStyle( CGraphicsContext::ENullBrush );
       
   696             }
       
   697             CFbsBitmap* tmpMask = new(ELeave) CFbsBitmap;
       
   698             CleanupStack::PushL( tmpMask );
       
   699             User::LeaveIfError( tmpMask->Create( prevMask.SizeInPixels(), prevMask.DisplayMode() ) );
       
   700             CFbsBitmapDevice* tmpMaskDev = CFbsBitmapDevice::NewL( tmpMask );
       
   701             CleanupStack::PushL( tmpMaskDev );
       
   702             CFbsBitGc* tmpMaskGc;
       
   703             User::LeaveIfError( tmpMaskDev->CreateContext( tmpMaskGc ) );
       
   704             CleanupStack::PushL( tmpMaskGc );
       
   705 
       
   706             tmpMaskGc->BitBlt( TPoint( 0, 0 ), &prevMask, frameInfo.iFrameCoordsInPixels );
       
   707 
       
   708             bitGc->BitBltMasked( frameInfo.iFrameCoordsInPixels.iTl, &animMask,
       
   709             animMask.SizeInPixels(), tmpMask, ETrue );
       
   710 
       
   711             CleanupStack::PopAndDestroy( 5 ); //tmpMask, tmpMaskDev, tmpMaskGc, bitGc, bitDevice
       
   712         }
       
   713     else
       
   714         prevMask.Reset(); // Mask not valid anymore -> reset
       
   715     }
       
   716 }
       
   717 
       
   718 // -----------------------------------------------------------------------------
       
   719 // CAnimationDecoderWrapped::ErrorCleanup
       
   720 // -----------------------------------------------------------------------------
       
   721 void CAnimationDecoderWrapped::ErrorCleanup()
       
   722 {
       
   723     if( iAnimationBitmap ) {
       
   724         delete iAnimationBitmap;
       
   725         iAnimationBitmap = NULL;
       
   726     }
       
   727 
       
   728     if( iDestination ) {
       
   729         delete iDestination;
       
   730         iDestination = NULL;
       
   731     }
       
   732 }
       
   733 
       
   734 // -----------------------------------------------------------------------------
       
   735 // CAnimationDecoderWrapped::SelfComplete
       
   736 // -----------------------------------------------------------------------------
       
   737 void CAnimationDecoderWrapped::SelfComplete( TInt aError )
       
   738 {
       
   739     SetActive();
       
   740     iStatus = KRequestPending;
       
   741     TRequestStatus* status = &iStatus;
       
   742     User::RequestComplete( status, aError );
       
   743 }
       
   744 
       
   745 
       
   746 
       
   747 //  End of File