mmplugins/imagingplugins/bitmaptransform/src/refplugin/BitmapScalerPlugin.cpp
changeset 0 40261b775718
equal deleted inserted replaced
-1:000000000000 0:40261b775718
       
     1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "BitmapTransformsPlugin.h"
       
    17 
       
    18 #include "BitmapConverter.h"
       
    19 #include <bitmtrans/bitmtranspanic.h>
       
    20 #include <e32math.h>
       
    21 
       
    22 const TInt KFixedPointBits = 4;
       
    23 const TInt KFixedPointScale = (1 << KFixedPointBits);
       
    24 const TInt KLinesPerCall = 10;
       
    25 const TInt KBitsPerByte = 8;
       
    26 
       
    27 /*
       
    28 *The function NewL constructs a CBitmapScalerPlugin
       
    29 *
       
    30 *@return CBitmapScalerPlugin* 
       
    31 */
       
    32 MBitmapScalerPlugin* CBitmapScalerPlugin::NewL()
       
    33 	{
       
    34 	CBitmapScalerPlugin* self = new(ELeave) CBitmapScalerPlugin();
       
    35 	CleanupStack::PushL(self);
       
    36 	self->ConstructL();
       
    37 	CleanupStack::Pop(self);
       
    38 	return self;
       
    39 	}
       
    40 
       
    41 /*
       
    42 *
       
    43 *CBitmapScalerPlugin()
       
    44 *Constructor for this class. Adds itself to CActiveScheduler.
       
    45 */
       
    46 CBitmapScalerPlugin::CBitmapScalerPlugin()
       
    47 	: CActive(CActive::EPriorityIdle), iOrigDes(NULL, 0), iDestDes(NULL, 0),
       
    48 	iQualityLevel(CBitmapScaler::EMaximumQuality)
       
    49 	{
       
    50 	CActiveScheduler::Add(this);
       
    51 	}
       
    52 
       
    53 /*
       
    54 *
       
    55 *ConstructL()
       
    56 *Performs second phase of construction.
       
    57 */
       
    58 void CBitmapScalerPlugin::ConstructL()
       
    59 	{
       
    60 	iScanlineBitmap = new(ELeave) CFbsBitmap;
       
    61 
       
    62 	SetPostProcessingEnabled(ETrue);	
       
    63 	ASSERT( GetCurrentState() == EInactiveState );
       
    64 	}
       
    65 
       
    66 
       
    67 /*
       
    68 *
       
    69 *~CBitmapScalerPlugin
       
    70 *This is the destructor for the CBitmapScalerPlugin 
       
    71 *and is resposible for deallocating all resources 
       
    72 *allocated by the CBitmapScalerPlugin.
       
    73 */
       
    74 CBitmapScalerPlugin::~CBitmapScalerPlugin()
       
    75 	{
       
    76 	Cancel();
       
    77 	Cleanup();
       
    78 
       
    79 	delete iScanlineBitmap;
       
    80 
       
    81 	// should have been deleted by cleanup
       
    82 	ASSERT(iScaleBitmap==NULL || !(iFlags & EScaleBitmapIsOwned));
       
    83 	ASSERT(iFilterIndexTable==NULL);
       
    84 	ASSERT(iFilterCoeffsTable==NULL);
       
    85 	ASSERT(iDevice==NULL);
       
    86 	ASSERT(iGc==NULL);
       
    87 	ASSERT(iPostProcessBitmap == NULL );
       
    88 	ASSERT(iBitmapConverter == NULL );
       
    89 	ASSERT( GetCurrentState() == EInactiveState );
       
    90 	}
       
    91 
       
    92 /*
       
    93 *This function performs deallocation of memory allocated by the class
       
    94 *which is allocated on each scale as opposed to the entire liftime
       
    95 *of the scaler object.
       
    96 */
       
    97 void CBitmapScalerPlugin::Cleanup()
       
    98 	{
       
    99 	delete[] iFilterIndexTable; 
       
   100 	iFilterIndexTable = NULL;
       
   101 	delete[] iFilterCoeffsTable; 
       
   102 	iFilterCoeffsTable = NULL;
       
   103 
       
   104 	if (iOrigDes.Length() != 0)	// Test is required to avoid PANIC 45
       
   105 		{
       
   106 		User::Free( reinterpret_cast<TAny*>( const_cast<TUint8*>( iOrigDes.Ptr() ) ) );
       
   107 		iOrigDes.SetLength(0);
       
   108 		}
       
   109 
       
   110 	if (iDestDes.Length() != 0)	// Test is required to avoid PANIC 45
       
   111 		{
       
   112 		User::Free( reinterpret_cast<TAny*>( const_cast<TUint8*>( iDestDes.Ptr() ) ) );
       
   113 		iDestDes.SetLength(0);
       
   114 		}
       
   115 
       
   116 	if (iFlags & ECreatedTempBitmap)
       
   117 		{
       
   118 		delete iTempBitmap; 
       
   119 		iTempBitmap = NULL;
       
   120 		iFlags &= ~ECreatedTempBitmap;
       
   121 		}
       
   122 
       
   123 	// Reset the EIsSourceBitmapResized flag here
       
   124 	if (iFlags & EIsSourceBitmapResized)
       
   125 		{
       
   126 		iFlags &= ~EIsSourceBitmapResized;
       
   127 		ASSERT((iFlags & EIsSourceBitmapResized) == 0);
       
   128 		}
       
   129 
       
   130 	// Only delete the scale bitmap if we created it.
       
   131 	if (iFlags & EScaleBitmapIsOwned)
       
   132 		{
       
   133 		delete iScaleBitmap;
       
   134 		iFlags &= ~EScaleBitmapIsOwned;
       
   135 		}
       
   136 	iScaleBitmap = NULL;
       
   137 
       
   138 	delete iGc; 
       
   139 	iGc = NULL;
       
   140 	delete iDevice; 
       
   141 	iDevice = NULL;
       
   142 	iDestBmpPtr = NULL; // we don't own it
       
   143 	delete iPostProcessBitmap; 
       
   144 	iPostProcessBitmap = NULL;
       
   145 	delete iBitmapConverter;
       
   146 	iBitmapConverter = NULL;
       
   147 	SetCurrentState( EInactiveState );
       
   148 	}
       
   149 
       
   150 /*
       
   151 * Allocates some memory and assigns a pointer to it.
       
   152 * @param aPtr Pointer to the allocated memory
       
   153 * @param aAllocSize The size in bytes of the memory to allocate
       
   154 * @pre aAllocSize >= 0
       
   155 * @pre InVariant
       
   156 */
       
   157 TInt CBitmapScalerPlugin::AllocPtr( TPtr8& aPtr, TInt aAllocSize )
       
   158 	{
       
   159 	//[ preconditions ]
       
   160 	ASSERT(aAllocSize >= 0 );
       
   161 	ASSERT(InVariant());
       
   162 
       
   163 	TInt rc = KErrNone;
       
   164 
       
   165 	// User::Alloc() returns NULL if no memory
       
   166 	TUint8* addr = static_cast<TUint8*>(User::Alloc(aAllocSize + sizeof(TUint32) ));
       
   167 	if (addr)
       
   168 		{
       
   169 		// coverity [memory_leak]
       
   170 		addr = reinterpret_cast<TUint8*>( _ALIGN_UP(TLinAddr(addr), sizeof(TUint32)) );
       
   171 		aPtr.Set(addr, aAllocSize, aAllocSize);
       
   172 		}
       
   173 	else
       
   174 		{
       
   175 		rc = KErrNoMemory;
       
   176 		}
       
   177 	
       
   178 	return rc;
       
   179 	}
       
   180 
       
   181 // MBitmapScalerPlugin::Cancel() calls CActive::Cancel()
       
   182 void CBitmapScalerPlugin::Cancel()
       
   183 	{
       
   184 	CActive::Cancel();
       
   185 	}
       
   186 
       
   187 /*
       
   188 *
       
   189 * ScaleRequestPostcondition
       
   190 * @return 'ETrue' when post conditions for scale request are 
       
   191 * correct
       
   192 *
       
   193 */
       
   194 TBool CBitmapScalerPlugin::ScaleRequestPostcondition() const 
       
   195 	{
       
   196 	TBool result = ETrue;
       
   197 
       
   198 	if (QualityAlgorithm() != CBitmapScaler::EMaximumQuality )
       
   199 		{
       
   200 		if(	( iFinalOffset != iDestSize.iHeight ) ||
       
   201 			( iFilterIndexTable != NULL ) ||
       
   202 			( iFilterCoeffsTable != 0 ) )
       
   203 			{
       
   204 			result = EFalse;
       
   205 			}
       
   206 		}
       
   207 	else
       
   208 		{
       
   209 		// Using the original (maximum quality) algorithm
       
   210 		if(	( iFlags & EVerticalScan) ||
       
   211 			( iFilterIndexTable == NULL ) ||
       
   212 			( iFinalOffset != iOrigSize.iHeight ) ||
       
   213 			( iFilterCoeffsTable == 0 ) )
       
   214 			{
       
   215 			result = EFalse;
       
   216 			}
       
   217 
       
   218 	if (( iDevice == NULL ) ||
       
   219 		( iScanlineBitmap->Handle() == 0 ) ||
       
   220 		( iCurOffset != 0 ))
       
   221 		{
       
   222 		result = EFalse;
       
   223 			}			
       
   224 		}
       
   225 
       
   226 	return result;
       
   227 	}
       
   228 
       
   229 /**
       
   230  *
       
   231  * Begins the bitmap re-scaling operation.
       
   232  *
       
   233  * The scaling factor is based on the relative value of the source bitmap
       
   234  * size and the explicitly supplied size. The operation is asynchronous.
       
   235  * When it is complete, successfully or otherwise, the
       
   236  * <code>TRequestStatus</code>& is set, passing the state of the operation.
       
   237  *
       
   238  * @param     "TRequestStatus* aRequestStatus"
       
   239  *
       
   240  * @param     "CFbsBitmap& aBitmap"
       
   241  *            The bitmap to be re-scaled. This reference is also the
       
   242  *            target location for the re-scaled bitmap.
       
   243  * @param     "const TSize& aDestinationSize"
       
   244  *            The requested target size for the re-scaled bitmap.
       
   245  * @param     "TBool aMaintainAspectRatio = ETrue"
       
   246  *            <code>ETrue</code> - the aspect ratio is retained;
       
   247  *            this is the default. The same scaling factor is
       
   248  *            applied in both the horizontal and vertical
       
   249  *            directions. This is the smaller of the horizontal
       
   250  *            scaling factor and the vertical scaling factor.
       
   251  *            <code>EFalse</code> - the aspect ratio need not be
       
   252  *            retained.
       
   253  *
       
   254  */
       
   255 void CBitmapScalerPlugin::Scale(TRequestStatus* aRequestStatus,
       
   256 									 CFbsBitmap& aBitmap,
       
   257 									 const TSize& aDestinationSize,
       
   258 									 TBool aMaintainAspectRatio)
       
   259 	{
       
   260 	//[ assert preconditions ]
       
   261 	// [ panic if aRequestStatus is NULL ]
       
   262 	__ASSERT_ALWAYS( (aRequestStatus != NULL), Panic( EBadArgumentScale ) );
       
   263 
       
   264 	//[ panic if the src has not been created]
       
   265 	__ASSERT_ALWAYS( (aBitmap.Handle() != 0), Panic( ENoSourceBitmap ) );
       
   266 	
       
   267 	iScaleStatus = aRequestStatus;
       
   268 	*iScaleStatus = KRequestPending;
       
   269 
       
   270 	if(aBitmap.ExtendedBitmapType()!=KNullUid)
       
   271         {
       
   272         RequestComplete(KErrNotSupported);
       
   273         return;
       
   274         }
       
   275 
       
   276 	// Set up the sizes before they're lost
       
   277 	iOrigSize = aBitmap.SizeInPixels();
       
   278 	iDestSize = aDestinationSize;
       
   279 
       
   280 	// Dithering is not required if the tgt's display mode
       
   281 	// is none of EGray256, EColor16M, EColor16MU, EColor16MA
       
   282 	TBool dither = ETrue;
       
   283 	iTgtDisplayMode = aBitmap.DisplayMode();
       
   284 	if ((iTgtDisplayMode == EGray256) ||
       
   285 		(iTgtDisplayMode == EColor16M) ||
       
   286 		(iTgtDisplayMode == EColor16MA)||
       
   287 		(iTgtDisplayMode == EColor16MU) )
       
   288 		{
       
   289 		dither = EFalse;
       
   290 		}
       
   291 
       
   292 	// Create a temporary bitmap if we're not using the low memory algorithm
       
   293 	// OR if we're using the low memory algorithm AND dithering
       
   294 	TInt leaveErr = KErrNone;
       
   295 	if (!UseLowMemoryAlgorithm() || 
       
   296 		(UseLowMemoryAlgorithm() && dither) )
       
   297 		{
       
   298 		if (iFlags & ECreatedTempBitmap)
       
   299 			{
       
   300 			delete iTempBitmap;
       
   301 			iTempBitmap = NULL;
       
   302 			iFlags &= ~ECreatedTempBitmap;
       
   303 			}
       
   304 
       
   305 		iTempBitmap = new CFbsBitmap;
       
   306 
       
   307 		if (iTempBitmap != NULL)
       
   308 			{
       
   309 			// iTempBitmap has been created so flag that it needs to be deleted
       
   310 			iFlags |= ECreatedTempBitmap;
       
   311 			leaveErr = iTempBitmap->Create(aDestinationSize, iTgtDisplayMode);
       
   312 			}
       
   313 		else
       
   314 			{
       
   315 			// No memory to new the temp bitmap
       
   316 			leaveErr = KErrNoMemory;
       
   317 			}
       
   318 		}
       
   319 	
       
   320 	if (leaveErr == KErrNoMemory ||
       
   321 		(UseLowMemoryAlgorithm() && !dither) )
       
   322 		{
       
   323 		// Either failed to create the tempbitmap OR
       
   324 		// we explicitly want to use the low-memory algorithm.
       
   325 		// Either way use the source directly in the manner of the low-memory algorithm.
       
   326 		// Check if we need to delete the tempbitmap 
       
   327 		if (iFlags & ECreatedTempBitmap)
       
   328 			{
       
   329 			delete iTempBitmap;
       
   330 			iTempBitmap = NULL;
       
   331 			iFlags &= ~ECreatedTempBitmap;
       
   332 			}
       
   333 		iTempBitmap = &aBitmap;
       
   334 		iFlags |= EIsSourceBitmapResized;
       
   335 		}
       
   336 	else if (leaveErr != KErrNone)
       
   337 		{
       
   338 		iScaleStatus = aRequestStatus;
       
   339 		*iScaleStatus = KRequestPending;
       
   340 		ProcessError(leaveErr);
       
   341 		return;
       
   342 		}
       
   343 
       
   344 	Scale(aRequestStatus, aBitmap, *iTempBitmap, aMaintainAspectRatio);
       
   345 	}
       
   346 
       
   347 /*
       
   348  *
       
   349  * Begins the bitmap re-scaling operation.
       
   350  *
       
   351  * The scaling factor is based on the relative sizes of the source
       
   352  * and target bitmaps. The operation is asynchronous. When it is
       
   353  * complete, successfully or otherwise, the TRequestStatus &
       
   354  * aStatus is set, passing the state of the operation.
       
   355  *
       
   356  * @param     TRequestStatus* aRequestStatus
       
   357  *
       
   358  * @param     "CFbsBitmap& aSrcBitmap"
       
   359  *            The bitmap to be re-scaled.
       
   360  * @param     "CFbsBitmap& aTgtBitmap"
       
   361  *            The target location for the re-scaled bitmap.
       
   362  * @param     "TBool aMaintainAspectRatio = ETrue"
       
   363  *            ETrue  - the aspect ratio is retained;
       
   364  *            this is the default. The same scaling factor is
       
   365  *            applied in both the horizontal and vertical
       
   366  *            directions. This is the smaller of the horizontal
       
   367  *            scaling factor and the vertical scaling factor.
       
   368  *             EFalse  - the aspect ratio need not be
       
   369  *            retained.
       
   370  *
       
   371  *
       
   372  */
       
   373 void CBitmapScalerPlugin::Scale(TRequestStatus* aRequestStatus,
       
   374 							  CFbsBitmap& aSrcBitmap,
       
   375 							  CFbsBitmap& aTgtBitmap,
       
   376 							  TBool aMaintainAspectRatio)
       
   377 	{
       
   378 	// [ precondition checking on arguments ]
       
   379 	// [ panic if aRequestStatus is NULL ]
       
   380 	__ASSERT_ALWAYS( (aRequestStatus != NULL), Panic( EBadArgumentScale ) );
       
   381 	
       
   382 	//[ panic if the src has not been created]
       
   383 	__ASSERT_ALWAYS( (aSrcBitmap.Handle() != 0), Panic( ENoSourceBitmap ) );
       
   384 	
       
   385 	//[ panic if the tgt has not been created]
       
   386 	__ASSERT_ALWAYS( (aTgtBitmap.Handle() != 0), Panic( ENoDestinationBitmap ) );
       
   387 
       
   388 	iScaleStatus = aRequestStatus;
       
   389 	*iScaleStatus = KRequestPending;
       
   390 
       
   391 	//[ current state must be inactive ]
       
   392 	if( GetCurrentState() != EInactiveState )
       
   393 		{
       
   394 		ProcessError( KErrGeneral );
       
   395 		return;
       
   396 		}
       
   397 		
       
   398 	ASSERT(iDevice==NULL);
       
   399 	
       
   400 	if(aSrcBitmap.ExtendedBitmapType()!=KNullUid || aTgtBitmap.ExtendedBitmapType()!=KNullUid)
       
   401         {
       
   402         RequestComplete(KErrNotSupported);
       
   403         return;
       
   404         }
       
   405 	
       
   406 	iSrcBitmap = &aSrcBitmap;
       
   407 	iTgtBitmap = &aTgtBitmap;
       
   408 
       
   409 	if (!(iFlags & EIsSourceBitmapResized))
       
   410 		{
       
   411 		// As we're not scaling directly to the source bitmap
       
   412 		// we can determine the scaling sizes here (otherwise
       
   413 		// we'd overwrite the values that we got prior to setting
       
   414 		// the tgtBitmap to the srcBitmap!!)
       
   415 		iOrigSize = iSrcBitmap->SizeInPixels();
       
   416 		iDestSize = iTgtBitmap->SizeInPixels();
       
   417 		}
       
   418 
       
   419 	TInt err = KErrNone;
       
   420 
       
   421 	// Target's colour depth
       
   422 	iTgtDisplayMode = iTgtBitmap->DisplayMode();
       
   423 
       
   424 	// Check the aspect ratio and adjust the resolution if needed
       
   425 	if (aMaintainAspectRatio)
       
   426 		{
       
   427 		//[ update destination height to preserve aspect ratio ]
       
   428 	    HeightAndWidthPreservingAspectRatio( iDestSize, iOrigSize );
       
   429 		}
       
   430 
       
   431 	iIntermediateSize.iWidth = iDestSize.iWidth;
       
   432 	if ( QualityAlgorithm() != CBitmapScaler::EMaximumQuality )
       
   433 		{
       
   434 		// Using one of the lower quality algorithms so use the destination size
       
   435 		// that we are scaling to.
       
   436 		iIntermediateSize.iHeight = iDestSize.iHeight;
       
   437 		}
       
   438 	else
       
   439 		{
       
   440 		// Using the original algorithm (which firstly scales horizontally to
       
   441 		// an intermediate bitmap), so the intermediate size requires the original
       
   442 		// height unchanged.
       
   443 		iIntermediateSize.iHeight = iOrigSize.iHeight;
       
   444 		}
       
   445 
       
   446 	// if either of the destination dimension is zero then 
       
   447 	// complete with KErrNone
       
   448 	if ((iDestSize.iWidth == 0) ||
       
   449 		(iDestSize.iHeight == 0))
       
   450 		{
       
   451 		ProcessError(KErrNone);
       
   452 		return;
       
   453 		}
       
   454 
       
   455 	// if either of the source dimension is zero then send back an error 
       
   456 	if ((iOrigSize.iWidth == 0) || 
       
   457 		(iOrigSize.iHeight == 0)) 
       
   458 		{
       
   459 		ProcessError( KErrArgument );
       
   460 		return;
       
   461 		}
       
   462 
       
   463 	// Scale to bitmap of display mode EColor16M except for 
       
   464 	// target bitmaps of EGray256, EColor16MU and EColor16MA
       
   465 	if ( (iTgtDisplayMode == EGray256) || (iTgtDisplayMode == EColor16MU) 
       
   466 			|| (iTgtDisplayMode == EColor16MA))
       
   467 		{
       
   468 		iLocalDisplayMode = iTgtDisplayMode;
       
   469 		}
       
   470 	else
       
   471 		{
       
   472 		iLocalDisplayMode = EColor16M;
       
   473 		}
       
   474 
       
   475 	if (iTgtDisplayMode != EColor16M && iTgtDisplayMode != EColor16MA && iTgtDisplayMode != EColor16MU)
       
   476 		{
       
   477 		// Create an intermediate bitmap to scale to for cases other than EColor16M
       
   478 		if (iScaleBitmap == NULL)
       
   479 			{
       
   480 			// Only want one instance of iScaleBitmap
       
   481 			iScaleBitmap = new CFbsBitmap;
       
   482 			iFlags |= EScaleBitmapIsOwned;	// flag that we're the owner of the scale bitmap
       
   483 			if (iScaleBitmap == NULL)
       
   484 				{
       
   485 				err = KErrNoMemory;
       
   486 				}
       
   487 			}
       
   488 		if( err != KErrNone )
       
   489 			{
       
   490 			ProcessError( err );
       
   491 			return;
       
   492 			}
       
   493 
       
   494 		err = iScaleBitmap->Create(iIntermediateSize, iLocalDisplayMode);
       
   495 
       
   496 		if( err != KErrNone )
       
   497 			{
       
   498 			ProcessError( err );
       
   499 			return;
       
   500 			}
       
   501 			
       
   502 		iDestBmpPtr = iScaleBitmap;
       
   503 		}
       
   504 	else
       
   505 		{
       
   506 		// For EColor16M scale directly to TgtBitmap
       
   507 		iScaleBitmap = iTgtBitmap;
       
   508 
       
   509 		// Downscaling one bitmap to another requires 
       
   510 		// the scale bitmap to be resized to ensure that
       
   511 		// the correct amount of data is read from the source.
       
   512 		if (!(iFlags & EIsSourceBitmapResized))
       
   513 			{
       
   514 			err = iScaleBitmap->Resize(iIntermediateSize);
       
   515 			if (err != KErrNone)
       
   516 				{
       
   517 				ProcessError(err);
       
   518 				return;
       
   519 				}
       
   520 			}
       
   521 		}
       
   522 
       
   523 	iComponentsPerPixel = TDisplayModeUtils::NumDisplayModeBitsPerPixel(iLocalDisplayMode) / KBitsPerByte;
       
   524 	if (iComponentsPerPixel == 0)
       
   525 		{
       
   526 		iComponentsPerPixel = 1;
       
   527 		}
       
   528 
       
   529 		iSrcY = 0;
       
   530 	if (iDestSize.iHeight < iOrigSize.iHeight)
       
   531 		{
       
   532 		iCurY = 0;
       
   533 		}
       
   534 	else
       
   535 		{
       
   536 		iCurY = (iOrigSize.iHeight << KFixedPointScale);
       
   537 		}
       
   538 
       
   539 	if (QualityAlgorithm() == CBitmapScaler::EMaximumQuality)
       
   540 		{
       
   541 		// Try to create and size the scanline bitmap here instead of in the ConstructL
       
   542 	if ((err = iScanlineBitmap->Create(TSize(1, iDestSize.iHeight), iLocalDisplayMode)) != KErrNone)
       
   543 		{
       
   544 		ProcessError(err);
       
   545 		return;
       
   546 		}
       
   547 		}
       
   548 
       
   549 	// Upscaling so ensure we're writing to a suitably
       
   550 	// large target
       
   551 	TInt newWidth = iTgtBitmap->SizeInPixels().iWidth;
       
   552 	TInt newHeight = iTgtBitmap->SizeInPixels().iHeight;
       
   553 	
       
   554 	TBool needsResize = EFalse;
       
   555 	if(iDestSize.iWidth > iOrigSize.iWidth)
       
   556 		{
       
   557 		newWidth = iDestSize.iWidth;
       
   558 		needsResize = ETrue;
       
   559 		}
       
   560 		
       
   561 	if(iDestSize.iHeight > iOrigSize.iHeight)
       
   562 		{
       
   563 		newHeight = iDestSize.iHeight;	
       
   564 		needsResize = ETrue;
       
   565 		}
       
   566 		
       
   567 	if(needsResize)
       
   568 		{
       
   569 		err = iTgtBitmap->Resize(TSize(newWidth, newHeight));
       
   570 			
       
   571 		if( err != KErrNone )
       
   572 			{
       
   573 			ProcessError(err);
       
   574 			return;
       
   575 			}	
       
   576 		}
       
   577 
       
   578 	if (QualityAlgorithm() == CBitmapScaler::EMaximumQuality)
       
   579 		{
       
   580 		// [Create device for normal condition where target bitmap is the
       
   581 		// destination]
       
   582 	TRAP(err, iDevice = CFbsBitmapDevice::NewL(iTgtBitmap));
       
   583 	if( err != KErrNone )
       
   584 		{
       
   585 		ProcessError(KErrNoMemory);
       
   586 		return;
       
   587 			}
       
   588 		}
       
   589 
       
   590 	iDestBmpPtr = iTgtBitmap;
       
   591 
       
   592 	SetProcessingNeeded( EFalse );
       
   593 
       
   594 	//[ Is Post processing required ]
       
   595 	if( ( iTgtDisplayMode != EColor16M) && 
       
   596 		( iTgtDisplayMode != EColor16MU) &&
       
   597 		( iTgtDisplayMode != EColor16MA) &&
       
   598 		( iTgtDisplayMode != EGray256) &&
       
   599 		(! IsPostProcessingDisabled() )  ||
       
   600 		((iTgtDisplayMode == EGray256) && (QualityAlgorithm() != CBitmapScaler::EMaximumQuality) &&
       
   601 											(iLocalDisplayMode != EGray256))
       
   602 		)
       
   603 		{
       
   604 		SetProcessingNeeded( ETrue );	
       
   605 		
       
   606 		//[ create a bitmap converter to colour quantize the image
       
   607 		// to the number of colours available in the output
       
   608 		// note CFbsBitmap has a private constructor whence new is not
       
   609 		//used ]
       
   610 		TRAP(err, iBitmapConverter = CBitmapConverter::NewL());
       
   611 		if(err != KErrNone )
       
   612 			{
       
   613 			ProcessError(err);
       
   614 			return;
       
   615 			}
       
   616 		
       
   617 		//[ create a post processing bitmap]
       
   618 		iPostProcessBitmap = new CFbsBitmap;
       
   619 		if( iPostProcessBitmap == NULL )
       
   620 			{
       
   621 			err = KErrNoMemory;
       
   622 			ProcessError(err);
       
   623 			return;
       
   624 			}
       
   625 		
       
   626 		//[ size the post processing bitmap ]
       
   627 		if ((err = iPostProcessBitmap->Create(iDestSize, EColor16M )) != KErrNone)
       
   628 			{
       
   629 			ProcessError(err);
       
   630 			return;
       
   631 			}
       
   632 		
       
   633 		// Create device with post processing bitmap as the target
       
   634 		delete iDevice;
       
   635 		iDevice = NULL;
       
   636 		iDestBmpPtr = NULL;
       
   637 		if (QualityAlgorithm() == CBitmapScaler::EMaximumQuality)
       
   638 			{
       
   639 		TRAP(err, iDevice = CFbsBitmapDevice::NewL(iPostProcessBitmap));
       
   640 		if( err != KErrNone )
       
   641 			{
       
   642 			ProcessError(err);
       
   643 			return;
       
   644 				}			
       
   645 			}
       
   646 		iDestBmpPtr = iPostProcessBitmap;
       
   647 		}
       
   648 	
       
   649 	iCurOffset = 0;
       
   650 	iCurOffsetUp = iDestSize.iHeight;
       
   651 	if (QualityAlgorithm() != CBitmapScaler::EMaximumQuality)
       
   652 		{
       
   653 		// Using one of the lower quality algorithms
       
   654 		iFinalOffset = iDestSize.iHeight;
       
   655 		if (iTgtBitmap->SizeInPixels() != iDestSize && iTgtBitmap->Handle() != iSrcBitmap->Handle())
       
   656 			{
       
   657 			err = iTgtBitmap->Resize(iDestSize);
       
   658 			if( err != KErrNone )
       
   659 				{
       
   660 				ProcessError(err);
       
   661 				return;
       
   662 				}
       
   663 			}
       
   664 		}
       
   665 	else
       
   666 		{
       
   667 		// We're using the original scaling algorithm
       
   668 		// Set Horizontal Scan flag
       
   669 		iFlags &= ~EVerticalScan;
       
   670 		iFinalOffset = iOrigSize.iHeight;
       
   671 		iCurLineSize = iOrigSize.iWidth;
       
   672 
       
   673 		// Set up filter tables
       
   674 		err = FilterTables();
       
   675 		if( err != KErrNone )
       
   676 			{
       
   677 			ProcessError( err );
       
   678 			return;
       
   679 			}
       
   680 		}
       
   681 
       
   682 	// Allocate the buffers
       
   683 	TInt allocErr = AllocPtr( iOrigDes, iOrigSize.iWidth * iComponentsPerPixel );
       
   684 	if (allocErr == KErrNone)
       
   685 		{
       
   686 		allocErr = AllocPtr( iDestDes, iDestSize.iWidth * iComponentsPerPixel );
       
   687 		}
       
   688 
       
   689 	if( allocErr != KErrNone )
       
   690 		{
       
   691 		ProcessError(allocErr);
       
   692 		return;
       
   693 		}
       
   694 	
       
   695 	if (QualityAlgorithm() == CBitmapScaler::EMaximumQuality)
       
   696 		{
       
   697 		err = iDevice->CreateContext(iGc);
       
   698 		}
       
   699 
       
   700 	if (err != KErrNone)
       
   701 		{
       
   702 		ProcessError(err);
       
   703 		return;
       
   704 		}
       
   705 
       
   706 	//[ set state to scaling ]
       
   707 	SetCurrentState(EScalingState);
       
   708 
       
   709 	//[ assert post conditions of scale request ]
       
   710 	ASSERT( ScaleRequestPostcondition() );
       
   711 
       
   712 	// Start the active object
       
   713 	SelfComplete(KErrNone);
       
   714 	}
       
   715 
       
   716 /*
       
   717 *
       
   718 * FilterTables
       
   719 * Initialise the filter tables
       
   720 *
       
   721 */
       
   722 TInt CBitmapScalerPlugin::FilterTables()
       
   723 	{
       
   724 	TInt result = KErrNone;
       
   725 	
       
   726 	ASSERT(iFilterCoeffsTable==NULL);
       
   727 	ASSERT(iFilterIndexTable==NULL);
       
   728 	
       
   729 	if (iDestSize.iWidth > iDestSize.iHeight)
       
   730 		{
       
   731 		iFilterIndexNum = 2 * iDestSize.iWidth;
       
   732 		}
       
   733 	else
       
   734 		{
       
   735 		iFilterIndexNum = 2 * iDestSize.iHeight;
       
   736 		}
       
   737 
       
   738 	if (iDestSize.iWidth > iOrigSize.iWidth) 
       
   739 		{
       
   740 		iFilterCoeffsNum = iDestSize.iWidth;
       
   741 		}
       
   742 	else
       
   743 		{
       
   744 		iFilterCoeffsNum = 2 * iOrigSize.iWidth;
       
   745 		}
       
   746 	
       
   747 	TInt filterCoeffsNumVert;
       
   748 	
       
   749 	if (iDestSize.iHeight > iOrigSize.iHeight)
       
   750 		{
       
   751 		filterCoeffsNumVert = iDestSize.iHeight;
       
   752 		}
       
   753 	else
       
   754 		{
       
   755 		filterCoeffsNumVert = 2 * iOrigSize.iHeight;
       
   756 		}
       
   757 	
       
   758 	if (filterCoeffsNumVert > iFilterCoeffsNum)
       
   759 		{
       
   760 		iFilterCoeffsNum = filterCoeffsNumVert;
       
   761 		}
       
   762 
       
   763 	//[ allocate a filter index table and check for memory alloc failure]
       
   764 	iFilterIndexTable = new TInt[iFilterIndexNum];
       
   765 	if( iFilterIndexTable  == NULL )
       
   766 		{
       
   767 		return KErrNoMemory;
       
   768 		}
       
   769 	
       
   770 	//[ alloc filter coefficient table and check for memory alloc failure]
       
   771 	iFilterCoeffsTable = new TInt[iFilterCoeffsNum];
       
   772 	if( iFilterCoeffsTable == NULL )
       
   773 		{
       
   774 		return KErrNoMemory;
       
   775 		}
       
   776 	
       
   777 	// Calculate filter tables for horizontal scaling
       
   778 	iFilterIndexTablePtr = iFilterIndexTable;
       
   779 	iFilterCoeffsTablePtr = iFilterCoeffsTable;
       
   780 	result = CalcFilterTables(iOrigSize.iWidth, iDestSize.iWidth, iFilterIndexTablePtr, iFilterCoeffsTablePtr);
       
   781 
       
   782 	return result;
       
   783 	}
       
   784 
       
   785 /*
       
   786 *
       
   787 * DoScale
       
   788 * This function does the scaling of a bitmap in chunks
       
   789 *
       
   790 */
       
   791 void CBitmapScalerPlugin::DoScale()
       
   792 	{
       
   793 	//[assert the invariant ]
       
   794 	__ASSERT_DEBUG( InVariant(), Panic( EBadInvariant ) );
       
   795 
       
   796 	switch( iCurrentState )
       
   797 		{
       
   798 		case EScalingState:
       
   799 			{
       
   800 			//[ we are scaling the image]
       
   801 			if (QualityAlgorithm() != CBitmapScaler::EMaximumQuality)
       
   802 				{
       
   803 				FastScale();
       
   804 				}
       
   805 			else
       
   806 				{
       
   807 				Scale();
       
   808 				}
       
   809 			break;
       
   810 			}
       
   811 		case EStartPostProcessState:
       
   812 			{
       
   813 			//[ we are setting up post processing]
       
   814 			StartPostProcessing();
       
   815 			break;
       
   816 			}
       
   817 		case ECleanUpState:
       
   818 			{
       
   819 			//[ cleaning up ]
       
   820 			ScaleCleanUp();
       
   821 			break;
       
   822 			}
       
   823 		default:
       
   824 			{
       
   825 			//[we can never get here
       
   826 			// because the invariant has been asserted
       
   827 			//assert the invariant ]
       
   828 			__ASSERT_DEBUG( InVariant(), Panic( EBadInvariant ) );
       
   829 			}
       
   830 		}
       
   831 
       
   832 	//[assert the invariant ]
       
   833 	__ASSERT_DEBUG( InVariant(), Panic( EBadInvariant ) );
       
   834 	}
       
   835 
       
   836 /**
       
   837 *
       
   838 * Scale
       
   839 * This method does the scaling
       
   840 * @pre current state is ScalingState
       
   841 */
       
   842 void CBitmapScalerPlugin::Scale()
       
   843 	{
       
   844 #if defined (__SCALING_PROFILING)
       
   845 	RDebug::ProfileStart(7);
       
   846 #endif // __SCALING_PROFILING
       
   847 
       
   848 	//[ assert precondition ]
       
   849     ASSERT( GetCurrentState() == EScalingState );
       
   850 	//[ assert invariant ]
       
   851 	ASSERT( InVariant() );
       
   852 
       
   853 	TInt linesLeftPerCall = KLinesPerCall;
       
   854 	
       
   855 	while (linesLeftPerCall>0 && iCurOffset<iFinalOffset)
       
   856 		{
       
   857 		if (!(iFlags & EVerticalScan))
       
   858 			{
       
   859 			//
       
   860 			// Get current scan line
       
   861 			#if defined (__SCALING_PROFILING)
       
   862 				RDebug::ProfileStart(8);
       
   863 			#endif // __SCALING_PROFILING
       
   864 			iSrcBitmap->GetScanLine(iOrigDes, TPoint(0, iCurOffset), iOrigSize.iWidth, iLocalDisplayMode);
       
   865 			#if defined (__SCALING_PROFILING)
       
   866 				RDebug::ProfileEnd(8);
       
   867 			#endif // __SCALING_PROFILING
       
   868 			}
       
   869 		else
       
   870 			{
       
   871 			#if defined (__SCALING_PROFILING)
       
   872 				RDebug::ProfileStart(11);
       
   873 			#endif // __SCALING_PROFILING
       
   874 			// Get the vertical scan line...
       
   875 			iScaleBitmap->GetVerticalScanLine(iOrigDes, iCurOffset, iLocalDisplayMode);
       
   876 			#if defined (__SCALING_PROFILING)
       
   877 				RDebug::ProfileEnd(11);
       
   878 			#endif // __SCALING_PROFILING
       
   879 			}
       
   880 
       
   881 		if (!(iFlags & EVerticalScan))
       
   882 			{
       
   883 			// Scale the scan line horizontally
       
   884 			for (TInt i=0; i < iComponentsPerPixel; i++)
       
   885 				{
       
   886 				ScaleLine(iOrigDes, iDestDes, i, iOrigSize.iWidth, iDestSize.iWidth, iFilterIndexTable, iFilterCoeffsTable);
       
   887 				}
       
   888 			}
       
   889 		else
       
   890 			{
       
   891 			//
       
   892 			// Scale vertically
       
   893 			for (TInt i=0; i < iComponentsPerPixel; i++)
       
   894 				{
       
   895 				ScaleLine(iOrigDes, iDestDes, i, iOrigSize.iHeight, iDestSize.iHeight, iFilterIndexTable, iFilterCoeffsTable);
       
   896 				}
       
   897 			}
       
   898 
       
   899 #if defined (__SCALING_PROFILING)
       
   900 	RDebug::ProfileStart(10);
       
   901 #endif //__SCALING_PROFILING
       
   902 
       
   903 		if (!(iFlags & EVerticalScan))
       
   904 			{
       
   905 			// Set the scaled horizontal line back into the bitmap
       
   906 			iScaleBitmap->SetScanLine(iDestDes, iCurOffset);
       
   907 			}
       
   908 		else
       
   909 			{
       
   910 			// Write to output bitmap
       
   911 			// Lock & unlock the heap to prevent the Font & Bitmap server moving the bitmap around
       
   912 			// Now writing to iScaleBitmap
       
   913 			if (iDestBmpPtr->DisplayMode()==EColor16MA && iLocalDisplayMode==EColor16MA)
       
   914 				{
       
   915 				TUint8* dataAddress = reinterpret_cast<TUint8*>( iDestBmpPtr->DataAddress());
       
   916 				dataAddress +=iCurOffset*iComponentsPerPixel;
       
   917 				const TInt scanLineLength = iDestBmpPtr->ScanLineLength(iDestBmpPtr->SizeInPixels().iWidth, iDestBmpPtr->DisplayMode() );
       
   918 
       
   919 				const TInt limit = iDestSize.iHeight * iComponentsPerPixel;
       
   920 				const TUint8* ptr = iDestDes.Ptr();
       
   921 				for (TInt y = 0; y < limit; y += iComponentsPerPixel, dataAddress += scanLineLength)
       
   922 					{
       
   923 					CopyPixel(dataAddress,ptr);
       
   924 					ptr += iComponentsPerPixel;
       
   925 					}
       
   926 				}
       
   927 			else
       
   928 				{
       
   929 				TUint8* dataAddress = reinterpret_cast<TUint8*>( iScanlineBitmap->DataAddress());
       
   930 				ASSERT( iScanlineBitmap->SizeInPixels().iWidth==1 ); // that must be a "column"
       
   931 				const TInt scanLineLength = iScanlineBitmap->ScanLineLength(1, iScanlineBitmap->DisplayMode() );
       
   932 
       
   933 				const TInt limit = iDestSize.iHeight * iComponentsPerPixel;
       
   934 				const TUint8* ptr = iDestDes.Ptr();
       
   935 				for (TInt y = 0; y < limit; y += iComponentsPerPixel, dataAddress += scanLineLength)
       
   936 					{
       
   937 					CopyPixel(dataAddress, ptr);
       
   938 					ptr += iComponentsPerPixel;					
       
   939 					}
       
   940 		
       
   941 				iGc->BitBlt(TPoint(iCurOffset, 0), iScanlineBitmap);
       
   942 				}
       
   943 			}
       
   944 
       
   945 #if defined (__SCALING_PROFILING)
       
   946 		RDebug::ProfileEnd(10);
       
   947 #endif //__SCALING_PROFILING
       
   948 
       
   949 		linesLeftPerCall--;
       
   950 		iCurOffset++;
       
   951 		}
       
   952 
       
   953 	if ( IsScalingComplete() && !(iFlags & EVerticalScan))
       
   954 		{
       
   955 		iCurLineSize = iOrigSize.iHeight;
       
   956 		iCurOffset = 0;
       
   957 		iFinalOffset = iDestSize.iWidth;
       
   958 		iFlags |= EVerticalScan;
       
   959 		// Finished the horizontal scaling so now need to setup descriptors
       
   960 		// for the intermediate size as we're now longer using an intermediate
       
   961 		// bitmap.
       
   962 		iOrigSize = iIntermediateSize;
       
   963 
       
   964 		User::Free( reinterpret_cast<TAny*>( const_cast<TUint8*>( iOrigDes.Ptr() ) ) );
       
   965 		iOrigDes.SetLength(0);
       
   966 
       
   967 		TInt allocErr = AllocPtr(iOrigDes, iOrigSize.iHeight * iComponentsPerPixel);
       
   968 		if( allocErr != KErrNone )
       
   969 			{
       
   970 			ProcessError( allocErr );
       
   971 			return;
       
   972 			}
       
   973 
       
   974 		User::Free( reinterpret_cast<TAny*>( const_cast<TUint8*>( iDestDes.Ptr() ) ) );
       
   975 		iDestDes.SetLength(0);
       
   976 
       
   977 		allocErr = AllocPtr(iDestDes, iDestSize.iHeight * iComponentsPerPixel);
       
   978 		if( allocErr != KErrNone )
       
   979 			{
       
   980 			ProcessError( allocErr );
       
   981 			return;
       
   982 			}
       
   983 		iFilterIndexTablePtr = iFilterIndexTable;
       
   984 		iFilterCoeffsTablePtr = iFilterCoeffsTable;
       
   985 		TInt err = CalcFilterTables(iOrigSize.iHeight, iDestSize.iHeight, iFilterIndexTablePtr, iFilterCoeffsTablePtr);
       
   986 		if( err != KErrNone )
       
   987 			{
       
   988 			ProcessError(err);
       
   989 			return;
       
   990 			}
       
   991 		}
       
   992 	else if ( IsScalingComplete() )
       
   993 		{
       
   994 		// Finished the vertical scaling so, as the tgtbitmap has been scaled in place (ie
       
   995 		// to the intermediate size) we need to resize it to the true destination size
       
   996 		TInt err = iTgtBitmap->Resize(iDestSize);
       
   997 		if( err != KErrNone )
       
   998 			{
       
   999 			ProcessError(err);
       
  1000 			return;
       
  1001 			}
       
  1002 
       
  1003 		if( IsPostProcessingNeeded() )
       
  1004 			{
       
  1005 			//[ transition to start post processing state]
       
  1006 			SetCurrentState( EStartPostProcessState );
       
  1007 			}
       
  1008 		else
       
  1009 			{
       
  1010 			//[ transition to cleanup state ]
       
  1011 			SetCurrentState( ECleanUpState );
       
  1012 			}
       
  1013 		}
       
  1014 	
       
  1015 	// Start the active object
       
  1016 	SelfComplete(KErrNone);
       
  1017 
       
  1018 #if defined (__SCALING_PROFILING)
       
  1019 	RDebug::ProfileEnd(7);
       
  1020 #endif // __SCALING_PROFILING
       
  1021 
       
  1022 	//[ assert invariant ]
       
  1023 	ASSERT( InVariant() );
       
  1024 	}
       
  1025 
       
  1026 /*
       
  1027 *
       
  1028 * StartPostProcessing
       
  1029 *
       
  1030 */
       
  1031 void CBitmapScalerPlugin::StartPostProcessing()
       
  1032 	{
       
  1033 	ASSERT( InVariant() );
       
  1034 	ASSERT( GetCurrentState() == EStartPostProcessState );
       
  1035 	// set state to post processing in progress
       
  1036 	// lauch async post process operation
       
  1037 	SetCurrentState(ECleanUpState);	
       
  1038 
       
  1039 	iBitmapConverter->Convert( &iStatus, *iTgtBitmap, *iDestBmpPtr);	
       
  1040 
       
  1041 	SetActive();
       
  1042 	ASSERT( InVariant() );
       
  1043 	ASSERT( GetCurrentState() == ECleanUpState );
       
  1044 	}
       
  1045 
       
  1046 /*
       
  1047 *
       
  1048 * GetCurrentState
       
  1049 * @return CBitmapScalerPlugin::TScaleState The current state
       
  1050 * of the state machine
       
  1051 *
       
  1052 */
       
  1053 CBitmapScalerPlugin::TScaleState CBitmapScalerPlugin::GetCurrentState() const
       
  1054 	{
       
  1055 	return iCurrentState;
       
  1056 	}
       
  1057 
       
  1058 /*
       
  1059 *
       
  1060 * SetCurrentState
       
  1061 * @param aState
       
  1062 * @pre aState <= CleanUpState
       
  1063 * @pre aState >= InactiveState
       
  1064 * @post Invariant
       
  1065 *
       
  1066 */
       
  1067 void CBitmapScalerPlugin::SetCurrentState( TScaleState aState )
       
  1068 	{
       
  1069 	iCurrentState = aState;
       
  1070 	}
       
  1071 
       
  1072 /*
       
  1073 *
       
  1074 * CleanUp
       
  1075 *
       
  1076 */
       
  1077 void CBitmapScalerPlugin::ScaleCleanUp()
       
  1078 	{
       
  1079 	TInt errStatus = iStatus.Int();
       
  1080 
       
  1081 	if( errStatus == KErrNone )
       
  1082 		{
       
  1083 		if ((iFlags & ECreatedTempBitmap) != 0)
       
  1084 			{
       
  1085 			if (iTempBitmap)
       
  1086 				{
       
  1087 				TInt handle = 0;
       
  1088 				if (QualityAlgorithm() != CBitmapScaler::EMaximumQuality)
       
  1089 					{
       
  1090 					// medium OR min qualitity algorithm
       
  1091 					handle = iDestBmpPtr->Handle();
       
  1092 					}
       
  1093 				else
       
  1094 					{
       
  1095 					// Normal (maximum quality) algorithm
       
  1096 					handle = iTgtBitmap->Handle();
       
  1097 					}
       
  1098 				errStatus = iSrcBitmap->Duplicate(handle);
       
  1099 				}
       
  1100 			}
       
  1101 		}
       
  1102 
       
  1103 	ProcessError( errStatus );
       
  1104 	}
       
  1105 
       
  1106 /*
       
  1107 *
       
  1108 * ProcessError
       
  1109 * @param aErrorStatus
       
  1110 *
       
  1111 */
       
  1112 void CBitmapScalerPlugin::ProcessError( TInt aErrorStatus )
       
  1113 	{
       
  1114 	if( iPostProcessBitmap )
       
  1115 		{
       
  1116 		iPostProcessBitmap->Reset();
       
  1117 		}
       
  1118 	Cleanup();
       
  1119 	RequestComplete( aErrorStatus );
       
  1120 	}
       
  1121 
       
  1122 /*
       
  1123 *
       
  1124 * IsScalingComplete
       
  1125 * @return TBool scaling process has been completed
       
  1126 *
       
  1127 */
       
  1128 TBool CBitmapScalerPlugin::IsScalingComplete() const
       
  1129 	{
       
  1130 	TBool result = EFalse ;
       
  1131 	if(iCurOffset == iFinalOffset || iCurOffsetUp == 0) 
       
  1132 		{
       
  1133 		result = ETrue;
       
  1134 		}
       
  1135 	return result;
       
  1136 	}
       
  1137 
       
  1138 /*
       
  1139 *
       
  1140 * RunL
       
  1141 * Handles an active object’s request completion event.
       
  1142 * The function is called by the active scheduler 
       
  1143 * when a request completion event occurs.
       
  1144 */
       
  1145 void CBitmapScalerPlugin::RunL()
       
  1146 	{
       
  1147 	DoScale();
       
  1148 	}
       
  1149 
       
  1150 /*
       
  1151 *
       
  1152 * DoCancel
       
  1153 * Called by active object to prematurely terminate this bitmap scaling.
       
  1154 *
       
  1155 */
       
  1156 void CBitmapScalerPlugin::DoCancel()
       
  1157 	{
       
  1158 	ASSERT( InVariant());
       
  1159 	
       
  1160 	if( iBitmapConverter )
       
  1161 		{
       
  1162 		iBitmapConverter->Cancel();
       
  1163 		}
       
  1164 	
       
  1165 	Cleanup();
       
  1166 	ASSERT( GetCurrentState() == EInactiveState );
       
  1167 	ASSERT( InVariant());
       
  1168 	RequestComplete(KErrCancel);
       
  1169 	}
       
  1170 
       
  1171 /*
       
  1172 * 
       
  1173 * RequestComplete
       
  1174 * @param "TInt aReason"
       
  1175 *
       
  1176 */
       
  1177 void CBitmapScalerPlugin::RequestComplete(TInt aReason)
       
  1178 	{
       
  1179 	ASSERT(iScaleStatus);
       
  1180 	TRequestStatus* status = iScaleStatus;
       
  1181 	User::RequestComplete(status, aReason);
       
  1182 	}
       
  1183 
       
  1184 /*
       
  1185 *
       
  1186 * SelfComplete
       
  1187 * This function activates the active object and 
       
  1188 * signals completion of the current asynchronous operation
       
  1189 *
       
  1190 * @param "TInt aReason"
       
  1191 *
       
  1192 */
       
  1193 void CBitmapScalerPlugin::SelfComplete(TInt aReason)
       
  1194 	{
       
  1195 	SetActive();
       
  1196 	TRequestStatus* status = &iStatus;
       
  1197 	User::RequestComplete(status, aReason);
       
  1198 	}
       
  1199 
       
  1200 /*
       
  1201 *
       
  1202 * This function calculates the filter tables for scaling
       
  1203 * CalcFilterTables
       
  1204 * @param "TInt aOrigWidth"
       
  1205 * @param "TInt aDestWidth"
       
  1206 * @param "TInt*& aFilterCoeffsTablePtr"
       
  1207 *
       
  1208 */
       
  1209 TInt CBitmapScalerPlugin::CalcFilterTables(TInt aOrigWidth, TInt aDestWidth, TInt*& aFilterIndexTablePtr, TInt*& aFilterCoeffsTablePtr)
       
  1210 	{
       
  1211 	TInt inputWidth = aOrigWidth;
       
  1212 	TInt scaledWidth = aDestWidth;
       
  1213 	//this is added since to test indX<< KFixedPointBits for overflow 
       
  1214 	TInt fixedPointsVal = 1<<KFixedPointBits;
       
  1215 
       
  1216 	if ( (MAKE_TUINT64(0,inputWidth) * MAKE_TUINT64(0,scaledWidth)) > KMaxTInt )
       
  1217     	{
       
  1218     	return KErrOverflow;	
       
  1219     	}
       
  1220 	//Checking OverFlow for ((indX << KFixedPointBits) * inputWidth) 
       
  1221     if ( (MAKE_TUINT64(0,inputWidth) * MAKE_TUINT64(0,scaledWidth) * MAKE_TUINT64(0,fixedPointsVal)) > KMaxTInt )
       
  1222     	{
       
  1223     	return KErrOverflow;	
       
  1224     	}
       
  1225 	if ( scaledWidth > inputWidth )
       
  1226 		{
       
  1227 		// Calculate tables for interpolation (scaling up)
       
  1228 		for (TInt indX = 0; indX < scaledWidth; indX++)
       
  1229 			{
       
  1230 			const TInt indFilt = ((indX << KFixedPointBits) * inputWidth) / scaledWidth;
       
  1231 			const TInt firstX  = indFilt >> KFixedPointBits;
       
  1232 			const TInt lastX = (firstX >= inputWidth - 1) ? firstX : firstX+1;
       
  1233 
       
  1234 			*aFilterIndexTablePtr++ = firstX;
       
  1235 			*aFilterIndexTablePtr++ = lastX;
       
  1236 			*aFilterCoeffsTablePtr++ = indFilt - (firstX << KFixedPointBits);
       
  1237 			}
       
  1238 		}
       
  1239 	else
       
  1240 		{
       
  1241 		// Calculate tables for decimation (scaling down)		
       
  1242 		const TInt ftNew = (inputWidth << KFixedPointBits)/scaledWidth;
       
  1243 		TInt firstX = 0;
       
  1244 		TInt lastX = 0;
       
  1245 		for (TInt indX = 0; indX < scaledWidth; indX++)
       
  1246 			{
       
  1247 			firstX = lastX;
       
  1248 			lastX = ((indX + 1) * inputWidth) / scaledWidth;
       
  1249 
       
  1250 			*aFilterIndexTablePtr++ = firstX;
       
  1251 			*aFilterIndexTablePtr++ = lastX;
       
  1252 
       
  1253 			const TInt indOrig	= ((indX << KFixedPointBits) * inputWidth) / scaledWidth;
       
  1254 			const TInt indOrigInt = indOrig >> KFixedPointBits;
       
  1255 			for (TInt indFilt = firstX; indFilt <= lastX; indFilt++)
       
  1256 				{
       
  1257 				TInt fixTap;
       
  1258 				if(indFilt <= indOrigInt)
       
  1259 					{
       
  1260 					fixTap = ftNew - (indOrig - (indFilt << KFixedPointBits));
       
  1261 					}
       
  1262 				else
       
  1263 					{
       
  1264 					fixTap = ftNew - ((indFilt << KFixedPointBits) - indOrig);
       
  1265 					}
       
  1266 
       
  1267 				if (fixTap < 0) 
       
  1268 					{
       
  1269 					fixTap = 0;
       
  1270 					}
       
  1271 				*aFilterCoeffsTablePtr++ = (fixTap << KFixedPointBits) / ftNew;
       
  1272 				}
       
  1273 			}
       
  1274 		}
       
  1275 	return KErrNone;
       
  1276 	}
       
  1277 
       
  1278 
       
  1279 /*
       
  1280 * This function calculates the filter tables for scaling
       
  1281 * ScaleLine
       
  1282 * @param "const TDesC8& aInDes"
       
  1283 * @param "TDes8& aOutDes" 
       
  1284 * @param "TInt* aTableCoeffsPtr"
       
  1285 *
       
  1286 */
       
  1287 void CBitmapScalerPlugin::ScaleLine(const TDesC8& aInDes,
       
  1288 								  TDes8& aOutDes,
       
  1289 								  TInt aStartIndex,
       
  1290 								  TInt aInputWidth,
       
  1291 								  TInt aOutputWidth,
       
  1292 								  TInt* aTableIndexPtr, TInt* aTableCoeffsPtr)
       
  1293 	{
       
  1294 #if defined (__SCALING_PROFILING)
       
  1295 	RDebug::ProfileStart(9);
       
  1296 #endif // __SCALING_PROFILING
       
  1297 	
       
  1298 	// Initialize variables
       
  1299 	TInt* tableIndexesPtr = aTableIndexPtr;
       
  1300 	TInt* tableCoeffsPtr  = aTableCoeffsPtr;
       
  1301 
       
  1302 	if (aOutputWidth == aInputWidth)
       
  1303 		{
       
  1304 		aOutDes = aInDes;
       
  1305 		}
       
  1306 	else if (aOutputWidth > aInputWidth)
       
  1307 		{
       
  1308 		// Perform interpolation when scaling up
       
  1309 		const TInt startIndex = aStartIndex;
       
  1310 		const TUint8* inputDesPtr = aInDes.Ptr();
       
  1311 		TUint8* outputDesPtr = const_cast<TUint8*>( aOutDes.Ptr() );
       
  1312 
       
  1313 		for (TInt indX = 0; indX < aOutputWidth; indX++, aStartIndex += iComponentsPerPixel)
       
  1314 			{
       
  1315 			TInt firstX = *tableIndexesPtr++;
       
  1316 			TInt lastX  = *tableIndexesPtr++;
       
  1317 			TInt fixTap = *tableCoeffsPtr++;
       
  1318 
       
  1319 			// Stay in bounds
       
  1320 			if (firstX >= aInputWidth)
       
  1321 				{
       
  1322 				firstX = aInputWidth - 1;	
       
  1323 				}
       
  1324 			// Factor for aggregated colour component
       
  1325 			firstX *= iComponentsPerPixel;
       
  1326 			firstX += startIndex;
       
  1327 
       
  1328 			// Stay in bounds
       
  1329 			if (lastX >= aInputWidth)
       
  1330 				{
       
  1331 				lastX = aInputWidth - 1;	
       
  1332 				}
       
  1333 			lastX *= iComponentsPerPixel;
       
  1334 			lastX += startIndex;
       
  1335 
       
  1336 			// Filtering
       
  1337 			outputDesPtr[aStartIndex] = 
       
  1338 				TUint8(((fixTap * TInt(inputDesPtr[lastX])+ 
       
  1339 						 (KFixedPointScale - fixTap) * TInt(inputDesPtr[firstX])) 
       
  1340 						 >> KFixedPointBits));
       
  1341 			}
       
  1342 		}
       
  1343 	else
       
  1344 		{
       
  1345 		// Perform decimation if scaling down requested
       
  1346 		const TInt startIndex = aStartIndex;
       
  1347 		const TInt widthLimit = iComponentsPerPixel * aInputWidth;
       
  1348 		const TInt16 startWidthlimit = widthLimit - iComponentsPerPixel + startIndex;
       
  1349 		const TUint8* inputDesPtr = aInDes.Ptr();
       
  1350 		TUint8* outputDesPtr = const_cast<TUint8*>( aOutDes.Ptr() );
       
  1351 
       
  1352 		for (TInt indX = 0; indX < aOutputWidth; indX++, aStartIndex += iComponentsPerPixel)
       
  1353 			{
       
  1354 			TInt firstX = *tableIndexesPtr++;
       
  1355 			firstX *= iComponentsPerPixel;
       
  1356 			firstX += startIndex;
       
  1357 			
       
  1358 			TInt lastX  = *tableIndexesPtr++;
       
  1359 			if (lastX >= aInputWidth)
       
  1360 				{
       
  1361 				lastX = aInputWidth - 1;	
       
  1362 				}
       
  1363 			lastX *= iComponentsPerPixel;
       
  1364 			lastX += startIndex;
       
  1365 			
       
  1366 			// Filtering
       
  1367 			TInt sum       = 0;
       
  1368 			TInt fixTapSum = 0;
       
  1369 			for(TInt indFilt = firstX; indFilt <= lastX; indFilt += iComponentsPerPixel)
       
  1370 				{
       
  1371 				TInt fixTap = *tableCoeffsPtr++;
       
  1372 				TInt indIn;
       
  1373 				if (indFilt < 0)
       
  1374 					{
       
  1375 					indIn = startIndex;
       
  1376 					}
       
  1377 				else if (indFilt >= widthLimit )
       
  1378 					{
       
  1379 					indIn = startWidthlimit;
       
  1380 					}
       
  1381 				else
       
  1382 					{
       
  1383 					indIn = indFilt;
       
  1384 					}
       
  1385 
       
  1386 				sum += fixTap * TInt(inputDesPtr[indIn]);
       
  1387 				fixTapSum = TInt(fixTapSum + fixTap);
       
  1388 				}
       
  1389 
       
  1390 			// Let's not divide by zero
       
  1391 			if (fixTapSum == 0)
       
  1392 				{
       
  1393 				outputDesPtr[aStartIndex] = TUint8(sum);
       
  1394 				}
       
  1395 			else
       
  1396 				{
       
  1397 				outputDesPtr[aStartIndex] = TUint8(sum/fixTapSum);	
       
  1398 				}
       
  1399 			}
       
  1400 		}
       
  1401 #if defined (__SCALING_PROFILING)
       
  1402 	RDebug::ProfileEnd(9);
       
  1403 #endif // __SCALING_PROFILING
       
  1404 	}
       
  1405 
       
  1406 
       
  1407 /*
       
  1408 *
       
  1409 * InVariant
       
  1410 * Used to determine the state of health of the scaler body
       
  1411 *
       
  1412 */
       
  1413 TBool CBitmapScalerPlugin::InVariant() const
       
  1414 	{
       
  1415     return ((iCurrentState <= ECleanUpState ) && (iCurrentState >= EInactiveState ));
       
  1416 	}
       
  1417 
       
  1418 /**
       
  1419 *
       
  1420 * SetProcessingNeeded
       
  1421 * @param aStatus ETrue EFalse
       
  1422 *
       
  1423 */
       
  1424 void CBitmapScalerPlugin::SetProcessingNeeded( TBool aStatus )
       
  1425 	{
       
  1426 	if(aStatus)
       
  1427 		{
       
  1428 		iFlags |= EIsPostProcessingNeeded;
       
  1429 		}
       
  1430 	else
       
  1431 		{
       
  1432 		iFlags &= ~EIsPostProcessingNeeded;
       
  1433 		}
       
  1434 	}
       
  1435 
       
  1436 /**
       
  1437 *
       
  1438 * SetDisablePostProcessing
       
  1439 * @param aStatus ETrue EFalse
       
  1440 *
       
  1441 */
       
  1442 void CBitmapScalerPlugin::SetDisablePostProcessing( TBool aIsDisabled )
       
  1443 	{
       
  1444 	if(aIsDisabled)
       
  1445 		{
       
  1446 		iFlags |= EDisablePostProcessing;
       
  1447 		}
       
  1448 	else
       
  1449 		{
       
  1450 		iFlags &= ~EDisablePostProcessing;
       
  1451 		}
       
  1452 	}
       
  1453 
       
  1454 /**
       
  1455 *
       
  1456 * IsPostProcessingDisabled
       
  1457 * @return ETrue, EFalse
       
  1458 *
       
  1459 */
       
  1460 TBool CBitmapScalerPlugin::IsPostProcessingDisabled()
       
  1461 	{
       
  1462 	return ((iFlags & EDisablePostProcessing) != 0);
       
  1463 	}
       
  1464 
       
  1465 /**
       
  1466 *
       
  1467 * IsPostProcessingNeeded
       
  1468 * @return TBool scaling process has been completed
       
  1469 *
       
  1470 */
       
  1471 TBool CBitmapScalerPlugin::IsPostProcessingNeeded() const
       
  1472 	{
       
  1473 	return ((iFlags & EIsPostProcessingNeeded) != 0);
       
  1474 	}
       
  1475 
       
  1476 /*
       
  1477 *
       
  1478 * HeightAndWidthPreservingAspectRatio
       
  1479 * @param aDestSize
       
  1480 * @param aOrigSize
       
  1481 * Calculates the destination bitmap size based on preserving
       
  1482 * the aspect ratio of the original bitmap
       
  1483 * @pre aOrigSize is not zero in any dimension
       
  1484 */
       
  1485 void CBitmapScalerPlugin::HeightAndWidthPreservingAspectRatio( TSize& aDestSize, const TSize& aOrigSize ) const
       
  1486     {
       
  1487     
       
  1488     if ((aOrigSize.iWidth == 0) || (aOrigSize.iHeight == 0))
       
  1489         {
       
  1490         return;
       
  1491         }
       
  1492 
       
  1493     // no need to optimise, it is not a kernal function which may get called many times
       
  1494     TReal widthRatio = (TReal)aDestSize.iWidth / (TReal)aOrigSize.iWidth;
       
  1495     TReal heightRatio = (TReal)aDestSize.iHeight / (TReal)aOrigSize.iHeight;
       
  1496 
       
  1497     // choose the smaller ratio to use
       
  1498     if(widthRatio < heightRatio)
       
  1499         {
       
  1500         TReal height;
       
  1501         Math::Round(height, aOrigSize.iHeight * widthRatio, 0);
       
  1502         aDestSize.iHeight = static_cast<TInt>(height);
       
  1503         }
       
  1504     else
       
  1505         {
       
  1506         TReal width;
       
  1507         Math::Round(width, aOrigSize.iWidth * heightRatio, 0);
       
  1508         aDestSize.iWidth = static_cast<TInt>(width);
       
  1509         }
       
  1510     }
       
  1511 
       
  1512 /*
       
  1513 *
       
  1514 * IsPostProcessingEnabled
       
  1515 * @return 'TBool'
       
  1516 * 
       
  1517 */
       
  1518 TBool CBitmapScalerPlugin::IsPostProcessingEnabled() const
       
  1519 	{
       
  1520 	return ((iFlags & EPostProcessingEnabled) != 0);
       
  1521 	}
       
  1522 
       
  1523 /*
       
  1524 *
       
  1525 * SetPostProcessingEnabled
       
  1526 * @param aIsEnabled
       
  1527 * 
       
  1528 */
       
  1529 void CBitmapScalerPlugin::SetPostProcessingEnabled( TBool aIsEnabled )
       
  1530 	{
       
  1531 	if(aIsEnabled)
       
  1532 		{
       
  1533 		iFlags |= EPostProcessingEnabled;
       
  1534 		}
       
  1535 	else
       
  1536 		{
       
  1537 		iFlags &= ~EPostProcessingEnabled;
       
  1538 		}
       
  1539 	}
       
  1540 
       
  1541 /*
       
  1542 *
       
  1543 * CustomCommand
       
  1544 * @param aUid
       
  1545 * @param aParam
       
  1546 * @return 'TInt' an error code indicating success or failure of the 
       
  1547 * command
       
  1548 *
       
  1549 */
       
  1550 TInt CBitmapScalerPlugin::CustomCommand(TUid aUid, TAny* aParam)
       
  1551 	{
       
  1552 	TInt status = KErrNotSupported;
       
  1553 	if( ( aUid == KICLUidPostProcessCommand ) && ( aParam != NULL ) )
       
  1554 		{
       
  1555 		TBool postProcess = *( reinterpret_cast<TBool*>(aParam));
       
  1556 		SetDisablePostProcessing( postProcess ); 
       
  1557 		status = KErrNone;
       
  1558 		}
       
  1559 	else if( ( aUid == KICLUidUseLowMemoryAlgorithmCommand ) && ( aParam != NULL ) )
       
  1560 		{
       
  1561 		TBool useLowMemAlgorithm = *( reinterpret_cast<TBool*>(aParam) );
       
  1562 		SetUseLowMemoryAlgorithm( useLowMemAlgorithm );
       
  1563 		status = KErrNone;
       
  1564 		}
       
  1565 	else if( ( aUid == KICLUidSetQualityAlgorithmCommand ) && ( aParam != NULL ) )
       
  1566 		{
       
  1567 		CBitmapScaler::TQualityAlgorithm quality = *( reinterpret_cast<CBitmapScaler::TQualityAlgorithm*>(aParam) );
       
  1568 		SetQualityAlgorithm(quality);
       
  1569 		status = KErrNone;
       
  1570 		}
       
  1571  
       
  1572 	return status;
       
  1573 	}
       
  1574 
       
  1575 /*
       
  1576 *
       
  1577 * UseLowMemoryAlgorithm
       
  1578 * @return 'TBool'
       
  1579 * 
       
  1580 */
       
  1581 TBool CBitmapScalerPlugin::UseLowMemoryAlgorithm() const
       
  1582 	{
       
  1583 	return ((iFlags & EUseLowMemoryAlgorithm) != 0);
       
  1584 	}
       
  1585 
       
  1586 /*
       
  1587 *
       
  1588 * SetUseLowMemoryAlgorithm
       
  1589 * @param aUseLowMemoryAlgorithm
       
  1590 * 
       
  1591 */
       
  1592 void CBitmapScalerPlugin::SetUseLowMemoryAlgorithm(TBool aUseLowMemoryAlgorithm)
       
  1593 	{
       
  1594 	if(aUseLowMemoryAlgorithm)
       
  1595 		{
       
  1596 		iFlags |= EUseLowMemoryAlgorithm;
       
  1597 		}
       
  1598 	else
       
  1599 		{
       
  1600 		iFlags &= ~EUseLowMemoryAlgorithm;
       
  1601 		}
       
  1602 	}
       
  1603 
       
  1604 /*
       
  1605 *
       
  1606 * SetQualityAlgorithm
       
  1607 * @param CBitmapScaler::TQualityAlgorithm aQuality
       
  1608 * 
       
  1609 */
       
  1610 void CBitmapScalerPlugin::SetQualityAlgorithm( CBitmapScaler::TQualityAlgorithm aQuality)
       
  1611 	{
       
  1612 	iQualityLevel = aQuality;
       
  1613 	}
       
  1614 
       
  1615 /*
       
  1616 *
       
  1617 *	QualityAlgorithm
       
  1618 *	@return CBitmapScaler::TQualityAlgorithm
       
  1619 *
       
  1620 */
       
  1621 CBitmapScaler::TQualityAlgorithm CBitmapScalerPlugin::QualityAlgorithm() const
       
  1622 	{
       
  1623 	return iQualityLevel;
       
  1624 	}
       
  1625 
       
  1626 /**
       
  1627 *	This function is called when the state iCurrentState == EScalingState 
       
  1628 *	and either the UseMediumQualityAlgorithm or the UseMinimumQualityAlgorithm custom
       
  1629 *	commands have been invoked.
       
  1630 *	In terms of speed and quality, the normal algorithm, as implemented in Scale(),
       
  1631 *	is the slowest / highest quality, whereas the fastest / lowest quality
       
  1632 *	implementation is for the case when UseMinimumQualityAlgorithm is specified.
       
  1633 *	The difference between the minimum quality and fast algorithms is that
       
  1634 *	the fast algorithm forms the destination value from weighted averages of
       
  1635 *	the x values prior to and proceeding the value under consideration.
       
  1636 */
       
  1637 void CBitmapScalerPlugin::FastScale()
       
  1638 	{
       
  1639 #if defined (__SCALING_PROFILING)
       
  1640 	RDebug::ProfileStart(7);
       
  1641 #endif // __SCALING_PROFILING
       
  1642 	TInt linesLeftPerCall = KLinesPerCall;
       
  1643 	
       
  1644 	// Height and width to scale to
       
  1645 	const TInt maxX = iDestSize.iWidth * iComponentsPerPixel;
       
  1646 	const TInt stepY = (iOrigSize.iHeight << KFixedPointScale) / iDestSize.iHeight;
       
  1647 	const TInt destBufferLength = iDestDes.Length();
       
  1648 	const TInt divisor = (destBufferLength < iDestSize.iWidth ? destBufferLength : iDestSize.iWidth);
       
  1649 	const TInt stepX = (iOrigSize.iWidth << KFixedPointScale) / divisor;
       
  1650 	TInt sourceX = 0;	// x
       
  1651 	const TInt roundVal = 1;
       
  1652 	if (iDestSize == iOrigSize)
       
  1653 		{
       
  1654 		// Same size so just directly copy values.
       
  1655 		while(linesLeftPerCall > 0 && iCurOffset < iFinalOffset)
       
  1656 			{
       
  1657 			iSrcBitmap->GetScanLine(iOrigDes, TPoint(0, iCurOffset), iOrigSize.iWidth, iLocalDisplayMode);
       
  1658 			iDestBmpPtr->SetScanLine(iOrigDes, iCurOffset);
       
  1659 			linesLeftPerCall--;
       
  1660 			iCurOffset++;
       
  1661 			}
       
  1662 		}
       
  1663 	else if (iDestSize.iHeight < iOrigSize.iHeight)
       
  1664 		{
       
  1665 		TInt currentX = 0;
       
  1666 		// For downscaling (destination bitmap size is smaller than the original bitmap size)
       
  1667 		while(linesLeftPerCall > 0 && iCurOffset < iFinalOffset)
       
  1668 			{
       
  1669 			sourceX = 0;			
       
  1670 			// Fetch the relevant row from the source bitmap
       
  1671 			iSrcBitmap->GetScanLine(iOrigDes, TPoint(0, iSrcY), iOrigSize.iWidth, iLocalDisplayMode);
       
  1672 
       
  1673 			// Get each colour component of each relevant pixel
       
  1674 			for (TInt x = 0; x < maxX; x += iComponentsPerPixel)
       
  1675 				{
       
  1676 				//Line scaling
       
  1677 				ScaleBitmapLine(x,sourceX);
       
  1678 				// Increment to the next pixel
       
  1679 				currentX += stepX;
       
  1680 				// Avoid TInt rounding error
       
  1681 				sourceX = ( currentX + (roundVal << KFixedPointScale - 1) ) >> KFixedPointScale;
       
  1682 				// Factor for the number of components
       
  1683 				sourceX *= iComponentsPerPixel;
       
  1684 				// Stay in bounds
       
  1685 				if (sourceX >= iOrigDes.Length())
       
  1686 					{
       
  1687 					sourceX = iOrigDes.Length() - iComponentsPerPixel;
       
  1688 					}
       
  1689 				}
       
  1690 			currentX = 0;	// reset the x counter
       
  1691 			iDestBmpPtr->SetScanLine(iDestDes, iCurOffset);	// set the scaled line into the target
       
  1692 				
       
  1693 			// increment to the next row
       
  1694 			iCurY += stepY;
       
  1695 			// avoiding any rounding errors (using TInt = (TInt + 0.5) )
       
  1696 			iSrcY = (iCurY + (roundVal << KFixedPointScale - 1) ) >> KFixedPointScale;
       
  1697 			// Stay in bounds
       
  1698 			if (iSrcY >= iOrigSize.iHeight)
       
  1699 				{
       
  1700 				iSrcY = iOrigSize.iHeight - 1;
       
  1701 				}
       
  1702 			linesLeftPerCall--;
       
  1703 			iCurOffset++;
       
  1704 			}
       
  1705 		}
       
  1706 	else
       
  1707 		{
       
  1708 		TInt currentX = 0;
       
  1709 		//For upscaling (Destination bitmap size is bigger than the original bitmap size)
       
  1710 		while(linesLeftPerCall > 0 && iCurOffsetUp !=0 )
       
  1711 			{
       
  1712 			sourceX = 0;			
       
  1713 			// avoiding any rounding errors (using TInt = (TInt + 0.5) )
       
  1714 			iSrcY = (iCurY + (roundVal << KFixedPointScale - 1) ) >> KFixedPointScale;
       
  1715 			// Fetch the relevant row from the source bitmap
       
  1716 			iSrcBitmap->GetScanLine(iOrigDes, TPoint(0, iSrcY), iOrigSize.iWidth, iLocalDisplayMode);
       
  1717 			
       
  1718 			// Get each colour component of each relevant pixel
       
  1719 			for (TInt x = 0; x < maxX; x += iComponentsPerPixel)
       
  1720 				{
       
  1721 				//Line scaling
       
  1722 				ScaleBitmapLine(x,sourceX);
       
  1723 				// Increment to the next pixel
       
  1724 				currentX += stepX;
       
  1725 				// Avoid TInt rounding error
       
  1726 				sourceX = ( currentX + (roundVal << KFixedPointScale - 1) ) >> KFixedPointScale;
       
  1727 				// Factor for the number of components
       
  1728 				sourceX *= iComponentsPerPixel;
       
  1729 				// Stay in bounds
       
  1730 				if (sourceX >= iOrigDes.Length())
       
  1731 					{
       
  1732 					sourceX = iOrigDes.Length() - iComponentsPerPixel;
       
  1733 					}
       
  1734 				}
       
  1735 			currentX = 0;	// reset the x counter
       
  1736 			iDestBmpPtr->SetScanLine(iDestDes, iCurOffsetUp);	// set the scaled line into the target				
       
  1737 			// Decrement to the next row from the end
       
  1738 			iCurY -= stepY;	
       
  1739 			// Stay in bounds
       
  1740 			if (iSrcY >= iOrigSize.iHeight)
       
  1741 				{
       
  1742 				iSrcY = iOrigSize.iHeight - 1;
       
  1743 				}
       
  1744 			linesLeftPerCall--;
       
  1745 			iCurOffsetUp--;
       
  1746 			}
       
  1747 		}
       
  1748 	if (IsScalingComplete())
       
  1749 		{
       
  1750 		// in case of low memory algo and 1 bitmap we have to resize the resulting bitmap
       
  1751 		if (iDestBmpPtr->Handle() == iSrcBitmap->Handle()
       
  1752 				&& iDestBmpPtr->SizeInPixels() != iDestSize )
       
  1753 			{
       
  1754 			TInt err=iDestBmpPtr->Resize(iDestSize);
       
  1755 			if (err != KErrNone)
       
  1756 				{
       
  1757 				ProcessError( err );
       
  1758 				return;
       
  1759 				}
       
  1760 			}		
       
  1761 		if( IsPostProcessingNeeded() )
       
  1762 			{
       
  1763 			//[ transition to start post processing state]
       
  1764 			SetCurrentState( EStartPostProcessState );
       
  1765 			}
       
  1766 		else
       
  1767 			{
       
  1768 			//[ transition to cleanup state ]
       
  1769 			SetCurrentState( ECleanUpState );
       
  1770 			}
       
  1771 		}
       
  1772 	// Start the active object
       
  1773 	SelfComplete(KErrNone);
       
  1774 #if defined (__SCALING_PROFILING)
       
  1775 	RDebug::ProfileEnd(7);
       
  1776 #endif // __SCALING_PROFILING
       
  1777 	}
       
  1778 	
       
  1779 /*
       
  1780 *
       
  1781 * ScaleBitmapLine
       
  1782 * @param aX
       
  1783 * @param aSourceX
       
  1784 *
       
  1785 */
       
  1786 void CBitmapScalerPlugin::ScaleBitmapLine(TInt aX,TInt aSourceX)
       
  1787 	{
       
  1788 	TUint8* destDesPtr = const_cast<TUint8*>( iDestDes.Ptr() );
       
  1789 	const TUint8* orgDesPtr = iOrigDes.Ptr();
       
  1790 	
       
  1791 	if (QualityAlgorithm() == CBitmapScaler::EMinimumQuality)
       
  1792 		{
       
  1793 		CopyPixel(destDesPtr + aX,orgDesPtr + aSourceX);
       
  1794 		}
       
  1795 	else	// must be CBitmapScaler::EMediumQuality
       
  1796 		{
       
  1797 		// Better quality
       
  1798 		TInt nextValue = 0;
       
  1799 		TInt prevValue = 0;
       
  1800 		TInt value = 0;
       
  1801 		// eg weightedAv. = (w1*v1 + w2*v2 + w3*v3) / (w1 + w2 + w3)
       
  1802 		// so if w1=w3=8 and w2=16
       
  1803 		// (v1 * 2<<3 + v2 * 2<<4 + v3 * 2<<3) >> 2 * 5
       
  1804 		const TInt minorShift = 3;	// prev and next value weighting
       
  1805 		const TInt majorShift = 4;	// current value weighting
       
  1806 		const TInt backShift = 5;	// average
       
  1807 
       
  1808 		for (TInt i = 0; i < iComponentsPerPixel; i++)
       
  1809 			{
       
  1810 			// Get the previous value
       
  1811 			TInt index = aSourceX - iComponentsPerPixel;
       
  1812 			if (index < 0)
       
  1813 				{
       
  1814 				index = i;
       
  1815 				}
       
  1816 			else
       
  1817 				{
       
  1818 				index += i;
       
  1819 				}
       
  1820 			prevValue = TInt(orgDesPtr[index]);
       
  1821 				
       
  1822 			// Weight the previous value
       
  1823 			prevValue = prevValue << minorShift;
       
  1824 			// Get the next value
       
  1825 			index = aSourceX;
       
  1826 			if (index  + iComponentsPerPixel >= iOrigDes.Length())
       
  1827 				{
       
  1828 				index += i;
       
  1829 				}
       
  1830 			else
       
  1831 				{
       
  1832 				index += (i + iComponentsPerPixel);
       
  1833 				}
       
  1834 			nextValue = TInt(orgDesPtr[index]);
       
  1835 
       
  1836 			// Weight the next value
       
  1837 			nextValue = nextValue << minorShift;
       
  1838 			// Weight the current value
       
  1839 			value = TInt(orgDesPtr[aSourceX+ i]);
       
  1840 
       
  1841 			value = value << majorShift;
       
  1842 			// Sum all values
       
  1843 			value += prevValue;
       
  1844 			value += nextValue;
       
  1845 			// Average
       
  1846 			value = value >> backShift;
       
  1847 			destDesPtr[aX + i] = TUint8(value);
       
  1848 			}
       
  1849 		}
       
  1850 	}
       
  1851