messagingappbase/msgeditor/mediacontrolsrc/MsgImageControl.cpp
changeset 0 72b543305e3a
child 66 fc3320e39880
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingappbase/msgeditor/mediacontrolsrc/MsgImageControl.cpp	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,1073 @@
+/*
+* Copyright (c) 2005-2006 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:  
+*       MsgEditor image UI control - a Message Editor Base control.
+*
+*/
+
+
+
+// INCLUDE FILES
+#include "MsgImageControl.h"
+
+#include <DRMCommon.h>
+#include <AknUtils.h>               // AknsUtils
+#include <AknsDrawUtils.h>          // AknsDrawUtils
+#include <aknlayoutscalable_apps.cdl.h>
+
+#include <MsgEditorView.h>          // CMsgEditorView
+#include <MsgEditorCommon.h>
+
+#include <IHLImageFactory.h>        // IHLImageFactory
+#include <IHLViewerFactory.h>       // IHLViewerFactory
+#include <MIHLFileImage.h>          // MIHLFileImage
+#include <MIHLBitmap.h>             // MIHLBitmap
+#include <MIHLImageViewer.h>        // MIHLImageViewer
+#include <icl/imagecodecdata.h>     // KImageTypeBMPUid
+
+#include "MsgFrameControl.h"
+#include "MsgIconControl.h"
+#include "MsgBitmapControl.h"
+
+#include "MsgMediaControlLogging.h"
+
+// ==========================================================
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES
+
+// CONSTANTS
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+const TInt KAnimationStartDelay = 500000; // 0,5s
+const TInt KAnimationDelayBetweenLoops = 1000000; // 1s
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// ================= MEMBER FUNCTIONS =======================
+
+// ---------------------------------------------------------
+// CMsgImageControl::CMsgImageControl
+//
+// Constructor.
+// ---------------------------------------------------------
+//
+CMsgImageControl::CMsgImageControl( MMsgBaseControlObserver& aBaseControlObserver ) : 
+    CMsgMediaControl( aBaseControlObserver, EMsgComponentIdImage, EMsgImageControl )
+    {
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::ConstructL
+// ---------------------------------------------------------
+//
+void CMsgImageControl::ConstructL( CMsgEditorView& aParent, MMsgAsyncControlObserver* aObserver )
+    {
+    BaseConstructL( aParent, aObserver );    
+    
+    iBitmapControl = new( ELeave ) CMsgBitmapControl;
+    iBitmapControl->SetContainerWindowL( *this );
+    
+    CalculateMaxSize();
+
+    TRect rect( aParent.Rect() );
+    if ( rect.Height() == 0 || rect.Width() == 0 )
+        {
+        // We have been called before view construction.
+        // Set rect to screen size.
+        rect.SetRect( TPoint(), iMaxSize );
+        }
+
+    SetRect( rect );
+    
+    iLoopTimer = CPeriodic::NewL( EPriorityNormal );
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::NewL
+//
+// Two-phased constructor.
+// ---------------------------------------------------------
+//
+EXPORT_C CMsgImageControl* CMsgImageControl::NewL( CMsgEditorView& aParent,
+                                                   MMsgAsyncControlObserver* aObserver )
+    {
+    CMsgImageControl* self = new( ELeave ) CMsgImageControl( aParent );
+    
+    CleanupStack::PushL( self );
+    self->ConstructL( aParent, aObserver );
+    CleanupStack::Pop( self );
+    
+    return self;
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::~CMsgImageControl
+//
+// Destructor
+// ---------------------------------------------------------
+//
+CMsgImageControl::~CMsgImageControl()
+    {
+    delete iEngine;
+    delete iDestinationBitmap;
+    delete iSourceImage;
+    delete iBitmapControl;
+    delete iLoopTimer;
+    }
+    
+// ---------------------------------------------------------
+// CMsgImageControl::LoadL
+// ---------------------------------------------------------
+//
+void CMsgImageControl::LoadL( RFile& aFileHandle )
+    {
+    Reset();
+    
+    iSourceImage = IHLImageFactory::OpenFileImageL( aFileHandle, 
+                                                    0,  // image index
+                                                    MIHLFileImage::EOptionNoDRMConsume );
+    
+    SetState( EMsgAsyncControlStateOpening );
+    
+    iDestinationBitmap = IHLBitmap::CreateL();
+            
+    TSize sourceSize( iSourceImage->Size() );
+    TSize targetSize = TSize(
+    	Min( sourceSize.iWidth, iMaxSize.iWidth - iFrame->FrameBorderSize().iWidth ),
+		Min( sourceSize.iHeight, iMaxSize.iHeight - iFrame->FrameBorderSize().iHeight ) );
+
+    if ( !iSourceImage->IsAnimation() &&
+         ( iSourceImage->ImageType() == KImageTypeBMPUid || 
+           iSourceImage->ImageType() == KImageTypeGIFUid ||
+           iSourceImage->ImageType() == KImageTypePNGUid ) )
+        {
+        iEngine = IHLViewerFactory::CreateImageViewerL( targetSize,
+                                                        *iSourceImage, 
+                                                        *iDestinationBitmap, 
+                                                        *this, 
+                                                        MIHLImageViewer::EOptionUseBilinearInterpolation);
+        }
+   else
+        {
+        iEngine = IHLViewerFactory::CreateImageViewerL( targetSize,
+                                                        *iSourceImage, 
+                                                        *iDestinationBitmap, 
+                                                        *this, 
+                                                        0 );
+        
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::Cancel
+// ---------------------------------------------------------
+//
+void CMsgImageControl::Cancel()
+    {
+    if ( iState == EMsgAsyncControlStateOpening )
+        {
+        Reset();
+        
+        SetState( EMsgAsyncControlStateIdle );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::PlayL
+// ---------------------------------------------------------
+//
+void CMsgImageControl::PlayL()
+    {
+    if ( IsAnimation() &&
+         iState >= EMsgAsyncControlStateOpening )
+        {
+        DoPlay( 0 );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::PauseL
+// ---------------------------------------------------------
+//
+void CMsgImageControl::PauseL()
+    {
+    if ( IsAnimation() && 
+         iState >= EMsgAsyncControlStateReady )
+        {
+        DoPause();
+        }
+    }
+     
+// ---------------------------------------------------------
+// CMsgImageControl::Stop
+// ---------------------------------------------------------
+//
+void CMsgImageControl::Stop()
+    {    
+    if ( IsAnimation() && 
+         iState >= EMsgAsyncControlStateReady )
+        {
+        StopAnimation();
+    
+        SetState( EMsgAsyncControlStateStopped );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::Close
+// ---------------------------------------------------------
+//
+void CMsgImageControl::Close()
+    {
+    Stop();
+    SetState( EMsgAsyncControlStateIdle );
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::IsAnimation
+//
+// Return ETrue if loaded image is animation.
+// ---------------------------------------------------------
+//
+EXPORT_C TBool CMsgImageControl::IsAnimation() const
+    {
+    TBool result( EFalse );
+    
+    if ( iSourceImage )
+        {
+        result = iSourceImage->IsAnimation();
+        }
+        
+    return result;
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::SetAnimationLoopCount
+//
+// Sets animation loop count (i.e. how many times animation
+// is played fully through). -1 means that it is looped forever.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgImageControl::SetAnimationLoopCount( TInt aCount )
+    {
+    iLoopCount = aCount;
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::SetImageFileOpenOrClose
+//
+// Sets image file open or close.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgImageControl::SetImageFileClosed( )
+    {
+    if ( iSourceImage )
+        {
+        Stop();
+        
+        delete iSourceImage;
+        iSourceImage = NULL;
+        
+        delete iEngine;
+        iEngine = NULL;
+        
+        SetState( EMsgAsyncControlStateIdle );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::SetAndGetSizeL
+//
+// Calculates and sets the size of the control and returns new size as
+// reference aSize.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::SetAndGetSizeL( TSize& aSize )
+    {
+    // Adjust max height if needed
+    if ( aSize.iHeight > iMaxSize.iHeight )
+        {
+        aSize.iHeight = iMaxSize.iHeight;
+        }
+
+    // Do not adjust the width. The width of the control must always
+    // be the same as the width of the client rect.
+    aSize = CalculateControlSize( aSize );
+
+    SetSize( aSize );
+    }
+
+
+// ---------------------------------------------------------
+// CMsgImageControl::NotifyViewEvent
+//
+// Animation playback is paused if view looses focus and resumed
+// when focus is again gained. Resuming happens only if animation is
+// still at pause state and control is on playing state.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::NotifyViewEvent( TMsgViewEvent aEvent, TInt aParam )
+    {
+    switch ( aEvent )
+        {
+        case EMsgViewEventViewFocusLost:
+            {
+            if ( iAnimationState == EAnimationPlaying )
+                {
+                PauseAnimation();
+                }
+            break;
+            }
+        case EMsgViewEventViewFocusGain:
+            {
+            if ( iAnimationState == EAnimationPaused &&
+                 iState == EMsgAsyncControlStatePlaying )
+                {
+                StartAnimation( KAnimationStartDelay );
+                }
+            break;
+            }
+        default:
+            {
+            break;
+            }
+        }
+        
+    CMsgMediaControl::NotifyViewEvent( aEvent, aParam );
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::Reset
+//
+// Empties the control.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::Reset()
+    {
+    delete iEngine;
+    iEngine = NULL;
+    
+    iAnimationState = EAnimationStopped;
+    
+    delete iDestinationBitmap;
+    iDestinationBitmap = NULL;
+    
+    iBitmapControl->SetBitmap( NULL );
+    
+    delete iSourceImage;
+    iSourceImage = NULL;
+    
+    ResetIconId();
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::FocusChanged
+//
+// Updates the focus (i.e. set frame control visible/invisible).
+// Calls base class implementation if icon is visible. Otherwise
+// performs it's own handling.
+// Frame control is redraw immediatelly if that 
+// is requested and frame control state is changed. Otherwise
+// normal deferred drawing is done. This is activated at 
+// CCoeControl::MakeVisible if needed.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::FocusChanged( TDrawNow aDrawNow )
+    {
+    if ( VisiblePlaceholder() )
+        {
+        CMsgMediaControl::FocusChanged( aDrawNow );
+        }
+    else 
+        {
+        TBool oldVisibility( iFrame->IsVisible() );
+    
+        iFrame->MakeVisible( IsFocused() );
+        
+        if ( aDrawNow == EDrawNow &&
+             iFrame->IsVisible() != oldVisibility )
+            {
+            DrawNow();
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::SizeChanged
+//
+// Called when size is changed.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::SizeChanged()
+    {
+    if ( iEngine && 
+         Size() != iEngine->ViewerSize() )
+        {
+        TSize bitmapSize = iEngine->SourceSize() ;
+        TSize controlSize = iSize;
+        controlSize.iWidth -= iFrame->FrameBorderSize().iWidth;
+        controlSize.iHeight -= iFrame->FrameBorderSize().iHeight;
+        
+        TReal widthRatio = static_cast<TReal>( controlSize.iWidth ) / 
+                           static_cast<TReal>( bitmapSize.iWidth );
+        TReal heightRatio = static_cast<TReal>( controlSize.iHeight ) / 
+                            static_cast<TReal>( bitmapSize.iHeight );
+        TReal zoomRatio = ( widthRatio < heightRatio ) ? widthRatio : heightRatio;
+        
+        iEngine->SetViewerSize( Size() );
+        iEngine->SetZoomRatio( zoomRatio );
+        }
+    
+    // Size updated at the ViewerBitmapChanged when image scaling is done.
+    iBitmapControl->SetPosition( Position() + CalculateImagePosition() );
+        
+    if ( iDestinationBitmap && 
+         iDestinationBitmap->IsCreated() )
+        {
+        iFrame->SetImageSize( iDestinationBitmap->Bitmap().SizeInPixels() );
+        }
+    
+    if ( iState == EMsgAsyncControlStatePlaying )
+        {
+        // Start animation if needed on playing state.
+        StartAnimation( 0 );
+        }
+        
+    CMsgMediaControl::SizeChanged();
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::Draw
+//
+// Draws the basic skin background for given rectangle. 
+// Image is drawn on CBitmapControl::Draw function.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::Draw( const TRect& aRect ) const
+    {
+    CWindowGc& gc = SystemGc();
+    
+    if ( !VisiblePlaceholder() )
+        {
+        if ( !AknsDrawUtils::BackgroundBetweenRects( AknsUtils::SkinInstance(), 
+                                                 AknsDrawUtils::ControlContext( this ), 
+                                                 this, 
+                                                 gc, 
+                                                 Rect(),
+                                                 iBitmapControl->Rect(),
+                                                 KAknsDrawParamNoClearUnderImage ) )
+            {
+            gc.SetBrushColor( AKN_LAF_COLOR( 0 ) );
+            gc.SetPenStyle( CGraphicsContext::ENullPen );
+    		gc.SetBrushStyle( CGraphicsContext::ESolidBrush );
+        	gc.DrawRect( aRect );
+            }
+        }
+    else 
+        {
+        // Basic icon drawing from base class when icon is visible.
+        CMsgMediaControl::Draw( aRect );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMmsImageControl::MakeVisible
+//
+// Sets same visibility to bitmap control as image control has.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::MakeVisible( TBool aVisible )
+    {
+    iBitmapControl->MakeVisible( aVisible );
+    
+    CMsgMediaControl::MakeVisible( aVisible );
+    }
+
+// ---------------------------------------------------------
+// CMmsImageControl::PositionChanged
+//
+// Calculates new position to bitmap control as image control position
+// has changed.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::PositionChanged()
+    {
+    iBitmapControl->SetPosition( Position() + CalculateImagePosition() );
+    
+    CMsgMediaControl::PositionChanged();
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::HandleResourceChange
+// ---------------------------------------------------------
+//
+void CMsgImageControl::HandleResourceChange( TInt aType )
+    {
+    CMsgMediaControl::HandleResourceChange( aType ); 
+    
+    if ( aType == KEikDynamicLayoutVariantSwitch )
+        {
+        CalculateMaxSize();
+        
+        if ( iEngine )
+            {
+            TSize sourceSize( iSourceImage->Size() );
+            TSize targetSize = TSize(
+                    Min( sourceSize.iWidth, iMaxSize.iWidth - iFrame->FrameBorderSize().iWidth ),
+                    Min( sourceSize.iHeight, iMaxSize.iHeight - iFrame->FrameBorderSize().iHeight ) );
+            
+            iBitmapControl->SetSize( TSize( 0, 0 ) );
+            SetSize( targetSize );
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CMmsImageControl::CountComponentControls
+//
+// Return count of controls be included in this component.
+// ---------------------------------------------------------
+//
+TInt CMsgImageControl::CountComponentControls() const
+    {    
+    return 2;
+    }
+
+// ---------------------------------------------------------
+// CMmsImageControl::ComponentControl
+//
+// Return pointer to component in question.
+// Note! Image and Icon cannot exist at a same time.
+// ---------------------------------------------------------
+//
+CCoeControl* CMsgImageControl::ComponentControl( TInt aIndex ) const
+    {
+    CCoeControl* result = NULL;
+    switch ( aIndex )
+        {
+        case 0:
+            {
+            result = iFrame;                
+            break;
+            }
+        case 1:
+            {
+            CCoeControl* visiblePlaceholder = VisiblePlaceholder();
+            if ( visiblePlaceholder )
+                {
+                result = visiblePlaceholder;
+                }
+            else
+                {
+                result = iBitmapControl;
+                }
+            break;
+            }
+        default:
+            {
+            break;
+            }
+        }
+        
+    return result;
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::IsOffScreen
+//
+// Returns ETrue if image is off screen.
+// ---------------------------------------------------------
+//
+TBool CMsgImageControl::IsOffScreen() const
+    {
+    TRect rect( Position() + CalculateImagePosition(),
+                iDestinationBitmap->Bitmap().SizeInPixels() );
+    
+    TBool result( EFalse );
+    
+    if ( rect.iTl.iY < 0 || 
+         rect.iBr.iY >  MsgEditorCommons::MsgMainPane().Height() )
+        {
+        result = ETrue;
+        }
+        
+    return result;
+    }
+
+
+// ---------------------------------------------------------
+// CMsgImageControl::ViewerBitmapChangedL
+//
+// Handle bitmap change notifications. State is changed accordingly
+// if this is the first frame. GIF animation is stopped if control
+// goes off screen and started again when it is fully visible and control
+// is on playing state. On editor mode animation is looped only once. 
+// Animation is also stopped if animation loop count is reached.
+// New animation loop is started after KAnimationDelayBetweenLoops
+// delay.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::ViewerBitmapChangedL()
+    {
+    if ( iState == EMsgAsyncControlStateOpening )   
+        {
+        SetState( EMsgAsyncControlStateReady );        
+        
+        if ( iAnimationState == EAnimationPlaying )
+            {
+            SetState( EMsgAsyncControlStatePlaying );
+            }
+        }
+        
+    if ( iSourceImage->IsAnimation() )
+        {
+        switch ( iAnimationState )
+            {
+            case EAnimationPlaying:
+                {   
+                if ( IsOffScreen() )
+                    {
+                    // Stop the playback if animation is not fully visible
+                    StopAnimation();
+                    }
+                else if ( iEngine->AnimationFrame() == 
+                          iSourceImage->AnimationFrameCount() - 1 )
+                    {
+                    // Last frame of the animation has been loaded.
+                    iCurrentLoop++;
+                    
+                    if ( iCurrentLoop == iLoopCount )
+                        {
+                        // Maximum loop count reached. Do not stop yet as first
+                        // frame is wanted to be displayed. Stopping is done on 
+                        // EAnimationStopped state.
+                        iAnimationState = EAnimationStopped;
+                        }
+                    else
+                        {
+                        iEngine->Stop();
+                        
+                        iLoopTimer->Cancel();
+                        iLoopTimer->Start( KAnimationDelayBetweenLoops,
+                                           KAnimationDelayBetweenLoops,
+                                           TCallBack( DoStartLoop, this ) );
+                        }
+                    }
+                break;
+                }
+            case EAnimationStopped:
+                {
+                if( iState == EMsgAsyncControlStatePlaying &&
+                    !IsOffScreen() &&
+                    iCurrentLoop != iLoopCount )
+                    {
+                    StartAnimation( 0 );
+                    }
+                else
+                    {
+                    StopAnimation();
+                    }
+                break;
+                }
+            case EAnimationNotReady:
+            default:
+                {
+                break;
+                }
+            }
+        }
+    
+    iBitmapControl->SetBitmap( iDestinationBitmap );
+    
+    TRect imageRect( Position() + CalculateImagePosition(),
+                     iDestinationBitmap->Bitmap().SizeInPixels() );
+    iBitmapControl->SetRect( imageRect );
+    
+    if( IsVisible() )
+        {
+        // Sometimes iDestinationBitmap is not ready when in SizeChanged()
+        if ( iDestinationBitmap &&  
+             iDestinationBitmap->IsCreated() )
+            {
+            iFrame->SetImageSize( imageRect.Size() );
+            }  
+
+        DrawNow();
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::ViewerError
+//
+// Handles engine errors.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::ViewerError( TInt aError )
+    {
+    MSGMEDIACONTROLLOGGER_WRITEF_ERROR_STATE( _L("CMsgImageControl::HandleCallback: **aError: %d, CurrentState: %S"),aError, iState);
+    
+    iError = aError;
+            
+    switch ( aError )
+        {
+        case KErrNone:
+            {
+            if ( iState == EMsgAsyncControlStateOpening )
+                {
+                // image shown in the viewer and image had rights
+                SetState( EMsgAsyncControlStateReady );
+                DoPlay( 0 );
+                }
+            else if (  iState == EMsgAsyncControlStatePlaying )
+                {
+                SetState( EMsgAsyncControlStateReady );
+                DoPlay( 0 );
+                }
+            break;
+            }
+        case DRMCommon::EGeneralError:
+        case DRMCommon::EUnknownMIME:
+        case DRMCommon::EVersionNotSupported:
+        case DRMCommon::ESessionError:
+        case DRMCommon::ENoRights:
+        case DRMCommon::ERightsDBCorrupted:
+        case DRMCommon::EUnsupported:
+        case DRMCommon::ERightsExpired:
+        case DRMCommon::EInvalidRights:
+            {
+            SetState( EMsgAsyncControlStateNoRights );
+            break;
+            }
+        case KErrNoMemory:  // cannot recover
+        default:
+            {
+            SetState( EMsgAsyncControlStateCorrupt );
+            break;
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::CalculateImagePosition
+//
+// Calculates image position so that it is centered to 
+// control extent.
+// ---------------------------------------------------------
+//
+TPoint CMsgImageControl::CalculateImagePosition() const
+    {
+    TPoint result;
+    
+    TSize controlSize( Size() );
+    TSize imageSize;
+    
+    if ( iEngine )
+        {
+        imageSize = iEngine->SourceSize();
+        imageSize.iWidth *= iEngine->ZoomRatio();
+        imageSize.iHeight *= iEngine->ZoomRatio();
+        }
+    else
+        {
+        // Engine has been unloaded. Use current bitmap control size
+        // as imageSize.
+        imageSize = iBitmapControl->Size();
+        }
+    
+    result.iX = ( controlSize.iWidth - imageSize.iWidth ) / 2;
+    result.iY = ( controlSize.iHeight - imageSize.iHeight ) / 2;
+    
+    if ( result.iX < 0 )
+        {
+        result.iX = 0;
+        }
+    
+    if ( result.iY < 0 )
+        {
+        result.iY = 0;
+        }
+        
+    return result;
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::CalculateControlSize
+//
+// Calculates the correct size for the image control.
+// ---------------------------------------------------------
+//
+TSize CMsgImageControl::CalculateControlSize( const TSize& aProposedSize ) const
+    {
+    TSize result( aProposedSize.iWidth, 0 );
+    TSize bitmapSize = BitmapSize();
+    
+    if ( !bitmapSize.iHeight || !bitmapSize.iWidth )
+        {
+        result.iHeight = aProposedSize.iHeight;
+        return result;
+        }
+    else if ( bitmapSize.iHeight < aProposedSize.iHeight )
+        {
+        result.iHeight = bitmapSize.iHeight;
+        }
+    else
+        {
+        result.iHeight = aProposedSize.iHeight;
+        }
+
+    TInt scaledHeight( 
+        ( static_cast<TReal>( bitmapSize.iHeight ) /
+          static_cast<TReal>( bitmapSize.iWidth ) ) *
+          aProposedSize.iWidth );
+    if ( scaledHeight < result.iHeight )
+        {
+        result.iHeight = scaledHeight;
+        }
+
+    // Height should be multiple of baseline.
+    // Round up to the next full multiple if needed.
+    TInt remainder = result.iHeight % iBaseLine;
+    if ( remainder )
+        {
+        result.iHeight += ( iBaseLine - remainder );
+        }
+        
+    if ( result.iHeight > iMaxSize.iHeight )
+        {
+        result.iHeight = iMaxSize.iHeight;
+        }
+
+    return result;
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::BitmapSize
+// 
+// Returns correct size for bitmap.
+// ---------------------------------------------------------
+//
+TSize CMsgImageControl::BitmapSize() const
+    {
+    TSize bitmapSize( 0, 0 );
+    if ( !iIconControl->IsVisible() &&
+         ( iBitmapControl->Size().iWidth == 0 ||
+           iBitmapControl->Size().iHeight == 0 ) )
+        {
+        if ( iEngine )
+            {
+            bitmapSize = iEngine->SourceSize() ;
+            bitmapSize.iWidth += iFrame->FrameBorderSize().iWidth;
+            bitmapSize.iHeight += iFrame->FrameBorderSize().iHeight;
+            }
+        }
+    else 
+        {
+        // Bitmap or icon visible. 
+        bitmapSize = iFrame->FrameSize();
+        }
+
+    return bitmapSize;
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::DoPlay
+//
+// Starts animation if possible and sets control to correct state.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::DoPlay( TInt aAnimationStartDelay )
+    {
+    StartAnimation( aAnimationStartDelay );
+    
+    if ( iState != EMsgAsyncControlStateOpening )
+        {
+        SetState( EMsgAsyncControlStatePlaying );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::DoPause
+//
+// Stops animation and sets control to correct state.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::DoPause()
+    {
+    StopAnimation();
+    
+    SetState( EMsgAsyncControlStatePaused );
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::CalculateMaxSize
+// ---------------------------------------------------------
+//
+void CMsgImageControl::CalculateMaxSize()
+    {
+    TAknLayoutRect maxSizeLayout;
+    maxSizeLayout.LayoutRect( MsgEditorCommons::MsgDataPane(),
+                              AknLayoutScalable_Apps::msg_data_pane_g1().LayoutLine() );
+    
+    iMaxSize = maxSizeLayout.Rect().Size();
+    
+    // Make sure "iMaxSize" is multiple of "iBaseLine"
+    iMaxSize.iHeight = iBaseLine * ( iMaxSize.iHeight / iBaseLine );
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::HitRegionContains
+// 
+// Note! CONE will do final verification if control is really hit so
+//       not need to do it here.
+// ---------------------------------------------------------
+//
+#ifdef RD_SCALABLE_UI_V2
+TBool CMsgImageControl::HitRegionContains( const TPoint& aPoint, 
+                                     const CCoeControl& /*aControl*/ ) const
+    {
+    TBool result( EFalse );
+    
+    CCoeControl* visiblePlaceholder = VisiblePlaceholder();
+    
+    if ( visiblePlaceholder )
+        {
+        result = visiblePlaceholder->Rect().Contains( aPoint );
+        }
+    else
+        {
+        result = iBitmapControl->Rect().Contains( aPoint );
+        }
+        
+    return result;
+    }
+#else
+TBool CMsgImageControl::HitRegionContains( const TPoint& /*aPoint*/, 
+                                     const CCoeControl& /*aControl*/ ) const
+    {
+    return EFalse;
+    }
+#endif
+
+
+// ---------------------------------------------------------
+// CMsgImageControl::FrameSize
+//
+// Returns the framesize
+// ---------------------------------------------------------
+//
+EXPORT_C TSize CMsgImageControl::FrameSize()
+    {
+    return iFrame->FrameSize();
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::StartAnimation
+//
+// Starts animation if possible.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::StartAnimation( TInt aAnimationStartDelay )
+    {
+    iLoopTimer->Cancel();
+    
+    if ( iEngine && 
+         IsAnimation() && 
+         !IsOffScreen() &&
+         iLoopCount != iCurrentLoop )
+        {    
+        iAnimationState = EAnimationPlaying;
+            
+        if ( aAnimationStartDelay == 0 )
+            {
+            iEngine->Play();
+            }
+        else 
+            {
+            iLoopTimer->Start( aAnimationStartDelay,
+                               aAnimationStartDelay,
+                               TCallBack( DoStartLoop, this ) );
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::StopAnimation
+//
+// Stops animation if possible.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::StopAnimation()
+    {
+    iLoopTimer->Cancel();
+    
+    if ( iEngine &&  
+         IsAnimation() )
+        {
+        iEngine->Stop();
+        iAnimationState = EAnimationStopped;
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::PauseAnimation
+//
+// Pauses animation if possible.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::PauseAnimation()
+    {
+    StopAnimation();
+    iAnimationState = EAnimationPaused;
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::DoStartLoop
+//
+// Start new animation loop.
+// ---------------------------------------------------------
+//
+TInt CMsgImageControl::DoStartLoop( TAny* aObject )
+    {
+    // cast, and call non-static function
+    CMsgImageControl* control = static_cast<CMsgImageControl*>( aObject );
+    control->StartLoop();
+    
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------
+// CMsgImageControl::StartLoop
+//
+// Start new animation loop.
+// ---------------------------------------------------------
+//
+void CMsgImageControl::StartLoop()
+    {
+    if ( iAnimationState == EAnimationPlaying )
+        {
+        StartAnimation( 0 );
+        }
+    else
+        {
+        iLoopTimer->Cancel();
+        }
+    }
+
+//  End of File