windowing/windowserver/nonnga/SERVER/ScreenRedraw.cpp
changeset 0 5d03bc08d59c
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 // SCREEN_REDRAW.CPP
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "ScreenRedraw.h"
       
    19 
       
    20 #include <hal.h>
       
    21 
       
    22 #include "debugbar.h"
       
    23 #include "screen.h"
       
    24 #include "inifile.h"
       
    25 #include "offscreenbitmap.h"
       
    26 #include "wspluginmanager.h"
       
    27 #include "pointer.h"
       
    28 #include "rootwin.h"
       
    29 #include "walkwindowtree.h"
       
    30 #include "wstop.h"
       
    31 #include "WsMemMgr.h"
       
    32 #include "Graphics/WsRenderStageFactory.h"
       
    33 #include "Graphics/WsRenderStage.h"
       
    34 #include "EVENT.H"
       
    35 
       
    36 GLREF_D CDebugLogBase *wsDebugLog;
       
    37 
       
    38 #ifdef USE_DEBUG_REGIONS
       
    39 #	define DEBUG_REGION(col,fill,reg) DebugRegion(col,fill,reg)
       
    40 #	define DEBUG_RECT(col,fill,rect) DebugRect(col,fill,rect)
       
    41 #else
       
    42 #	define DEBUG_REGION(col,fill,reg)
       
    43 #	define DEBUG_RECT(col,fill,rect)
       
    44 #endif
       
    45 
       
    46 #if defined(__WINS__) && defined(_DEBUG)
       
    47 #	define DEBUGOSB { CWsOffScreenBitmap * ofb = iScreen.OffScreenBitmap(); if (ofb) ofb->Update(); }
       
    48 #else
       
    49 #	define DEBUGOSB
       
    50 #endif				
       
    51 
       
    52 #ifdef _DEBUG
       
    53 # define LOG_SCREEN_REDRAW_START {if (wsDebugLog) {_LIT(KLogScreenRedrawStart, ">> CScreenRedraw::OnAnimation()"); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, KLogScreenRedrawStart);}}
       
    54 # define LOG_SCREEN_REDRAW_END {if (wsDebugLog) {_LIT(KLogScreenRedrawEnd, "<< CScreenRedraw::OnAnimation()"); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, KLogScreenRedrawEnd);}}
       
    55 #else
       
    56 # define LOG_SCREEN_REDRAW_START
       
    57 # define LOG_SCREEN_REDRAW_END
       
    58 #endif
       
    59 
       
    60 CScreenRedraw::TTimedRect::TTimedRect(const TRect& aRect, const TTime& aTime):
       
    61 	iRect(aRect), iTime(aTime)
       
    62 	{
       
    63 	}
       
    64 
       
    65 TInt CScreenRedraw::TTimedRect::Compare(const TTimedRect& aOne,const TTimedRect& aOther)
       
    66 	{
       
    67 	if(aOne.iTime < aOther.iTime)
       
    68 		return -1;
       
    69 	else if(aOne.iTime > aOther.iTime)
       
    70 		return 1;
       
    71 	else
       
    72 		return 0;
       
    73 	}
       
    74 
       
    75 CScreenRedraw * CScreenRedraw::NewL(CScreen& aScreen)
       
    76 	{
       
    77 	CScreenRedraw * self = new (ELeave) CScreenRedraw(aScreen);
       
    78 	CleanupStack::PushL(self);
       
    79 	self->ConstructL();
       
    80 	CleanupStack::Pop(self);
       
    81 	return self;
       
    82 	}
       
    83 	
       
    84 CScreenRedraw::CScreenRedraw(CScreen& aScreen): iScreen(aScreen)
       
    85 	{
       
    86 	}
       
    87 
       
    88 CScreenRedraw::~CScreenRedraw()
       
    89 	{
       
    90 	CWsRenderStage * stage = iRenderStages;
       
    91 	while (stage!=NULL)
       
    92    		{
       
    93 		CWsRenderStage *next=stage->Next();
       
    94    		delete stage;
       
    95 		stage=next;
       
    96    		}
       
    97 	iTimedDrawRect.Close();
       
    98 	iInvalid.Close();
       
    99 	iTopLayer.Close();
       
   100 	iBannedRegion.Close();	
       
   101 	}
       
   102 
       
   103 void CScreenRedraw::ConstructL()
       
   104 	{
       
   105 	CWsPluginManager * pluginMgr = CWsTop::WindowServer()->PluginManager();
       
   106 	
       
   107 	// Setup the render stages for this screen:
       
   108 	_LIT(KDefaultRenderStages, "std");
       
   109 	_LIT(KDefaultFlickerFreeRenderStages, "flickerbuffer std");
       
   110 	_LIT(KRenderStages,"RENDERSTAGES");
       
   111 	TPtrC stagesString;
       
   112 	const TBool customStages = WsIniFile->FindVar(iScreen.ScreenNumber(),KRenderStages,stagesString);
       
   113 	
       
   114 	// If noone specifies stages for this screen, assume the standard implementation:
       
   115 	const TDesC * stages;
       
   116 	if (customStages)
       
   117 		stages = &stagesString;
       
   118 	else if (iScreen.OffScreenBitmap())
       
   119 		stages = &KDefaultFlickerFreeRenderStages();
       
   120 	else
       
   121 		stages = &KDefaultRenderStages();
       
   122 	
       
   123 	CWsRenderStage * lastStage = 0;
       
   124 
       
   125 	// Parse the string for implementation IDs:
       
   126 	TLex lex(*stages);
       
   127 	while(true)
       
   128 		{
       
   129 		TPtrC ptr = lex.NextToken();
       
   130 		if (ptr.Length() > 0)
       
   131 			{
       
   132 			TInt err = KErrNone;
       
   133 			MWsRenderStageFactory * factory = pluginMgr->FindNamedImplementation<MWsRenderStageFactory>(ptr);
       
   134 			if (factory)
       
   135 				{
       
   136 				CWsRenderStage * stage = 0;
       
   137 				TRAP(err, stage = factory->CreateStageL(static_cast<MWsScreen*>(&iScreen), this));
       
   138 				if (err == KErrNone)
       
   139 					{
       
   140 					if (!stage)
       
   141 						{
       
   142 						err = KErrNotFound;
       
   143 						}
       
   144 					else
       
   145 						{
       
   146 						if (lastStage)
       
   147 							lastStage->SetNext(stage);
       
   148 						else
       
   149 							iRenderStages = stage;
       
   150 						lastStage = stage;
       
   151 						}
       
   152 					}
       
   153 				}
       
   154 			else
       
   155 				{
       
   156 				err = KErrNotFound;
       
   157 				}
       
   158 
       
   159 			if (wsDebugLog)
       
   160 				{
       
   161 				TBuf<64> buf;
       
   162 				if (err == KErrNone)
       
   163 					{
       
   164 					_LIT(KAddedRenderStage,"Added render stage: ");
       
   165 					buf.Append(KAddedRenderStage);
       
   166 					buf.Append(ptr);
       
   167 					wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,buf);
       
   168 					}
       
   169 				else
       
   170 					{
       
   171 					_LIT(KMissingRenderStage,"Failed to add render stage (%d): ");
       
   172 					buf.Append(KMissingRenderStage);
       
   173 					buf.Append(ptr);
       
   174 					wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,buf,err);
       
   175 					}
       
   176 				}
       
   177 			}
       
   178 		else
       
   179 			{
       
   180 			break;
       
   181 			}
       
   182 		}
       
   183 	}
       
   184 
       
   185 const TTime& CScreenRedraw::Now() const
       
   186 	{
       
   187 	if(!iAnimating)
       
   188 		{
       
   189 		iNow.UniversalTime();
       
   190 		}
       
   191 	return iNow;
       
   192 	}
       
   193 
       
   194 void CScreenRedraw::ScheduleRender(const TTimeIntervalMicroSeconds& aFromNow)
       
   195 	{
       
   196 	iRenderScheduled = ETrue;
       
   197 	TTime then(Now() + aFromNow);
       
   198 	if ((!iScheduled) || then < iNext)
       
   199 		iNext = then;
       
   200 	iScheduled = ETrue;
       
   201 	CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen,iNext);
       
   202 	}
       
   203 
       
   204 void CScreenRedraw::ScheduleRedraw()
       
   205 	{
       
   206 	iNext = Now();
       
   207 	iScheduled = ETrue;
       
   208 		
       
   209 	// The other scheduler also removes future animations which this one encompasses.
       
   210 	// We choose not to do the region calculations needed to achieve that here.
       
   211 	MWsAnimationScheduler* animSched=CWsTop::WindowServer()->AnimationScheduler();
       
   212 	if (animSched)
       
   213 		{
       
   214 		animSched->ScheduleRedraw(iScreen,iNext);
       
   215 		}
       
   216 	}
       
   217 
       
   218 void CScreenRedraw::ScheduleAnimation(const TRect& aRect,const TTimeIntervalMicroSeconds& aFromNow,const TTimeIntervalMicroSeconds& /*aFreq*/,const TTimeIntervalMicroSeconds& /*aStop*/)
       
   219 	{
       
   220 	TRect test(aRect);
       
   221 	test.Intersection(iScreen.DrawableArea());
       
   222 	if(!test.IsEmpty())
       
   223 		{
       
   224 		const TTime then(Now() + aFromNow);
       
   225 		TTimedRect tRect(aRect, then);
       
   226 
       
   227 		const TInt error = iTimedDrawRect.InsertInOrderAllowRepeats(tRect,TTimedRect::Compare);
       
   228 		if (KErrNone == error)
       
   229 	   		{
       
   230 			if (iScheduled)
       
   231 				{
       
   232 				if (then < iNext)
       
   233 					{
       
   234 					iNext = then;
       
   235 					}
       
   236 				}
       
   237 			else
       
   238 				{
       
   239 				iNext = then;
       
   240 				iScheduled = ETrue;
       
   241 				}
       
   242 			// remove further futures that are completely contained
       
   243 			TInt count = iTimedDrawRect.Count();
       
   244 			for(TInt i=0; i<count; i++)
       
   245 				{
       
   246 				const TTimedRect& future = iTimedDrawRect[i];
       
   247 				if(future.iTime.Int64() > then.Int64())
       
   248 					{
       
   249 					TRect rect(aRect);
       
   250 					rect.BoundingRect(future.iRect);
       
   251 					if(rect == aRect) // future is completely contained within aRect
       
   252 						{
       
   253 						iTimedDrawRect.Remove(i);
       
   254 						count--;
       
   255 						i--;
       
   256 						}
       
   257 					}
       
   258 				}
       
   259 			CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen,iNext);
       
   260 
       
   261 			// Blue rectangles for scheduled animations
       
   262 			DEBUG_RECT(TRgb(0x00, 0x00, 0xFF),TRgb(0x00, 0x00, 0xFF, 0x20),&aRect);
       
   263 			}
       
   264 		}
       
   265 	}
       
   266 
       
   267 // This adds a region to the stored invalid region.
       
   268 // The invalid region is the area of the screen that needs to be redrawn in addition to any animations.
       
   269 // The draw region is the area of the screen on which only the top window needs to be redrawn.
       
   270 // If the top window has transparency, this can only be true when it has been made newly visible.
       
   271 // The value of aSchedule could be determined automatically from iAnimating, but passing it this way
       
   272 // allows us to have the assert, which is a very valuable assert.
       
   273 void CScreenRedraw::AddRedrawRegion(const TRegion& aRegion, TBool aSchedule, TRedrawDepth aDepth)
       
   274 	{
       
   275 	WS_ASSERT_DEBUG(!iAnimating || !aSchedule, EWsPanicScheduledRedraw);
       
   276 	
       
   277 	if(aRegion.CheckError())
       
   278 		{
       
   279 		iInvalid.ForceError();
       
   280 
       
   281 		if (aSchedule)
       
   282 			ScheduleRedraw();
       
   283 		}
       
   284 	else if(aRegion.Count()) // often called despite window not being visible
       
   285 		{
       
   286 		if (aDepth == ERedrawAll)
       
   287 			{
       
   288 			// red lines for an invalid region which is ready to be drawn
       
   289 			DEBUG_REGION(TRgb(0xFF, 0x00, 0x00),TRgb(0xFF, 0x00, 0x00, 0x20),&aRegion);
       
   290 				
       
   291 			iInvalid.Union(aRegion);
       
   292 			
       
   293 			if (aSchedule)
       
   294 				ScheduleRedraw();
       
   295 			}
       
   296 		else
       
   297 			{
       
   298 			// yellow lines for a valid region which we will draw on top of
       
   299 			DEBUG_REGION(TRgb(0xFF, 0xFF, 0x00),TRgb(0xFF, 0xFF, 0x00, 0x20),&aRegion);
       
   300 				
       
   301 			iTopLayer.Union(aRegion);
       
   302 			
       
   303 			if (aSchedule)
       
   304 				ScheduleRedraw();			
       
   305 			}
       
   306 		}
       
   307 	}
       
   308 
       
   309 // This causes any asynchronously scheduled redraw to happen immediately
       
   310 // It should be avoided where possible for performance reasons, but is 
       
   311 // needed whenever the redraw store is discarded for a window which still
       
   312 // has a redraw region pending.
       
   313 void CScreenRedraw::DoRedrawNow()
       
   314 	{
       
   315 	if(!iAnimating)
       
   316 		CWsTop::WindowServer()->AnimationScheduler()->DoRedrawNow(iScreen);
       
   317 	}
       
   318 	
       
   319 #ifdef USE_DEBUG_REGIONS
       
   320 void CScreenRedraw::DebugRect(TRgb aColor, TRgb aFill, const TRect* aRect)
       
   321 	{
       
   322 	if (aRect)
       
   323 		{
       
   324 		CFbsBitGc * gc = iScreen.GetBitGc();
       
   325 		gc->SetPenColor(aColor);
       
   326 		gc->SetPenStyle(CGraphicsContext::ESolidPen);
       
   327 		gc->SetPenSize(TSize(2,2));
       
   328 		gc->SetBrushColor(aFill);
       
   329 		gc->SetBrushStyle(CGraphicsContext::ESolidBrush);
       
   330 		TRect smaller = *aRect;
       
   331 		smaller.iBr.iX -= 1;
       
   332 		smaller.iBr.iY -= 1;
       
   333 		gc->DrawRect(smaller);
       
   334 		iScreen.Update();
       
   335 		}
       
   336 	}
       
   337 
       
   338 void CScreenRedraw::DebugRegion(TRgb aColor, TRgb aFill, const TRegion * aRegion)
       
   339 	{
       
   340 	if (aRegion)
       
   341 		{
       
   342 		CFbsBitGc * gc = iScreen.GetBitGc();
       
   343 		gc->SetPenColor(aColor);
       
   344 		gc->SetPenStyle(CGraphicsContext::ESolidPen);
       
   345 		gc->SetPenSize(TSize(2,2));
       
   346 		gc->SetBrushColor(aFill);
       
   347 		gc->SetBrushStyle(CGraphicsContext::ESolidBrush);
       
   348 		for (const TRect *rect = aRegion->RectangleList(); rect - aRegion->RectangleList() < aRegion->Count(); ++rect)
       
   349 			{
       
   350 			TRect smaller = *rect;
       
   351 			smaller.iBr.iX -= 1;
       
   352 			smaller.iBr.iY -= 1;
       
   353 			gc->DrawRect(smaller);
       
   354 			}
       
   355 		iScreen.Update();
       
   356 		}
       
   357 	}
       
   358 #endif 
       
   359 
       
   360 void CScreenRedraw::OnAnimation()
       
   361 	{
       
   362 	LOG_SCREEN_REDRAW_START
       
   363 	ASSERT(!iAnimating);
       
   364 	ASSERT(iScheduled);
       
   365 	iAnimating = ETrue;
       
   366 	iScheduled = EFalse;
       
   367 	TBool futureAnimationRequired = EFalse;	
       
   368 
       
   369 	CWsActiveScheduler::Static()->PrepareDraw();
       
   370 	
       
   371 	// Calculate any updates required by region changes:
       
   372 	RegionUpdate();
       
   373 
       
   374 	// Add the timed rectangles to the invalid region:
       
   375 	iNow.UniversalTime();
       
   376 	TInt count(iTimedDrawRect.Count());
       
   377 	while (0 < count)
       
   378 		{
       
   379 		if(iTimedDrawRect[0].iTime.Int64() <= iNow.Int64())
       
   380 			{
       
   381 			iInvalid.AddRect(iTimedDrawRect[0].iRect);
       
   382 			iTimedDrawRect.Remove(0);
       
   383 			count--;
       
   384 			}
       
   385 		else
       
   386 			{
       
   387 			futureAnimationRequired = ETrue;	
       
   388 			break;
       
   389 			}
       
   390 		}
       
   391 
       
   392 	// Animating rectangles could cause iInvalid to overlap iTopLayer,
       
   393 	// in which case iTopLayer won't work.
       
   394 	iTopLayer.SubRegion(iInvalid);
       
   395 	iTopLayer.Intersect(iScreen.RootWindow()->WindowArea());
       
   396 	iTopLayer.Tidy();
       
   397 	// Anything in the top layer is implcitly invalid
       
   398 	iInvalid.Union(iTopLayer);
       
   399 	iInvalid.Intersect(iScreen.RootWindow()->WindowArea());
       
   400 	
       
   401 /*
       
   402 	if (const CDebugBar* dbg = iScreen.DebugBar())
       
   403 		{
       
   404 		iTopLayer.SubRect(dbg->Rect());
       
   405 		iInvalid.SubRect(dbg->Rect());
       
   406 		}
       
   407 */
       
   408 
       
   409 	iInvalid.Tidy();
       
   410 
       
   411 	if(iInvalid.CheckError()) //Will: agree with Andy, want bounding rects instead!
       
   412 		{
       
   413 		iTopLayer.Clear();
       
   414 		iInvalid.Clear();
       
   415 		iInvalid.Copy(iScreen.RootWindow()->WindowArea()); // assumed cannot fail, all regions can contain at least 1 rect..
       
   416 		}
       
   417 
       
   418 	iInvalid.SubRegion( iBannedRegion );	
       
   419 	iInvalid.Tidy();
       
   420 	iTopLayer.SubRegion( iBannedRegion );
       
   421 	iTopLayer.Tidy();
       
   422 	
       
   423 	STACK_REGION invalidCopy;
       
   424 	invalidCopy.Copy(iInvalid);
       
   425 	TWalkWindowTreeScheduleRegions regionScheduler(&invalidCopy, iTopLayer);
       
   426 	TWalkWindowTreeScheduleFallback fallbackScheduler(iScreen.FallbackMap());
       
   427 	TWalkWindowTreeSchedule * scheduler = &regionScheduler;
       
   428 	
       
   429 	// At this point, if the DEBUG_REGION is being used:
       
   430 	// Red represents invalid regions that need to be redrawn completely.
       
   431 	// Yellow represents regions that only need the top window to be drawn.
       
   432 	// Blue represents regions which are being animated server side.
       
   433 	if (iRenderScheduled || !iInvalid.IsEmpty())
       
   434 		{
       
   435 		iRenderScheduled = EFalse;
       
   436 		// invalidCopy.ForceError(); //### DEBUG
       
   437 		
       
   438 		iScreen.RootWindow()->WalkWindowTree(regionScheduler,EWalkChildren);
       
   439 		if (!regionScheduler.ScheduledRegionsOk())
       
   440 			{
       
   441 			// our region calculations for what to draw failed at some point.
       
   442 			// From this point on we MUST NOT rely on allocating memory
       
   443 			// Andy - localRedrawRegion allocates
       
   444 			// Andy - setPenSize allocates (even if you don't call it)
       
   445 			// Andy - all draw commands add to a gdi dirty region (which allocates)
       
   446 			// Andy - combining client clipping regions with window clipping regions allocates
       
   447 			scheduler = &fallbackScheduler;
       
   448 			iScreen.FallbackMap()->Prepare();
       
   449 			iScreen.RootWindow()->WalkWindowTree(fallbackScheduler,EWalkChildren);
       
   450 			}
       
   451 		
       
   452 		CWsActiveScheduler::Static()->StartDraw();
       
   453 		CWsMemoryManager::Static()->EnableReserve();
       
   454 
       
   455 		if (&fallbackScheduler == scheduler)
       
   456 			iAnimationRegion = iScreen.FallbackMap()->Region();
       
   457 		else
       
   458 			iAnimationRegion = &iInvalid;
       
   459 		
       
   460 		// Redraw debug regions more brightly than before:
       
   461 		DEBUG_REGION(TRgb(0xFF, 0x00, 0x00),TRgb(0xFF, 0x00, 0x00, 0x80),&iInvalid);
       
   462 		DEBUG_REGION(TRgb(0xFF, 0xFF, 0x00),TRgb(0xFF, 0xFF, 0x00, 0x80),&iTopLayer);
       
   463 		
       
   464 		RWsRegion accumulatedDrawing;
       
   465 		
       
   466 		// Pipe the drawing into the first render stage:
       
   467 		CFbsBitGc * stageGc = iRenderStages->Begin();
       
   468 		
       
   469 		for (CWsWindow * win = scheduler->HeadWindow(); win; win = win->NextScheduled())
       
   470 			{
       
   471 			const TRegion * targetRegion = scheduler->Region(win);
       
   472 			const TRect * screenRect = 0;
       
   473 			if ((&fallbackScheduler == scheduler) && !targetRegion->IsContainedBy(iScreen.RootWindow()->Abs()))
       
   474 				{
       
   475 				screenRect = &iScreen.RootWindow()->Abs();
       
   476 				}
       
   477 			if (!screenRect)
       
   478 				{
       
   479 				// Purple regions are about to be drawn
       
   480 				DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80),targetRegion);
       
   481 				// Do the drawing
       
   482 				stageGc->Reset();
       
   483 				win->Render(stageGc, *targetRegion);
       
   484 				accumulatedDrawing.Union(*targetRegion);
       
   485 				// Green regions have been drawn
       
   486 				DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80),targetRegion);
       
   487 				}
       
   488 			else
       
   489 				{
       
   490 				// Our region overlaps the edges of the screen, and we have no memory
       
   491 				// to create a clipped one, so we will use a single-rect region for each rect
       
   492 				// and call Draw multiple times.
       
   493 				TRegionFix<1> rectRegion;
       
   494 				for (const TRect * rect = targetRegion->RectangleList() + targetRegion->Count() - 1; rect >= targetRegion->RectangleList(); --rect)
       
   495 					{
       
   496 					rectRegion.Clear();
       
   497 					TRect combined(*screenRect);
       
   498 					combined.Intersection(*rect);
       
   499 					rectRegion.AddRect(combined);
       
   500 					// Purple regions are about to be drawn
       
   501 					DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80),&rectRegion);
       
   502 					// Do the drawing
       
   503 					stageGc->Reset();
       
   504 					win->Render(stageGc, rectRegion);
       
   505 					accumulatedDrawing.AddRect(combined);
       
   506 					// Green regions have been drawn
       
   507 					DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80),&rectRegion);
       
   508 					}
       
   509 				}
       
   510 			DEBUGOSB
       
   511 			}
       
   512 
       
   513 		DEBUGOSB			
       
   514 		iScreen.SpriteManager()->DrawFloatingSprites(stageGc,accumulatedDrawing); // we limit sprite drawing over only actually affected ares but necessary to all "planned" for redraw
       
   515 		if (!accumulatedDrawing.CheckError() && iScreen.SpriteManager()->SpriteCount() == 0)
       
   516 			{
       
   517 			iAnimationRegion = &accumulatedDrawing;
       
   518 			}
       
   519 
       
   520 		// Tell the render stage we've finished:
       
   521 		iRenderStages->End();
       
   522 		
       
   523 		// We nolonger need the regions
       
   524 		for (CWsWindow * win = scheduler->HeadWindow(); win; win = win->NextScheduled())
       
   525 			{
       
   526 			win->ClearScheduledRegion();
       
   527 			}
       
   528 			
       
   529 		CWsMemoryManager::Static()->DisableReserve();
       
   530 
       
   531 		if (const CDebugBar* dbg = iScreen.DebugBar())
       
   532 			{
       
   533 			dbg->RedrawDebugBar();
       
   534 			}
       
   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 		iScreen.Update();
       
   541 		// At this point, if the DEBUG_REGION is being used, there should be no regions visible
       
   542 		// of any colour.  If we see green, then it means an area of the screen was drawn to which
       
   543 		// wasn't invalid, or the screen update call failed.  The former is more likely.
       
   544 		// If we still see red or yellow it is a region that is not yet ready to draw.
       
   545 
       
   546 		const TRect* rect = iAnimationRegion->RectangleList();
       
   547 		TInt pixels = 0;
       
   548 		for(TInt r = iAnimationRegion->Count(); r>0; r--)
       
   549 			{
       
   550 			pixels += (rect->Width()*rect->Height());
       
   551 			rect++;
       
   552 			}
       
   553 		CWsActiveScheduler::Static()->StopDraw(pixels);
       
   554 		
       
   555 		TWindowServerEvent::NotifyScreenDrawingEvent(iAnimationRegion);
       
   556 
       
   557 		iAnimationRegion = 0;
       
   558 		accumulatedDrawing.Close();
       
   559 		iInvalid.Clear();
       
   560 		}
       
   561 	else
       
   562 		{
       
   563 		CWsActiveScheduler::Static()->CancelPrepare();
       
   564 		}
       
   565 
       
   566 	iInvalid.Clear();
       
   567 	iTopLayer.Clear();
       
   568 	invalidCopy.Close();
       
   569 	iAnimating = EFalse;
       
   570 	
       
   571 	if (futureAnimationRequired && iTimedDrawRect.Count() > 0 && !iScheduled)
       
   572 		{
       
   573 		// If this flag is set then it means there were already some animations scheduled when we ran,
       
   574 		// but they themselves didn't run.  We need to make sure we have _something_ scheduled.
       
   575 		CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen, iTimedDrawRect[0].iTime);
       
   576 		iScheduled = ETrue;
       
   577 		}
       
   578 	
       
   579 	if(iObserver)
       
   580 		{
       
   581 		iObserver->ScreenUpdated(iScreen.ScreenNumber());
       
   582 		iObserver=NULL; //once signalled we are never going to call it again
       
   583 		}
       
   584 	LOG_SCREEN_REDRAW_END
       
   585 	}
       
   586 
       
   587 //
       
   588 void CScreenRedraw::DiscardAllSchedules()
       
   589 	{
       
   590 	ASSERT(!iAnimating);
       
   591 	
       
   592 	iTimedDrawRect.Reset();
       
   593 	iInvalid.Clear();
       
   594 	iInvalid.Tidy();
       
   595 	}
       
   596 
       
   597 /**
       
   598 Indicates that a window has moved or changed ordinal position so that the visible regions
       
   599 of all windows needs to be recalculated
       
   600 */
       
   601 void CScreenRedraw::ScheduleRegionUpdate(const TRegion* aDefinitelyDirty)
       
   602 	{
       
   603 	iRegionUpdateScheduled = ETrue;
       
   604 	ScheduleRedraw();
       
   605 	if(aDefinitelyDirty)
       
   606 		{
       
   607 		iInvalid.Union(*aDefinitelyDirty);
       
   608 		// Cyan regions for invalidations caused by this:
       
   609 		DEBUG_REGION(TRgb(0x00, 0xFF, 0xFF),TRgb(0x00, 0xFF, 0xFF, 0x20),aDefinitelyDirty);
       
   610 		}
       
   611 	}
       
   612 	
       
   613 /**
       
   614 Recalculates visible regions and schedules redraws or queues redraw events in response to
       
   615 any changes
       
   616 */
       
   617 void CScreenRedraw::RegionUpdate()
       
   618 	{
       
   619 	if (iRegionUpdateScheduled)
       
   620 		{
       
   621 		iRegionUpdateScheduled = EFalse;
       
   622 		
       
   623 		TWalkWindowTreeUpdateRegions updater(iScreen);
       
   624 		updater.Walk();
       
   625 
       
   626 		WsPointer::ReLogCurrentWindow();
       
   627 		CWsTop::TriggerRedraws(iScreen.RootWindow());
       
   628 		}
       
   629 	}
       
   630 
       
   631 void CScreenRedraw::SetObserver(MWsScreenRedrawObserver* aObserver)
       
   632 	{
       
   633 	iObserver = aObserver;
       
   634 	}
       
   635 
       
   636 TBool CScreenRedraw::IsUpdatePending()
       
   637 	{
       
   638 	if(iScheduled || iAnimating)
       
   639 		return ETrue;
       
   640 	else 
       
   641 		return EFalse;
       
   642 	}
       
   643 
       
   644 /**
       
   645  Overidding MWsObjectProvider
       
   646 */
       
   647 TAny* CScreenRedraw::ResolveObjectInterface(TUint aTypeId)
       
   648 	{
       
   649 	TAny* interface = NULL;
       
   650 
       
   651 	switch (aTypeId)
       
   652 		{
       
   653 		case KWsScreenRedraw:
       
   654 			interface = static_cast<MWsScreenRedraw*>(this);
       
   655 			break;
       
   656 		}
       
   657 
       
   658 	if (!interface)
       
   659 		{
       
   660 		interface = iRenderStages->ResolveObjectInterface(aTypeId);
       
   661 		}
       
   662 	
       
   663 	return interface;
       
   664 	}
       
   665 
       
   666 const TRegion * CScreenRedraw::AnimationRegion() const
       
   667 	{
       
   668 	if (iAnimating)
       
   669 		return iAnimationRegion;
       
   670 	else
       
   671 		return 0;
       
   672 	}
       
   673 
       
   674 void CScreenRedraw::UpdateDevice()
       
   675 	{
       
   676 	iScreen.Update();
       
   677 	}
       
   678 
       
   679 void CScreenRedraw::BanThisRegionUpdate( TRegion& aForbiddenRegion )
       
   680 	{
       
   681 	iBannedRegion.Union( aForbiddenRegion );
       
   682 	iBannedRegion.Tidy();
       
   683 	}
       
   684 
       
   685 void CScreenRedraw::LiftRegionUpdateBan( TRegion& aFormerForbiddenRegion  )
       
   686 	{
       
   687 	iBannedRegion.SubRegion( aFormerForbiddenRegion );
       
   688 	iBannedRegion.Tidy();
       
   689 	}
       
   690 
       
   691 void CScreenRedraw::AcceptFadeRequest( CWsWindow* aWin, TBool aFadeOn, TBool aFadeBehind, TBool aIncludeChildren )
       
   692 	{
       
   693 	if ( aFadeOn )
       
   694 		{
       
   695 		TWalkWindowTreeScheduleFadeNoRedraw walkerFadeNoRedraw;
       
   696 		if ( aFadeBehind )
       
   697 			{
       
   698 			aWin->WalkWindowTree( walkerFadeNoRedraw, EWalkBehind );				
       
   699 			}
       
   700 		else
       
   701 			{
       
   702 			if(aWin->WinType() != EWinTypeGroup)
       
   703 				{
       
   704 				ScheduleRegionUpdate( aWin->VisibleRegionIfValid() );
       
   705 				}
       
   706 			
       
   707 			if ( aIncludeChildren )
       
   708 				{
       
   709 				aWin->WalkWindowTree( walkerFadeNoRedraw, EWalkChildren );
       
   710 				}				
       
   711 			}
       
   712 		}
       
   713 	else
       
   714 		{	// fade off, just initiate redraw
       
   715 		TWalkWindowTreeScheduleRedraws walkerRedraw( TWalkWindowTreeScheduleRedraws::ERedrawFilterOmitDSA ) ;
       
   716 		if ( aFadeBehind )
       
   717 			{
       
   718 			aWin->WalkWindowTree( walkerRedraw, EWalkBehind );								
       
   719 			}
       
   720 		else
       
   721 			{ // fade this win not behind
       
   722 			if ( !aWin->IsDSAHost() )
       
   723 				{
       
   724 				AddRedrawRegion( aWin->VisibleRegion() );
       
   725 				}
       
   726 			if ( aIncludeChildren )
       
   727 				{
       
   728 				aWin->WalkWindowTree( walkerRedraw, EWalkChildren );
       
   729 				}				
       
   730 			}			
       
   731 		}		
       
   732 	ScheduleRegionUpdate(NULL);
       
   733 	}