diff -r 2e2a89493e2b -r 48dd0f169f0d imagehandlinglib/Src/CIHLScaler.cpp --- a/imagehandlinglib/Src/CIHLScaler.cpp Fri Sep 03 10:29:37 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1315 +0,0 @@ -/* -* 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 -#include -#include - -// 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( 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( 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