diff -r 000000000000 -r 05e9090e2422 skins/AknSkins/rlpluginsrc/AknsRlEffectPluginConvolution.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/skins/AknSkins/rlpluginsrc/AknsRlEffectPluginConvolution.cpp Thu Dec 17 09:14:12 2009 +0200 @@ -0,0 +1,1948 @@ +/* +* Copyright (c) 2004-2008 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: Provides convolution operations on images. +* +*/ + + +// INCLUDE FILES +#include "AknsRlEffectPluginConvolution.h" +#include "AknsRlEffectUtil.h" +#include "fx_asm_versions.h" + +// CONSTANTS + +// Fixed convolution kernels +const TInt KKernelEdgeDetect[9] = { -1, -1, -1, + -1, 8, -1, + -1, -1, -1 }; + +const TInt KKernelBlur[9] = { 1, 2, 1, + 2, 2, 2, + 1, 2, 1 }; + +const TInt KKernelBlurGauss[9] = { 0, 1, 0, + 1, 4, 1, + 0, 1, 0 }; + +const TInt KKernelEmbossSoft[9] = { -1, 0, 0, + 0, 0, 0, + 0, 0, 1 }; + +const TInt KKernelEmbossHard[9] = { -1, -1, 0, + -1, 0, 1, + 0, 1, 1 }; + +const TInt KKernelEnhanceDetail[9] = { 0, -1, 0, + -1, 9, -1, + 0, -1, 0 }; + +const TInt KKernelEnhanceFocus[9] = { -1, 0, -1, + 0, 7, 0, + -1, 0, -1 }; + +const TInt KKernelSoften[9] = { 1, 1, 1, + 1, 1, 1, + 1, 1, 1 }; + +const TInt KKernelSharpen[9] = { 0, -1, 0, + -1, 5, -1, + 0, -1, 0 }; + +const TInt KKernelSharpenMore[9] = {-1, -1, -1, + -1, 9, -1, + -1, -1, -1 }; + +/*lint -save -e834 */ // Let's get real...not confusing + +// ==================== TEMPLATE IMPL. OF CONVOLUTION ========================== +/** +* Template implementation of Convolution. Type defines the used data type for +* iterating over the bitmap data. X, R, G and B define the used pixel color bit +* layout. +*/ +template +class AknsRlEffectConvolution + { + public: + //------------------------------------------------------------------------ + /** + * Convolutes a bitmap with generic 3x3 convolution kernel. + */ + static void Kernel( const CFbsBitmap& aTarget, + const CFbsBitmap& aSource, + const TInt aKernel[9], + const TInt aBlendFactor, + const TInt aBias ) + { + TInt width = aTarget.SizeInPixels().iWidth; + TInt height = aTarget.SizeInPixels().iHeight; + // ScanLineLength returns bytes, but width must match the Type + TInt scanWtarget = (CFbsBitmap::ScanLineLength(aTarget.SizeInPixels().iWidth, aTarget.DisplayMode())) / sizeof(Type); + TInt scanWsource = (CFbsBitmap::ScanLineLength(aSource.SizeInPixels().iWidth, aSource.DisplayMode())) / sizeof(Type); + + TInt kernelSum = aKernel[0] + aKernel[1] + aKernel[2] + + aKernel[3] + aKernel[4] + aKernel[5] + + aKernel[6] + aKernel[7] + aKernel[8]; + + if( 0 == kernelSum ) + kernelSum = 1; + + TInt r, g, b; + TInt x, y; // Loop counters + + // Pitch is the number of pixels to skip before next scanline start + TInt pitchTarget = scanWtarget - width; + TInt pitchSource = scanWsource - width; + + // Prepare the data addresses + aTarget.LockHeap( ETrue ); // Lock the global bitmap heap + Type* dataT = reinterpret_cast( aTarget.DataAddress() ); + Type* dataS = reinterpret_cast( aSource.DataAddress() ); + + dataS = dataS + scanWsource + 1; + + // Do the actual convolution + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + { + r = aBias + (AknsRlRgb::R8(*(dataS - scanWsource - 1)) * aKernel[0] + + AknsRlRgb::R8(*(dataS - scanWsource )) * aKernel[1] + + AknsRlRgb::R8(*(dataS - scanWsource + 1)) * aKernel[2] + + AknsRlRgb::R8(*(dataS - 1 )) * aKernel[3] + + AknsRlRgb::R8(*(dataS )) * aKernel[4] + + AknsRlRgb::R8(*(dataS + 1 )) * aKernel[5] + + AknsRlRgb::R8(*(dataS + scanWsource - 1)) * aKernel[6] + + AknsRlRgb::R8(*(dataS + scanWsource )) * aKernel[7] + + AknsRlRgb::R8(*(dataS + scanWsource + 1)) * aKernel[8]) / kernelSum; + + g = aBias + (AknsRlRgb::G8(*(dataS - scanWsource - 1)) * aKernel[0] + + AknsRlRgb::G8(*(dataS - scanWsource )) * aKernel[1] + + AknsRlRgb::G8(*(dataS - scanWsource + 1)) * aKernel[2] + + AknsRlRgb::G8(*(dataS - 1 )) * aKernel[3] + + AknsRlRgb::G8(*(dataS )) * aKernel[4] + + AknsRlRgb::G8(*(dataS + 1 )) * aKernel[5] + + AknsRlRgb::G8(*(dataS + scanWsource - 1)) * aKernel[6] + + AknsRlRgb::G8(*(dataS + scanWsource )) * aKernel[7] + + AknsRlRgb::G8(*(dataS + scanWsource + 1)) * aKernel[8]) / kernelSum; + + + b = aBias + (AknsRlRgb::B8(*(dataS - scanWsource - 1)) * aKernel[0] + + AknsRlRgb::B8(*(dataS - scanWsource )) * aKernel[1] + + AknsRlRgb::B8(*(dataS - scanWsource + 1)) * aKernel[2] + + AknsRlRgb::B8(*(dataS - 1 )) * aKernel[3] + + AknsRlRgb::B8(*(dataS )) * aKernel[4] + + AknsRlRgb::B8(*(dataS + 1 )) * aKernel[5] + + AknsRlRgb::B8(*(dataS + scanWsource - 1)) * aKernel[6] + + AknsRlRgb::B8(*(dataS + scanWsource )) * aKernel[7] + + AknsRlRgb::B8(*(dataS + scanWsource + 1)) * aKernel[8]) / kernelSum; + + + // Exposure blending. Note: It is assumed that arithmetic shifting + // is supported -> negative values are shifted correctly + r = ( r * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::R8(*dataS) ) >> 8; + g = ( g * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::G8(*dataS) ) >> 8; + b = ( b * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::B8(*dataS) ) >> 8; + + if( r < 0 ) r = 0; + else if( r > 255 ) r = 255; + + if( g < 0 ) g = 0; + else if( g > 255 ) g = 255; + + if( b < 0 ) b = 0; + else if( b > 255 ) b = 255; + + AknsRlRgb::SetRgb8( dataT, TUint8(r), TUint8(g), TUint8(b) ); + + dataT++; + dataS++; + } + + dataT = dataT + pitchTarget; + dataS = dataS + pitchSource; + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + } + //------------------------------------------------------------------------ + /** + * "Convolutes" a bitmap with adjustable gaussian blur kernel. + * Kernel size from 3*3 to 33*33 (odd sizes). + */ + static void AdjustableGaussian( const CFbsBitmap& aTarget, + const CFbsBitmap& aSource, + TUint16* aColumnBuffer, + const TInt aKernelsize ) + { + TInt width = aTarget.SizeInPixels().iWidth; + TInt height = aTarget.SizeInPixels().iHeight; + // ScanLineLength returns bytes, but width must match the Type + TInt scanWtarget = (CFbsBitmap::ScanLineLength(aTarget.SizeInPixels().iWidth, aTarget.DisplayMode())) / sizeof(Type); + TInt scanWsource = (CFbsBitmap::ScanLineLength(aSource.SizeInPixels().iWidth, aSource.DisplayMode())) / sizeof(Type); + + + TUint16 r, g, b; + r=0; + g=0; + b=0; + TInt x, y, i; // Loop counters + TInt bufIndx, bufIndxTarget; + + // Pitch is the number of pixels to skip before next scanline start + TInt pitchTarget = scanWtarget - width; + TInt pitchSource = scanWsource - width; + + // Prepare the data addresses + aTarget.LockHeap( ETrue ); // Lock the global bitmap heap + Type* dataT = reinterpret_cast( aTarget.DataAddress() ); + Type* dataS = reinterpret_cast( aSource.DataAddress() ); + Type* dataR = dataT; // for recursive iterations, both source and target are the same + dataS = dataS + scanWsource + 1; // state machine takes pixel (1,1) and output goes to pixel (0,0) + + TUint16 tmp1; + TUint16 tmp2; + + // row buffer variables for red, green and blue components + TUint16 SR0r; + TUint16 SR1r; + TUint16 SR0g; + TUint16 SR1g; + TUint16 SR0b; + TUint16 SR1b; + + TInt col0_rIndex; // index for row 0 columns in aColumnBuffer for red component + TInt col1_rIndex; // index for row 1 columns in aColumnBuffer for red component + TInt col0_gIndex; // index for row 0 columns in aColumnBuffer for green component + TInt col1_gIndex; // index for row 1 columns in aColumnBuffer for green component + TInt col0_bIndex; // index for row 0 columns in aColumnBuffer for blue component + TInt col1_bIndex; // index for row 1 columns in aColumnBuffer for blue component + + TBool renderWithBuffers = ETrue; + if ( aKernelsize < 7 ) // don't try to use temp buffers with small kernel + renderWithBuffers = EFalse; + + TUint16* redBuffer; + TUint16* greenBuffer; + TUint16* blueBuffer; + + // to disable warnings + redBuffer = NULL; + greenBuffer = NULL; + blueBuffer = NULL; + + if( renderWithBuffers ) + { + // OOM returns NULL + redBuffer = new TUint16[(width+1)*(height+1)]; + greenBuffer = new TUint16[(width+1)*(height+1)]; + blueBuffer = new TUint16[(width+1)*(height+1)]; + + // All buffers are required for rendering + if( !redBuffer || !greenBuffer || !blueBuffer ) + { + delete [] redBuffer; + redBuffer = NULL; + delete [] greenBuffer; + greenBuffer = NULL; + delete [] blueBuffer; + blueBuffer = NULL; + + renderWithBuffers = EFalse; + } + } + + if( renderWithBuffers ) + { + i = width + 2; // start writing to pixel (1,1) + for ( y = 0; y < (height - 1) ; y++ ) + { + for ( x = 0; x < (width - 1) ; x++ ) + { + redBuffer[i] = (TUint16)AknsRlRgb::R8(*dataS); + greenBuffer[i] = (TUint16)AknsRlRgb::G8(*dataS); + blueBuffer[i] = (TUint16)AknsRlRgb::B8(*dataS); + i++; + dataS++; + } + redBuffer[i] = redBuffer[i-1]; + greenBuffer[i] = greenBuffer[i-1]; + blueBuffer[i] = blueBuffer[i-1]; + i+=2; // start from second pixel + dataS = dataS + pitchSource + 1; // start from second pixel + } + + for ( x = 0; x < width ; x++ ) // copy bottom row + { + redBuffer[i] = redBuffer[i-(width+1)]; + greenBuffer[i] = greenBuffer[i-(width+1)]; + blueBuffer[i] = blueBuffer[i-(width+1)]; + i++; + } + + redBuffer[1] = redBuffer[width+2]; // initialize these for row registers + greenBuffer[1] = greenBuffer[width+2]; + blueBuffer[1] = blueBuffer[width+2]; + + for ( i = 0; i < (aKernelsize - 1) >> 1 ; i++ ) // do (N-1) / 2 times + { + bufIndx = width+2; + bufIndxTarget = 0; + + for( y = 0; y < height; y++ ) + { + SR0r = redBuffer[bufIndxTarget+1]; // initialize row buffer variables + SR1r = redBuffer[bufIndxTarget+1]; + SR0g = greenBuffer[bufIndxTarget+1]; + SR1g = greenBuffer[bufIndxTarget+1]; + SR0b = blueBuffer[bufIndxTarget+1]; + SR1b = blueBuffer[bufIndxTarget+1]; + col0_rIndex = 0; // initialize indexes for column buffers + col1_rIndex = width; + col0_gIndex = col1_rIndex + width; + col1_gIndex = col0_gIndex + width; + col0_bIndex = col1_gIndex + width; + col1_bIndex = col0_bIndex + width; + for( x = 0; x < width; x++ ) + { + // red + tmp1 = redBuffer[bufIndx]; + tmp2 = (TUint16)(SR0r + tmp1); + SR0r = tmp1; + tmp1 = (TUint16)(SR1r + tmp2); + SR1r = tmp2; + + tmp2 = (TUint16)(aColumnBuffer[col0_rIndex] + tmp1); + aColumnBuffer[col0_rIndex++] = tmp1; + redBuffer[bufIndxTarget] = (TUint16)((8 + aColumnBuffer[col1_rIndex] + tmp2) >> 4); + aColumnBuffer[col1_rIndex++] = tmp2; + + // green + tmp1 = greenBuffer[bufIndx]; + tmp2 = (TUint16)(SR0g + tmp1); + SR0g = tmp1; + tmp1 = (TUint16)(SR1g + tmp2); + SR1g = tmp2; + + tmp2 = (TUint16)(aColumnBuffer[col0_gIndex] + tmp1); + aColumnBuffer[col0_gIndex++] = tmp1; + greenBuffer[bufIndxTarget] = (TUint16)((8 + aColumnBuffer[col1_gIndex] + tmp2) >> 4); + aColumnBuffer[col1_gIndex++] = tmp2; + + // blue + tmp1 = blueBuffer[bufIndx++]; + tmp2 = (TUint16)(SR0b + tmp1); + SR0b = tmp1; + tmp1 = (TUint16)(SR1b + tmp2); + SR1b = tmp2; + + tmp2 = (TUint16)(aColumnBuffer[col0_bIndex] + tmp1); + aColumnBuffer[col0_bIndex++] = tmp1; + b = (TUint16)((8 + aColumnBuffer[col1_bIndex] + tmp2) >> 4); + blueBuffer[bufIndxTarget++] = (TUint16)b; + aColumnBuffer[col1_bIndex++] = tmp2; + } + bufIndx++; + bufIndxTarget++; + } + } + + // now write target from buffers + i = 0; + for ( y = 0; y < height ; y++ ) + { + for ( x = 0; x < width ; x++ ) + { + AknsRlRgb::SetRgb8LessG( dataT, + redBuffer[i], + greenBuffer[i], + blueBuffer[i++] ); + dataT++; + } + dataT = dataT + pitchTarget; + i++; + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + delete [] redBuffer; + delete [] greenBuffer; + delete [] blueBuffer; + return; + } + else + { + // Do the actual convolution + for ( i = 0; i < (aKernelsize - 1) >> 1 ; i++ ) // do (N-1) / 2 times + { + + for( y = 0; y < (height - 1); y++ ) + { + SR0r = 0; // initialize row buffer variables + SR1r = 0; + SR0g = 0; + SR1g = 0; + SR0b = 0; + SR1b = 0; + col0_rIndex = 0; // initialize indexes for column buffers + col1_rIndex = width; + col0_gIndex = col1_rIndex + width; + col1_gIndex = col0_gIndex + width; + col0_bIndex = col1_gIndex + width; + col1_bIndex = col0_bIndex + width; + for( x = 0; x < (width - 1); x++ ) + { + // red + tmp1 = (TUint16)AknsRlRgb::R8(*dataS); + tmp2 = (TUint16)(SR0r + tmp1); + SR0r = tmp1; + tmp1 = (TUint16)(SR1r + tmp2); + SR1r = tmp2; + + tmp2 = (TUint16)(aColumnBuffer[col0_rIndex] + tmp1); + aColumnBuffer[col0_rIndex++] = tmp1; + r = (TUint16)((8 + aColumnBuffer[col1_rIndex] + tmp2) >> 4); + aColumnBuffer[col1_rIndex++] = tmp2; + + // green + tmp1 = (TUint16)AknsRlRgb::G8(*dataS); + tmp2 = (TUint16)(SR0g + tmp1); + SR0g = tmp1; + tmp1 = (TUint16)(SR1g + tmp2); + SR1g = tmp2; + + tmp2 = (TUint16)(aColumnBuffer[col0_gIndex] + tmp1); + aColumnBuffer[col0_gIndex++] = tmp1; + g = (TUint16)((8 + aColumnBuffer[col1_gIndex] + tmp2) >> 4); + aColumnBuffer[col1_gIndex++] = tmp2; + + // blue + tmp1 = (TUint16)AknsRlRgb::B8(*dataS); + tmp2 = (TUint16)(SR0b + tmp1); + SR0b = tmp1; + tmp1 = (TUint16)(SR1b + tmp2); + SR1b = tmp2; + + tmp2 = (TUint16)(aColumnBuffer[col0_bIndex] + tmp1); + aColumnBuffer[col0_bIndex++] = tmp1; + b = (TUint16)((8 + aColumnBuffer[col1_bIndex] + tmp2) >> 4); + aColumnBuffer[col1_bIndex++] = tmp2; + + + if( r > 255 ) r = 255; + if( g > 255 ) g = 255; + if( b > 255 ) b = 255; + + AknsRlRgb::SetRgb8LessG( dataT, r, g, b ); + + dataT++; + dataS++; + } + + dataT = dataT + pitchTarget + 1; + dataS = dataS + pitchSource + 1; + } + dataT = dataR; // for more than 1 iterations, use target bitmap for both + dataS = dataR+scanWtarget+1; // target and source + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + } + } + + //------------------------------------------------------------------------ + /** + * Convolutes a bitmap by calculating the mean value of a 3x3 pixel + * neighborhood as the resulting pixel value. + */ + static void Mean( const CFbsBitmap& aTarget, + const CFbsBitmap& aSource, + TInt aBlendFactor ) + { + TInt width = aTarget.SizeInPixels().iWidth; + TInt height = aTarget.SizeInPixels().iHeight; + // ScanLineLength returns bytes, but width must match the Type + TInt scanWtarget = (CFbsBitmap::ScanLineLength(aTarget.SizeInPixels().iWidth, aTarget.DisplayMode())) / sizeof(Type); + TInt scanWsource = (CFbsBitmap::ScanLineLength(aSource.SizeInPixels().iWidth, aSource.DisplayMode())) / sizeof(Type); + + TInt r, g, b; + TInt x, y; // Loop counters + + // Pitch is the number of pixels to skip before next scanline start + TInt pitchTarget = scanWtarget - width; + TInt pitchSource = scanWsource - width; + + // Prepare the data addresses + aTarget.LockHeap( ETrue ); // Lock the global bitmap heap + Type* dataT = reinterpret_cast( aTarget.DataAddress() ); + Type* dataS = reinterpret_cast( aSource.DataAddress() ); + + dataS = dataS + scanWsource + 1; + + // Calculate the mean per pixel + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + { + r = (AknsRlRgb::R8(*(dataS - scanWsource - 1)) + + AknsRlRgb::R8(*(dataS - scanWsource )) + + AknsRlRgb::R8(*(dataS - scanWsource + 1)) + + AknsRlRgb::R8(*(dataS - 1 )) + + AknsRlRgb::R8(*(dataS )) + + AknsRlRgb::R8(*(dataS + 1 )) + + AknsRlRgb::R8(*(dataS + scanWsource - 1)) + + AknsRlRgb::R8(*(dataS + scanWsource )) + + AknsRlRgb::R8(*(dataS + scanWsource + 1))) / 9; + + g = (AknsRlRgb::G8(*(dataS - scanWsource - 1)) + + AknsRlRgb::G8(*(dataS - scanWsource )) + + AknsRlRgb::G8(*(dataS - scanWsource + 1)) + + AknsRlRgb::G8(*(dataS - 1 )) + + AknsRlRgb::G8(*(dataS )) + + AknsRlRgb::G8(*(dataS + 1 )) + + AknsRlRgb::G8(*(dataS + scanWsource - 1)) + + AknsRlRgb::G8(*(dataS + scanWsource )) + + AknsRlRgb::G8(*(dataS + scanWsource + 1))) / 9; + + + b = (AknsRlRgb::B8(*(dataS - scanWsource - 1)) + + AknsRlRgb::B8(*(dataS - scanWsource )) + + AknsRlRgb::B8(*(dataS - scanWsource + 1)) + + AknsRlRgb::B8(*(dataS - 1 )) + + AknsRlRgb::B8(*(dataS )) + + AknsRlRgb::B8(*(dataS + 1 )) + + AknsRlRgb::B8(*(dataS + scanWsource - 1)) + + AknsRlRgb::B8(*(dataS + scanWsource )) + + AknsRlRgb::B8(*(dataS + scanWsource + 1))) / 9; + + // Exposure blending. Note: It is assumed that arithmetic shifting + // is supported -> negative values are shifted correctly + r = ( r * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::R8(*dataS) ) >> 8; + g = ( g * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::G8(*dataS) ) >> 8; + b = ( b * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::B8(*dataS) ) >> 8; + + if( r < 0 ) r = 0; + else if( r > 255 ) r = 255; + + if( g < 0 ) g = 0; + else if( g > 255 ) g = 255; + + if( b < 0 ) b = 0; + else if( b > 255 ) b = 255; + + AknsRlRgb::SetRgb8( dataT, TUint8(r), TUint8(g), TUint8(b) ); + + dataT++; + dataS++; + } + + dataT = dataT + pitchTarget; + dataS = dataS + pitchSource; + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + } + + //------------------------------------------------------------------------ + /** + * Extracts the color channel values (red, green, blue) on a 3x3 + * neighborhood to arrays. + */ + static void ExtractChannels( TUint8 aReds[9], TUint8 aGreens[9], TUint8 aBlues[9], + const Type* aPtr, TInt aScanW ) + { + // Top left + Type val = *(aPtr - aScanW - 1); + aReds[0] = AknsRlRgb::R8(val); + aGreens[0] = AknsRlRgb::G8(val); + aBlues[0] = AknsRlRgb::B8(val); + + // Top + val = *(aPtr - aScanW); + aReds[1] = AknsRlRgb::R8(val); + aGreens[1] = AknsRlRgb::G8(val); + aBlues[1] = AknsRlRgb::B8(val); + + // Top right + val = *(aPtr - aScanW + 1); + aReds[2] = AknsRlRgb::R8(val); + aGreens[2] = AknsRlRgb::G8(val); + aBlues[2] = AknsRlRgb::B8(val); + + // Left + val = *(aPtr - 1); + aReds[3] = AknsRlRgb::R8(val); + aGreens[3] = AknsRlRgb::G8(val); + aBlues[3] = AknsRlRgb::B8(val); + + // Center + val = *(aPtr); + aReds[4] = AknsRlRgb::R8(val); + aGreens[4] = AknsRlRgb::G8(val); + aBlues[4] = AknsRlRgb::B8(val); + + // Right + val = *(aPtr + 1); + aReds[5] = AknsRlRgb::R8(val); + aGreens[5] = AknsRlRgb::G8(val); + aBlues[5] = AknsRlRgb::B8(val); + + // Bottom left + val = *(aPtr + aScanW - 1); + aReds[6] = AknsRlRgb::R8(val); + aGreens[6] = AknsRlRgb::G8(val); + aBlues[6] = AknsRlRgb::B8(val); + + // Bottom + val = *(aPtr + aScanW); + aReds[7] = AknsRlRgb::R8(val); + aGreens[7] = AknsRlRgb::G8(val); + aBlues[7] = AknsRlRgb::B8(val); + + // Bottom right + val = *(aPtr + aScanW + 1); + aReds[8] = AknsRlRgb::R8(val); + aGreens[8] = AknsRlRgb::G8(val); + aBlues[8] = AknsRlRgb::B8(val); + } + //------------------------------------------------------------------------ + /** + * Convolutes a bitmap by calculating the median value of a 3x3 pixel + * neighborhood as the resulting pixel value. + */ + static void Median( const CFbsBitmap& aTarget, + const CFbsBitmap& aSource, + TInt aBlendFactor ) + { + TInt width = aTarget.SizeInPixels().iWidth; + TInt height = aTarget.SizeInPixels().iHeight; + // ScanLineLength returns bytes, but width must match the Type + TInt scanWtarget = (CFbsBitmap::ScanLineLength(aTarget.SizeInPixels().iWidth, aTarget.DisplayMode())) / sizeof(Type); + TInt scanWsource = (CFbsBitmap::ScanLineLength(aSource.SizeInPixels().iWidth, aSource.DisplayMode())) / sizeof(Type); + + TInt r, g, b; + TInt x, y; // Loop counters + TUint8 reds[9], greens[9], blues[9]; + + // Pitch is the number of pixels to skip before next scanline start + TInt pitchTarget = scanWtarget - width; + TInt pitchSource = scanWsource - width; + + // Prepare the data addresses + aTarget.LockHeap( ETrue ); // Lock the global bitmap heap + Type* dataT = reinterpret_cast( aTarget.DataAddress() ); + Type* dataS = reinterpret_cast( aSource.DataAddress() ); + + // Convolute the inner rect + dataS = dataS + scanWsource + 1; + + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + { + // Median calculation is done on per channel basis, extract the + // neighborhood channels. + ExtractChannels(reds, greens, blues, dataS, scanWsource); + + // Median + exposure blending. Note: It is assumed that arithmetic + // shifting is supported -> negative values are shifted correctly + r = ( AknsRlUtil::Median9(reds) * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::R8(*dataS) ) >> 8; + g = ( AknsRlUtil::Median9(greens) * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::G8(*dataS) ) >> 8; + b = ( AknsRlUtil::Median9(blues) * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::B8(*dataS) ) >> 8; + + if( r < 0 ) r = 0; + else if( r > 255 ) r = 255; + + if( g < 0 ) g = 0; + else if( g > 255 ) g = 255; + + if( b < 0 ) b = 0; + else if( b > 255 ) b = 255; + + AknsRlRgb::SetRgb8( dataT, TUint8(r), TUint8(g), TUint8(b) ); + + dataT++; + dataS++; + } + + dataT = dataT + pitchTarget; + dataS = dataS + pitchSource; + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + } + //------------------------------------------------------------------------ + /** + * Convolutes a bitmap by calculating the maximum value of a 3x3 pixel + * neighborhood as the resulting pixel value. + */ + static void Max( const CFbsBitmap& aTarget, + const CFbsBitmap& aSource, + TInt aBlendFactor ) + { + TInt width = aTarget.SizeInPixels().iWidth; + TInt height = aTarget.SizeInPixels().iHeight; + // ScanLineLength returns bytes, but width must match the Type + TInt scanWtarget = (CFbsBitmap::ScanLineLength(aTarget.SizeInPixels().iWidth, aTarget.DisplayMode())) / sizeof(Type); + TInt scanWsource = (CFbsBitmap::ScanLineLength(aSource.SizeInPixels().iWidth, aSource.DisplayMode())) / sizeof(Type); + + TInt r, g, b; + TInt x, y; // Loop counters + + // Pitch is the number of pixels to skip before next scanline start + TInt pitchTarget = scanWtarget - width; + TInt pitchSource = scanWsource - width; + + // Prepare the data addresses + aTarget.LockHeap( ETrue ); // Lock the global bitmap heap + Type* dataT = reinterpret_cast( aTarget.DataAddress() ); + Type* dataS = reinterpret_cast( aSource.DataAddress() ); + + // Convolute the inner rect + dataS = dataS + scanWsource + 1; + + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + { + r = AknsRlRgb::R8(*(dataS - scanWsource - 1 )); + r = AknsRlUtil::Max( AknsRlRgb::R8(*(dataS - scanWsource )), r ); + r = AknsRlUtil::Max( AknsRlRgb::R8(*(dataS - scanWsource + 1)), r ); + r = AknsRlUtil::Max( AknsRlRgb::R8(*(dataS - 1 )), r ); + r = AknsRlUtil::Max( AknsRlRgb::R8(*(dataS )), r ); + r = AknsRlUtil::Max( AknsRlRgb::R8(*(dataS + 1 )), r ); + r = AknsRlUtil::Max( AknsRlRgb::R8(*(dataS + scanWsource - 1)), r ); + r = AknsRlUtil::Max( AknsRlRgb::R8(*(dataS + scanWsource )), r ); + r = AknsRlUtil::Max( AknsRlRgb::R8(*(dataS + scanWsource + 1)), r ); + + g = AknsRlRgb::G8(*(dataS - scanWsource - 1 )); + g = AknsRlUtil::Max( AknsRlRgb::G8(*(dataS - scanWsource )), g ); + g = AknsRlUtil::Max( AknsRlRgb::G8(*(dataS - scanWsource + 1)), g ); + g = AknsRlUtil::Max( AknsRlRgb::G8(*(dataS - 1 )), g ); + g = AknsRlUtil::Max( AknsRlRgb::G8(*(dataS )), g ); + g = AknsRlUtil::Max( AknsRlRgb::G8(*(dataS + 1 )), g ); + g = AknsRlUtil::Max( AknsRlRgb::G8(*(dataS + scanWsource - 1)), g ); + g = AknsRlUtil::Max( AknsRlRgb::G8(*(dataS + scanWsource )), g ); + g = AknsRlUtil::Max( AknsRlRgb::G8(*(dataS + scanWsource + 1)), g ); + + + b = AknsRlRgb::B8(*(dataS - scanWsource - 1 )); + b = AknsRlUtil::Max( AknsRlRgb::B8(*(dataS - scanWsource )), b ); + b = AknsRlUtil::Max( AknsRlRgb::B8(*(dataS - scanWsource + 1)), b ); + b = AknsRlUtil::Max( AknsRlRgb::B8(*(dataS - 1 )), b ); + b = AknsRlUtil::Max( AknsRlRgb::B8(*(dataS )), b ); + b = AknsRlUtil::Max( AknsRlRgb::B8(*(dataS + 1 )), b ); + b = AknsRlUtil::Max( AknsRlRgb::B8(*(dataS + scanWsource - 1)), b ); + b = AknsRlUtil::Max( AknsRlRgb::B8(*(dataS + scanWsource )), b ); + b = AknsRlUtil::Max( AknsRlRgb::B8(*(dataS + scanWsource + 1)), b ); + + // Exposure blending. Note: It is assumed that arithmetic shifting + // is supported -> negative values are shifted correctly + r = ( r * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::R8(*dataS) ) >> 8; + g = ( g * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::G8(*dataS) ) >> 8; + b = ( b * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::B8(*dataS) ) >> 8; + + if( r < 0 ) r = 0; + else if( r > 255 ) r = 255; + + if( g < 0 ) g = 0; + else if( g > 255 ) g = 255; + + if( b < 0 ) b = 0; + else if( b > 255 ) b = 255; + + AknsRlRgb::SetRgb8( dataT, TUint8(r), TUint8(g), TUint8(b) ); + + dataT++; + dataS++; + } + + dataT = dataT + pitchTarget; + dataS = dataS + pitchSource; + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + } + //------------------------------------------------------------------------ + /** + * Convolutes a bitmap by calculating the minimum value of a 3x3 pixel + * neighborhood as the resulting pixel value. + */ + static void Min( const CFbsBitmap& aTarget, + const CFbsBitmap& aSource, + TInt aBlendFactor ) + { + TInt width = aTarget.SizeInPixels().iWidth; + TInt height = aTarget.SizeInPixels().iHeight; + // ScanLineLength returns bytes, but width must match the Type + TInt scanWtarget = (CFbsBitmap::ScanLineLength(aTarget.SizeInPixels().iWidth, aTarget.DisplayMode())) / sizeof(Type); + TInt scanWsource = (CFbsBitmap::ScanLineLength(aSource.SizeInPixels().iWidth, aSource.DisplayMode())) / sizeof(Type); + + TInt r, g, b; + TInt x, y; // Loop counters + + // Pitch is the number of pixels to skip before next scanline start + TInt pitchTarget = scanWtarget - width; + TInt pitchSource = scanWsource - width; + + // Prepare the data addresses + aTarget.LockHeap( ETrue ); // Lock the global bitmap heap + Type* dataT = reinterpret_cast( aTarget.DataAddress() ); + Type* dataS = reinterpret_cast( aSource.DataAddress() ); + + // Convolute the inner rect + dataS = dataS + scanWsource + 1; + + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + { + r = AknsRlRgb::R8(*(dataS - scanWsource - 1 )); + r = AknsRlUtil::Min( AknsRlRgb::R8(*(dataS - scanWsource )), r ); + r = AknsRlUtil::Min( AknsRlRgb::R8(*(dataS - scanWsource + 1)), r ); + r = AknsRlUtil::Min( AknsRlRgb::R8(*(dataS - 1 )), r ); + r = AknsRlUtil::Min( AknsRlRgb::R8(*(dataS )), r ); + r = AknsRlUtil::Min( AknsRlRgb::R8(*(dataS + 1 )), r ); + r = AknsRlUtil::Min( AknsRlRgb::R8(*(dataS + scanWsource - 1)), r ); + r = AknsRlUtil::Min( AknsRlRgb::R8(*(dataS + scanWsource )), r ); + r = AknsRlUtil::Min( AknsRlRgb::R8(*(dataS + scanWsource + 1)), r ); + + g = AknsRlRgb::G8(*(dataS - scanWsource - 1 )); + g = AknsRlUtil::Min( AknsRlRgb::G8(*(dataS - scanWsource )), g ); + g = AknsRlUtil::Min( AknsRlRgb::G8(*(dataS - scanWsource + 1)), g ); + g = AknsRlUtil::Min( AknsRlRgb::G8(*(dataS - 1 )), g ); + g = AknsRlUtil::Min( AknsRlRgb::G8(*(dataS )), g ); + g = AknsRlUtil::Min( AknsRlRgb::G8(*(dataS + 1 )), g ); + g = AknsRlUtil::Min( AknsRlRgb::G8(*(dataS + scanWsource - 1)), g ); + g = AknsRlUtil::Min( AknsRlRgb::G8(*(dataS + scanWsource )), g ); + g = AknsRlUtil::Min( AknsRlRgb::G8(*(dataS + scanWsource + 1)), g ); + + + b = AknsRlRgb::B8(*(dataS - scanWsource - 1 )); + b = AknsRlUtil::Min( AknsRlRgb::B8(*(dataS - scanWsource )), b ); + b = AknsRlUtil::Min( AknsRlRgb::B8(*(dataS - scanWsource + 1)), b ); + b = AknsRlUtil::Min( AknsRlRgb::B8(*(dataS - 1 )), b ); + b = AknsRlUtil::Min( AknsRlRgb::B8(*(dataS )), b ); + b = AknsRlUtil::Min( AknsRlRgb::B8(*(dataS + 1 )), b ); + b = AknsRlUtil::Min( AknsRlRgb::B8(*(dataS + scanWsource - 1)), b ); + b = AknsRlUtil::Min( AknsRlRgb::B8(*(dataS + scanWsource )), b ); + b = AknsRlUtil::Min( AknsRlRgb::B8(*(dataS + scanWsource + 1)), b ); + + // Exposure blending. Note: It is assumed that arithmetic shifting + // is supported -> negative values are shifted correctly + r = ( r * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::R8(*dataS) ) >> 8; + g = ( g * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::G8(*dataS) ) >> 8; + b = ( b * aBlendFactor + (255 - aBlendFactor) * AknsRlRgb::B8(*dataS) ) >> 8; + + if( r < 0 ) r = 0; + else if( r > 255 ) r = 255; + + if( g < 0 ) g = 0; + else if( g > 255 ) g = 255; + + if( b < 0 ) b = 0; + else if( b > 255 ) b = 255; + + AknsRlRgb::SetRgb8( dataT, TUint8(r), TUint8(g), TUint8(b) ); + + dataT++; + dataS++; + } + + dataT = dataT + pitchTarget; + dataS = dataS + pitchSource; + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + } + }; // End of AknsRlEffectConvolution + +// =================== GRAYSCALE IMPL. OF CONVOLUTION ========================== +/** +* Implementation of grayscale convolutions. The code is similar to templated +* RGB versions above, the main difference is that only one channel value (gray) +* is processed per pixel. +*/ +class AknsRlEffectConvolutionGray + { + public: + //------------------------------------------------------------------------ + static void Kernel( const CFbsBitmap& aTarget, + const CFbsBitmap& aSource, + const TInt aKernel[9], + const TInt aBlendFactor, + const TInt aBias ) + { + TInt width = aTarget.SizeInPixels().iWidth; + TInt height = aTarget.SizeInPixels().iHeight; + // CFbsBitmap::ScanLineLength returns bytes + TInt scanWtarget = CFbsBitmap::ScanLineLength(aTarget.SizeInPixels().iWidth, aTarget.DisplayMode()); + TInt scanWsource = CFbsBitmap::ScanLineLength(aSource.SizeInPixels().iWidth, aSource.DisplayMode()); + + TInt kernelSum = aKernel[0] + aKernel[1] + aKernel[2] + + aKernel[3] + aKernel[4] + aKernel[5] + + aKernel[6] + aKernel[7] + aKernel[8]; + + if( 0 == kernelSum ) + kernelSum = 1; + + TInt shade; + TInt x, y; // Loop counters + + // Pitch is the number of pixels to skip before next scanline start + TInt pitchTarget = scanWtarget - width; + TInt pitchSource = scanWsource - width; + + // Prepare the data addresses + aTarget.LockHeap( ETrue ); // Lock the global bitmap heap + TUint8* dataT = reinterpret_cast( aTarget.DataAddress() ); + TUint8* dataS = reinterpret_cast( aSource.DataAddress() ); + + dataS = dataS + scanWsource + 1; + + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + { + shade = aBias + (*(dataS - scanWsource - 1) * aKernel[0] + + *(dataS - scanWsource ) * aKernel[1] + + *(dataS - scanWsource + 1) * aKernel[2] + + *(dataS - 1 ) * aKernel[3] + + *(dataS ) * aKernel[4] + + *(dataS + 1 ) * aKernel[5] + + *(dataS + scanWsource - 1) * aKernel[6] + + *(dataS + scanWsource ) * aKernel[7] + + *(dataS + scanWsource + 1) * aKernel[8]) / kernelSum; + + // Exposure blending. Note: It is assumed that arithmetic shifting + // is supported -> negative values are shifted correctly + shade = ( shade * aBlendFactor + (255 - aBlendFactor) * (*dataS) ) >> 8; //lint !e702 Arithmetic shifting assumed + + if( shade < 0 ) + *dataT = 0; + else if( shade > 255 ) + *dataT = 255; + else + *dataT = TUint8(shade); + + dataT++; + dataS++; + } + + dataT = dataT + pitchTarget; + dataS = dataS + pitchSource; + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + } + //------------------------------------------------------------------------ + /** + * "Convolutes" a bitmap with adjustable gaussian blur kernel. + * Kernel size from 3*3 to 33*33 (odd sizes). + */ + static void AdjustableGaussian( const CFbsBitmap& aTarget, + const CFbsBitmap& aSource, + TUint16* aColumnBuffer, + const TInt aKernelsize ) + { + TInt width = aTarget.SizeInPixels().iWidth; + TInt height = aTarget.SizeInPixels().iHeight; + // ScanLineLength returns bytes, but width must match the Type + TInt scanWtarget = (CFbsBitmap::ScanLineLength(aTarget.SizeInPixels().iWidth, aTarget.DisplayMode())); + TInt scanWsource = (CFbsBitmap::ScanLineLength(aSource.SizeInPixels().iWidth, aSource.DisplayMode())); + + TUint16 shade; + TInt x, y, i; // Loop counters + + // Pitch is the number of pixels to skip before next scanline start + TInt pitchTarget = scanWtarget - width; + TInt pitchSource = scanWsource - width; + + // Prepare the data addresses + aTarget.LockHeap( ETrue ); // Lock the global bitmap heap + TUint8* dataT = reinterpret_cast( aTarget.DataAddress() ); + TUint8* dataS = reinterpret_cast( aSource.DataAddress() ); + TUint8* dataR = dataT; // for recursive iterations, both source and target are the same + dataS = dataS + scanWsource + 1; // state machine takes pixel (1,1) and output goes to pixel (0,0) + + TUint16 tmp1; + TUint16 tmp2; + + // row buffer variables + TUint16 SR0; + TUint16 SR1; + + TInt col0_Index; // index for row 0 columns in aColumnBuffer + TInt col1_Index; // index for row 1 columns in aColumnBuffer + + for ( i = 0; i < (aKernelsize - 1) >> 1 ; i++ ) // do (N-1) / 2 times + { + + for( y = 0; y < (height - 1); y++ ) + { + SR0 = (TUint16)*dataS; // initialize row buffer variables + SR1 = (TUint16)*dataS; + col0_Index = 0; // initialize indexes for column buffers + col1_Index = width; + + for( x = 0; x < (width - 1); x++ ) + { + tmp1 = (TUint16)*dataS; + tmp2 = (TUint16)(SR0 + tmp1); + SR0 = tmp1; + tmp1 = (TUint16)(SR1 + tmp2); + SR1 = tmp2; + + tmp2 = (TUint16)(aColumnBuffer[col0_Index] + tmp1); + aColumnBuffer[col0_Index++] = tmp1; + shade = (TUint16)((8 + aColumnBuffer[col1_Index] + tmp2) >> 4); + aColumnBuffer[col1_Index++] = tmp2; + + if( shade > 255 ) shade = 255; + *dataT = (TUint8)shade; + + dataT++; + dataS++; + } + + dataT = dataT + pitchTarget + 1; + dataS = dataS + pitchSource + 1; + } + dataT = dataR; // for more than 1 iterations, use target bitmap for both + dataS = dataR+scanWtarget+1; // target and source + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + } + + //------------------------------------------------------------------------ + static void Mean( const CFbsBitmap& aTarget, + const CFbsBitmap& aSource, + TInt aBlendFactor ) + { + TInt width = aTarget.SizeInPixels().iWidth; + TInt height = aTarget.SizeInPixels().iHeight; + // CFbsBitmap::ScanLineLength returns bytes + TInt scanWtarget = CFbsBitmap::ScanLineLength(aTarget.SizeInPixels().iWidth, aTarget.DisplayMode()); + TInt scanWsource = CFbsBitmap::ScanLineLength(aSource.SizeInPixels().iWidth, aSource.DisplayMode()); + + TInt shade; + TInt x, y; // Loop counters + + // Pitch is the number of pixels to skip before next scanline start + TInt pitchTarget = scanWtarget - width; + TInt pitchSource = scanWsource - width; + + // Prepare the data addresses + aTarget.LockHeap( ETrue ); // Lock the global bitmap heap + TUint8* dataT = reinterpret_cast( aTarget.DataAddress() ); + TUint8* dataS = reinterpret_cast( aSource.DataAddress() ); + + // Convolute the inner rect + dataS = dataS + scanWsource + 1; + + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + { + shade = (*(dataS - scanWsource - 1) + + *(dataS - scanWsource ) + + *(dataS - scanWsource + 1) + + *(dataS - 1 ) + + *(dataS ) + + *(dataS + 1 ) + + *(dataS + scanWsource - 1) + + *(dataS + scanWsource ) + + *(dataS + scanWsource + 1)) / 9; + + // Exposure blending. Note: It is assumed that arithmetic shifting + // is supported -> negative values are shifted correctly + shade = ( shade * aBlendFactor + (255 - aBlendFactor) * (*dataS) ) >> 8; + + if( shade < 0 ) + *dataT = 0; + else if( shade > 255 ) + *dataT = 255; + else + *dataT = TUint8(shade); + + dataT++; + dataS++; + } + + dataT = dataT + pitchTarget; + dataS = dataS + pitchSource; + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + } + //------------------------------------------------------------------------ + /** + * Collects the shades on a 3x3 neighborhood to array. + */ + static void ExtractShades( TUint8 aShades[9], const TUint8* aPtr, TInt aScanW ) + { + aShades[0] = *(aPtr - aScanW - 1); // Top left + aShades[1] = *(aPtr - aScanW); // Top + aShades[2] = *(aPtr - aScanW + 1); // Top right + aShades[3] = *(aPtr - 1); // Left + aShades[4] = *(aPtr); // Center + aShades[5] = *(aPtr + 1); // Right + aShades[6] = *(aPtr + aScanW - 1); // Bottom left + aShades[7] = *(aPtr + aScanW); // Bottom + aShades[8] = *(aPtr + aScanW + 1); // Bottom right + } + //------------------------------------------------------------------------ + static void Median( const CFbsBitmap& aTarget, + const CFbsBitmap& aSource, + TInt aBlendFactor ) + { + TInt width = aTarget.SizeInPixels().iWidth; + TInt height = aTarget.SizeInPixels().iHeight; + // CFbsBitmap::ScanLineLength returns bytes + TInt scanWtarget = CFbsBitmap::ScanLineLength(aTarget.SizeInPixels().iWidth, aTarget.DisplayMode()); + TInt scanWsource = CFbsBitmap::ScanLineLength(aSource.SizeInPixels().iWidth, aSource.DisplayMode()); + + TInt shade; + TInt x, y; // Loop counters + TUint8 shades[9]; + + // Pitch is the number of pixels to skip before next scanline start + TInt pitchTarget = scanWtarget - width; + TInt pitchSource = scanWsource - width; + + // Prepare the data addresses + aTarget.LockHeap( ETrue ); // Lock the global bitmap heap + TUint8* dataT = reinterpret_cast( aTarget.DataAddress() ); + TUint8* dataS = reinterpret_cast( aSource.DataAddress() ); + + // Convolute the inner rect + dataS = dataS + scanWsource + 1; + + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + { + ExtractShades(shades, dataS, scanWsource); + + // Median + exposure blending. Note: It is assumed that arithmetic + // shifting is supported -> negative values are shifted correctly + shade = ( AknsRlUtil::Median9(shades) * aBlendFactor + (255 - aBlendFactor) * (*dataS) ) >> 8; + + if( shade < 0 ) + *dataT = 0; + else if( shade > 255 ) + *dataT = 255; + else + *dataT = TUint8(shade); + + dataT++; + dataS++; + } + + dataT = dataT + pitchTarget; + dataS = dataS + pitchSource; + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + } + //------------------------------------------------------------------------ + static void Max( const CFbsBitmap& aTarget, + const CFbsBitmap& aSource, + TInt aBlendFactor ) + { + TInt width = aTarget.SizeInPixels().iWidth; + TInt height = aTarget.SizeInPixels().iHeight; + // CFbsBitmap::ScanLineLength returns bytes + TInt scanWtarget = CFbsBitmap::ScanLineLength(aTarget.SizeInPixels().iWidth, aTarget.DisplayMode()); + TInt scanWsource = CFbsBitmap::ScanLineLength(aSource.SizeInPixels().iWidth, aSource.DisplayMode()); + + TInt shade; + TInt x, y; // Loop counters + + // Pitch is the number of pixels to skip before next scanline start + TInt pitchTarget = scanWtarget - width; + TInt pitchSource = scanWsource - width; + + // Prepare the data addresses + aTarget.LockHeap( ETrue ); // Lock the global bitmap heap + TUint8* dataT = reinterpret_cast( aTarget.DataAddress() ); + TUint8* dataS = reinterpret_cast( aSource.DataAddress() ); + + // Convolute the inner rect + dataS = dataS + scanWsource + 1; + + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + { + shade = *(dataS - scanWsource - 1 ); + shade = AknsRlUtil::Max( *(dataS - scanWsource ), shade ); + shade = AknsRlUtil::Max( *(dataS - scanWsource + 1), shade ); + shade = AknsRlUtil::Max( *(dataS - 1 ), shade ); + shade = AknsRlUtil::Max( *(dataS ), shade ); + shade = AknsRlUtil::Max( *(dataS + 1 ), shade ); + shade = AknsRlUtil::Max( *(dataS + scanWsource - 1), shade ); + shade = AknsRlUtil::Max( *(dataS + scanWsource ), shade ); + shade = AknsRlUtil::Max( *(dataS + scanWsource + 1), shade ); + + // Exposure blending. Note: It is assumed that arithmetic shifting + // is supported -> negative values are shifted correctly + shade = ( shade * aBlendFactor + (255 - aBlendFactor) * (*dataS) ) >> 8; + + if( shade < 0 ) + *dataT = 0; + else if( shade > 255 ) + *dataT = 255; + else + *dataT = TUint8(shade); + + dataT++; + dataS++; + } + + dataT = dataT + pitchTarget; + dataS = dataS + pitchSource; + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + } + //------------------------------------------------------------------------ + static void Min( const CFbsBitmap& aTarget, + const CFbsBitmap& aSource, + TInt aBlendFactor ) + { + TInt width = aTarget.SizeInPixels().iWidth; + TInt height = aTarget.SizeInPixels().iHeight; + // CFbsBitmap::ScanLineLength returns bytes + TInt scanWtarget = CFbsBitmap::ScanLineLength(aTarget.SizeInPixels().iWidth, aTarget.DisplayMode()); + TInt scanWsource = CFbsBitmap::ScanLineLength(aSource.SizeInPixels().iWidth, aSource.DisplayMode()); + + TInt shade; + TInt x, y; // Loop counters + + // Pitch is the number of pixels to skip before next scanline start + TInt pitchTarget = scanWtarget - width; + TInt pitchSource = scanWsource - width; + + // Prepare the data addresses + aTarget.LockHeap( ETrue ); // Lock the global bitmap heap + TUint8* dataT = reinterpret_cast( aTarget.DataAddress() ); + TUint8* dataS = reinterpret_cast( aSource.DataAddress() ); + + // Convolute the inner rect + dataS = dataS + scanWsource + 1; + + for( y = 0; y < height; y++ ) + { + for( x = 0; x < width; x++ ) + { + shade = *(dataS - scanWsource - 1 ); + shade = AknsRlUtil::Min( *(dataS - scanWsource ), shade ); + shade = AknsRlUtil::Min( *(dataS - scanWsource + 1), shade ); + shade = AknsRlUtil::Min( *(dataS - 1 ), shade ); + shade = AknsRlUtil::Min( *(dataS ), shade ); + shade = AknsRlUtil::Min( *(dataS + 1 ), shade ); + shade = AknsRlUtil::Min( *(dataS + scanWsource - 1), shade ); + shade = AknsRlUtil::Min( *(dataS + scanWsource ), shade ); + shade = AknsRlUtil::Min( *(dataS + scanWsource + 1), shade ); + + // Exposure blending. Note: It is assumed that arithmetic shifting + // is supported -> negative values are shifted correctly + shade = ( shade * aBlendFactor + (255 - aBlendFactor) * (*dataS) ) >> 8; //lint !e702 Arithmetic shifting assumed + + if( shade < 0 ) + *dataT = 0; + else if( shade > 255 ) + *dataT = 255; + else + *dataT = TUint8(shade); + + dataT++; + dataS++; + } + + dataT = dataT + pitchTarget; + dataS = dataS + pitchSource; + } + + aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap + } + }; // End of AknsRlEffectConvolutionGray + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CAknsRlEffectPluginConvolution::CAknsRlEffectPluginConvolution +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CAknsRlEffectPluginConvolution::CAknsRlEffectPluginConvolution() + { + } + +// ----------------------------------------------------------------------------- +// Destructor +// ----------------------------------------------------------------------------- +// +CAknsRlEffectPluginConvolution::~CAknsRlEffectPluginConvolution() + { + iContext = NULL; // Removes lint nag + iColumnBuffer = NULL; // Removes lint nag + } + +// ----------------------------------------------------------------------------- +// CAknsRlEffectPluginConvolution::EffectUid +// ----------------------------------------------------------------------------- +// +TUid CAknsRlEffectPluginConvolution::EffectUid() const + { + return TUid::Uid( KAknsRlEffectPluginConvolutionUID ); + } + +// ----------------------------------------------------------------------------- +// CAknsRlEffectPluginConvolution::Effect +// ----------------------------------------------------------------------------- +// +MAknsRlEffect* CAknsRlEffectPluginConvolution::Effect( const TInt aInterface ) + { + if( aInterface == KAknsRlEffectPluginInterfaceEffect ) + return this; + return NULL; + } + +// ----------------------------------------------------------------------------- +// CAknsRlEffectPluginConvolution::InitializeL +// ----------------------------------------------------------------------------- +// +void CAknsRlEffectPluginConvolution::InitializeL() + { + iContext = NULL; + } + +// ----------------------------------------------------------------------------- +// CAknsRlEffectPluginConvolution::Release +// ----------------------------------------------------------------------------- +// +void CAknsRlEffectPluginConvolution::Release() + { + } + +// ----------------------------------------------------------------------------- +// CAknsRlEffectPluginConvolution::ActivateL +// ----------------------------------------------------------------------------- +// +void CAknsRlEffectPluginConvolution::ActivateL( MAknsRlEffectContext* aContext ) + { + if( !aContext ) // We absolutely need the context + { + User::Leave( KErrArgument ); + } + + iContext = aContext; + + iMode = EModeEdge; + iBlendFactor = 255; + iGaussianBlurSize = 3; + } + +// ----------------------------------------------------------------------------- +// CAknsRlEffectPluginConvolution::Deactivate +// ----------------------------------------------------------------------------- +// +void CAknsRlEffectPluginConvolution::Deactivate() + { + } + +// ----------------------------------------------------------------------------- +// CAknsRlEffectPluginConvolution::SetParametersL +// ----------------------------------------------------------------------------- +// +void CAknsRlEffectPluginConvolution::SetParametersL( MAknsRlParameterIterator& aParameters ) + { + // Iterate over available parameters + while( aParameters.HasNext() ) + { + const TAknsRlParameterData* param = aParameters.NextL(); + + // Fetch mode value + if( param->iName->Compare( KAknsRlEffectConvolutionMode ) == 0 ) + { + if( param->iType != EAknsRlParameterTypeNumber ) + User::Leave( KErrArgument ); + + if( param->iNumber < EModeEdge || param->iNumber > EModeAdjustableGaussian ) + User::Leave( KErrArgument ); + + iMode = param->iNumber; + } + // Fetch blend factor value + else if( param->iName->Compare( KAknsRlEffectConvolutionBlendFactor ) == 0 ) + { + if( param->iType != EAknsRlParameterTypeNumber ) + User::Leave( KErrArgument ); + + iBlendFactor = param->iNumber; + } + // Fetch adjustable gaussian blur size + else if( param->iName->Compare( KAknsRlEffectConvolutionGaussianBlurSize ) == 0 ) + { + if( param->iType != EAknsRlParameterTypeNumber ) + User::Leave( KErrArgument ); + + // only odd sizes allowed + if ( param->iNumber < 3 || + param->iNumber > 55 || + !(param->iNumber&1) ) + User::Leave( KErrArgument ); + iGaussianBlurSize = param->iNumber; + } + } + } + +// ----------------------------------------------------------------------------- +// CAknsRlEffectPluginConvolution::GetCapabilities +// ----------------------------------------------------------------------------- +// +void CAknsRlEffectPluginConvolution::GetCapabilities( TAknsRlEffectCaps& aCaps ) + { + aCaps.iOutputLayerSupport = KAknsRlLayerRGBOnly; + aCaps.iInputLayerASupport = KAknsRlLayerRGBOnly; + aCaps.iInputLayerBSupport = KAknsRlLayerNone; + } + +// ----------------------------------------------------------------------------- +// CAknsRlEffectPluginConvolution::Render +// ----------------------------------------------------------------------------- +// +TInt CAknsRlEffectPluginConvolution::Render( const TAknsRlRenderOpParam& aParam ) + { + if( !iContext ) // We absolutely need the context + { + return KErrBadHandle; + } + + // To do anything we need both, the output layer and input layer + if( ( aParam.iOutputLayerStatus & KAknsRlLayerRGBOnly ) && + ( aParam.iInputLayerAStatus & KAknsRlLayerRGBOnly ) ) + { + // Query the layers, uninitialized because we process the whole image + TAknsRlLayerData dataTarget; + TRAPD( err, iContext->GetLayerDataL( dataTarget, aParam.iOutputLayerIndex, + aParam.iOutputLayerStatus, EFalse ) ); + if( KErrNone != err ) + return KErrArgument; + + TAknsRlLayerData dataSource; + TRAP( err, iContext->GetLayerDataL( dataSource, aParam.iInputLayerAIndex, + aParam.iInputLayerAStatus, EFalse ) ); + if( KErrNone != err ) + return KErrArgument; + + if( !dataTarget.iRGBBitmap ) // We need the target bitmap + return KErrBadHandle; + + if( !dataSource.iRGBBitmap ) // We need the source bitmap + return KErrBadHandle; + + CFbsBitmap& t = *(dataTarget.iRGBBitmap); + CFbsBitmap& s = *(dataSource.iRGBBitmap); + + TDisplayMode modeT = t.DisplayMode(); + TDisplayMode modeS = s.DisplayMode(); + + TInt sWidth = s.SizeInPixels().iWidth; + TInt sHeight = s.SizeInPixels().iHeight; + + // adjustable gaussian blur is a special case, which doesn't need + // temporary bitmap, so this must be handled before other convolution + // filters + if ( TMode( iMode ) == EModeAdjustableGaussian) + { + // first try to allocate space for row and column data buffers + + TInt rgbUsed = 3; + if( EGray256 == modeT && EGray256 == modeS ) + rgbUsed = 1; // no need for extra buffer for rgb components + + // 2 rows in sWidth columns, 3 times for rgb pictures + iColumnBuffer = new TUint16[2*sWidth*rgbUsed]; // OOM returns NULL + if ( !iColumnBuffer ) + return KErrNoMemory; + + for (int i=0; i<2*sWidth*rgbUsed ; i++) + iColumnBuffer[i] = 0; // empty buffer + + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::AdjustableGaussian( t, s, iColumnBuffer, iGaussianBlurSize ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::AdjustableGaussian( t, s, iColumnBuffer, iGaussianBlurSize ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::AdjustableGaussian( t, s, iColumnBuffer, iGaussianBlurSize ); + else + return KErrArgument; + + delete [] iColumnBuffer; + return KErrNone; + } + + + + // for convolution we need source bitmap that is 2 pixels wider and + // higher than target (because we need to convolute border pixels) + // this also removes the need to backup source pixels if source + // and target bitmaps are the same + CFbsBitmap* sNew = NULL; + sNew = new CFbsBitmap(); // OOM returns NULL + if( !sNew ) + return KErrNoMemory; + const CFbsBitmap& sTmp = *sNew; + + TInt bmpError = sNew->Create(TSize(sWidth+2,sHeight+2),modeS); + if (bmpError != KErrNone) // if there was some error in creating new bitmap + { + delete sNew; + return bmpError; + } + + // CFbsBitmap::ScanLineLength returns bytes + TInt originalSourceScanW = CFbsBitmap::ScanLineLength( + s.SizeInPixels().iWidth, + s.DisplayMode()); + TInt convoSourceScanW = CFbsBitmap::ScanLineLength( + sTmp.SizeInPixels().iWidth, + sTmp.DisplayMode()); + + // Prepare the data addresses + s.LockHeap( ETrue ); // Lock the global bitmap heap + TUint* originalSourceAddr = reinterpret_cast( s.DataAddress() ); + TUint* convoSourceAddr = reinterpret_cast( sTmp.DataAddress() ); + + switch( modeS ) + { + case EColor64K: + { + AMakeConvoluteSource64K(convoSourceAddr, + originalSourceAddr, + convoSourceScanW, + originalSourceScanW, + sWidth, + sHeight); + s.UnlockHeap( ETrue ); // Unlock the global bitmap heap + break; + } + case EColor16MU: + { + AMakeConvoluteSource16MU(convoSourceAddr, + originalSourceAddr, + convoSourceScanW, + originalSourceScanW, + sWidth, + sHeight); + s.UnlockHeap( ETrue ); // Unlock the global bitmap heap + break; + } + case EGray256: + { + AMakeConvoluteSource256(convoSourceAddr, + originalSourceAddr, + convoSourceScanW, + originalSourceScanW, + sWidth, + sHeight); + s.UnlockHeap( ETrue ); // Unlock the global bitmap heap + break; + } + default: + { + s.UnlockHeap( ETrue ); // Unlock the global bitmap heap + return KErrArgument; + } + } + + +#if !defined(ARM_VERSION) // separate switch-case for WINS and ARMI versions + switch( TMode( iMode ) ) + { + // Convolution kernel modes + case EModeEdge: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEdgeDetect, iBlendFactor, 0 ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEdgeDetect, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelEdgeDetect, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeBlur: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelBlur, iBlendFactor, 0 ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelBlur, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelBlur, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeBlurGauss: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelBlurGauss, iBlendFactor, 0 ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelBlurGauss, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelBlurGauss, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeEmbossSoft: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEmbossSoft, iBlendFactor, 127 ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEmbossSoft, iBlendFactor, 127 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelEmbossSoft, iBlendFactor, 127 ); + else + return KErrArgument; + } + break; + case EModeEmbossHard: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEmbossHard, iBlendFactor, 127 ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEmbossHard, iBlendFactor, 127 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelEmbossHard, iBlendFactor, 127 ); + else + return KErrArgument; + } + break; + case EModeEnhanceDetail: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEnhanceDetail, iBlendFactor, 0 ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEnhanceDetail, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelEnhanceDetail, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeEnhanceFocus: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEnhanceFocus, iBlendFactor, 0 ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEnhanceFocus, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelEnhanceFocus, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeSoften: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelSoften, iBlendFactor, 0 ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelSoften, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelSoften, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeSharpen: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelSharpen, iBlendFactor, 0 ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelSharpen, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelSharpen, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeSharpenMore: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelSharpenMore, iBlendFactor, 0 ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelSharpenMore, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelSharpenMore, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + + // Convolution filter modes + case EModeMean: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Mean( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Mean( t, sTmp, iBlendFactor ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Mean( t, sTmp, iBlendFactor ); + else + return KErrArgument; + } + break; + case EModeMedian: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Median( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Median( t, sTmp, iBlendFactor ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Median( t, sTmp, iBlendFactor ); + else + return KErrArgument; + } + break; + case EModeDilate: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Max( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Max( t, sTmp, iBlendFactor ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Max( t, sTmp, iBlendFactor ); + else + return KErrArgument; + } + break; + case EModeErode: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Min( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Min( t, sTmp, iBlendFactor ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Min( t, sTmp, iBlendFactor ); + else + return KErrArgument; + } + break; + + default: + return KErrArgument; + } +#else // ASM versions for hardware + switch( TMode( iMode ) ) + { + // Convolution kernel modes + case EModeEdge: + { + if( EColor64K == modeT && EColor64K == modeS ) + AConvolute64KEdge( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEdgeDetect, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelEdgeDetect, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeBlur: + { + if( EColor64K == modeT && EColor64K == modeS ) + AConvolute64KBlur( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelBlur, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelBlur, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeBlurGauss: + { + if( EColor64K == modeT && EColor64K == modeS ) + AConvolute64KBlurGauss( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelBlurGauss, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelBlurGauss, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeEmbossSoft: + { + if( EColor64K == modeT && EColor64K == modeS ) + AConvolute64KEmbossSoft( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEmbossSoft, iBlendFactor, 127 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelEmbossSoft, iBlendFactor, 127 ); + else + return KErrArgument; + } + break; + case EModeEmbossHard: + { + if( EColor64K == modeT && EColor64K == modeS ) + AConvolute64KEmbossHard( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEmbossHard, iBlendFactor, 127 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelEmbossHard, iBlendFactor, 127 ); + else + return KErrArgument; + } + break; + case EModeEnhanceDetail: + { + if( EColor64K == modeT && EColor64K == modeS ) + AConvolute64KEnhanceDetail( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEnhanceDetail, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelEnhanceDetail, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeEnhanceFocus: + { + if( EColor64K == modeT && EColor64K == modeS ) + AConvolute64KEnhanceFocus( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelEnhanceFocus, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelEnhanceFocus, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeSoften: + { + if( EColor64K == modeT && EColor64K == modeS ) + AConvolute64KSoften( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelSoften, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelSoften, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeSharpen: + { + if( EColor64K == modeT && EColor64K == modeS ) + AConvolute64KSharpen( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelSharpen, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelSharpen, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + case EModeSharpenMore: + { + if( EColor64K == modeT && EColor64K == modeS ) + AConvolute64KSharpenMore( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Kernel( t, sTmp, KKernelSharpenMore, iBlendFactor, 0 ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Kernel( t, sTmp, KKernelSharpenMore, iBlendFactor, 0 ); + else + return KErrArgument; + } + break; + + // Convolution filter modes + case EModeMean: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Mean( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Mean( t, sTmp, iBlendFactor ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Mean( t, sTmp, iBlendFactor ); + else + return KErrArgument; + } + break; + case EModeMedian: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Median( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Median( t, sTmp, iBlendFactor ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Median( t, sTmp, iBlendFactor ); + else + return KErrArgument; + } + break; + case EModeDilate: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Max( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Max( t, sTmp, iBlendFactor ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Max( t, sTmp, iBlendFactor ); + else + return KErrArgument; + } + break; + case EModeErode: + { + if( EColor64K == modeT && EColor64K == modeS ) + AknsRlEffectConvolution::Min( t, sTmp, iBlendFactor ); + else if( EColor16MU == modeT && EColor16MU == modeS ) + AknsRlEffectConvolution::Min( t, sTmp, iBlendFactor ); + else if( EGray256 == modeT && EGray256 == modeS ) + AknsRlEffectConvolutionGray::Min( t, sTmp, iBlendFactor ); + else + return KErrArgument; + } + break; + + default: + return KErrArgument; + } + +#endif // !__MARM_ARMI__ + + delete sNew; + } + else + { + // Required layers were not provided + return KErrArgument; + } + + return KErrNone; + } + +/*lint -restore */ + +// End of File