--- /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);
+ }
+ }
+ }
+