windowing/windowserver/nonnga/SERVER/ScreenRedraw.cpp
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nonnga/SERVER/ScreenRedraw.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,733 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// SCREEN_REDRAW.CPP
+// 
+//
+
+#include "ScreenRedraw.h"
+
+#include <hal.h>
+
+#include "debugbar.h"
+#include "screen.h"
+#include "inifile.h"
+#include "offscreenbitmap.h"
+#include "wspluginmanager.h"
+#include "pointer.h"
+#include "rootwin.h"
+#include "walkwindowtree.h"
+#include "wstop.h"
+#include "WsMemMgr.h"
+#include "Graphics/WsRenderStageFactory.h"
+#include "Graphics/WsRenderStage.h"
+#include "EVENT.H"
+
+GLREF_D CDebugLogBase *wsDebugLog;
+
+#ifdef USE_DEBUG_REGIONS
+#	define DEBUG_REGION(col,fill,reg) DebugRegion(col,fill,reg)
+#	define DEBUG_RECT(col,fill,rect) DebugRect(col,fill,rect)
+#else
+#	define DEBUG_REGION(col,fill,reg)
+#	define DEBUG_RECT(col,fill,rect)
+#endif
+
+#if defined(__WINS__) && defined(_DEBUG)
+#	define DEBUGOSB { CWsOffScreenBitmap * ofb = iScreen.OffScreenBitmap(); if (ofb) ofb->Update(); }
+#else
+#	define DEBUGOSB
+#endif				
+
+#ifdef _DEBUG
+# define LOG_SCREEN_REDRAW_START {if (wsDebugLog) {_LIT(KLogScreenRedrawStart, ">> CScreenRedraw::OnAnimation()"); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, KLogScreenRedrawStart);}}
+# define LOG_SCREEN_REDRAW_END {if (wsDebugLog) {_LIT(KLogScreenRedrawEnd, "<< CScreenRedraw::OnAnimation()"); wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, KLogScreenRedrawEnd);}}
+#else
+# define LOG_SCREEN_REDRAW_START
+# define LOG_SCREEN_REDRAW_END
+#endif
+
+CScreenRedraw::TTimedRect::TTimedRect(const TRect& aRect, const TTime& aTime):
+	iRect(aRect), iTime(aTime)
+	{
+	}
+
+TInt CScreenRedraw::TTimedRect::Compare(const TTimedRect& aOne,const TTimedRect& aOther)
+	{
+	if(aOne.iTime < aOther.iTime)
+		return -1;
+	else if(aOne.iTime > aOther.iTime)
+		return 1;
+	else
+		return 0;
+	}
+
+CScreenRedraw * CScreenRedraw::NewL(CScreen& aScreen)
+	{
+	CScreenRedraw * self = new (ELeave) CScreenRedraw(aScreen);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+CScreenRedraw::CScreenRedraw(CScreen& aScreen): iScreen(aScreen)
+	{
+	}
+
+CScreenRedraw::~CScreenRedraw()
+	{
+	CWsRenderStage * stage = iRenderStages;
+	while (stage!=NULL)
+   		{
+		CWsRenderStage *next=stage->Next();
+   		delete stage;
+		stage=next;
+   		}
+	iTimedDrawRect.Close();
+	iInvalid.Close();
+	iTopLayer.Close();
+	iBannedRegion.Close();	
+	}
+
+void CScreenRedraw::ConstructL()
+	{
+	CWsPluginManager * pluginMgr = CWsTop::WindowServer()->PluginManager();
+	
+	// Setup the render stages for this screen:
+	_LIT(KDefaultRenderStages, "std");
+	_LIT(KDefaultFlickerFreeRenderStages, "flickerbuffer std");
+	_LIT(KRenderStages,"RENDERSTAGES");
+	TPtrC stagesString;
+	const TBool customStages = WsIniFile->FindVar(iScreen.ScreenNumber(),KRenderStages,stagesString);
+	
+	// If noone specifies stages for this screen, assume the standard implementation:
+	const TDesC * stages;
+	if (customStages)
+		stages = &stagesString;
+	else if (iScreen.OffScreenBitmap())
+		stages = &KDefaultFlickerFreeRenderStages();
+	else
+		stages = &KDefaultRenderStages();
+	
+	CWsRenderStage * lastStage = 0;
+
+	// Parse the string for implementation IDs:
+	TLex lex(*stages);
+	while(true)
+		{
+		TPtrC ptr = lex.NextToken();
+		if (ptr.Length() > 0)
+			{
+			TInt err = KErrNone;
+			MWsRenderStageFactory * factory = pluginMgr->FindNamedImplementation<MWsRenderStageFactory>(ptr);
+			if (factory)
+				{
+				CWsRenderStage * stage = 0;
+				TRAP(err, stage = factory->CreateStageL(static_cast<MWsScreen*>(&iScreen), this));
+				if (err == KErrNone)
+					{
+					if (!stage)
+						{
+						err = KErrNotFound;
+						}
+					else
+						{
+						if (lastStage)
+							lastStage->SetNext(stage);
+						else
+							iRenderStages = stage;
+						lastStage = stage;
+						}
+					}
+				}
+			else
+				{
+				err = KErrNotFound;
+				}
+
+			if (wsDebugLog)
+				{
+				TBuf<64> buf;
+				if (err == KErrNone)
+					{
+					_LIT(KAddedRenderStage,"Added render stage: ");
+					buf.Append(KAddedRenderStage);
+					buf.Append(ptr);
+					wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,buf);
+					}
+				else
+					{
+					_LIT(KMissingRenderStage,"Failed to add render stage (%d): ");
+					buf.Append(KMissingRenderStage);
+					buf.Append(ptr);
+					wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,buf,err);
+					}
+				}
+			}
+		else
+			{
+			break;
+			}
+		}
+	}
+
+const TTime& CScreenRedraw::Now() const
+	{
+	if(!iAnimating)
+		{
+		iNow.UniversalTime();
+		}
+	return iNow;
+	}
+
+void CScreenRedraw::ScheduleRender(const TTimeIntervalMicroSeconds& aFromNow)
+	{
+	iRenderScheduled = ETrue;
+	TTime then(Now() + aFromNow);
+	if ((!iScheduled) || then < iNext)
+		iNext = then;
+	iScheduled = ETrue;
+	CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen,iNext);
+	}
+
+void CScreenRedraw::ScheduleRedraw()
+	{
+	iNext = Now();
+	iScheduled = ETrue;
+		
+	// The other scheduler also removes future animations which this one encompasses.
+	// We choose not to do the region calculations needed to achieve that here.
+	MWsAnimationScheduler* animSched=CWsTop::WindowServer()->AnimationScheduler();
+	if (animSched)
+		{
+		animSched->ScheduleRedraw(iScreen,iNext);
+		}
+	}
+
+void CScreenRedraw::ScheduleAnimation(const TRect& aRect,const TTimeIntervalMicroSeconds& aFromNow,const TTimeIntervalMicroSeconds& /*aFreq*/,const TTimeIntervalMicroSeconds& /*aStop*/)
+	{
+	TRect test(aRect);
+	test.Intersection(iScreen.DrawableArea());
+	if(!test.IsEmpty())
+		{
+		const TTime then(Now() + aFromNow);
+		TTimedRect tRect(aRect, then);
+
+		const TInt error = iTimedDrawRect.InsertInOrderAllowRepeats(tRect,TTimedRect::Compare);
+		if (KErrNone == error)
+	   		{
+			if (iScheduled)
+				{
+				if (then < iNext)
+					{
+					iNext = then;
+					}
+				}
+			else
+				{
+				iNext = then;
+				iScheduled = ETrue;
+				}
+			// remove further futures that are completely contained
+			TInt count = iTimedDrawRect.Count();
+			for(TInt i=0; i<count; i++)
+				{
+				const TTimedRect& future = iTimedDrawRect[i];
+				if(future.iTime.Int64() > then.Int64())
+					{
+					TRect rect(aRect);
+					rect.BoundingRect(future.iRect);
+					if(rect == aRect) // future is completely contained within aRect
+						{
+						iTimedDrawRect.Remove(i);
+						count--;
+						i--;
+						}
+					}
+				}
+			CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen,iNext);
+
+			// Blue rectangles for scheduled animations
+			DEBUG_RECT(TRgb(0x00, 0x00, 0xFF),TRgb(0x00, 0x00, 0xFF, 0x20),&aRect);
+			}
+		}
+	}
+
+// This adds a region to the stored invalid region.
+// The invalid region is the area of the screen that needs to be redrawn in addition to any animations.
+// The draw region is the area of the screen on which only the top window needs to be redrawn.
+// If the top window has transparency, this can only be true when it has been made newly visible.
+// The value of aSchedule could be determined automatically from iAnimating, but passing it this way
+// allows us to have the assert, which is a very valuable assert.
+void CScreenRedraw::AddRedrawRegion(const TRegion& aRegion, TBool aSchedule, TRedrawDepth aDepth)
+	{
+	WS_ASSERT_DEBUG(!iAnimating || !aSchedule, EWsPanicScheduledRedraw);
+	
+	if(aRegion.CheckError())
+		{
+		iInvalid.ForceError();
+
+		if (aSchedule)
+			ScheduleRedraw();
+		}
+	else if(aRegion.Count()) // often called despite window not being visible
+		{
+		if (aDepth == ERedrawAll)
+			{
+			// red lines for an invalid region which is ready to be drawn
+			DEBUG_REGION(TRgb(0xFF, 0x00, 0x00),TRgb(0xFF, 0x00, 0x00, 0x20),&aRegion);
+				
+			iInvalid.Union(aRegion);
+			
+			if (aSchedule)
+				ScheduleRedraw();
+			}
+		else
+			{
+			// yellow lines for a valid region which we will draw on top of
+			DEBUG_REGION(TRgb(0xFF, 0xFF, 0x00),TRgb(0xFF, 0xFF, 0x00, 0x20),&aRegion);
+				
+			iTopLayer.Union(aRegion);
+			
+			if (aSchedule)
+				ScheduleRedraw();			
+			}
+		}
+	}
+
+// This causes any asynchronously scheduled redraw to happen immediately
+// It should be avoided where possible for performance reasons, but is 
+// needed whenever the redraw store is discarded for a window which still
+// has a redraw region pending.
+void CScreenRedraw::DoRedrawNow()
+	{
+	if(!iAnimating)
+		CWsTop::WindowServer()->AnimationScheduler()->DoRedrawNow(iScreen);
+	}
+	
+#ifdef USE_DEBUG_REGIONS
+void CScreenRedraw::DebugRect(TRgb aColor, TRgb aFill, const TRect* aRect)
+	{
+	if (aRect)
+		{
+		CFbsBitGc * gc = iScreen.GetBitGc();
+		gc->SetPenColor(aColor);
+		gc->SetPenStyle(CGraphicsContext::ESolidPen);
+		gc->SetPenSize(TSize(2,2));
+		gc->SetBrushColor(aFill);
+		gc->SetBrushStyle(CGraphicsContext::ESolidBrush);
+		TRect smaller = *aRect;
+		smaller.iBr.iX -= 1;
+		smaller.iBr.iY -= 1;
+		gc->DrawRect(smaller);
+		iScreen.Update();
+		}
+	}
+
+void CScreenRedraw::DebugRegion(TRgb aColor, TRgb aFill, const TRegion * aRegion)
+	{
+	if (aRegion)
+		{
+		CFbsBitGc * gc = iScreen.GetBitGc();
+		gc->SetPenColor(aColor);
+		gc->SetPenStyle(CGraphicsContext::ESolidPen);
+		gc->SetPenSize(TSize(2,2));
+		gc->SetBrushColor(aFill);
+		gc->SetBrushStyle(CGraphicsContext::ESolidBrush);
+		for (const TRect *rect = aRegion->RectangleList(); rect - aRegion->RectangleList() < aRegion->Count(); ++rect)
+			{
+			TRect smaller = *rect;
+			smaller.iBr.iX -= 1;
+			smaller.iBr.iY -= 1;
+			gc->DrawRect(smaller);
+			}
+		iScreen.Update();
+		}
+	}
+#endif 
+
+void CScreenRedraw::OnAnimation()
+	{
+	LOG_SCREEN_REDRAW_START
+	ASSERT(!iAnimating);
+	ASSERT(iScheduled);
+	iAnimating = ETrue;
+	iScheduled = EFalse;
+	TBool futureAnimationRequired = EFalse;	
+
+	CWsActiveScheduler::Static()->PrepareDraw();
+	
+	// Calculate any updates required by region changes:
+	RegionUpdate();
+
+	// Add the timed rectangles to the invalid region:
+	iNow.UniversalTime();
+	TInt count(iTimedDrawRect.Count());
+	while (0 < count)
+		{
+		if(iTimedDrawRect[0].iTime.Int64() <= iNow.Int64())
+			{
+			iInvalid.AddRect(iTimedDrawRect[0].iRect);
+			iTimedDrawRect.Remove(0);
+			count--;
+			}
+		else
+			{
+			futureAnimationRequired = ETrue;	
+			break;
+			}
+		}
+
+	// Animating rectangles could cause iInvalid to overlap iTopLayer,
+	// in which case iTopLayer won't work.
+	iTopLayer.SubRegion(iInvalid);
+	iTopLayer.Intersect(iScreen.RootWindow()->WindowArea());
+	iTopLayer.Tidy();
+	// Anything in the top layer is implcitly invalid
+	iInvalid.Union(iTopLayer);
+	iInvalid.Intersect(iScreen.RootWindow()->WindowArea());
+	
+/*
+	if (const CDebugBar* dbg = iScreen.DebugBar())
+		{
+		iTopLayer.SubRect(dbg->Rect());
+		iInvalid.SubRect(dbg->Rect());
+		}
+*/
+
+	iInvalid.Tidy();
+
+	if(iInvalid.CheckError()) //Will: agree with Andy, want bounding rects instead!
+		{
+		iTopLayer.Clear();
+		iInvalid.Clear();
+		iInvalid.Copy(iScreen.RootWindow()->WindowArea()); // assumed cannot fail, all regions can contain at least 1 rect..
+		}
+
+	iInvalid.SubRegion( iBannedRegion );	
+	iInvalid.Tidy();
+	iTopLayer.SubRegion( iBannedRegion );
+	iTopLayer.Tidy();
+	
+	STACK_REGION invalidCopy;
+	invalidCopy.Copy(iInvalid);
+	TWalkWindowTreeScheduleRegions regionScheduler(&invalidCopy, iTopLayer);
+	TWalkWindowTreeScheduleFallback fallbackScheduler(iScreen.FallbackMap());
+	TWalkWindowTreeSchedule * scheduler = &regionScheduler;
+	
+	// At this point, if the DEBUG_REGION is being used:
+	// Red represents invalid regions that need to be redrawn completely.
+	// Yellow represents regions that only need the top window to be drawn.
+	// Blue represents regions which are being animated server side.
+	if (iRenderScheduled || !iInvalid.IsEmpty())
+		{
+		iRenderScheduled = EFalse;
+		// invalidCopy.ForceError(); //### DEBUG
+		
+		iScreen.RootWindow()->WalkWindowTree(regionScheduler,EWalkChildren);
+		if (!regionScheduler.ScheduledRegionsOk())
+			{
+			// our region calculations for what to draw failed at some point.
+			// From this point on we MUST NOT rely on allocating memory
+			// Andy - localRedrawRegion allocates
+			// Andy - setPenSize allocates (even if you don't call it)
+			// Andy - all draw commands add to a gdi dirty region (which allocates)
+			// Andy - combining client clipping regions with window clipping regions allocates
+			scheduler = &fallbackScheduler;
+			iScreen.FallbackMap()->Prepare();
+			iScreen.RootWindow()->WalkWindowTree(fallbackScheduler,EWalkChildren);
+			}
+		
+		CWsActiveScheduler::Static()->StartDraw();
+		CWsMemoryManager::Static()->EnableReserve();
+
+		if (&fallbackScheduler == scheduler)
+			iAnimationRegion = iScreen.FallbackMap()->Region();
+		else
+			iAnimationRegion = &iInvalid;
+		
+		// Redraw debug regions more brightly than before:
+		DEBUG_REGION(TRgb(0xFF, 0x00, 0x00),TRgb(0xFF, 0x00, 0x00, 0x80),&iInvalid);
+		DEBUG_REGION(TRgb(0xFF, 0xFF, 0x00),TRgb(0xFF, 0xFF, 0x00, 0x80),&iTopLayer);
+		
+		RWsRegion accumulatedDrawing;
+		
+		// Pipe the drawing into the first render stage:
+		CFbsBitGc * stageGc = iRenderStages->Begin();
+		
+		for (CWsWindow * win = scheduler->HeadWindow(); win; win = win->NextScheduled())
+			{
+			const TRegion * targetRegion = scheduler->Region(win);
+			const TRect * screenRect = 0;
+			if ((&fallbackScheduler == scheduler) && !targetRegion->IsContainedBy(iScreen.RootWindow()->Abs()))
+				{
+				screenRect = &iScreen.RootWindow()->Abs();
+				}
+			if (!screenRect)
+				{
+				// Purple regions are about to be drawn
+				DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80),targetRegion);
+				// Do the drawing
+				stageGc->Reset();
+				win->Render(stageGc, *targetRegion);
+				accumulatedDrawing.Union(*targetRegion);
+				// Green regions have been drawn
+				DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80),targetRegion);
+				}
+			else
+				{
+				// Our region overlaps the edges of the screen, and we have no memory
+				// to create a clipped one, so we will use a single-rect region for each rect
+				// and call Draw multiple times.
+				TRegionFix<1> rectRegion;
+				for (const TRect * rect = targetRegion->RectangleList() + targetRegion->Count() - 1; rect >= targetRegion->RectangleList(); --rect)
+					{
+					rectRegion.Clear();
+					TRect combined(*screenRect);
+					combined.Intersection(*rect);
+					rectRegion.AddRect(combined);
+					// Purple regions are about to be drawn
+					DEBUG_REGION(TRgb(0x80, 0x00, 0x80),TRgb(0x80, 0x00, 0x80, 0x80),&rectRegion);
+					// Do the drawing
+					stageGc->Reset();
+					win->Render(stageGc, rectRegion);
+					accumulatedDrawing.AddRect(combined);
+					// Green regions have been drawn
+					DEBUG_REGION(TRgb(0x00, 0xFF, 0x00),TRgb(0x00, 0xFF, 0x00, 0x80),&rectRegion);
+					}
+				}
+			DEBUGOSB
+			}
+
+		DEBUGOSB			
+		iScreen.SpriteManager()->DrawFloatingSprites(stageGc,accumulatedDrawing); // we limit sprite drawing over only actually affected ares but necessary to all "planned" for redraw
+		if (!accumulatedDrawing.CheckError() && iScreen.SpriteManager()->SpriteCount() == 0)
+			{
+			iAnimationRegion = &accumulatedDrawing;
+			}
+
+		// Tell the render stage we've finished:
+		iRenderStages->End();
+		
+		// We nolonger need the regions
+		for (CWsWindow * win = scheduler->HeadWindow(); win; win = win->NextScheduled())
+			{
+			win->ClearScheduledRegion();
+			}
+			
+		CWsMemoryManager::Static()->DisableReserve();
+
+		if (const CDebugBar* dbg = iScreen.DebugBar())
+			{
+			dbg->RedrawDebugBar();
+			}
+
+		// At this point, if the DEBUG_REGION is being used, there should usually be only green regions
+		// displayed.  If we see red or yellow, then something didn't get redrawn that should have been.
+		// If we see purple then a window has disobeyed the const setting on the region to draw.
+		// Red or yellow is valid - a window can decide it isn't ready to draw yet - purple is very bad.
+		iScreen.Update();
+		// At this point, if the DEBUG_REGION is being used, there should be no regions visible
+		// of any colour.  If we see green, then it means an area of the screen was drawn to which
+		// wasn't invalid, or the screen update call failed.  The former is more likely.
+		// If we still see red or yellow it is a region that is not yet ready to draw.
+
+		const TRect* rect = iAnimationRegion->RectangleList();
+		TInt pixels = 0;
+		for(TInt r = iAnimationRegion->Count(); r>0; r--)
+			{
+			pixels += (rect->Width()*rect->Height());
+			rect++;
+			}
+		CWsActiveScheduler::Static()->StopDraw(pixels);
+		
+		TWindowServerEvent::NotifyScreenDrawingEvent(iAnimationRegion);
+
+		iAnimationRegion = 0;
+		accumulatedDrawing.Close();
+		iInvalid.Clear();
+		}
+	else
+		{
+		CWsActiveScheduler::Static()->CancelPrepare();
+		}
+
+	iInvalid.Clear();
+	iTopLayer.Clear();
+	invalidCopy.Close();
+	iAnimating = EFalse;
+	
+	if (futureAnimationRequired && iTimedDrawRect.Count() > 0 && !iScheduled)
+		{
+		// If this flag is set then it means there were already some animations scheduled when we ran,
+		// but they themselves didn't run.  We need to make sure we have _something_ scheduled.
+		CWsTop::WindowServer()->AnimationScheduler()->ScheduleAnimation(iScreen, iTimedDrawRect[0].iTime);
+		iScheduled = ETrue;
+		}
+	
+	if(iObserver)
+		{
+		iObserver->ScreenUpdated(iScreen.ScreenNumber());
+		iObserver=NULL; //once signalled we are never going to call it again
+		}
+	LOG_SCREEN_REDRAW_END
+	}
+
+//
+void CScreenRedraw::DiscardAllSchedules()
+	{
+	ASSERT(!iAnimating);
+	
+	iTimedDrawRect.Reset();
+	iInvalid.Clear();
+	iInvalid.Tidy();
+	}
+
+/**
+Indicates that a window has moved or changed ordinal position so that the visible regions
+of all windows needs to be recalculated
+*/
+void CScreenRedraw::ScheduleRegionUpdate(const TRegion* aDefinitelyDirty)
+	{
+	iRegionUpdateScheduled = ETrue;
+	ScheduleRedraw();
+	if(aDefinitelyDirty)
+		{
+		iInvalid.Union(*aDefinitelyDirty);
+		// Cyan regions for invalidations caused by this:
+		DEBUG_REGION(TRgb(0x00, 0xFF, 0xFF),TRgb(0x00, 0xFF, 0xFF, 0x20),aDefinitelyDirty);
+		}
+	}
+	
+/**
+Recalculates visible regions and schedules redraws or queues redraw events in response to
+any changes
+*/
+void CScreenRedraw::RegionUpdate()
+	{
+	if (iRegionUpdateScheduled)
+		{
+		iRegionUpdateScheduled = EFalse;
+		
+		TWalkWindowTreeUpdateRegions updater(iScreen);
+		updater.Walk();
+
+		WsPointer::ReLogCurrentWindow();
+		CWsTop::TriggerRedraws(iScreen.RootWindow());
+		}
+	}
+
+void CScreenRedraw::SetObserver(MWsScreenRedrawObserver* aObserver)
+	{
+	iObserver = aObserver;
+	}
+
+TBool CScreenRedraw::IsUpdatePending()
+	{
+	if(iScheduled || iAnimating)
+		return ETrue;
+	else 
+		return EFalse;
+	}
+
+/**
+ Overidding MWsObjectProvider
+*/
+TAny* CScreenRedraw::ResolveObjectInterface(TUint aTypeId)
+	{
+	TAny* interface = NULL;
+
+	switch (aTypeId)
+		{
+		case KWsScreenRedraw:
+			interface = static_cast<MWsScreenRedraw*>(this);
+			break;
+		}
+
+	if (!interface)
+		{
+		interface = iRenderStages->ResolveObjectInterface(aTypeId);
+		}
+	
+	return interface;
+	}
+
+const TRegion * CScreenRedraw::AnimationRegion() const
+	{
+	if (iAnimating)
+		return iAnimationRegion;
+	else
+		return 0;
+	}
+
+void CScreenRedraw::UpdateDevice()
+	{
+	iScreen.Update();
+	}
+
+void CScreenRedraw::BanThisRegionUpdate( TRegion& aForbiddenRegion )
+	{
+	iBannedRegion.Union( aForbiddenRegion );
+	iBannedRegion.Tidy();
+	}
+
+void CScreenRedraw::LiftRegionUpdateBan( TRegion& aFormerForbiddenRegion  )
+	{
+	iBannedRegion.SubRegion( aFormerForbiddenRegion );
+	iBannedRegion.Tidy();
+	}
+
+void CScreenRedraw::AcceptFadeRequest( CWsWindow* aWin, TBool aFadeOn, TBool aFadeBehind, TBool aIncludeChildren )
+	{
+	if ( aFadeOn )
+		{
+		TWalkWindowTreeScheduleFadeNoRedraw walkerFadeNoRedraw;
+		if ( aFadeBehind )
+			{
+			aWin->WalkWindowTree( walkerFadeNoRedraw, EWalkBehind );				
+			}
+		else
+			{
+			if(aWin->WinType() != EWinTypeGroup)
+				{
+				ScheduleRegionUpdate( aWin->VisibleRegionIfValid() );
+				}
+			
+			if ( aIncludeChildren )
+				{
+				aWin->WalkWindowTree( walkerFadeNoRedraw, EWalkChildren );
+				}				
+			}
+		}
+	else
+		{	// fade off, just initiate redraw
+		TWalkWindowTreeScheduleRedraws walkerRedraw( TWalkWindowTreeScheduleRedraws::ERedrawFilterOmitDSA ) ;
+		if ( aFadeBehind )
+			{
+			aWin->WalkWindowTree( walkerRedraw, EWalkBehind );								
+			}
+		else
+			{ // fade this win not behind
+			if ( !aWin->IsDSAHost() )
+				{
+				AddRedrawRegion( aWin->VisibleRegion() );
+				}
+			if ( aIncludeChildren )
+				{
+				aWin->WalkWindowTree( walkerRedraw, EWalkChildren );
+				}				
+			}			
+		}		
+	ScheduleRegionUpdate(NULL);
+	}