windowing/windowserver/tauto/tcrpanim.cpp
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/tauto/tcrpanim.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,1464 @@
+// Copyright (c) 2007-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:
+// Implements  CTCrpAnim
+// Test CRP animations & their interaction with overlapping transparent/non-transparent windows 
+// & wserv's underlying redraw-store strategies
+// 
+//
+
+/**
+ @file
+ @test
+ @internalComponent - Internal Symbian test code
+*/
+
+#include <w32stdgraphic.h>
+#include "tcrpanim.h"
+
+// RUN_SAMPLE_ON_LEFT allows the demo animation to run in the left-hand window during testing. 
+// Used for demonstration purposes only
+#define RUN_SAMPLE_ON_LEFT
+
+namespace	//anonymous local scope
+	{
+	const TInt KAnimationFrameDelayTime = 50000; 				// delay in microseconds between frames
+	const TInt KShortDelayLoop = 2*KAnimationFrameDelayTime; 	// delay time in microseconds used in test cases
+	const TInt KAnimationTotalFrames = 40;						// total number of frames in a CWsGraphicBitmapAnimation
+	const TInt KAnimDimension = 40;								// animation width/height. We're enforcing a square animation here
+	const TInt KFrameMissedAnimationsThreshold = 10;			// maximum number of missed frame steps allowed
+	const TInt KAnimationTearWidthThreshold = 4; 				// maximum columns permitted between a tear
+	const TInt KMinGoodFrameThreshold = 30; 					// percentage threshold for number of good frames detected in a test
+	const TInt KMaxXY = 200;									// arbitrary maximum size of square used to invalidate a window
+	const TInt KMaxRepeatDraw = 2;								// arbitrary value for DrawLine calls during a Draw
+	TUid  KUidTestAnimation2 = {0xBAADF00D};					// unique id. for CWsGraphicBitmapAnimation object
+	const TUint32 KWhitePixels = 0xFFFFFFFF;					// 32-bit mask value for rgb white
+	const TUint32 KBlackPixels = 0x00000000;					// 32-bit value for rgb black
+	const TPoint KPointZero(0,0);								// initial point used for animation creation & manipulation (currently 0,0)
+	const TPoint KPointOffsite(1000,1000);						// point used to draw off-screen
+	const TDisplayMode KTestDisplayMode = EColor16MU;			// display mode used for testing
+	const TInt KFrameStepCalculation = Max(1, KAnimDimension/Max(1, KAnimationTotalFrames)); // determine framestep size in columns
+	
+	enum TColorDetected
+		{
+		ECantTell=0,
+		EDetRed=1,
+		EDetGreen=2,
+		EDetBlue=4,
+		EDetBlack=0x10,
+		EDetGrey=0x20,
+		EDetWhite=0x40
+		};
+
+	class CCrpAnim;		
+	class CAnimRedrawWindow : public CTWin
+		{
+	public:
+		CAnimRedrawWindow(CCrpAnim *aAnimWindow, TBool aIsBase);
+		~CAnimRedrawWindow();
+		void Draw();
+	private:
+		CCrpAnim *iAnimWindow;
+		TBool iIsBase;
+		};
+		
+	class CCrpAnim : public CBase
+		{
+		friend class CAnimRedrawWindow;
+	public:
+		enum TWinType
+			{
+			ERedraw,
+			EBlank,		// note: not currently used in tcrpanim tests
+			EBackedUp	// note: not currently used in tcrpanim tests
+			};
+	public:
+		CCrpAnim(TBool aIsBase, TWinType aWinType);
+		~CCrpAnim();
+		enum 
+			{
+			ENoTransparency=0x100
+			};
+		void ConstructL(const TPoint &aPos, const TSize &aSize,const TInt aAlphaValue=ENoTransparency);
+		void DoDraw(TBool aBlankIt);
+		inline void DoDraw();
+		void DoDrawEllipse();
+		inline TSize Size() {return iCtWin->Size();};
+		inline RWindowBase* BaseWin() const {return iCtWin->BaseWin();};
+		inline RWindow* Window() const {return STATIC_CAST(RWindow*, iCtWin->BaseWin());};
+		inline CTBaseWin* CtBaseWin() {return iCtWin;};
+		inline void Invalidate() {CTUser::Splat(TheClient, TRect(iCtWin->Position(), iCtWin->Size()), KRgbGray);};
+		void Invalidate(const TRect &aRect);
+		static void SetEllipseDrawMode(CGraphicsContext::TDrawMode aEllipseDrawMode);
+		void InvalidateAndRedraw(TBool aUseBlankItMember,TBool aBlankIt,TBool aUseRWindowInvalidate,TRect* aRect=NULL);
+
+		//A bit of an animation interface...
+		//I have written this interface to be amenable to playing multiple animations,
+		//which I think needs testing,
+		//but the underlying implementation assumes one animation at present.
+		//Your mission, should you choose to accept it, ....
+		
+		void SetPosAnimation(const TUid& aUid, const TRect& aRect);
+		TRect* GetPosAnimation(const TUid& aUid);
+		TWsGraphicAnimation* SetAnimation(TUid);	
+		TWsGraphicAnimation* GetAnimation(TUid);	
+		TBool RemoveAnimation(TUid);	
+		inline void	SetBlankIt(TBool aNewVal) {iBlankIt = aNewVal;};
+		inline void SetRepeatDrawMax(TInt aVal) {iRepeatDrawMax = aVal;};
+	protected:
+		static void Draw(CBitmapContext *aGc, const TSize &aSize, TBool aIsBase,const TRect &aRect, TBool aBlankIt,TInt aRepeat, TInt aAlphaValue);
+		static void DrawEllipse(CBitmapContext *aGc, const TRect &aRect, TInt aAlphaValue);
+		CTBaseWin *iCtWin;
+		TWinType iWinType;
+		TBool iIsBase;
+		TBool iBlankIt;
+		TRect iRect;
+		TInt  iRepeatDrawMax;
+		static CGraphicsContext::TDrawMode iEllipseDrawMode;
+		TUid  iAnimUid;
+		TWsGraphicAnimation iAnimData;
+		TRect iAnimPos;
+		TInt iAlphaValue;
+		};
+
+/*	    Using this time delay class in order to allow animations to play in our draw.
+		User::Wait does not allow the draw to occur (aparrently)
+		Note when using this time-delay class: because other active objects can perform part of their
+	    processing whilst we wait, wrapping calls to this in __UHEAP_MARK / __UHEAP_MARKEND
+	    is likely to fail.  The data providers and animators are a major cause of this. 
+*/
+	class CActiveWait : public CActive
+		{
+	public:
+		static CActiveWait* NewL();
+		~CActiveWait();
+		void Wait(TInt aDelay);
+		// From CActive:
+		void RunL();
+		void DoCancel();
+		TInt RunError(TInt aError);
+	protected:
+		CActiveWait();
+		void ConstructL();
+	protected:
+		RTimer iTimer;
+		TTime iFromTime;
+		};
+
+	CActiveWait* CActiveWait::NewL()
+		{
+		CActiveWait* self = new (ELeave) CActiveWait;
+		CleanupStack::PushL(self);
+		self->ConstructL();
+		CleanupStack::Pop(self);
+		return self;
+		}
+		
+	void CActiveWait::ConstructL()
+		{
+		User::LeaveIfError(iTimer.CreateLocal());
+		CActiveScheduler::Add(this);
+		}
+		
+	CActiveWait::CActiveWait() : CActive(EPriorityNormal)
+		{
+		iFromTime.HomeTime();
+		}
+
+	CActiveWait::~CActiveWait()
+		{
+		Cancel();
+		iTimer.Close();
+		}
+
+	void CActiveWait::DoCancel()
+		{
+		iTimer.Cancel();
+		CActiveScheduler::Stop();
+		}
+
+	void CActiveWait::RunL()
+		{
+		CActiveScheduler::Stop();
+		}
+		
+	TInt CActiveWait::RunError(TInt aError)
+		{
+		return aError; // exists so a break point can be placed on it.
+		}
+
+/*	    Note when using this : because other active objects can perform part of their
+	    processing whilst we wait, wrapping calls to this in __UHEAP_MARK / __UHEAP_MARKEND
+	    is likely to fail.  The data providers and animators are a major cause of this. 
+*/
+	void CActiveWait::Wait(TInt aDelay)
+		{
+		iTimer.After(iStatus, aDelay);
+		SetActive();
+		CActiveScheduler::Start();
+		}
+	CGraphicsContext::TDrawMode CCrpAnim::iEllipseDrawMode;
+
+//
+	}	//end anonymous local scope
+//
+
+/** This fn allocates an animation frame of the specified dimensions.
+	Not tested outside the current limited parameter set (16/2/2007).
+	Note the use of 32-bit integers for pixel/colour values. Using display mode lower than 24bpp may not produce correct results
+	My attempt to write animation generating code that avoids CIclLoader and Decoder class.
+	@param aDelayUs	 	the display time for the frame
+	@param aImageType	Colour format for colour plane. 24MA currently not flagged correctly I expect.
+	@param aMaskType	Format for mask. ENone for no mask.
+	@param aImageSize	Width/height of bitmap area
+	@param aImageOffset	Optional offset for bitmap area
+	@param aTotalSize	Optional width/height of whole animation (I think)
+	@return CFrame		filled in with allocated bitmaps. The get methods for the bitmaps return const type.
+**/
+static CWsGraphicBitmapAnimation::CFrame* NewFrameLC(TInt aDelayUs,TDisplayMode aImageType,TDisplayMode aMaskType,const TSize& aImageSize,const TPoint& aImageOffset=KPointZero,const TSize& aTotalSize=TSize(0,0))
+	{
+	TFrameInfo info;
+	info.iFrameCoordsInPixels = TRect(aImageOffset,aImageSize);
+	info.iFrameSizeInTwips = aImageSize;	  //this is zero in the gif loader
+	info.iDelay = TTimeIntervalMicroSeconds(aDelayUs);
+	info.iFlags = TFrameInfo::EColor|TFrameInfo::ELeaveInPlace|TFrameInfo::EUsesFrameSizeInPixels;
+	if (aMaskType != ENone)
+		{
+		info.iFlags|=TFrameInfo::ETransparencyPossible;
+		}
+	if ((aTotalSize.iHeight > 0) && (aTotalSize.iWidth > 0))
+		{
+		// restrict the size of the frame to specified size of the animation
+		info.iOverallSizeInPixels = aTotalSize;
+		}
+	else
+		{
+		// assign the size of the frame to the size of the entire bitmap area
+		info.iOverallSizeInPixels = info.iFrameCoordsInPixels.iBr.AsSize();
+		}
+	info.iFrameDisplayMode = aImageType;
+	info.iBackgroundColor = KRgbGreen;
+
+	CWsGraphicBitmapAnimation::CFrame* frame = CWsGraphicBitmapAnimation::CFrame::NewL();
+	CleanupStack::PushL(frame);
+	frame->SetFrameInfo(info);
+	CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
+	frame->SetBitmap(bitmap); //takes ownership
+	TSize frameInfoSize = info.iFrameCoordsInPixels.Size();
+	User::LeaveIfError(bitmap->Create(frameInfoSize, aImageType));
+	if((TFrameInfo::EAlphaChannel|TFrameInfo::ETransparencyPossible) & info.iFlags)
+		{
+		CFbsBitmap* mask = new(ELeave) CFbsBitmap;
+		frame->SetMask(mask); //takes ownership
+		User::LeaveIfError(mask->Create(frameInfoSize, aMaskType));
+		}
+	return frame;
+	}
+
+//
+// function called back by TCleanupItem frameListCleanup from within CreateAnimFramesL(..) method
+//
+void CleanupFrameList(TAny* aPtr)
+	{
+	RPointerArray<CWsGraphicBitmapAnimation::CFrame>* ptrArray = STATIC_CAST(RPointerArray<CWsGraphicBitmapAnimation::CFrame>*, aPtr);
+	ptrArray->ResetAndDestroy();
+	ptrArray->Close();
+	}
+
+/** Helper function for making animation frames.
+	//Called from CreateAnimL(...)
+	@param aDelayUs		the delay between frames
+	@param aNumFrames	number of frames (approx - image width is a factor)
+	@param aImageType	colour format of colour data. This may not work properly for non-32-bit, but I haven't fully understood TBitmapUtil documentation.
+	@param aMaskType	format for mask - ENone for no mask.
+	@param aImageSize	width/height of animation
+	@param aBgCol		background colour for image non-masked areas. Masked areas are black.
+	@param aFgCol		foreground colour of animating area
+	@param aFrames		frames that the animation is constructed from
+**/
+static void CreateAnimFramesL(TInt aDelayUs,TInt aNumFrames,TDisplayMode aImageType,TDisplayMode aMaskType,TSize aImageSize,TRgb aBgCol,TRgb aFgCol, RPointerArray<CWsGraphicBitmapAnimation::CFrame>& aFrames)
+	{
+	const TInt 	animWH = aImageSize.iWidth;
+	const TInt	animStep = Max(1,animWH/Max(1,aNumFrames));	//note this intentionally rounds down to avoid overflows
+	for (TInt ii = 0 ; ii < animWH ; ii += animStep)
+		{
+		CWsGraphicBitmapAnimation::CFrame* frame = NewFrameLC(aDelayUs,aImageType,aMaskType,aImageSize,KPointZero,aImageSize);
+		aFrames.AppendL(frame);
+		CleanupStack::Pop(frame);
+		TBitmapUtil utilMask(CONST_CAST(CFbsBitmap*, frame->Mask()));
+		TBitmapUtil utilCol(CONST_CAST(CFbsBitmap*, frame->Bitmap()));
+		utilCol.Begin(KPointZero);
+		
+		// cycle through the frame's actual bitmap & assign each pixel a value identical to the specified colours
+		TUint32 colback=aBgCol.Internal();
+		TUint32 colfront=aFgCol.Internal();
+		TInt row = KErrNone;
+		TInt col = KErrNone;
+		for (row = 0 ; row < aImageSize.iHeight ; row++)
+			{
+			utilCol.SetPos(TPoint(0, row));
+			for (col = 0 ; col < aImageSize.iWidth ; col++)
+				{
+				utilCol.SetPixel(colback);	
+				utilCol.IncXPos();
+				}
+			utilCol.SetPos(TPoint(ii, row));
+			for (col = 0 ; col < animStep ; col++)	  //Note I rely on intentional rounding down here!
+				{
+				utilCol.SetPixel(colfront);	
+				utilCol.IncXPos();
+				}			
+			}
+		
+		if (aMaskType)
+			{
+			// cycle through each pixel of the frame's mask & assign a default pixel a colour value
+			utilMask.Begin(KPointZero);
+			for (row = 0 ; row < aImageSize.iHeight ; row++)
+				{
+				utilMask.SetPos(TPoint(0,row));
+				for (col = 0 ; col < aImageSize.iWidth ; col++)
+					{
+					utilMask.SetPixel(KWhitePixels);
+					utilMask.IncXPos();
+					}
+				}
+			
+			const TInt maxmaskWidth = Min(8,Max(animWH/3,2));
+
+			//cut the corners off the mask
+			for (row = 0 ; row < maxmaskWidth ; row++)
+				{
+				TInt currentX = maxmaskWidth - row;
+				TInt xPos = KErrNone;
+
+				utilCol.SetPos(TPoint(0,row));
+				utilMask.SetPos(TPoint(0,row));
+				for(xPos = currentX ; xPos >= 0 ; xPos--)
+					{
+					utilCol.SetPixel(KBlackPixels);	
+					utilCol.IncXPos();
+					utilMask.SetPixel(KBlackPixels);	
+					utilMask.IncXPos();
+					}
+
+				utilCol.SetPos(TPoint(animWH - 1, row));
+				utilMask.SetPos(TPoint(animWH - 1, row));
+				for(xPos = currentX ; xPos >= 0 ; xPos--)
+					{
+					utilCol.SetPixel(KBlackPixels);	
+					utilCol.DecXPos();
+					utilMask.SetPixel(KBlackPixels);	
+					utilMask.DecXPos();
+					}
+
+				utilCol.SetPos(TPoint(0, animWH - 1 - row));
+				utilMask.SetPos(TPoint(0, animWH - 1 - row));
+				for(xPos = currentX ; xPos >= 0 ; xPos--)
+					{
+					utilCol.SetPixel(KBlackPixels);	
+					utilCol.IncXPos();
+					utilMask.SetPixel(KBlackPixels);	
+					utilMask.IncXPos();
+					}
+
+				utilCol.SetPos(TPoint(animWH - 1, animWH - 1 - row));
+				utilMask.SetPos(TPoint(animWH - 1, animWH - 1 - row));
+				for(xPos = currentX ; xPos >= 0 ; xPos--)
+					{
+					utilCol.SetPixel(KBlackPixels);	
+					utilCol.DecXPos();
+					utilMask.SetPixel(KBlackPixels);	
+					utilMask.DecXPos();
+					}
+				}
+			utilMask.End();
+			}
+		utilCol.End();
+		}
+	}
+
+/** My attempt to write animation generating code that avoids CIclLoader and Decoder class.
+	//It is better if this test class used it's own generated animation
+	//rather than relying on the GIF loader in order to reduce the cross-dependencies.
+	//The animation generated is a simple vertical line moving from left to right.
+	//To prove the masking, I cut the corners off.
+	@param aDelayUs		the delay between frames
+	@param aNumFrames	number of frames (approx - image width is a factor)
+	@param aImageType	colour format of colour data. This may not work properly for non-32-bit, but I haven't fully understood TBitmapUtil documentation.
+	@param aMaskType	format for mask - ENone for no mask.
+	@param aImageSize	width/height of animation
+	@param aBgCol		background colour for image non-masked areas. Masked areas are black.
+	@param aFgCol		foreground colour of animating area
+	@param aTUid		TUid assigned to animation
+	@return CWsGraphicBitmapAnimation allocated to represent the final animation	
+**/
+static CWsGraphicBitmapAnimation* CreateAnimL(TInt aDelayUs,TInt aNumFrames,TDisplayMode aImageType,TDisplayMode aMaskType,TSize aImageSize,TRgb aBgCol,TRgb aFgCol,TUid& aTUid)
+	{
+	RPointerArray<CWsGraphicBitmapAnimation::CFrame> frames;
+	TCleanupItem frameListCleanup(CleanupFrameList, &frames);
+	CleanupStack::PushL(frameListCleanup);
+	
+	CreateAnimFramesL(aDelayUs, aNumFrames, aImageType, aMaskType, aImageSize,aBgCol, aFgCol, frames);
+	
+	CWsGraphicBitmapAnimation* anim = CWsGraphicBitmapAnimation::NewL(aTUid,frames.Array());
+	CleanupStack::PopAndDestroy(&frames);
+	return anim;
+	}
+
+//
+// Describes the pure colour of the RGB value. yellow/magenta/cyan set 2 bits. White/grey is seperately flagged.
+// This method attempts to determine the strongest primary colour present in any given pixel. 
+// Note: The algorithm used is known to work for the current test cases only but requires careful review
+// for anyone making additional changes to tcrpanim. Given time, improved algorithm should be developed
+// to replace the current one
+//
+TUint PredominantColour(TUint aCol)
+	{	 //I don't like all these ifs, but I don't see an easy alternative
+		 //Possibly a bit look-up of the deltas from average would work 
+		 //(ignoring the bottom 5 bits =32, not 0x30=48. Ignore bottom 4 bits and accept 3-same answers, or divide by delta?)
+		 //
+	const TInt Kdelta=0x30;
+	TInt red=(aCol&0x00ff0000)>>16;
+	TInt green=(aCol&0x0000ff00)>>8;
+	TInt blue=(aCol&0x000000ff);
+	TInt ave=((red+green+blue)*(65536/3))>>16;
+	TBool rOverA=(red>ave);
+	TBool gOverA=(green>ave);
+	TBool bOverA=(blue>ave);
+	TInt numOverAve=(rOverA?1:0)+(gOverA?1:0)+(bOverA?1:0);
+
+	if (numOverAve==1)
+		{
+		if (rOverA)
+			{
+			if (red>ave+Kdelta)
+				{
+				if ((green-blue)>-Kdelta && (green-blue)<Kdelta)
+					return  EDetRed;
+				}
+			else
+				{
+				if (ave<Kdelta)
+					return EDetBlack;
+				else
+					{
+					if (green>ave-Kdelta && blue>ave-Kdelta)
+						{
+						if (ave>256-Kdelta)
+							return EDetWhite;
+						else
+							return EDetGrey;
+						}
+					}
+				}
+			}
+				
+		if (gOverA)
+			{
+			if (green>ave+Kdelta)
+				{
+				if ((blue-red)>-Kdelta && (blue-red)<Kdelta)
+					return  EDetGreen;
+				}
+			else
+				{
+				if (ave<Kdelta)
+					return EDetBlack;
+				else
+					{
+					if (red>ave-Kdelta && blue>ave-Kdelta)
+						if (ave>256-Kdelta)
+							return EDetWhite;
+						else
+							return EDetGrey;
+					}
+				}
+			}
+
+		if (bOverA)
+			{
+			if (blue>ave+Kdelta)
+				{
+				if ((green-red)>-Kdelta && (green-red)<Kdelta)
+					return  EDetBlue;
+				}
+			else
+				{
+				if (ave<Kdelta)
+					return EDetBlack;
+				else
+					{
+					if (red>ave-Kdelta && green>ave-Kdelta)
+						if (ave>256-Kdelta)
+							return EDetWhite;
+						else
+							return EDetGrey;
+					}
+				}
+			}
+		}
+	else	
+		{
+		if (!rOverA)
+			 if (red<ave-Kdelta)
+			 	{
+			 	if ((green-blue)>-Kdelta && (green-blue)<Kdelta)
+			 		return EDetGreen|EDetBlue;
+			 	}
+			 else
+				{
+				if (ave>256-Kdelta)
+					return EDetWhite;
+				else
+					{
+					if (blue<ave+Kdelta && green<ave+Kdelta)
+						{
+						if (ave<Kdelta)
+							return EDetBlack;
+						else
+							return EDetGrey;
+						}
+					}
+				}
+
+		if (!gOverA)
+			{
+			if (green<ave-Kdelta)
+				{
+				if ((blue-red)>-Kdelta && (blue-red)<Kdelta)
+					return  EDetRed|EDetBlue;
+				}
+			 else
+				{
+				if (ave>256-Kdelta)
+					return EDetWhite;
+				else
+					{
+					if (blue<ave+Kdelta && red<ave+Kdelta)
+						if (ave<Kdelta)
+							return EDetBlack;
+						else
+							return EDetGrey;
+					}
+				}
+			}
+
+		if (!bOverA)
+			{
+			if (blue<ave-Kdelta)
+				{
+				if ((green-red)>-Kdelta && (green-red)<Kdelta)
+					return  EDetGreen|EDetRed;
+				}
+			 else
+				{
+				if (ave>256-Kdelta)
+					return EDetWhite;
+				else
+					{
+					if (red<ave+Kdelta && green<ave+Kdelta)
+						if (ave<Kdelta)
+							return EDetBlack;
+						else
+							return EDetGrey;
+					}
+				}
+			}
+		}
+	return ECantTell;
+	}
+
+/**
+	Helper fn to ensure I put the anims in the same place each time...
+**/
+void CalcCentredAnimPosition(TRect& aRect,const TSize& aWinSize)
+	{
+	aRect.Shrink(aWinSize.iWidth*3/8,aWinSize.iHeight*4/10);
+	}
+
+CTCrpAnim::CTCrpAnim(CTestStep* aStep) : 
+	CTWsGraphicsBase(aStep)
+	{
+	}
+
+void CTCrpAnim::ConstructL()
+	{
+	TheClient->iGroup->WinTreeNode()->SetOrdinalPosition(0);
+	iRedrawWin=new(ELeave) CCrpAnim(EFalse, CCrpAnim::ERedraw);
+	iBaseWin=new(ELeave) CCrpAnim(EFalse, CCrpAnim::ERedraw);
+	iOverWin=new(ELeave) CCrpAnim(EFalse, CCrpAnim::ERedraw);
+
+	TSize screenSize=TheClient->iGroup->Size();
+	TInt winWidth=(screenSize.iWidth/3)-10;
+	TInt winHeight=screenSize.iHeight-10;
+	TSize windowSize(winWidth,winHeight);
+
+	iRedrawWin->ConstructL(TPoint(screenSize.iWidth/3*2+5,5), windowSize);
+	iBaseWin->ConstructL(TPoint(screenSize.iWidth/3+5,5), windowSize);
+	
+	//Create a transparent window that exactly overlaps the test window
+	//If transparency is not supported the leave causes the window to be destroyed and set to NULL.
+	//There is a test for transparency supported, but that simply creates a temp window to test anyway... 
+	
+	//Note that when I originally wrote this test to fix PDEF101991, it generated white areas that I detected.
+	//However, if this transparent window used for extended tests is created over the test window,
+	//that somehow stops the white fill from occurring.
+	//The fault still occurs, but the previous screen contents are left behind.
+	//So now this window is created at an off-screen location.
+	TRAPD(err, iOverWin->ConstructL(KPointOffsite, windowSize, 0x80); iOverWin->SetBlankIt(ETrue); iOverWin->SetRepeatDrawMax(KMaxRepeatDraw););
+	if (err)
+		{
+		delete iOverWin;
+		iOverWin = NULL;
+		}
+	
+	iTestWin = iRedrawWin;
+	iTestWin->SetRepeatDrawMax(KMaxRepeatDraw);
+	iBaseWin->SetRepeatDrawMax(KMaxRepeatDraw);
+
+	// create animation object & share it with everyone
+	iAnim = CreateAnimL(KAnimationFrameDelayTime,KAnimationTotalFrames,KTestDisplayMode,EGray256,TSize(KAnimDimension, KAnimDimension),KRgbBlue,KRgbRed,KUidTestAnimation2);
+	if (!iAnim)
+		{
+		User::Leave(KErrNoMemory);
+		}
+	iAnim->ShareGlobally();
+	
+	// calculate minimum length of the red line
+	const TInt maxmaskHeight = Min(8, Max(KAnimDimension/3,2)); // note this calculation mimics that for the size of the corners cut from the mask in CreateAnimL above
+	iMinimumCalcRedLine = KAnimDimension - maxmaskHeight*2; // the height of the image minus the two cut corners
+
+	// create the timer object
+	iWaiter = CActiveWait::NewL();
+
+	// create screen bitmap object & scanline buffer
+	iScreenBitmap = new (ELeave) CFbsBitmap;
+	User::LeaveIfError(iScreenBitmap->Create(TSize(KAnimDimension, KAnimDimension), KTestDisplayMode));
+	TInt bufLength = iScreenBitmap->ScanLineLength(windowSize.iHeight, KTestDisplayMode);
+	iScanlineBuf = HBufC8::NewL(bufLength);
+	
+	#ifdef RUN_SAMPLE_ON_LEFT
+    	{
+		// play animation on iBaseWin window
+		iBaseWin->SetAnimation(KUidTestAnimation2)->Play(ETrue);
+		TSize subsize1 = iTestWin->BaseWin()->Size();
+		TRect subposition1(subsize1);
+		CalcCentredAnimPosition(subposition1, subsize1);
+		iBaseWin->SetPosAnimation(KUidTestAnimation2, subposition1);
+		iBaseWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
+    	}
+	#endif
+	}
+
+CTCrpAnim::~CTCrpAnim()
+	{
+	delete iRedrawWin;
+	delete iBaseWin;
+	delete iOverWin;
+	if (iAnim)
+		{
+		// destroy the animation object
+		iAnim->UnShareGlobally();
+		iAnim->Destroy();
+		delete iAnim;				
+		iAnim = NULL;
+		}
+	if (iWaiter)
+		{
+		// destroy the timer object
+		delete iWaiter;
+		iWaiter = NULL;
+		}
+	if (iScreenBitmap)
+		{
+		// destroy the screen capture of the animation
+		delete iScreenBitmap;
+		iScreenBitmap = NULL;
+		}
+	if (iScanlineBuf)
+		{
+		// destroy the scanline buffer
+		delete iScanlineBuf;
+		iScanlineBuf = NULL;
+		}
+	User::After(200000);
+	}
+
+//
+// This method checks the animation contained in the aAnimWin window has progressed. That is 
+// that it's drawn a sufficient number of concurrent frames to screen & the animation is 
+// drawn properly to screen
+// returns a Bool identifying whether the animation is considered 'good' or not
+//  
+void CTCrpAnim::CheckAnimProgressedL(CAnonAnimWindow* aAnimWin, TInt aAdditionalFrameCount, TBool aCaptureFrameResult)
+	{
+	TBool goodAnimation = ETrue;
+
+	// retrieve the rect from the screen's bitmap that contains the animation
+	CWsScreenDevice* screen = TheClient->iScreen;
+	TRect animPos = *aAnimWin->GetPosAnimation(KUidTestAnimation2);
+	CTBaseWin* bWin = aAnimWin->CtBaseWin();
+	animPos.Move(bWin->Position());
+	User::LeaveIfError(screen->CopyScreenToBitmap(iScreenBitmap, animPos));
+	
+	TInt frameNum = DetermineApproxFrameNum(iScreenBitmap, aCaptureFrameResult); // determines the frame Number & checks quality of animation (no tearing, etc)
+	TBool frameIdentified=(frameNum>=0);
+	
+	if (aCaptureFrameResult)
+		{
+		if (frameIdentified)
+			{
+			if (iPreviousFrameNum != KErrNotFound)
+			 	{
+				if (iPreviousFrameNum < frameNum)
+					{
+					TInt frameStep = KFrameStepCalculation * aAdditionalFrameCount;
+					iPreviousFrameNum += frameStep; // move to our *expected* framenumber
+					if (frameNum > iPreviousFrameNum)
+						{
+						// the frame number is ahead of it's expected position
+						// This suggests we've possibly missed animating a frame in wserv
+						// or test code isn't getting a chance to execute as crp animations taking all cpu cycles
+						// If its significantly outside norms, we log the fact (as a performance metric)
+						TInt performance = ((frameNum - iPreviousFrameNum) / frameStep);
+						if (performance > KFrameMissedAnimationsThreshold)
+							{
+							iFrameStatus.iFrameSkipped++;
+							goodAnimation = EFalse;	
+							}	
+						}
+					// else we're animating above an acceptable threshold
+					}
+				else if (iPreviousFrameNum == frameNum) // potentially not animating anymore
+					{
+					iFrameStatus.iFrameIdentical++;
+					goodAnimation = EFalse;
+					}
+				// else animation is progressing fine
+				}
+			// ignore iPreviousFrameNum == KErrNotFound
+			}
+		else
+			{
+			goodAnimation = EFalse; // couldn't id the red line	
+			}
+
+		if (goodAnimation)
+			{
+			iFrameStatus.iFrameOK++;
+			}
+		}
+	// else we were only interested in calculating the frameNum
+	iPreviousFrameNum = frameNum;
+	}
+
+//
+// method to estimate the framenumber based on the location of the thin, red line. 
+// Also checks whether tearing of the animation has occured or the animation
+// is only partially drawn. 
+// These are known issues with wserv animation performance & so we give some allowance for error
+// 
+TInt CTCrpAnim::DetermineApproxFrameNum(CFbsBitmap* aBitmap, TBool aCaptureFrameResult)
+	{
+	TInt colFirstTear = KErrNotFound; 	// column id'ing the first tear in the vertical line
+	TPtr8 des = iScanlineBuf->Des();	// ptr to the scanline buffer
+
+	// locate the thin, red line in the bitmap
+	for (TInt xPos = 0 ; xPos < aBitmap->SizeInPixels().iWidth ; xPos++)
+		{
+		aBitmap->GetVerticalScanLine(des, xPos, EColor16MA);
+		TUint32* pixel = (TUint32*) des.Ptr();
+		TInt colour = KErrNone;
+		
+		for (TInt ii = 0 ; ii < aBitmap->SizeInPixels().iHeight ; ii++)
+			{
+			colour = PredominantColour(*pixel);
+			if (colour & EDetRed)
+				{
+				if (colFirstTear < 0)
+					{
+					// check the length of the red line is a good length
+					pixel += (iMinimumCalcRedLine - 1); // minus the one pixel to position on last pixel in red line
+					colour = PredominantColour(*pixel);
+					if (colour & EDetRed)
+						{
+						// good line
+						return xPos;
+						}
+					else // we've detected first part of a torn line
+						{
+						colFirstTear = xPos; 
+						}
+					}
+				else
+					{
+					// located second part of torn line
+					if ((xPos - colFirstTear) > KAnimationTearWidthThreshold)
+						{
+						if (aCaptureFrameResult)
+							{
+							iFrameStatus.iFrameTearing++;	
+							}
+						xPos = KErrNotFound;
+						}
+					return xPos;
+					}	
+				break;
+				}
+			pixel++;
+			}
+		}
+	if (aCaptureFrameResult)
+		{
+		if (colFirstTear < 0)
+			{
+			iFrameStatus.iFrameEmpty++; // we never located any red line at all
+			}
+		else
+			{
+			iFrameStatus.iFramePartial++; // we only located a single, small part of the red line
+			}
+		}
+	return KErrNotFound;
+	}
+
+/**	This internal loop tests that the animation and the foreground interact correctly
+	The primary test is that the outline of the animation 
+	intersects the lines drawn on the foreground correctly, compared to a reference version.
+	The iBaseWin is already showing this reference anim.
+	If the animation is not drawn, or the foreground is wiped, then this test will fail.
+**/
+void CTCrpAnim::TestSpriteLoopL(TBool aAnimForeground,TBool aDrawForeground)
+	{
+	_LIT(KForegroundInfo,"TestSpriteLoop animForeground [%d] drawForeground [%d]");
+	INFO_PRINTF3(KForegroundInfo, aAnimForeground, aDrawForeground);
+	
+	if (!iOverWin && (aAnimForeground || aDrawForeground))
+		{
+		User::Leave(KErrGeneral); // unable to run this test without iOverWin
+		}
+
+	ResetFrameCounters();
+	iTestWin->RemoveAnimation(KUidTestAnimation2);
+	iTestWin->SetBlankIt(ETrue);		
+	if (iOverWin)
+		{
+		iOverWin->RemoveAnimation(KUidTestAnimation2);
+		iOverWin->SetBlankIt(ETrue);
+		}
+
+	// determine which window holds the animation, & which will be invalidated with progressively larger rects
+	CCrpAnim* animWin=aAnimForeground?iOverWin:iTestWin;
+	CCrpAnim* paintWin=aDrawForeground?iOverWin:iTestWin;
+	paintWin->SetBlankIt(EFalse);
+	
+	// set & play the animation on the specified window (animWin)
+	animWin->SetAnimation(KUidTestAnimation2)->Play(ETrue);
+	TSize subsize1 = paintWin->BaseWin()->Size();
+	TRect subposition1(subsize1);
+	CalcCentredAnimPosition(subposition1, subsize1);
+	animWin->SetPosAnimation(KUidTestAnimation2, subposition1);
+	
+	#ifdef RUN_SAMPLE_ON_LEFT
+		// play the demo animation in the left-hand window also
+		iBaseWin->InvalidateAndRedraw(ETrue, EFalse, ETrue);
+	#endif
+
+	iTestWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
+	if (iOverWin)
+		{
+		iOverWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
+		}
+	
+	// invalidate increasingly larger squares on paintWin 
+	// note, some fully overlap the animation, some partially overlap, and some don't overlap at all
+	TInt invalidateWaitTime=KAnimationFrameDelayTime*3/4; // microseconds
+	TInt temp = KErrNotFound;
+	for (TInt step=30;step<KMaxXY;step+=30)
+		{
+		for (TInt xx=0;xx<KMaxXY;xx+=step)
+			{
+			for (TInt yy=10;yy<KMaxXY;yy+=step)
+	    		{
+				// calculate rectangle & invalidate paintWin with it
+	    		TRect invalidRect(xx,yy,xx+step,yy+step);
+	    		paintWin->InvalidateAndRedraw(ETrue,EFalse,ETrue,&invalidRect);
+				
+				// calculate any additional frames that may be drawn by above. Note intentionally ignore frame result
+				temp = iPreviousFrameNum;	
+				CheckAnimProgressedL(animWin, 1, EFalse);
+				
+				//new defect DEF101896: Test runs faster with this line removed, but there is evident tearing
+				iWaiter->Wait(invalidateWaitTime);			//DEF101896 search string: //interrupt_foreground_draw
+				
+				if (temp == iPreviousFrameNum)
+					{
+					// give wserv more time to animate the frame
+					iWaiter->Wait(invalidateWaitTime);
+					}
+				CheckAnimProgressedL(animWin, 1); // calculate the frame drawn. Capture frame result
+				}
+			}
+		}
+
+	// determine whether the animation was successful (ie: enough Good frames were detected) or not
+	// Note KMinGoodFrameThreshold is essentially an arbitrary number. This can be adjusted to accommodate
+	// performance requirements as needed
+	temp = LogResults();
+	TInt quality = 100*iFrameStatus.iFrameOK/temp;
+	TEST(quality > KMinGoodFrameThreshold);
+	
+	ResetFrameCounters();
+	iWaiter->Cancel();
+	iTestWin->RemoveAnimation(KUidTestAnimation2);
+	iTestWin->SetBlankIt(ETrue);		
+	if (iOverWin)
+		{
+		iOverWin->RemoveAnimation(KUidTestAnimation2);
+		iOverWin->SetBlankIt(ETrue);
+		}
+	}
+
+//
+// resets the frame trackers to intial values
+//
+void CTCrpAnim::ResetFrameCounters()
+	{
+	iPreviousFrameNum = KErrNotFound;
+	iFrameStatus.iFrameOK = 0;
+	iFrameStatus.iFramePartial = 0;
+	iFrameStatus.iFrameIdentical = 0;
+	iFrameStatus.iFrameEmpty = 0;
+	iFrameStatus.iFrameTearing = 0;
+	iFrameStatus.iFrameSkipped = 0;
+	}
+
+//
+// Log the current frame results & return the total number of frame calculations
+//
+// Calculated : the total number of frame-checks run
+// Good: 		the frame was successfully drawn to screen & within specified tolerances for tearing, expected position & colour
+// Partial: 	the frame was only partially drawn to screen. Specifcally the animated red line was only partially drawn
+// Identical: 	the frame was in the same position as the last frame
+// Empty: 		no redline was detected at all in the frame
+// Skipped: 	the position of the frame was beyond the expected position
+//
+// There is a dependency on the timing as to when the frame is animated hence tolerances are used to allow
+// for this. 
+// 
+TInt CTCrpAnim::LogResults()
+	{
+	TInt result = iFrameStatus.iFrameOK + iFrameStatus.iFramePartial + iFrameStatus.iFrameIdentical + 
+				iFrameStatus.iFrameEmpty + iFrameStatus.iFrameTearing + iFrameStatus.iFrameSkipped;
+	INFO_PRINTF4(_L("\tAnimation results:  Calculated[%d], Good[%d], Partial[%d]"), result, iFrameStatus.iFrameOK, iFrameStatus.iFramePartial);
+	INFO_PRINTF5(_L("\tAnimation results:  Identical[%d], Empty[%d], Tearing[%d], Skipped[%d]"), iFrameStatus.iFrameIdentical, iFrameStatus.iFrameEmpty, iFrameStatus.iFrameTearing, iFrameStatus.iFrameSkipped);
+	return result;
+	}
+
+/** This test tests the result of drawing an animation and main draw to two windows that overlap.
+	The two windows are placed in exactly the same location, so the result of splitting the drawing across them should be "identical".
+	Note that when the anim and the draw are on different screens the lines are seen merged over the anim.
+**/
+void CTCrpAnim::TestOverlappingWindowsL()
+	{
+	if (!iOverWin)
+		{
+		INFO_PRINTF1(_L("- Test skipped - transparency not supported"));
+		return;
+		}
+		
+	// setup necessary params
+	// Note we place the overlapping transparent window (iOverWin) directly on top of the test window (iTestWin)
+	iOverWin->BaseWin()->SetPosition(iTestWin->BaseWin()->Position());
+		
+	enum 
+		{
+		 EAllBackground=0,
+		 EForegroundDraw=1,
+		 EForegroundAnim=2,
+		 EAllForeGround=3,
+		 ECountModes,
+		 EFirstMode=EAllBackground,
+		};
+	
+	// test the various permutations of overlapping vs animated windows
+	for (TInt mode = EFirstMode ; mode < ECountModes ; mode++)	    
+		{
+		INFO_PRINTF2(_L("TestOverlappingWindowsL [%d]"), mode);
+		TestSpriteLoopL((mode&EForegroundAnim)!=0,(mode&EForegroundDraw)!=0);
+		}
+	}
+	
+/**
+	This method demonstrates clipping of an animation running behind a transparent window.
+	No main window redraw takes place here.
+**/	
+void CTCrpAnim::DemoClippingWindowsL()
+	{
+	if (!iOverWin)
+		{
+		INFO_PRINTF1(_L("- Test skipped - transparency not supported"));
+		return;
+		}
+
+	// setup test case params. Note we calculate three different positions for the overlapping window
+	RWindow* win = iTestWin->Window();
+	
+	TPoint	screenPos= win->Position();
+	TSize screenSize = win->Size();	
+	TRect subposition1(screenSize);
+	CalcCentredAnimPosition(subposition1, screenSize);
+
+	TPoint testPositions[]=
+		{	
+		//first test: window clips corner of anim
+			TPoint(screenPos.iX+screenSize.iWidth/2-10,screenPos.iY+screenSize.iHeight/2-10),
+		//test: window clips all of anim
+			TPoint(screenPos.iX+screenSize.iWidth/3,screenPos.iY+screenSize.iHeight/3),
+		//test: window clips none of anim
+			TPoint(screenPos.iX+screenSize.iWidth*2/3,screenPos.iY+screenSize.iHeight*2/3),
+		};
+
+	// calculate roughly number of frames we expect to have drawn
+	TInt loopWaitTime = KShortDelayLoop; // time given to allow animation to progress (arbitrary number)
+	float expectedFrameCount = 1;
+	if (loopWaitTime > KAnimationFrameDelayTime)
+		{
+		expectedFrameCount = loopWaitTime/KAnimationFrameDelayTime;
+		}
+
+	for (TInt ii = 0; ii < ((sizeof testPositions)/(sizeof testPositions[0])) ; ii++)
+		{
+		// initialise test windows to known state with no active animations
+		ResetFrameCounters();
+		iTestWin->RemoveAnimation(KUidTestAnimation2);
+		iTestWin->SetBlankIt(EFalse);		
+		iOverWin->SetBlankIt(ETrue);		
+		iOverWin->RemoveAnimation(KUidTestAnimation2);
+
+		// position animation windows
+		iTestWin->SetAnimation(KUidTestAnimation2)->Play(ETrue);
+		iTestWin->SetPosAnimation(KUidTestAnimation2, subposition1);
+		iOverWin->BaseWin()->SetPosition(testPositions[ii]); // positions the transparent overlapping window
+
+		// redraw both test windows
+		iTestWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
+		iOverWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
+
+		// run the animation for an arbitrary period
+		for (TInt loopit = 0 ; loopit < 20 ; loopit++)
+			{
+			iWaiter->Wait(loopWaitTime);	
+			CheckAnimProgressedL(iTestWin,static_cast<TInt>(expectedFrameCount)); // log the frame result
+			}
+
+		// calculate & log frame results. Test an acceptable number of frames were successfully animated
+		TInt total = LogResults();
+		TInt qA = 100*iFrameStatus.iFrameOK/total;
+		TEST(qA > KMinGoodFrameThreshold);
+		}
+	}
+
+/**	In this version, the background window is updated in patches. 
+	If the animation intersects the transparent window then the whole transparent window is redrawn.
+**/	
+void CTCrpAnim::TestClippingWindowsL()
+	{
+	if (!iOverWin)
+		{
+		INFO_PRINTF1(_L("- Test skipped - transparency not supported"));
+		return;
+		}
+	// setup test case params. Note we calculate three different positions for the overlapping window
+	RWindow* win = iTestWin->Window();
+	TPoint screenPos= win->Position();
+	TSize screenSize = win->Size();	
+	
+	TPoint testPositions[]=
+		{	
+		//first test: window clips corner of anim
+			TPoint(screenPos.iX+screenSize.iWidth/2-10,screenPos.iY+screenSize.iHeight/2-10),
+		//test: window clips all of anim
+			TPoint(screenPos.iX+screenSize.iWidth/3,screenPos.iY+screenSize.iHeight/3),
+		//test: window clips none of anim
+			TPoint(screenPos.iX+screenSize.iWidth*2/3,screenPos.iY+screenSize.iHeight*2/3),
+		};
+
+	for (TInt loopIt = 0; loopIt < ((sizeof testPositions)/(sizeof testPositions[0])) ; loopIt++)
+		{
+	    iOverWin->BaseWin()->SetPosition(testPositions[loopIt]); // position the overlapping window
+	    TestSpriteLoopL(EFalse,EFalse);
+		}
+	}
+
+/**	This just demonstrates that an animation plays - for about 1 second.
+**/
+void CTCrpAnim::BasicCRPDemo()
+	{
+	// draw the animation in two positions
+	TSize subsize1 = iTestWin->BaseWin()->Size();
+	TRect subposition1(subsize1);
+	CalcCentredAnimPosition(subposition1, subsize1);
+	
+	if (iOverWin)
+		{
+		iOverWin->BaseWin()->SetPosition(KPointOffsite);	//way away!
+		iOverWin->InvalidateAndRedraw(EFalse,EFalse,ETrue);
+		}
+		
+	CCrpAnim *animWin= iTestWin;
+	animWin->SetAnimation(KUidTestAnimation2)->Play(ETrue);
+	animWin->SetPosAnimation(KUidTestAnimation2, subposition1);
+	iTestWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
+	iBaseWin->InvalidateAndRedraw(ETrue,EFalse,ETrue);
+
+	// allow the animation to play for ~1 second. Purpose is to demonstrate animation to an observer	
+	iWaiter->Wait(KShortDelayLoop);
+	
+	ResetFrameCounters();
+	iWaiter->Cancel();
+	iTestWin->RemoveAnimation(KUidTestAnimation2);
+	}
+
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-CRP01-0001
+
+@SYMDEF             DEF100356
+
+@SYMTestCaseDesc    CRP animation test for redraw storing interrupting main draw
+
+@SYMTestPriority    High
+
+@SYMTestStatus      Implemented
+
+@SYMTestActions     Creates a CRP animation and runs it on the server scheduler 
+					while also running redraws of the window.
+					
+					With Redraw storing this has been known to cause problems 
+					sharing and resetting the window iDisplayRegion.
+					This is evidenced by white areas.
+
+
+@SYMTestExpectedResults 
+					The LHS window shows what the animation should look like just animating,
+					while the RHS window demonstrates the simultanious animation and redraw.
+					No White patches should be in evidence, and no missing fragments of animation.
+					The TEST should detect white patches.
+*/
+void CTCrpAnim::TestSpriteInterruptsForegroundL()
+	{	
+	// setup test params
+	TSize subsize1(iTestWin->BaseWin()->Size());
+	TRect subposition1(subsize1);
+	CalcCentredAnimPosition(subposition1, subsize1);
+	if (iOverWin)
+		{
+		iOverWin->BaseWin()->SetPosition(KPointOffsite);	// ensure overlapping transparent window DOESN'T overlap the test window
+		}
+
+	// execute test loop
+	TestSpriteLoopL(EFalse,EFalse);
+	}
+
+void CTCrpAnim::RunTestCaseL(TInt /*aCurTestCase*/)
+	{
+	_LIT(KTest1,"1: Basic CRP demo");
+	_LIT(KTest2,"2: sprite anim interrupts foreground");
+	_LIT(KTest3,"3: translucent windows");
+	_LIT(KTest4,"4: CRP clipping windows");
+	_LIT(KTest5,"5: CRP & redraw clipping windows");
+	_LIT(KTest6,"6: CRP Invalidation");
+
+	((CTCrpAnimStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName);
+	switch(++iTest->iState)
+		{
+		case 1:
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-CRP01-0002
+*/
+			((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0002"));
+			iTest->LogSubTest(KTest1);
+			BasicCRPDemo();
+			break;
+		case 2:
+			((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0001"));
+			iTest->LogSubTest(KTest2);
+			TestSpriteInterruptsForegroundL();
+			break;
+		case 3:
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-CRP01-0003
+*/
+			((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0003"));
+			iTest->LogSubTest(KTest3);
+			TestOverlappingWindowsL();
+			break;
+		case 4:
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-CRP01-0004
+*/
+			((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0004"));
+			iTest->LogSubTest(KTest4);
+			DemoClippingWindowsL();
+			break;
+		case 5:
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-CRP01-0005
+*/
+			((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0005"));
+			iTest->LogSubTest(KTest5);
+			TestClippingWindowsL();
+			break;
+		case 6:
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-CRP01-0006
+*/
+			((CTCrpAnimStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-CRP01-0006"));
+			iTest->LogSubTest(KTest6);
+			//this testcase is removed, because invalidation is removed from CWsGraphicDrawer destructor (due to flickering)
+			break;
+		default:
+			((CTCrpAnimStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName);
+			((CTCrpAnimStep*)iStep)->CloseTMSGraphicsStep();
+			TestComplete();
+		}
+	((CTCrpAnimStep*)iStep)->RecordTestResultL();
+	}
+
+//
+namespace	//anonymous namespace
+	{
+//
+	CAnimRedrawWindow::CAnimRedrawWindow(CCrpAnim *aAnimWindow, TBool aIsBase) : CTWin(),
+		iAnimWindow(aAnimWindow),
+		iIsBase(aIsBase)
+		{
+		}
+
+	CAnimRedrawWindow::~CAnimRedrawWindow()
+		{
+		}
+
+	void CAnimRedrawWindow::Draw()
+		{
+		CCrpAnim::Draw(Gc(),Size(),iIsBase,iAnimWindow->iRect,iAnimWindow->iBlankIt,iAnimWindow->iRepeatDrawMax,iAnimWindow->iAlphaValue);
+		if (iAnimWindow->iAnimUid!=TUid::Null())
+			{
+			TheClient->Flush();
+			Gc()->DrawWsGraphic(iAnimWindow->iAnimUid,iAnimWindow->iAnimPos,iAnimWindow->iAnimData.Pckg());
+			TheClient->Flush();
+			}
+		}
+
+	//
+
+	CCrpAnim::CCrpAnim(TBool aIsBase, TWinType aWinType) 
+	:	iWinType(aWinType), 
+		iIsBase(aIsBase),
+		iBlankIt(EFalse),
+		iRepeatDrawMax(1),
+		iAnimUid(TUid::Null()),
+		iAlphaValue(ENoTransparency)
+		{
+		}
+
+	CCrpAnim::~CCrpAnim()
+		{
+		delete iCtWin;
+		}
+
+	void CCrpAnim::ConstructL(const TPoint &aPos, const TSize &aSize, TInt aAlphaValue)
+		{
+		TDisplayMode reqMode = EColor16MA; //for transparency we need 16ma or 16map mode
+		TDisplayMode *pReqMode=&reqMode;	
+		switch(iWinType)
+			{
+			case ERedraw:
+				iCtWin = new(ELeave) CAnimRedrawWindow(this, iIsBase);
+				break;
+			case EBlank:
+				iCtWin = new(ELeave) CTBlankWindow();
+				break;
+			case EBackedUp:
+				iCtWin = new(ELeave) CTBackedUpWin(EColor64K);
+				pReqMode = NULL;
+				break;
+			}
+		iCtWin->SetUpL(aPos, aSize, TheClient->iGroup, *TheClient->iGc, pReqMode, ETrue);
+		if (aAlphaValue != ENoTransparency)
+			{
+			User::LeaveIfError(Window()->SetTransparencyAlphaChannel());
+			//the window itself should be completely transparent, the draw commands will use the alpha value
+			Window()->SetBackgroundColor(TRgb(0, 0, 0, 0));
+			iAlphaValue = aAlphaValue;
+			}
+		}
+
+	void CCrpAnim::SetEllipseDrawMode(CGraphicsContext::TDrawMode aEllipseDrawMode)
+		{
+		iEllipseDrawMode = aEllipseDrawMode;
+		}
+
+	void CCrpAnim::DrawEllipse(CBitmapContext *aGc, const TRect &aRect, TInt aAlphaValue)
+		{
+		if(aAlphaValue != ENoTransparency)
+			{
+			aGc->SetBrushColor(TRgb(85,85,85, aAlphaValue));
+			aGc->SetPenColor(TRgb(170,170,170, aAlphaValue));
+			}
+		else
+			{
+			aGc->SetBrushColor(TRgb(85,85,85));
+			aGc->SetPenColor(TRgb(170,170,170));
+			}
+		aGc->SetDrawMode(iEllipseDrawMode);
+		aGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
+		aGc->DrawEllipse(aRect);
+		}
+
+	void CCrpAnim::Draw(CBitmapContext *aGc, const TSize &aSize, TBool aIsBase, const TRect &aRect, TBool aBlankIt,TInt aRepeat, TInt aAlphaValue)
+		{
+		static TInt sGrey=0;
+		sGrey+=3;
+		if (sGrey>0x40)
+			sGrey-=0x40;		
+		sGrey=sGrey^0x20;
+		if(aAlphaValue != ENoTransparency)
+			{
+			aGc->SetBrushColor(TRgb(sGrey, sGrey, sGrey, aAlphaValue));
+		    aGc->SetPenColor(TRgb(KRgbGreen.Value(), aAlphaValue));
+			}
+		else
+			{		
+			aGc->SetBrushColor(TRgb::Gray256(sGrey));
+		    aGc->SetPenColor(KRgbGreen);
+			}
+		aGc->Clear();
+	    TInt xPos=aSize.iHeight,yPos=aSize.iWidth;
+	    
+	    // The test windows are created relative to screen size. The
+	    // number of green lines generated needs to be tied into the
+	    // window size to prevent green becoming the dominant colour
+	    // when blended with the second animation, which would
+	    // prevent the PredominantColour() algorithm from discovering
+	    // the red line.
+	    TInt yStep = aSize.iHeight/14;
+	    TInt xStep = aSize.iWidth/6;
+	    
+	    //This paint is intentionally complex and slow so that the animation timer is likely to interrupt it.
+		if (!aBlankIt)
+		 for (TInt nn = 0 ; nn < aRepeat ; nn++)
+			for(yPos=0 ; yPos < aSize.iHeight ; yPos += yStep)
+				for(xPos=0 ; xPos < aSize.iWidth ; xPos += xStep)
+					aGc->DrawLine(aRect.Center(),TPoint(xPos,yPos));
+		if (aIsBase)
+			DrawEllipse(aGc, aRect, aAlphaValue);			
+		}
+
+	//This simple API may need replacing by a list and search if multiple anims are played together
+	TWsGraphicAnimation* CCrpAnim::SetAnimation(TUid aUid)
+		{	//currently only have 1 animation - it gets replaced. It could get refiused
+		iAnimUid=aUid;
+		return &iAnimData;	
+		}
+
+	TWsGraphicAnimation* CCrpAnim::GetAnimation(TUid aUid)
+		{   //currently only have 1 animation
+		if (iAnimUid==aUid)
+			return &iAnimData;	
+		else
+			return NULL;
+		}
+		
+	void CCrpAnim::SetPosAnimation(const TUid& aUid, const TRect& aRect)
+		{   //currently only have 1 animation
+		if (iAnimUid==aUid)
+			iAnimPos = aRect;
+		}
+	
+	TRect* CCrpAnim::GetPosAnimation(const TUid& aUid)
+		{   //currently only have 1 animation
+		if (iAnimUid==aUid)
+			return &iAnimPos;	
+		else
+			return NULL;
+		}
+	
+	TBool CCrpAnim::RemoveAnimation(TUid)
+		{
+		iAnimUid=TUid::Null();
+		iAnimData.Stop(EFalse);		
+		return ETrue;
+		}	
+
+	void CCrpAnim::DoDraw()
+		{
+		DoDraw(iBlankIt);
+		}
+
+	inline void CCrpAnim::DoDraw(TBool aBlankIt)
+		{
+		__ASSERT_ALWAYS(iWinType!=EBlank,AutoPanic(EAutoPanicWindowType));
+		iCtWin->Gc()->Activate(*Window());
+		Draw(iCtWin->Gc(),Size(),iIsBase,iRect,aBlankIt,iRepeatDrawMax,iAlphaValue);
+		if (iAnimUid!=TUid::Null())
+			iCtWin->Gc()->DrawWsGraphic(iAnimUid,iAnimPos,iAnimData.Pckg());
+		iCtWin->Gc()->Deactivate();
+		}
+		
+	void CCrpAnim::DoDrawEllipse()
+		{
+		__ASSERT_ALWAYS(iWinType!=EBlank,AutoPanic(EAutoPanicWindowType));
+		iCtWin->Gc()->Activate(*Window());
+		DrawEllipse(iCtWin->Gc(),iRect,iAlphaValue);
+		iCtWin->Gc()->Deactivate();
+		}
+
+	void CCrpAnim::InvalidateAndRedraw(TBool /*aUseBlankItMember*/,TBool /*aBlankIt*/,TBool aUseRWindowInvalidate,TRect* aRect)
+		{
+		RWindow& win = *Window();
+		if (aRect)
+			{
+			if (aUseRWindowInvalidate)
+				win.Invalidate(*aRect);
+			else
+				Invalidate(*aRect);
+			}
+		else
+			{
+			if (aUseRWindowInvalidate)
+				win.Invalidate();
+			else
+				Invalidate();
+			}
+		if (aRect)
+			win.BeginRedraw(*aRect);
+		else
+			win.BeginRedraw();
+		DoDraw();
+		win.EndRedraw();
+		TheClient->Flush();
+		}
+		
+	void CCrpAnim::Invalidate(const TRect &aRect)
+		{
+		TRect rect(aRect);
+		rect.Move(iCtWin->Position());
+		CTUser::Splat(TheClient,rect,TRgb::Gray256(0));
+		}
+
+//
+	}	//end anonymous namespace
+//
+__WS_CONSTRUCT_STEP__(CrpAnim)