skins/AknSkins/rlpluginsrc/AknsRlEffectPluginMovingLayers.cpp
changeset 0 05e9090e2422
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/skins/AknSkins/rlpluginsrc/AknsRlEffectPluginMovingLayers.cpp	Thu Dec 17 09:14:12 2009 +0200
@@ -0,0 +1,499 @@
+/*
+* Copyright (c) 2004-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:  Provides moving layer(s) functionality.
+*
+*/
+
+
+// INCLUDE FILES
+#include "AknsRlEffectPluginMovingLayers.h"
+
+// ================= INTERNAL IMPL. OF MOVING LAYERS ===========================
+class AknsRlMovingLayers
+    {
+    public:
+    static void RenderTiled( CFbsBitGc& aBitGc,
+                         const TInt aX, const TInt aY,
+                         const TInt aW, const TInt aH,
+                         const CFbsBitmap& aBmp,
+                         const CFbsBitmap* aMask=NULL )
+        {
+        if( 0 == aX && 0 == aY ) // Render 1:1
+            {
+            if( aMask )
+                {
+                aBitGc.BitBltMasked( TPoint( 0, 0 ), &aBmp,
+                                     TRect( TPoint( 0, 0 ),
+                                     TSize( aW, aH ) ),
+                                     aMask, EFalse );
+                }
+            else
+                {
+                aBitGc.BitBlt( TPoint( 0, 0 ), &aBmp,
+                                TRect( TPoint( 0, 0 ),
+                                TSize( aW, aH ) ) );
+                }
+            }
+        else // Draw tiled
+            {
+            /*
+            Output        Input
+             ---------     ---------
+            |4' |3'   |   |1    |2  |
+            |---o-----|   |     |   |
+            |2' |1'   |   |     |   |
+            |   |     |   |     |   |
+            |   |     |   |-----o---|
+            |   |     |   |3    |4  |
+             ---------     ---------
+
+            Output rects:
+            1' (     x,     y, w - x, h - y )
+            2' (     0,     y,     x, h - y )
+            3' (     x,     0, w - x,     y )
+            4' (     0,     0,     x,     y )
+
+            Input rects:
+            1  (     0,     0, w - x, h - y )
+            2  ( w - x,     0,     x, h - y )
+            3  (     0, h - y, w - x,     y )
+            4  ( w - x, h - y,     x,     y )
+
+            */
+            TRect source;
+
+            if( aMask )
+                {
+                // Target top left ( 4 -> 4' )
+                source.SetRect( TPoint( aW - aX, aH - aY ), TSize( aX, aY ) );
+                aBitGc.BitBltMasked( TPoint( 0, 0 ), &aBmp, source, aMask, EFalse );
+                // Target top right ( 3 -> 3' )
+                source.SetRect( TPoint( 0, aH - aY ), TSize( aW - aX, aY ) );
+                aBitGc.BitBltMasked( TPoint( aX, 0 ), &aBmp, source, aMask, EFalse );
+                // Target bottom left ( 2 -> 2' )
+                source.SetRect( TPoint( aW - aX, 0 ), TSize( aX, aH - aY ) );
+                aBitGc.BitBltMasked( TPoint( 0, aY ), &aBmp, source, aMask, EFalse );
+                // Target bottom right ( 1 -> 1' )
+                source.SetRect( TPoint( 0, 0 ), TSize( aW - aX, aH - aY ) );
+                aBitGc.BitBltMasked( TPoint( aX, aY ), &aBmp, source, aMask, EFalse );
+                }
+            else
+                {
+                // Target top left ( 4 -> 4' )
+                source.SetRect( TPoint( aW - aX, aH - aY ), TSize( aX, aY ) );
+                aBitGc.BitBlt( TPoint( 0, 0 ), &aBmp, source );
+                // Target top right ( 3 -> 3' )
+                source.SetRect( TPoint( 0, aH - aY ), TSize( aW - aX, aY ) );
+                aBitGc.BitBlt( TPoint( aX, 0 ), &aBmp, source );
+                // Target bottom left ( 2 -> 2' )
+                source.SetRect( TPoint( aW - aX, 0 ), TSize( aX, aH - aY ) );
+                aBitGc.BitBlt( TPoint( 0, aY ), &aBmp, source );
+                // Target bottom right ( 1 -> 1' )
+                source.SetRect( TPoint( 0, 0 ), TSize( aW - aX, aH - aY ) );
+                aBitGc.BitBlt( TPoint( aX, aY ), &aBmp, source );
+                }
+            }
+        }
+    };
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginMovingLayers::CAknsRlEffectPluginMovingLayers
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CAknsRlEffectPluginMovingLayers::CAknsRlEffectPluginMovingLayers()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CAknsRlEffectPluginMovingLayers::~CAknsRlEffectPluginMovingLayers()
+    {
+    // The user of this plugin should call deactivate...but we ensure deletion
+    // here (just in case).
+    DeleteTempBitmap(); //lint !e1551 No exception thrown
+    }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginMovingLayers::EffectUid
+// -----------------------------------------------------------------------------
+//
+TUid CAknsRlEffectPluginMovingLayers::EffectUid() const
+    {
+    return TUid::Uid( KAknsRlEffectPluginMovingLayersUID );
+    }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginMovingLayers::Effect
+// -----------------------------------------------------------------------------
+//
+MAknsRlEffect* CAknsRlEffectPluginMovingLayers::Effect( const TInt aInterface )
+    {
+    if( aInterface == KAknsRlEffectPluginInterfaceEffect )
+        return this;
+    return NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginMovingLayers::InitializeL
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginMovingLayers::InitializeL()
+    {
+    iContext = NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginMovingLayers::Release
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginMovingLayers::Release()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginMovingLayers::ActivateL
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginMovingLayers::ActivateL( MAknsRlEffectContext* aContext )
+    {
+    if( !aContext ) // We absolutely need the context
+        {
+        User::Leave( KErrArgument );
+        }
+
+    iContext = aContext;
+
+    iAx = 0;
+    iAy = 0;
+    iBx = 0;
+    iBy = 0;
+
+    DeleteTempBitmap();
+    }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginMovingLayers::Deactivate
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginMovingLayers::Deactivate()
+    {
+    DeleteTempBitmap();
+    }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginMovingLayers::SetParametersL
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginMovingLayers::SetParametersL( MAknsRlParameterIterator& aParameters )
+    {
+    // Iterate over available parameters
+    while( aParameters.HasNext() )
+        {
+        const TAknsRlParameterData* param = aParameters.NextL();
+
+        if( param->iName->Compare( KAknsRlEffectMovingLayersAX ) == 0 )
+            {
+            if( param->iType != EAknsRlParameterTypeNumber )
+                User::Leave( KErrArgument );
+
+            iAx = param->iNumber;
+            }
+        else if( param->iName->Compare( KAknsRlEffectMovingLayersAY ) == 0 )
+            {
+            if( param->iType != EAknsRlParameterTypeNumber )
+                User::Leave( KErrArgument );
+
+            iAy = param->iNumber;
+            }
+        else if( param->iName->Compare( KAknsRlEffectMovingLayersBX ) == 0 )
+            {
+            if( param->iType != EAknsRlParameterTypeNumber )
+                User::Leave( KErrArgument );
+
+            iBx = param->iNumber;
+            }
+        else if( param->iName->Compare( KAknsRlEffectMovingLayersBY ) == 0 )
+            {
+            if( param->iType != EAknsRlParameterTypeNumber )
+                User::Leave( KErrArgument );
+
+            iBy = param->iNumber;
+            }
+        else if( param->iName->Compare( KAknsRlEffectMovingLayersAXY ) == 0 )
+            {
+            if( param->iType != EAknsRlParameterTypeString || !param->iString )
+                User::Leave( KErrArgument );
+
+            if( param->iString->Length() < 2 )
+                User::Leave( KErrArgument );
+
+            iAx = (*param->iString)[0];
+            iAy = (*param->iString)[1];
+            }
+        else if( param->iName->Compare( KAknsRlEffectMovingLayersBXY ) == 0 )
+            {
+            if( param->iType != EAknsRlParameterTypeString || !param->iString )
+                User::Leave( KErrArgument );
+
+            if( param->iString->Length() < 2 )
+                User::Leave( KErrArgument );
+
+            iBx = (*param->iString)[0];
+            iBy = (*param->iString)[1];
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginMovingLayers::GetCapabilities
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginMovingLayers::GetCapabilities( TAknsRlEffectCaps& aCaps )
+    {
+    aCaps.iOutputLayerSupport = KAknsRlLayerRGBOnly;
+    aCaps.iInputLayerASupport = KAknsRlLayerRGBOnly;
+    aCaps.iInputLayerBSupport = KAknsRlLayerNone | KAknsRlLayerRGBOnly | KAknsRlLayerRGBA;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginMovingLayers::Render
+// -----------------------------------------------------------------------------
+//
+TInt CAknsRlEffectPluginMovingLayers::Render( const TAknsRlRenderOpParam& aParam )
+    {
+    if( !iContext ) // We absolutely need the context
+        {
+        return KErrBadHandle;
+        }
+
+    TAknsRlLayerData dataT;
+    TAknsRlLayerData dataA;
+    TAknsRlLayerData dataB;
+
+    // We need the output layer
+    if( !( ( aParam.iOutputLayerStatus & KAknsRlLayerRGBOnly ) ||
+           ( aParam.iOutputLayerStatus & KAknsRlLayerRGBA ) ) )
+        return KErrArgument; // Output must be some sort of RGB layer
+
+    TRAPD( err, iContext->GetLayerDataL( dataT, aParam.iOutputLayerIndex,
+                                         aParam.iOutputLayerStatus, EFalse ) );
+    if( KErrNone != err )
+        return KErrArgument;
+
+    if( !dataT.iRGBGc || !dataT.iRGBBitmap )
+        return KErrBadHandle;
+
+    // We need the input layer A
+    if( !( ( aParam.iInputLayerAStatus & KAknsRlLayerRGBOnly ) ||
+           ( aParam.iInputLayerAStatus & KAknsRlLayerRGBA ) ) )
+        return KErrArgument; // Input layer A must be some sort of RGB layer
+
+    TRAP( err, iContext->GetLayerDataL( dataA, aParam.iInputLayerAIndex,
+                                        aParam.iInputLayerAStatus, EFalse ) );
+    if( KErrNone != err )
+        return KErrArgument;
+
+    if( !dataA.iRGBBitmap )
+        return KErrBadHandle;
+
+    // Input layer B is optional
+    if( ( aParam.iInputLayerBStatus & KAknsRlLayerRGBOnly ) ||
+        ( aParam.iInputLayerBStatus & KAknsRlLayerRGBA ) )
+        {
+        // Input layer B is RGB layer
+        TRAP( err, iContext->GetLayerDataL( dataB, aParam.iInputLayerBIndex,
+                                            aParam.iInputLayerBStatus, EFalse ) );
+        if( KErrNone != err )
+            return KErrArgument;
+
+        if( !dataB.iRGBBitmap )
+            return KErrBadHandle;
+        }
+
+    // If we got this far we have all the required devices for doing rendering.
+
+    // Tiled rendering does not work correctly if one of the input layers is
+    // the same as output layer.
+    if( ( aParam.iInputLayerAIndex == aParam.iOutputLayerIndex && dataA.iRGBBitmap ) ||
+        ( aParam.iInputLayerBIndex == aParam.iOutputLayerIndex && dataB.iRGBBitmap ) )
+        {
+        if( !iTempBitmap )
+            {
+            err = CreateTempBitmap( *dataT.iRGBBitmap );
+            if( KErrNone != err )
+                return err;
+            }
+        else // Temp bitmap already exists
+            {
+            // Check if we can reuse the existing bitmap
+            if( iTempBitmap->SizeInPixels() == dataT.iRGBBitmap->SizeInPixels() &&
+                iTempBitmap->DisplayMode() == dataT.iRGBBitmap->DisplayMode() )
+                {
+                iTempContext->BitBlt( TPoint( 0, 0 ), dataT.iRGBBitmap );
+                }
+            else
+                {
+                DeleteTempBitmap();
+                err = CreateTempBitmap( *dataT.iRGBBitmap );
+                if( KErrNone != err )
+                    return err;
+                }
+            }
+        }
+
+    // Determine real coordinates (we do tiling)
+    TSize size = iContext->LayerSize();
+
+    TInt ax = iAx % size.iWidth;
+    TInt ay = iAy % size.iHeight;
+
+    if( ax < 0 )
+        ax = ax + size.iWidth;
+    if( ay < 0 )
+        ay = ay + size.iHeight;
+    // ax, bx are now in range [0, size.iWidth - 1]
+
+    TInt bx = iBx % size.iWidth;
+    TInt by = iBy % size.iHeight;
+
+    if( bx < 0 )
+        bx = bx + size.iWidth;
+    if( by < 0 )
+        by = by + size.iHeight;
+    // bx, by are now in range [0, size.iHeight - 1]
+
+    // Render
+    if( dataA.iRGBBitmap && !dataB.iRGBBitmap ) // Only A is available
+        {
+        if( aParam.iInputLayerAIndex == aParam.iOutputLayerIndex  )
+            AknsRlMovingLayers::RenderTiled( *dataT.iRGBGc,
+                            ax, ay, size.iWidth, size.iHeight,
+                            *iTempBitmap );
+        else
+            AknsRlMovingLayers::RenderTiled( *dataT.iRGBGc,
+                            ax, ay, size.iWidth, size.iHeight,
+                            *dataA.iRGBBitmap );
+        }
+    // A, B and mask B available
+    else if( dataA.iRGBBitmap && dataB.iRGBBitmap && dataB.iAlphaBitmap )
+        {
+        if( aParam.iInputLayerAIndex == aParam.iOutputLayerIndex  )
+            AknsRlMovingLayers::RenderTiled( *dataT.iRGBGc,
+                            ax, ay, size.iWidth, size.iHeight,
+                            *iTempBitmap );
+        else
+            AknsRlMovingLayers::RenderTiled( *dataT.iRGBGc,
+                            ax, ay, size.iWidth, size.iHeight,
+                            *dataA.iRGBBitmap );
+
+        if( aParam.iInputLayerBIndex == aParam.iOutputLayerIndex  )
+            AknsRlMovingLayers::RenderTiled( *dataT.iRGBGc,
+                            bx, by, size.iWidth, size.iHeight,
+                            *iTempBitmap );
+        else
+            AknsRlMovingLayers::RenderTiled( *dataT.iRGBGc,
+                            bx, by, size.iWidth, size.iHeight,
+                            *dataB.iRGBBitmap, dataB.iAlphaBitmap );
+        }
+    // A and B available, but no mask for B
+    else if( dataA.iRGBBitmap && dataB.iRGBBitmap && !dataB.iAlphaBitmap )
+        {
+        // Render B only
+        if( aParam.iInputLayerBIndex == aParam.iOutputLayerIndex  )
+            AknsRlMovingLayers::RenderTiled( *dataT.iRGBGc,
+                            bx, by, size.iWidth, size.iHeight,
+                            *iTempBitmap );
+        else
+            AknsRlMovingLayers::RenderTiled( *dataT.iRGBGc,
+                            bx, by, size.iWidth, size.iHeight,
+                            *dataB.iRGBBitmap, dataB.iAlphaBitmap );
+        }
+
+    // Clear the target alpha if it exists
+    if( dataT.iAlphaGc )
+        {
+        dataT.iAlphaGc->SetBrushColor( KRgbWhite );
+        dataT.iAlphaGc->Clear();
+        }
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginMovingLayers::CreateTempBitmap
+// -----------------------------------------------------------------------------
+//
+TInt CAknsRlEffectPluginMovingLayers::CreateTempBitmap(
+    const CFbsBitmap& aBitmap )
+    {
+    ASSERT( NULL == iTempBitmap );
+    ASSERT( NULL == iTempDevice );
+    ASSERT( NULL == iTempContext );
+
+    iTempBitmap = new CFbsBitmap(); // OOM returns NULL
+    if( !iTempBitmap )
+        {
+        DeleteTempBitmap();
+        return KErrNoMemory;
+        }
+
+    TInt err = iTempBitmap->Create( aBitmap.SizeInPixels(), aBitmap.DisplayMode() );
+    if( KErrNone != err )
+        {
+        DeleteTempBitmap();
+        return err;
+        }
+
+    TRAP( err, iTempDevice = CFbsBitmapDevice::NewL( iTempBitmap ) );
+    if( KErrNone != err )
+        {
+        DeleteTempBitmap();
+        return err;
+        }
+
+    err = iTempDevice->CreateContext( iTempContext );
+    if( KErrNone != err )
+        {
+        DeleteTempBitmap();
+        return err;
+        }
+
+    // Temp bitmap and related objects created ok, just render the temp bitmap.
+    iTempContext->BitBlt( TPoint( 0, 0 ), &aBitmap );
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginMovingLayers::DeleteTempBitmap
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginMovingLayers::DeleteTempBitmap()
+    {
+    delete iTempBitmap;
+    iTempBitmap  = NULL;
+    delete iTempDevice;
+    iTempDevice  = NULL;
+    delete iTempContext;
+    iTempContext = NULL;
+    }
+
+// End of File
+