mmplugins/imagingplugins/bitmaptransform/src/refplugin/BitmapScalerPlugin.cpp
changeset 0 40261b775718
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/imagingplugins/bitmaptransform/src/refplugin/BitmapScalerPlugin.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,1851 @@
+// Copyright (c) 2002-2009 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:
+//
+
+#include "BitmapTransformsPlugin.h"
+
+#include "BitmapConverter.h"
+#include <bitmtrans/bitmtranspanic.h>
+#include <e32math.h>
+
+const TInt KFixedPointBits = 4;
+const TInt KFixedPointScale = (1 << KFixedPointBits);
+const TInt KLinesPerCall = 10;
+const TInt KBitsPerByte = 8;
+
+/*
+*The function NewL constructs a CBitmapScalerPlugin
+*
+*@return CBitmapScalerPlugin* 
+*/
+MBitmapScalerPlugin* CBitmapScalerPlugin::NewL()
+	{
+	CBitmapScalerPlugin* self = new(ELeave) CBitmapScalerPlugin();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/*
+*
+*CBitmapScalerPlugin()
+*Constructor for this class. Adds itself to CActiveScheduler.
+*/
+CBitmapScalerPlugin::CBitmapScalerPlugin()
+	: CActive(CActive::EPriorityIdle), iOrigDes(NULL, 0), iDestDes(NULL, 0),
+	iQualityLevel(CBitmapScaler::EMaximumQuality)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+/*
+*
+*ConstructL()
+*Performs second phase of construction.
+*/
+void CBitmapScalerPlugin::ConstructL()
+	{
+	iScanlineBitmap = new(ELeave) CFbsBitmap;
+
+	SetPostProcessingEnabled(ETrue);	
+	ASSERT( GetCurrentState() == EInactiveState );
+	}
+
+
+/*
+*
+*~CBitmapScalerPlugin
+*This is the destructor for the CBitmapScalerPlugin 
+*and is resposible for deallocating all resources 
+*allocated by the CBitmapScalerPlugin.
+*/
+CBitmapScalerPlugin::~CBitmapScalerPlugin()
+	{
+	Cancel();
+	Cleanup();
+
+	delete iScanlineBitmap;
+
+	// should have been deleted by cleanup
+	ASSERT(iScaleBitmap==NULL || !(iFlags & EScaleBitmapIsOwned));
+	ASSERT(iFilterIndexTable==NULL);
+	ASSERT(iFilterCoeffsTable==NULL);
+	ASSERT(iDevice==NULL);
+	ASSERT(iGc==NULL);
+	ASSERT(iPostProcessBitmap == NULL );
+	ASSERT(iBitmapConverter == NULL );
+	ASSERT( GetCurrentState() == EInactiveState );
+	}
+
+/*
+*This function performs deallocation of memory allocated by the class
+*which is allocated on each scale as opposed to the entire liftime
+*of the scaler object.
+*/
+void CBitmapScalerPlugin::Cleanup()
+	{
+	delete[] iFilterIndexTable; 
+	iFilterIndexTable = NULL;
+	delete[] iFilterCoeffsTable; 
+	iFilterCoeffsTable = NULL;
+
+	if (iOrigDes.Length() != 0)	// Test is required to avoid PANIC 45
+		{
+		User::Free( reinterpret_cast<TAny*>( const_cast<TUint8*>( iOrigDes.Ptr() ) ) );
+		iOrigDes.SetLength(0);
+		}
+
+	if (iDestDes.Length() != 0)	// Test is required to avoid PANIC 45
+		{
+		User::Free( reinterpret_cast<TAny*>( const_cast<TUint8*>( iDestDes.Ptr() ) ) );
+		iDestDes.SetLength(0);
+		}
+
+	if (iFlags & ECreatedTempBitmap)
+		{
+		delete iTempBitmap; 
+		iTempBitmap = NULL;
+		iFlags &= ~ECreatedTempBitmap;
+		}
+
+	// Reset the EIsSourceBitmapResized flag here
+	if (iFlags & EIsSourceBitmapResized)
+		{
+		iFlags &= ~EIsSourceBitmapResized;
+		ASSERT((iFlags & EIsSourceBitmapResized) == 0);
+		}
+
+	// Only delete the scale bitmap if we created it.
+	if (iFlags & EScaleBitmapIsOwned)
+		{
+		delete iScaleBitmap;
+		iFlags &= ~EScaleBitmapIsOwned;
+		}
+	iScaleBitmap = NULL;
+
+	delete iGc; 
+	iGc = NULL;
+	delete iDevice; 
+	iDevice = NULL;
+	iDestBmpPtr = NULL; // we don't own it
+	delete iPostProcessBitmap; 
+	iPostProcessBitmap = NULL;
+	delete iBitmapConverter;
+	iBitmapConverter = NULL;
+	SetCurrentState( EInactiveState );
+	}
+
+/*
+* Allocates some memory and assigns a pointer to it.
+* @param aPtr Pointer to the allocated memory
+* @param aAllocSize The size in bytes of the memory to allocate
+* @pre aAllocSize >= 0
+* @pre InVariant
+*/
+TInt CBitmapScalerPlugin::AllocPtr( TPtr8& aPtr, TInt aAllocSize )
+	{
+	//[ preconditions ]
+	ASSERT(aAllocSize >= 0 );
+	ASSERT(InVariant());
+
+	TInt rc = KErrNone;
+
+	// User::Alloc() returns NULL if no memory
+	TUint8* addr = static_cast<TUint8*>(User::Alloc(aAllocSize + sizeof(TUint32) ));
+	if (addr)
+		{
+		// coverity [memory_leak]
+		addr = reinterpret_cast<TUint8*>( _ALIGN_UP(TLinAddr(addr), sizeof(TUint32)) );
+		aPtr.Set(addr, aAllocSize, aAllocSize);
+		}
+	else
+		{
+		rc = KErrNoMemory;
+		}
+	
+	return rc;
+	}
+
+// MBitmapScalerPlugin::Cancel() calls CActive::Cancel()
+void CBitmapScalerPlugin::Cancel()
+	{
+	CActive::Cancel();
+	}
+
+/*
+*
+* ScaleRequestPostcondition
+* @return 'ETrue' when post conditions for scale request are 
+* correct
+*
+*/
+TBool CBitmapScalerPlugin::ScaleRequestPostcondition() const 
+	{
+	TBool result = ETrue;
+
+	if (QualityAlgorithm() != CBitmapScaler::EMaximumQuality )
+		{
+		if(	( iFinalOffset != iDestSize.iHeight ) ||
+			( iFilterIndexTable != NULL ) ||
+			( iFilterCoeffsTable != 0 ) )
+			{
+			result = EFalse;
+			}
+		}
+	else
+		{
+		// Using the original (maximum quality) algorithm
+		if(	( iFlags & EVerticalScan) ||
+			( iFilterIndexTable == NULL ) ||
+			( iFinalOffset != iOrigSize.iHeight ) ||
+			( iFilterCoeffsTable == 0 ) )
+			{
+			result = EFalse;
+			}
+
+	if (( iDevice == NULL ) ||
+		( iScanlineBitmap->Handle() == 0 ) ||
+		( iCurOffset != 0 ))
+		{
+		result = EFalse;
+			}			
+		}
+
+	return result;
+	}
+
+/**
+ *
+ * Begins the bitmap re-scaling operation.
+ *
+ * The scaling factor is based on the relative value of the source bitmap
+ * size and the explicitly supplied size. The operation is asynchronous.
+ * When it is complete, successfully or otherwise, the
+ * <code>TRequestStatus</code>& is set, passing the state of the operation.
+ *
+ * @param     "TRequestStatus* aRequestStatus"
+ *
+ * @param     "CFbsBitmap& aBitmap"
+ *            The bitmap to be re-scaled. This reference is also the
+ *            target location for the re-scaled bitmap.
+ * @param     "const TSize& aDestinationSize"
+ *            The requested target size for the re-scaled bitmap.
+ * @param     "TBool aMaintainAspectRatio = ETrue"
+ *            <code>ETrue</code> - the aspect ratio is retained;
+ *            this is the default. The same scaling factor is
+ *            applied in both the horizontal and vertical
+ *            directions. This is the smaller of the horizontal
+ *            scaling factor and the vertical scaling factor.
+ *            <code>EFalse</code> - the aspect ratio need not be
+ *            retained.
+ *
+ */
+void CBitmapScalerPlugin::Scale(TRequestStatus* aRequestStatus,
+									 CFbsBitmap& aBitmap,
+									 const TSize& aDestinationSize,
+									 TBool aMaintainAspectRatio)
+	{
+	//[ assert preconditions ]
+	// [ panic if aRequestStatus is NULL ]
+	__ASSERT_ALWAYS( (aRequestStatus != NULL), Panic( EBadArgumentScale ) );
+
+	//[ panic if the src has not been created]
+	__ASSERT_ALWAYS( (aBitmap.Handle() != 0), Panic( ENoSourceBitmap ) );
+	
+	iScaleStatus = aRequestStatus;
+	*iScaleStatus = KRequestPending;
+
+	if(aBitmap.ExtendedBitmapType()!=KNullUid)
+        {
+        RequestComplete(KErrNotSupported);
+        return;
+        }
+
+	// Set up the sizes before they're lost
+	iOrigSize = aBitmap.SizeInPixels();
+	iDestSize = aDestinationSize;
+
+	// Dithering is not required if the tgt's display mode
+	// is none of EGray256, EColor16M, EColor16MU, EColor16MA
+	TBool dither = ETrue;
+	iTgtDisplayMode = aBitmap.DisplayMode();
+	if ((iTgtDisplayMode == EGray256) ||
+		(iTgtDisplayMode == EColor16M) ||
+		(iTgtDisplayMode == EColor16MA)||
+		(iTgtDisplayMode == EColor16MU) )
+		{
+		dither = EFalse;
+		}
+
+	// Create a temporary bitmap if we're not using the low memory algorithm
+	// OR if we're using the low memory algorithm AND dithering
+	TInt leaveErr = KErrNone;
+	if (!UseLowMemoryAlgorithm() || 
+		(UseLowMemoryAlgorithm() && dither) )
+		{
+		if (iFlags & ECreatedTempBitmap)
+			{
+			delete iTempBitmap;
+			iTempBitmap = NULL;
+			iFlags &= ~ECreatedTempBitmap;
+			}
+
+		iTempBitmap = new CFbsBitmap;
+
+		if (iTempBitmap != NULL)
+			{
+			// iTempBitmap has been created so flag that it needs to be deleted
+			iFlags |= ECreatedTempBitmap;
+			leaveErr = iTempBitmap->Create(aDestinationSize, iTgtDisplayMode);
+			}
+		else
+			{
+			// No memory to new the temp bitmap
+			leaveErr = KErrNoMemory;
+			}
+		}
+	
+	if (leaveErr == KErrNoMemory ||
+		(UseLowMemoryAlgorithm() && !dither) )
+		{
+		// Either failed to create the tempbitmap OR
+		// we explicitly want to use the low-memory algorithm.
+		// Either way use the source directly in the manner of the low-memory algorithm.
+		// Check if we need to delete the tempbitmap 
+		if (iFlags & ECreatedTempBitmap)
+			{
+			delete iTempBitmap;
+			iTempBitmap = NULL;
+			iFlags &= ~ECreatedTempBitmap;
+			}
+		iTempBitmap = &aBitmap;
+		iFlags |= EIsSourceBitmapResized;
+		}
+	else if (leaveErr != KErrNone)
+		{
+		iScaleStatus = aRequestStatus;
+		*iScaleStatus = KRequestPending;
+		ProcessError(leaveErr);
+		return;
+		}
+
+	Scale(aRequestStatus, aBitmap, *iTempBitmap, aMaintainAspectRatio);
+	}
+
+/*
+ *
+ * Begins the bitmap re-scaling operation.
+ *
+ * The scaling factor is based on the relative sizes of the source
+ * and target bitmaps. The operation is asynchronous. When it is
+ * complete, successfully or otherwise, the TRequestStatus &
+ * aStatus is set, passing the state of the operation.
+ *
+ * @param     TRequestStatus* aRequestStatus
+ *
+ * @param     "CFbsBitmap& aSrcBitmap"
+ *            The bitmap to be re-scaled.
+ * @param     "CFbsBitmap& aTgtBitmap"
+ *            The target location for the re-scaled bitmap.
+ * @param     "TBool aMaintainAspectRatio = ETrue"
+ *            ETrue  - the aspect ratio is retained;
+ *            this is the default. The same scaling factor is
+ *            applied in both the horizontal and vertical
+ *            directions. This is the smaller of the horizontal
+ *            scaling factor and the vertical scaling factor.
+ *             EFalse  - the aspect ratio need not be
+ *            retained.
+ *
+ *
+ */
+void CBitmapScalerPlugin::Scale(TRequestStatus* aRequestStatus,
+							  CFbsBitmap& aSrcBitmap,
+							  CFbsBitmap& aTgtBitmap,
+							  TBool aMaintainAspectRatio)
+	{
+	// [ precondition checking on arguments ]
+	// [ panic if aRequestStatus is NULL ]
+	__ASSERT_ALWAYS( (aRequestStatus != NULL), Panic( EBadArgumentScale ) );
+	
+	//[ panic if the src has not been created]
+	__ASSERT_ALWAYS( (aSrcBitmap.Handle() != 0), Panic( ENoSourceBitmap ) );
+	
+	//[ panic if the tgt has not been created]
+	__ASSERT_ALWAYS( (aTgtBitmap.Handle() != 0), Panic( ENoDestinationBitmap ) );
+
+	iScaleStatus = aRequestStatus;
+	*iScaleStatus = KRequestPending;
+
+	//[ current state must be inactive ]
+	if( GetCurrentState() != EInactiveState )
+		{
+		ProcessError( KErrGeneral );
+		return;
+		}
+		
+	ASSERT(iDevice==NULL);
+	
+	if(aSrcBitmap.ExtendedBitmapType()!=KNullUid || aTgtBitmap.ExtendedBitmapType()!=KNullUid)
+        {
+        RequestComplete(KErrNotSupported);
+        return;
+        }
+	
+	iSrcBitmap = &aSrcBitmap;
+	iTgtBitmap = &aTgtBitmap;
+
+	if (!(iFlags & EIsSourceBitmapResized))
+		{
+		// As we're not scaling directly to the source bitmap
+		// we can determine the scaling sizes here (otherwise
+		// we'd overwrite the values that we got prior to setting
+		// the tgtBitmap to the srcBitmap!!)
+		iOrigSize = iSrcBitmap->SizeInPixels();
+		iDestSize = iTgtBitmap->SizeInPixels();
+		}
+
+	TInt err = KErrNone;
+
+	// Target's colour depth
+	iTgtDisplayMode = iTgtBitmap->DisplayMode();
+
+	// Check the aspect ratio and adjust the resolution if needed
+	if (aMaintainAspectRatio)
+		{
+		//[ update destination height to preserve aspect ratio ]
+	    HeightAndWidthPreservingAspectRatio( iDestSize, iOrigSize );
+		}
+
+	iIntermediateSize.iWidth = iDestSize.iWidth;
+	if ( QualityAlgorithm() != CBitmapScaler::EMaximumQuality )
+		{
+		// Using one of the lower quality algorithms so use the destination size
+		// that we are scaling to.
+		iIntermediateSize.iHeight = iDestSize.iHeight;
+		}
+	else
+		{
+		// Using the original algorithm (which firstly scales horizontally to
+		// an intermediate bitmap), so the intermediate size requires the original
+		// height unchanged.
+		iIntermediateSize.iHeight = iOrigSize.iHeight;
+		}
+
+	// if either of the destination dimension is zero then 
+	// complete with KErrNone
+	if ((iDestSize.iWidth == 0) ||
+		(iDestSize.iHeight == 0))
+		{
+		ProcessError(KErrNone);
+		return;
+		}
+
+	// if either of the source dimension is zero then send back an error 
+	if ((iOrigSize.iWidth == 0) || 
+		(iOrigSize.iHeight == 0)) 
+		{
+		ProcessError( KErrArgument );
+		return;
+		}
+
+	// Scale to bitmap of display mode EColor16M except for 
+	// target bitmaps of EGray256, EColor16MU and EColor16MA
+	if ( (iTgtDisplayMode == EGray256) || (iTgtDisplayMode == EColor16MU) 
+			|| (iTgtDisplayMode == EColor16MA))
+		{
+		iLocalDisplayMode = iTgtDisplayMode;
+		}
+	else
+		{
+		iLocalDisplayMode = EColor16M;
+		}
+
+	if (iTgtDisplayMode != EColor16M && iTgtDisplayMode != EColor16MA && iTgtDisplayMode != EColor16MU)
+		{
+		// Create an intermediate bitmap to scale to for cases other than EColor16M
+		if (iScaleBitmap == NULL)
+			{
+			// Only want one instance of iScaleBitmap
+			iScaleBitmap = new CFbsBitmap;
+			iFlags |= EScaleBitmapIsOwned;	// flag that we're the owner of the scale bitmap
+			if (iScaleBitmap == NULL)
+				{
+				err = KErrNoMemory;
+				}
+			}
+		if( err != KErrNone )
+			{
+			ProcessError( err );
+			return;
+			}
+
+		err = iScaleBitmap->Create(iIntermediateSize, iLocalDisplayMode);
+
+		if( err != KErrNone )
+			{
+			ProcessError( err );
+			return;
+			}
+			
+		iDestBmpPtr = iScaleBitmap;
+		}
+	else
+		{
+		// For EColor16M scale directly to TgtBitmap
+		iScaleBitmap = iTgtBitmap;
+
+		// Downscaling one bitmap to another requires 
+		// the scale bitmap to be resized to ensure that
+		// the correct amount of data is read from the source.
+		if (!(iFlags & EIsSourceBitmapResized))
+			{
+			err = iScaleBitmap->Resize(iIntermediateSize);
+			if (err != KErrNone)
+				{
+				ProcessError(err);
+				return;
+				}
+			}
+		}
+
+	iComponentsPerPixel = TDisplayModeUtils::NumDisplayModeBitsPerPixel(iLocalDisplayMode) / KBitsPerByte;
+	if (iComponentsPerPixel == 0)
+		{
+		iComponentsPerPixel = 1;
+		}
+
+		iSrcY = 0;
+	if (iDestSize.iHeight < iOrigSize.iHeight)
+		{
+		iCurY = 0;
+		}
+	else
+		{
+		iCurY = (iOrigSize.iHeight << KFixedPointScale);
+		}
+
+	if (QualityAlgorithm() == CBitmapScaler::EMaximumQuality)
+		{
+		// Try to create and size the scanline bitmap here instead of in the ConstructL
+	if ((err = iScanlineBitmap->Create(TSize(1, iDestSize.iHeight), iLocalDisplayMode)) != KErrNone)
+		{
+		ProcessError(err);
+		return;
+		}
+		}
+
+	// Upscaling so ensure we're writing to a suitably
+	// large target
+	TInt newWidth = iTgtBitmap->SizeInPixels().iWidth;
+	TInt newHeight = iTgtBitmap->SizeInPixels().iHeight;
+	
+	TBool needsResize = EFalse;
+	if(iDestSize.iWidth > iOrigSize.iWidth)
+		{
+		newWidth = iDestSize.iWidth;
+		needsResize = ETrue;
+		}
+		
+	if(iDestSize.iHeight > iOrigSize.iHeight)
+		{
+		newHeight = iDestSize.iHeight;	
+		needsResize = ETrue;
+		}
+		
+	if(needsResize)
+		{
+		err = iTgtBitmap->Resize(TSize(newWidth, newHeight));
+			
+		if( err != KErrNone )
+			{
+			ProcessError(err);
+			return;
+			}	
+		}
+
+	if (QualityAlgorithm() == CBitmapScaler::EMaximumQuality)
+		{
+		// [Create device for normal condition where target bitmap is the
+		// destination]
+	TRAP(err, iDevice = CFbsBitmapDevice::NewL(iTgtBitmap));
+	if( err != KErrNone )
+		{
+		ProcessError(KErrNoMemory);
+		return;
+			}
+		}
+
+	iDestBmpPtr = iTgtBitmap;
+
+	SetProcessingNeeded( EFalse );
+
+	//[ Is Post processing required ]
+	if( ( iTgtDisplayMode != EColor16M) && 
+		( iTgtDisplayMode != EColor16MU) &&
+		( iTgtDisplayMode != EColor16MA) &&
+		( iTgtDisplayMode != EGray256) &&
+		(! IsPostProcessingDisabled() )  ||
+		((iTgtDisplayMode == EGray256) && (QualityAlgorithm() != CBitmapScaler::EMaximumQuality) &&
+											(iLocalDisplayMode != EGray256))
+		)
+		{
+		SetProcessingNeeded( ETrue );	
+		
+		//[ create a bitmap converter to colour quantize the image
+		// to the number of colours available in the output
+		// note CFbsBitmap has a private constructor whence new is not
+		//used ]
+		TRAP(err, iBitmapConverter = CBitmapConverter::NewL());
+		if(err != KErrNone )
+			{
+			ProcessError(err);
+			return;
+			}
+		
+		//[ create a post processing bitmap]
+		iPostProcessBitmap = new CFbsBitmap;
+		if( iPostProcessBitmap == NULL )
+			{
+			err = KErrNoMemory;
+			ProcessError(err);
+			return;
+			}
+		
+		//[ size the post processing bitmap ]
+		if ((err = iPostProcessBitmap->Create(iDestSize, EColor16M )) != KErrNone)
+			{
+			ProcessError(err);
+			return;
+			}
+		
+		// Create device with post processing bitmap as the target
+		delete iDevice;
+		iDevice = NULL;
+		iDestBmpPtr = NULL;
+		if (QualityAlgorithm() == CBitmapScaler::EMaximumQuality)
+			{
+		TRAP(err, iDevice = CFbsBitmapDevice::NewL(iPostProcessBitmap));
+		if( err != KErrNone )
+			{
+			ProcessError(err);
+			return;
+				}			
+			}
+		iDestBmpPtr = iPostProcessBitmap;
+		}
+	
+	iCurOffset = 0;
+	iCurOffsetUp = iDestSize.iHeight;
+	if (QualityAlgorithm() != CBitmapScaler::EMaximumQuality)
+		{
+		// Using one of the lower quality algorithms
+		iFinalOffset = iDestSize.iHeight;
+		if (iTgtBitmap->SizeInPixels() != iDestSize && iTgtBitmap->Handle() != iSrcBitmap->Handle())
+			{
+			err = iTgtBitmap->Resize(iDestSize);
+			if( err != KErrNone )
+				{
+				ProcessError(err);
+				return;
+				}
+			}
+		}
+	else
+		{
+		// We're using the original scaling algorithm
+		// Set Horizontal Scan flag
+		iFlags &= ~EVerticalScan;
+		iFinalOffset = iOrigSize.iHeight;
+		iCurLineSize = iOrigSize.iWidth;
+
+		// Set up filter tables
+		err = FilterTables();
+		if( err != KErrNone )
+			{
+			ProcessError( err );
+			return;
+			}
+		}
+
+	// Allocate the buffers
+	TInt allocErr = AllocPtr( iOrigDes, iOrigSize.iWidth * iComponentsPerPixel );
+	if (allocErr == KErrNone)
+		{
+		allocErr = AllocPtr( iDestDes, iDestSize.iWidth * iComponentsPerPixel );
+		}
+
+	if( allocErr != KErrNone )
+		{
+		ProcessError(allocErr);
+		return;
+		}
+	
+	if (QualityAlgorithm() == CBitmapScaler::EMaximumQuality)
+		{
+		err = iDevice->CreateContext(iGc);
+		}
+
+	if (err != KErrNone)
+		{
+		ProcessError(err);
+		return;
+		}
+
+	//[ set state to scaling ]
+	SetCurrentState(EScalingState);
+
+	//[ assert post conditions of scale request ]
+	ASSERT( ScaleRequestPostcondition() );
+
+	// Start the active object
+	SelfComplete(KErrNone);
+	}
+
+/*
+*
+* FilterTables
+* Initialise the filter tables
+*
+*/
+TInt CBitmapScalerPlugin::FilterTables()
+	{
+	TInt result = KErrNone;
+	
+	ASSERT(iFilterCoeffsTable==NULL);
+	ASSERT(iFilterIndexTable==NULL);
+	
+	if (iDestSize.iWidth > iDestSize.iHeight)
+		{
+		iFilterIndexNum = 2 * iDestSize.iWidth;
+		}
+	else
+		{
+		iFilterIndexNum = 2 * iDestSize.iHeight;
+		}
+
+	if (iDestSize.iWidth > iOrigSize.iWidth) 
+		{
+		iFilterCoeffsNum = iDestSize.iWidth;
+		}
+	else
+		{
+		iFilterCoeffsNum = 2 * iOrigSize.iWidth;
+		}
+	
+	TInt filterCoeffsNumVert;
+	
+	if (iDestSize.iHeight > iOrigSize.iHeight)
+		{
+		filterCoeffsNumVert = iDestSize.iHeight;
+		}
+	else
+		{
+		filterCoeffsNumVert = 2 * iOrigSize.iHeight;
+		}
+	
+	if (filterCoeffsNumVert > iFilterCoeffsNum)
+		{
+		iFilterCoeffsNum = filterCoeffsNumVert;
+		}
+
+	//[ allocate a filter index table and check for memory alloc failure]
+	iFilterIndexTable = new TInt[iFilterIndexNum];
+	if( iFilterIndexTable  == NULL )
+		{
+		return KErrNoMemory;
+		}
+	
+	//[ alloc filter coefficient table and check for memory alloc failure]
+	iFilterCoeffsTable = new TInt[iFilterCoeffsNum];
+	if( iFilterCoeffsTable == NULL )
+		{
+		return KErrNoMemory;
+		}
+	
+	// Calculate filter tables for horizontal scaling
+	iFilterIndexTablePtr = iFilterIndexTable;
+	iFilterCoeffsTablePtr = iFilterCoeffsTable;
+	result = CalcFilterTables(iOrigSize.iWidth, iDestSize.iWidth, iFilterIndexTablePtr, iFilterCoeffsTablePtr);
+
+	return result;
+	}
+
+/*
+*
+* DoScale
+* This function does the scaling of a bitmap in chunks
+*
+*/
+void CBitmapScalerPlugin::DoScale()
+	{
+	//[assert the invariant ]
+	__ASSERT_DEBUG( InVariant(), Panic( EBadInvariant ) );
+
+	switch( iCurrentState )
+		{
+		case EScalingState:
+			{
+			//[ we are scaling the image]
+			if (QualityAlgorithm() != CBitmapScaler::EMaximumQuality)
+				{
+				FastScale();
+				}
+			else
+				{
+				Scale();
+				}
+			break;
+			}
+		case EStartPostProcessState:
+			{
+			//[ we are setting up post processing]
+			StartPostProcessing();
+			break;
+			}
+		case ECleanUpState:
+			{
+			//[ cleaning up ]
+			ScaleCleanUp();
+			break;
+			}
+		default:
+			{
+			//[we can never get here
+			// because the invariant has been asserted
+			//assert the invariant ]
+			__ASSERT_DEBUG( InVariant(), Panic( EBadInvariant ) );
+			}
+		}
+
+	//[assert the invariant ]
+	__ASSERT_DEBUG( InVariant(), Panic( EBadInvariant ) );
+	}
+
+/**
+*
+* Scale
+* This method does the scaling
+* @pre current state is ScalingState
+*/
+void CBitmapScalerPlugin::Scale()
+	{
+#if defined (__SCALING_PROFILING)
+	RDebug::ProfileStart(7);
+#endif // __SCALING_PROFILING
+
+	//[ assert precondition ]
+    ASSERT( GetCurrentState() == EScalingState );
+	//[ assert invariant ]
+	ASSERT( InVariant() );
+
+	TInt linesLeftPerCall = KLinesPerCall;
+	
+	while (linesLeftPerCall>0 && iCurOffset<iFinalOffset)
+		{
+		if (!(iFlags & EVerticalScan))
+			{
+			//
+			// Get current scan line
+			#if defined (__SCALING_PROFILING)
+				RDebug::ProfileStart(8);
+			#endif // __SCALING_PROFILING
+			iSrcBitmap->GetScanLine(iOrigDes, TPoint(0, iCurOffset), iOrigSize.iWidth, iLocalDisplayMode);
+			#if defined (__SCALING_PROFILING)
+				RDebug::ProfileEnd(8);
+			#endif // __SCALING_PROFILING
+			}
+		else
+			{
+			#if defined (__SCALING_PROFILING)
+				RDebug::ProfileStart(11);
+			#endif // __SCALING_PROFILING
+			// Get the vertical scan line...
+			iScaleBitmap->GetVerticalScanLine(iOrigDes, iCurOffset, iLocalDisplayMode);
+			#if defined (__SCALING_PROFILING)
+				RDebug::ProfileEnd(11);
+			#endif // __SCALING_PROFILING
+			}
+
+		if (!(iFlags & EVerticalScan))
+			{
+			// Scale the scan line horizontally
+			for (TInt i=0; i < iComponentsPerPixel; i++)
+				{
+				ScaleLine(iOrigDes, iDestDes, i, iOrigSize.iWidth, iDestSize.iWidth, iFilterIndexTable, iFilterCoeffsTable);
+				}
+			}
+		else
+			{
+			//
+			// Scale vertically
+			for (TInt i=0; i < iComponentsPerPixel; i++)
+				{
+				ScaleLine(iOrigDes, iDestDes, i, iOrigSize.iHeight, iDestSize.iHeight, iFilterIndexTable, iFilterCoeffsTable);
+				}
+			}
+
+#if defined (__SCALING_PROFILING)
+	RDebug::ProfileStart(10);
+#endif //__SCALING_PROFILING
+
+		if (!(iFlags & EVerticalScan))
+			{
+			// Set the scaled horizontal line back into the bitmap
+			iScaleBitmap->SetScanLine(iDestDes, iCurOffset);
+			}
+		else
+			{
+			// Write to output bitmap
+			// Lock & unlock the heap to prevent the Font & Bitmap server moving the bitmap around
+			// Now writing to iScaleBitmap
+			if (iDestBmpPtr->DisplayMode()==EColor16MA && iLocalDisplayMode==EColor16MA)
+				{
+				TUint8* dataAddress = reinterpret_cast<TUint8*>( iDestBmpPtr->DataAddress());
+				dataAddress +=iCurOffset*iComponentsPerPixel;
+				const TInt scanLineLength = iDestBmpPtr->ScanLineLength(iDestBmpPtr->SizeInPixels().iWidth, iDestBmpPtr->DisplayMode() );
+
+				const TInt limit = iDestSize.iHeight * iComponentsPerPixel;
+				const TUint8* ptr = iDestDes.Ptr();
+				for (TInt y = 0; y < limit; y += iComponentsPerPixel, dataAddress += scanLineLength)
+					{
+					CopyPixel(dataAddress,ptr);
+					ptr += iComponentsPerPixel;
+					}
+				}
+			else
+				{
+				TUint8* dataAddress = reinterpret_cast<TUint8*>( iScanlineBitmap->DataAddress());
+				ASSERT( iScanlineBitmap->SizeInPixels().iWidth==1 ); // that must be a "column"
+				const TInt scanLineLength = iScanlineBitmap->ScanLineLength(1, iScanlineBitmap->DisplayMode() );
+
+				const TInt limit = iDestSize.iHeight * iComponentsPerPixel;
+				const TUint8* ptr = iDestDes.Ptr();
+				for (TInt y = 0; y < limit; y += iComponentsPerPixel, dataAddress += scanLineLength)
+					{
+					CopyPixel(dataAddress, ptr);
+					ptr += iComponentsPerPixel;					
+					}
+		
+				iGc->BitBlt(TPoint(iCurOffset, 0), iScanlineBitmap);
+				}
+			}
+
+#if defined (__SCALING_PROFILING)
+		RDebug::ProfileEnd(10);
+#endif //__SCALING_PROFILING
+
+		linesLeftPerCall--;
+		iCurOffset++;
+		}
+
+	if ( IsScalingComplete() && !(iFlags & EVerticalScan))
+		{
+		iCurLineSize = iOrigSize.iHeight;
+		iCurOffset = 0;
+		iFinalOffset = iDestSize.iWidth;
+		iFlags |= EVerticalScan;
+		// Finished the horizontal scaling so now need to setup descriptors
+		// for the intermediate size as we're now longer using an intermediate
+		// bitmap.
+		iOrigSize = iIntermediateSize;
+
+		User::Free( reinterpret_cast<TAny*>( const_cast<TUint8*>( iOrigDes.Ptr() ) ) );
+		iOrigDes.SetLength(0);
+
+		TInt allocErr = AllocPtr(iOrigDes, iOrigSize.iHeight * iComponentsPerPixel);
+		if( allocErr != KErrNone )
+			{
+			ProcessError( allocErr );
+			return;
+			}
+
+		User::Free( reinterpret_cast<TAny*>( const_cast<TUint8*>( iDestDes.Ptr() ) ) );
+		iDestDes.SetLength(0);
+
+		allocErr = AllocPtr(iDestDes, iDestSize.iHeight * iComponentsPerPixel);
+		if( allocErr != KErrNone )
+			{
+			ProcessError( allocErr );
+			return;
+			}
+		iFilterIndexTablePtr = iFilterIndexTable;
+		iFilterCoeffsTablePtr = iFilterCoeffsTable;
+		TInt err = CalcFilterTables(iOrigSize.iHeight, iDestSize.iHeight, iFilterIndexTablePtr, iFilterCoeffsTablePtr);
+		if( err != KErrNone )
+			{
+			ProcessError(err);
+			return;
+			}
+		}
+	else if ( IsScalingComplete() )
+		{
+		// Finished the vertical scaling so, as the tgtbitmap has been scaled in place (ie
+		// to the intermediate size) we need to resize it to the true destination size
+		TInt err = iTgtBitmap->Resize(iDestSize);
+		if( err != KErrNone )
+			{
+			ProcessError(err);
+			return;
+			}
+
+		if( IsPostProcessingNeeded() )
+			{
+			//[ transition to start post processing state]
+			SetCurrentState( EStartPostProcessState );
+			}
+		else
+			{
+			//[ transition to cleanup state ]
+			SetCurrentState( ECleanUpState );
+			}
+		}
+	
+	// Start the active object
+	SelfComplete(KErrNone);
+
+#if defined (__SCALING_PROFILING)
+	RDebug::ProfileEnd(7);
+#endif // __SCALING_PROFILING
+
+	//[ assert invariant ]
+	ASSERT( InVariant() );
+	}
+
+/*
+*
+* StartPostProcessing
+*
+*/
+void CBitmapScalerPlugin::StartPostProcessing()
+	{
+	ASSERT( InVariant() );
+	ASSERT( GetCurrentState() == EStartPostProcessState );
+	// set state to post processing in progress
+	// lauch async post process operation
+	SetCurrentState(ECleanUpState);	
+
+	iBitmapConverter->Convert( &iStatus, *iTgtBitmap, *iDestBmpPtr);	
+
+	SetActive();
+	ASSERT( InVariant() );
+	ASSERT( GetCurrentState() == ECleanUpState );
+	}
+
+/*
+*
+* GetCurrentState
+* @return CBitmapScalerPlugin::TScaleState The current state
+* of the state machine
+*
+*/
+CBitmapScalerPlugin::TScaleState CBitmapScalerPlugin::GetCurrentState() const
+	{
+	return iCurrentState;
+	}
+
+/*
+*
+* SetCurrentState
+* @param aState
+* @pre aState <= CleanUpState
+* @pre aState >= InactiveState
+* @post Invariant
+*
+*/
+void CBitmapScalerPlugin::SetCurrentState( TScaleState aState )
+	{
+	iCurrentState = aState;
+	}
+
+/*
+*
+* CleanUp
+*
+*/
+void CBitmapScalerPlugin::ScaleCleanUp()
+	{
+	TInt errStatus = iStatus.Int();
+
+	if( errStatus == KErrNone )
+		{
+		if ((iFlags & ECreatedTempBitmap) != 0)
+			{
+			if (iTempBitmap)
+				{
+				TInt handle = 0;
+				if (QualityAlgorithm() != CBitmapScaler::EMaximumQuality)
+					{
+					// medium OR min qualitity algorithm
+					handle = iDestBmpPtr->Handle();
+					}
+				else
+					{
+					// Normal (maximum quality) algorithm
+					handle = iTgtBitmap->Handle();
+					}
+				errStatus = iSrcBitmap->Duplicate(handle);
+				}
+			}
+		}
+
+	ProcessError( errStatus );
+	}
+
+/*
+*
+* ProcessError
+* @param aErrorStatus
+*
+*/
+void CBitmapScalerPlugin::ProcessError( TInt aErrorStatus )
+	{
+	if( iPostProcessBitmap )
+		{
+		iPostProcessBitmap->Reset();
+		}
+	Cleanup();
+	RequestComplete( aErrorStatus );
+	}
+
+/*
+*
+* IsScalingComplete
+* @return TBool scaling process has been completed
+*
+*/
+TBool CBitmapScalerPlugin::IsScalingComplete() const
+	{
+	TBool result = EFalse ;
+	if(iCurOffset == iFinalOffset || iCurOffsetUp == 0) 
+		{
+		result = ETrue;
+		}
+	return result;
+	}
+
+/*
+*
+* RunL
+* Handles an active object’s request completion event.
+* The function is called by the active scheduler 
+* when a request completion event occurs.
+*/
+void CBitmapScalerPlugin::RunL()
+	{
+	DoScale();
+	}
+
+/*
+*
+* DoCancel
+* Called by active object to prematurely terminate this bitmap scaling.
+*
+*/
+void CBitmapScalerPlugin::DoCancel()
+	{
+	ASSERT( InVariant());
+	
+	if( iBitmapConverter )
+		{
+		iBitmapConverter->Cancel();
+		}
+	
+	Cleanup();
+	ASSERT( GetCurrentState() == EInactiveState );
+	ASSERT( InVariant());
+	RequestComplete(KErrCancel);
+	}
+
+/*
+* 
+* RequestComplete
+* @param "TInt aReason"
+*
+*/
+void CBitmapScalerPlugin::RequestComplete(TInt aReason)
+	{
+	ASSERT(iScaleStatus);
+	TRequestStatus* status = iScaleStatus;
+	User::RequestComplete(status, aReason);
+	}
+
+/*
+*
+* SelfComplete
+* This function activates the active object and 
+* signals completion of the current asynchronous operation
+*
+* @param "TInt aReason"
+*
+*/
+void CBitmapScalerPlugin::SelfComplete(TInt aReason)
+	{
+	SetActive();
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, aReason);
+	}
+
+/*
+*
+* This function calculates the filter tables for scaling
+* CalcFilterTables
+* @param "TInt aOrigWidth"
+* @param "TInt aDestWidth"
+* @param "TInt*& aFilterCoeffsTablePtr"
+*
+*/
+TInt CBitmapScalerPlugin::CalcFilterTables(TInt aOrigWidth, TInt aDestWidth, TInt*& aFilterIndexTablePtr, TInt*& aFilterCoeffsTablePtr)
+	{
+	TInt inputWidth = aOrigWidth;
+	TInt scaledWidth = aDestWidth;
+	//this is added since to test indX<< KFixedPointBits for overflow 
+	TInt fixedPointsVal = 1<<KFixedPointBits;
+
+	if ( (MAKE_TUINT64(0,inputWidth) * MAKE_TUINT64(0,scaledWidth)) > KMaxTInt )
+    	{
+    	return KErrOverflow;	
+    	}
+	//Checking OverFlow for ((indX << KFixedPointBits) * inputWidth) 
+    if ( (MAKE_TUINT64(0,inputWidth) * MAKE_TUINT64(0,scaledWidth) * MAKE_TUINT64(0,fixedPointsVal)) > KMaxTInt )
+    	{
+    	return KErrOverflow;	
+    	}
+	if ( scaledWidth > inputWidth )
+		{
+		// Calculate tables for interpolation (scaling up)
+		for (TInt indX = 0; indX < scaledWidth; indX++)
+			{
+			const TInt indFilt = ((indX << KFixedPointBits) * inputWidth) / scaledWidth;
+			const TInt firstX  = indFilt >> KFixedPointBits;
+			const TInt lastX = (firstX >= inputWidth - 1) ? firstX : firstX+1;
+
+			*aFilterIndexTablePtr++ = firstX;
+			*aFilterIndexTablePtr++ = lastX;
+			*aFilterCoeffsTablePtr++ = indFilt - (firstX << KFixedPointBits);
+			}
+		}
+	else
+		{
+		// Calculate tables for decimation (scaling down)		
+		const TInt ftNew = (inputWidth << KFixedPointBits)/scaledWidth;
+		TInt firstX = 0;
+		TInt lastX = 0;
+		for (TInt indX = 0; indX < scaledWidth; indX++)
+			{
+			firstX = lastX;
+			lastX = ((indX + 1) * inputWidth) / scaledWidth;
+
+			*aFilterIndexTablePtr++ = firstX;
+			*aFilterIndexTablePtr++ = lastX;
+
+			const TInt indOrig	= ((indX << KFixedPointBits) * inputWidth) / scaledWidth;
+			const TInt indOrigInt = indOrig >> KFixedPointBits;
+			for (TInt indFilt = firstX; indFilt <= lastX; indFilt++)
+				{
+				TInt fixTap;
+				if(indFilt <= indOrigInt)
+					{
+					fixTap = ftNew - (indOrig - (indFilt << KFixedPointBits));
+					}
+				else
+					{
+					fixTap = ftNew - ((indFilt << KFixedPointBits) - indOrig);
+					}
+
+				if (fixTap < 0) 
+					{
+					fixTap = 0;
+					}
+				*aFilterCoeffsTablePtr++ = (fixTap << KFixedPointBits) / ftNew;
+				}
+			}
+		}
+	return KErrNone;
+	}
+
+
+/*
+* This function calculates the filter tables for scaling
+* ScaleLine
+* @param "const TDesC8& aInDes"
+* @param "TDes8& aOutDes" 
+* @param "TInt* aTableCoeffsPtr"
+*
+*/
+void CBitmapScalerPlugin::ScaleLine(const TDesC8& aInDes,
+								  TDes8& aOutDes,
+								  TInt aStartIndex,
+								  TInt aInputWidth,
+								  TInt aOutputWidth,
+								  TInt* aTableIndexPtr, TInt* aTableCoeffsPtr)
+	{
+#if defined (__SCALING_PROFILING)
+	RDebug::ProfileStart(9);
+#endif // __SCALING_PROFILING
+	
+	// Initialize variables
+	TInt* tableIndexesPtr = aTableIndexPtr;
+	TInt* tableCoeffsPtr  = aTableCoeffsPtr;
+
+	if (aOutputWidth == aInputWidth)
+		{
+		aOutDes = aInDes;
+		}
+	else if (aOutputWidth > aInputWidth)
+		{
+		// Perform interpolation when scaling up
+		const TInt startIndex = aStartIndex;
+		const TUint8* inputDesPtr = aInDes.Ptr();
+		TUint8* outputDesPtr = const_cast<TUint8*>( aOutDes.Ptr() );
+
+		for (TInt indX = 0; indX < aOutputWidth; indX++, aStartIndex += iComponentsPerPixel)
+			{
+			TInt firstX = *tableIndexesPtr++;
+			TInt lastX  = *tableIndexesPtr++;
+			TInt fixTap = *tableCoeffsPtr++;
+
+			// Stay in bounds
+			if (firstX >= aInputWidth)
+				{
+				firstX = aInputWidth - 1;	
+				}
+			// Factor for aggregated colour component
+			firstX *= iComponentsPerPixel;
+			firstX += startIndex;
+
+			// Stay in bounds
+			if (lastX >= aInputWidth)
+				{
+				lastX = aInputWidth - 1;	
+				}
+			lastX *= iComponentsPerPixel;
+			lastX += startIndex;
+
+			// Filtering
+			outputDesPtr[aStartIndex] = 
+				TUint8(((fixTap * TInt(inputDesPtr[lastX])+ 
+						 (KFixedPointScale - fixTap) * TInt(inputDesPtr[firstX])) 
+						 >> KFixedPointBits));
+			}
+		}
+	else
+		{
+		// Perform decimation if scaling down requested
+		const TInt startIndex = aStartIndex;
+		const TInt widthLimit = iComponentsPerPixel * aInputWidth;
+		const TInt16 startWidthlimit = widthLimit - iComponentsPerPixel + startIndex;
+		const TUint8* inputDesPtr = aInDes.Ptr();
+		TUint8* outputDesPtr = const_cast<TUint8*>( aOutDes.Ptr() );
+
+		for (TInt indX = 0; indX < aOutputWidth; indX++, aStartIndex += iComponentsPerPixel)
+			{
+			TInt firstX = *tableIndexesPtr++;
+			firstX *= iComponentsPerPixel;
+			firstX += startIndex;
+			
+			TInt lastX  = *tableIndexesPtr++;
+			if (lastX >= aInputWidth)
+				{
+				lastX = aInputWidth - 1;	
+				}
+			lastX *= iComponentsPerPixel;
+			lastX += startIndex;
+			
+			// Filtering
+			TInt sum       = 0;
+			TInt fixTapSum = 0;
+			for(TInt indFilt = firstX; indFilt <= lastX; indFilt += iComponentsPerPixel)
+				{
+				TInt fixTap = *tableCoeffsPtr++;
+				TInt indIn;
+				if (indFilt < 0)
+					{
+					indIn = startIndex;
+					}
+				else if (indFilt >= widthLimit )
+					{
+					indIn = startWidthlimit;
+					}
+				else
+					{
+					indIn = indFilt;
+					}
+
+				sum += fixTap * TInt(inputDesPtr[indIn]);
+				fixTapSum = TInt(fixTapSum + fixTap);
+				}
+
+			// Let's not divide by zero
+			if (fixTapSum == 0)
+				{
+				outputDesPtr[aStartIndex] = TUint8(sum);
+				}
+			else
+				{
+				outputDesPtr[aStartIndex] = TUint8(sum/fixTapSum);	
+				}
+			}
+		}
+#if defined (__SCALING_PROFILING)
+	RDebug::ProfileEnd(9);
+#endif // __SCALING_PROFILING
+	}
+
+
+/*
+*
+* InVariant
+* Used to determine the state of health of the scaler body
+*
+*/
+TBool CBitmapScalerPlugin::InVariant() const
+	{
+    return ((iCurrentState <= ECleanUpState ) && (iCurrentState >= EInactiveState ));
+	}
+
+/**
+*
+* SetProcessingNeeded
+* @param aStatus ETrue EFalse
+*
+*/
+void CBitmapScalerPlugin::SetProcessingNeeded( TBool aStatus )
+	{
+	if(aStatus)
+		{
+		iFlags |= EIsPostProcessingNeeded;
+		}
+	else
+		{
+		iFlags &= ~EIsPostProcessingNeeded;
+		}
+	}
+
+/**
+*
+* SetDisablePostProcessing
+* @param aStatus ETrue EFalse
+*
+*/
+void CBitmapScalerPlugin::SetDisablePostProcessing( TBool aIsDisabled )
+	{
+	if(aIsDisabled)
+		{
+		iFlags |= EDisablePostProcessing;
+		}
+	else
+		{
+		iFlags &= ~EDisablePostProcessing;
+		}
+	}
+
+/**
+*
+* IsPostProcessingDisabled
+* @return ETrue, EFalse
+*
+*/
+TBool CBitmapScalerPlugin::IsPostProcessingDisabled()
+	{
+	return ((iFlags & EDisablePostProcessing) != 0);
+	}
+
+/**
+*
+* IsPostProcessingNeeded
+* @return TBool scaling process has been completed
+*
+*/
+TBool CBitmapScalerPlugin::IsPostProcessingNeeded() const
+	{
+	return ((iFlags & EIsPostProcessingNeeded) != 0);
+	}
+
+/*
+*
+* HeightAndWidthPreservingAspectRatio
+* @param aDestSize
+* @param aOrigSize
+* Calculates the destination bitmap size based on preserving
+* the aspect ratio of the original bitmap
+* @pre aOrigSize is not zero in any dimension
+*/
+void CBitmapScalerPlugin::HeightAndWidthPreservingAspectRatio( TSize& aDestSize, const TSize& aOrigSize ) const
+    {
+    
+    if ((aOrigSize.iWidth == 0) || (aOrigSize.iHeight == 0))
+        {
+        return;
+        }
+
+    // no need to optimise, it is not a kernal function which may get called many times
+    TReal widthRatio = (TReal)aDestSize.iWidth / (TReal)aOrigSize.iWidth;
+    TReal heightRatio = (TReal)aDestSize.iHeight / (TReal)aOrigSize.iHeight;
+
+    // choose the smaller ratio to use
+    if(widthRatio < heightRatio)
+        {
+        TReal height;
+        Math::Round(height, aOrigSize.iHeight * widthRatio, 0);
+        aDestSize.iHeight = static_cast<TInt>(height);
+        }
+    else
+        {
+        TReal width;
+        Math::Round(width, aOrigSize.iWidth * heightRatio, 0);
+        aDestSize.iWidth = static_cast<TInt>(width);
+        }
+    }
+
+/*
+*
+* IsPostProcessingEnabled
+* @return 'TBool'
+* 
+*/
+TBool CBitmapScalerPlugin::IsPostProcessingEnabled() const
+	{
+	return ((iFlags & EPostProcessingEnabled) != 0);
+	}
+
+/*
+*
+* SetPostProcessingEnabled
+* @param aIsEnabled
+* 
+*/
+void CBitmapScalerPlugin::SetPostProcessingEnabled( TBool aIsEnabled )
+	{
+	if(aIsEnabled)
+		{
+		iFlags |= EPostProcessingEnabled;
+		}
+	else
+		{
+		iFlags &= ~EPostProcessingEnabled;
+		}
+	}
+
+/*
+*
+* CustomCommand
+* @param aUid
+* @param aParam
+* @return 'TInt' an error code indicating success or failure of the 
+* command
+*
+*/
+TInt CBitmapScalerPlugin::CustomCommand(TUid aUid, TAny* aParam)
+	{
+	TInt status = KErrNotSupported;
+	if( ( aUid == KICLUidPostProcessCommand ) && ( aParam != NULL ) )
+		{
+		TBool postProcess = *( reinterpret_cast<TBool*>(aParam));
+		SetDisablePostProcessing( postProcess ); 
+		status = KErrNone;
+		}
+	else if( ( aUid == KICLUidUseLowMemoryAlgorithmCommand ) && ( aParam != NULL ) )
+		{
+		TBool useLowMemAlgorithm = *( reinterpret_cast<TBool*>(aParam) );
+		SetUseLowMemoryAlgorithm( useLowMemAlgorithm );
+		status = KErrNone;
+		}
+	else if( ( aUid == KICLUidSetQualityAlgorithmCommand ) && ( aParam != NULL ) )
+		{
+		CBitmapScaler::TQualityAlgorithm quality = *( reinterpret_cast<CBitmapScaler::TQualityAlgorithm*>(aParam) );
+		SetQualityAlgorithm(quality);
+		status = KErrNone;
+		}
+ 
+	return status;
+	}
+
+/*
+*
+* UseLowMemoryAlgorithm
+* @return 'TBool'
+* 
+*/
+TBool CBitmapScalerPlugin::UseLowMemoryAlgorithm() const
+	{
+	return ((iFlags & EUseLowMemoryAlgorithm) != 0);
+	}
+
+/*
+*
+* SetUseLowMemoryAlgorithm
+* @param aUseLowMemoryAlgorithm
+* 
+*/
+void CBitmapScalerPlugin::SetUseLowMemoryAlgorithm(TBool aUseLowMemoryAlgorithm)
+	{
+	if(aUseLowMemoryAlgorithm)
+		{
+		iFlags |= EUseLowMemoryAlgorithm;
+		}
+	else
+		{
+		iFlags &= ~EUseLowMemoryAlgorithm;
+		}
+	}
+
+/*
+*
+* SetQualityAlgorithm
+* @param CBitmapScaler::TQualityAlgorithm aQuality
+* 
+*/
+void CBitmapScalerPlugin::SetQualityAlgorithm( CBitmapScaler::TQualityAlgorithm aQuality)
+	{
+	iQualityLevel = aQuality;
+	}
+
+/*
+*
+*	QualityAlgorithm
+*	@return CBitmapScaler::TQualityAlgorithm
+*
+*/
+CBitmapScaler::TQualityAlgorithm CBitmapScalerPlugin::QualityAlgorithm() const
+	{
+	return iQualityLevel;
+	}
+
+/**
+*	This function is called when the state iCurrentState == EScalingState 
+*	and either the UseMediumQualityAlgorithm or the UseMinimumQualityAlgorithm custom
+*	commands have been invoked.
+*	In terms of speed and quality, the normal algorithm, as implemented in Scale(),
+*	is the slowest / highest quality, whereas the fastest / lowest quality
+*	implementation is for the case when UseMinimumQualityAlgorithm is specified.
+*	The difference between the minimum quality and fast algorithms is that
+*	the fast algorithm forms the destination value from weighted averages of
+*	the x values prior to and proceeding the value under consideration.
+*/
+void CBitmapScalerPlugin::FastScale()
+	{
+#if defined (__SCALING_PROFILING)
+	RDebug::ProfileStart(7);
+#endif // __SCALING_PROFILING
+	TInt linesLeftPerCall = KLinesPerCall;
+	
+	// Height and width to scale to
+	const TInt maxX = iDestSize.iWidth * iComponentsPerPixel;
+	const TInt stepY = (iOrigSize.iHeight << KFixedPointScale) / iDestSize.iHeight;
+	const TInt destBufferLength = iDestDes.Length();
+	const TInt divisor = (destBufferLength < iDestSize.iWidth ? destBufferLength : iDestSize.iWidth);
+	const TInt stepX = (iOrigSize.iWidth << KFixedPointScale) / divisor;
+	TInt sourceX = 0;	// x
+	const TInt roundVal = 1;
+	if (iDestSize == iOrigSize)
+		{
+		// Same size so just directly copy values.
+		while(linesLeftPerCall > 0 && iCurOffset < iFinalOffset)
+			{
+			iSrcBitmap->GetScanLine(iOrigDes, TPoint(0, iCurOffset), iOrigSize.iWidth, iLocalDisplayMode);
+			iDestBmpPtr->SetScanLine(iOrigDes, iCurOffset);
+			linesLeftPerCall--;
+			iCurOffset++;
+			}
+		}
+	else if (iDestSize.iHeight < iOrigSize.iHeight)
+		{
+		TInt currentX = 0;
+		// For downscaling (destination bitmap size is smaller than the original bitmap size)
+		while(linesLeftPerCall > 0 && iCurOffset < iFinalOffset)
+			{
+			sourceX = 0;			
+			// Fetch the relevant row from the source bitmap
+			iSrcBitmap->GetScanLine(iOrigDes, TPoint(0, iSrcY), iOrigSize.iWidth, iLocalDisplayMode);
+
+			// Get each colour component of each relevant pixel
+			for (TInt x = 0; x < maxX; x += iComponentsPerPixel)
+				{
+				//Line scaling
+				ScaleBitmapLine(x,sourceX);
+				// Increment to the next pixel
+				currentX += stepX;
+				// Avoid TInt rounding error
+				sourceX = ( currentX + (roundVal << KFixedPointScale - 1) ) >> KFixedPointScale;
+				// Factor for the number of components
+				sourceX *= iComponentsPerPixel;
+				// Stay in bounds
+				if (sourceX >= iOrigDes.Length())
+					{
+					sourceX = iOrigDes.Length() - iComponentsPerPixel;
+					}
+				}
+			currentX = 0;	// reset the x counter
+			iDestBmpPtr->SetScanLine(iDestDes, iCurOffset);	// set the scaled line into the target
+				
+			// increment to the next row
+			iCurY += stepY;
+			// avoiding any rounding errors (using TInt = (TInt + 0.5) )
+			iSrcY = (iCurY + (roundVal << KFixedPointScale - 1) ) >> KFixedPointScale;
+			// Stay in bounds
+			if (iSrcY >= iOrigSize.iHeight)
+				{
+				iSrcY = iOrigSize.iHeight - 1;
+				}
+			linesLeftPerCall--;
+			iCurOffset++;
+			}
+		}
+	else
+		{
+		TInt currentX = 0;
+		//For upscaling (Destination bitmap size is bigger than the original bitmap size)
+		while(linesLeftPerCall > 0 && iCurOffsetUp !=0 )
+			{
+			sourceX = 0;			
+			// avoiding any rounding errors (using TInt = (TInt + 0.5) )
+			iSrcY = (iCurY + (roundVal << KFixedPointScale - 1) ) >> KFixedPointScale;
+			// Fetch the relevant row from the source bitmap
+			iSrcBitmap->GetScanLine(iOrigDes, TPoint(0, iSrcY), iOrigSize.iWidth, iLocalDisplayMode);
+			
+			// Get each colour component of each relevant pixel
+			for (TInt x = 0; x < maxX; x += iComponentsPerPixel)
+				{
+				//Line scaling
+				ScaleBitmapLine(x,sourceX);
+				// Increment to the next pixel
+				currentX += stepX;
+				// Avoid TInt rounding error
+				sourceX = ( currentX + (roundVal << KFixedPointScale - 1) ) >> KFixedPointScale;
+				// Factor for the number of components
+				sourceX *= iComponentsPerPixel;
+				// Stay in bounds
+				if (sourceX >= iOrigDes.Length())
+					{
+					sourceX = iOrigDes.Length() - iComponentsPerPixel;
+					}
+				}
+			currentX = 0;	// reset the x counter
+			iDestBmpPtr->SetScanLine(iDestDes, iCurOffsetUp);	// set the scaled line into the target				
+			// Decrement to the next row from the end
+			iCurY -= stepY;	
+			// Stay in bounds
+			if (iSrcY >= iOrigSize.iHeight)
+				{
+				iSrcY = iOrigSize.iHeight - 1;
+				}
+			linesLeftPerCall--;
+			iCurOffsetUp--;
+			}
+		}
+	if (IsScalingComplete())
+		{
+		// in case of low memory algo and 1 bitmap we have to resize the resulting bitmap
+		if (iDestBmpPtr->Handle() == iSrcBitmap->Handle()
+				&& iDestBmpPtr->SizeInPixels() != iDestSize )
+			{
+			TInt err=iDestBmpPtr->Resize(iDestSize);
+			if (err != KErrNone)
+				{
+				ProcessError( err );
+				return;
+				}
+			}		
+		if( IsPostProcessingNeeded() )
+			{
+			//[ transition to start post processing state]
+			SetCurrentState( EStartPostProcessState );
+			}
+		else
+			{
+			//[ transition to cleanup state ]
+			SetCurrentState( ECleanUpState );
+			}
+		}
+	// Start the active object
+	SelfComplete(KErrNone);
+#if defined (__SCALING_PROFILING)
+	RDebug::ProfileEnd(7);
+#endif // __SCALING_PROFILING
+	}
+	
+/*
+*
+* ScaleBitmapLine
+* @param aX
+* @param aSourceX
+*
+*/
+void CBitmapScalerPlugin::ScaleBitmapLine(TInt aX,TInt aSourceX)
+	{
+	TUint8* destDesPtr = const_cast<TUint8*>( iDestDes.Ptr() );
+	const TUint8* orgDesPtr = iOrigDes.Ptr();
+	
+	if (QualityAlgorithm() == CBitmapScaler::EMinimumQuality)
+		{
+		CopyPixel(destDesPtr + aX,orgDesPtr + aSourceX);
+		}
+	else	// must be CBitmapScaler::EMediumQuality
+		{
+		// Better quality
+		TInt nextValue = 0;
+		TInt prevValue = 0;
+		TInt value = 0;
+		// eg weightedAv. = (w1*v1 + w2*v2 + w3*v3) / (w1 + w2 + w3)
+		// so if w1=w3=8 and w2=16
+		// (v1 * 2<<3 + v2 * 2<<4 + v3 * 2<<3) >> 2 * 5
+		const TInt minorShift = 3;	// prev and next value weighting
+		const TInt majorShift = 4;	// current value weighting
+		const TInt backShift = 5;	// average
+
+		for (TInt i = 0; i < iComponentsPerPixel; i++)
+			{
+			// Get the previous value
+			TInt index = aSourceX - iComponentsPerPixel;
+			if (index < 0)
+				{
+				index = i;
+				}
+			else
+				{
+				index += i;
+				}
+			prevValue = TInt(orgDesPtr[index]);
+				
+			// Weight the previous value
+			prevValue = prevValue << minorShift;
+			// Get the next value
+			index = aSourceX;
+			if (index  + iComponentsPerPixel >= iOrigDes.Length())
+				{
+				index += i;
+				}
+			else
+				{
+				index += (i + iComponentsPerPixel);
+				}
+			nextValue = TInt(orgDesPtr[index]);
+
+			// Weight the next value
+			nextValue = nextValue << minorShift;
+			// Weight the current value
+			value = TInt(orgDesPtr[aSourceX+ i]);
+
+			value = value << majorShift;
+			// Sum all values
+			value += prevValue;
+			value += nextValue;
+			// Average
+			value = value >> backShift;
+			destDesPtr[aX + i] = TUint8(value);
+			}
+		}
+	}
+