--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/scrsaver/scrsaverplugins/ScreenSaverGifAnimPlugin/src/GifAnimationPluginControl.cpp Thu Dec 17 08:46:04 2009 +0200
@@ -0,0 +1,603 @@
+/*
+* Copyright (c) 2005 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: Screensaver GifAnimation plug-in container source file
+*
+*/
+
+
+
+
+
+#include <eikenv.h>
+#include <w32std.h>
+#include <e32base.h>
+#include <e32std.h>
+
+#include <IHLImageFactory.h> // IHLImageFactory
+#include <IHLViewerFactory.h> // IHLViewerFactory
+#include <MIHLImageViewer.h> // MIHLImageViewer
+#include <MIHLFileImage.h> // MIHLFileImage
+#include <MIHLBitmap.h> // MIHLBitmap
+#include <MIHLImageViewer.h> // MIHLImageViewer
+#include <MIHLViewerObserver.h>
+#include <bautils.h>
+
+#include "GifAnimationPlugin.h"
+#include "GifAnimationUtils.h"
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Instance factory
+// ---------------------------------------------------------------------------
+//
+CGifAnimationPluginControl* CGifAnimationPluginControl::NewL(
+ CCoeControl *aParentControl,
+ MPluginAdapter* aPluginAdapter )
+ {
+ ASSERT( aPluginAdapter );
+ DBG_TRACE_FN_BEGIN;
+ CGifAnimationPluginControl* tmp =
+ new ( ELeave )CGifAnimationPluginControl();
+ CleanupStack::PushL( tmp );
+ tmp->ConstructL( aParentControl, aPluginAdapter );
+ CleanupStack::Pop();
+ DBG_TRACE_FN_END;
+ return tmp;
+ }
+
+// ---------------------------------------------------------------------------
+// 2nd phase constructor
+// ---------------------------------------------------------------------------
+//
+void CGifAnimationPluginControl::ConstructL( CCoeControl* aParentControl,
+ MPluginAdapter* aPluginAdapter )
+ {
+ DBG_TRACE_FN_BEGIN;
+
+ iPluginAdapter = aPluginAdapter;
+
+ if ( aParentControl != NULL )
+ {
+ CreateWindowL( aParentControl );
+ }
+ else
+ {
+ CreateWindowL();
+ }
+ ActivateL();
+
+ MakeVisible( ETrue ); // make it invisible for now
+
+ DBG_TRACE_FN_END;
+ }
+
+// ---------------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------------
+//
+CGifAnimationPluginControl::CGifAnimationPluginControl()
+ : iSourceImage( NULL ),
+ iDrawingBitmap( NULL ),
+ iScalingBitmap( NULL ),
+ iScalingBitmapMask( NULL ),
+ iEngine( NULL ),
+ iAnimationState( EAnimationNotReady ),
+ iLastError( KErrNone )
+ {
+ DBG_TRACE_FN_BEGIN;
+ // nothing goes here
+ DBG_TRACE_FN_END;
+ }
+
+// ---------------------------------------------------------------------------
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CGifAnimationPluginControl::~CGifAnimationPluginControl()
+ {
+ DBG_TRACE_FN_BEGIN;
+
+ DeleteAnimation();
+
+ iPluginAdapter = NULL;
+
+ DBG_TRACE_FN_END;
+ }
+
+// ---------------------------------------------------------
+// Loads the image into display.
+// Param aImageFileName image file name - expected to be valid image
+// ---------------------------------------------------------
+//
+void CGifAnimationPluginControl::LoadImageL( const TDesC& aImageFileName )
+ {
+ DBG_TRACE_FN_BEGIN;
+ iFileName.Copy( aImageFileName );
+
+ iLastError = KErrNotReady; // if asked before loading is complete+Draw()
+ TRAPD( error, DoImageLoadingL() );
+ if ( error )
+ {
+ iLastError = error;
+ DeleteAnimation();
+ DBG_TRACE_FN_END;
+ User::Leave( error ); // re-throw it
+ }
+ else
+ {
+ DBG_TRACE( "Animation loaded" );
+ iAnimationState = EAnimationLoading;
+ iLastError = KErrNone;
+ }
+ DBG_TRACE_FN_END;
+ }
+
+// ---------------------------------------------------------
+// Return ETrue if loaded image is animation.
+// ---------------------------------------------------------
+//
+TBool CGifAnimationPluginControl::IsAnimation() const
+ {
+ DBG_TRACE_FN_BEGIN;
+ if ( iSourceImage
+ && iLastError == KErrNone ) // we did not have any error loading picture
+ {
+ DBG_TRACE_FN_END;
+ return iSourceImage->IsAnimation();
+ }
+ DBG_TRACE_FN_END;
+ return EFalse;
+ }
+
+
+// ---------------------------------------------------------
+// Return TInt with image loading error.
+// ---------------------------------------------------------
+//
+TBool CGifAnimationPluginControl::GetLastError() const
+ {
+ DBG_TRACE_FN_BEGIN;
+ //
+ DBG_TRACE_FN_END;
+ return iLastError;
+ }
+
+// ---------------------------------------------------------
+// Start animation.
+// ---------------------------------------------------------
+//
+void CGifAnimationPluginControl::StartAnimationL()
+ {
+ DBG_TRACE_FN_BEGIN;
+
+ if ( iEngine == NULL ) // animation was stopped,
+ { // need to re-load animation file
+ DoImageLoadingL();
+ }
+
+ // start animation
+ if ( iEngine && IsAnimation() )
+ {
+ iEngine->Play();
+ iAnimationState = EAnimationPlaying;
+ }
+
+ DBG_TRACE_FN_END;
+ }
+
+// ---------------------------------------------------------
+// Stop animation.
+// ---------------------------------------------------------
+//
+void CGifAnimationPluginControl::StopAnimation()
+ {
+ DBG_TRACE_FN_BEGIN;
+
+ // bugfix for JPYO-6KXHRW
+ MakeVisible( EFalse );
+
+
+ // instead of just stopping player, we delete it.
+ // This is because of stability issues with the start-stop-destroy cycle
+ DeleteAnimation();
+ DBG_TRACE_FN_END;
+ }
+
+// ---------------------------------------------------------
+// Called when size is changed.
+// ---------------------------------------------------------
+//
+void CGifAnimationPluginControl::SizeChanged()
+ {
+ DBG_TRACE_FN_BEGIN;
+ if ( iEngine )
+ {
+ iEngine->SetViewerSize( Size() );
+ }
+ DBG_TRACE_FN_END;
+ }
+
+// ---------------------------------------------------------------------------
+// Overriden CCoeControl::Draw()
+// ---------------------------------------------------------------------------
+//
+void CGifAnimationPluginControl::Draw( const TRect& /*aRect*/ ) const
+ {
+ //DBG_TRACE_FN_BEGIN;
+ CWindowGc& gc = SystemGc();
+ TRect rect( Rect() );
+
+ DBG_TRACE( "Draw: Clearing background" );
+ gc.Clear( Rect() );
+ gc.SetBrushColor( KRgbBlack );
+ gc.SetBrushStyle( CGraphicsContext::ESolidBrush);
+ gc.DrawRect( rect );
+
+ if ( iDrawingBitmap
+ && iEngine
+ && iLastError == KErrNone ) // loading was successful
+ {
+ TSize screenSize( rect.Size() );
+ TPoint destinationPoint(
+ ( screenSize.iWidth-iTargetNewSize.iWidth ) / 2,
+ ( screenSize.iHeight-iTargetNewSize.iHeight ) / 2 );
+
+ TSize drawingBitmapSize( iDrawingBitmap->Bitmap().SizeInPixels() );
+ if ( drawingBitmapSize.iHeight == iTargetNewSize.iHeight
+ && drawingBitmapSize.iWidth == iTargetNewSize.iWidth )
+ {
+ // we use unscaled version as size is Ok
+ iDrawingBitmap->Draw( gc,
+ destinationPoint,
+ iTargetNewSize );
+ }
+ else
+ {
+ // we use scaled version
+ if ( iDrawingBitmap->HasMask() )
+ {
+ gc.BitBltMasked( destinationPoint,
+ iScalingBitmap,
+ iTargetNewSize,
+ iScalingBitmapMask,
+ EFalse );
+ }
+ else
+ {
+ gc.BitBlt( destinationPoint,
+ iScalingBitmap );
+ }
+ }
+ }
+ else // image is not ready or broken
+ {
+ DBG_TRACE( "image is not ready or broken" );
+ }
+ //DBG_TRACE_FN_END;
+ }
+
+// ---------------------------------------------------------
+// CGifAnimationPluginControl::DoImageLoadingL
+// ---------------------------------------------------------
+//
+void CGifAnimationPluginControl::DoImageLoadingL()
+ {
+ DBG_TRACE_FN_BEGIN;
+
+ RFs& fs = CEikonEnv::Static()->FsSession();
+ TBool fileExists = BaflUtils::FileExists( fs, iFileName );
+ if ( !fileExists )
+ {
+ DBG_TRACE_FN_END;
+ User::Leave( KErrPathNotFound );
+ }
+
+
+ RFile fileHandle;
+ CleanupClosePushL( fileHandle );
+ iLastError = fileHandle.Open( fs, iFileName, EFileRead | EFileShareReadersOnly );
+ User::LeaveIfError(iLastError);
+
+ // delete old instances, if any
+ DeleteAnimation();
+
+ // create new objects
+ if ( iDrawingBitmap == NULL )
+ {
+ iDrawingBitmap = IHLBitmap::CreateL();
+ }
+
+ TInt drmOption( 0 );
+ if ( isPreviewMode )
+ {
+ drmOption = MIHLFileImage::EOptionNoDRMConsume;
+ }
+ iSourceImage = IHLImageFactory::OpenFileImageL( fileHandle,
+ 0, // image index
+ drmOption );
+
+ // calculate target size so that picture fits the screen and centered
+ TSize sourceSize( iSourceImage->Size() );
+ TSize maxSize = Size();
+
+ iTargetSize = TSize( Min( sourceSize.iWidth, maxSize.iWidth ),
+ Min( sourceSize.iHeight, maxSize.iHeight ) );
+
+ if ( sourceSize.iWidth < maxSize.iWidth
+ && sourceSize.iHeight < maxSize.iHeight )
+ {
+ // scale up N-times
+ TInt upScale = Min( maxSize.iWidth / sourceSize.iWidth,
+ maxSize.iHeight / sourceSize.iHeight );
+ iTargetSize = TSize( sourceSize.iWidth * upScale,
+ sourceSize.iHeight * upScale );
+ const TUint32 options( 0 ); // no flags set
+ // we do not want IHL do scaling, so targetSize= sourceSize
+ iEngine = IHLViewerFactory::CreateImageViewerL( sourceSize,
+ *iSourceImage,
+ *iDrawingBitmap,
+ *this,
+ options );
+ iTargetNewSize = iTargetSize;
+ }
+ else
+ {
+ //The image needs to be scaled down. We pass the target size to
+ //IHL so that it doesn't come back with an OOM situation in case
+ //the resolution is too high.
+ // scale up N-times
+ TReal downScale = Min( TReal(maxSize.iWidth) / TReal(sourceSize.iWidth),
+ TReal(maxSize.iHeight) / TReal(sourceSize.iHeight) );
+ iTargetSize = TSize( sourceSize.iWidth * downScale,
+ sourceSize.iHeight * downScale );
+ const TUint32 options( 0 ); // no flags set
+ TReal widthRatio( TReal( iTargetSize.iWidth ) / TReal( sourceSize.iWidth ) );
+ TReal heightRatio( TReal( iTargetSize.iHeight ) / TReal( sourceSize.iHeight ) );
+ if( options & MIHLImageViewer::EOptionIgnoreAspectRatio )
+ {
+ downScale = ( widthRatio > heightRatio ) ? widthRatio : heightRatio;
+ }
+ else
+ {
+ downScale = ( widthRatio < heightRatio ) ? widthRatio : heightRatio;
+ }
+ TReal widthZoomRatio( downScale );
+ TReal heightZoomRatio( downScale );
+ if( options & MIHLImageViewer::EOptionIgnoreAspectRatio )
+ {
+ TReal widthRatio( TReal( iTargetSize.iWidth ) / TReal( sourceSize.iWidth ) );
+ TReal heightRatio( TReal( iTargetSize.iHeight ) / TReal( sourceSize.iHeight ) );
+ if( widthRatio < heightRatio )
+ {
+ widthZoomRatio = widthZoomRatio * widthRatio / heightRatio;
+ }
+ else
+ {
+ heightZoomRatio = heightZoomRatio * heightRatio / widthRatio;
+ }
+ }
+ iTargetNewSize = TSize( sourceSize.iWidth * widthZoomRatio,
+ sourceSize.iHeight * heightZoomRatio );
+ // we do not want IHL do scaling, so targetSize= sourceSize
+ iEngine = IHLViewerFactory::CreateImageViewerL( iTargetSize,
+ *iSourceImage,
+ *iDrawingBitmap,
+ *this,
+ options );
+ }
+
+ // create bitmaps needed for manual scaling
+ TDisplayMode dMode = CEikonEnv::Static()->DefaultDisplayMode();
+ if ( iScalingBitmap == NULL )
+ {
+ iScalingBitmap = new( ELeave ) CFbsBitmap;
+ iScalingBitmap->Create( iTargetSize, dMode );
+ }
+
+ if ( iScalingBitmapMask == NULL )
+ {
+ iScalingBitmapMask = new( ELeave ) CFbsBitmap;
+ iScalingBitmapMask->Create( iTargetSize, dMode );
+ }
+
+ CleanupStack::PopAndDestroy( &fileHandle );
+ DBG_TRACE_FN_END;
+ }
+
+// ---------------------------------------------------------
+// CGifAnimationPluginControl::CheckFileIsValidL
+// ---------------------------------------------------------
+//
+void CGifAnimationPluginControl::CheckFileIsValidL(
+ const TDesC& aImageFileName )
+ {
+ DBG_TRACE_FN_BEGIN;
+
+ ASSERT( aImageFileName.Size() );
+ CGifAnimationPluginControl* temp =
+ new ( ELeave )CGifAnimationPluginControl();
+ CleanupStack::PushL( temp );
+ temp->SetSize( TSize( 100, 100 ) );
+ temp->SetPreviewMode();
+ temp->LoadImageL( aImageFileName );
+ temp->DeleteAnimation();
+ CleanupStack::PopAndDestroy( temp );
+
+ DBG_TRACE_FN_END;
+ }
+
+// ---------------------------------------------------------
+// CGifAnimationPluginControl::DeleteAnimation
+// ---------------------------------------------------------
+//
+void CGifAnimationPluginControl::DeleteAnimation()
+ {
+ DBG_TRACE_FN_BEGIN;
+ if ( iEngine )
+ {
+ iAnimationState = EAnimationNotReady;
+ iEngine->Stop();
+ delete iEngine;
+ iEngine = NULL;
+ }
+
+ if ( iSourceImage )
+ {
+ delete iSourceImage;
+ iSourceImage = NULL;
+ }
+
+ if ( iDrawingBitmap )
+ {
+ delete iDrawingBitmap;
+ iDrawingBitmap = NULL;
+ }
+
+ if ( iScalingBitmap )
+ {
+ delete iScalingBitmap;
+ iScalingBitmap = NULL;
+ }
+
+ if ( iScalingBitmapMask )
+ {
+ delete iScalingBitmapMask;
+ iScalingBitmapMask = NULL;
+ }
+
+
+ DBG_TRACE_FN_END;
+ }
+
+// ---------------------------------------------------------
+// Handle bitmap change notifications. State is changed accordingly
+// if this is the first frame.
+// ---------------------------------------------------------
+//
+void CGifAnimationPluginControl::ViewerBitmapChangedL()
+ {
+ if ( iSourceImage )
+ {
+ switch ( iAnimationState )
+ {
+ case EAnimationLoading:
+ {
+ iAnimationState = EAnimationPlaying;
+ break;
+ }
+ case EAnimationPlaying:
+ {
+ // do nothing
+ break;
+ }
+ case EAnimationNotReady:
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ if( iAnimationState == EAnimationPlaying )
+ {
+ if ( iDrawingBitmap
+ && iEngine
+ && iLastError == KErrNone ) // loading was successful
+ {
+ TSize drawingBitmapSize( iDrawingBitmap->Bitmap().SizeInPixels() );
+ if ( drawingBitmapSize.iHeight == iTargetNewSize.iHeight
+ && drawingBitmapSize.iWidth == iTargetNewSize.iWidth )
+ {
+ // we do not need to do scaling
+ }
+ else
+ {
+ // we need to do scaling
+ CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL( iScalingBitmap );
+ CleanupStack::PushL(bitmapDevice);
+ CFbsBitGc* graphicsContext = NULL;
+ User::LeaveIfError( bitmapDevice->CreateContext( graphicsContext ) );
+ CleanupStack::PushL( graphicsContext );
+ TRect srcRect( iSourceImage->Size() );
+ graphicsContext->DrawBitmap( iTargetSize, &iDrawingBitmap->Bitmap(), srcRect );
+ CleanupStack::PopAndDestroy( 2 );//graphicsContext,bitmapDevice
+
+ if ( iDrawingBitmap->HasMask() )
+ {
+ CFbsBitmapDevice* bitmapMaskDevice = CFbsBitmapDevice::NewL( iScalingBitmapMask );
+ CleanupStack::PushL(bitmapMaskDevice);
+ CFbsBitGc* graphicsMaskContext = NULL;
+ User::LeaveIfError( bitmapMaskDevice->CreateContext( graphicsMaskContext ) );
+ CleanupStack::PushL( graphicsMaskContext );
+ graphicsContext->DrawBitmap( iTargetSize, &iDrawingBitmap->Mask(), srcRect );
+ CleanupStack::PopAndDestroy( 2 );//graphicsContext,bitmapDevice
+ }
+ }
+ }
+
+ MakeVisible( ETrue );
+ DrawNow();
+ }
+ }
+
+// ---------------------------------------------------------
+// Handles engine errors.
+// ---------------------------------------------------------
+//
+void CGifAnimationPluginControl::ViewerError( TInt aError )
+ {
+ DBG_TRACE_FN_BEGIN;
+ iLastError = aError;
+ HandleCallback( aError );
+ DBG_TRACE_FN_END;
+ }
+
+
+// ---------------------------------------------------------
+// Handles error codes; stores the error
+// ---------------------------------------------------------
+//
+void CGifAnimationPluginControl::HandleCallback( TInt aError )
+ {
+ DBG_TRACE_FN_BEGIN;
+
+ if ( aError )
+ {
+ InformPluginFinished();
+ }
+
+ DBG_TRACE_FN_END;
+ }
+
+
+// ---------------------------------------------------------
+// Informs that plug-in wants to terminate
+// ---------------------------------------------------------
+//
+void CGifAnimationPluginControl::InformPluginFinished()
+ {
+
+ ASSERT( iPluginAdapter );
+
+ StopAnimation();
+
+ TRAP_IGNORE(iPluginAdapter->PluginFinishedL());
+ }
+
+void CGifAnimationPluginControl::SetPreviewMode()
+ {
+ isPreviewMode = ETrue;
+ }