--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/imagehandlinglib/Src/CIHLScaler.cpp Tue Jan 26 15:18:05 2010 +0200
@@ -0,0 +1,1315 @@
+/*
+* Copyright (c) 2004 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: Implementation of Scaling processor
+* : using Font and Bitmap Server bitmaps.
+*
+*/
+
+// INCLUDE FILES
+#include "CIHLScaler.h"
+#include "IHLDebugPrint.h" // Debug print
+#include <MIHLImageViewer.h> // MIHLImageViewer
+#include <fbs.h>
+#include <hal.h>
+
+// Private namespace for constants and functions
+namespace
+ {
+ // Processed pixels per one activesheduler step
+ const TInt KProcessPixelsPerStep = 16384;
+
+ // These make the fast path scalings step out about every 5-10ms
+ // no reason to cut more aggressively since it just slows down everything
+ const TInt KBytesPerStepFastPath = 640*480;
+ const TInt KBytesPerStepFastPathScaleOnly = 640*480*2;
+
+ const TInt KStepPrecision = 16; // 16 bit = 65k subpixels
+ const TInt KMaxProcessSize = KMaxTInt / 2;
+ }
+
+//functions and typedefs used inside ProcessBilinear scaling
+namespace
+ {
+ // using our own RGB instead of TRGB as we need TInt32 for each value
+ typedef struct
+ {
+ TInt32 r, g, b, a;
+ } TColorRGB;
+
+ // structure for handling data of 4 pixels
+ typedef struct
+ {
+ TColorRGB colXY00, colXY01, colXY10, colXY11;
+ TColorRGB col0, col1, col;
+ } TPixelData;
+
+ // functions to handle conversion between TColorRGB and colr value stored in TInt32
+ inline void IntToRgb(TInt32 aIntRGB_val, TColorRGB &col)
+ {
+ col.r = (aIntRGB_val >> 16) & 0x00ff;
+ col.g = (aIntRGB_val >> 8) & 0x00ff;
+ col.b = aIntRGB_val & 0x00ff;
+ col.a = (aIntRGB_val >> 24) & 0x00ff;
+ }
+ inline TUint32 RgbToInt(TColorRGB &col)
+ {
+ return 0x00000000 | ( ( col.r & 0xff) << 16 ) | ( ( col.g & 0xff) << 8 )
+ | ( col.b & 0xff) | ( ( col.a & 0xff) << 24 );
+ }
+
+ // function which interpolates color using gathered data
+ inline void ProcessColorData( TPixelData &dat, TPoint aSrcPos )
+ {
+ TInt32 pixel_width = 1 << KStepPrecision;
+
+ //first pass (Y axis)
+ dat.col0.r = (dat.colXY01.r - dat.colXY00.r)*(aSrcPos.iY % pixel_width) / pixel_width + dat.colXY00.r;
+ dat.col0.g = (dat.colXY01.g - dat.colXY00.g)*(aSrcPos.iY % pixel_width) / pixel_width + dat.colXY00.g;
+ dat.col0.b = (dat.colXY01.b - dat.colXY00.b)*(aSrcPos.iY % pixel_width) / pixel_width + dat.colXY00.b;
+ dat.col0.a = (dat.colXY01.a - dat.colXY00.a)*(aSrcPos.iY % pixel_width) / pixel_width + dat.colXY00.a;
+
+ dat.col1.r = (dat.colXY11.r - dat.colXY10.r)*(aSrcPos.iY % pixel_width) / pixel_width + dat.colXY10.r;
+ dat.col1.g = (dat.colXY11.g - dat.colXY10.g)*(aSrcPos.iY % pixel_width) / pixel_width + dat.colXY10.g;
+ dat.col1.b = (dat.colXY11.b - dat.colXY10.b)*(aSrcPos.iY % pixel_width) / pixel_width + dat.colXY10.b;
+ dat.col1.a = (dat.colXY11.a - dat.colXY10.a)*(aSrcPos.iY % pixel_width) / pixel_width + dat.colXY10.a;
+
+ //second pass (X axis)
+ dat.col.r = (dat.col1.r - dat.col0.r)*(aSrcPos.iX % pixel_width) / pixel_width + dat.col0.r;
+ dat.col.g = (dat.col1.g - dat.col0.g)*(aSrcPos.iX % pixel_width) / pixel_width + dat.col0.g;
+ dat.col.b = (dat.col1.b - dat.col0.b)*(aSrcPos.iX % pixel_width) / pixel_width + dat.col0.b;
+ dat.col.a = (dat.col1.a - dat.col0.a)*(aSrcPos.iX % pixel_width) / pixel_width + dat.col0.a;
+ }
+ }
+
+// ======================== STATIC FACTORY FUNCTION ============================
+// -----------------------------------------------------------------------------
+// IHLScaler::CreateL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C MIHLScaler* IHLScaler::CreateL( const TUint32 aOptions )
+ {
+ return CIHLScaler::NewL( aOptions );
+ }
+
+// ============================ MEMBER FUNCTIONS ===============================
+// -----------------------------------------------------------------------------
+//
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+CIHLScaler::CIHLScaler( const TUint32 aOptions )
+:CActive( CActive::EPriorityStandard ), iOptions( aOptions )
+ {
+ CActiveScheduler::Add( this );
+ }
+
+// -----------------------------------------------------------------------------
+//
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+CIHLScaler* CIHLScaler::NewL( const TUint32 aOptions )
+ {
+ CIHLScaler* self = new( ELeave ) CIHLScaler( aOptions );
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+CIHLScaler::~CIHLScaler()
+ {
+ Cancel();
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::Scale
+// -----------------------------------------------------------------------------
+TInt CIHLScaler::Scale( TRequestStatus& aStatus,
+ const CFbsBitmap& aSrcBitmap, const TRect& aSrcRect,
+ CFbsBitmap& aDstBitmap, const TRect& aDstRect )
+ {
+ if( IsBusy() )
+ {
+ return KErrNotReady;
+ }
+
+ TSize srcRectSize( aSrcRect.Size() );
+ TSize dstRectSize( aDstRect.Size() );
+ if( Abs( srcRectSize.iWidth ) > KMaxProcessSize ||
+ Abs( srcRectSize.iHeight ) > KMaxProcessSize ||
+ Abs( dstRectSize.iWidth ) > KMaxProcessSize ||
+ Abs( dstRectSize.iHeight ) > KMaxProcessSize )
+ {
+ return KErrTooBig;
+ }
+
+ if( !aSrcBitmap.Handle() ||
+ !IsValidRect( aSrcBitmap.SizeInPixels(), aSrcRect ) )
+ {
+ return KErrArgument;
+ }
+
+ if( aDstBitmap.Handle() )
+ {
+ if( !IsValidRect( aDstBitmap.SizeInPixels(), aDstRect ) )
+ {
+ return KErrArgument;
+ }
+ }
+ else
+ {
+ // Create destination bitmap
+ TSize dstSize( Abs( dstRectSize.iWidth ), Abs( dstRectSize.iHeight ) );
+ TInt err = aDstBitmap.Create( dstSize, aSrcBitmap.DisplayMode() );
+ if( err )
+ {
+ return err;
+ }
+ }
+
+#ifdef RD_MEASURE_THROUGHPUT
+ iStartTime = User::FastCounter(); // For measuring scaler throughput
+#endif
+
+ TSize srcSize( aSrcBitmap.SizeInPixels() );
+ TSize dstSize( aDstBitmap.SizeInPixels() );
+
+ if( srcSize.iWidth == 0 || srcSize.iHeight == 0 ||
+ dstSize.iWidth == 0 || dstSize.iHeight == 0 ||
+ aSrcRect.iTl.iX == aSrcRect.iBr.iX ||
+ aSrcRect.iTl.iY == aSrcRect.iBr.iY ||
+ aDstRect.iTl.iX == aDstRect.iBr.iX ||
+ aDstRect.iTl.iY == aDstRect.iBr.iY )
+ {
+ // Bitmap or rect width or height is zero so there is nothing to do.
+ // Complete process without error.
+ iNeedProcess = EFalse;
+ }
+ else
+ {
+ iNeedProcess = ETrue;
+
+ // Set parameters to member data references
+ iSrcBitmap = &aSrcBitmap;
+ iSrcRect = aSrcRect;
+ iDstBitmap = &aDstBitmap;
+ iDstRect = aDstRect;
+
+ TDisplayMode srcMode(iSrcBitmap->DisplayMode());
+ TDisplayMode dstMode(iDstBitmap->DisplayMode());
+
+ IHL_DEBUG3( KIHLDebug1, "CIHLScaler: src bitmap size %dx%d", srcSize.iWidth, srcSize.iHeight);
+ IHL_DEBUG3( KIHLDebug2, "CIHLScaler: dst bitmap size %dx%d", dstSize.iWidth, dstSize.iHeight);
+ IHL_DEBUG5( KIHLDebug3, "CIHLScaler: src bitmap rect %d.%d -> %d.%d", iSrcRect.iTl.iX, iSrcRect.iTl.iY, iSrcRect.iBr.iX, iSrcRect.iBr.iY);
+ IHL_DEBUG5( KIHLDebug4, "CIHLScaler: dst bitmap rect %d.%d -> %d.%d", iDstRect.iTl.iX, iDstRect.iTl.iY, iDstRect.iBr.iX, iDstRect.iBr.iY);
+ IHL_DEBUG2( KIHLDebug5, "CIHLScaler: src bitmap mode %d", srcMode);
+ IHL_DEBUG2( KIHLDebug6, "CIHLScaler: dst bitmap mode %d", dstMode);
+ IHL_DEBUG2( KIHLDebug7, "CIHLScaler: src compressed %d", iSrcBitmap->IsCompressedInRAM());
+ IHL_DEBUG2( KIHLDebug8, "CIHLScaler: dst compressed %d", iSrcBitmap->IsCompressedInRAM());
+
+ // Init stepper values
+ TBool onlyScaling = InitStepperValues();
+
+ // Select correct code path
+ InitCodePath(srcSize, srcMode, dstSize, dstMode, onlyScaling);
+ }
+
+ IHL_DEBUG1( KIHLDebug, "IHL - CIHLScaler - Start bitmap scaling" );
+
+ // Start processing
+ iScalerStatus = &aStatus;
+ *iScalerStatus = KRequestPending;
+
+ SelfComplete();
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::IsBusy
+// -----------------------------------------------------------------------------
+TBool CIHLScaler::IsBusy() const
+ {
+ return IsActive();
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::CancelProcess
+// -----------------------------------------------------------------------------
+void CIHLScaler::CancelProcess()
+ {
+ Cancel();
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::SetFilter
+// -----------------------------------------------------------------------------
+void CIHLScaler::SetFilter( MIHFilter* /*aFilter*/ )
+ {
+ // Not in use
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::DoCancel
+// -----------------------------------------------------------------------------
+void CIHLScaler::DoCancel()
+ {
+ RequestComplete( KErrCancel );
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::RunL
+// -----------------------------------------------------------------------------
+void CIHLScaler::RunL()
+ {
+ User::LeaveIfError( iStatus.Int() );
+
+ // Process bitmap (this if-else may look weird but it removes one extra triggering of the AS
+ if( iNeedProcess )
+ {
+ // Call the selected code path directly via a function pointer
+ iNeedProcess = (this->*ProcessingFunc)();
+ }
+
+ if(!iNeedProcess)
+ {
+#ifdef RD_MEASURE_THROUGHPUT
+ // Calculate throughput
+ TUint32 end = User::FastCounter();
+
+ TInt tickPeriod;
+ HAL::Get(HALData::EFastCounterFrequency, tickPeriod);
+ TReal time = TReal(end-iStartTime) / TReal(tickPeriod);
+ TReal bytes = iProcessSize.iWidth*iProcessSize.iHeight*2;
+
+ IHL_DEBUG3("IHL - CIHLScaler - Scaling complete, %.3f ms, %.3f MB/s", time*1000.0, (bytes/time)/1024.0/1024.0);
+#else
+ IHL_DEBUG1( KIHLDebug, "IHL - CIHLScaler - Scaling complete!" );
+#endif
+ // Process complete
+ RequestComplete( KErrNone );
+ }
+ else
+ {
+ // Another round
+ SelfComplete();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::RunError
+// -----------------------------------------------------------------------------
+TInt CIHLScaler::RunError( TInt aError )
+ {
+ IHL_DEBUG2( KIHLDebug, "IHL - CIHLScaler - Scaling error: %d", aError );
+
+ RequestComplete( aError );
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::IsValidRect
+// -----------------------------------------------------------------------------
+TBool CIHLScaler::IsValidRect( const TSize& aSize, const TRect& aRect )
+ {
+ if( aRect.iTl.iX >= 0 &&
+ aRect.iTl.iX <= aSize.iWidth &&
+ aRect.iTl.iY >= 0 &&
+ aRect.iTl.iY <= aSize.iHeight &&
+ aRect.iBr.iX >= 0 &&
+ aRect.iBr.iX <= aSize.iWidth &&
+ aRect.iBr.iY >= 0 &&
+ aRect.iBr.iY <= aSize.iHeight )
+ {
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::InitStepperValues
+// -----------------------------------------------------------------------------
+TBool CIHLScaler::InitStepperValues()
+ {
+ TBool onlyScaling = EFalse;
+
+ TSize srcRectSize( Abs( iSrcRect.Width() ), Abs( iSrcRect.Height() ) );
+ TSize dstRectSize( Abs( iDstRect.Width() ), Abs( iDstRect.Height() ) );
+
+ TReal srcW = srcRectSize.iWidth << KStepPrecision;
+ TReal srcH = srcRectSize.iHeight << KStepPrecision;
+
+ // -----------------------------------------
+ // Set source start point and increment
+ // -----------------------------------------
+ if( iSrcRect.iTl.iX > iSrcRect.iBr.iX &&
+ iSrcRect.iTl.iY < iSrcRect.iBr.iY )
+ {
+ TReal incrementInner( srcH / TReal(dstRectSize.iWidth) );
+ TReal incrementOuter( srcW / TReal(dstRectSize.iHeight) );
+
+ iSrcIncrementInner.iX = 0;
+ iSrcIncrementInner.iY = incrementInner;
+ iSrcIncrementOuter.iX = -incrementOuter;
+ iSrcIncrementOuter.iY = 0;
+
+ iSrcPos.SetXY( (iSrcRect.iTl.iX << KStepPrecision) - (incrementOuter / 2.0),
+ (iSrcRect.iTl.iY << KStepPrecision) + (incrementInner / 2.0) );
+ }
+ else if ( iSrcRect.iTl.iX > iSrcRect.iBr.iX &&
+ iSrcRect.iTl.iY > iSrcRect.iBr.iY )
+ {
+ TReal incrementInner( srcW / TReal(dstRectSize.iWidth) );
+ TReal incrementOuter( srcH / TReal(dstRectSize.iHeight) );
+
+ iSrcIncrementInner.iX = -incrementInner;
+ iSrcIncrementInner.iY = 0;
+ iSrcIncrementOuter.iX = 0;
+ iSrcIncrementOuter.iY = -incrementOuter;
+
+ iSrcPos.SetXY( (iSrcRect.iTl.iX << KStepPrecision) - (incrementInner / 2.0),
+ (iSrcRect.iTl.iY << KStepPrecision) - (incrementOuter / 2.0) );
+ }
+ else if ( iSrcRect.iTl.iX < iSrcRect.iBr.iX &&
+ iSrcRect.iTl.iY > iSrcRect.iBr.iY )
+ {
+ TReal incrementInner( srcH / TReal(dstRectSize.iWidth) );
+ TReal incrementOuter( srcW / TReal(dstRectSize.iHeight) );
+
+ iSrcIncrementInner.iX = 0;
+ iSrcIncrementInner.iY = -incrementInner;
+ iSrcIncrementOuter.iX = incrementOuter;
+ iSrcIncrementOuter.iY = 0;
+
+ iSrcPos.SetXY( (iSrcRect.iTl.iX << KStepPrecision) + (incrementOuter / 2.0),
+ (iSrcRect.iTl.iY << KStepPrecision) - (incrementInner / 2.0) );
+ }
+ else
+ {
+ TReal incrementInner( srcW / TReal(dstRectSize.iWidth) );
+ TReal incrementOuter( srcH / TReal(dstRectSize.iHeight) );
+
+ IHL_DEBUG3(KIHLDebug, "incrementInner: %f, incrementOuter: %f", incrementInner, incrementOuter);
+
+ iSrcIncrementInner.iX = incrementInner;
+ iSrcIncrementInner.iY = 0;
+ iSrcIncrementOuter.iX = 0;
+ iSrcIncrementOuter.iY = incrementOuter;
+
+ iSrcPos.SetXY( (iSrcRect.iTl.iX << KStepPrecision) + (incrementInner / 2.0),
+ (iSrcRect.iTl.iY << KStepPrecision) + (incrementOuter / 2.0) );
+
+ onlyScaling = ETrue;
+ }
+
+ // -----------------------------------------
+ // Set destination start point and increment
+ // -----------------------------------------
+
+ iDstPos.iX = iDstRect.iTl.iX;
+ iDstIncrementInner = 1;
+ iDstPos.iY = iDstRect.iTl.iY;
+ iDstIncrementOuter = 1;
+
+ if( iDstRect.iTl.iX > iDstRect.iBr.iX )
+ {
+ // From right to left
+ iDstPos.iX--;
+ iDstIncrementInner = -1;
+ onlyScaling = EFalse;
+ }
+
+ if( iDstRect.iTl.iY > iDstRect.iBr.iY )
+ {
+ // From bottom to up
+ iDstPos.iY--;
+ iDstIncrementOuter = -1;
+ onlyScaling = EFalse;
+ }
+
+ // -----------------------------------------
+ // Reset process counters
+ // -----------------------------------------
+ iProcessInner = 0;
+ iProcessOuter = 0;
+ iProcessSize = dstRectSize;
+
+ // These are for fast code path
+
+ // Init how many scanlines to process
+ iScanlinesLeft = iProcessSize.iHeight;
+
+ return onlyScaling;
+ }
+
+
+// Optimize the fast code paths properly for ARM
+#ifdef __ARMCC__
+#pragma push
+#pragma O3
+#pragma Otime
+#pragma arm
+#endif
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::ProcessNearestNeighbour64K
+// Description: Scales & rotates 64K color bitmaps
+// -----------------------------------------------------------------------------
+TBool CIHLScaler::ProcessNearestNeighbour64K()
+ {
+ // Lock bitmap heaps
+ iSrcBitmap->LockHeap();
+ iDstBitmap->LockHeap();
+
+ // Pointers to start of bitmap data
+ TUint16 *srcBitmapPtr = (TUint16*)iSrcBitmap->DataAddress();
+ TUint16 *dstBitmapPtr = (TUint16*)iDstBitmap->DataAddress();
+
+ // Get pointer to correct destination pixel (offset is updated after every round)
+ register TUint16* dst = dstBitmapPtr + iDstStartOffset;
+
+ TUint32 width = iProcessSize.iWidth;
+
+ // Check how many scanlines we can process this round
+ register TUint32 scanlinesLeft = iScanlinesLeft;
+ if(scanlinesLeft>iScanlinesPerRound)
+ {
+ scanlinesLeft = iScanlinesPerRound;
+ }
+
+ // How many scanlines left for the next round
+ iScanlinesLeft-=scanlinesLeft;
+
+ // Faster access to variables (it's slow to use member variables)
+ register TInt srcPosX(iSrcPos.iX);
+ register TInt srcPosY(iSrcPos.iY);
+ register TInt srcPitch = iSrcPitchInPixels;
+
+ TInt incOuterSrcX = (-iSrcIncrementInner.iX * width) + iSrcIncrementOuter.iX;
+ TInt incOuterSrcY = (-iSrcIncrementInner.iY * width) + iSrcIncrementOuter.iY;
+
+ while(scanlinesLeft!=0)
+ {
+ for(register TUint32 x = width; x!=0; x--)
+ {
+ register TUint16* src = srcBitmapPtr + ((srcPosY >> KStepPrecision) * srcPitch) + (srcPosX>>KStepPrecision);
+ *dst = *src;
+
+ // Add inner counters
+ srcPosX+=iSrcIncrementInner.iX;
+ srcPosY+=iSrcIncrementInner.iY;
+
+ dst+=iDstIncrementInner;
+ }
+
+ // Reset inner counters and add outer counters
+ srcPosX += incOuterSrcX;
+ srcPosY += incOuterSrcY;
+
+ // Move destination pointer to next pixel
+ dst += iDstResidualPixels;
+
+ // One scanline done, n to go
+ scanlinesLeft--;
+ }
+ // Unlock bitmap heaps
+ iDstBitmap->UnlockHeap();
+ iSrcBitmap->UnlockHeap();
+
+ if(iScanlinesLeft)
+ {
+ // Not all scanlines were processed yet
+
+ // Save the necessary offsets for next round
+ iSrcPos.iX = srcPosX;
+ iSrcPos.iY = srcPosY;
+ iDstStartOffset = dst - dstBitmapPtr;
+
+ return ETrue;
+ }
+
+ // Processing done
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::ProcessNearestNeighbour64KScaleOnly
+// -----------------------------------------------------------------------------
+TBool CIHLScaler::ProcessNearestNeighbour64KScaleOnly()
+ {
+ // Lock bitmap heaps
+ iSrcBitmap->LockHeap();
+ iDstBitmap->LockHeap();
+
+ // Get bitmap data start addresses
+ TUint16 *srcBitmapPtr = (TUint16*)iSrcBitmap->DataAddress();
+ TUint16 *dstBitmapPtr = (TUint16*)iDstBitmap->DataAddress();
+
+ // Target height and width
+ TInt width = iProcessSize.iWidth;
+
+ // fixed point source coordinates
+ TInt startX = iSrcPos.iX;
+ TInt srcY = iSrcPos.iY;
+
+ // How much to increase src position (in fixed point)
+ TInt srcYIncrement = iSrcIncrementOuter.iY;
+ register TInt srcXIncrement = iSrcIncrementInner.iX;
+
+ // Set pointers to correct location (src = start of scanline, dst = start pixel)
+ register TUint16* dst = dstBitmapPtr + iDstStartOffset;
+
+ // Calculate how many scanlines we can process this round
+ register TInt scanlinesLeft = iScanlinesLeft;
+ if(scanlinesLeft>iScanlinesPerRound)
+ {
+ scanlinesLeft = iScanlinesPerRound;
+ }
+
+ iScanlinesLeft-=scanlinesLeft;
+
+ while(scanlinesLeft--)
+ {
+ // Outer loop
+
+ // Reset src X and scanline pointer
+ register TInt srcX = startX;
+ register TUint16* src = srcBitmapPtr + (srcY >> KStepPrecision) * iSrcPitchInPixels;
+
+ // Init pixel counter
+ register TUint32 pixels = width;
+
+ // Unaligned pixels to the left of 8B-aligned section
+ while((TUint32(dst)&0x7) && pixels)
+ {
+ *dst++ = (*(src + (srcX >> KStepPrecision)));
+
+ srcX += srcXIncrement;
+
+ pixels--;
+ }
+
+ // Aligned middle section
+ register TUint32 middle = pixels&0xFFFFFFFC;
+ pixels &= 0x3;
+
+ while(middle)
+ {
+ // Read four pixels
+ register TUint16 p1 = (*(src + (srcX >> KStepPrecision)));
+ srcX += srcXIncrement;
+ register TUint16 p2 = (*(src + (srcX >> KStepPrecision)));
+ srcX += srcXIncrement;
+ register TUint16 p3 = (*(src + (srcX >> KStepPrecision)));
+ srcX += srcXIncrement;
+ register TUint16 p4 = (*(src + (srcX >> KStepPrecision)));
+ srcX += srcXIncrement;
+
+ // Write four pixels
+ *(dst++) = p1;
+ *(dst++) = p2;
+ *(dst++) = p3;
+ *(dst++) = p4;
+
+ middle-=4;
+ }
+
+ // Unaligned residual pixels to the right of 8-aligned section
+ while(pixels)
+ {
+ *dst++ = (*(src + (srcX >> KStepPrecision)));
+
+ srcX += srcXIncrement;
+
+ pixels--;
+ }
+
+ // Move to next correct src scanline
+ srcY += srcYIncrement;
+
+ // Advance dst to start of correct pixel in the next row
+ dst += iDstResidualPixels;
+ }
+
+ iDstBitmap->UnlockHeap();
+ iSrcBitmap->UnlockHeap();
+
+ if(iScanlinesLeft)
+ {
+ // Not all scanlines were processed yet
+
+ // Save the necessary offsets for next round
+ iSrcPos.iY = srcY;
+ iDstStartOffset = dst - dstBitmapPtr;
+
+ return ETrue;
+ }
+
+ return EFalse;
+
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::ProcessNearestNeighbour16MX
+// Description: Scales & rotates 16MU/MA color bitmaps
+// -----------------------------------------------------------------------------
+TBool CIHLScaler::ProcessNearestNeighbour16MX()
+ {
+ // Lock bitmap heaps
+ iSrcBitmap->LockHeap();
+ iDstBitmap->LockHeap();
+
+ // Pointers to start of bitmap data
+ TUint32 *srcBitmapPtr = (TUint32*)iSrcBitmap->DataAddress();
+ TUint32 *dstBitmapPtr = (TUint32*)iDstBitmap->DataAddress();
+
+ // Get pointer to correct destination pixel (offset is updated after every round)
+ register TUint32* dst = dstBitmapPtr + iDstStartOffset;
+
+ TUint32 width = iProcessSize.iWidth;
+
+ // Check how many scanlines we can process this round
+ register TUint32 scanlinesLeft = iScanlinesLeft;
+ if(scanlinesLeft>iScanlinesPerRound)
+ {
+ scanlinesLeft = iScanlinesPerRound;
+ }
+
+ // How many scanlines left for the next round
+ iScanlinesLeft-=scanlinesLeft;
+
+ // Faster access to variables (it's slow to use member variables)
+ register TInt srcPosX(iSrcPos.iX);
+ register TInt srcPosY(iSrcPos.iY);
+ register TInt srcPitch = iSrcPitchInPixels;
+
+ TInt incOuterSrcX = (-iSrcIncrementInner.iX * width) + iSrcIncrementOuter.iX;
+ TInt incOuterSrcY = (-iSrcIncrementInner.iY * width) + iSrcIncrementOuter.iY;
+
+ while(scanlinesLeft!=0)
+ {
+ for(register TUint32 x = width; x!=0; x--)
+ {
+ register TUint32* src = srcBitmapPtr + ((srcPosY >> KStepPrecision) * srcPitch) + (srcPosX>>KStepPrecision);
+ *dst = *src;
+
+ // Add inner counters
+ srcPosX+=iSrcIncrementInner.iX;
+ srcPosY+=iSrcIncrementInner.iY;
+
+ dst+=iDstIncrementInner;
+ }
+
+ // Reset inner counters and add outer counters
+ srcPosX += incOuterSrcX;
+ srcPosY += incOuterSrcY;
+
+ // Move destination pointer to next pixel
+ dst += iDstResidualPixels;
+
+ // One scanline done, n to go
+ scanlinesLeft--;
+ }
+ // Unlock bitmap heaps
+ iDstBitmap->UnlockHeap();
+ iSrcBitmap->UnlockHeap();
+
+ if(iScanlinesLeft)
+ {
+ // Not all scanlines were processed yet
+
+ // Save the necessary offsets for next round
+ iSrcPos.iX = srcPosX;
+ iSrcPos.iY = srcPosY;
+ iDstStartOffset = dst - dstBitmapPtr;
+
+ return ETrue;
+ }
+
+ // Processing done
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::ProcessNearestNeighbour64KScaleOnly
+// -----------------------------------------------------------------------------
+TBool CIHLScaler::ProcessNearestNeighbour16MXScaleOnly()
+ {
+ // Lock bitmap heaps
+ iSrcBitmap->LockHeap();
+ iDstBitmap->LockHeap();
+
+ // Get bitmap data start addresses
+ TUint32 *srcBitmapPtr = (TUint32*)iSrcBitmap->DataAddress();
+ TUint32 *dstBitmapPtr = (TUint32*)iDstBitmap->DataAddress();
+
+ // Target height and width
+ TInt width = iProcessSize.iWidth;
+
+ // fixed point source coordinates
+ TInt startX = iSrcPos.iX;
+ TInt srcY = iSrcPos.iY;
+
+ // How much to increase src position (in fixed point)
+ TInt srcYIncrement = iSrcIncrementOuter.iY;
+ register TInt srcXIncrement = iSrcIncrementInner.iX;
+
+ // Set pointers to correct location (src = start of scanline, dst = start pixel)
+ register TUint32* dst = dstBitmapPtr + iDstStartOffset;
+
+ // Calculate how many scanlines we can process this round
+ register TInt scanlinesLeft = iScanlinesLeft;
+ if(scanlinesLeft>iScanlinesPerRound)
+ {
+ scanlinesLeft = iScanlinesPerRound;
+ }
+
+ iScanlinesLeft-=scanlinesLeft;
+
+ while(scanlinesLeft--)
+ {
+ // Outer loop
+
+ // Reset src X and scanline pointer
+ register TInt srcX = startX;
+ register TUint32* src = srcBitmapPtr + (srcY >> KStepPrecision) * iSrcPitchInPixels;
+
+ // Init pixel counter
+ register TUint32 pixels = width;
+
+ // Unaligned pixels to the left of 16B-aligned section
+ while((TUint32(dst)&0xF) && pixels)
+ {
+ *dst++ = (*(src + (srcX >> KStepPrecision)));
+
+ srcX += srcXIncrement;
+
+ pixels--;
+ }
+
+ // Aligned middle section
+ register TUint32 middle = pixels&0xFFFFFFFC;
+ pixels &= 0x3;
+
+ while(middle)
+ {
+ // Read four pixels
+ register TUint32 p1 = (*(src + (srcX >> KStepPrecision)));
+ srcX += srcXIncrement;
+ register TUint32 p2 = (*(src + (srcX >> KStepPrecision)));
+ srcX += srcXIncrement;
+ register TUint32 p3 = (*(src + (srcX >> KStepPrecision)));
+ srcX += srcXIncrement;
+ register TUint32 p4 = (*(src + (srcX >> KStepPrecision)));
+ srcX += srcXIncrement;
+
+ // Write four pixels
+ *(dst+0) = p1;
+ *(dst+1) = p2;
+ *(dst+2) = p3;
+ *(dst+3) = p4;
+
+ middle-=4;
+ dst+=4;
+ }
+
+ // Unaligned residual pixels to the right of 8-aligned section
+ while(pixels)
+ {
+ *dst++ = (*(src + (srcX >> KStepPrecision)));
+
+ srcX += srcXIncrement;
+
+ pixels--;
+ }
+
+ // Move to next correct src scanline
+ srcY += srcYIncrement;
+
+ // Advance dst to start of correct pixel in the next row
+ dst += iDstResidualPixels;
+ }
+
+ iDstBitmap->UnlockHeap();
+ iSrcBitmap->UnlockHeap();
+
+ if(iScanlinesLeft)
+ {
+ // Not all scanlines were processed yet
+
+ // Save the necessary offsets for next round
+ iSrcPos.iY = srcY;
+ iDstStartOffset = dst - dstBitmapPtr;
+
+ return ETrue;
+ }
+
+ return EFalse;
+
+ }
+
+// Restore previous pragma state
+#ifdef __ARMCC__
+#pragma pop
+#endif
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::ProcessNearestNeighbour
+// -----------------------------------------------------------------------------
+TBool CIHLScaler::ProcessNearestNeighbour()
+ {
+ // Util needs non-const pointers even if it's only used for reading pixels
+ TBitmapUtil srcBitmap( const_cast<CFbsBitmap*>( iSrcBitmap ) );
+ TBitmapUtil dstBitmap( iDstBitmap );
+ srcBitmap.Begin( TPoint( iSrcPos.iX >> KStepPrecision, iSrcPos.iY >> KStepPrecision ) );
+ dstBitmap.Begin( iDstPos ); // heap already locked by srcBitmap
+ TInt pixelCounter( KProcessPixelsPerStep );
+
+ // Start outer and inner process loops
+ while( iProcessOuter < iProcessSize.iHeight && pixelCounter )
+ {
+ while( iProcessInner < iProcessSize.iWidth && pixelCounter )
+ {
+ srcBitmap.SetPos( TPoint( iSrcPos.iX >> KStepPrecision, iSrcPos.iY >> KStepPrecision ) );
+ dstBitmap.SetPos( iDstPos );
+ dstBitmap.SetPixel( srcBitmap );
+
+ // Add inner counters
+ iSrcPos += iSrcIncrementInner;
+ iDstPos.iX += iDstIncrementInner;
+ ++iProcessInner;
+ --pixelCounter;
+ }
+ // Check if inner loop is finished (not just pixel counter)
+ if( iProcessInner == iProcessSize.iWidth )
+ {
+ // Reset inner counters
+ iSrcPos.iX -= iSrcIncrementInner.iX * iProcessInner;
+ iSrcPos.iY -= iSrcIncrementInner.iY * iProcessInner;
+
+ iDstPos.iX -= iDstIncrementInner * iProcessInner;
+ iProcessInner = 0;
+
+ // Add outer counters
+ iSrcPos += iSrcIncrementOuter;
+ iDstPos.iY += iDstIncrementOuter;
+ ++iProcessOuter;
+ }
+ }
+
+ // Release heap lock
+ dstBitmap.End();
+ srcBitmap.End();
+
+ // ETrue if more processing is still needed
+ return ( iProcessOuter < iProcessSize.iHeight );
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::ProcessBilinear
+// -----------------------------------------------------------------------------
+TBool CIHLScaler::ProcessBilinear()
+ {
+ // Util needs non-const pointers
+ //even if it's only used for reading pixels
+ TBitmapUtil srcBitmap( const_cast<CFbsBitmap*>( iSrcBitmap ) );
+ TBitmapUtil dstBitmap( iDstBitmap );
+
+ srcBitmap.Begin( TPoint( iSrcPos.iX >> KStepPrecision, iSrcPos.iY >> KStepPrecision ) );
+ dstBitmap.Begin( iDstPos ); // heap already locked by srcBitmap
+ TInt pixelCounter( KProcessPixelsPerStep );
+
+ TInt incSrcX = iSrcIncrementInner.iX + iSrcIncrementOuter.iX;
+ TInt incSrcY = iSrcIncrementInner.iY + iSrcIncrementOuter.iY;
+
+ TPixelData pixelData;
+ TUint32 color;
+
+ TInt32 pixel_width = 1 << KStepPrecision;
+
+ //if there is no scaling then process through loop using NearestNeighbour alghoritm
+ if ( incSrcX == pixel_width || -incSrcX == pixel_width )
+ {
+ while( iProcessOuter < iProcessSize.iHeight && pixelCounter )
+ {
+ while( iProcessInner < iProcessSize.iWidth && pixelCounter )
+ {
+ srcBitmap.SetPos( TPoint( iSrcPos.iX >> KStepPrecision, iSrcPos.iY >> KStepPrecision ) );
+ dstBitmap.SetPos( iDstPos );
+ dstBitmap.SetPixel( srcBitmap );
+
+ // Add inner counters
+ iSrcPos += iSrcIncrementInner;
+ iDstPos.iX += iDstIncrementInner;
+ ++iProcessInner;
+ --pixelCounter;
+ }
+
+ // Check if inner loop is finished (not just pixel counter)
+ if( iProcessInner == iProcessSize.iWidth )
+ {
+ // Reset inner counters
+ iSrcPos.iX -= iSrcIncrementInner.iX * iProcessInner;
+ iSrcPos.iY -= iSrcIncrementInner.iY * iProcessInner;
+
+ iDstPos.iX -= iDstIncrementInner * iProcessInner;
+ iProcessInner = 0;
+
+ // Add outer counters
+ iSrcPos += iSrcIncrementOuter;
+ iDstPos.iY += iDstIncrementOuter;
+ ++iProcessOuter;
+ }
+ }
+ }
+ // Process using bilinear method according to
+ // orientation between source and destination bitmap
+ //
+ // There are 4 possibilities of orientation and can be
+ // determined by this if we're increasing or decreasing
+ // position on source bitmap.
+ else if ( ( incSrcY >= 0) && (incSrcX >= 0 ) )
+ {
+ while( iProcessOuter < iProcessSize.iHeight && pixelCounter )
+ {
+ while( iProcessInner < iProcessSize.iWidth && pixelCounter )
+ {
+ srcBitmap.SetPos( TPoint( iSrcPos.iX >> KStepPrecision, iSrcPos.iY >> KStepPrecision ) );
+ dstBitmap.SetPos( iDstPos );
+
+ // gather pixel data with step:
+ // 00 > 10
+ // V
+ // 01 < 11
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY00);
+ srcBitmap.IncXPos();
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY10);
+ srcBitmap.IncYPos();
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY11);
+ srcBitmap.DecXPos();
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY01);
+ //return to starting position
+ srcBitmap.DecYPos();
+
+ // interpolate color using gathered pixel-data
+ ProcessColorData(pixelData, iSrcPos);
+
+ // put color in destination package
+ color = RgbToInt(pixelData.col);
+ dstBitmap.SetPixel(color);
+
+ // Add inner counters
+ iSrcPos += iSrcIncrementInner;
+ iDstPos.iX += iDstIncrementInner;
+ ++iProcessInner;
+ --pixelCounter;
+ }
+
+ // Check if inner loop is finished (not just pixel counter)
+ if( iProcessInner == iProcessSize.iWidth )
+ {
+ // Reset inner counters
+ iSrcPos.iX -= iSrcIncrementInner.iX * iProcessInner;
+ iSrcPos.iY -= iSrcIncrementInner.iY * iProcessInner;
+
+ iDstPos.iX -= iDstIncrementInner * iProcessInner;
+ iProcessInner = 0;
+
+ // Add outer counters
+ iSrcPos += iSrcIncrementOuter;
+ iDstPos.iY += iDstIncrementOuter;
+ ++iProcessOuter;
+ }
+ }
+ }
+ else if ( ( incSrcY >= 0) && (incSrcX < 0 ) )
+ {
+ while( iProcessOuter < iProcessSize.iHeight && pixelCounter )
+ {
+ while( iProcessInner < iProcessSize.iWidth && pixelCounter )
+ {
+ srcBitmap.SetPos( TPoint( iSrcPos.iX >> KStepPrecision, iSrcPos.iY >> KStepPrecision ) );
+ dstBitmap.SetPos( iDstPos );
+
+ // gather pixel data with step:
+ // 00 10
+ // /\ V
+ // 01 < 11
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY10);
+ srcBitmap.IncYPos();
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY11);
+ srcBitmap.DecXPos();
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY01);
+ srcBitmap.DecYPos();
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY00);
+ //return to starting position
+ srcBitmap.IncXPos();
+
+ // interpolate color using gathered pixel-data
+ ProcessColorData(pixelData, iSrcPos);
+
+ // put color in destination package
+ color = RgbToInt(pixelData.col);
+ dstBitmap.SetPixel(color);
+
+ // Add inner counters
+ iSrcPos += iSrcIncrementInner;
+ iDstPos.iX += iDstIncrementInner;
+ ++iProcessInner;
+ --pixelCounter;
+ }
+
+ // Check if inner loop is finished (not just pixel counter)
+ if( iProcessInner == iProcessSize.iWidth )
+ {
+ // Reset inner counters
+ iSrcPos.iX -= iSrcIncrementInner.iX * iProcessInner;
+ iSrcPos.iY -= iSrcIncrementInner.iY * iProcessInner;
+
+ iDstPos.iX -= iDstIncrementInner * iProcessInner;
+ iProcessInner = 0;
+
+ // Add outer counters
+ iSrcPos += iSrcIncrementOuter;
+ iDstPos.iY += iDstIncrementOuter;
+ ++iProcessOuter;
+ }
+
+ }
+ }
+ else if ( ( incSrcY < 0) && (incSrcX >= 0 ) )
+ {
+ while( iProcessOuter < iProcessSize.iHeight && pixelCounter )
+ {
+ while( iProcessInner < iProcessSize.iWidth && pixelCounter )
+ {
+ srcBitmap.SetPos( TPoint( iSrcPos.iX >> KStepPrecision, iSrcPos.iY >> KStepPrecision ) );
+ dstBitmap.SetPos( iDstPos );
+
+ // gather pixel data with step:
+ // 00 > 10
+ // /\ V
+ // 01 11
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY01);
+ srcBitmap.DecYPos();
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY00);
+ srcBitmap.IncXPos();
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY10);
+ srcBitmap.IncYPos();
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY11);
+ //return to starting position
+ srcBitmap.DecXPos();
+
+ // interpolate color using gathered pixel-data
+ ProcessColorData(pixelData, iSrcPos);
+
+ // put color in destination package
+ color = RgbToInt(pixelData.col);
+ dstBitmap.SetPixel(color);
+
+ // Add inner counters
+ iSrcPos += iSrcIncrementInner;
+ iDstPos.iX += iDstIncrementInner;
+ ++iProcessInner;
+ --pixelCounter;
+ }
+
+ // Check if inner loop is finished (not just pixel counter)
+ if( iProcessInner == iProcessSize.iWidth )
+ {
+ // Reset inner counters
+ iSrcPos.iX -= iSrcIncrementInner.iX * iProcessInner;
+ iSrcPos.iY -= iSrcIncrementInner.iY * iProcessInner;
+
+ iDstPos.iX -= iDstIncrementInner * iProcessInner;
+ iProcessInner = 0;
+
+ // Add outer counters
+ iSrcPos += iSrcIncrementOuter;
+ iDstPos.iY += iDstIncrementOuter;
+ ++iProcessOuter;
+ }
+ }
+ }
+ else
+ {
+ while( iProcessOuter < iProcessSize.iHeight && pixelCounter )
+ {
+ while( iProcessInner < iProcessSize.iWidth && pixelCounter )
+ {
+ srcBitmap.SetPos( TPoint( iSrcPos.iX >> KStepPrecision, iSrcPos.iY >> KStepPrecision ) );
+ dstBitmap.SetPos( iDstPos );
+
+ // gather pixel data with step:
+ // 00 > 10
+ // /\
+ // 01 < 11
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY11);
+ srcBitmap.DecXPos();
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY01);
+ srcBitmap.DecYPos();
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY00);
+ srcBitmap.IncXPos();
+ IntToRgb(srcBitmap.GetPixel(),pixelData.colXY10);
+ //return to starting position
+ srcBitmap.IncYPos();
+
+ // interpolate color using gathered pixel-data
+ ProcessColorData(pixelData, iSrcPos);
+
+ // put color in destination package
+ color = RgbToInt(pixelData.col);
+ dstBitmap.SetPixel(color);
+
+ // Add inner counters
+ iSrcPos += iSrcIncrementInner;
+ iDstPos.iX += iDstIncrementInner;
+ ++iProcessInner;
+ --pixelCounter;
+ }
+
+ // Check if inner loop is finished (not just pixel counter)
+ if( iProcessInner == iProcessSize.iWidth )
+ {
+ // Reset inner counters
+ iSrcPos.iX -= iSrcIncrementInner.iX * iProcessInner;
+ iSrcPos.iY -= iSrcIncrementInner.iY * iProcessInner;
+
+ iDstPos.iX -= iDstIncrementInner * iProcessInner;
+ iProcessInner = 0;
+
+ // Add outer counters
+ iSrcPos += iSrcIncrementOuter;
+ iDstPos.iY += iDstIncrementOuter;
+ ++iProcessOuter;
+ }
+
+ }
+ }
+
+ // Release heap lock
+ dstBitmap.End();
+ srcBitmap.End();
+
+ // ETrue if more processing is still needed
+ return ( iProcessOuter < iProcessSize.iHeight );
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::SelfComplete
+// -----------------------------------------------------------------------------
+void CIHLScaler::SelfComplete()
+ {
+ SetActive();
+ iStatus = KRequestPending;
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete( status, KErrNone );
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::RequestComplete
+// -----------------------------------------------------------------------------
+void CIHLScaler::RequestComplete( TInt aReason )
+ {
+ ASSERT( iScalerStatus );
+ User::RequestComplete( iScalerStatus, aReason );
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLScaler::InitCodePath
+// -----------------------------------------------------------------------------
+void CIHLScaler::InitCodePath(const TSize& aSrcSize, const TDisplayMode &aSrcMode, const TSize& aDstSize, const TDisplayMode &aDstMode, TBool aOnlyScaling)
+ {
+ // Choose the correct processing code path
+ ProcessingFunc = &CIHLScaler::ProcessNearestNeighbour;
+
+ if( iOptions & MIHLImageViewer::EOptionUseBilinearInterpolation )
+ {
+ // TODO: optimize bilinear scaling
+ IHL_DEBUG("CIHLScaler::InitCodePath: slow bilinear");
+ ProcessingFunc = CIHLScaler::ProcessBilinear;
+ iScanlinesPerRound = KProcessPixelsPerStep / iProcessSize.iWidth;
+ }
+ else if(aSrcMode == EColor64K && aSrcMode==aDstMode && !iSrcBitmap->IsCompressedInRAM() && !iDstBitmap->IsCompressedInRAM())
+ {
+ // 16 bit non-compressed bitmaps
+
+ // Calculate how many pixels the scanline is actually wide in the memory
+ iSrcPitchInPixels = CFbsBitmap::ScanLineLength( aSrcSize.iWidth, aSrcMode ) >> 1;
+ iDstPitchInPixels = CFbsBitmap::ScanLineLength( aDstSize.iWidth, aDstMode ) >> 1;
+
+ // How many pixels to move destination pointer at the end of each scanline to get to next pixel
+ iDstResidualPixels = iDstIncrementOuter*iDstPitchInPixels - iDstIncrementInner*iProcessSize.iWidth;
+
+ // Buffer offset to the first destination pixel
+ iDstStartOffset = iDstPos.iY * iDstPitchInPixels + iDstPos.iX;
+
+ if(!aOnlyScaling)
+ {
+ IHL_DEBUG("CIHLScaler::InitCodePath: fast 64K scale&rotate");
+ ProcessingFunc = &CIHLScaler::ProcessNearestNeighbour64K;
+
+ // Calculate how often the process should allow AS to run
+ iScanlinesPerRound = KBytesPerStepFastPath / (iProcessSize.iWidth<<1);
+ }
+ else
+ {
+ IHL_DEBUG("CIHLScaler::InitCodePath: fast 64K scale only");
+ ProcessingFunc = &CIHLScaler::ProcessNearestNeighbour64KScaleOnly;
+
+ // Calculate how often the process should allow AS to run
+ iScanlinesPerRound = KBytesPerStepFastPathScaleOnly / (iProcessSize.iWidth<<1);
+ }
+ }
+
+ else if((aSrcMode == EColor16MU || aSrcMode == EColor16MA) && aSrcMode==aDstMode && !iSrcBitmap->IsCompressedInRAM() && !iDstBitmap->IsCompressedInRAM())
+ {
+ // 32 bit non-compressed bitmaps
+
+ // Calculate how many pixels the scanline is actually wide in the memory
+ iSrcPitchInPixels = CFbsBitmap::ScanLineLength( aSrcSize.iWidth, aSrcMode ) >> 2;
+ iDstPitchInPixels = CFbsBitmap::ScanLineLength( aDstSize.iWidth, aDstMode ) >> 2;
+
+ // How many pixels to move destination pointer at the end of each scanline to get to next pixel
+ iDstResidualPixels = iDstIncrementOuter*iDstPitchInPixels - iDstIncrementInner*iProcessSize.iWidth;
+
+ // Buffer offset to the first destination pixel
+ iDstStartOffset = iDstPos.iY * iDstPitchInPixels + iDstPos.iX;
+
+ if(!aOnlyScaling)
+ {
+ IHL_DEBUG("CIHLScaler::InitCodePath: fast 16MX scale&rotate");
+ ProcessingFunc = &CIHLScaler::ProcessNearestNeighbour16MX;
+
+ // Calculate how often the process should allow AS to run
+ iScanlinesPerRound = KBytesPerStepFastPath / (iProcessSize.iWidth<<2);
+ }
+ else
+ {
+ IHL_DEBUG("CIHLScaler::InitCodePath: fast 16MX scale only");
+ ProcessingFunc = &CIHLScaler::ProcessNearestNeighbour16MXScaleOnly;
+
+ // Calculate how often the process should allow AS to run
+ iScanlinesPerRound = KBytesPerStepFastPathScaleOnly / (iProcessSize.iWidth<<2);
+ }
+ }
+ else
+ {
+ IHL_DEBUG("CIHLScaler::InitCodePath: slow nearest neighbor");
+ iScanlinesPerRound = KProcessPixelsPerStep / iProcessSize.iWidth;
+ }
+
+ IHL_DEBUG2(KIHLDebug, "CIHLScaler::InitCodePath: scanlines per round = %d", iScanlinesPerRound);
+ }
+
+// End of File