|
1 /* |
|
2 * Copyright (c) 2002-2006 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Utility methods for call object handling. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 // INCLUDE FILES |
|
21 #include "BMCallObjectUtils.h" |
|
22 #include "BMLayout2.h" |
|
23 #include "BMUtils.h" |
|
24 #include "BMPanic.h" |
|
25 #include <AknUtils.h> |
|
26 #include <AknBidiTextUtils.h> |
|
27 #include <AknLayoutFont.h> |
|
28 |
|
29 // CONSTANTS |
|
30 const TReal KBMCallObjectScaleFactorMax = 1.0; |
|
31 _LIT( KSpaceChar, " " ); |
|
32 |
|
33 |
|
34 // ============================ MEMBER FUNCTIONS =============================== |
|
35 |
|
36 // --------------------------------------------------------------------------- |
|
37 // BubbleCallObjectUtils::CreateBitmapL |
|
38 // |
|
39 // --------------------------------------------------------------------------- |
|
40 // |
|
41 CFbsBitmap* BubbleCallObjectUtils::CreateBitmapL( |
|
42 const CFbsBitmap* aBitmap, |
|
43 const TSize& aTargetSize, |
|
44 TDisplayMode aDisplayMode, |
|
45 TTileMode aTileMode ) |
|
46 { |
|
47 __ASSERT_ALWAYS( aBitmap, User::Leave( KErrArgument ) ); |
|
48 |
|
49 // get scaling factor |
|
50 TReal scalingFactor = ScalingFactor( aBitmap->SizeInPixels(), |
|
51 aTargetSize, |
|
52 EFillTarget ); |
|
53 |
|
54 if ( scalingFactor > 1.0 ) // bitmap scaling not supported |
|
55 { |
|
56 // image smaller than target area is tiled |
|
57 return CreateTiledBitmapL( aBitmap, |
|
58 aTargetSize, |
|
59 aDisplayMode, |
|
60 aTileMode ); |
|
61 } |
|
62 else |
|
63 { |
|
64 // image bigger than target area is clipped |
|
65 return CreateCroppedBitmapL( aBitmap, |
|
66 aTargetSize, |
|
67 aDisplayMode ); |
|
68 } |
|
69 } |
|
70 |
|
71 // --------------------------------------------------------------------------- |
|
72 // BubbleCallObjectUtils::CreateCroppedBitmapL |
|
73 // |
|
74 // --------------------------------------------------------------------------- |
|
75 // |
|
76 CFbsBitmap* BubbleCallObjectUtils::CreateCroppedBitmapL( |
|
77 const CFbsBitmap* aBitmap, |
|
78 const TSize& aTargetSize, |
|
79 TDisplayMode aDisplayMode ) |
|
80 { |
|
81 __ASSERT_ALWAYS( aBitmap, User::Leave( KErrArgument ) ); |
|
82 |
|
83 // create bitmap |
|
84 CFbsBitmap* bitmap = new(ELeave) CFbsBitmap; |
|
85 CleanupStack::PushL( bitmap ); |
|
86 |
|
87 // calculate cropping rectangle |
|
88 TSize sourceBitmapSize( aBitmap->SizeInPixels() ); |
|
89 TRect croppingRect( TPoint(0,0), sourceBitmapSize ); |
|
90 |
|
91 TInt xDelta( sourceBitmapSize.iWidth - aTargetSize.iWidth ); |
|
92 if ( xDelta < 0 ) |
|
93 { |
|
94 // do not crop horizontally |
|
95 xDelta = 0; |
|
96 } |
|
97 |
|
98 TInt yDelta( sourceBitmapSize.iHeight - aTargetSize.iHeight ); |
|
99 if ( yDelta < 0 ) |
|
100 { |
|
101 // do not crop vertically |
|
102 yDelta = 0; |
|
103 } |
|
104 |
|
105 if ( xDelta == 0 && yDelta == 0 ) |
|
106 { |
|
107 // cropping not required -> just duplicate |
|
108 User::LeaveIfError( bitmap->Duplicate( aBitmap->Handle() ) ); |
|
109 CleanupStack::Pop( bitmap ); |
|
110 return bitmap; |
|
111 } |
|
112 else |
|
113 { |
|
114 // shrink to cropping area |
|
115 croppingRect.Shrink( xDelta/2, yDelta/2 ); |
|
116 } |
|
117 |
|
118 |
|
119 // create bitmap to target size |
|
120 User::LeaveIfError( bitmap->Create( aTargetSize, |
|
121 aDisplayMode ) ); |
|
122 // crop |
|
123 CFbsBitmapDevice* bitmapDev = |
|
124 CFbsBitmapDevice::NewL( bitmap ); |
|
125 CleanupStack::PushL( bitmapDev ); |
|
126 CFbsBitGc* bitmapCtx; |
|
127 User::LeaveIfError( bitmapDev->CreateContext( bitmapCtx ) ); |
|
128 CleanupStack::PushL( bitmapCtx ); |
|
129 TRect targetRect( TPoint(0,0), aTargetSize ); |
|
130 bitmapCtx->DrawBitmap( targetRect, aBitmap, croppingRect ); |
|
131 |
|
132 CleanupStack::PopAndDestroy( 2, bitmapDev ); |
|
133 CleanupStack::Pop( bitmap ); |
|
134 |
|
135 return bitmap; |
|
136 } |
|
137 |
|
138 // --------------------------------------------------------------------------- |
|
139 // BubbleCallObjectUtils::CreateTiledBitmapL |
|
140 // |
|
141 // --------------------------------------------------------------------------- |
|
142 // |
|
143 CFbsBitmap* BubbleCallObjectUtils::CreateTiledBitmapL( |
|
144 const CFbsBitmap* aBitmap, |
|
145 const TSize& aTargetSize, |
|
146 TDisplayMode aDisplayMode, |
|
147 TTileMode aTileMode ) |
|
148 { |
|
149 __ASSERT_ALWAYS( aBitmap, User::Leave( KErrArgument ) ); |
|
150 |
|
151 TSize sourceSize = aBitmap->SizeInPixels(); |
|
152 TPoint offset(0,0); |
|
153 |
|
154 // calculate offset for brush origin |
|
155 |
|
156 // horizontal offset |
|
157 if ( aTargetSize.iWidth <= sourceSize.iWidth ) |
|
158 { |
|
159 // wide image -> center horizontally |
|
160 offset.iX = ( sourceSize.iWidth - aTargetSize.iWidth ) / 2; |
|
161 } |
|
162 else if ( ( aTileMode == ETileCenterRight ) || |
|
163 ( aTileMode == ETileTopRight ) ) |
|
164 { |
|
165 // begin tiling from right |
|
166 offset.iX = sourceSize.iWidth - ( aTargetSize.iWidth % |
|
167 sourceSize.iWidth ); |
|
168 } |
|
169 |
|
170 // vertical offset |
|
171 if ( aTargetSize.iHeight <= sourceSize.iHeight ) |
|
172 { |
|
173 // tall image -> center vertically |
|
174 offset.iY = ( sourceSize.iHeight - aTargetSize.iHeight ) / 2; |
|
175 } |
|
176 else if ( ( aTileMode == ETileCenterRight ) || |
|
177 ( aTileMode == ETileCenterLeft ) ) |
|
178 { |
|
179 // middle most tile is centered vertically |
|
180 TInt topMargin = ( aTargetSize.iHeight - sourceSize.iHeight ) / 2; |
|
181 if ( topMargin <= sourceSize.iHeight ) |
|
182 { |
|
183 offset.iY = ( sourceSize.iHeight - topMargin ); |
|
184 } |
|
185 else |
|
186 { |
|
187 offset.iY = sourceSize.iHeight - ( topMargin % |
|
188 sourceSize.iHeight ); |
|
189 } |
|
190 } |
|
191 |
|
192 // create bitmap to target size |
|
193 CFbsBitmap* bitmap = new(ELeave) CFbsBitmap; |
|
194 CleanupStack::PushL( bitmap ); |
|
195 User::LeaveIfError( bitmap->Create( aTargetSize, |
|
196 aDisplayMode ) ); |
|
197 |
|
198 // create device and graphics context |
|
199 CFbsBitmapDevice* bitmapDev = CFbsBitmapDevice::NewL( bitmap ); |
|
200 CleanupStack::PushL( bitmapDev ); |
|
201 CFbsBitGc* bitmapCtx; |
|
202 User::LeaveIfError( bitmapDev->CreateContext( bitmapCtx ) ); |
|
203 CleanupStack::PushL( bitmapCtx ); |
|
204 |
|
205 // do tiling by using patterned brush |
|
206 CFbsBitmap* pattern = new(ELeave) CFbsBitmap; |
|
207 CleanupStack::PushL( pattern ); |
|
208 User::LeaveIfError( pattern->Duplicate( aBitmap->Handle() ) ); |
|
209 |
|
210 TRect bitmapRect( TPoint(0,0), aTargetSize ); |
|
211 bitmapCtx->SetPenStyle( CGraphicsContext::ENullPen ); |
|
212 bitmapCtx->SetBrushStyle( CGraphicsContext::EPatternedBrush ); |
|
213 bitmapCtx->UseBrushPattern( pattern ); |
|
214 bitmapCtx->SetBrushOrigin( -offset ); |
|
215 bitmapCtx->DrawRect( bitmapRect ); |
|
216 bitmapCtx->DiscardBrushPattern(); |
|
217 |
|
218 CleanupStack::PopAndDestroy( 3, bitmapDev ); |
|
219 CleanupStack::Pop( bitmap ); |
|
220 |
|
221 return bitmap; |
|
222 } |
|
223 |
|
224 // --------------------------------------------------------------------------- |
|
225 // BubbleCallObjectUtils::CreateImageBitmapsFromTextLC |
|
226 // |
|
227 // --------------------------------------------------------------------------- |
|
228 // |
|
229 void BubbleCallObjectUtils::CreateImageBitmapsFromTextLC( |
|
230 const TDesC& aText, |
|
231 const TRect& aMainPaneRect, |
|
232 const TSize& aSize, |
|
233 const TRgb& aTextColor, |
|
234 TUint aAlpha, |
|
235 TDisplayMode aDisplayMode, |
|
236 CFbsBitmap*& aBitmap, |
|
237 CFbsBitmap*& aMask ) |
|
238 { |
|
239 // create bitmap |
|
240 aBitmap= new(ELeave) CFbsBitmap; |
|
241 CleanupStack::PushL( aBitmap ); |
|
242 User::LeaveIfError( aBitmap->Create( aSize, aDisplayMode ) ); |
|
243 |
|
244 // create mask |
|
245 aMask = new(ELeave) CFbsBitmap; |
|
246 CleanupStack::PushL( aMask ); |
|
247 User::LeaveIfError( aMask->Create( aSize, EGray256 ) ); |
|
248 |
|
249 // create bitmap context |
|
250 CFbsBitmapDevice* bitmapDev = CFbsBitmapDevice::NewL( aBitmap ); |
|
251 CleanupStack::PushL( bitmapDev ); |
|
252 CFbsBitGc* bitmapGc; |
|
253 User::LeaveIfError( bitmapDev->CreateContext( bitmapGc ) ); |
|
254 CleanupStack::PushL( bitmapGc ); |
|
255 |
|
256 // create mask context |
|
257 CFbsBitmapDevice* maskDev = CFbsBitmapDevice::NewL( aMask ); |
|
258 CleanupStack::PushL( maskDev ); |
|
259 CFbsBitGc* maskGc; |
|
260 User::LeaveIfError( maskDev->CreateContext( maskGc ) ); |
|
261 CleanupStack::PushL( maskGc ); |
|
262 |
|
263 // initialize bitmap |
|
264 bitmapGc->SetBrushStyle( CGraphicsContext::ESolidBrush ); |
|
265 bitmapGc->SetPenStyle( CGraphicsContext::ENullPen ); |
|
266 bitmapGc->SetBrushColor( KRgbWhite ); |
|
267 bitmapGc->DrawRect( TRect( aSize ) ); |
|
268 bitmapGc->SetPenStyle( CGraphicsContext::ESolidPen ); |
|
269 bitmapGc->SetBrushStyle( CGraphicsContext::ENullBrush ); |
|
270 // initialize mask |
|
271 maskGc->SetBrushStyle( CGraphicsContext::ESolidBrush ); |
|
272 maskGc->SetPenStyle( CGraphicsContext::ENullPen ); |
|
273 maskGc->SetBrushColor( KRgbBlack ); |
|
274 maskGc->DrawRect( TRect( aSize ) ); |
|
275 maskGc->SetPenStyle( CGraphicsContext::ESolidPen ); |
|
276 maskGc->SetBrushStyle( CGraphicsContext::ENullBrush ); |
|
277 |
|
278 // reserve text buffers |
|
279 TAknLayoutRect textPaneLayout; |
|
280 textPaneLayout.LayoutRect( aMainPaneRect, |
|
281 BubbleLayout2::call2_cli_visual_text_pane() ); |
|
282 TRect textPaneRect = textPaneLayout.Rect(); |
|
283 |
|
284 TAknLayoutText textLayout; |
|
285 textLayout.LayoutText( textPaneRect, |
|
286 BubbleLayout2::call2_main_pane_text( 0 ) ); |
|
287 const CFont* font = textLayout.Font(); |
|
288 TInt lineWidth = textLayout.TextRect().Size().iWidth; |
|
289 TInt averageFontWidth( font->WidthZeroInPixels() ); |
|
290 |
|
291 TInt maxCharsPerLine( lineWidth / averageFontWidth ); |
|
292 maxCharsPerLine = maxCharsPerLine * 4; // to secure |
|
293 HBufC* logicalLineBuf = HBufC::NewL( maxCharsPerLine ); |
|
294 CleanupStack::PushL( logicalLineBuf ); |
|
295 HBufC* visualLineBuf = HBufC::NewL( maxCharsPerLine + |
|
296 KAknBidiExtraSpacePerLine ); |
|
297 CleanupStack::PushL( visualLineBuf ); |
|
298 TPtr logicalLine( logicalLineBuf->Des() ); |
|
299 TPtr visualLine( visualLineBuf->Des() ); |
|
300 |
|
301 TRgb alphaColor( aAlpha, aAlpha, aAlpha ); |
|
302 TInt currentRow = 0; |
|
303 TInt i = 0; |
|
304 TInt textLength = aText.Length(); |
|
305 const TInt numberOfRows = |
|
306 BubbleLayout2::call2_cli_visual_text_number_of_rows(); |
|
307 |
|
308 // shift gc origin |
|
309 TPoint offset( (aMainPaneRect.Size().iWidth - aSize.iWidth) / 2, |
|
310 (aMainPaneRect.Size().iHeight - aSize.iHeight) / 2 ); |
|
311 bitmapGc->SetOrigin( -offset ); |
|
312 maskGc->SetOrigin( -offset ); |
|
313 |
|
314 // render text |
|
315 while ( currentRow <= numberOfRows ) |
|
316 { |
|
317 TAknLayoutText textLayout; |
|
318 textLayout.LayoutText( textPaneRect, |
|
319 BubbleLayout2::call2_main_pane_text( currentRow ) ); |
|
320 |
|
321 TRect textRect = textLayout.TextRect(); |
|
322 if ( ( textRect.iBr.iY < offset.iY ) || |
|
323 ( textRect.iTl.iY > ( offset.iY + aSize.iHeight ) ) ) |
|
324 { |
|
325 // this line is outside the bitmap. |
|
326 currentRow++; |
|
327 continue; |
|
328 } |
|
329 |
|
330 logicalLine.Zero(); |
|
331 TBool clipped( EFalse ); |
|
332 do // Find the clipping point |
|
333 { |
|
334 TChar c( aText[i] ); |
|
335 if( logicalLine.Length() == maxCharsPerLine ) |
|
336 { |
|
337 User::Leave( KErrOverflow ); |
|
338 } |
|
339 logicalLine.Append( c ); |
|
340 i++; |
|
341 if ( i == textLength ) |
|
342 { |
|
343 if( logicalLine.Length() == maxCharsPerLine ) |
|
344 { |
|
345 User::Leave( KErrOverflow ); |
|
346 } |
|
347 // start over to fill whole pane |
|
348 i = 0; |
|
349 logicalLine.Append( KSpaceChar ); |
|
350 } |
|
351 |
|
352 visualLine.Zero(); |
|
353 clipped = AknBidiTextUtils::ConvertToVisualAndClip( |
|
354 logicalLine, |
|
355 visualLine, |
|
356 *font, |
|
357 lineWidth, |
|
358 lineWidth, |
|
359 AknBidiTextUtils::EImplicit, |
|
360 0xFFFF ); |
|
361 |
|
362 } while ( !clipped ); |
|
363 |
|
364 // Remove the last character that caused clipping |
|
365 if ( logicalLine.Length() ) |
|
366 { |
|
367 logicalLine.SetLength( logicalLine.Length() - 1 ); |
|
368 } |
|
369 |
|
370 AknBidiTextUtils::ConvertToVisualAndClip( |
|
371 logicalLine, |
|
372 visualLine, |
|
373 *font, |
|
374 lineWidth, |
|
375 lineWidth, |
|
376 AknBidiTextUtils::EImplicit, |
|
377 0xFFFF ); |
|
378 |
|
379 textLayout.DrawText( *bitmapGc, visualLine, EFalse, aTextColor ); |
|
380 textLayout.DrawText( *maskGc, visualLine, EFalse, alphaColor ); |
|
381 |
|
382 // clipped -> go back by one |
|
383 i = i > 0 ? (i - 1) : (textLength-1); |
|
384 |
|
385 currentRow++; |
|
386 } |
|
387 |
|
388 CleanupStack::PopAndDestroy(6, bitmapDev); |
|
389 } |
|
390 |
|
391 // --------------------------------------------------------------------------- |
|
392 // BubbleCallObjectUtils::ScalingFactor |
|
393 // |
|
394 // --------------------------------------------------------------------------- |
|
395 // |
|
396 TReal BubbleCallObjectUtils::ScalingFactor( |
|
397 const TSize& aSourceSize, |
|
398 const TSize& aTargetSize, |
|
399 TScaleMode aScaleMode ) |
|
400 { |
|
401 if ( aTargetSize == TSize(0,0) || aSourceSize == TSize(0,0) ) |
|
402 { |
|
403 return 0; |
|
404 } |
|
405 |
|
406 // check aspect ratios |
|
407 TReal targetAspectRatio = (TReal) aTargetSize.iWidth / |
|
408 (TReal) aTargetSize.iHeight; |
|
409 TReal sourceAspectRatio = (TReal) aSourceSize.iWidth / |
|
410 (TReal) aSourceSize.iHeight; |
|
411 TReal scaleFactor = 1.0; |
|
412 |
|
413 |
|
414 if ( sourceAspectRatio == targetAspectRatio ) |
|
415 { |
|
416 // aspect ratios are same. |
|
417 return (TReal) aTargetSize.iWidth / (TReal) aSourceSize.iWidth; |
|
418 } |
|
419 else if ( targetAspectRatio > sourceAspectRatio ) |
|
420 { |
|
421 // target wide more screen than source. |
|
422 if ( aScaleMode == EFillTarget ) |
|
423 { |
|
424 // width defines the scale |
|
425 scaleFactor = (TReal) aTargetSize.iWidth / |
|
426 (TReal) aSourceSize.iWidth; |
|
427 } |
|
428 else // EMaximumFit |
|
429 { |
|
430 // height defines the scale |
|
431 scaleFactor = (TReal) aTargetSize.iHeight / |
|
432 (TReal) aSourceSize.iHeight; |
|
433 } |
|
434 } |
|
435 else |
|
436 { |
|
437 // video is more wide screen than window. |
|
438 if ( aScaleMode == EFillTarget ) |
|
439 { |
|
440 // height defines the scale |
|
441 scaleFactor = (TReal) aTargetSize.iHeight / |
|
442 (TReal) aSourceSize.iHeight; |
|
443 } |
|
444 else // EMaximumFit |
|
445 { |
|
446 // width defines the scale |
|
447 scaleFactor = (TReal) aTargetSize.iWidth / |
|
448 (TReal) aSourceSize.iWidth; |
|
449 } |
|
450 } |
|
451 |
|
452 return scaleFactor; |
|
453 } |
|
454 |
|
455 // --------------------------------------------------------------------------- |
|
456 // BubbleCallObjectUtils::GetScaleFactorAndClipRect |
|
457 // |
|
458 // --------------------------------------------------------------------------- |
|
459 // |
|
460 TBool BubbleCallObjectUtils::GetScaleFactorAndClipRect( |
|
461 const TSize& aSourceSize, |
|
462 const TSize& aTargetSize, |
|
463 TScaleMode aScaleMode, |
|
464 TReal& aScaleFactor, |
|
465 TRect& aClipRect ) |
|
466 { |
|
467 TBool isTinyImage( EFalse ); |
|
468 |
|
469 // scaling to fit main pane |
|
470 TReal scaleFactor = BubbleCallObjectUtils::ScalingFactor( |
|
471 aSourceSize, |
|
472 aTargetSize, |
|
473 aScaleMode ); |
|
474 |
|
475 // set clipping rect |
|
476 TRect clipRect; |
|
477 |
|
478 if ( aScaleMode == EMaximumFit ) |
|
479 { |
|
480 aScaleFactor = scaleFactor > KBMCallObjectScaleFactorMax ? |
|
481 KBMCallObjectScaleFactorMax : scaleFactor; |
|
482 aClipRect = TRect( aSourceSize ); // no clip |
|
483 } |
|
484 else if ( scaleFactor == 0 ) |
|
485 { |
|
486 aScaleFactor = scaleFactor; |
|
487 aClipRect = TRect( aSourceSize ); |
|
488 } |
|
489 else if ( scaleFactor > KBMCallObjectScaleFactorMax ) |
|
490 { |
|
491 isTinyImage = ETrue; |
|
492 aScaleFactor = KBMCallObjectScaleFactorMax; |
|
493 TInt x_offset = 0; |
|
494 if ( aSourceSize.iWidth > aTargetSize.iWidth ) |
|
495 { |
|
496 // center horizontally |
|
497 x_offset = |
|
498 ( aSourceSize.iWidth - aTargetSize.iWidth ) / 4; |
|
499 } |
|
500 TInt y_offset = 0; |
|
501 if ( aSourceSize.iHeight > aTargetSize.iHeight ) |
|
502 { |
|
503 // center vertically |
|
504 y_offset = |
|
505 ( aSourceSize.iHeight - aTargetSize.iHeight ) / 4; |
|
506 } |
|
507 |
|
508 aClipRect = TRect( aSourceSize ); |
|
509 aClipRect.Shrink( x_offset, y_offset ); |
|
510 } |
|
511 else // 0 < scaleFactor < KBMCallObjectScaleFactorMax |
|
512 { |
|
513 aScaleFactor = scaleFactor; |
|
514 TSize relativeTargetSize; |
|
515 relativeTargetSize.iWidth = aTargetSize.iWidth / scaleFactor; |
|
516 relativeTargetSize.iHeight = aTargetSize.iHeight / scaleFactor; |
|
517 TInt x_offset = ( aSourceSize.iWidth - |
|
518 relativeTargetSize.iWidth ) / 2; |
|
519 TInt y_offset = ( aSourceSize.iHeight - |
|
520 relativeTargetSize.iHeight ) / 2; |
|
521 aClipRect = TRect( relativeTargetSize ); |
|
522 if ( x_offset >= 0 && y_offset >= 0 ) |
|
523 { |
|
524 // clip from center of the source image |
|
525 aClipRect.Move( x_offset, y_offset ); |
|
526 } |
|
527 } |
|
528 |
|
529 return isTinyImage; |
|
530 } |
|
531 |
|
532 // End of File |