1 /* |
|
2 * Copyright (c) 2003 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: Main code file for plugin |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 #include <eikenv.h> |
|
21 #include <e32math.h> |
|
22 #include <bitdev.h> |
|
23 #include <aknutils.h> |
|
24 #include <akniconutils.h> |
|
25 #include <mifconvdefs.h> |
|
26 |
|
27 #include "CBmpAnimScrPlugin.h" |
|
28 #include "BmpAnimUtils.h" |
|
29 |
|
30 #include <AknQueryDialog.h> |
|
31 #include <avkon.rsg> |
|
32 // "BmpAnimScrPlugin.rsg" |
|
33 |
|
34 const TInt KDefaultViewTime = 1000000; |
|
35 |
|
36 // |
|
37 // CBmpAnimSrcPlugin |
|
38 // |
|
39 |
|
40 // Creates and returns a new instance of CBmpAnimScrPlugin |
|
41 CBmpAnimScrPlugin* CBmpAnimScrPlugin::NewL() |
|
42 { |
|
43 CBmpAnimScrPlugin *plugin = new (ELeave) CBmpAnimScrPlugin(); |
|
44 |
|
45 // Initialize settings object so that the plugin name can be retrieved |
|
46 iSettings = CBmpAnimSettings::NewL(); |
|
47 |
|
48 return plugin; |
|
49 } |
|
50 |
|
51 |
|
52 // Default constructor |
|
53 CBmpAnimScrPlugin::CBmpAnimScrPlugin() |
|
54 : iState(EPluginStateLoading), |
|
55 iStopDisplaying(EFalse), |
|
56 iLoadedAnimation(ENone) |
|
57 { |
|
58 BMALOGGER_CREATE; |
|
59 |
|
60 } |
|
61 |
|
62 |
|
63 // Destructor |
|
64 CBmpAnimScrPlugin::~CBmpAnimScrPlugin() |
|
65 { |
|
66 delete iModel; |
|
67 delete iSettings; |
|
68 |
|
69 StopDisplayTimer(); |
|
70 delete iDisplayTimer; |
|
71 |
|
72 BMALOGGER_DELETE; |
|
73 } |
|
74 |
|
75 |
|
76 // --- from Screensaverplugin --- |
|
77 |
|
78 |
|
79 // Initialization function. Must be called before anything but |
|
80 // name query can be done |
|
81 TInt CBmpAnimScrPlugin::InitializeL(MScreensaverPluginHost *aHost) |
|
82 { |
|
83 ASSERT(aHost); |
|
84 |
|
85 // Sanity check |
|
86 if (!aHost) |
|
87 { |
|
88 return KErrArgument; |
|
89 } |
|
90 |
|
91 // Save the host interface |
|
92 iHost = aHost; |
|
93 |
|
94 // Start state |
|
95 iState = EPluginStateLoading; |
|
96 |
|
97 // Initial timing (may be overridden by settings) |
|
98 iHost->SetRefreshTimerValue(KDefaultViewTime); |
|
99 |
|
100 // Lie that we'll show indicators so that host does not prevent |
|
101 // plugin to be run if there are any to show. We'll stop after a |
|
102 // while anyway and the indicators are shown by normal Screensaver |
|
103 iHost->OverrideStandardIndicators(); |
|
104 |
|
105 // Grab hold of the environment (this could be in the plugin host interface) |
|
106 iEikEnv = CEikonEnv::Static(); |
|
107 |
|
108 // Create the model to store the animation in |
|
109 iModel = new(ELeave) CBmpAnimModel(); |
|
110 iModel->ConstructL(iSettings); |
|
111 |
|
112 // Get screen info |
|
113 UpdateDisplayInfo(); |
|
114 |
|
115 // Load the animation (Reload figures out which graphics should be used) |
|
116 ReloadAnimationL(); |
|
117 |
|
118 // Create display timer |
|
119 iDisplayTimer = CPeriodic::NewL(CActive::EPriorityStandard); |
|
120 |
|
121 return KErrNone; |
|
122 } |
|
123 |
|
124 |
|
125 // Draw function being called repeatedly by the host |
|
126 TInt CBmpAnimScrPlugin::Draw(CWindowGc& aGc) |
|
127 { |
|
128 // If initializing, start the timer and move on to animation state |
|
129 if (iState == EPluginStateInitializing) |
|
130 { |
|
131 BMALOGGER_WRITE("First draw, initializing"); |
|
132 |
|
133 StartDisplayTimer(); |
|
134 HandlePluginState(); |
|
135 SetDisplayMode(); |
|
136 TInt nLights = iModel->Settings()->Lights(); |
|
137 |
|
138 if (nLights > 0) |
|
139 { |
|
140 Lights(nLights); |
|
141 } |
|
142 |
|
143 // Make sure the animation sequence starts from the beginning |
|
144 iModel->SetCurrentItemIndex(0); |
|
145 } |
|
146 |
|
147 // Retrieve the next image in sequence |
|
148 TBool endOfSequence = EFalse; |
|
149 CBmpAnimItem* pItem = iModel->NextItem(endOfSequence); |
|
150 |
|
151 if ((endOfSequence) || (!pItem)) |
|
152 { |
|
153 // End of sequence reached, see if we've shown enough (1 minute) |
|
154 if (iStopDisplaying) |
|
155 { |
|
156 // Stop the timer |
|
157 StopDisplayTimer(); |
|
158 |
|
159 // Back to square 1 |
|
160 iState = EPluginStateInitializing; |
|
161 |
|
162 // Set a lower refresh rate while plugin is suspended. |
|
163 // This allows the Screensaver to stop Window Server heartbeat |
|
164 // and the system is able to sleep normally |
|
165 // NOTE: Not needed anymore, Screensaver now shuts down |
|
166 // WSERV heartbeat for suspended plugins |
|
167 // iHost->SetRefreshTimerValue(KDefaultViewTime); |
|
168 |
|
169 TInt suspendTime = iModel->Settings()->SuspendTime(); |
|
170 |
|
171 BMALOGGER_WRITEF(_L("BMA: Done drawing, suspending for %d"), |
|
172 suspendTime); |
|
173 |
|
174 iHost->Suspend(suspendTime); |
|
175 |
|
176 return KErrNone; |
|
177 } |
|
178 } |
|
179 |
|
180 if (pItem) |
|
181 { |
|
182 // Make sure the window is empty in case the bitmap doesn't |
|
183 // fill the whole screen |
|
184 aGc.Clear(); |
|
185 |
|
186 DrawCentered(aGc, pItem); |
|
187 } |
|
188 |
|
189 // Activate code if centering INI-controllable |
|
190 #if 0 |
|
191 // Retrieve drawing information |
|
192 CGulIcon* pIcon = pItem->Icon(); |
|
193 TPoint position = pItem->Position(); |
|
194 CFbsBitmap* bitmap = pIcon->Bitmap(); |
|
195 CFbsBitmap* mask = pIcon->Mask(); |
|
196 |
|
197 // Draw the whole bitmap at position |
|
198 TRect rect(position, bitmap->SizeInPixels()); |
|
199 |
|
200 if (mask) |
|
201 { |
|
202 // Looks like a real icon - draw masked |
|
203 aGc.BitBltMasked(position, bitmap, rect, mask, ETrue); |
|
204 } |
|
205 else |
|
206 { |
|
207 // Just the bitmap - no masked draw |
|
208 aGc.BitBlt(position, bitmap, rect); |
|
209 } |
|
210 |
|
211 // Wait for the specified time until next image |
|
212 // |
|
213 // TODO: The new wk28 Screensaver crashes if the next call |
|
214 // is uncommented. Maybe the timer is not stopped |
|
215 // before starting again? Hmm... doesn't seem to happen |
|
216 // anymore. I wonder what changed. Anyway, I'll have it |
|
217 // commented out for the time being, in order to control |
|
218 // all frames' rate with the single setting |
|
219 // |
|
220 // NOTE: There was a flaw in Screensaver where it would try to |
|
221 // start refresh timer twice, if plugin changes the value during |
|
222 // the first draw. The fix is released for 2.6_wk40_FB4 |
|
223 // iHost->SetRefreshTimerValue(pItem->Timing()); |
|
224 } |
|
225 /* |
|
226 aGc.SetPenColor(TRgb(255,0,0)); |
|
227 aGc.SetPenStyle(CGraphicsContext::ESolidPen); |
|
228 aGc.DrawRect(TRect(30, 30, 100, 100)); |
|
229 |
|
230 aGc.SetPenColor(TRgb(255,0,0)); |
|
231 aGc.SetPenSize(TSize(3,3)); |
|
232 aGc.DrawRect(TRect(120, 100, 200, 150)); |
|
233 */ |
|
234 #endif |
|
235 return KErrNone; |
|
236 } |
|
237 |
|
238 |
|
239 // Return the name of the plugin |
|
240 const TDesC16& CBmpAnimScrPlugin::Name() const |
|
241 { |
|
242 if (iSettings) |
|
243 { |
|
244 return iSettings->PluginName(); |
|
245 } |
|
246 |
|
247 return KPluginName; |
|
248 } |
|
249 |
|
250 |
|
251 // Handles events sent by the screensaver |
|
252 TInt CBmpAnimScrPlugin::HandleScreensaverEventL( |
|
253 TScreensaverEvent aEvent, |
|
254 TAny* /* aData */) |
|
255 { |
|
256 switch (aEvent) |
|
257 { |
|
258 case EScreensaverEventStarting: |
|
259 BMALOGGER_WRITE("Start event"); |
|
260 break; |
|
261 case EScreensaverEventStopping: |
|
262 BMALOGGER_WRITE("Stop event"); |
|
263 StopDisplayTimer(); |
|
264 iState = EPluginStateInitializing; |
|
265 break; |
|
266 case EScreensaverEventDisplayChanged: |
|
267 BMALOGGER_WRITE("Display changed event"); |
|
268 // Grab current screen info |
|
269 UpdateDisplayInfo(); |
|
270 // Reload animation, if needed |
|
271 ReloadAnimationL(); |
|
272 break; |
|
273 default: |
|
274 break; |
|
275 } |
|
276 |
|
277 return KErrNone; |
|
278 } |
|
279 |
|
280 |
|
281 // Return plugin capabilities (configurable) |
|
282 TInt CBmpAnimScrPlugin::Capabilities() |
|
283 { |
|
284 return EScpCapsConfigure; |
|
285 } |
|
286 |
|
287 |
|
288 // Perform a plugin function |
|
289 TInt CBmpAnimScrPlugin::PluginFunction(TScPluginCaps aFunction, TAny* aParam) |
|
290 { |
|
291 switch (aFunction) |
|
292 { |
|
293 case EScpCapsConfigure: |
|
294 { |
|
295 TRAPD(err, err = ConfigureL(aParam)); |
|
296 return err; |
|
297 } |
|
298 break; |
|
299 default: |
|
300 return KErrNotSupported; |
|
301 break; |
|
302 } |
|
303 } |
|
304 |
|
305 |
|
306 // --- private functions --- |
|
307 |
|
308 // Draws centered items |
|
309 void CBmpAnimScrPlugin::DrawCentered(CWindowGc& aGc, CBmpAnimItem* aItem) |
|
310 { |
|
311 CGulIcon* pIcon = aItem->Icon(); |
|
312 CFbsBitmap* bitmap = pIcon->Bitmap(); |
|
313 CFbsBitmap* mask = pIcon->Mask(); |
|
314 |
|
315 if (!bitmap) |
|
316 return; |
|
317 |
|
318 // Center the bitmap horizontally and vertically (crop off excess) |
|
319 TPoint pos; |
|
320 TRect rectToDraw; |
|
321 TSize sizeBmp = bitmap->SizeInPixels(); |
|
322 TInt screenWidth = iDi.iRect.Width(); |
|
323 TInt screenHeight = iDi.iRect.Height(); |
|
324 |
|
325 // Horizontally |
|
326 if (sizeBmp.iWidth <= screenWidth) |
|
327 { |
|
328 // Width fits on screen - center xpos |
|
329 pos.iX = (screenWidth - sizeBmp.iWidth) / 2; |
|
330 |
|
331 // Whole width of bmp can be drawn |
|
332 rectToDraw.SetWidth(sizeBmp.iWidth); |
|
333 } |
|
334 else |
|
335 { |
|
336 // Bmp wider than screen - xpos top left |
|
337 pos.iX = 0; |
|
338 |
|
339 // Adjust draw rect position and width |
|
340 rectToDraw.iTl.iX = (sizeBmp.iWidth - screenWidth) / 2; |
|
341 rectToDraw.SetWidth(screenWidth); |
|
342 } |
|
343 |
|
344 // Vertically |
|
345 if (sizeBmp.iHeight <= screenHeight) |
|
346 { |
|
347 // Height fits on screen - center ypos |
|
348 pos.iY = (screenHeight - sizeBmp.iHeight) / 2; |
|
349 |
|
350 // Whole height of bmp can be drawn |
|
351 rectToDraw.SetHeight(sizeBmp.iHeight); |
|
352 } |
|
353 else |
|
354 { |
|
355 // Bmp higher than screen - ypos top left |
|
356 pos.iY = 0; |
|
357 |
|
358 // Adjust draw rect position and height |
|
359 rectToDraw.iTl.iY = (sizeBmp.iHeight - screenHeight) / 2; |
|
360 rectToDraw.SetHeight(screenHeight); |
|
361 } |
|
362 |
|
363 // Do the drawing |
|
364 if (mask) |
|
365 { |
|
366 // Looks like a real icon - draw masked |
|
367 aGc.BitBltMasked(pos, bitmap, rectToDraw, mask, ETrue); |
|
368 } |
|
369 else |
|
370 { |
|
371 // Just the bitmap - no masked draw |
|
372 aGc.BitBlt(pos, bitmap, rectToDraw); |
|
373 } |
|
374 } |
|
375 |
|
376 |
|
377 // Loads the animation into the model |
|
378 void CBmpAnimScrPlugin::LoadAnimationL(TBool aLandscape, TBool aRotate) |
|
379 { |
|
380 // Rotated landscape not supported |
|
381 ASSERT(!(aLandscape && aRotate)); |
|
382 |
|
383 // Start by getting rid of a possible loaded animation |
|
384 iModel->DeleteAll(); |
|
385 |
|
386 // Bitmap index. If negative, loading is finished. |
|
387 TInt nIndex = KMifIdFirst; |
|
388 |
|
389 TFileName fileName; |
|
390 |
|
391 if (aLandscape) |
|
392 { |
|
393 fileName = iModel->Settings()->BitmapFilenameLandscape(); |
|
394 } |
|
395 else |
|
396 { |
|
397 fileName = iModel->Settings()->BitmapFilename(); |
|
398 } |
|
399 |
|
400 BMALOGGER_WRITEF(_L("BMA: Loading from: %S"), &(fileName)); |
|
401 |
|
402 while (nIndex > 0) |
|
403 { |
|
404 CFbsBitmap* pBmp = NULL; |
|
405 |
|
406 TRAPD(err, pBmp = AknIconUtils::CreateIconL(fileName, nIndex)); |
|
407 |
|
408 if ((pBmp) && (err == KErrNone)) |
|
409 { |
|
410 // Got bitmap, push and set size |
|
411 CleanupStack::PushL(pBmp); |
|
412 TInt scaleErr = ScaleBitmap(pBmp, aRotate); |
|
413 if (scaleErr == KErrNone) |
|
414 { |
|
415 // Create an item with the bitmap and store it in the model |
|
416 CBmpAnimItem* pItem = new(ELeave) CBmpAnimItem(); |
|
417 CleanupStack::PushL(pItem); |
|
418 |
|
419 pItem->SetIconL(pBmp); |
|
420 iModel->AppendItemL(pItem); |
|
421 |
|
422 CleanupStack::Pop(2); // pBmp, pItem |
|
423 |
|
424 BMALOGGER_WRITEF(_L("BMA: Loaded bmp %d"), nIndex); |
|
425 |
|
426 // Try loading next bitmap (skip mask IDs) |
|
427 nIndex += 2; |
|
428 } |
|
429 else |
|
430 { |
|
431 BMALOGGER_WRITEF(_L("BMA: Bmp %d scale err %d"), |
|
432 nIndex, scaleErr); |
|
433 |
|
434 // Apparently SVG icon was not found, this is not caught |
|
435 // in CreateIconL(). Assume last image was loaded. |
|
436 CleanupStack::PopAndDestroy(); // pBmp |
|
437 nIndex = -1; |
|
438 } |
|
439 } |
|
440 else |
|
441 { |
|
442 // Loading failed - maybe reached end of bitmaps |
|
443 nIndex = -1; |
|
444 |
|
445 BMALOGGER_WRITEF(_L("BMA: Bmp load failed: %d"), err); |
|
446 } |
|
447 } |
|
448 |
|
449 // Save the type of loaded animation |
|
450 if (aLandscape) |
|
451 { |
|
452 iLoadedAnimation = ELandscape; |
|
453 } |
|
454 else if (aRotate) |
|
455 { |
|
456 iLoadedAnimation = EPortraitRotated; |
|
457 } |
|
458 else |
|
459 { |
|
460 iLoadedAnimation = EPortrait; |
|
461 } |
|
462 |
|
463 // On to next state |
|
464 HandlePluginState(); |
|
465 |
|
466 // Start animating, when appropriate |
|
467 iHost->SetRefreshTimerValue(iModel->Settings()->Timing()); |
|
468 |
|
469 BMALOGGER_WRITE("BMA: Animation loaded"); |
|
470 } |
|
471 |
|
472 |
|
473 // Re-loads the animation into the model, if needed |
|
474 void CBmpAnimScrPlugin::ReloadAnimationL() |
|
475 { |
|
476 // Check if the correct graphics are already loaded |
|
477 if (!ReloadNeeded()) |
|
478 { |
|
479 // Done! That was easy :) |
|
480 return; |
|
481 } |
|
482 |
|
483 // Load correct graphics |
|
484 LoadAnimationL(LoadLandscape(), RotateNeeded()); |
|
485 } |
|
486 |
|
487 |
|
488 // Starts the display timer |
|
489 void CBmpAnimScrPlugin::StartDisplayTimer() |
|
490 { |
|
491 ASSERT(iDisplayTimer); |
|
492 |
|
493 TInt time = iModel->Settings()->RunningTime(); |
|
494 |
|
495 BMALOGGER_WRITEF(_L("BMA: Start display timer for %d"), time); |
|
496 |
|
497 iStopDisplaying = EFalse; |
|
498 iDisplayTimer->Start( |
|
499 time, |
|
500 time, |
|
501 TCallBack(DisplayTimerCallback, this)); |
|
502 } |
|
503 |
|
504 |
|
505 // Stops the display timer |
|
506 void CBmpAnimScrPlugin::StopDisplayTimer() |
|
507 { |
|
508 BMALOGGER_WRITE("BMA: Stop display timer"); |
|
509 |
|
510 if (iDisplayTimer) |
|
511 { |
|
512 iDisplayTimer->Cancel(); |
|
513 } |
|
514 |
|
515 iStopDisplaying = EFalse; |
|
516 } |
|
517 |
|
518 |
|
519 // Display timer callback - sets animation stop flag |
|
520 TInt CBmpAnimScrPlugin::DisplayTimerCallback(TAny* aPtr) |
|
521 { |
|
522 BMALOGGER_WRITE("BMA: Display timer timeout"); |
|
523 |
|
524 CBmpAnimScrPlugin* _this = REINTERPRET_CAST(CBmpAnimScrPlugin*, aPtr); |
|
525 _this->iStopDisplaying = ETrue; |
|
526 return KErrNone; |
|
527 } |
|
528 |
|
529 |
|
530 // Changes the internal state flag |
|
531 void CBmpAnimScrPlugin::HandlePluginState() |
|
532 { |
|
533 switch (iState) |
|
534 { |
|
535 case EPluginStateLoading: |
|
536 iState = EPluginStateInitializing; |
|
537 break; |
|
538 case EPluginStateInitializing: |
|
539 iState = EPluginStateAnimation; |
|
540 break; |
|
541 case EPluginStateAnimation: |
|
542 break; |
|
543 case EPluginStateStoppingAnimation: |
|
544 iHost->SetRefreshTimerValue(KDefaultViewTime); |
|
545 iState = EPluginStateInitializing; |
|
546 break; |
|
547 } |
|
548 } |
|
549 |
|
550 |
|
551 // Requests display mode from host |
|
552 void CBmpAnimScrPlugin::SetDisplayMode() |
|
553 { |
|
554 if (!iHost) |
|
555 { |
|
556 return; |
|
557 } |
|
558 |
|
559 // Exit partial mode |
|
560 iHost->ExitPartialMode(); |
|
561 } |
|
562 |
|
563 |
|
564 void CBmpAnimScrPlugin::Lights(TInt aSecs) |
|
565 { |
|
566 BMALOGGER_WRITEF(_L("BMA: Request lights for %d secs"), aSecs); |
|
567 iHost->RequestLights(aSecs); |
|
568 } |
|
569 |
|
570 |
|
571 // Configure the plugin |
|
572 TInt CBmpAnimScrPlugin::ConfigureL(TAny* aParam) |
|
573 { |
|
574 if (!iSettings) |
|
575 { |
|
576 return KErrNotFound; |
|
577 } |
|
578 |
|
579 // Grab the parameter (CEikonEnv in this case) |
|
580 CEikonEnv* eikEnv = NULL; |
|
581 |
|
582 if (aParam) |
|
583 { |
|
584 // The host was kind enough to provide us with a param - use it |
|
585 eikEnv = REINTERPRET_CAST(CEikonEnv*, aParam); |
|
586 } |
|
587 else if (iEikEnv) |
|
588 { |
|
589 // Use own env, if initialized |
|
590 eikEnv = iEikEnv; |
|
591 } |
|
592 |
|
593 TInt setting = iSettings->Lights(); |
|
594 |
|
595 CAknNumberQueryDialog* dlg = CAknNumberQueryDialog::NewL(setting); |
|
596 CleanupStack::PushL(dlg); |
|
597 _LIT(KPrompt, "Lights time (sec)"); |
|
598 dlg->SetPromptL(KPrompt); |
|
599 dlg->SetMinimumAndMaximum(0, 30); |
|
600 CleanupStack::Pop(); |
|
601 |
|
602 if (dlg->ExecuteLD(R_AVKON_DIALOG_QUERY_VALUE_NUMBER)) |
|
603 { |
|
604 iSettings->SetLights(setting); |
|
605 iSettings->SaveSettingsL(); |
|
606 } |
|
607 |
|
608 // All was swell! |
|
609 return KErrNone; |
|
610 } |
|
611 |
|
612 |
|
613 // Scale bitmap to screen size, set size of SVG bitmaps |
|
614 TInt CBmpAnimScrPlugin::ScaleBitmap(CFbsBitmap* aBmp, TBool aRotate) |
|
615 { |
|
616 TInt ret = KErrNone; |
|
617 |
|
618 // SVG size always screen size |
|
619 TSize size = iDi.iRect.Size(); |
|
620 |
|
621 if (!AknIconUtils::IsMifIcon(aBmp)) |
|
622 { |
|
623 // Bitmaps maintain their original size, unless scaling requested, in which |
|
624 // case screen size is OK |
|
625 if (!iSettings->ScaleBmps()) |
|
626 { |
|
627 // No scaling, use original size |
|
628 size = aBmp->SizeInPixels(); |
|
629 |
|
630 if (aRotate) |
|
631 { |
|
632 // Lie the target size, otherwise IconUitls will think |
|
633 // the image needs scaling (this won't work perfectly |
|
634 // either, the image gets clipped a little :( |
|
635 //size.SetSize(size.iHeight, size.iHeight); |
|
636 |
|
637 // Flip size for rotation |
|
638 size.SetSize(size.iHeight, size.iWidth); |
|
639 } |
|
640 } |
|
641 } |
|
642 |
|
643 if (aRotate) |
|
644 { |
|
645 // Set image to screen size and rotate 90 deg left (270 right) |
|
646 // ret = SetSizeAndRotation(aBmp, size, 270); |
|
647 ret = AknIconUtils::SetSizeAndRotation( |
|
648 aBmp, size, EAspectRatioPreservedSlice, 270); |
|
649 } |
|
650 else |
|
651 { |
|
652 // Just set image to size |
|
653 ret = AknIconUtils::SetSize(aBmp, size, EAspectRatioPreserved); |
|
654 } |
|
655 |
|
656 return ret; |
|
657 } |
|
658 |
|
659 |
|
660 // Returns ETrue if reload of the animation is needed |
|
661 TBool CBmpAnimScrPlugin::ReloadNeeded() |
|
662 { |
|
663 // Assume reload needed |
|
664 TBool needed = ETrue; |
|
665 |
|
666 switch (iLoadedAnimation) |
|
667 { |
|
668 case EPortrait: |
|
669 // No reload if display portrait |
|
670 if (!DisplayIsLandscape()) |
|
671 { |
|
672 needed = EFalse; |
|
673 } |
|
674 break; |
|
675 |
|
676 case ELandscape: |
|
677 case EPortraitRotated: |
|
678 // No reload if display landscape |
|
679 if (DisplayIsLandscape()) |
|
680 { |
|
681 needed = EFalse; |
|
682 } |
|
683 break; |
|
684 |
|
685 case ENone: |
|
686 default: |
|
687 // Reload |
|
688 break; |
|
689 } |
|
690 |
|
691 return needed; |
|
692 } |
|
693 |
|
694 |
|
695 // Returns ETrue if display in landscape |
|
696 TBool CBmpAnimScrPlugin::DisplayIsLandscape() |
|
697 { |
|
698 // Should actually check the rotation and stuff, but what the hey... |
|
699 return (iDi.iRect.Width() > iDi.iRect.Height()); |
|
700 } |
|
701 |
|
702 |
|
703 // Returns ETrue if graphics should be rotated |
|
704 TBool CBmpAnimScrPlugin::RotateNeeded() |
|
705 { |
|
706 // Rotate needed, if only portrait graphics are used, and |
|
707 // display is landscape |
|
708 return ((!iSettings->UseLandscape()) && (DisplayIsLandscape())); |
|
709 } |
|
710 |
|
711 |
|
712 // Returns ETrue if landscape graphics should be loaded |
|
713 TBool CBmpAnimScrPlugin::LoadLandscape() |
|
714 { |
|
715 // Landscape, if only available and display is landscape |
|
716 return ((iSettings->UseLandscape()) && (DisplayIsLandscape())); |
|
717 } |
|
718 |
|
719 |
|
720 // Updates the saved information about display |
|
721 void CBmpAnimScrPlugin::UpdateDisplayInfo() |
|
722 { |
|
723 iDi.iSize = sizeof(TScreensaverDisplayInfo); |
|
724 iHost->DisplayInfo(&iDi); |
|
725 } |
|
726 |
|
727 #if 0 |
|
728 // Rotates and scales a source bitmap into target bitmap (non-leaving wrapper) |
|
729 TInt CBmpAnimScrPlugin::SetSizeAndRotation( |
|
730 CFbsBitmap* aBmp, TSize aSize, TInt aAngle) |
|
731 { |
|
732 // Anything to do? |
|
733 if ((aBmp) && (aBmp->SizeInPixels() == aSize) && ((aAngle % 360) == 0)) |
|
734 { |
|
735 // Duh, the bitmap is already as requested |
|
736 return KErrNone; |
|
737 } |
|
738 |
|
739 // Call the actual workhorse |
|
740 TRAPD(err, SetSizeAndRotationL(aBmp, aSize, aAngle)); |
|
741 |
|
742 return err; |
|
743 } |
|
744 |
|
745 |
|
746 // Rotates and scales a source bitmap into target bitmap (leaving version) |
|
747 void CBmpAnimScrPlugin::SetSizeAndRotationL( |
|
748 CFbsBitmap* aBmp, TSize aSize, TInt aAngle) |
|
749 { |
|
750 // Make a copy of the source bitmap, and use the original source as target |
|
751 CFbsBitmap* tmpBmp = new (ELeave) CFbsBitmap; |
|
752 CleanupStack::PushL(tmpBmp); |
|
753 |
|
754 User::LeaveIfError(tmpBmp->Duplicate(aBmp->Handle())); |
|
755 |
|
756 // Discard original bitmap |
|
757 aBmp->Reset(); |
|
758 |
|
759 // Create new target bitmap in the original object |
|
760 User::LeaveIfError(aBmp->Create(aSize, tmpBmp->DisplayMode())); |
|
761 |
|
762 // Let the workhorse do its work |
|
763 RotateAndScaleBitmapL(TRect(aSize), aBmp, tmpBmp, aAngle); |
|
764 |
|
765 // Not interested in original anymore |
|
766 CleanupStack::PopAndDestroy(tmpBmp); |
|
767 } |
|
768 |
|
769 |
|
770 // Rotates and scales a source bitmap into target bitmap |
|
771 void CBmpAnimScrPlugin::RotateAndScaleBitmapL( |
|
772 const TRect& aTrgRect, |
|
773 CFbsBitmap* aTrgBitmap, |
|
774 CFbsBitmap* aSrcBitmap, |
|
775 TInt aAngle) |
|
776 { |
|
777 aAngle = aAngle % 360; |
|
778 if (aAngle < 0) |
|
779 { |
|
780 aAngle+=360; |
|
781 } |
|
782 |
|
783 if (!aSrcBitmap) User::Leave(KErrArgument); |
|
784 if (!aTrgBitmap) User::Leave(KErrArgument); |
|
785 if (aSrcBitmap->DisplayMode() != aTrgBitmap->DisplayMode()) |
|
786 User::Leave(KErrArgument); |
|
787 |
|
788 TSize trgBitmapSize = aTrgBitmap->SizeInPixels(); |
|
789 if ((trgBitmapSize.iHeight < aTrgRect.iBr.iY) || |
|
790 (trgBitmapSize.iWidth < aTrgRect.iBr.iX)) |
|
791 { |
|
792 User::Leave(KErrArgument); |
|
793 } |
|
794 |
|
795 if (aTrgRect.IsEmpty()) |
|
796 return; |
|
797 |
|
798 TSize srcSize = aSrcBitmap->SizeInPixels(); |
|
799 |
|
800 TInt centerX = srcSize.iWidth / 2; |
|
801 TInt centerY = srcSize.iHeight / 2; |
|
802 |
|
803 TInt trgWidth = aTrgRect.Width(); |
|
804 TInt trgHeight = aTrgRect.Height(); |
|
805 |
|
806 TInt scalefactor = 65536; |
|
807 TInt xscalefactor = (srcSize.iWidth << 16) / trgWidth; |
|
808 TInt yscalefactor = (srcSize.iHeight << 16) / trgHeight; |
|
809 |
|
810 // Check if rotating 90 left or right, no need to scale |
|
811 if (((aAngle == 270) || (aAngle == 90)) && |
|
812 (srcSize.iWidth == trgHeight) && |
|
813 (srcSize.iHeight == trgWidth)) |
|
814 { |
|
815 scalefactor = 65535; |
|
816 } |
|
817 else |
|
818 { |
|
819 if (xscalefactor < yscalefactor) |
|
820 { |
|
821 scalefactor = yscalefactor; |
|
822 } |
|
823 else |
|
824 { |
|
825 scalefactor = xscalefactor; |
|
826 } |
|
827 } |
|
828 |
|
829 TBool srcTemporary = EFalse; |
|
830 TBool hardMask = EFalse; |
|
831 if (aSrcBitmap->IsRomBitmap()) |
|
832 { |
|
833 srcTemporary = ETrue; |
|
834 } |
|
835 if (aSrcBitmap->IsCompressedInRAM()) |
|
836 { |
|
837 srcTemporary = ETrue; |
|
838 } |
|
839 |
|
840 TBool fallbackOnly = EFalse; |
|
841 TDisplayMode displayMode = aSrcBitmap->DisplayMode(); |
|
842 TUint8 fillColor = 0; |
|
843 |
|
844 switch(displayMode) |
|
845 { |
|
846 case EGray2: |
|
847 srcTemporary = ETrue; |
|
848 hardMask = ETrue; |
|
849 fillColor = 0xff; // white |
|
850 break; |
|
851 case EGray4: |
|
852 case EGray16: |
|
853 case EColor16: |
|
854 case EColor16M: |
|
855 case ERgb: |
|
856 fallbackOnly = ETrue; |
|
857 break; |
|
858 case EColor256: |
|
859 fillColor = 0xff; // should be black in our indexed palette.... |
|
860 case EGray256: |
|
861 case EColor4K: |
|
862 case EColor64K: |
|
863 |
|
864 case EColor16MU: |
|
865 // These are the supported modes |
|
866 break; |
|
867 default: |
|
868 fallbackOnly = ETrue; |
|
869 } |
|
870 |
|
871 if (fallbackOnly) |
|
872 { |
|
873 // Color mode not supported |
|
874 User::Leave(KErrNotSupported); |
|
875 } |
|
876 |
|
877 CFbsBitmap* realSource = aSrcBitmap; |
|
878 CFbsBitmap* realTarget = aTrgBitmap; |
|
879 if (srcTemporary) |
|
880 { |
|
881 realSource = new (ELeave) CFbsBitmap(); |
|
882 CleanupStack::PushL(realSource); |
|
883 if (hardMask) |
|
884 { |
|
885 realTarget = new (ELeave) CFbsBitmap(); |
|
886 CleanupStack::PushL(realTarget); |
|
887 User::LeaveIfError(realSource->Create(srcSize, EGray256)); |
|
888 displayMode = EGray256; |
|
889 User::LeaveIfError(realTarget->Create( |
|
890 aTrgBitmap->SizeInPixels(), EGray256)); |
|
891 } |
|
892 else |
|
893 { |
|
894 User::LeaveIfError(realSource->Create( |
|
895 srcSize, aSrcBitmap->DisplayMode())); |
|
896 } |
|
897 |
|
898 CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(realSource); |
|
899 CleanupStack::PushL(dev); |
|
900 CFbsBitGc* gc = NULL; |
|
901 User::LeaveIfError(dev->CreateContext(gc)); |
|
902 CleanupStack::PushL(gc); |
|
903 gc->BitBlt(TPoint(0,0), aSrcBitmap); |
|
904 CleanupStack::PopAndDestroy(2); // dev, gc |
|
905 } |
|
906 |
|
907 // Heap lock for FBServ large chunk is only needed with large bitmaps. |
|
908 if (realSource->IsLargeBitmap() || realTarget->IsLargeBitmap()) |
|
909 { |
|
910 realTarget->LockHeapLC(ETrue); // fbsheaplock |
|
911 } |
|
912 else |
|
913 { |
|
914 // Bogus push so we can pop() anyway |
|
915 CleanupStack::PushL((TAny*)NULL); |
|
916 } |
|
917 |
|
918 TUint32* srcAddress = realSource->DataAddress(); |
|
919 TUint32* trgAddress = realTarget->DataAddress(); |
|
920 |
|
921 TReal realsin; |
|
922 TReal realcos; |
|
923 TInt sin; |
|
924 TInt cos; |
|
925 |
|
926 User::LeaveIfError(Math::Sin(realsin, ((2*KPi)/360) * aAngle)); |
|
927 User::LeaveIfError(Math::Cos(realcos, ((2*KPi)/360) * aAngle)); |
|
928 |
|
929 sin = ((TInt)(realsin * scalefactor)); |
|
930 cos = ((TInt)(realcos * scalefactor)); |
|
931 |
|
932 TInt xx = ((trgWidth)/2) - ((srcSize.iWidth/2) - centerX); |
|
933 TInt yy = ((trgHeight)/2) - ((srcSize.iHeight/2) - centerY); |
|
934 |
|
935 TInt x = 0; |
|
936 TInt y = 0; |
|
937 TInt u = 0; |
|
938 TInt v = 0; |
|
939 |
|
940 if( (displayMode==EGray256) || (displayMode==EColor256) ) |
|
941 { |
|
942 TInt srcScanLen8 = CFbsBitmap::ScanLineLength( |
|
943 srcSize.iWidth, displayMode); |
|
944 TInt trgScanLen8 = CFbsBitmap::ScanLineLength( |
|
945 trgBitmapSize.iWidth, displayMode); |
|
946 TUint8* srcAddr8 = reinterpret_cast<TUint8*>(srcAddress); |
|
947 TUint8* trgAddr8 = reinterpret_cast<TUint8*>(trgAddress); |
|
948 |
|
949 // skip left and top margins in the beginning |
|
950 trgAddr8 += trgScanLen8 * aTrgRect.iTl.iY + aTrgRect.iTl.iX; |
|
951 |
|
952 for (y = 0; y < trgHeight; y++) |
|
953 { |
|
954 u = (-xx) * cos + (y-yy) * sin + (centerX<<16); |
|
955 v = (y-yy) * cos - (-xx) * sin + (centerY<<16); |
|
956 for (x = 0; x < trgWidth; x++) |
|
957 { |
|
958 if (((u>>16)>=srcSize.iWidth) || |
|
959 ((v>>16)>=srcSize.iHeight) || |
|
960 ((u>>16)<0) || |
|
961 ((v>>16)<0)) |
|
962 { |
|
963 *trgAddr8++ = fillColor; |
|
964 } |
|
965 else |
|
966 { |
|
967 *trgAddr8++ = srcAddr8[(u>>16)+(((v>>16))*srcScanLen8)]; |
|
968 } |
|
969 u += cos; |
|
970 v -= sin; |
|
971 } |
|
972 trgAddr8 += trgScanLen8 - trgWidth; |
|
973 } |
|
974 } |
|
975 else if( displayMode == EColor64K || displayMode == EColor4K) |
|
976 { |
|
977 TInt srcScanLen16 = CFbsBitmap::ScanLineLength( |
|
978 srcSize.iWidth, displayMode) / 2; |
|
979 TInt trgScanLen16 = CFbsBitmap::ScanLineLength( |
|
980 trgBitmapSize.iWidth, displayMode) / 2; |
|
981 TUint16* srcAddr16 = reinterpret_cast<TUint16*>(srcAddress); |
|
982 TUint16* trgAddr16 = reinterpret_cast<TUint16*>(trgAddress); |
|
983 |
|
984 // skip left and top margins in the beginning |
|
985 trgAddr16 += trgScanLen16 * aTrgRect.iTl.iY + aTrgRect.iTl.iX; |
|
986 |
|
987 for (y = 0; y < trgHeight; y++) |
|
988 { |
|
989 u = (-xx) * cos + (y-yy) * sin + (centerX<<16); |
|
990 v = (y-yy) * cos - (-xx) * sin + (centerY<<16); |
|
991 for (x = 0; x < trgWidth; x++) |
|
992 { |
|
993 if (((u>>16)>=srcSize.iWidth) || |
|
994 ((v>>16)>=srcSize.iHeight) || |
|
995 ((u>>16)<0) || |
|
996 ((v>>16)<0)) |
|
997 { |
|
998 *trgAddr16++ = 0; |
|
999 } |
|
1000 else |
|
1001 { |
|
1002 *trgAddr16++ = |
|
1003 srcAddr16[(u>>16)+(((v>>16))*srcScanLen16)]; |
|
1004 } |
|
1005 u += cos; |
|
1006 v -= sin; |
|
1007 } |
|
1008 trgAddr16 += trgScanLen16 - trgWidth; |
|
1009 } |
|
1010 } |
|
1011 else if(displayMode == EColor16MU) |
|
1012 { |
|
1013 TInt srcScanLen32 = CFbsBitmap::ScanLineLength( |
|
1014 srcSize.iWidth, displayMode) / 4; |
|
1015 TInt trgScanLen32 = CFbsBitmap::ScanLineLength( |
|
1016 trgBitmapSize.iWidth, displayMode) / 4; |
|
1017 TUint32* srcAddr32 = srcAddress; |
|
1018 TUint32* trgAddr32 = trgAddress; |
|
1019 |
|
1020 // skip left and top margins in the beginning |
|
1021 trgAddr32 += trgScanLen32 * aTrgRect.iTl.iY + aTrgRect.iTl.iX; |
|
1022 |
|
1023 for (y = 0; y < trgHeight; y++) |
|
1024 { |
|
1025 u = (-xx) * cos + (y-yy) * sin + (centerX<<16); |
|
1026 v = (y-yy) * cos - (-xx) * sin + (centerY<<16); |
|
1027 for (x = 0; x < trgWidth; x++) |
|
1028 { |
|
1029 if (((u>>16)>=srcSize.iWidth) || |
|
1030 ((v>>16)>=srcSize.iHeight) || |
|
1031 ((u>>16)<0) || |
|
1032 ((v>>16)<0)) |
|
1033 { |
|
1034 *trgAddr32++ = 0; |
|
1035 } |
|
1036 else |
|
1037 { |
|
1038 *trgAddr32++ = |
|
1039 srcAddr32[(u>>16)+(((v>>16))*srcScanLen32)]; |
|
1040 } |
|
1041 u += cos; |
|
1042 v -= sin; |
|
1043 } |
|
1044 trgAddr32 += trgScanLen32 - trgWidth; |
|
1045 } |
|
1046 } |
|
1047 else |
|
1048 { |
|
1049 // Display mode not supported - but this should've been caught |
|
1050 // already earlier |
|
1051 User::Leave(KErrUnknown); |
|
1052 } |
|
1053 |
|
1054 CleanupStack::PopAndDestroy(); // fbsheaplock |
|
1055 |
|
1056 if (srcTemporary) |
|
1057 { |
|
1058 if (hardMask) |
|
1059 { |
|
1060 CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(aTrgBitmap); |
|
1061 CleanupStack::PushL(dev); |
|
1062 CFbsBitGc* gc = NULL; |
|
1063 User::LeaveIfError(dev->CreateContext(gc)); |
|
1064 CleanupStack::PushL(gc); |
|
1065 gc->BitBlt(TPoint(0,0), realTarget); |
|
1066 CleanupStack::PopAndDestroy(3); // dev, gc, realtarget |
|
1067 } |
|
1068 CleanupStack::PopAndDestroy(); // realSource |
|
1069 } |
|
1070 } |
|
1071 #endif |
|
1072 |
|
1073 // End of file |
|