windowing/windowserver/nga/SERVER/openwfc/ScreenRedraw.cpp
changeset 0 5d03bc08d59c
child 121 d72fc2aace31
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "ScreenRedraw.h"
       
    17 
       
    18 #include <hal.h>
       
    19 
       
    20 #include "debugbar.h"
       
    21 #include "inifile.h"
       
    22 #include "screen.h"
       
    23 #include "pointer.h"
       
    24 #include "rootwin.h"
       
    25 #include "walkwindowtree.h"
       
    26 #include "wstop.h"
       
    27 #include "WsMemMgr.h"
       
    28 #include "renderstagemanager.h"
       
    29 #include "Graphics/WsRenderStageFactory.h"
       
    30 #include "Graphics/WsRenderStage.h"
       
    31 #include "Graphics/wsgraphicscontext.h"
       
    32 #include "EVENT.H"
       
    33 
       
    34 #ifdef USE_DEBUG_FRAME_CAPTURE
       
    35 #include <graphics/wsscreendevice.h>
       
    36 #include "../debuglog/debuglog.h"
       
    37 #endif
       
    38 
       
    39 GLREF_D CDebugLogBase *wsDebugLog;
       
    40 
       
    41 #ifdef USE_DEBUG_REGIONS
       
    42 #	define DEBUG_REGION(col,fill,reg) DebugRegion(col,fill,reg)
       
    43 #	define DEBUG_RECT(col,fill,rect) DebugRect(col,fill,rect)
       
    44 #else
       
    45 #	define DEBUG_REGION(col,fill,reg)
       
    46 #	define DEBUG_RECT(col,fill,rect)
       
    47 #endif
       
    48 
       
    49 #ifdef _DEBUG
       
    50 # define LOG_SCREEN_REDRAW_START {if (wsDebugLog) {_LIT(KLogScreenRedrawStart, ">> CScreenRedraw::OnAnimation()"); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, KLogScreenRedrawStart);}}
       
    51 # define LOG_SCREEN_REDRAW_END {if (wsDebugLog) {_LIT(KLogScreenRedrawEnd, "<< CScreenRedraw::OnAnimation()"); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, KLogScreenRedrawEnd);}}
       
    52 #else
       
    53 # define LOG_SCREEN_REDRAW_START
       
    54 # define LOG_SCREEN_REDRAW_END
       
    55 #endif
       
    56 
       
    57 
       
    58 #ifdef USE_DEBUG_FRAME_CAPTURE
       
    59 #	ifdef __WINS__
       
    60 	_LIT(KDefaultFrameCaptureLocation, "c:\\");
       
    61 #	else
       
    62 	_LIT(KDefaultFrameCaptureLocation, "e:\\");
       
    63 #	endif
       
    64 #endif //USE_DEBUG_FRAME_CAPTURE
       
    65 
       
    66 CScreenRedraw::TTimedRect::TTimedRect(TAnimType aType, const TRect& aRect, const TTime& aTime, CWsWindow* aWindow)
       
    67 	: iType(aType), iRect(aRect), iTime(aTime), iWindow(aWindow)
       
    68 	{
       
    69 	}
       
    70 
       
    71 TInt CScreenRedraw::TTimedRect::Compare(const TTimedRect& aOne,const TTimedRect& aOther)
       
    72 	{
       
    73 	if(aOne.iTime < aOther.iTime)
       
    74 		return -1;
       
    75 	else if(aOne.iTime > aOther.iTime)
       
    76 		return 1;
       
    77 	else
       
    78 		return 0;
       
    79 	}
       
    80 
       
    81 CScreenRedraw * CScreenRedraw::NewL(CScreen& aScreen)
       
    82 	{
       
    83 	CScreenRedraw * self = new (ELeave) CScreenRedraw(aScreen);
       
    84 	CleanupStack::PushL(self);
       
    85 	self->ConstructL();
       
    86 	CleanupStack::Pop(self);
       
    87 	return self;
       
    88 	}
       
    89 	
       
    90 CScreenRedraw::CScreenRedraw(CScreen& aScreen): iScreen(aScreen)
       
    91 	{
       
    92 	}
       
    93 
       
    94 CScreenRedraw::~CScreenRedraw()
       
    95 	{
       
    96 	CRenderStageManager::Release(iRenderStages);
       
    97 	iRenderStages = NULL;
       
    98 	iTimedDrawRect.Close();
       
    99 	iInvalid.Reset();
       
   100 	iTopElement.Reset();
       
   101 	iQuickFadeList.Reset();
       
   102 #ifdef USE_DEBUG_FRAME_CAPTURE
       
   103 	delete iDebugBitmap;
       
   104 	delete iDebugBitmapDevice;
       
   105 	delete iDebugBitmapGc;
       
   106 #endif //USE_DEBUG_FRAME_CAPTURE
       
   107 	}
       
   108 
       
   109 void CScreenRedraw::ConstructL()
       
   110 	{
       
   111 	
       
   112 	LEAVE_LOG_INSTALL_C;
       
   113 	
       
   114 	iRenderStages = CRenderStageManager::ConnectL(
       
   115 						iScreen.ScreenNumber(),
       
   116 						static_cast<MWsScreen*>(&iScreen),
       
   117 						this
       
   118 						);
       
   119 	
       
   120 	LEAVE_LOG_UNINSTALL_C;
       
   121 	
       
   122 	WS_ASSERT_ALWAYS(iRenderStages, EWsPanicNoRenderStagePipeline);
       
   123 	iRenderStageTextCursor = static_cast<MWsTextCursor*>(iRenderStages->ResolveObjectInterface(KMWsTextCursor));
       
   124 	WS_ASSERT_ALWAYS(iRenderStageTextCursor, EWsPanicTextCursorInterfaceMissing);
       
   125 
       
   126 #ifdef USE_DEBUG_FRAME_CAPTURE
       
   127 	_LIT(KWSERVIniFileVarFrameCapture,"FRAMECAPTURE");
       
   128 	iFrameCapture = WsIniFile->FindVar(KWSERVIniFileVarFrameCapture);
       
   129 
       
   130 	// Location to save captured images
       
   131 	if (!WsIniFile->FindVar(KWSERVIniFileVarFrameCapture, iFrameCaptureLocation) || iFrameCaptureLocation.Length() == 0)
       
   132 		{
       
   133 		iFrameCaptureLocation.Set(KDefaultFrameCaptureLocation);
       
   134 		}
       
   135 #endif //USE_DEBUG_FRAME_CAPTURE
       
   136 	}
       
   137 
       
   138 MWsTextCursor* CScreenRedraw::RenderStageTextCursor() const
       
   139 	{
       
   140 	return iRenderStageTextCursor;
       
   141 	}
       
   142 
       
   143 const TTime& CScreenRedraw::Now() const
       
   144 	{
       
   145 	if(!iAnimating)
       
   146 		{
       
   147 		iNow.UniversalTime();
       
   148 		}
       
   149 	return iNow;
       
   150 	}
       
   151 
       
   152 void CScreenRedraw::ScheduleRender(const TTimeIntervalMicroSeconds& aFromNow)
       
   153 	{
       
   154 	iRenderScheduled = ETrue;
       
   155 	TTime then(Now() + aFromNow);
       
   156 	if ((!iScheduled) || then < iNext)
       
   157 		iNext = then;
       
   158 	iScheduled = ETrue;
       
   159 	CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen,iNext);
       
   160 	}
       
   161 
       
   162 void CScreenRedraw::ScheduleRedraw()
       
   163 	{
       
   164 	iNext = Now();
       
   165 	iScheduled = ETrue;
       
   166 		
       
   167 	// The other scheduler also removes future animations which this one encompasses.
       
   168 	// We choose not to do the region calculations needed to achieve that here.
       
   169 	CWindowServer* server = CWsTop::WindowServer();
       
   170 	ASSERT(server);
       
   171 	MWsAnimationScheduler* sched = server->AnimationScheduler();
       
   172 	if(sched)
       
   173 		sched->ScheduleRedraw(iScreen,iNext);
       
   174 	else
       
   175 		RDebug::Printf("CWsTop::WindowServer()->RedrawScheduler() is NULL!!!");			
       
   176 	}
       
   177 
       
   178 /**
       
   179 @param aRect in screen coordinates 
       
   180 */
       
   181 void CScreenRedraw::ScheduleAnimation(TAnimType aType, const TRect& aRect,const TTimeIntervalMicroSeconds& aFromNow,const TTimeIntervalMicroSeconds& /*aFreq*/,const TTimeIntervalMicroSeconds& /*aStop*/, CWsWindow* aWindow)
       
   182 	{
       
   183 	TRect scheduledRect(aRect);
       
   184 	TRect test(aRect);
       
   185 	// In changetracking mode, animation is either scheduled via a window dirty region (aWindow non-NULL)
       
   186 	// or via a sprite manager dirty region (aWindow NULL) if scheduling a floating sprite
       
   187 	if (iScreen.ChangeTracking())
       
   188 		{
       
   189 		if (aWindow)
       
   190 			{
       
   191 			// scheduling a window dirty rect for a window/anim/sprite
       
   192 			test.Intersection(aWindow->Abs());
       
   193 			scheduledRect.Move(-aWindow->Origin()); // convert to window coordinates
       
   194 			}
       
   195 		// else, // scheduling a sprite manager dirty rect for a floating sprite
       
   196 		}
       
   197 	else
       
   198 		{
       
   199 		// scheduling a screen dirty rect
       
   200 		test.Intersection(iScreen.DrawableArea());
       
   201 		aWindow = NULL; // ensure all future timed draw screen rects are checked below
       
   202 		}
       
   203 	if(!test.IsEmpty())
       
   204 		{
       
   205 		const TTime then(Now() + aFromNow);
       
   206 		TTimedRect tRect(aType, scheduledRect, then, aWindow);
       
   207 
       
   208 		const TInt error = iTimedDrawRect.InsertInOrderAllowRepeats(tRect,TTimedRect::Compare);
       
   209 		if (KErrNone == error)
       
   210 	   		{
       
   211 			if (iScheduled)
       
   212 				{
       
   213 				if (then < iNext)
       
   214 					{
       
   215 					iNext = then;
       
   216 					}
       
   217 				}
       
   218 			else
       
   219 				{
       
   220 				iNext = then;
       
   221 				iScheduled = ETrue;
       
   222 				}
       
   223 			// remove further futures that are completely contained
       
   224 			TInt count = iTimedDrawRect.Count();
       
   225 			for(TInt i=0; i<count; i++)
       
   226 				{
       
   227 				const TTimedRect& future = iTimedDrawRect[i];
       
   228 				if (future.iWindow != aWindow) // only check futures for the window/floating sprite/screen we're scheduling
       
   229 					continue;
       
   230 				if(future.iTime.Int64() > then.Int64())
       
   231 					{
       
   232 					TRect rect(scheduledRect);
       
   233 					rect.BoundingRect(future.iRect);
       
   234 					if(rect == scheduledRect) // future is completely contained within scheduledRect
       
   235 						{
       
   236 						iTimedDrawRect.Remove(i);
       
   237 						count--;
       
   238 						i--;
       
   239 						}
       
   240 					}
       
   241 				}
       
   242 			CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen,iNext);
       
   243 
       
   244 			// Blue rectangles for scheduled animations
       
   245 			DEBUG_RECT(TRgb(0x00, 0x00, 0xFF),TRgb(0x00, 0x00, 0xFF, 0x20),&aRect);
       
   246 			}
       
   247 		}
       
   248 	}
       
   249 
       
   250 TBool CScreenRedraw::IsScheduled(TAnimType aType, const TRect& aRect, CWsWindow* aWindow) const
       
   251 	{
       
   252 	TRect rect(aRect);
       
   253 	if(aWindow)
       
   254 		{
       
   255 		rect.Move(-aWindow->Origin()); //convert to window coordinates
       
   256 		}
       
   257 	
       
   258 	const TInt count(iTimedDrawRect.Count());
       
   259 	for(TInt i=0; i<count; i++)
       
   260 		{
       
   261 		if ((iTimedDrawRect[i].iType == aType) && 
       
   262 				(iTimedDrawRect[i].iRect == rect) && 
       
   263 				(iTimedDrawRect[i].iWindow == aWindow))
       
   264 			{
       
   265 			return ETrue;
       
   266 			}
       
   267 		}
       
   268 	return EFalse;
       
   269 	}
       
   270 
       
   271 // This adds a region to the stored invalid region.
       
   272 // The invalid region is the area of the screen that needs to be redrawn in addition to any animations.
       
   273 // The draw region is the area of the screen on which only the top window needs to be redrawn.
       
   274 // If the top window has transparency, this can only be true when it has been made newly visible.
       
   275 // The value of aSchedule could be determined automatically from iAnimating, but passing it this way
       
   276 // allows us to have the assert, which is a very valuable assert.
       
   277 void CScreenRedraw::AddRedrawRegion(const TRegion& aRegion, TBool aSchedule, TRedrawDepth aDepth)
       
   278 	{
       
   279 	WS_ASSERT_DEBUG(!iAnimating || !aSchedule, EWsPanicScheduledRedraw);
       
   280 
       
   281 	if(aRegion.CheckError())
       
   282 		{
       
   283 		iInvalid.ForceError();
       
   284 
       
   285 		if (aSchedule)
       
   286 			ScheduleRedraw();
       
   287 		}
       
   288 	else if(aRegion.Count()) // often called despite window not being visible
       
   289 		{
       
   290 		if (aDepth == ERedrawAll)
       
   291 			{
       
   292 			// red lines for an invalid region which is ready to be drawn
       
   293 			DEBUG_REGION(TRgb(0xFF, 0x00, 0x00),TRgb(0xFF, 0x00, 0x00, 0x20),&aRegion);
       
   294 			iInvalid.Union(aRegion);
       
   295 			
       
   296 			if (aSchedule)
       
   297 				ScheduleRedraw();
       
   298 			}
       
   299 		else
       
   300 			{
       
   301 			// yellow lines for a valid region which we will draw on top of
       
   302 			DEBUG_REGION(TRgb(0xFF, 0xFF, 0x00),TRgb(0xFF, 0xFF, 0x00, 0x20),&aRegion);
       
   303 				
       
   304 			iTopElement.Union(aRegion);
       
   305 			
       
   306 			if (aSchedule)
       
   307 				ScheduleRedraw();			
       
   308 			}
       
   309 		}
       
   310 	}
       
   311 
       
   312 // This causes any asynchronously scheduled redraw to happen immediately
       
   313 // It should be avoided where possible for performance reasons, but is 
       
   314 // needed whenever the redraw store is discarded for a window which still
       
   315 // has a redraw region pending.
       
   316 // @note This method always attempts to DoRedrawNow(), even if currently
       
   317 //		 animating. In this context, animation is a frame update. With NGA
       
   318 // 		 that update completes at some point in the future. If you get a request
       
   319 //		 to DoRedrawNow() the expectation is that all updates scheduled on or 
       
   320 //		 before that point in time will have completed by the time the call 
       
   321 //		 returns. An update may have been scheduled during a current (asynchronous)
       
   322 //		 Animate call...the animation scheduler has this knowledge, so let it
       
   323 //		 decide what to do.
       
   324 
       
   325 void CScreenRedraw::DoRedrawNow()
       
   326 	{
       
   327 	CWsTop::WindowServer()->AnimationScheduler()->DoRedrawNow(iScreen);
       
   328 	}
       
   329 	
       
   330 #ifdef USE_DEBUG_REGIONS
       
   331 void CScreenRedraw::DebugRect(TRgb aColor, TRgb aFill, const TRect* aRect)
       
   332 	{
       
   333 	if (aRect)
       
   334 		{
       
   335 		CFbsBitGc * gc = iScreen.GetBitGc();
       
   336 		gc->SetPenColor(aColor);
       
   337 		gc->SetPenStyle(CGraphicsContext::ESolidPen);
       
   338 		gc->SetPenSize(TSize(2,2));
       
   339 		gc->SetBrushColor(aFill);
       
   340 		gc->SetBrushStyle(CGraphicsContext::ESolidBrush);
       
   341 		TRect smaller = *aRect;
       
   342 		smaller.iBr.iX -= 1;
       
   343 		smaller.iBr.iY -= 1;
       
   344 		gc->DrawRect(smaller);
       
   345 		iScreen.Update();
       
   346 		}
       
   347 	}
       
   348 
       
   349 void CScreenRedraw::DebugRegion(TRgb aColor, TRgb aFill, const TRegion * aRegion)
       
   350 	{
       
   351 	if (aRegion)
       
   352 		{
       
   353 		CFbsBitGc * gc = iScreen.GetBitGc();
       
   354 		gc->SetPenColor(aColor);
       
   355 		gc->SetPenStyle(CGraphicsContext::ESolidPen);
       
   356 		gc->SetPenSize(TSize(2,2));
       
   357 		gc->SetBrushColor(aFill);
       
   358 		gc->SetBrushStyle(CGraphicsContext::ESolidBrush);
       
   359 		for (const TRect *rect = aRegion->RectangleList(); rect - aRegion->RectangleList() < aRegion->Count(); ++rect)
       
   360 			{
       
   361 			TRect smaller = *rect;
       
   362 			smaller.iBr.iX -= 1;
       
   363 			smaller.iBr.iY -= 1;
       
   364 			gc->DrawRect(smaller);
       
   365 			}
       
   366 		iScreen.Update();
       
   367 		}
       
   368 	}
       
   369 #endif 
       
   370 
       
   371 void CScreenRedraw::OnAnimation(TRequestStatus* aFinished)
       
   372 	{
       
   373 	LOG_SCREEN_REDRAW_START
       
   374 	WS_ASSERT_ALWAYS(!iAnimating,EWsPanicAnimationAlreadyAnimating);
       
   375 	WS_ASSERT_ALWAYS(iScheduled,EWsPanicAnimationNotScheduled);
       
   376 	iAnimating = ETrue;
       
   377 	iScheduled = EFalse;
       
   378 
       
   379 	const TBool changeTracking = iScreen.ChangeTracking();
       
   380 	
       
   381  	const TRegionFix<1> fallbackRegion(iScreen.RootWindow()->Abs());
       
   382 
       
   383 	CWsActiveScheduler::Static()->PrepareDraw();
       
   384 	
       
   385 	// Calculate any updates required by region changes:
       
   386 	RegionUpdate();
       
   387 
       
   388 	// Use the timed rectangles to mark screen, window or floating sprite as dirty
       
   389 	RWsRegionBuf<10> floatingSpriteDirtyRegion;
       
   390  	const TBool futureAnimationRequired = ScheduleTimedRects(floatingSpriteDirtyRegion);
       
   391  	if (floatingSpriteDirtyRegion.CheckError())
       
   392  		{
       
   393  		floatingSpriteDirtyRegion.Reset();
       
   394  		floatingSpriteDirtyRegion.Copy(fallbackRegion);
       
   395  		}
       
   396  	
       
   397  	TWalkWindowTreeSchedule* scheduler = NULL;
       
   398  	TWalkWindowListSchedule windowScheduler(iScheduledWindowList, iInvalid); //ChangeTracking
       
   399 	if (!changeTracking)
       
   400 		{
       
   401 		// Animating rectangles could cause iInvalid to overlap iTopElement, in which case iTopElement won't work.
       
   402 		iTopElement.SubRegion(iInvalid);
       
   403 		iTopElement.Intersect(iScreen.RootWindow()->WindowArea());
       
   404 		iTopElement.Tidy();
       
   405 		// Anything in the top element is implicitly invalid
       
   406 		iInvalid.Union(iTopElement);
       
   407 		iInvalid.Intersect(iScreen.RootWindow()->WindowArea());
       
   408 		iInvalid.Tidy();
       
   409 		
       
   410 		if(iInvalid.CheckError())
       
   411 			{
       
   412 			iTopElement.Reset();
       
   413 			iInvalid.Reset();
       
   414 			iInvalid.Copy(fallbackRegion);
       
   415 			}
       
   416 		}
       
   417 	else 
       
   418 		{
       
   419 		// In ChangeTracking mode, iInvalid is only used to tell the render stage
       
   420 		// which part of the screen needs updating.
       
   421 		iInvalid.Reset();
       
   422 		iInvalid.Copy(floatingSpriteDirtyRegion);
       
   423 		scheduler = &windowScheduler;
       
   424 		windowScheduler.WalkWindowList();
       
   425 		CWsTop::TriggerRedraws(iScreen.RootWindow()); //In case WalkWindowList did queue a request for the client to provide draw commands
       
   426 		iInvalid.Tidy();
       
   427 		if(iInvalid.CheckError())
       
   428 			{
       
   429 			iInvalid.Reset();
       
   430 			iInvalid.Copy(fallbackRegion);
       
   431 			}
       
   432 		}
       
   433 		
       
   434 	// At this point, if the DEBUG_REGION is being used:
       
   435 	// Red represents invalid regions that need to be redrawn completely.
       
   436 	// Yellow represents regions that only need the top window to be drawn.
       
   437 	// Blue represents regions which are being animated server side.
       
   438 	if (iRenderScheduled || !iInvalid.IsEmpty() || iQuickFadeList.Count() > 0)  
       
   439 		{
       
   440 		iRenderScheduled = EFalse;
       
   441 		
       
   442 		TWalkWindowTreeScheduleRegions regionScheduler(iInvalid, iTopElement); //!ChangeTeacking
       
   443 		TWalkWindowTreeScheduleFallback fallbackScheduler(iScreen.FallbackMap());//!ChangeTeacking
       
   444 
       
   445 		RWsRegionBuf<20> animationRegion;
       
   446 		
       
   447 		if (!changeTracking)
       
   448 			{	
       
   449 			animationRegion.Copy(iInvalid);
       
   450 			AddQuickFadeableRegions(animationRegion);
       
   451 			if (animationRegion.CheckError())
       
   452 				{
       
   453 				animationRegion.Reset();
       
   454 				animationRegion.Copy(fallbackRegion);
       
   455 				}
       
   456 			iAnimationRegion = &animationRegion; //iAnimationRegion must be reset to NULL before the call stack unwinds.
       
   457 			
       
   458 			scheduler = &regionScheduler;
       
   459 			iScreen.RootWindow()->WalkWindowTree(regionScheduler,EWalkChildren);
       
   460 			if (!regionScheduler.ScheduledRegionsOk())
       
   461 				{
       
   462 				// our region calculations for what to draw failed at some point.
       
   463 				// From this point on we MUST NOT rely on allocating memory
       
   464 				scheduler = &fallbackScheduler;
       
   465 				iScreen.FallbackMap()->Prepare();
       
   466 				iScreen.RootWindow()->WalkWindowTree(fallbackScheduler,EWalkChildren);
       
   467 				iAnimationRegion = iScreen.FallbackMap()->Region();
       
   468 				}
       
   469 			}
       
   470 		else
       
   471 			{
       
   472 			iAnimationRegion = &iInvalid;
       
   473 			}
       
   474 		
       
   475 		CWsActiveScheduler::Static()->StartDraw();
       
   476 		CWsMemoryManager::Static()->EnableReserve();
       
   477 		
       
   478 		// Redraw debug regions more brightly than before:
       
   479 		DEBUG_REGION(TRgb(0xFF, 0x00, 0x00),TRgb(0xFF, 0x00, 0x00, 0x80),iAnimationRegion);
       
   480 		DEBUG_REGION(TRgb(0xFF, 0xFF, 0x00),TRgb(0xFF, 0xFF, 0x00, 0x80),&iTopElement);
       
   481 		
       
   482 		// Pipe the drawing into the first render stage:
       
   483 		iRenderStages->Begin(iAnimationRegion);
       
   484 		
       
   485 		RWsRegionBuf<10> accumulatedDrawing;
       
   486 		
       
   487 		MWsGraphicsContext * stageGc = static_cast<MWsGraphicsContext*>(iRenderStages->ResolveObjectInterface(KMWsGraphicsContext));
       
   488 		for (CWsWindow * win = scheduler->HeadWindow(); (win!=NULL); win = win->NextScheduled())
       
   489 			{
       
   490 			if(!changeTracking)
       
   491 					accumulatedDrawing.Union(scheduler->WindowRegion(*win));
       
   492 			
       
   493 			Render(*win, *stageGc, *scheduler);
       
   494 			}
       
   495 
       
   496 		if(!changeTracking && !accumulatedDrawing.CheckError())
       
   497 			{
       
   498 			//Fade any region of the screen scheduled for fading which has not been redrawn,
       
   499 			DoQuickFade(stageGc, accumulatedDrawing);
       
   500 			}
       
   501 		accumulatedDrawing.Reset();
       
   502 		
       
   503 		//We limit floating sprite drawing to regions already touched
       
   504 		iScreen.SpriteManager()->DrawFloatingSprites(stageGc, iScreen.ChangeTracking() ? floatingSpriteDirtyRegion : *iAnimationRegion);
       
   505 		
       
   506 		iRenderStages->End(aFinished);
       
   507 		stageGc = NULL; //we're not allowed to draw outside Begin()/End()
       
   508 
       
   509 #if defined(__WINS__) && defined(_DEBUG)
       
   510 		MWsDebugBar * debugBar = static_cast<MWsDebugBar*>(iRenderStages->ResolveObjectInterface(KMWsDebugBar));
       
   511 		if (debugBar) //optional for the licensees
       
   512 			{
       
   513 			if (CDebugBar* dbg = iScreen.DebugBar())
       
   514 				{	
       
   515 				RArray<TPtrC> debugText;
       
   516 				dbg->DebugBarInfo(debugText);
       
   517 				debugBar->DrawDebugBar(debugText.Array());
       
   518 				debugText.Close();
       
   519 				}
       
   520 			}
       
   521 #endif
       
   522 		
       
   523 		iScheduledWindowList = NULL;
       
   524 		CWsMemoryManager::Static()->DisableReserve();
       
   525 
       
   526 #ifdef USE_DEBUG_FRAME_CAPTURE
       
   527 		if (iFrameCapture)
       
   528 			{
       
   529 			CaptureFrame(iAnimationRegion);
       
   530 			}
       
   531 #endif
       
   532 		
       
   533 		// DEBUG_REGION does not work with render stages.
       
   534 		// These comments refer to what used to happen.
       
   535 		
       
   536 		// At this point, if the DEBUG_REGION is being used, there should usually be only green regions
       
   537 		// displayed.  If we see red or yellow, then something didn't get redrawn that should have been.
       
   538 		// If we see purple then a window has disobeyed the const setting on the region to draw.
       
   539 		// Red or yellow is valid - a window can decide it isn't ready to draw yet - purple is very bad.
       
   540 		
       
   541 		//iScreen.Update();
       
   542 		
       
   543 		// At this point, if the DEBUG_REGION is being used, there should be no regions visible
       
   544 		// of any colour.  If we see green, then it means an area of the screen was drawn to which
       
   545 		// wasn't invalid, or the screen update call failed.  The former is more likely.
       
   546 		// If we still see red or yellow it is a region that is not yet ready to draw.
       
   547 
       
   548 		const TRect* rect = iAnimationRegion->RectangleList();
       
   549 		TInt pixels = 0;
       
   550 		for(TInt r = iAnimationRegion->Count(); r>0; r--)
       
   551 			{
       
   552 			pixels += (rect->Width()*rect->Height());
       
   553 			rect++;
       
   554 			}
       
   555 		CWsActiveScheduler::Static()->StopDraw(pixels);
       
   556 		
       
   557 		TWindowServerEvent::NotifyScreenDrawingEvent(iAnimationRegion);
       
   558 
       
   559 		iAnimationRegion = NULL; //iAnimationRegion must be reset to NULL before the call stack unwinds.
       
   560 		iInvalid.Reset();
       
   561 		animationRegion.Reset();
       
   562 		}
       
   563 	else
       
   564 		{
       
   565 		// There was nothing to compose. Signal that composition is complete.
       
   566 		if (aFinished) 
       
   567 			{
       
   568 			*aFinished = KRequestPending;
       
   569 			User::RequestComplete(aFinished, KErrNone);
       
   570 			}
       
   571 		
       
   572 		CWsActiveScheduler::Static()->CancelPrepare();
       
   573 		}
       
   574 	
       
   575 	floatingSpriteDirtyRegion.Reset();
       
   576 	iInvalid.Reset();
       
   577 	iTopElement.Reset();
       
   578 	iAnimating = EFalse;
       
   579 	
       
   580 	if (futureAnimationRequired && iTimedDrawRect.Count() > 0 && !iScheduled)
       
   581 		{
       
   582 		// If this flag is set then it means there were already some animations scheduled when we ran,
       
   583 		// but they themselves didn't run.  We need to make sure we have _something_ scheduled.
       
   584 		CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen, iTimedDrawRect[0].iTime);
       
   585 		iScheduled = ETrue;
       
   586 		}
       
   587 	
       
   588 	if(iObserver)
       
   589 		{
       
   590 		iObserver->ScreenUpdated(iScreen.ScreenNumber());
       
   591 		iObserver=NULL; //once signalled we are never going to call it again
       
   592 		}
       
   593 	LOG_SCREEN_REDRAW_END
       
   594 	}
       
   595 
       
   596 void CScreenRedraw::AddQuickFadeableRegions(TRegion& aRegion)
       
   597 	{
       
   598 	if (iQuickFadeList.Count() > 0)
       
   599 		{
       
   600 		for (TInt idx = iQuickFadeList.Count() - 1; idx >= 0; idx --)
       
   601 			{
       
   602 			CWsWindow* win = iQuickFadeList[ idx ];
       
   603 
       
   604 			if ( !win->IsDSAHost() )
       
   605 				{
       
   606 				aRegion.Union(win->QuickFadeRegion() );
       
   607 				}
       
   608 			}
       
   609 		aRegion.Tidy();
       
   610 		}
       
   611 	}
       
   612 
       
   613 void CScreenRedraw::DoQuickFade(MWsGraphicsContext* aGc, TRegion& aAccumulatedDrawing)
       
   614 	{
       
   615 	if ( iQuickFadeList.Count() > 0 )
       
   616 		{
       
   617 		for ( TInt idx = iQuickFadeList.Count() - 1; idx >= 0 ; idx -- )
       
   618 			{
       
   619 
       
   620 			CWsWindow* win = iQuickFadeList[ idx ];
       
   621 			
       
   622 			if ( !win->IsDSAHost() )
       
   623 				{				
       
   624 				STACK_REGION winFadeRgn;				
       
   625 				winFadeRgn.Copy( win->QuickFadeRegion() );
       
   626 				winFadeRgn.SubRegion( aAccumulatedDrawing );
       
   627 				winFadeRgn.Tidy();
       
   628 				if ( !winFadeRgn.IsEmpty() && !winFadeRgn.CheckError() )
       
   629 					{ // now fade any region that has not been redrawn (via win->Render())
       
   630 					win->Fade( aGc, winFadeRgn );
       
   631 					aAccumulatedDrawing.Union( winFadeRgn );	      		
       
   632 					}		      	
       
   633 	  			winFadeRgn.Close();
       
   634 				}
       
   635 			}
       
   636 	
       
   637 		iQuickFadeList.Reset();
       
   638 		}
       
   639 	}
       
   640 
       
   641 /**
       
   642 This function will iterate the timed rectangles and find any animation or sprite 
       
   643 that are due to be scheduled for render now. Then schedule them and remove them 
       
   644 from iTimedDrawRect.
       
   645 @return ETrue if iTimedDrawRect still contains future animations
       
   646 */
       
   647 TBool CScreenRedraw::ScheduleTimedRects(TRegion& aScheduledFloatingSpriteRegion)
       
   648  	{
       
   649 	iNow.UniversalTime();
       
   650 	TInt count(iTimedDrawRect.Count());
       
   651 	TBool futureAnimationRequired = EFalse;
       
   652 	while (0 < count)
       
   653 		{
       
   654 		if(iTimedDrawRect[0].iTime.Int64() <= iNow.Int64())
       
   655 			{
       
   656 			if (iScreen.ChangeTracking())
       
   657 				{
       
   658 				switch(iTimedDrawRect[0].iType)
       
   659 					{
       
   660 					case ECrpAnim:
       
   661 						{
       
   662 						CWsWindow* win = iTimedDrawRect[0].iWindow;
       
   663 						WS_ASSERT_DEBUG(win,EWsPanicWindowNull);
       
   664 						if(!win->IsTrackingVisibleRegion() || (win->IsTrackingVisibleRegion() && !win->VisibleRegion().IsEmpty()))
       
   665 							{
       
   666 							TRegionFix<1> region;
       
   667 							region.AddRect(iTimedDrawRect[0].iRect);
       
   668 							win->AddDirtyWindowRegion(region);
       
   669 							ScheduleWindow(win);
       
   670 							}
       
   671 						break;
       
   672 						}
       
   673 					case EWindowAnim:
       
   674 					case ESpriteAnim:
       
   675 					case ETextCursor:
       
   676 					case EWindowSprite:
       
   677 						{
       
   678 						CWsWindow* win = iTimedDrawRect[0].iWindow;
       
   679 						WS_ASSERT_DEBUG(win,EWsPanicWindowNull);
       
   680 						if(!win->IsTrackingVisibleRegion() || (win->IsTrackingVisibleRegion() && !win->VisibleRegion().IsEmpty()))
       
   681 							{
       
   682 							TRegionFix<1> region;
       
   683 							region.AddRect(iTimedDrawRect[0].iRect);
       
   684 							win->AddDirtySpriteRegion(region);
       
   685 							ScheduleWindow(win);
       
   686 							}
       
   687 						break;
       
   688 						}
       
   689 					case EFloatingSprite:
       
   690 					case EFloatingSpriteAnim:
       
   691 						{
       
   692 						aScheduledFloatingSpriteRegion.AddRect(iTimedDrawRect[0].iRect);
       
   693 						break;
       
   694 						}
       
   695 					}
       
   696 				
       
   697 				TRect screenRect(iTimedDrawRect[0].iRect);
       
   698 				if(iTimedDrawRect[0].iWindow)
       
   699 					{
       
   700 					screenRect.Move(iTimedDrawRect[0].iWindow->Origin()); // convert to screen coordinates
       
   701 					}	
       
   702 				}
       
   703 			else
       
   704 				{ 
       
   705 				// schedule a screen dirty rect
       
   706 				iInvalid.AddRect(iTimedDrawRect[0].iRect);
       
   707 				}
       
   708 			iTimedDrawRect.Remove(0);
       
   709 			count--;
       
   710 			}
       
   711 		else
       
   712 			{
       
   713 			futureAnimationRequired = ETrue;	
       
   714 			break;
       
   715 			}
       
   716 		}
       
   717 	return futureAnimationRequired;
       
   718  	}
       
   719 
       
   720 void CScreenRedraw::Render(CWsWindow& aWin, MWsGraphicsContext& aGc, const TWalkWindowTreeSchedule& aScheduler)
       
   721 	{
       
   722 	const TRegion* windowRegion = &(aScheduler.WindowRegion(aWin));
       
   723 	const TRegion* spriteRegion = &(aScheduler.SpriteRegion(aWin));
       
   724 
       
   725 	if(windowRegion->IsEmpty() && spriteRegion->IsEmpty()) 
       
   726 	    return; //Don't call CWsWindow::Render if there is nothing that can be rendered 
       
   727 	
       
   728 	//Make sure we don't try to draw outside screen
       
   729 	STACK_REGION clippedWindowRegion;
       
   730 	if(!windowRegion->IsContainedBy(iScreen.RootWindow()->Abs()))
       
   731 		{
       
   732 		TRegionFix<1> screen(iScreen.RootWindow()->Abs());
       
   733 		clippedWindowRegion.Intersection(*windowRegion, screen);
       
   734 		windowRegion = &clippedWindowRegion;
       
   735 		}
       
   736 	STACK_REGION clippedSpriteRegion;
       
   737 	if(!spriteRegion->IsContainedBy(iScreen.RootWindow()->Abs()))
       
   738 		{
       
   739 		TRegionFix<1> screen(iScreen.RootWindow()->Abs());
       
   740 		clippedSpriteRegion.Intersection(*spriteRegion, screen);
       
   741 		spriteRegion = &clippedSpriteRegion;
       
   742 		}	
       
   743 	
       
   744 	if(!windowRegion->CheckError() && !spriteRegion->CheckError())
       
   745 		{
       
   746 		// Purple regions are about to be drawn
       
   747 		DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80), windowRegion);
       
   748 		DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80), spriteRegion);
       
   749 		
       
   750 		aWin.Render(aGc, *windowRegion, *spriteRegion); //When not in ChangeTracking mode, both windowRegion and spriteRegion points to the same region
       
   751 		aWin.ClearScheduledRegion();
       
   752 		aWin.ClearScheduledSpriteRegion();
       
   753 		
       
   754 		// Green regions have been drawn
       
   755 		DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80), windowRegion);
       
   756 		DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80), spriteRegion);
       
   757 		}
       
   758 	else
       
   759 		{
       
   760 		OomRender(aWin, aGc, aScheduler);		
       
   761 		}
       
   762 	
       
   763 	clippedSpriteRegion.Close();
       
   764 	clippedWindowRegion.Close();
       
   765 	}
       
   766 
       
   767 void CScreenRedraw::OomRender(CWsWindow& aWin, MWsGraphicsContext& aGc, const TWalkWindowTreeSchedule& aScheduler)
       
   768 	{	
       
   769 	const TRegion* windowRegion = &(aScheduler.WindowRegion(aWin));
       
   770 	const TRegion* spriteRegion = &(aScheduler.SpriteRegion(aWin));
       
   771 
       
   772 	WS_ASSERT_DEBUG(!(windowRegion->IsEmpty() && spriteRegion->IsEmpty()), EWsPanicRegionNull);
       
   773 	
       
   774 	TRect validWindow(aWin.Abs());
       
   775 	validWindow.Intersection(iScreen.RootWindow()->Abs());
       
   776 	
       
   777     TRegionFix<1> fallbackRegion(validWindow);
       
   778     
       
   779     if(windowRegion->CheckError())
       
   780         windowRegion = &fallbackRegion;
       
   781     if(spriteRegion->CheckError())
       
   782         spriteRegion = &fallbackRegion;
       
   783     
       
   784     // Purple regions are about to be drawn
       
   785     DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80), windowRegion);
       
   786     DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80), spriteRegion);
       
   787     
       
   788     aWin.Render(aGc, *windowRegion, *spriteRegion); //When not in ChangeTracking mode, both windowRegion and spriteRegion points to the same region
       
   789     aWin.ClearScheduledRegion();
       
   790     aWin.ClearScheduledSpriteRegion();
       
   791     
       
   792     // Green regions have been drawn
       
   793     DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80), windowRegion);
       
   794     DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80), spriteRegion);	
       
   795 	}
       
   796 
       
   797 //
       
   798 void CScreenRedraw::DiscardAllSchedules()
       
   799 	{
       
   800 	ASSERT(!iAnimating);
       
   801 	
       
   802 	iTimedDrawRect.Reset();
       
   803 	iInvalid.Reset();
       
   804 	}
       
   805 
       
   806 /**
       
   807 Indicates that a window has moved or changed ordinal position so that the visible regions
       
   808 of all windows needs to be recalculated
       
   809 */
       
   810 void CScreenRedraw::ScheduleRegionUpdate(const TRegion* aDefinitelyDirty)
       
   811 	{
       
   812 	if (iScreen.ChangeTracking() && iScreen.WindowVisibilityNotifier())
       
   813 		return;
       
   814 
       
   815 	iRegionUpdateScheduled = ETrue;
       
   816 	ScheduleRedraw();
       
   817 	if(!iScreen.ChangeTracking() && aDefinitelyDirty)
       
   818 		{
       
   819 		iInvalid.Union(*aDefinitelyDirty);
       
   820 		// Cyan regions for invalidations caused by this:
       
   821 		DEBUG_REGION(TRgb(0x00, 0xFF, 0xFF),TRgb(0x00, 0xFF, 0xFF, 0x20),aDefinitelyDirty);
       
   822 		}
       
   823 	}
       
   824 
       
   825 /**
       
   826 Only used in CHANGETRACKING mode.
       
   827 Windows are scheduled to:
       
   828 - if required, ask client to validate (from lower loop)
       
   829 - render the dirty window region
       
   830 */
       
   831 void CScreenRedraw::ScheduleWindow(CWsWindow* aWindow)
       
   832 	{
       
   833 	// Add a scheduled window to the linked list, ignoring duplicates
       
   834 	CWsWindow* win = iScheduledWindowList;
       
   835 	while (win && win != aWindow)
       
   836 		{
       
   837 		win = win->NextScheduled();
       
   838 		}
       
   839 	if (!win)
       
   840 		{
       
   841 		aWindow->SetNextScheduled(iScheduledWindowList);
       
   842 		iScheduledWindowList = aWindow;
       
   843 		}
       
   844 	ScheduleRedraw();
       
   845 	}
       
   846 
       
   847 void CScreenRedraw::RemoveFromScheduledList(CWsWindow* aWindow)
       
   848 	{
       
   849 	// Search for the window
       
   850 	CWsWindow* win = iScheduledWindowList;
       
   851 	CWsWindow* previous = NULL;
       
   852 	while (win && win != aWindow)
       
   853 		{
       
   854 		previous = win;
       
   855 		win = win->NextScheduled();
       
   856 		}
       
   857 	if (win)
       
   858 		{
       
   859 		// Found it, remove from list
       
   860 		if (win == iScheduledWindowList)
       
   861 			{
       
   862 			iScheduledWindowList = win->NextScheduled();
       
   863 			}
       
   864 		else
       
   865 			{
       
   866 			previous->SetNextScheduled(win->NextScheduled());
       
   867 			}
       
   868 		}
       
   869 	}
       
   870 
       
   871 void CScreenRedraw::RemoveFromTimedDrawList(CWsWindow* aWindow)
       
   872 	{
       
   873 	if(aWindow)
       
   874 		{	
       
   875 		TInt count(iTimedDrawRect.Count());
       
   876 		TInt index = 0;
       
   877 		while(index < count)
       
   878 			{
       
   879 			if (iTimedDrawRect[index].iWindow == aWindow)
       
   880 				{
       
   881 				iTimedDrawRect.Remove(index);
       
   882 				--count;
       
   883 				}
       
   884 			else
       
   885 				{
       
   886 				++index;
       
   887 				}
       
   888 			}
       
   889 		}
       
   890 	}
       
   891 
       
   892 /**
       
   893 Recalculates visible regions and schedules redraws or queues redraw events in response to
       
   894 any changes
       
   895 */
       
   896 void CScreenRedraw::RegionUpdate()
       
   897 	{
       
   898 	TBool somethingScheduled = EFalse;
       
   899 
       
   900 	if (iVisibilityUpdateScheduled)
       
   901 		{
       
   902 		iVisibilityUpdateScheduled = EFalse;
       
   903 		somethingScheduled = ETrue;
       
   904 		MWsWindowVisibilityNotifier* const notifier = iScreen.WindowVisibilityNotifier();
       
   905 		if(notifier)
       
   906 			{
       
   907 			notifier->SendVisibilityChanges(); // Should result in one callback to SetWindowVisibility for each window subscribing for visible region updates
       
   908 			}
       
   909 		}
       
   910 
       
   911 	if (iRegionUpdateScheduled)
       
   912 		{
       
   913 		iRegionUpdateScheduled = EFalse;
       
   914 		somethingScheduled = ETrue;
       
   915 		TWalkWindowTreeUpdateRegions updater(iScreen);
       
   916 		updater.Walk();
       
   917 		
       
   918 		for ( TInt idx = iQuickFadeList.Count() - 1; idx >= 0; idx-- )
       
   919 			{
       
   920 			CWsWindow* win = iQuickFadeList[ idx ];
       
   921 			const TRegion& quickFadeRegion = win->QuickFadeRegion();
       
   922 			//If QuickFadeRegion().IsEmpty() we should remove the window from iQuickFadeList.
       
   923 			//And if this window has not been drawn to the screen, then it is not possible to quick fade it.
       
   924 			if (quickFadeRegion.IsEmpty() || !win->HasBeenDrawnToScreen())
       
   925 				{
       
   926 				iQuickFadeList.Remove( idx );
       
   927 				}
       
   928 			}
       
   929 		}
       
   930 
       
   931 	if (somethingScheduled)
       
   932 		{
       
   933 		TWsPointer::ReLogPointersCurrentWindows();
       
   934 		CWsTop::TriggerRedraws(iScreen.RootWindow());
       
   935 		}
       
   936 	}
       
   937 
       
   938 /**
       
   939 To be called by MWsWindowVisibilityNotifier (when running in ChangeTracking mode) 
       
   940 in response to MWsWindowVisibilityNotifier::SendVisibilityChanges()  
       
   941 */
       
   942 void CScreenRedraw::SetWindowVisibility(const MWsWindow& aWindow, const TRegion& aVisibleRegion)
       
   943 	{
       
   944 	CWsWindow& win = static_cast<CWsWindow&>(const_cast<MWsWindow&>(aWindow));
       
   945 	WS_ASSERT_DEBUG(win.IsTrackingVisibleRegion(), EWsPanicVisibleRegionTracking);
       
   946 	WS_ASSERT_DEBUG(!aVisibleRegion.CheckError(), EWsPanicRegion);
       
   947 	
       
   948 	if(aVisibleRegion.IsEmpty() && !win.VisibleRegion().IsEmpty())
       
   949 		{
       
   950 		win.ClearVisibleRegion();
       
   951 		}
       
   952 	else if(!aVisibleRegion.IsEmpty() && !aVisibleRegion.CheckError())
       
   953 		{
       
   954 		// Assert that aVisibleRegion is contained by aWin
       
   955 		TRect bounds = win.AbsRect();
       
   956 		bounds.Resize(1,1);
       
   957 		WS_ASSERT_DEBUG(bounds.Contains(aVisibleRegion.BoundingRect().iTl), EWsPanicRegion);
       
   958 		WS_ASSERT_DEBUG(bounds.Contains(aVisibleRegion.BoundingRect().iBr), EWsPanicRegion);
       
   959 		win.SetVisibleRegion(aVisibleRegion, NULL);
       
   960 		}
       
   961 	else if(aVisibleRegion.CheckError())
       
   962 		{
       
   963 		const TRegionFix<1> fallback(win.Abs());
       
   964 		win.SetVisibleRegion(fallback, NULL);
       
   965 		}
       
   966 	}
       
   967 
       
   968 /**
       
   969 To be called by MWsWindowVisibilityNotifier (when running in ChangeTracking mode) when the 
       
   970 iVisibleRegion is changed for a window that subscribes for this information. The visible region 
       
   971 of the window has not been updated yet at the time of this function call, but the new metrics will be retrieved 
       
   972 from MWsWindowVisibilityNotifier (through a call to MWsWindowVisibilityObserver::SetWindowVisibility())
       
   973 and set to each window next time OnAnimation is called.   
       
   974 */
       
   975 void CScreenRedraw::VisibilityChanged()
       
   976 	{
       
   977 	iVisibilityUpdateScheduled = ETrue;
       
   978 	ScheduleRedraw();
       
   979 	}
       
   980 
       
   981 void CScreenRedraw::SetObserver(MWsScreenRedrawObserver* aObserver)
       
   982 	{
       
   983 	iObserver = aObserver;
       
   984 	}
       
   985 
       
   986 /**
       
   987 Returns ETrue if an update or animation is scheduled.
       
   988 
       
   989 Note: Now that WSERV surface and composition updates are asynchronous (with NGA)
       
   990 it is possible for this method to return EFalse, even if the last update has
       
   991 not been completed by the rendering pipeline. This is dependant on the configuration
       
   992 and implementation of render stages that make up the rendering pipeline.
       
   993 
       
   994 If in doubt, it is best to call CScreenRedraw::DoRedrawNow(), which will not return
       
   995 untill all updates have been signalled as being complete (note that if signalling
       
   996 is not used, then even this cannot guarantee completion).
       
   997 */ 
       
   998 TBool CScreenRedraw::IsUpdatePending()
       
   999 	{
       
  1000 	if(iScheduled || iAnimating)
       
  1001 		return ETrue;
       
  1002 	else 
       
  1003 		return EFalse;
       
  1004 	}
       
  1005 
       
  1006 /**
       
  1007  Overidding MWsObjectProvider
       
  1008 */
       
  1009 TAny* CScreenRedraw::ResolveObjectInterface(TUint aTypeId)
       
  1010 	{
       
  1011 	TAny* interface = NULL;
       
  1012 
       
  1013 	switch (aTypeId)
       
  1014 		{
       
  1015 		case KWsScreenRedraw:
       
  1016 			interface = static_cast<MWsScreenRedraw*>(this);
       
  1017 			break;
       
  1018 		}
       
  1019 
       
  1020 	if (!interface)
       
  1021 		{
       
  1022 		interface = iRenderStages->ResolveObjectInterface(aTypeId);
       
  1023 		}
       
  1024 	
       
  1025 	return interface;
       
  1026 	}
       
  1027 
       
  1028 const TRegion * CScreenRedraw::AnimationRegion() const
       
  1029 	{
       
  1030 	if (iAnimating)
       
  1031 		return iAnimationRegion;
       
  1032 	else
       
  1033 		return 0;
       
  1034 	}
       
  1035 
       
  1036 void CScreenRedraw::UpdateDevice()
       
  1037 	{
       
  1038 	//this used to call iScreen->Update, not needed anymore in NGA
       
  1039 	}
       
  1040 
       
  1041 TBool CScreenRedraw::IsQuickFadeScheduled( CWsWindow* aWin ) const
       
  1042 	{
       
  1043 	const TInt idx = iQuickFadeList.Find( aWin );	
       
  1044 	return (idx > KErrNotFound);
       
  1045 	}
       
  1046 
       
  1047 void CScreenRedraw::ScheduleQuickFade( CWsWindow* aWin )
       
  1048 	{
       
  1049 	const TInt idx = iQuickFadeList.Find( aWin );	
       
  1050 	if ( idx == KErrNotFound )
       
  1051 		{ // not yet enlisted		
       
  1052 		if ( KErrNone != iQuickFadeList.Append(aWin) )
       
  1053 			{  // out of resources?
       
  1054 			const TRegion& winReg = aWin->VisibleRegion();
       
  1055 			ScheduleRegionUpdate( &winReg );
       
  1056 			}		
       
  1057 		}
       
  1058 	}
       
  1059 
       
  1060 void CScreenRedraw::RemoveFromQuickFadeList( CWsWindow* aWin )
       
  1061 	{	
       
  1062 	const TInt idx = iQuickFadeList.Find( aWin );	
       
  1063 	if ( idx > KErrNotFound )
       
  1064 		{
       
  1065 		iQuickFadeList.Remove( idx );
       
  1066 		}
       
  1067 	}
       
  1068 
       
  1069 void CScreenRedraw::AcceptFadeRequest( CWsWindow* aWin, TBool aFadeOn )
       
  1070 	{
       
  1071 	if (aFadeOn)
       
  1072 		{
       
  1073 		if (aWin->WinType() != EWinTypeGroup)
       
  1074 			{
       
  1075 			ScheduleQuickFade(aWin);
       
  1076 			ScheduleRegionUpdate(NULL);
       
  1077 			}
       
  1078 		}
       
  1079 	else
       
  1080 		{ // fade off, just initiate redraw
       
  1081 		if ( !aWin->IsDSAHost() )
       
  1082 			{
       
  1083 			AddRedrawRegion(aWin->VisibleRegion() );
       
  1084 			ScheduleRegionUpdate(NULL);
       
  1085 			}
       
  1086 		}
       
  1087 	}
       
  1088 
       
  1089 
       
  1090 #ifdef USE_DEBUG_FRAME_CAPTURE
       
  1091 class TTruncateOverflow : public TDesOverflow
       
  1092 	{
       
  1093 public: //from TDesOverflow
       
  1094 	void Overflow(TDes&) {};
       
  1095 	};
       
  1096 
       
  1097 void CScreenRedraw::CaptureFrame(const TRegion* aRegion)
       
  1098 	{
       
  1099 	MWsScreenDevice* screenDevice = static_cast<MWsScreen&>(iScreen).ObjectInterface<MWsScreenDevice>();
       
  1100 	WS_ASSERT_ALWAYS(screenDevice, EWsPanicScreenDeviceMissing);
       
  1101 	const TSize screenSize(screenDevice->SizeInPixels());
       
  1102 	const TDisplayMode screenDisplayMode(screenDevice->DisplayMode());
       
  1103 
       
  1104 	//copy the whole screen
       
  1105 	TRAPD(err, SetupFrameCaptureResourcesL(screenSize, screenDisplayMode);
       
  1106 	           screenDevice->CopyScreenToBitmapL(iDebugBitmap, TRect(screenSize)));
       
  1107 
       
  1108 	if(err)
       
  1109 		{
       
  1110 		if(wsDebugLog)
       
  1111 			wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, _L("CScreenRedraw::CaptureFrame(): Failed to create resources for screen capture"));
       
  1112 		return;
       
  1113 		}
       
  1114 
       
  1115 	//remove what's not part of the region
       
  1116 	iDebugBitmapGc->Activate(iDebugBitmapDevice);
       
  1117 	
       
  1118 	if(aRegion && !aRegion->IsEmpty() && !aRegion->CheckError())
       
  1119 		{
       
  1120 		RWsRegion inverseRegion;
       
  1121 		inverseRegion.AddRect(TRect(screenSize));
       
  1122 		const TRect* rectList = aRegion->RectangleList();
       
  1123 		for(TInt i = aRegion->Count() - 1; i >= 0; i--)
       
  1124 			{
       
  1125 			inverseRegion.SubRect(rectList[i]);
       
  1126 			}
       
  1127 		if(!inverseRegion.CheckError())
       
  1128 			{
       
  1129 			iDebugBitmapGc->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
       
  1130 			iDebugBitmapGc->SetClippingRegion(inverseRegion);
       
  1131 			iDebugBitmapGc->SetBrushColor(TRgb(55, 55, 55, 0));
       
  1132 			iDebugBitmapGc->Clear();
       
  1133 			iDebugBitmapGc->CancelClippingRegion();
       
  1134 			iDebugBitmapGc->SetDrawMode(CGraphicsContext::EDrawModePEN);
       
  1135 			}
       
  1136 		inverseRegion.Close();
       
  1137 		}
       
  1138 
       
  1139 	//save to file
       
  1140 	const TUint timestamp = User::FastCounter();	
       
  1141 	TFileName filename;
       
  1142 	TTruncateOverflow overflow;
       
  1143 	filename.AppendFormat(iFrameCaptureLocation, &overflow);
       
  1144 	filename.AppendFormat(_L("frame_%010u.mbm"), &overflow, timestamp);
       
  1145 	iDebugBitmap->Save(filename);
       
  1146 
       
  1147 	//log region
       
  1148 	LogRegion(filename, _L(" CScreenRedraw::CaptureFrame() "), aRegion);	
       
  1149 	}
       
  1150 
       
  1151 void CScreenRedraw::SetupFrameCaptureResourcesL(const TSize& aScreenSize, TDisplayMode aScreenDisplayMode)
       
  1152 	{
       
  1153 	//make sure the existing bitmap has the correct display mode
       
  1154 	if(iDebugBitmap && iDebugBitmap->DisplayMode() != aScreenDisplayMode)
       
  1155 		{
       
  1156 		if(iDebugBitmap->SetDisplayMode(aScreenDisplayMode) != KErrNone)
       
  1157 			{
       
  1158 			delete iDebugBitmap;
       
  1159 			iDebugBitmap = NULL;
       
  1160 			delete iDebugBitmapDevice;
       
  1161 			iDebugBitmapDevice = NULL;
       
  1162 			}
       
  1163 		}
       
  1164 
       
  1165 	//make sure the existing bitmap has the correct size
       
  1166 	if(iDebugBitmap && iDebugBitmap->SizeInPixels() != aScreenSize)
       
  1167 		{
       
  1168 		if(iDebugBitmap->Resize(aScreenSize) != KErrNone)
       
  1169 			{
       
  1170 			delete iDebugBitmap;
       
  1171 			iDebugBitmap = NULL;
       
  1172 			delete iDebugBitmapDevice;
       
  1173 			iDebugBitmapDevice = NULL;
       
  1174 			}
       
  1175 		}
       
  1176 
       
  1177 	//make sure the bitmap and bitmap device is created
       
  1178 	if(!iDebugBitmap)
       
  1179 		{
       
  1180 		WS_ASSERT_ALWAYS(!iDebugBitmapDevice, EWsPanicTemp); //this should never occur, they should always be created/destroyed in tandem
       
  1181 		CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
       
  1182 		CleanupStack::PushL(bitmap);
       
  1183 		User::LeaveIfError(bitmap->Create(aScreenSize, aScreenDisplayMode));
       
  1184 
       
  1185 		iDebugBitmapDevice = CFbsBitmapDevice::NewL(bitmap);
       
  1186 		iDebugBitmap = bitmap;
       
  1187 		CleanupStack::Pop(bitmap);
       
  1188 		}
       
  1189 	
       
  1190 	//make sure the gc is created
       
  1191 	if(!iDebugBitmapGc)
       
  1192 		{
       
  1193 		User::LeaveIfError(iDebugBitmapDevice->CreateContext(iDebugBitmapGc));
       
  1194 		}
       
  1195 	}
       
  1196 
       
  1197 void CScreenRedraw::LogRegion(const TDesC& aPrefix, const TDesC& aFunctionName, const TRegion* aRegion)
       
  1198 	{
       
  1199 	if(!wsDebugLog)
       
  1200 		return;
       
  1201 
       
  1202 	TBuf<LogTBufSize> log;
       
  1203 	TTruncateOverflow overflow;
       
  1204 	TInt rectCount = (aRegion == NULL ? 0 : aRegion->Count());
       
  1205 	log.AppendFormat(aPrefix, &overflow);
       
  1206 	log.AppendFormat(aFunctionName, &overflow);
       
  1207 	log.AppendFormat(_L("region [%d,"), &overflow, rectCount);
       
  1208 	if (rectCount > 0)
       
  1209 		{
       
  1210 		const TRect* rectangles = aRegion->RectangleList();
       
  1211 		TBuf<1> comma;
       
  1212 		for (TInt ii = 0; ii < rectCount; ii++)
       
  1213 			{
       
  1214 			TRect current = rectangles[ii];
       
  1215 			log.AppendFormat(_L("%S{{%d,%d},{%d,%d}}"), &overflow, &comma,
       
  1216                              current.iTl.iX,current.iTl.iY,current.iBr.iX,current.iBr.iY);
       
  1217 			comma = _L(",");
       
  1218 			}
       
  1219 		}
       
  1220 	else
       
  1221 		{
       
  1222 		log.AppendFormat(_L("NULL"), &overflow);
       
  1223 		}
       
  1224 	log.AppendFormat(_L("]"), &overflow);
       
  1225 	wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, log);
       
  1226 	}
       
  1227 #endif //USE_DEBUG_FRAME_CAPTURE
       
  1228