webengine/osswebengine/WebCore/platform/symbian/bitmap/StaticImageDecoder.cpp
changeset 0 dd21522fd290
child 26 cb62a4f66ebe
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/platform/symbian/bitmap/StaticImageDecoder.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,333 @@
+/*
+* Copyright (c) 2006-2008 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:  
+*
+*/
+
+
+#include "StaticImageDecoder.h"
+#include "MaskedBitmap.h"
+#include <imageconversion.h>
+#include <eikenv.h>
+#include <fbs.h>
+#include <oom.h>
+
+// CONSTANTS
+// block all images that would take free ram below this amount when decoded
+const TInt KFreeRamBitmapBlockLimit = 1536 * 1024;
+// do the following additional checks if image would take free ram below this amount
+const TInt KFreeRamBitmapCheckLimit = 7 * 1024 * 1024;
+// if bitmap size is times this much bigger than data size then it is a high expansion bitmap
+const TInt KHighExpansionBitmapFactor = 16;
+// block high expansion bitmap above this size (they are usually backgrounds and so less important)
+const TInt KLargeHighExpansionBitmapSize = 800*600*2;
+// block all images that would take more than this percentage of available free ram
+const TInt KMaxBitmapRamPercent = 25;
+
+//=============================================================================
+// CRawData
+//=============================================================================
+CRawData* CRawData::NewL( const TDesC8& aData, TDesC* aMime, CMaskedBitmap* aTarget, MAnimationDecoderObserver* aObserv )
+    {
+    CRawData* self = new (ELeave) CRawData();
+    CleanupStack::PushL( self );
+    self->ConstructL( aData, aMime, aTarget, aObserv );
+    CleanupStack::Pop();
+    return self;
+    }
+
+void CRawData::ConstructL( const TDesC8& aData, TDesC* aMIMEType, CMaskedBitmap* aTarget, MAnimationDecoderObserver* aObserv )
+    {
+    // mime type
+    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
+            iMime = HBufC8::NewL(aMIMEType->Length());
+            iMime->des().Copy(*aMIMEType);
+            }
+        }
+
+    // data
+    const TUint8* src = aData.Ptr();
+    iData = MemoryManager::Alloc( aData.Length() );
+    Mem::Copy( iData, src, aData.Length() );
+    iDataPtr.Set((TUint8*)iData, aData.Length(), aData.Length() );
+    iObserver = aObserv;
+    iTarget = aTarget;
+    }
+
+CRawData::~CRawData()
+    {
+    MemoryManager::Free( iData );
+    delete iMime;
+    }
+
+//=============================================================================
+// CStaticImageDecoder
+//=============================================================================
+CStaticImageDecoder::CStaticImageDecoder() : CActive(CActive::EPriorityStandard)
+    {
+    CActiveScheduler::Add( this );
+    }
+
+CStaticImageDecoder* CStaticImageDecoder::NewL()
+    {
+    CStaticImageDecoder* self = new (ELeave) CStaticImageDecoder();
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+CStaticImageDecoder::~CStaticImageDecoder()
+    {
+
+    iQueue.Reset();
+    delete iDecoder;
+    iContext = 0;
+
+    if (IsActive())
+        {
+        Cancel();
+        }
+    }
+
+void CStaticImageDecoder::ConstructL()
+    {
+    iDecoder = CBufferedImageDecoder::NewL(CEikonEnv::Static()->FsSession());
+    }
+
+TBool CStaticImageDecoder::LoadNextImage()
+    {
+  if( iQueue.Count() == 0 ) return EFalse;
+
+    // load the data, FIFO
+    CRawData* data = iQueue[0];
+
+  TRAP_IGNORE(
+        if( data->iMime )
+            iDecoder->OpenL( data->iDataPtr, *(data->iMime), CImageDecoder::EOptionNone );
+        else
+            iDecoder->OpenL( data->iDataPtr, CImageDecoder::EOptionNone );
+    )
+
+    // set the context
+  if(iDecoder->ValidDecoder()  && iDecoder->IsImageHeaderProcessingComplete())
+    {
+    if( iDecoder->FrameCount() == 1 )
+      {
+            iContext = data;
+            TFrameInfo frmInfo = iDecoder->FrameInfo( 0 );
+
+            // check memory before creating bitmaps
+            if( CheckBitmapMemoryConsumption( frmInfo ) )
+                {
+                if (frmInfo.iFlags & TFrameInfo::ETransparencyPossible)
+                    {
+                    TDisplayMode mskMode = (frmInfo.iFlags & TFrameInfo::EAlphaChannel) ? EGray256 : EGray2;
+                    iContext->iTarget->Create( frmInfo.iOverallSizeInPixels, GetBestDisplayMode(frmInfo.iFrameDisplayMode), mskMode );
+                    }
+                else
+                    {
+                    iContext->iTarget->Create( frmInfo.iOverallSizeInPixels, GetBestDisplayMode(frmInfo.iFrameDisplayMode) );
+                    }
+
+          LoadOneFrame();
+                return ETrue;
+                }
+      }
+    else
+      {
+      // animated images need a dedicated decoder
+            data->iObserver->StartAnimationDecoder();
+
+      iQueue.Remove( 0 );
+      Reset();
+
+      StartLoading();
+            return ETrue;
+      }
+    }
+
+    // something must be wrong with the current image
+    data->iObserver->decoderError( -1 );
+    iQueue.Remove(0);
+
+    // decode next image
+    Reset();
+    StartLoading();
+
+    return ETrue;
+    }
+
+void CStaticImageDecoder::LoadOneFrame()
+    {
+    // static image has only one frame;
+    const TFrameInfo& frameInfo = iDecoder->FrameInfo( 0 );
+    CFbsBitmap& bmp = iContext->iTarget->BitmapModifyable();
+    if ( frameInfo.iFlags & TFrameInfo::ETransparencyPossible )
+        {
+        CFbsBitmap& msk = iContext->iTarget->MaskModifyable();
+        iDecoder->Convert( &iStatus, bmp, msk, 0 );
+        }
+    else
+        {
+        iDecoder->Convert( &iStatus, bmp, 0 );
+        }
+
+    // the first frame, partial information is available
+    iContext->iObserver->PartialImage();
+
+    SetActive();
+    iState = EOneFrameReady;
+    }
+
+TBool CStaticImageDecoder::DecodeL( CRawData* aData )
+    {
+    // queue the data, FIFO
+    iQueue.AppendL( aData );
+    StartLoading();
+    return ETrue;
+    }
+
+void CStaticImageDecoder::StartLoading()
+    {
+    if( !IsActive() )
+        {
+        // initalize decoding
+      TRequestStatus* status = &iStatus;
+        User::RequestComplete( status, 0 );
+        SetActive();
+        iState = EStartLoading;
+        }
+    }
+
+void CStaticImageDecoder::RunL()
+    {
+    if( iState == EStartLoading )
+        {
+        LoadNextImage();
+        }
+    else if( iState == EOneFrameReady )
+        {
+        if( iStatus.Int() != KErrNone )
+            {
+            iContext->iObserver->decoderError( iStatus.Int() );
+
+            iQueue.Remove(0);
+
+            // decode next image
+            Reset();
+            if( iQueue.Count() > 0 ) LoadNextImage();
+            }
+        else
+            {
+            // pass bitmap's ownership to the observer
+            iContext->iObserver->ImageReady();
+
+            iQueue.Remove(0);
+
+            // decode next image
+            Reset();
+            if( iQueue.Count() > 0 ) LoadNextImage();
+            }
+        }
+    }
+
+void CStaticImageDecoder::DoCancel()
+    {
+    // TODO: maybe we should delete all the intermediate data?
+    }
+
+void CStaticImageDecoder::Reset()
+    {
+    // decoder reset
+    iDecoder->Cancel();
+    iDecoder->Reset();
+    iState = EIdle;
+
+    // context reset
+    iContext = 0;
+    }
+
+void CStaticImageDecoder::StopObserving( MAnimationDecoderObserver* aObserv )
+    {
+    // fast check
+    if( iQueue.Count() == 0 ) return;
+
+    // is the image currently being decoded?
+    if( iContext && iContext->iObserver == aObserv )
+        {
+        // stop decoding
+        if( IsActive() ) Cancel();
+        }
+
+    // remove image data from the queue
+    TInt idx = KErrNotFound;
+    for( TInt i=0; i<iQueue.Count(); ++i )
+        if( iQueue[i]->iObserver == aObserv )
+            idx = i;
+    if( idx == KErrNotFound ) return;
+
+    CRawData* data = iQueue[idx];
+    iQueue.Remove( idx );
+
+    // decode next image
+    Reset();
+    if( iQueue.Count() > 0 ) StartLoading();
+    }
+
+TDisplayMode CStaticImageDecoder::GetBestDisplayMode( TDisplayMode /*aMode*/ ) const
+    {
+    return EColor64K;
+    }
+
+TBool CStaticImageDecoder::CheckBitmapMemoryConsumption( const TFrameInfo& aFrameInfo ) const
+    {
+    TMemoryInfoV1Buf info;
+    UserHal::MemoryInfo( info );
+    TInt freeRamInBytes = 10*1024*1024;
+    TInt dataSize = iContext->iDataPtr.Length();
+    if( UserHal::MemoryInfo( info ) == KErrNone )
+        freeRamInBytes = info().iFreeRamInBytes;
+    TInt bitmapBytes = aFrameInfo.iOverallSizeInPixels.iWidth*aFrameInfo.iOverallSizeInPixels.iHeight*2;
+    TInt freeRamAfterLoad = freeRamInBytes-bitmapBytes;
+    if (freeRamAfterLoad < KFreeRamBitmapBlockLimit)
+        {
+        // block image decoding when we are below block limit
+        return EFalse;
+        }
+    if (freeRamAfterLoad < KFreeRamBitmapCheckLimit)
+        {
+        // low on memory, do additional checks
+        if (dataSize*KHighExpansionBitmapFactor < bitmapBytes && bitmapBytes>KLargeHighExpansionBitmapSize )
+            {
+            // bitmaps with high expansion factor are commonly used as background image etc. and are of less importance
+            // block large ones
+            return EFalse;
+            }
+        if (freeRamInBytes*KMaxBitmapRamPercent/100 < bitmapBytes)
+            {
+            // block all bitmaps that would consume more than this percent of available memory
+            return EFalse;
+            }
+        }
+    return ETrue;
+    }
+
+// END OF FILE