uiacceltk/hitchcock/coretoolkit/src/huitextureanimationstate.cpp
changeset 0 15bf7259bb7c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uiacceltk/hitchcock/coretoolkit/src/huitextureanimationstate.cpp	Tue Feb 02 07:56:43 2010 +0200
@@ -0,0 +1,1043 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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:   Implementation of CHuiTextureAnimationState.
+*
+*/
+
+
+
+#include <e32base.h>
+#include <fbs.h>
+#include <bitstd.h>
+#include <uiacceltk/HuiUtil.h>
+#include "huitextureanimationstate.h"
+
+/**
+ * Modifiable bitmap helper class for CHuiTextureAnimationState.
+ */
+NONSHARABLE_CLASS( CHuiModifiableBitmap ) : public CBase
+    {
+public:
+    /**
+     * Two-phased constructor. This creates new bitmap, 
+     * this instance owns it until @c ReleaseBitmap is called.
+     * @param aSize size of bitmap.
+     * @param aMode display mode of bitmap.
+     */
+    static CHuiModifiableBitmap* NewLC( const TSize& aSize, TDisplayMode aMode );
+    
+    /**
+     * Two-phased constructor. Use another bitmap and ownership
+     * is not taken.
+     * @param aBitmap bitmap to be modified.
+     */
+    static CHuiModifiableBitmap* NewLC( CFbsBitmap& aBitmap );
+    
+    /**
+     * Destructor.
+     */
+    ~CHuiModifiableBitmap();
+
+    /**
+     * Returns graphics context. Ownership is not passed.
+     * @return graphics context.
+     */
+    CFbsBitGc& Context();    
+    
+    /**
+     * Releases bitmap and passes ownership to caller.
+     * After this has been called, bitmap operations should not
+     * be performed through this class.
+     * @return bitmap.
+     */
+    CFbsBitmap* ReleaseBitmap();
+    
+    /**
+     * Clears the whole bitmap with specified color.
+     * @param aColor color to use.
+     */
+    void Clear( const TRgb& aColor );
+    
+    /**
+     * Clears area of bitmap with specified color.
+     * @param aRect area to fill.
+     * @param aColor color to use.
+     */
+    void Clear( const TRect& aRect, const TRgb& aColor );
+        
+    /**
+     * Copies area from another bitmap to this one.
+     * @param aRect area to copy.
+     * @param aBitmap source bitmap.
+     */
+    void BitBlt( const TRect& aRect, CHuiModifiableBitmap& aBitmap );
+    
+    /**
+     * Combines source and mask bitmap to this 16MA bitmap.
+     * @param aSrc bitmap.
+     * @param aSrcMask mask bitmap.
+     */
+    void Combine( const CFbsBitmap& aSrc, const CFbsBitmap& aSrcMask );
+    
+    /**
+     * Combines source and mask bitmap to this 16MA bitmap.
+     * @para aPos position of bitmap.
+     * @param aSrc bitmap.
+     * @param aSrcMask mask bitmap.
+     */
+    void Combine( const TPoint& aPos, const CFbsBitmap& aSrc, const CFbsBitmap& aSrcMask );
+    
+    /**
+     * Combines gray 256 mask to this gray 256 bitmap. 
+     * It's expected that aMask contains only 0 or 255 values.
+     * @param aRect rect to combine.
+     * @param aMask gray 256 bitmap.
+     */
+    void CombineMasks( const TRect& aRect, CFbsBitmap* aMask );
+    
+    /**
+     * Extracts alpha from 16MA source to this EGray256 bitmap.
+     * @param aSource source bitmap.
+     */
+    void ExtractAlpha( CHuiModifiableBitmap& aSource );
+    
+    /**
+     * Extracts color from 16MA source to this EColor64K/EColor16MU bitmap.
+     * @param aSource source bitmap.
+     */
+    void ExtractColor( CHuiModifiableBitmap& aSource );
+        
+private:
+    void ConstructL( const TSize& aSize, TDisplayMode aMode );
+    void ConstructL( CFbsBitmap& aBitmap );
+
+    template<class Converter>
+    static void DoExtractColor( CFbsBitmap* aTarget, CFbsBitmap* aSource );
+    
+    struct Convert16MA_16MU
+        {    
+        inline static TUint32 Convert( TUint32 aPixel );
+        };
+    struct Convert16MA_64K
+        {
+        inline static TUint32 Convert( TUint32 aPixel );
+        };
+    
+private:
+    /**
+     * Boolean value indicating if iBitmap is owned by this class.
+     */
+    TBool iOwnBitmap;
+    /**
+     * Bitmap instance. Ownership depends on value of iOwnBitmap.
+     */
+    CFbsBitmap* iBitmap;
+    /**
+     * Bitmap device.
+     * Own.
+     */
+    CFbsBitmapDevice* iDevice;
+    /**
+     * Graphics context.
+     * Own.
+     */
+    CFbsBitGc* iGc;
+    };
+
+CHuiTextureAnimationState* CHuiTextureAnimationState::NewL(
+        TInt aTextureGroupId, const TDesC& aImageFile, TInt aFrameCount )
+    {
+    CHuiTextureAnimationState* self = new (ELeave) CHuiTextureAnimationState;
+    CleanupStack::PushL( self );
+    self->ConstructL( aTextureGroupId, aImageFile, aFrameCount );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+CHuiTextureAnimationState::~CHuiTextureAnimationState()
+    {
+    HUI_DEBUG1(_L("CHuiTextureAnimationState(%x): Destroyed"), this );
+    delete iFile;
+    
+    delete iPrevFrame;
+    delete iPrevFrameMask;
+    }
+
+TInt CHuiTextureAnimationState::OwnerTextureGroupId() const
+    {
+    return iTextureGroupId;
+    }
+    
+TBool CHuiTextureAnimationState::CheckIfCanProduce( 
+        const TDesC& aImageFile, TInt aFrameNumber, TInt aFrameCount ) const
+    {
+    aFrameNumber--;
+    
+    TBool ok = ( aFrameCount == iFrameCount ) && 
+               ( iFrame <= aFrameNumber ) &&
+               !aImageFile.CompareF( *iFile );
+               
+    return ok; 
+    }
+
+TInt CHuiTextureAnimationState::GetNextFrameNumber() const
+    {
+    return ( iFrame + 1 );
+    }
+
+void CHuiTextureAnimationState::OfferNextFrameInfo( 
+        const TFrameInfo& aFrameInfo )
+    {
+    if ( iFrame == KErrNotFound )
+        {
+        // First frame defines size of all frames; subsequent frames
+        // are deltas to first frame.
+        iSize = aFrameInfo.iOverallSizeInPixels;
+        }
+        
+    iNextSubFrameRect = aFrameInfo.iFrameCoordsInPixels;
+    iNextSubFrameBgColor = aFrameInfo.iBackgroundColor;
+    
+    if ( aFrameInfo.iFlags & TFrameInfo::ERestoreToPrevious )
+        {
+        iNextSubFrameDisposalAction = ERestoreToPrevious;
+        }
+    else if ( aFrameInfo.iFlags & TFrameInfo::ELeaveInPlace )
+        {
+        // The variable name "'ELeave'InPlace" will cause FALSE positive in CodeScanners "Leave scan"
+        iNextSubFrameDisposalAction = ELeaveInPlace;
+        }
+    else if ( aFrameInfo.iFlags & TFrameInfo::ERestoreToBackground )
+        {
+        iNextSubFrameDisposalAction = ERestoreToBackgroundColour;
+        }
+    else
+        {
+        iNextSubFrameDisposalAction = EUnspecified;
+        }
+        
+    // If EAlphaChannel flag is on, EGray256 style alpha is available.
+    // If ETransparencyPossible flag is on, just EGray2.
+    iNextSubFrameHasAlpha = aFrameInfo.iFlags & TFrameInfo::EAlphaChannel;
+    }
+
+TSize CHuiTextureAnimationState::OverallSize() const
+    {
+    return iSize;
+    }
+
+void CHuiTextureAnimationState::ProduceNextFrameL(
+        CFbsBitmap*& aNewFrame,
+        CFbsBitmap*& aNewFrameMask,
+        CFbsBitmap* aSubFrame,
+        CFbsBitmap* aSubFrameMask )
+    {
+    HUI_DEBUG2(_L("CHuiTextureAnimationState(%x): Produce next %d"), 
+        this, iFrame + 1 );
+    HUI_DEBUG4(_L("CHuiTextureAnimationState(%x): pf:%x pfm:%x d:%d"), 
+        this, iPrevFrame, iPrevFrameMask, iNextSubFrameDisposalAction );
+    aNewFrame = NULL;
+    aNewFrameMask = NULL;
+    CheckSubFrameL( aSubFrame, aSubFrameMask );
+    
+    if ( iFrame == KErrNotFound )
+        {
+        // Check if previous frames can be reused.
+        const TSize frameSize = OverallSize();
+        if ( iPrevFrame )
+            {
+            if ( iPrevFrame->SizeInPixels() != frameSize ||
+                 iPrevFrame->DisplayMode() != aSubFrame->DisplayMode() )
+                {
+                delete iPrevFrame;
+                iPrevFrame = NULL;
+                }
+            }
+        if ( iPrevFrameMask && aSubFrameMask )
+            {
+            if ( iPrevFrameMask->SizeInPixels() != frameSize ||
+                 iPrevFrameMask->DisplayMode() != aSubFrameMask->DisplayMode() )
+                {
+                delete iPrevFrameMask;
+                iPrevFrameMask = NULL;
+                }
+            }
+        else
+            {
+            delete iPrevFrameMask;
+            iPrevFrameMask = NULL;
+            }
+
+        if ( !iNextSubFrameHasAlpha || !aSubFrameMask )
+            {
+            HUI_DEBUG1(_L("CHuiTextureAnimationState(%x): Quick 1st"), this );
+            QuickProduceFirstFrameAndGeneratePreviousL( 
+                aNewFrame, aNewFrameMask, 
+                aSubFrame, aSubFrameMask );
+            }
+        else
+            {           
+            HUI_DEBUG1(_L("CHuiTextureAnimationState(%x): Slow 1st"), this );
+            ProduceFirstFrameAndGeneratePreviousL( 
+                aNewFrame, aNewFrameMask, 
+                aSubFrame, aSubFrameMask );
+            }
+            
+        if ( !aNewFrameMask )
+            {
+            // So mask was not needed - get rid of previous (if any)
+            delete iPrevFrameMask;
+            iPrevFrameMask = NULL;
+            }
+        }
+    else
+        {
+        if ( !iPrevFrame )
+            {
+            User::Leave( KErrNotSupported );
+            }
+            
+        if ( !iNextSubFrameHasAlpha || 
+             !aSubFrameMask || 
+             !iPrevFrameMask )
+            {
+            HUI_DEBUG1(_L("CHuiTextureAnimationState(%x): Quick 2-"), this );
+            QuickProduceNextFrameAndUpdatePreviousL(
+                aNewFrame, aNewFrameMask,
+                aSubFrame, aSubFrameMask );
+            }
+        else
+            {
+            HUI_DEBUG1(_L("CHuiTextureAnimationState(%x): Slow 2-"), this );
+            ProduceNextFrameAndUpdatePreviousL(
+                aNewFrame, aNewFrameMask,
+                aSubFrame, aSubFrameMask );
+            }
+        }
+        
+    iFrame++; // Go to next frame
+        
+    if ( iFrame == ( iFrameCount - 1 ) )
+        {
+        // Reset back to the beginning
+        iFrame = KErrNotFound;
+        }
+    HUI_DEBUG1(_L("CHuiTextureAnimationState(%x): Produce next done"), this );        
+    }
+
+void CHuiTextureAnimationState::ProceedWithoutNextFrameL(
+        CFbsBitmap* aSubFrame,
+        CFbsBitmap* aSubFrameMask )
+    {
+    // This could be optimized. However, if this method is called,
+    // it means that client is anyway using the API in very performance
+    // inefficient way, i.e. asking system to load random frames rather
+    // than in sequence 0, 1, ..., N.
+    
+    CFbsBitmap* frame = NULL;
+    CFbsBitmap* frameMask = NULL;
+    
+    ProduceNextFrameL( frame, frameMask, aSubFrame, aSubFrameMask );
+    
+    delete frame;
+    delete frameMask;
+    }
+
+CHuiTextureAnimationState::CHuiTextureAnimationState()
+    {
+    HUI_DEBUG1(_L("CHuiTextureAnimationState(%x): Created"), this );
+    }
+    
+void CHuiTextureAnimationState::ConstructL( 
+        TInt aTextureGroupId, const TDesC& aImageFile, TInt aFrameCount )
+    {
+    iTextureGroupId = aTextureGroupId;
+    iFile = aImageFile.AllocL();
+    iFrame = KErrNotFound;
+    iFrameCount = aFrameCount;
+    }
+
+void CHuiTextureAnimationState::ProduceFirstFrameAndGeneratePreviousL(
+        CFbsBitmap*& aNewFrame,
+        CFbsBitmap*& aNewFrameMask,
+        CFbsBitmap* aSubFrame,
+        CFbsBitmap* aSubFrameMask )
+    {
+    if ( !aSubFrameMask )
+        {
+        User::Leave( KErrNotSupported );
+        }
+        
+    const TSize frameSize = OverallSize();
+
+    // Make scratch
+    CHuiModifiableBitmap* scratch = 
+        CHuiModifiableBitmap::NewLC( frameSize, EColor16MA );
+    scratch->Combine( iNextSubFrameRect.iTl, *aSubFrame, *aSubFrameMask );
+                        
+    // Extract new frame & mask
+    CHuiModifiableBitmap* frame = 
+        CHuiModifiableBitmap::NewLC( frameSize, aSubFrame->DisplayMode() );
+    frame->ExtractColor( *scratch );
+
+    CHuiModifiableBitmap* frameMask = 
+        CHuiModifiableBitmap::NewLC( frameSize, EGray256 );
+    frameMask->ExtractAlpha( *scratch );
+            
+    // Create prev frame & mask
+    CHuiModifiableBitmap* prevFrame = 
+        iPrevFrame ?
+        CHuiModifiableBitmap::NewLC( *iPrevFrame ) :
+        CHuiModifiableBitmap::NewLC( frameSize, aSubFrame->DisplayMode() );
+
+    CHuiModifiableBitmap* prevFrameMask = 
+        iPrevFrameMask ?
+            CHuiModifiableBitmap::NewLC( *iPrevFrameMask ) :
+            CHuiModifiableBitmap::NewLC( frameSize, EGray256 );
+
+    prevFrame->Clear( BitmapClearColor() );
+    prevFrameMask->Clear( MaskClearColor() );
+    
+    switch ( iNextSubFrameDisposalAction )
+        {                    
+        case ELeaveInPlace:
+            prevFrame->BitBlt( iNextSubFrameRect, *frame );
+            prevFrameMask->BitBlt( iNextSubFrameRect, *frameMask );
+            break;
+        
+        case ERestoreToPrevious:
+        case EUnspecified:        
+        case ERestoreToBackgroundColour:
+        default:
+            break;
+        }
+
+    // Cleanup
+    iPrevFrameMask = prevFrameMask->ReleaseBitmap();
+    CleanupStack::PopAndDestroy( prevFrameMask );
+            
+    iPrevFrame = prevFrame->ReleaseBitmap();
+    CleanupStack::PopAndDestroy( prevFrame );
+            
+    aNewFrameMask = frameMask->ReleaseBitmap();
+    CleanupStack::PopAndDestroy( frameMask );
+                
+    aNewFrame = frame->ReleaseBitmap();              
+    CleanupStack::PopAndDestroy( frame );
+    CleanupStack::PopAndDestroy( scratch ); 
+    }
+
+void CHuiTextureAnimationState::ProduceNextFrameAndUpdatePreviousL(
+        CFbsBitmap*& aNewFrame,
+        CFbsBitmap*& aNewFrameMask,
+        CFbsBitmap* aSubFrame,
+        CFbsBitmap* aSubFrameMask )
+    {
+    if ( !aSubFrameMask || !iPrevFrameMask )
+        {
+        User::Leave( KErrNotSupported );
+        }
+
+    const TSize frameSize = OverallSize();
+            
+    // Make previous state and blit new subframe on top of that
+    CHuiModifiableBitmap* scratch = 
+        CHuiModifiableBitmap::NewLC( frameSize, EColor16MA );
+    scratch->Combine( *iPrevFrame, *iPrevFrameMask );
+            
+    scratch->Context().BitBltMasked(
+        iNextSubFrameRect.iTl,
+        aSubFrame,
+        TRect( aSubFrame->SizeInPixels() ),
+        aSubFrameMask,
+        ETrue );
+            
+    // Extract new frame & mask
+    CHuiModifiableBitmap* frame = 
+        CHuiModifiableBitmap::NewLC( frameSize, aSubFrame->DisplayMode() );
+    frame->ExtractColor( *scratch );
+            
+    CHuiModifiableBitmap* frameMask =
+        CHuiModifiableBitmap::NewLC( frameSize, EGray256 );
+    frameMask->ExtractAlpha( *scratch );
+            
+    // Update previous frame & mask
+    CHuiModifiableBitmap* prevFrame = 
+        CHuiModifiableBitmap::NewLC( *iPrevFrame );
+    CHuiModifiableBitmap* prevFrameMask =
+        CHuiModifiableBitmap::NewLC( *iPrevFrameMask );
+        
+    switch ( iNextSubFrameDisposalAction )
+        {                    
+        case EUnspecified:
+        case ERestoreToBackgroundColour:
+            prevFrameMask->Clear( iNextSubFrameRect, MaskClearColor() );
+            prevFrame->Clear( iNextSubFrameRect, BitmapClearColor() );
+            break;
+                    
+        case ELeaveInPlace:
+            prevFrame->BitBlt( iNextSubFrameRect, *frame );
+            prevFrameMask->BitBlt( iNextSubFrameRect, *frameMask );
+            break;
+            
+        case ERestoreToPrevious:
+        default:
+            break;
+            }
+        
+    CleanupStack::PopAndDestroy( prevFrameMask );
+    CleanupStack::PopAndDestroy( prevFrame );
+
+    aNewFrame = frame->ReleaseBitmap();
+    aNewFrameMask = frameMask->ReleaseBitmap();
+            
+    CleanupStack::PopAndDestroy( frameMask );
+    CleanupStack::PopAndDestroy( frame );
+                        
+    CleanupStack::PopAndDestroy( scratch );
+    }
+
+void CHuiTextureAnimationState::QuickProduceFirstFrameAndGeneratePreviousL(
+        CFbsBitmap*& aNewFrame,
+        CFbsBitmap*& aNewFrameMask,
+        CFbsBitmap* aSubFrame,
+        CFbsBitmap* aSubFrameMask )
+    {
+    const TSize frameSize = OverallSize();
+    const TBool hasAlpha = ( aSubFrameMask != NULL );
+        
+    const TBool exactMatch = 
+        ( TRect( frameSize ) == iNextSubFrameRect ) &&
+        ( aSubFrame->SizeInPixels() == frameSize );
+                            
+    // Produce new frame & mask
+    CHuiModifiableBitmap* frame = 
+        CHuiModifiableBitmap::NewLC( frameSize, aSubFrame->DisplayMode() );
+    
+    CHuiModifiableBitmap* frameMask = NULL;
+    if ( hasAlpha )
+        {           
+        frameMask = CHuiModifiableBitmap::NewLC( frameSize, EGray256 );
+        
+        frame->Clear( BitmapClearColor() );
+        if ( !exactMatch )
+            {
+            frameMask->Clear( MaskClearColor() );
+            }
+        
+        frame->Context().BitBltMasked( 
+            iNextSubFrameRect.iTl, 
+            aSubFrame, 
+            TRect( aSubFrame->SizeInPixels() ), 
+            aSubFrameMask, 
+            ETrue );
+        frameMask->Context().BitBlt( iNextSubFrameRect.iTl, aSubFrameMask );
+        }
+    else
+        {
+        if ( !exactMatch )
+            {
+            frame->Clear( iNextSubFrameBgColor );
+            }
+        frame->Context().BitBlt( iNextSubFrameRect.iTl, aSubFrame );
+        }
+                
+    // Create prev frame & mask
+    CHuiModifiableBitmap* prevFrame = 
+        iPrevFrame ?
+        CHuiModifiableBitmap::NewLC( *iPrevFrame ) :
+        CHuiModifiableBitmap::NewLC( frameSize, aSubFrame->DisplayMode() );
+
+    CHuiModifiableBitmap* prevFrameMask = NULL;
+    if ( hasAlpha )
+        {
+        prevFrameMask = 
+            iPrevFrameMask ?
+                CHuiModifiableBitmap::NewLC( *iPrevFrameMask ) :
+                CHuiModifiableBitmap::NewLC( frameSize, EGray256 );
+        }
+
+    const TRgb clearColor = 
+        hasAlpha ? 
+            BitmapClearColor() : 
+            iNextSubFrameBgColor;
+    prevFrame->Clear( clearColor );        
+    if ( prevFrameMask )
+        {
+        prevFrameMask->Clear( MaskClearColor() );
+        }
+    
+    switch ( iNextSubFrameDisposalAction )
+        {                    
+        case ELeaveInPlace:
+            prevFrame->BitBlt( iNextSubFrameRect, *frame );
+            if ( prevFrameMask )
+                {
+                prevFrameMask->BitBlt( iNextSubFrameRect, *frameMask );
+                }
+            break;
+        
+        case ERestoreToPrevious:
+        case EUnspecified:        
+        case ERestoreToBackgroundColour:
+        default:
+            break;
+        }
+
+    // Cleanup
+    if ( prevFrameMask )
+        {
+        iPrevFrameMask = prevFrameMask->ReleaseBitmap();
+        CleanupStack::PopAndDestroy( prevFrameMask );
+        }       
+            
+    iPrevFrame = prevFrame->ReleaseBitmap();
+    CleanupStack::PopAndDestroy( prevFrame );
+            
+    if ( frameMask )
+        {
+        aNewFrameMask = frameMask->ReleaseBitmap();
+        CleanupStack::PopAndDestroy( frameMask );
+        }
+                
+    aNewFrame = frame->ReleaseBitmap();                    
+    CleanupStack::PopAndDestroy( frame );     
+    }
+
+void CHuiTextureAnimationState::QuickProduceNextFrameAndUpdatePreviousL(
+        CFbsBitmap*& aNewFrame,
+        CFbsBitmap*& aNewFrameMask,
+        CFbsBitmap* aSubFrame,
+        CFbsBitmap* aSubFrameMask )
+    {
+    const TSize frameSize = OverallSize();
+    const TBool hasAlpha = aSubFrameMask != NULL;
+
+    // Produce frame & frame mask
+    CHuiModifiableBitmap* frame = 
+        CHuiModifiableBitmap::NewLC( frameSize, aSubFrame->DisplayMode() );
+    frame->Context().BitBlt( TPoint(), iPrevFrame );
+    
+    CHuiModifiableBitmap* frameMask = NULL;
+    if ( iPrevFrameMask )
+        {
+        frameMask =
+            CHuiModifiableBitmap::NewLC( frameSize, EGray256 );        
+        frameMask->Context().BitBlt( TPoint(), iPrevFrameMask );
+        }
+    
+    if ( hasAlpha )
+        {
+        frame->Context().SetBrushStyle( CGraphicsContext::ENullBrush );
+        frame->Context().BitBltMasked( 
+            iNextSubFrameRect.iTl, 
+            aSubFrame, 
+            TRect( aSubFrame->SizeInPixels() ), 
+            aSubFrameMask, 
+            ETrue );
+
+        if ( iPrevFrameMask )
+            {                
+            // Merge masks:
+            // prev: 255 sub: 255 frame: 255
+            // prev: 255 sub: 0   frame: 255
+            // prev: 0   sub: 255 frame: 255
+            // prev: 0   sub: 0   frame: 0
+            // => OR style behaviour works
+            frameMask->CombineMasks( iNextSubFrameRect, aSubFrameMask );
+            }
+        }
+    else
+        {
+        frame->Context().BitBlt( iNextSubFrameRect.iTl, aSubFrame );
+        
+        if ( iPrevFrameMask )
+            {
+            frameMask->Clear( iNextSubFrameRect, MaskOpaqueColor() );
+            }
+        }
+    
+    // Update previous frame & mask
+    CHuiModifiableBitmap* prevFrame = 
+        CHuiModifiableBitmap::NewLC( *iPrevFrame );
+    CHuiModifiableBitmap* prevFrameMask = NULL;
+    if ( iPrevFrameMask )
+        {
+        prevFrameMask =
+            CHuiModifiableBitmap::NewLC( *iPrevFrameMask );
+        }
+        
+    switch ( iNextSubFrameDisposalAction )
+        {   
+        case EUnspecified:                         
+        case ERestoreToBackgroundColour:
+            if ( prevFrameMask )
+                {
+                prevFrameMask->Clear( iNextSubFrameRect, MaskClearColor() );
+                prevFrame->Clear( iNextSubFrameRect, BitmapClearColor() );
+                }
+            else
+                {
+                prevFrame->Clear( iNextSubFrameRect, iNextSubFrameBgColor );
+                }    
+            break;
+                    
+        case ELeaveInPlace:
+            prevFrame->BitBlt( iNextSubFrameRect, *frame );
+            if ( prevFrameMask )
+                {
+                prevFrameMask->BitBlt( iNextSubFrameRect, *frameMask );
+                }
+            break;
+            
+        case ERestoreToPrevious:
+        default:
+            break;
+        }
+
+    if ( prevFrameMask )
+        {
+        CleanupStack::PopAndDestroy( prevFrameMask );
+        }
+    CleanupStack::PopAndDestroy( prevFrame );
+
+    aNewFrame = frame->ReleaseBitmap();
+    if ( frameMask )
+        {
+        aNewFrameMask = frameMask->ReleaseBitmap();
+        CleanupStack::PopAndDestroy( frameMask );
+        }
+    CleanupStack::PopAndDestroy( frame );        
+    }
+
+inline TRgb CHuiTextureAnimationState::BitmapClearColor()
+    {
+    return TRgb(0,0,0); // black
+    }
+    
+inline TRgb CHuiTextureAnimationState::MaskClearColor()
+    {
+    return TRgb::Gray256( 0 ); // transparent for EGray256 masks
+    }
+
+inline TRgb CHuiTextureAnimationState::MaskOpaqueColor()
+    {
+    return TRgb::Gray256( 255 ); // opaque for EGray256 masks
+    }
+
+void CHuiTextureAnimationState::CheckSubFrameL( 
+        CFbsBitmap* aSubFrame, 
+        CFbsBitmap* aSubFrameMask )
+    {
+    if ( !aSubFrame )
+        {
+        User::Leave( KErrNotSupported );
+        }    
+            
+    // aSubFrame display mode should be either 64K or 16MU,
+    // but let's check it.
+    const TDisplayMode subFrameMode = aSubFrame->DisplayMode();
+    if ( ( subFrameMode != EColor64K && subFrameMode != EColor16MU ) ||
+         aSubFrame->IsCompressedInRAM() )
+        {
+        User::Leave( KErrNotSupported );
+        }
+        
+    // aSubFrameMask should be EGray256
+    if ( aSubFrameMask )
+        {
+        if ( ( aSubFrameMask->DisplayMode() != EGray256 ) ||
+             aSubFrame->IsCompressedInRAM() )
+            {
+            User::Leave( KErrNotSupported );
+            }
+        }
+    }
+
+
+
+//
+// CHuiModifiableBitmap implementation
+//
+
+
+CHuiModifiableBitmap* CHuiModifiableBitmap::NewLC( 
+        const TSize& aSize, TDisplayMode aMode )
+    {
+    CHuiModifiableBitmap* self = new (ELeave) CHuiModifiableBitmap;
+    CleanupStack::PushL( self );
+    self->ConstructL( aSize, aMode );
+    return self;
+    }
+    
+CHuiModifiableBitmap* CHuiModifiableBitmap::NewLC( 
+        CFbsBitmap& aBitmap )
+    {
+    CHuiModifiableBitmap* self = new (ELeave) CHuiModifiableBitmap;
+    CleanupStack::PushL( self );
+    self->ConstructL( aBitmap );
+    return self;    
+    }
+
+CHuiModifiableBitmap::~CHuiModifiableBitmap()
+    {
+    delete iGc;
+    delete iDevice;
+    if ( iOwnBitmap )
+        {
+        delete iBitmap;
+        }
+    }
+
+CFbsBitGc& CHuiModifiableBitmap::Context()
+    {
+    return *iGc;
+    }
+    
+CFbsBitmap* CHuiModifiableBitmap::ReleaseBitmap()
+    {
+    delete iGc;
+    iGc = NULL;
+    delete iDevice;
+    iDevice = NULL;
+    CFbsBitmap* bitmap = iBitmap;
+    iBitmap = NULL;
+    return bitmap;
+    }
+
+void CHuiModifiableBitmap::Clear( const TRgb& aColor )
+    {
+    iGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+    iGc->SetBrushColor( aColor );
+    iGc->Clear();
+    iGc->SetBrushStyle( CGraphicsContext::ENullBrush );
+    }
+
+void CHuiModifiableBitmap::Clear( const TRect& aRect, const TRgb& aColor )
+    {
+    iGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+    iGc->SetBrushColor( aColor );
+    iGc->Clear( aRect );
+    iGc->SetBrushStyle( CGraphicsContext::ENullBrush );    
+    }
+
+void CHuiModifiableBitmap::BitBlt( 
+        const TRect& aRect, CHuiModifiableBitmap& aBitmap )
+    {
+    if ( iGc && aBitmap.iBitmap && iBitmap )
+        {
+        // Copy area from one bitmap to another. Same size expected.
+        iGc->BitBlt( aRect.iTl, aBitmap.iBitmap, aRect );
+        }
+    }
+
+void CHuiModifiableBitmap::Combine( 
+        const CFbsBitmap& aSrc, const CFbsBitmap& aSrcMask )
+    {
+    if ( iBitmap )
+        {
+        Combine( TPoint(), aSrc, aSrcMask );
+        }
+    }
+
+void CHuiModifiableBitmap::Combine( 
+        const TPoint& aPos, const CFbsBitmap& aSrc, const CFbsBitmap& aSrcMask )
+    {
+    if ( iBitmap )
+        {
+        // Clear with transparent
+        iGc->SetDrawMode( CGraphicsContext::EDrawModeWriteAlpha );
+        iGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+        iGc->SetBrushColor( TRgb( 0, 0, 0, 0 ) );
+        iGc->Clear();
+        iGc->SetBrushStyle( CGraphicsContext::ENullBrush );    
+        iGc->SetDrawMode( CGraphicsContext::EDrawModePEN );
+        
+        // Blit masked
+        iGc->BitBltMasked( 
+            aPos, 
+            &aSrc, 
+            TRect( aSrc.SizeInPixels() ), 
+            &aSrcMask, 
+            ETrue );
+        }
+    }
+
+void CHuiModifiableBitmap::CombineMasks( 
+        const TRect& aRect, 
+        CFbsBitmap* aMask )
+    {    
+    if ( iBitmap )
+        {
+        // this is EGray256, aMask is EGray256
+        TRect targetRect( aRect );
+        targetRect.Intersection( iBitmap->SizeInPixels() );
+        targetRect.Intersection( TRect( aRect.iTl, aMask->SizeInPixels() ) );
+        
+        if ( targetRect.IsEmpty() )
+            {
+            // nothing to draw
+            return;
+            }
+    
+        // Starting target & source point and size to draw
+        const TPoint targetPoint = targetRect.iTl;
+        const TPoint sourcePoint = targetRect.iTl - aRect.iTl;
+        const TSize size = targetRect.Size();
+
+        // Go through all pixels using OR operation.
+        // As aMask contains only 0 or 255 values, it is
+        // sufficient to combine these masks.
+        TBitmapUtil source(aMask);
+        TBitmapUtil target(iBitmap);
+    
+        source.Begin( sourcePoint );
+        target.Begin( targetPoint );
+    
+        for( TInt y = 0; y < size.iHeight; ++y )
+            {
+            source.SetPos( sourcePoint + TPoint(0,y) );
+            target.SetPos( targetPoint + TPoint(0,y) );
+            
+            for( TInt x = 0; x < size.iWidth; ++x )
+                {
+                TUint32 pixel = source.GetPixel();
+                if ( pixel )
+                    {
+                    target.SetPixel( target.GetPixel() | pixel );
+                    }
+                
+                target.IncXPos();
+                source.IncXPos();
+                }
+            }
+            
+        target.End();
+        source.End();        
+        }    
+    }
+
+void CHuiModifiableBitmap::ExtractAlpha( CHuiModifiableBitmap& aSource )
+    {
+    if ( iBitmap && aSource.iBitmap )
+        {
+        // this is EGray256, aSource is 16MA
+        
+        TBitmapUtil source(aSource.iBitmap);
+        TBitmapUtil target(iBitmap);
+    
+        source.Begin( TPoint() );
+        target.Begin( TPoint() );
+    
+        const TSize size( iBitmap->SizeInPixels() );
+        for( TInt y = 0; y < size.iHeight; ++y )
+            {
+            source.SetPos( TPoint( 0, y) );
+            target.SetPos( TPoint( 0, y) );
+            
+            for( TInt x = 0; x < size.iWidth; ++x )
+                {
+                target.SetPixel( source.GetPixel() >> 24 );
+                
+                target.IncXPos();
+                source.IncXPos();
+                }
+            }
+            
+        target.End();
+        source.End();        
+        }
+    }
+   
+void CHuiModifiableBitmap::ExtractColor( CHuiModifiableBitmap& aSource )
+    {
+    // this is color, aSource is 16MA
+    
+    if ( iBitmap && aSource.iBitmap )
+        {
+        TDisplayMode mode = iBitmap->DisplayMode();
+        if ( mode == EColor64K )
+            {
+            DoExtractColor<Convert16MA_64K>( iBitmap, aSource.iBitmap );
+            }
+        else if ( mode == EColor16MU )
+            {
+            DoExtractColor<Convert16MA_16MU>( iBitmap, aSource.iBitmap );
+            }
+        }
+    }
+    
+void CHuiModifiableBitmap::ConstructL( const TSize& aSize, TDisplayMode aMode )
+    {
+    iOwnBitmap = ETrue;
+    iBitmap = new (ELeave) CFbsBitmap;
+    User::LeaveIfError( iBitmap->Create( aSize, aMode ) );
+    
+    iDevice = CFbsBitmapDevice::NewL( iBitmap );
+    iDevice->CreateContext( iGc );
+    User::LeaveIfNull( iGc );        
+    }
+
+void CHuiModifiableBitmap::ConstructL( CFbsBitmap& aBitmap )
+    {
+    iOwnBitmap = EFalse;
+    iBitmap = &aBitmap;
+    
+    iDevice = CFbsBitmapDevice::NewL( iBitmap );
+    iDevice->CreateContext( iGc );
+    User::LeaveIfNull( iGc );        
+    }
+
+template<typename Converter>
+void CHuiModifiableBitmap::DoExtractColor( 
+        CFbsBitmap* aTarget, CFbsBitmap* aSource )
+    {
+    TBitmapUtil source(aSource);
+    TBitmapUtil target(aTarget);
+    
+    source.Begin( TPoint() );
+    target.Begin( TPoint() );
+    
+    const TSize size( aTarget->SizeInPixels() );
+    for(TInt y = 0; y < size.iHeight; ++y)
+        {
+        source.SetPos(TPoint(0, y));
+        target.SetPos(TPoint(0, y));
+            
+        for(TInt x = 0; x < size.iWidth; ++x)
+            {
+            target.SetPixel( Converter::Convert( source.GetPixel() ) );
+                
+            target.IncXPos();
+            source.IncXPos();
+            }
+        }
+            
+    target.End();
+    source.End();
+    }
+
+inline TUint32 CHuiModifiableBitmap::Convert16MA_16MU::Convert( TUint32 aPixel )
+    {
+    return aPixel | 0xFF000000;
+    }
+    
+inline TUint32 CHuiModifiableBitmap::Convert16MA_64K::Convert( TUint32 aPixel )
+    {
+	const TUint32 b = (aPixel&0x000000ff)>>3;
+	const TUint32 g = (aPixel&0x0000fc00)>>5;
+	const TUint32 r = (aPixel&0x00f80000)>>8;
+	return (r|g|b);
+    }
+