webengine/osswebengine/WebCore/platform/symbian/bitmap/StaticImageDecoder.cpp
changeset 0 dd21522fd290
child 26 cb62a4f66ebe
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2 * Copyright (c) 2006-2008 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 #include "StaticImageDecoder.h"
       
    20 #include "MaskedBitmap.h"
       
    21 #include <imageconversion.h>
       
    22 #include <eikenv.h>
       
    23 #include <fbs.h>
       
    24 #include <oom.h>
       
    25 
       
    26 // CONSTANTS
       
    27 // block all images that would take free ram below this amount when decoded
       
    28 const TInt KFreeRamBitmapBlockLimit = 1536 * 1024;
       
    29 // do the following additional checks if image would take free ram below this amount
       
    30 const TInt KFreeRamBitmapCheckLimit = 7 * 1024 * 1024;
       
    31 // if bitmap size is times this much bigger than data size then it is a high expansion bitmap
       
    32 const TInt KHighExpansionBitmapFactor = 16;
       
    33 // block high expansion bitmap above this size (they are usually backgrounds and so less important)
       
    34 const TInt KLargeHighExpansionBitmapSize = 800*600*2;
       
    35 // block all images that would take more than this percentage of available free ram
       
    36 const TInt KMaxBitmapRamPercent = 25;
       
    37 
       
    38 //=============================================================================
       
    39 // CRawData
       
    40 //=============================================================================
       
    41 CRawData* CRawData::NewL( const TDesC8& aData, TDesC* aMime, CMaskedBitmap* aTarget, MAnimationDecoderObserver* aObserv )
       
    42     {
       
    43     CRawData* self = new (ELeave) CRawData();
       
    44     CleanupStack::PushL( self );
       
    45     self->ConstructL( aData, aMime, aTarget, aObserv );
       
    46     CleanupStack::Pop();
       
    47     return self;
       
    48     }
       
    49 
       
    50 void CRawData::ConstructL( const TDesC8& aData, TDesC* aMIMEType, CMaskedBitmap* aTarget, MAnimationDecoderObserver* aObserv )
       
    51     {
       
    52     // mime type
       
    53     if (aMIMEType)
       
    54         {
       
    55         // it is safer to ignore the server supplied mime type and just recognize
       
    56         // the image type from the data headers. this does not work for all formats though
       
    57         if ( *aMIMEType==KMimeWBMP || *aMIMEType==KMimeOTA || *aMIMEType==KMimeWMF)
       
    58             {
       
    59             // convert to 8 bit
       
    60             iMime = HBufC8::NewL(aMIMEType->Length());
       
    61             iMime->des().Copy(*aMIMEType);
       
    62             }
       
    63         }
       
    64 
       
    65     // data
       
    66     const TUint8* src = aData.Ptr();
       
    67     iData = MemoryManager::Alloc( aData.Length() );
       
    68     Mem::Copy( iData, src, aData.Length() );
       
    69     iDataPtr.Set((TUint8*)iData, aData.Length(), aData.Length() );
       
    70     iObserver = aObserv;
       
    71     iTarget = aTarget;
       
    72     }
       
    73 
       
    74 CRawData::~CRawData()
       
    75     {
       
    76     MemoryManager::Free( iData );
       
    77     delete iMime;
       
    78     }
       
    79 
       
    80 //=============================================================================
       
    81 // CStaticImageDecoder
       
    82 //=============================================================================
       
    83 CStaticImageDecoder::CStaticImageDecoder() : CActive(CActive::EPriorityStandard)
       
    84     {
       
    85     CActiveScheduler::Add( this );
       
    86     }
       
    87 
       
    88 CStaticImageDecoder* CStaticImageDecoder::NewL()
       
    89     {
       
    90     CStaticImageDecoder* self = new (ELeave) CStaticImageDecoder();
       
    91     CleanupStack::PushL( self );
       
    92     self->ConstructL();
       
    93     CleanupStack::Pop();
       
    94     return self;
       
    95     }
       
    96 
       
    97 CStaticImageDecoder::~CStaticImageDecoder()
       
    98     {
       
    99 
       
   100     iQueue.Reset();
       
   101     delete iDecoder;
       
   102     iContext = 0;
       
   103 
       
   104     if (IsActive())
       
   105         {
       
   106         Cancel();
       
   107         }
       
   108     }
       
   109 
       
   110 void CStaticImageDecoder::ConstructL()
       
   111     {
       
   112     iDecoder = CBufferedImageDecoder::NewL(CEikonEnv::Static()->FsSession());
       
   113     }
       
   114 
       
   115 TBool CStaticImageDecoder::LoadNextImage()
       
   116     {
       
   117   if( iQueue.Count() == 0 ) return EFalse;
       
   118 
       
   119     // load the data, FIFO
       
   120     CRawData* data = iQueue[0];
       
   121 
       
   122   TRAP_IGNORE(
       
   123         if( data->iMime )
       
   124             iDecoder->OpenL( data->iDataPtr, *(data->iMime), CImageDecoder::EOptionNone );
       
   125         else
       
   126             iDecoder->OpenL( data->iDataPtr, CImageDecoder::EOptionNone );
       
   127     )
       
   128 
       
   129     // set the context
       
   130   if(iDecoder->ValidDecoder()  && iDecoder->IsImageHeaderProcessingComplete())
       
   131     {
       
   132     if( iDecoder->FrameCount() == 1 )
       
   133       {
       
   134             iContext = data;
       
   135             TFrameInfo frmInfo = iDecoder->FrameInfo( 0 );
       
   136 
       
   137             // check memory before creating bitmaps
       
   138             if( CheckBitmapMemoryConsumption( frmInfo ) )
       
   139                 {
       
   140                 if (frmInfo.iFlags & TFrameInfo::ETransparencyPossible)
       
   141                     {
       
   142                     TDisplayMode mskMode = (frmInfo.iFlags & TFrameInfo::EAlphaChannel) ? EGray256 : EGray2;
       
   143                     iContext->iTarget->Create( frmInfo.iOverallSizeInPixels, GetBestDisplayMode(frmInfo.iFrameDisplayMode), mskMode );
       
   144                     }
       
   145                 else
       
   146                     {
       
   147                     iContext->iTarget->Create( frmInfo.iOverallSizeInPixels, GetBestDisplayMode(frmInfo.iFrameDisplayMode) );
       
   148                     }
       
   149 
       
   150           LoadOneFrame();
       
   151                 return ETrue;
       
   152                 }
       
   153       }
       
   154     else
       
   155       {
       
   156       // animated images need a dedicated decoder
       
   157             data->iObserver->StartAnimationDecoder();
       
   158 
       
   159       iQueue.Remove( 0 );
       
   160       Reset();
       
   161 
       
   162       StartLoading();
       
   163             return ETrue;
       
   164       }
       
   165     }
       
   166 
       
   167     // something must be wrong with the current image
       
   168     data->iObserver->decoderError( -1 );
       
   169     iQueue.Remove(0);
       
   170 
       
   171     // decode next image
       
   172     Reset();
       
   173     StartLoading();
       
   174 
       
   175     return ETrue;
       
   176     }
       
   177 
       
   178 void CStaticImageDecoder::LoadOneFrame()
       
   179     {
       
   180     // static image has only one frame;
       
   181     const TFrameInfo& frameInfo = iDecoder->FrameInfo( 0 );
       
   182     CFbsBitmap& bmp = iContext->iTarget->BitmapModifyable();
       
   183     if ( frameInfo.iFlags & TFrameInfo::ETransparencyPossible )
       
   184         {
       
   185         CFbsBitmap& msk = iContext->iTarget->MaskModifyable();
       
   186         iDecoder->Convert( &iStatus, bmp, msk, 0 );
       
   187         }
       
   188     else
       
   189         {
       
   190         iDecoder->Convert( &iStatus, bmp, 0 );
       
   191         }
       
   192 
       
   193     // the first frame, partial information is available
       
   194     iContext->iObserver->PartialImage();
       
   195 
       
   196     SetActive();
       
   197     iState = EOneFrameReady;
       
   198     }
       
   199 
       
   200 TBool CStaticImageDecoder::DecodeL( CRawData* aData )
       
   201     {
       
   202     // queue the data, FIFO
       
   203     iQueue.AppendL( aData );
       
   204     StartLoading();
       
   205     return ETrue;
       
   206     }
       
   207 
       
   208 void CStaticImageDecoder::StartLoading()
       
   209     {
       
   210     if( !IsActive() )
       
   211         {
       
   212         // initalize decoding
       
   213       TRequestStatus* status = &iStatus;
       
   214         User::RequestComplete( status, 0 );
       
   215         SetActive();
       
   216         iState = EStartLoading;
       
   217         }
       
   218     }
       
   219 
       
   220 void CStaticImageDecoder::RunL()
       
   221     {
       
   222     if( iState == EStartLoading )
       
   223         {
       
   224         LoadNextImage();
       
   225         }
       
   226     else if( iState == EOneFrameReady )
       
   227         {
       
   228         if( iStatus.Int() != KErrNone )
       
   229             {
       
   230             iContext->iObserver->decoderError( iStatus.Int() );
       
   231 
       
   232             iQueue.Remove(0);
       
   233 
       
   234             // decode next image
       
   235             Reset();
       
   236             if( iQueue.Count() > 0 ) LoadNextImage();
       
   237             }
       
   238         else
       
   239             {
       
   240             // pass bitmap's ownership to the observer
       
   241             iContext->iObserver->ImageReady();
       
   242 
       
   243             iQueue.Remove(0);
       
   244 
       
   245             // decode next image
       
   246             Reset();
       
   247             if( iQueue.Count() > 0 ) LoadNextImage();
       
   248             }
       
   249         }
       
   250     }
       
   251 
       
   252 void CStaticImageDecoder::DoCancel()
       
   253     {
       
   254     // TODO: maybe we should delete all the intermediate data?
       
   255     }
       
   256 
       
   257 void CStaticImageDecoder::Reset()
       
   258     {
       
   259     // decoder reset
       
   260     iDecoder->Cancel();
       
   261     iDecoder->Reset();
       
   262     iState = EIdle;
       
   263 
       
   264     // context reset
       
   265     iContext = 0;
       
   266     }
       
   267 
       
   268 void CStaticImageDecoder::StopObserving( MAnimationDecoderObserver* aObserv )
       
   269     {
       
   270     // fast check
       
   271     if( iQueue.Count() == 0 ) return;
       
   272 
       
   273     // is the image currently being decoded?
       
   274     if( iContext && iContext->iObserver == aObserv )
       
   275         {
       
   276         // stop decoding
       
   277         if( IsActive() ) Cancel();
       
   278         }
       
   279 
       
   280     // remove image data from the queue
       
   281     TInt idx = KErrNotFound;
       
   282     for( TInt i=0; i<iQueue.Count(); ++i )
       
   283         if( iQueue[i]->iObserver == aObserv )
       
   284             idx = i;
       
   285     if( idx == KErrNotFound ) return;
       
   286 
       
   287     CRawData* data = iQueue[idx];
       
   288     iQueue.Remove( idx );
       
   289 
       
   290     // decode next image
       
   291     Reset();
       
   292     if( iQueue.Count() > 0 ) StartLoading();
       
   293     }
       
   294 
       
   295 TDisplayMode CStaticImageDecoder::GetBestDisplayMode( TDisplayMode /*aMode*/ ) const
       
   296     {
       
   297     return EColor64K;
       
   298     }
       
   299 
       
   300 TBool CStaticImageDecoder::CheckBitmapMemoryConsumption( const TFrameInfo& aFrameInfo ) const
       
   301     {
       
   302     TMemoryInfoV1Buf info;
       
   303     UserHal::MemoryInfo( info );
       
   304     TInt freeRamInBytes = 10*1024*1024;
       
   305     TInt dataSize = iContext->iDataPtr.Length();
       
   306     if( UserHal::MemoryInfo( info ) == KErrNone )
       
   307         freeRamInBytes = info().iFreeRamInBytes;
       
   308     TInt bitmapBytes = aFrameInfo.iOverallSizeInPixels.iWidth*aFrameInfo.iOverallSizeInPixels.iHeight*2;
       
   309     TInt freeRamAfterLoad = freeRamInBytes-bitmapBytes;
       
   310     if (freeRamAfterLoad < KFreeRamBitmapBlockLimit)
       
   311         {
       
   312         // block image decoding when we are below block limit
       
   313         return EFalse;
       
   314         }
       
   315     if (freeRamAfterLoad < KFreeRamBitmapCheckLimit)
       
   316         {
       
   317         // low on memory, do additional checks
       
   318         if (dataSize*KHighExpansionBitmapFactor < bitmapBytes && bitmapBytes>KLargeHighExpansionBitmapSize )
       
   319             {
       
   320             // bitmaps with high expansion factor are commonly used as background image etc. and are of less importance
       
   321             // block large ones
       
   322             return EFalse;
       
   323             }
       
   324         if (freeRamInBytes*KMaxBitmapRamPercent/100 < bitmapBytes)
       
   325             {
       
   326             // block all bitmaps that would consume more than this percent of available memory
       
   327             return EFalse;
       
   328             }
       
   329         }
       
   330     return ETrue;
       
   331     }
       
   332 
       
   333 // END OF FILE