diff -r 41a7f70b3818 -r 5266b1f337bd phoneuis/BubbleManager/Src/BMCallObjectUtils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phoneuis/BubbleManager/Src/BMCallObjectUtils.cpp Wed Sep 01 12:30:10 2010 +0100 @@ -0,0 +1,532 @@ +/* +* Copyright (c) 2002-2006 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: Utility methods for call object handling. +* +*/ + + + +// INCLUDE FILES +#include "BMCallObjectUtils.h" +#include "BMLayout2.h" +#include "BMUtils.h" +#include "BMPanic.h" +#include +#include +#include + +// CONSTANTS +const TReal KBMCallObjectScaleFactorMax = 1.0; +_LIT( KSpaceChar, " " ); + + +// ============================ MEMBER FUNCTIONS =============================== + +// --------------------------------------------------------------------------- +// BubbleCallObjectUtils::CreateBitmapL +// +// --------------------------------------------------------------------------- +// +CFbsBitmap* BubbleCallObjectUtils::CreateBitmapL( + const CFbsBitmap* aBitmap, + const TSize& aTargetSize, + TDisplayMode aDisplayMode, + TTileMode aTileMode ) + { + __ASSERT_ALWAYS( aBitmap, User::Leave( KErrArgument ) ); + + // get scaling factor + TReal scalingFactor = ScalingFactor( aBitmap->SizeInPixels(), + aTargetSize, + EFillTarget ); + + if ( scalingFactor > 1.0 ) // bitmap scaling not supported + { + // image smaller than target area is tiled + return CreateTiledBitmapL( aBitmap, + aTargetSize, + aDisplayMode, + aTileMode ); + } + else + { + // image bigger than target area is clipped + return CreateCroppedBitmapL( aBitmap, + aTargetSize, + aDisplayMode ); + } + } + +// --------------------------------------------------------------------------- +// BubbleCallObjectUtils::CreateCroppedBitmapL +// +// --------------------------------------------------------------------------- +// +CFbsBitmap* BubbleCallObjectUtils::CreateCroppedBitmapL( + const CFbsBitmap* aBitmap, + const TSize& aTargetSize, + TDisplayMode aDisplayMode ) + { + __ASSERT_ALWAYS( aBitmap, User::Leave( KErrArgument ) ); + + // create bitmap + CFbsBitmap* bitmap = new(ELeave) CFbsBitmap; + CleanupStack::PushL( bitmap ); + + // calculate cropping rectangle + TSize sourceBitmapSize( aBitmap->SizeInPixels() ); + TRect croppingRect( TPoint(0,0), sourceBitmapSize ); + + TInt xDelta( sourceBitmapSize.iWidth - aTargetSize.iWidth ); + if ( xDelta < 0 ) + { + // do not crop horizontally + xDelta = 0; + } + + TInt yDelta( sourceBitmapSize.iHeight - aTargetSize.iHeight ); + if ( yDelta < 0 ) + { + // do not crop vertically + yDelta = 0; + } + + if ( xDelta == 0 && yDelta == 0 ) + { + // cropping not required -> just duplicate + User::LeaveIfError( bitmap->Duplicate( aBitmap->Handle() ) ); + CleanupStack::Pop( bitmap ); + return bitmap; + } + else + { + // shrink to cropping area + croppingRect.Shrink( xDelta/2, yDelta/2 ); + } + + + // create bitmap to target size + User::LeaveIfError( bitmap->Create( aTargetSize, + aDisplayMode ) ); + // crop + CFbsBitmapDevice* bitmapDev = + CFbsBitmapDevice::NewL( bitmap ); + CleanupStack::PushL( bitmapDev ); + CFbsBitGc* bitmapCtx; + User::LeaveIfError( bitmapDev->CreateContext( bitmapCtx ) ); + CleanupStack::PushL( bitmapCtx ); + TRect targetRect( TPoint(0,0), aTargetSize ); + bitmapCtx->DrawBitmap( targetRect, aBitmap, croppingRect ); + + CleanupStack::PopAndDestroy( 2, bitmapDev ); + CleanupStack::Pop( bitmap ); + + return bitmap; + } + +// --------------------------------------------------------------------------- +// BubbleCallObjectUtils::CreateTiledBitmapL +// +// --------------------------------------------------------------------------- +// +CFbsBitmap* BubbleCallObjectUtils::CreateTiledBitmapL( + const CFbsBitmap* aBitmap, + const TSize& aTargetSize, + TDisplayMode aDisplayMode, + TTileMode aTileMode ) + { + __ASSERT_ALWAYS( aBitmap, User::Leave( KErrArgument ) ); + + TSize sourceSize = aBitmap->SizeInPixels(); + TPoint offset(0,0); + + // calculate offset for brush origin + + // horizontal offset + if ( aTargetSize.iWidth <= sourceSize.iWidth ) + { + // wide image -> center horizontally + offset.iX = ( sourceSize.iWidth - aTargetSize.iWidth ) / 2; + } + else if ( ( aTileMode == ETileCenterRight ) || + ( aTileMode == ETileTopRight ) ) + { + // begin tiling from right + offset.iX = sourceSize.iWidth - ( aTargetSize.iWidth % + sourceSize.iWidth ); + } + + // vertical offset + if ( aTargetSize.iHeight <= sourceSize.iHeight ) + { + // tall image -> center vertically + offset.iY = ( sourceSize.iHeight - aTargetSize.iHeight ) / 2; + } + else if ( ( aTileMode == ETileCenterRight ) || + ( aTileMode == ETileCenterLeft ) ) + { + // middle most tile is centered vertically + TInt topMargin = ( aTargetSize.iHeight - sourceSize.iHeight ) / 2; + if ( topMargin <= sourceSize.iHeight ) + { + offset.iY = ( sourceSize.iHeight - topMargin ); + } + else + { + offset.iY = sourceSize.iHeight - ( topMargin % + sourceSize.iHeight ); + } + } + + // create bitmap to target size + CFbsBitmap* bitmap = new(ELeave) CFbsBitmap; + CleanupStack::PushL( bitmap ); + User::LeaveIfError( bitmap->Create( aTargetSize, + aDisplayMode ) ); + + // create device and graphics context + CFbsBitmapDevice* bitmapDev = CFbsBitmapDevice::NewL( bitmap ); + CleanupStack::PushL( bitmapDev ); + CFbsBitGc* bitmapCtx; + User::LeaveIfError( bitmapDev->CreateContext( bitmapCtx ) ); + CleanupStack::PushL( bitmapCtx ); + + // do tiling by using patterned brush + CFbsBitmap* pattern = new(ELeave) CFbsBitmap; + CleanupStack::PushL( pattern ); + User::LeaveIfError( pattern->Duplicate( aBitmap->Handle() ) ); + + TRect bitmapRect( TPoint(0,0), aTargetSize ); + bitmapCtx->SetPenStyle( CGraphicsContext::ENullPen ); + bitmapCtx->SetBrushStyle( CGraphicsContext::EPatternedBrush ); + bitmapCtx->UseBrushPattern( pattern ); + bitmapCtx->SetBrushOrigin( -offset ); + bitmapCtx->DrawRect( bitmapRect ); + bitmapCtx->DiscardBrushPattern(); + + CleanupStack::PopAndDestroy( 3, bitmapDev ); + CleanupStack::Pop( bitmap ); + + return bitmap; + } + +// --------------------------------------------------------------------------- +// BubbleCallObjectUtils::CreateImageBitmapsFromTextLC +// +// --------------------------------------------------------------------------- +// +void BubbleCallObjectUtils::CreateImageBitmapsFromTextLC( + const TDesC& aText, + const TRect& aMainPaneRect, + const TSize& aSize, + const TRgb& aTextColor, + TUint aAlpha, + TDisplayMode aDisplayMode, + CFbsBitmap*& aBitmap, + CFbsBitmap*& aMask ) + { + // create bitmap + aBitmap= new(ELeave) CFbsBitmap; + CleanupStack::PushL( aBitmap ); + User::LeaveIfError( aBitmap->Create( aSize, aDisplayMode ) ); + + // create mask + aMask = new(ELeave) CFbsBitmap; + CleanupStack::PushL( aMask ); + User::LeaveIfError( aMask->Create( aSize, EGray256 ) ); + + // create bitmap context + CFbsBitmapDevice* bitmapDev = CFbsBitmapDevice::NewL( aBitmap ); + CleanupStack::PushL( bitmapDev ); + CFbsBitGc* bitmapGc; + User::LeaveIfError( bitmapDev->CreateContext( bitmapGc ) ); + CleanupStack::PushL( bitmapGc ); + + // create mask context + CFbsBitmapDevice* maskDev = CFbsBitmapDevice::NewL( aMask ); + CleanupStack::PushL( maskDev ); + CFbsBitGc* maskGc; + User::LeaveIfError( maskDev->CreateContext( maskGc ) ); + CleanupStack::PushL( maskGc ); + + // initialize bitmap + bitmapGc->SetBrushStyle( CGraphicsContext::ESolidBrush ); + bitmapGc->SetPenStyle( CGraphicsContext::ENullPen ); + bitmapGc->SetBrushColor( KRgbWhite ); + bitmapGc->DrawRect( TRect( aSize ) ); + bitmapGc->SetPenStyle( CGraphicsContext::ESolidPen ); + bitmapGc->SetBrushStyle( CGraphicsContext::ENullBrush ); + // initialize mask + maskGc->SetBrushStyle( CGraphicsContext::ESolidBrush ); + maskGc->SetPenStyle( CGraphicsContext::ENullPen ); + maskGc->SetBrushColor( KRgbBlack ); + maskGc->DrawRect( TRect( aSize ) ); + maskGc->SetPenStyle( CGraphicsContext::ESolidPen ); + maskGc->SetBrushStyle( CGraphicsContext::ENullBrush ); + + // reserve text buffers + TAknLayoutRect textPaneLayout; + textPaneLayout.LayoutRect( aMainPaneRect, + BubbleLayout2::call2_cli_visual_text_pane() ); + TRect textPaneRect = textPaneLayout.Rect(); + + TAknLayoutText textLayout; + textLayout.LayoutText( textPaneRect, + BubbleLayout2::call2_main_pane_text( 0 ) ); + const CFont* font = textLayout.Font(); + TInt lineWidth = textLayout.TextRect().Size().iWidth; + TInt averageFontWidth( font->WidthZeroInPixels() ); + + TInt maxCharsPerLine( lineWidth / averageFontWidth ); + maxCharsPerLine = maxCharsPerLine * 4; // to secure + HBufC* logicalLineBuf = HBufC::NewL( maxCharsPerLine ); + CleanupStack::PushL( logicalLineBuf ); + HBufC* visualLineBuf = HBufC::NewL( maxCharsPerLine + + KAknBidiExtraSpacePerLine ); + CleanupStack::PushL( visualLineBuf ); + TPtr logicalLine( logicalLineBuf->Des() ); + TPtr visualLine( visualLineBuf->Des() ); + + TRgb alphaColor( aAlpha, aAlpha, aAlpha ); + TInt currentRow = 0; + TInt i = 0; + TInt textLength = aText.Length(); + const TInt numberOfRows = + BubbleLayout2::call2_cli_visual_text_number_of_rows(); + + // shift gc origin + TPoint offset( (aMainPaneRect.Size().iWidth - aSize.iWidth) / 2, + (aMainPaneRect.Size().iHeight - aSize.iHeight) / 2 ); + bitmapGc->SetOrigin( -offset ); + maskGc->SetOrigin( -offset ); + + // render text + while ( currentRow <= numberOfRows ) + { + TAknLayoutText textLayout; + textLayout.LayoutText( textPaneRect, + BubbleLayout2::call2_main_pane_text( currentRow ) ); + + TRect textRect = textLayout.TextRect(); + if ( ( textRect.iBr.iY < offset.iY ) || + ( textRect.iTl.iY > ( offset.iY + aSize.iHeight ) ) ) + { + // this line is outside the bitmap. + currentRow++; + continue; + } + + logicalLine.Zero(); + TBool clipped( EFalse ); + do // Find the clipping point + { + TChar c( aText[i] ); + if( logicalLine.Length() == maxCharsPerLine ) + { + User::Leave( KErrOverflow ); + } + logicalLine.Append( c ); + i++; + if ( i == textLength ) + { + if( logicalLine.Length() == maxCharsPerLine ) + { + User::Leave( KErrOverflow ); + } + // start over to fill whole pane + i = 0; + logicalLine.Append( KSpaceChar ); + } + + visualLine.Zero(); + clipped = AknBidiTextUtils::ConvertToVisualAndClip( + logicalLine, + visualLine, + *font, + lineWidth, + lineWidth, + AknBidiTextUtils::EImplicit, + 0xFFFF ); + + } while ( !clipped ); + + // Remove the last character that caused clipping + if ( logicalLine.Length() ) + { + logicalLine.SetLength( logicalLine.Length() - 1 ); + } + + AknBidiTextUtils::ConvertToVisualAndClip( + logicalLine, + visualLine, + *font, + lineWidth, + lineWidth, + AknBidiTextUtils::EImplicit, + 0xFFFF ); + + textLayout.DrawText( *bitmapGc, visualLine, EFalse, aTextColor ); + textLayout.DrawText( *maskGc, visualLine, EFalse, alphaColor ); + + // clipped -> go back by one + i = i > 0 ? (i - 1) : (textLength-1); + + currentRow++; + } + + CleanupStack::PopAndDestroy(6, bitmapDev); + } + +// --------------------------------------------------------------------------- +// BubbleCallObjectUtils::ScalingFactor +// +// --------------------------------------------------------------------------- +// +TReal BubbleCallObjectUtils::ScalingFactor( + const TSize& aSourceSize, + const TSize& aTargetSize, + TScaleMode aScaleMode ) + { + if ( aTargetSize == TSize(0,0) || aSourceSize == TSize(0,0) ) + { + return 0; + } + + // check aspect ratios + TReal targetAspectRatio = (TReal) aTargetSize.iWidth / + (TReal) aTargetSize.iHeight; + TReal sourceAspectRatio = (TReal) aSourceSize.iWidth / + (TReal) aSourceSize.iHeight; + TReal scaleFactor = 1.0; + + + if ( sourceAspectRatio == targetAspectRatio ) + { + // aspect ratios are same. + return (TReal) aTargetSize.iWidth / (TReal) aSourceSize.iWidth; + } + else if ( targetAspectRatio > sourceAspectRatio ) + { + // target wide more screen than source. + if ( aScaleMode == EFillTarget ) + { + // width defines the scale + scaleFactor = (TReal) aTargetSize.iWidth / + (TReal) aSourceSize.iWidth; + } + else // EMaximumFit + { + // height defines the scale + scaleFactor = (TReal) aTargetSize.iHeight / + (TReal) aSourceSize.iHeight; + } + } + else + { + // video is more wide screen than window. + if ( aScaleMode == EFillTarget ) + { + // height defines the scale + scaleFactor = (TReal) aTargetSize.iHeight / + (TReal) aSourceSize.iHeight; + } + else // EMaximumFit + { + // width defines the scale + scaleFactor = (TReal) aTargetSize.iWidth / + (TReal) aSourceSize.iWidth; + } + } + + return scaleFactor; + } + +// --------------------------------------------------------------------------- +// BubbleCallObjectUtils::GetScaleFactorAndClipRect +// +// --------------------------------------------------------------------------- +// +TBool BubbleCallObjectUtils::GetScaleFactorAndClipRect( + const TSize& aSourceSize, + const TSize& aTargetSize, + TScaleMode aScaleMode, + TReal& aScaleFactor, + TRect& aClipRect ) + { + TBool isTinyImage( EFalse ); + + // scaling to fit main pane + TReal scaleFactor = BubbleCallObjectUtils::ScalingFactor( + aSourceSize, + aTargetSize, + aScaleMode ); + + // set clipping rect + TRect clipRect; + + if ( aScaleMode == EMaximumFit ) + { + aScaleFactor = scaleFactor > KBMCallObjectScaleFactorMax ? + KBMCallObjectScaleFactorMax : scaleFactor; + aClipRect = TRect( aSourceSize ); // no clip + } + else if ( scaleFactor == 0 ) + { + aScaleFactor = scaleFactor; + aClipRect = TRect( aSourceSize ); + } + else if ( scaleFactor > KBMCallObjectScaleFactorMax ) + { + isTinyImage = ETrue; + aScaleFactor = KBMCallObjectScaleFactorMax; + TInt x_offset = 0; + if ( aSourceSize.iWidth > aTargetSize.iWidth ) + { + // center horizontally + x_offset = + ( aSourceSize.iWidth - aTargetSize.iWidth ) / 4; + } + TInt y_offset = 0; + if ( aSourceSize.iHeight > aTargetSize.iHeight ) + { + // center vertically + y_offset = + ( aSourceSize.iHeight - aTargetSize.iHeight ) / 4; + } + + aClipRect = TRect( aSourceSize ); + aClipRect.Shrink( x_offset, y_offset ); + } + else // 0 < scaleFactor < KBMCallObjectScaleFactorMax + { + aScaleFactor = scaleFactor; + TSize relativeTargetSize; + relativeTargetSize.iWidth = aTargetSize.iWidth / scaleFactor; + relativeTargetSize.iHeight = aTargetSize.iHeight / scaleFactor; + TInt x_offset = ( aSourceSize.iWidth - + relativeTargetSize.iWidth ) / 2; + TInt y_offset = ( aSourceSize.iHeight - + relativeTargetSize.iHeight ) / 2; + aClipRect = TRect( relativeTargetSize ); + if ( x_offset >= 0 && y_offset >= 0 ) + { + // clip from center of the source image + aClipRect.Move( x_offset, y_offset ); + } + } + + return isTinyImage; + } + +// End of File