diff -r 000000000000 -r 05e9090e2422 uigraphics/AknIcon/srvsrc/AknIconSrvUtils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uigraphics/AknIcon/srvsrc/AknIconSrvUtils.cpp Thu Dec 17 09:14:12 2009 +0200 @@ -0,0 +1,641 @@ +/* +* Copyright (c) 2002 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 class AknIconSrvUtils. +* +*/ + + + +// INCLUDE FILES + +#include +#include +#include +#include + +#include "AknIconSrvUtils.h" +#include "AknIconFormatHandler.h" +#include "AknIconLoader.h" +#include "AknIconSrv.h" +#include "AknIconFormatHandlerFactory.h" +#include "AknIconSrvDef.h" + +#include "AknBitmap.h" +// CONSTANTS + +// ================= MEMBER FUNCTIONS ========================================== + +TPtrC8 AknIconSrvUtils::InitIconDataAndHandlerLC( + CAknIconLoader* aLoader, + RPointerArray& aHandlerList, + MAknIconFormatHandler*& aHandler, + const TAknIconParams& aParams, + TBool aAnimated ) + { + CleanupStack::PushL( TCleanupItem( CleanupFreeIcon, aLoader ) ); + + if ( aLoader->IconAnimatedL( aParams.iBitmapId ) && !aAnimated ) + { + User::Leave( KAknIconSrvCodeAnimated ); + } + + TInt type = aLoader->IconTypeL( aParams.iBitmapId ); + +#ifdef _NGATESTING + type = aLoader->GetDerivedIconTypeL(type, aParams.iFileName); +#endif + + // Check if handler is already present, if so then return with same pointer + for ( TInt lIndex = 0; lIndex < aHandlerList.Count(); lIndex++ ) + { + if ( aHandlerList[ lIndex ]->IconFormatType() == type ) + { + aHandler = aHandlerList[ lIndex ]; + break; + } + } + + // No Handler found, create one and add to list + if ( !aHandler ) + { + aHandler = AknIconFormatHandlerFactory::NewIconFormatHandlerL( type ); + aHandlerList.Append( aHandler ); + aHandler->SetAnimated( aAnimated ); + } + + return aLoader->IconL( aParams.iBitmapId ); + } + +TPtrC8 AknIconSrvUtils::InitIconDataAndHandlerLC( + CAknIconLoader* aLoader, + MAknIconFormatHandler*& aHandler, + TInt aIconId, + TBool aAnimated ) + { + CleanupStack::PushL( TCleanupItem( CleanupFreeIcon, aLoader ) ); + + if ( aLoader->IconAnimatedL( aIconId ) && !aAnimated ) + { + User::Leave( KAknIconSrvCodeAnimated ); + } + + TInt type = aLoader->IconTypeL( aIconId ); + + if ( !aHandler ) + { + aHandler = AknIconFormatHandlerFactory::NewIconFormatHandlerL( type ); + aHandler->SetAnimated( aAnimated ); + } + + return aLoader->IconL( aIconId ); + } + +// ----------------------------------------------------------------------------- +// AknIconSrvUtils::RenderPreparedIconL +// ----------------------------------------------------------------------------- +// +TAknContentDimensions AknIconSrvUtils::RenderPreparedIconL( + MAknIconFormatHandler& aHandler, + CFbsBitmap* aBitmap, + CFbsBitmap* aMask, // may be NULL + TDisplayMode aBitmapDepth, + TDisplayMode aPreferredDepth, + const TSize& aSize, + TScaleMode aMode, + TInt aRotationAngle, + TRgb aColor, + TInt /*aBitmapId*/, + TInt /*aMaskId*/, + TBool isAppIcon) + { + TSize resultSize( aSize ); + CAknBitmap* aknIcon = CAknBitmap::DynamicCast(aBitmap); + + TAknContentDimensions dimensions; + TBool dimensionsRetrieved = EFalse; + + if ( aMode == EAspectRatioPreservedAndUnusedSpaceRemoved ) + { + if ( !resultSize.iWidth || !resultSize.iHeight ) + { + resultSize.iWidth = 0; + resultSize.iHeight = 0; + } + else + { + aHandler.GetContentDimensionsL( dimensions ); + dimensionsRetrieved = ETrue; + GetAspectRatioPreservedSize( dimensions, resultSize ); + } + } + + TDisplayMode definedDepth = aBitmapDepth; + // Change display mode to the closest one supported by the engine. + aHandler.SupportedDisplayMode( aBitmapDepth, aPreferredDepth ); + + CFbsBitmap* renderBitmap = aBitmap; + + // If EGray256 mode was defined, and the engine did not support it, + // render the icon first in a temporary bitmap. + + if ( definedDepth == EGray256 && definedDepth != aBitmapDepth ) + { + renderBitmap = new( ELeave ) CFbsBitmap; + CleanupStack::PushL( renderBitmap ); + } + + User::LeaveIfError( renderBitmap->Create( resultSize, aBitmapDepth ) ); + if ( aMask ) + { + // Always use soft masks with SVGs. + User::LeaveIfError( aMask->Create( resultSize, EGray256 ) ); + } + + aHandler.SetScaleMode( aMode ); + aHandler.SetRotation( aRotationAngle ); + aknIcon = CAknBitmap::DynamicCast(aBitmap); + aHandler.RenderPreparedIconL(renderBitmap, aMask ,resultSize, aBitmapDepth, EGray256,aColor, isAppIcon); + + // Copy from temp. render bitmap to real bitmap, + // and convert display depth to EGray256. + if ( renderBitmap != aBitmap ) + { + User::LeaveIfError( aBitmap->Create( resultSize, EGray256 ) ); + + CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL( aBitmap ); + CleanupStack::PushL( dev ); + CFbsBitGc* gc = NULL; + User::LeaveIfError( dev->CreateContext( gc ) ); + CleanupStack::PushL( gc ); + + gc->BitBlt( TPoint( 0, 0 ), renderBitmap ); + + CleanupStack::PopAndDestroy( 3 ); // renderBitmap, dev, gc + } + + if ( !dimensionsRetrieved ) + { + aHandler.GetContentDimensionsL( dimensions ); + } + + return dimensions; + } + +// ----------------------------------------------------------------------------- +// AknIconSrvUtils::GetAspectRatioPreservedSize +// ----------------------------------------------------------------------------- +// +void AknIconSrvUtils::GetAspectRatioPreservedSize( + const TAknContentDimensions& aDimensions, + TSize& aSize ) + { + if ( !aDimensions.iWidth || !aDimensions.iHeight ) + { + aSize.iWidth = 0; + aSize.iHeight = 0; + } + else + { + if ( aSize.iWidth > KMaxTInt16 ) + { + aSize.iWidth = KMaxTInt16; + } + if ( aSize.iHeight > KMaxTInt16 ) + { + aSize.iHeight = KMaxTInt16; + } + + TReal32 xScaleFactor = (TReal32)(aSize.iWidth) / aDimensions.iWidth; + TReal32 yScaleFactor = (TReal32)(aSize.iHeight) / aDimensions.iHeight; + + if ( xScaleFactor > yScaleFactor ) + { + TReal32 width = aDimensions.iWidth * yScaleFactor; + aSize.iWidth = width; + if ( width - aSize.iWidth > 0 ) //rounding + { + aSize.iWidth++; + } + } + else + { + TReal32 height = aDimensions.iHeight * xScaleFactor; + aSize.iHeight = height; + if ( height - aSize.iHeight > 0 ) //rounding + { + aSize.iHeight++; + } + } + } + } + +// ----------------------------------------------------------------------------- +// AknIconSrvUtils::GetAspectRatioPreservedSize +// ----------------------------------------------------------------------------- +// +void AknIconSrvUtils::GetAspectRatioPreservedSize( + const TSize& aDimensions, + TSize& aSize, + TBool aFitToOriginalSize ) + { + if ( !aDimensions.iWidth || !aDimensions.iHeight ) + { + aSize.iWidth = 0; + aSize.iHeight = 0; + } + else + { + if ( aSize.iWidth > KMaxTInt16 ) + { + aSize.iWidth = KMaxTInt16; + } + if ( aSize.iHeight > KMaxTInt16 ) + { + aSize.iHeight = KMaxTInt16; + } + + TInt xScaleFactor = (aSize.iWidth << 16) / aDimensions.iWidth; + TInt yScaleFactor = (aSize.iHeight << 16) / aDimensions.iHeight; + + + TBool chooseWidthScaling = (xScaleFactor > yScaleFactor); + + if (!aFitToOriginalSize) + { + chooseWidthScaling = !chooseWidthScaling; + } + + if ( chooseWidthScaling ) + { + aSize.iWidth = aDimensions.iWidth * yScaleFactor; + TBool rounding = aSize.iWidth & 0x8000; + + aSize.iWidth >>= 16; + if ( rounding ) + { + aSize.iWidth++; + } + } + else + { + aSize.iHeight = aDimensions.iHeight * xScaleFactor; + TBool rounding = aSize.iHeight & 0x8000; + + aSize.iHeight >>= 16; + if ( rounding ) + { + aSize.iHeight++; + } + } + } + } + +// ----------------------------------------------------------------------------- +// AknIconSrvUtils::ScaleBitmapIconL +// ----------------------------------------------------------------------------- +// +TBool AknIconSrvUtils::ScaleBitmapIconL( + const TSize& aSize, + const TScaleMode aMode, + const TInt aAngle, + const TRgb aColor, + CFbsBitmap* aSourceBitmap, + CFbsBitmap* aSourceMask, + CFbsBitmap* aTargetBitmap, + CFbsBitmap* aTargetMask ) + { + TSize scaledSize( aSize ); + TSize originalSize(aSourceBitmap->SizeInPixels()); + TBool colorIcon = aColor != KColorNotDefined; + + // Find out the scaled size according to the given scale mode. + // Note:In scaling mode EAspectRatioPreservedSlice no need to calculate scaledSize for color icons. + if ( aMode != EAspectRatioNotPreserved && (aMode != EAspectRatioPreservedSlice || !colorIcon)) + { + AknIconSrvUtils::GetAspectRatioPreservedSize( originalSize, scaledSize, aMode != EAspectRatioPreservedSlice ); + } + + const TSize& bitmapSize = + aMode == EAspectRatioPreservedAndUnusedSpaceRemoved ? + scaledSize : aSize; + + TDisplayMode colorDepth = colorIcon ? + EColor64K : aSourceBitmap->DisplayMode(); + + User::LeaveIfError( aTargetBitmap->Create( bitmapSize, colorDepth ) ); + + // Icon should be centered, so calculate x and y margins. + TInt xMargin = ( bitmapSize.iWidth - scaledSize.iWidth ) / 2; + TInt yMargin = ( bitmapSize.iHeight - scaledSize.iHeight ) / 2; + + // Target rect inside the target bitmap. + TRect targetRect( xMargin, yMargin, + xMargin + scaledSize.iWidth, yMargin + scaledSize.iHeight ); + + // Decide if fallback should be forced in ScaleBitmapExtL calls + TBool forceFallBack = EFalse; + if ( !colorIcon && aSourceBitmap && !aAngle ) + { + forceFallBack = AknIconUtils::DoesScaleBitmapUseFallBack( aSourceBitmap ); + } + if ( aSourceMask && aTargetMask && !aAngle ) + { + forceFallBack = forceFallBack || AknIconUtils::DoesScaleBitmapUseFallBack( aSourceMask ); + } + + // If color icon, just fill the bitmap with the defined color. + if ( colorIcon ) + { + CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL( aTargetBitmap ); + CleanupStack::PushL( dev ); + CFbsBitGc* gc = NULL; + User::LeaveIfError( dev->CreateContext( gc ) ); + CleanupStack::PushL( gc ); + + gc->SetBrushColor( aColor ); + gc->SetPenStyle( CGraphicsContext::ENullPen ); + gc->SetBrushStyle( CGraphicsContext::ESolidBrush ); + // Fill icon with the given color, mask defines the icon shape. + gc->DrawRect( TRect( TPoint( 0, 0 ), bitmapSize ) ); + + CleanupStack::PopAndDestroy( 2 ); // dev, gc + } + + // Otherwise, perform bitmap scaling and rotation as required. + else + { + if ( !aAngle ) + { + AknIconUtils::ScaleBitmapExtL( targetRect, aTargetBitmap, aSourceBitmap, forceFallBack ); + } + else + { + AknIconUtils::RotateAndScaleBitmapL( + targetRect, + aTargetBitmap, + aSourceBitmap, + aAngle ); + } + } + + // Optional mask is always scaled and rotated as required. + if ( aSourceMask && aTargetMask) + { + User::LeaveIfError(aTargetMask->Create( bitmapSize, aSourceMask->DisplayMode() ) ); + + + // If target mode is EAspectRatioPreserved, there may be unused parts + // in the bitmap, so need to initialize soft masks black before scaling. + if ( aMode == EAspectRatioPreserved && aTargetMask->DisplayMode() == EGray256 ) + { + CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL( aTargetMask ); + CleanupStack::PushL( dev ); + CFbsBitGc* gc = NULL; + User::LeaveIfError( dev->CreateContext( gc ) ); + CleanupStack::PushL( gc ); + gc->SetBrushColor( KRgbBlack ); + gc->SetBrushStyle( CGraphicsContext::ESolidBrush ); + gc->Clear(); + CleanupStack::PopAndDestroy(2); // dev, gc + } + + if ( !aAngle ) + { + AknIconUtils::ScaleBitmapExtL( targetRect, aTargetMask, aSourceMask, forceFallBack ); + } + else + { + AknIconUtils::RotateAndScaleBitmapL( + targetRect, + aTargetMask, + aSourceMask, + aAngle ); + } + } + + return colorIcon; + } + + +LOCAL_C TInt CheckTransparency(const CFbsBitmap* aBmp, TDes8& aBuffer, TInt aMask, TDisplayMode aMode) + { + // Note: The following calculations use the below notation. + // + // Ha = Actual height of the bitmap + // hTa = Height of the transparent region at the bottom of the bitmap + // hNT = Height of the non-transparent region in the bitmap + // Therefore, Ha = hNT + 2 * hTa + // + // hNTN = New height of the non-transparent region after accomodating + // for the 12% transparent margins(bottom) + // HaN = New needed height of the bitmap to adjust the transparent area + // at the bottom to 12% + // R = Ratio of hNTN / hNT + // C = 2 * hTa + // HaN = Ha * R - C * R + C + // + // This means that if the transparent margins are already 12% then + // R becomes 1 in the above equation and it reduces to + // HaN = Ha + // If R becomes > 1 i.e. hNTN > hNT, then it would be clipped to 1. + const TSize& sz = aBmp->SizeInPixels(); + const TInt lValidMargin = sz.iHeight * 12 / 100; + + const TInt Ha = sz.iHeight; + TInt hTa = 0; + TInt hNT = 0; + TInt C = 0; + TInt hNTN = Ha - 2.0 * 0.12 * Ha; + TReal R = 1.0; + TInt HaN = Ha; + + switch(aMode) + { + case EGray256: // for mask + { + const TInt lastColumn = sz.iWidth - 1; + const TUint8* ptr8 = reinterpret_cast (aBuffer.Ptr()); + for ( TInt curRow = 0; curRow < lValidMargin; curRow++ ) + { + const TInt y = (sz.iHeight - 1) - curRow; // h - 1 is the last line + aBmp->GetScanLine(aBuffer, TPoint(0, y), sz.iWidth, aMode); + for ( TInt s = lastColumn; s >= 0; --s ) + { + TUint8 lPixel = aBuffer[s]; + if ( aBuffer[s] & (TUint8)aMask ) //note that mask is inverted + { + hTa = curRow; + hNT = Ha - 2 * hTa; + C = 2 * hTa; + R = ( ( (TReal)hNTN / (TReal)hNT ) > 1.0 ) ? 1 : (TReal)hNTN / (TReal)hNT; + HaN = Ha * R - C * R + C; + // HaN =( 0.88 * Ha) + hTa; + return( HaN ); + } + } + } + } + + break; + case EColor16MA: + { + const TInt lastColumn = aBuffer.MaxLength() / sizeof(TUint32) - 1; + const TUint32* ptr = reinterpret_cast (aBuffer.Ptr()); + for ( TInt curRow = 0; curRow < lValidMargin; curRow++ ) + { + const TInt y = (sz.iHeight - 1) - curRow; // h - 1 is the last line + aBmp->GetScanLine(aBuffer, TPoint(0, y), sz.iWidth, aMode); + for ( TInt s = lastColumn; s >= 0; --s ) + { + if ( ptr[s] & aMask ) //note that mask is inverted + { + hTa = curRow; + hNT = Ha - 2 * hTa; + C = 2 * hTa; + R = ( ( (TReal)hNTN / (TReal)hNT ) > 1.0 ) ? 1 : (TReal)hNTN / (TReal)hNT; + HaN = Ha * R - C * R + C; + // HaN =( 0.88 * Ha) + hTa; + return( HaN ); + } + } + } + + } + break; + default: + break; + + } + + return HaN; + } + + +TInt AknIconSrvUtils::CheckMaskTransparencyL(const CFbsBitmap* aBmp) + { + const TSize& sz = aBmp->SizeInPixels(); + HBufC8* buffer = HBufC8::NewLC(sz.iWidth); + TPtr8 ptr = buffer->Des(); + const TInt h = CheckTransparency(aBmp, ptr, 0xFF, EGray256); + CleanupStack::PopAndDestroy(); + return h; + } + +TInt AknIconSrvUtils::CheckAlphaTransparencyL(const CFbsBitmap* aBmp) + { + const TSize& sz = aBmp->SizeInPixels(); + HBufC8* buffer = HBufC8::NewLC(sz.iWidth * sizeof(TUint32)); + TPtr8 ptr = buffer->Des(); + const TInt h = CheckTransparency(aBmp, ptr, 0xFF000000, EColor16MA); + CleanupStack::PopAndDestroy(); + return h; + } + +LOCAL_C void ScaleL(const TRect& aRect, CFbsBitmap* aBmp, TUint32 aFillColor, TBool aForceFb) + { + CFbsBitmap* bmp = new (ELeave) CFbsBitmap(); + CleanupStack::PushL(bmp); + User::LeaveIfError(bmp->Create(aRect.Size(), aBmp->DisplayMode())); + AknIconUtils::ScaleBitmapExtL( + TRect(TPoint(0, 0), aRect.Size()), + bmp, + aBmp, + aForceFb); + + + CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(aBmp); + CleanupStack::PushL(dev); + CFbsBitGc* con = NULL; + dev->CreateContext(con); + CleanupStack::PushL(con); + con->SetBrushColor( 0 ); + con->Clear(); + con->SetPenStyle(CGraphicsContext::ESolidPen); + con->SetBrushStyle(CGraphicsContext::ESolidBrush); + con->SetPenColor(aFillColor); + con->SetBrushColor(aFillColor); + const TSize sz = aBmp->SizeInPixels(); + con->DrawRect(TRect(TPoint(0, 0), aBmp->SizeInPixels())); + con->BitBlt(aRect.iTl, bmp); + CleanupStack::PopAndDestroy(3); + } + + + + +void AknIconSrvUtils::EnsureValidSizeL( CFbsBitmap* aBitmap, CFbsBitmap* aMask ) + { + if ( aBitmap == NULL ) + return; + CFbsBitmap* iBitmap = aBitmap; + CFbsBitmap* iMask = NULL; + if ( aMask ) + { + iMask = aMask; + } + TInt validHeight; + if(iMask != NULL) + { + SEpocBitmapHeader lBmpHeaderMask = iMask->Header(); + if ( lBmpHeaderMask.iBitsPerPixel != 8 ) + { + return; + } + validHeight = CheckMaskTransparencyL(iMask); + } + else + { + SEpocBitmapHeader lBmpHeaderBitmap = iBitmap->Header(); + if ( lBmpHeaderBitmap.iBitsPerPixel != 32 ) + { + return; + } + validHeight = CheckAlphaTransparencyL(iBitmap); + } + + const TSize& size = iBitmap->SizeInPixels(); + + if(validHeight == size.iHeight) + return; + + const TInt KOffSet = 16; + + //scale image down, leaving margins on sides + //then using fixed point math to get width + const TInt hmul = (validHeight << KOffSet) / size.iHeight; + const TInt validWidth = (size.iWidth * hmul + (1 << (KOffSet - 1))) >> KOffSet; // sz * mul + 0.5 + const TSize sz(validWidth, validHeight); + + //centrify it + TRect rect(TPoint((size.iWidth - sz.iWidth) >> 1, (size.iHeight - sz.iHeight) >> 1), sz); + + //it look better if even when centrified + rect.iTl.iX &= ~1; + rect.iBr.iX |= 1; + + TBool forceFb = + AknIconUtils::DoesScaleBitmapUseFallBack( iBitmap ); + + if(iMask != NULL) + { + forceFb = forceFb || AknIconUtils::DoesScaleBitmapUseFallBack( iMask ); + const TUint32 maskBytes = iMask->DisplayMode() != EGray256 ? 0xFFFFFFFFF : 0x0; + ::ScaleL(rect, iMask, maskBytes, forceFb); + } + + ::ScaleL(rect, iBitmap, 0xFF000000, forceFb); + + } + +// End of File