windowing/windowserver/tauto/TTEXTCURS.CPP
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/tauto/TTEXTCURS.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,2040 @@
+// Copyright (c) 1996-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:
+// Test the text cursor.
+//
+// This suite of tests checks to see if the TextCursors are operating
+// correctly for a number of use case scenarios; see doxygen comments
+// for each sub-test.  This test suite is applicable on both winscw
+// emulator and armv5 target hardware.  However, it must be noted that
+// text cursors are special due to their timeliness.  The text cursor
+// must flash every second: half a second ON, half a second OFF.  One
+// consequence of this is that when the test suite is run on emulator,
+// the PC must be otherwise quiescent.  No other IO or CPU intensive
+// activities may occur on the system, because these will cause delays
+// to the flashing of the text cursor giving unreliable results.
+// Where timeliness is a consideration, we use TEST_SOFTFAIL_WINSCW so
+// that if the test fails and we are running on the PC emulator, we only
+// record the fact, but don't mark the test as failing.
+
+/**
+ @file
+ @test
+ @internalComponent - Internal Symbian test code
+*/
+
+#include "TTEXTCURS.H"
+#include "graphics/windowserverconstants.h"
+
+const TInt KNumberOfCustoTextCursors	= 3;
+const TInt KTextCursorInitialIdValue	= 1001;
+const TInt KTextCursorPanicUid1			= 200;
+const TInt KTextCursorPanicUid2			= 2000;
+const TInt KTextCursorPanicUid3			= 3000;
+const TInt KTextCursorPanicUid4			= 4000;
+const TInt KTextCursorPanicUid5			= 5000;
+
+CTestBase* CTCursorTest::iStaticTest = NULL;
+const TInt kWinWidth=400;
+const TInt kWinHeight=100;
+const TSize kWinSize(kWinWidth,kWinHeight);
+const TInt kWinXPos=150;
+const TInt kCursorWidth = 10;
+const TInt kCursorHeight = 20;
+const TSize kCursorSize(kCursorWidth,kCursorHeight);
+const TPoint kWin1TopLeft(kWinXPos,0);
+const TPoint kWin2TopLeft(kWinXPos,kWinHeight+10);
+
+LOCAL_D void DeleteSpriteMember(TAny* aSpriteMember)
+	{
+	TSpriteMember* member=reinterpret_cast<TSpriteMember*>(aSpriteMember);
+	delete member->iBitmap;
+	member->iBitmap=NULL;
+	delete member->iMaskBitmap;
+	member->iMaskBitmap=NULL;
+	}
+
+CCustomTextCursor::~CCustomTextCursor()
+	{
+	const TInt count = iSpriteMemberArray.Count();
+	for (TInt index=0; index<count; ++index)
+		{
+		DeleteSpriteMember(&iSpriteMemberArray[index]);
+		}
+	iSpriteMemberArray.Close();
+	}
+	
+CCustomTextCursor::CCustomTextCursor(CTestBase* aTest)
+	: iTest(aTest)
+	{	
+	}
+
+void CCustomTextCursor::ConstructL(TInt aScreenNumber,TInt aBmpIndex)
+	{
+	ASSERT(aBmpIndex < KNumberOfCustoTextCursors);
+	
+
+	TSpriteMember spriteMember;
+	spriteMember.iBitmap = NULL;
+	spriteMember.iMaskBitmap = NULL;
+	spriteMember.iInvertMask =EFalse;
+	spriteMember.iDrawMode = CGraphicsContext::EDrawModePEN;
+	spriteMember.iOffset = TPoint();
+	spriteMember.iInterval = TTimeIntervalMicroSeconds32(0);
+	CleanupStack::PushL(TCleanupItem(DeleteSpriteMember, &spriteMember));
+	spriteMember.iBitmap = new (ELeave) CFbsBitmap;
+	User::LeaveIfError(spriteMember.iBitmap->Load(TEST_BITMAP_NAME, EMbmWsautotestBmp1));
+	spriteMember.iMaskBitmap = new (ELeave) CFbsBitmap;
+	User::LeaveIfError(spriteMember.iMaskBitmap->Load(TEST_BITMAP_NAME, EMbmWsautotestBmp1mask));
+
+	User::LeaveIfError(iSpriteMemberArray.Append(spriteMember));
+	CleanupStack::Pop(&spriteMember);
+
+	// create unique-id accross screens
+	//
+	iIdentifier = KTextCursorInitialIdValue + aScreenNumber*KNumberOfCustoTextCursors + aBmpIndex;
+	iAlignment = (RWsSession::TCustomTextCursorAlignment)(aBmpIndex);
+	}
+
+CCustomTextCursor* CCustomTextCursor::CreateCustomTextCursorL(TInt aScreenNumber,TInt aBmpIndex,CTestBase* aTest)
+	{
+	CCustomTextCursor* customTextCursor = new (ELeave) CCustomTextCursor(aTest);
+	CleanupStack::PushL(customTextCursor);
+	customTextCursor->ConstructL(aScreenNumber,aBmpIndex);
+	CleanupStack::Pop(customTextCursor);
+	return customTextCursor;
+	}
+
+/*
+ * Wrapper class for a list of custom text cursor.
+ */
+class CCustomTextCursorsWrapper : public CBase
+	{
+public:
+	static CCustomTextCursorsWrapper* NewLC(TInt aScreenNumber,CTestBase* aTest);
+	~CCustomTextCursorsWrapper();
+	inline RPointerArray<CCustomTextCursor>& CustomTextCursorsArray();
+	inline CCustomTextCursor& CustomTextCursor(TInt aIndex);
+private:
+	void ConstructL(TInt aScreenNumber,CTestBase* aTest);
+private:
+	RPointerArray<CCustomTextCursor> iCustomTextCursors;
+	};
+
+inline RPointerArray<CCustomTextCursor>& CCustomTextCursorsWrapper::CustomTextCursorsArray()
+		{
+		return iCustomTextCursors;
+		}
+
+inline CCustomTextCursor& CCustomTextCursorsWrapper::CustomTextCursor(TInt aIndex)
+		{
+		return *(iCustomTextCursors[aIndex]);
+		}
+
+CCustomTextCursorsWrapper* CCustomTextCursorsWrapper::NewLC(TInt aScreenNumber,CTestBase* aTest)
+	{
+	CCustomTextCursorsWrapper* self = new(ELeave) CCustomTextCursorsWrapper();
+	CleanupStack::PushL(self);
+	self->ConstructL(aScreenNumber,aTest);
+	return self;
+	}
+
+CCustomTextCursorsWrapper::~CCustomTextCursorsWrapper()
+	{
+	iCustomTextCursors.ResetAndDestroy();
+	iCustomTextCursors.Close();
+	}
+
+void CCustomTextCursorsWrapper::ConstructL(TInt aScreenNumber, CTestBase* aTest)
+	{
+	for (TInt index=0; index<KNumberOfCustoTextCursors; ++index)
+		{
+		CCustomTextCursor* customTextCursor=CCustomTextCursor::CreateCustomTextCursorL(aScreenNumber,index, aTest);
+		CleanupStack::PushL(customTextCursor);
+		User::LeaveIfError(iCustomTextCursors.Append(customTextCursor));
+		CleanupStack::Pop(customTextCursor);
+		}
+	}
+
+CTCursorTest::CTCursorTest(CTestStep* aStep) :
+	CTWsGraphicsBase(aStep)
+	{
+	iCursorType = TTextCursor::ETypeFirst;
+	iStaticTest=iTest;
+	}
+	
+CTCursorTest::~CTCursorTest()
+	{
+	delete iWorkInProgress;
+	delete iComparisonWindow;
+	}
+
+TInt CTCursorTest::DoPanicTest(TInt aInt, TAny *aScreenNumber)
+	{
+	RWsSession ws;
+	if (ws.Connect()==KErrNone)
+		{
+		// use correct screen
+		CWsScreenDevice* screen = new (ELeave) CWsScreenDevice(ws);
+		User::LeaveIfError(screen->Construct((TInt)aScreenNumber));
+		RWindowGroup group(ws);
+		if (group.Construct(444)==KErrNone)
+			{
+			group.EnableReceiptOfFocus(EFalse);	// Stop auto group switching on close
+			RWindow wnd(ws);
+			if (wnd.Construct(group, TInt32(&ws))==KErrNone)
+				{
+				TTextCursor tc;
+				tc.iHeight=10;
+				tc.iAscent=5;
+				tc.iWidth=10;
+				tc.iFlags=0;
+				tc.iColor=TRgb(0,0,0);
+				switch(aInt)
+					{
+					case 0:
+						{
+						/* TESTCASE:	6.1
+						* TITLE:		Invalid use of a custom text cursor ID (basic text cursor).
+						* IMPORTANCE:	1
+						* REQUIREMENT:	Unknown.
+						* 
+						* ACTION:		This test tries to set a text cursor using an ID which is invalid.
+						* 
+						* CHECK:		The thread should panic with the exit reason EWservPanicInvalidTextCursor
+						*/ 
+						tc.iType=(TTextCursor::EType)KTextCursorPanicUid1;
+						group.SetTextCursor(wnd,TPoint(10,10),tc);
+						}
+						break;
+					case 1:
+						{
+						/* TESTCASE:	6.2
+						* TITLE:		Invalid use of a window for a text cursor.
+						* IMPORTANCE:	1
+						* REQUIREMENT:	REQ 1079, CR RDEF-5F7Q24 (10/04/2003).
+						* 
+						* ACTION:		This test tries to set a text cursor using a window which is not part
+						*				of the window group calling the setting API.
+						* 
+						* CHECK:		The thread should panic with the exit reason EWservPanicWindow
+						*/ 
+						tc.iType=(TTextCursor::EType)KTextCursorPanicUid2;
+						group.SetTextCursor(*TestWin->Win(),TPoint(10,10),tc);
+						}
+						break;
+					case 2:
+						{
+						/* TESTCASE:	6.3
+						* TITLE:		Invalid use of a custom text cursor ID.
+						* IMPORTANCE:	1
+						* REQUIREMENT:	REQ 1079, CR RDEF-5F7Q24 (10/04/2003).
+						* 
+						* ACTION:		This test tries to set a text cursor using an ID which is associated to
+						*				an non-existing custom text cursor.
+						* 
+						* CHECK:		The thread should panic with the exit reason EWservPanicNoCustomTextCursor
+						*/ 
+						tc.iType=(TTextCursor::EType)KTextCursorPanicUid3;
+						group.SetTextCursor(wnd,TPoint(10,10),tc);
+						}
+						break;
+					case 3:
+						{
+						/* TESTCASE:	6.4
+						* TITLE:		Invalid use of a custom text cursor ID.
+						* IMPORTANCE:	1
+						* REQUIREMENT:	REQ 1079, CR RDEF-5F7Q24 (10/04/2003).
+						* 
+						* ACTION:		This test tries to set a custom text cursor which has been set to use
+						*				an invalid alignment.
+						* 
+						* CHECK:		The thread should panic with the exit reason EWservPanicCustomTextCursorAlign
+						*/ 
+						CCustomTextCursor* customTextCursor=NULL;
+						TRAPD(error, customTextCursor=CCustomTextCursor::CreateCustomTextCursorL((TInt)aScreenNumber,0,iStaticTest));
+						if (error==KErrNone)
+							{
+							error = ws.SetCustomTextCursor(KTextCursorPanicUid4, customTextCursor->iSpriteMemberArray.Array(), 0, (RWsSession::TCustomTextCursorAlignment)(RWsSession::ECustomTextCursorAlignBottom+1));
+							if (error==KErrNone || error==KErrAlreadyExists)
+								{
+								tc.iType=(TTextCursor::EType)KTextCursorPanicUid4;
+								group.SetTextCursor(wnd,TPoint(10,10),tc);
+								}
+							}
+						delete customTextCursor;
+						}
+						break;
+					case 4:
+						{
+						/* TESTCASE:	6.5
+						* TITLE:		Use of an invalid custom text cursor
+						* IMPORTANCE:	1
+						* REQUIREMENT:	REQ 1079, CR RDEF-5F7Q24 (10/04/2003).
+						* 
+						* ACTION:		This test tries to set a custom text cursor which does not have
+						*				any sprite member set.
+						* 
+						* CHECK:		The thread should panic with the exit reason EWservPanicNoSpriteMember
+						*/ 
+						RArray<TSpriteMember> spriteMemberArray;
+						const TInt error = ws.SetCustomTextCursor(KTextCursorPanicUid5, spriteMemberArray.Array(), 0, (RWsSession::TCustomTextCursorAlignment)(RWsSession::ECustomTextCursorAlignBottom));
+						if (error==KErrNone || error==KErrAlreadyExists)
+							{
+							tc.iType=(TTextCursor::EType)KTextCursorPanicUid5;
+							group.SetTextCursor(wnd,TPoint(10,10),tc);
+							}
+						}
+						break;
+					case 5:
+						{
+						// Uncover set.cursor.iType < TTextCursor::ETypeFirst code path
+						tc.iType=(TTextCursor::EType)TTextCursor::ETypeFirst - 1;
+						group.SetTextCursor(wnd,TPoint(10,10),tc);
+						}
+						break;
+					case 6:
+						{
+						// Uncover (set.cursor.iFlags&static_cast<TUint>(TTextCursor::EPrivateFlags) code path
+						tc.iFlags=ETextCursorPrivateFlags;
+						group.SetTextCursor(wnd,TPoint(10,10),tc);
+						}
+						break;
+					case 7:
+						{
+						// Uncover (iGroupWin != searchWin) i.e. bogus group window
+						tc.iType=(TTextCursor::EType)TTextCursor::ETypeRectangle;
+						RWindow windowNotAssociatedWithAGroup(ws);
+						group.SetTextCursor(windowNotAssociatedWithAGroup, TPoint(10,10),tc);
+						}
+						break;
+					}
+				}
+			ws.Flush();
+			}
+		}
+	return(EWsExitReasonBad);
+	}
+
+void CTCursorTest::TestPanicsL()
+	{	
+		TEST(iTest->TestWsPanicL(DoPanicTest, EWservPanicInvalidTextCursor, 0, (TAny*)iTest->iScreenNumber));
+		TEST(iTest->TestWsPanicL(DoPanicTest, EWservPanicWindow, 1, (TAny*)iTest->iScreenNumber));
+		TEST(iTest->TestWsPanicL(DoPanicTest, EWservPanicNoCustomTextCursor, 2, (TAny*)iTest->iScreenNumber));
+		TEST(iTest->TestWsPanicL(DoPanicTest, EWservPanicCustomTextCursorAlign, 3, (TAny*)iTest->iScreenNumber));
+		TEST(iTest->TestWsPanicL(DoPanicTest, EWservPanicNoSpriteMember, 4, (TAny*)iTest->iScreenNumber));
+		TEST(iTest->TestWsPanicL(DoPanicTest, EWservPanicInvalidTextCursor, 5, (TAny*)iTest->iScreenNumber));
+		TEST(iTest->TestWsPanicL(DoPanicTest, EWservPanicInvalidTextCursor, 6, (TAny*)iTest->iScreenNumber));
+		TEST(iTest->TestWsPanicL(DoPanicTest, EWservPanicWindow, 7, (TAny*)iTest->iScreenNumber));
+		iTest->CloseAllPanicWindows();
+	}
+
+void CTCursorTest::TextCursorSetLCoverageTests()
+	{
+	ValidateWin(BaseWin,TRgb::Gray256(255));
+	ValidateWin(TestWin,TRgb::Gray256(255));	
+	TTextCursor textCursor;
+	textCursor.iHeight = 10;
+	textCursor.iAscent = 0;
+	textCursor.iWidth = 10;
+	textCursor.iFlags = 0;
+	textCursor.iColor = KRgbBlack;
+	textCursor.iType = (TTextCursor::EType)TTextCursor::ETypeRectangle;
+	TPoint position(10, 10);
+	TRect clipRect0(10, 10, 10, 10);
+	TRect clipRect1(10, 10, 5, 5);
+	RWindowGroup *group = TheClient->iGroup->GroupWin(); 
+	group->SetTextCursor(*TestWin->Win(), position, textCursor);
+	/*
+	 * Duplicate the previous SetTextCursor command to uncover the code which checks for any delta in SetL
+	 * compared to the current settings.
+	 */
+	group->SetTextCursor(*TestWin->Win(), position, textCursor);
+	/*
+	 * Change the type only to pick up that difference in SetL.
+	 */
+	textCursor.iType++;
+	group->SetTextCursor(*TestWin->Win(), position, textCursor);
+	textCursor.iType--;
+	/*
+	 * Vary the clipping rectangle.
+	 */
+	group->SetTextCursor(*TestWin->Win(), position, textCursor, clipRect0);
+	group->SetTextCursor(*TestWin->Win(), position, textCursor, clipRect1);
+	/*
+	 * Vary the color.
+	 */
+	textCursor.iColor = KRgbGreen;
+	group->SetTextCursor(*TestWin->Win(), position, textCursor);
+	textCursor.iColor = KRgbBlack;
+	group->SetTextCursor(*TestWin->Win(), position, textCursor);
+	/*
+	 * Vary the target Window.
+	 */
+	group->SetTextCursor(*BaseWin->Win(), position, textCursor);
+	group->SetTextCursor(*TestWin->Win(), position, textCursor);
+	/*
+	 * Vary the size of the cursor.
+	 */
+	textCursor.iWidth++;
+	group->SetTextCursor(*TestWin->Win(), position, textCursor);
+	textCursor.iWidth--;
+	/*
+	 * Set different custom cursors.
+	 */
+	CCustomTextCursorsWrapper* customTextCursorsWrapper = CCustomTextCursorsWrapper::NewLC(iTest->iScreenNumber, iTest);
+	const TInt count = customTextCursorsWrapper->CustomTextCursorsArray().Count();
+	for (TInt index=0; index<count; ++index)
+		{
+		CCustomTextCursor& customTextCursor = customTextCursorsWrapper->CustomTextCursor(index);
+		textCursor.iType = customTextCursor.iIdentifier;
+		group->SetTextCursor(*TestWin->Win(), position, textCursor);
+		}			
+	CleanupStack::PopAndDestroy(customTextCursorsWrapper);
+	/*
+	 * Set the last custom cursor from the above loop again so the
+	 * product code sees the same Custom Text Cursor settings come
+	 * in a second time.
+	 */
+	group->SetTextCursor(*TestWin->Win(), position, textCursor);
+	textCursor.iType = (TTextCursor::EType)TTextCursor::ETypeRectangle;
+	/*
+	 * Vary the horizontal clipping.
+	 */
+	textCursor.iFlags = TTextCursor::EFlagClipHorizontal;
+	group->SetTextCursor(*TestWin->Win(), position, textCursor);
+	/*
+	 * Vary the horizontal clipping.
+	 */
+	textCursor.iFlags = TTextCursor::EFlagClipVertical;
+	group->SetTextCursor(*TestWin->Win(), position, textCursor);
+	/*
+	 * Try both horizontal and vertical clipping.
+	 */
+	textCursor.iFlags = TTextCursor::EFlagClipVertical|TTextCursor::EFlagClipHorizontal;
+	group->SetTextCursor(*TestWin->Win(), position, textCursor);
+	textCursor.iFlags = 0;
+	
+	TheClient->iWs.Flush();
+	CancelTextCursor();
+	}
+
+void CTCursorTest::SetCursor(const TPoint &aPos,const TSize &aSize,TRgb aColor, const TRect &aRect, TUint aFlags)
+	{
+	TTextCursor tc;
+	tc.iType=iCursorType;
+    tc.iHeight=aSize.iHeight;
+    tc.iAscent=aSize.iHeight*4/5;
+    tc.iWidth=aSize.iWidth;
+    tc.iFlags=aFlags;
+	tc.iColor=aColor;
+	TheClient->iGroup->GroupWin()->SetTextCursor(*TestWin->Win(),TPoint(aPos.iX,aPos.iY+tc.iAscent),tc,aRect);
+	}
+
+void CTCursorTest::SetCursor(const TPoint &aPos,const TSize &aSize,TRgb aColor, TUint aFlags)
+	{
+	TTextCursor tc;
+	tc.iType=iCursorType;
+    tc.iHeight=aSize.iHeight;
+    tc.iAscent=aSize.iHeight*4/5;
+    tc.iWidth=aSize.iWidth;
+    tc.iFlags=aFlags;
+	tc.iColor=aColor;
+	TheClient->iGroup->GroupWin()->SetTextCursor(*TestWin->Win(),TPoint(aPos.iX,aPos.iY+tc.iAscent),tc);
+	}
+
+void CTCursorTest::SetCursorPlusBox(const TPoint &aPos,const TSize &aSize,TRgb aColor, const TRect *aClipRect, TUint aFlags)
+	{
+	if (aClipRect)
+		SetCursor(aPos,aSize,aColor,*aClipRect,aFlags);
+	else
+		SetCursor(aPos,aSize,aColor,aFlags);
+	TRect rect(aPos,aSize);
+	if (aClipRect)
+		rect.Intersection(*aClipRect);
+	rect.Grow(2,2);
+	
+	TheClient->iGc->Activate(*(TestWin->Win()));
+	TestWin->Invalidate(rect);
+	TestWin->Win()->BeginRedraw(rect);
+	TheClient->iGc->SetPenColor(aColor);
+	TheClient->iGc->SetDrawMode(CGraphicsContext::EDrawModeXOR);
+
+	TheClient->iGc->DrawRect(rect);
+	TheClient->iGc->Deactivate();
+	TestWin->Win()->EndRedraw();
+	
+	}
+
+void CTCursorTest::CancelTextCursor()
+	{
+	TheClient->iGroup->GroupWin()->CancelTextCursor();
+	}
+
+void CTCursorTest::ConstructL()
+	{
+	// for allocating some cached memory
+	CFbsBitmap* bitmap = new (ELeave) CFbsBitmap;
+	CleanupStack::PushL(bitmap);
+	User::LeaveIfError(bitmap->Load(TEST_BITMAP_NAME, 0));
+	CleanupStack::PopAndDestroy(bitmap);
+
+	CCustomTextCursorsWrapper* customTextCursorsWrapper = CCustomTextCursorsWrapper::NewLC(iTest->iScreenNumber, iTest);
+	const TInt count = customTextCursorsWrapper->CustomTextCursorsArray().Count();
+	for (TInt index=0; index<count; ++index)
+		{
+		CCustomTextCursor& customTextCursor = customTextCursorsWrapper->CustomTextCursor(index);
+		TInt err = TheClient->iWs.SetCustomTextCursor(customTextCursor.iIdentifier, customTextCursor.iSpriteMemberArray.Array(), customTextCursor.iSpriteFlags, customTextCursor.iAlignment);
+		TEST(err == KErrNone || err == KErrAlreadyExists);
+		if (err!=KErrNone && err != KErrAlreadyExists)
+			INFO_PRINTF4(_L("TheClient->iWs.SetCustomTextCursor return value  - Expected: %d or %d, Actual: %d"), KErrNone, KErrAlreadyExists, err);
+
+		__UHEAP_MARK;
+		err = TheClient->iWs.SetCustomTextCursor(customTextCursor.iIdentifier, customTextCursor.iSpriteMemberArray.Array(), customTextCursor.iSpriteFlags, customTextCursor.iAlignment);
+		__UHEAP_MARKEND;
+		TEST(err == KErrAlreadyExists);
+		if (err != KErrAlreadyExists)
+			INFO_PRINTF3(_L("TheClient->iWs.SetCustomTextCursor return value  - Expected: %d, Actual: %d"), KErrAlreadyExists, err);
+
+		}
+	_LIT(KLog,"Text Cursor: Loaded %d Custom Cursors");
+	TLogMessageText buf;
+	buf.Format(KLog,count);
+	TheClient->LogMessage(buf);
+	CleanupStack::PopAndDestroy(customTextCursorsWrapper);
+//
+	ValidateWin(BaseWin,TRgb::Gray256(204));
+	ValidateWin(TestWin,TRgb::Gray256(204));
+//
+	SetCursor(TPoint(10,90),TSize(80,100),TRgb(255,255,255));
+//
+	iWinState=0;
+	iWinPos=TPoint(2*TheClient->iGroup->Size().iWidth/3,0);
+//
+	iMoveWin=new(ELeave) CBlankWindow(TRgb::Gray256(220));
+	TDisplayMode mode=EGray16;
+	TInt testWinWidth = TestWin->Size().iWidth;
+	TInt halfTestWinWidth = testWinWidth/2;
+	TInt halfTestWinHeight = TestWin->Size().iHeight/2;
+	
+	iMoveWin->SetUpL(iWinPos,TSize(halfTestWinHeight,halfTestWinHeight),
+			TheClient->iGroup,*TheClient->iGc,&mode);
+
+	iCheckWin=new(ELeave) CBlankWindow(TRgb::Gray256(220));
+	iCheckWin->SetUpL(TPoint(testWinWidth+halfTestWinWidth,halfTestWinHeight),
+			TSize(halfTestWinWidth,halfTestWinHeight),
+			TheClient->iGroup,*TheClient->iGc,&mode);
+	}
+
+void CTCursorTest::DeleteMoveWindows()
+	{
+	delete iMoveWin;
+	delete iCheckWin;
+	CancelTextCursor();
+	}
+
+void CTCursorTest::ResetMoveWindowsL()
+	{
+	SetCursor(TPoint(10,90),TSize(80,100),TRgb(255,255,255));
+	iWinState=0;
+	iWinPos=TPoint(2*TheClient->iGroup->Size().iWidth/3,0);
+	iMoveWin->SetExtL(iWinPos,TSize(TestWin->Size().iWidth/2,TestWin->Size().iHeight/2));
+	iCheckWin->SetExtL(TPoint(TestWin->Size().iWidth+(TestWin->Size().iWidth>>1),TestWin->Size().iHeight>>1),
+														TSize(TestWin->Size().iWidth/2,TestWin->Size().iHeight/2));
+	}
+
+TBool CTCursorTest::MoveWindow()
+	{
+	TSize scrSize(TheClient->iScreen->SizeInPixels());
+	iWinState++;
+	if (iWinState<20)
+		iWinPos+=TPoint((4*scrSize.iWidth)/640,(4*scrSize.iHeight)/240);
+	else if (iWinState<40)
+		iWinPos+=TPoint((1*scrSize.iWidth)/640,(-3*scrSize.iHeight)/240);
+	else if (iWinState<60)
+		iWinPos+=TPoint((-6*scrSize.iWidth)/640,(3*scrSize.iHeight)/240);
+	else
+		iWinPos+=TPoint((1*scrSize.iWidth)/640,(-2*scrSize.iHeight)/240);
+	iMoveWin->SetPos(iWinPos);
+	return (iWinState==80);
+	}
+
+void CTCursorTest::ValidateWin(TestWindow *aWin, TRgb aColor)
+	{
+	aWin->Win()->Invalidate();
+	RedrawWin(*aWin->Win(),aColor);
+	}
+
+void CTCursorTest::RedrawWin(RWindow &aWin, TRgb aColor)
+	{
+	aWin.BeginRedraw();
+	TheClient->iGc->Activate(aWin);
+	TheClient->iGc->SetBrushColor(aColor);
+	TheClient->iGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
+	TheClient->iGc->SetPenStyle(CGraphicsContext::ENullPen);
+	TheClient->iGc->Clear();
+	TheClient->iGc->Deactivate();
+	aWin.EndRedraw();
+	}
+
+void CTCursorTest::ScrollTest()
+	{
+	const TSize size(20,40);
+	ValidateWin(TestWin,TRgb::Gray256(255));
+
+	SetCursor(TPoint(10,20),size,TRgb::Gray256(255),TTextCursor::EFlagNoFlash);
+	TheClient->iWs.Flush();
+	TheClient->WaitForRedrawsToFinish();
+	TheClient->iWs.Finish();
+
+	for(TInt ii=0;ii<20;ii++)
+		{
+		TInt dist=(ii&3)*2;
+		TInt nx=ii&0x1?1:-1;
+		TInt ny=ii&0x2?1:-1;
+		TestWin->Win()->Scroll(TPoint(dist*nx,dist*ny),TRect(10,20,30,40));
+		TheClient->iWs.Flush();
+		}
+	TheClient->WaitForRedrawsToFinish();
+	TheClient->iWs.Finish();
+
+	BaseWin->Win()->Invalidate();
+	BaseWin->Win()->BeginRedraw();
+	TheClient->iGc->Activate(*(BaseWin->Win()));
+	TheClient->iGc->Clear();
+	TheClient->iGc->SetBrushColor(TRgb::Gray256(255));
+	TheClient->iGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
+	TheClient->iGc->SetPenStyle(CGraphicsContext::ENullPen);
+	TheClient->iGc->Clear(TRect(TPoint(10,20),size));
+	TheClient->iGc->Deactivate();
+	BaseWin->Win()->EndRedraw();
+
+	TheClient->iWs.Flush();
+	TheClient->WaitForRedrawsToFinish();
+	TheClient->iWs.Finish();
+
+	/*
+	 * NOTE: Reason for removal of COMPARE_WINDOWS_SOFTFAIL_WINSCW
+	 * Due to the new implementation of sprites in wserv2, the sprites no longer keep a 
+	 * backup bitmap of what the screen looks like beneath them. As it is not possible to 
+	 * move the sprites associated with the custom text cursors that were created in second 
+	 * phase construction of the CTCursorTest object, the COMPARE_WINDOWS_SOFTFAIL_WINSCW; 
+	 * macro function has been removed. Otherwise the test case is going to subject to the
+	 * timing of the flashing sprite. An alternative solution would be to assign NULL values
+	 * to the sprite bitmaps in second phase construction, but this is avoided as it would
+	 * trigger failures in some test cases later on (that are depended on these "embedded"
+	 * sprite images).
+	 */	
+	CancelTextCursor();
+	}
+
+void DrawTestSprite(CBitmapContext *aGc,TInt , const TSize &aSize, TBool aDoMask, TAny *)
+	{
+	aGc->SetBrushColor(TRgb::Gray4(aDoMask ? 0 : 2));
+	aGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
+	aGc->SetPenStyle(CGraphicsContext::ENullPen);
+	aGc->DrawRect(TRect(aSize));
+	aGc->SetPenStyle(CGraphicsContext::ESolidPen);
+	aGc->SetPenColor(TRgb::Gray4(aDoMask ? 3 : 0));
+	aGc->SetBrushColor(TRgb::Gray4(aDoMask ? 3 : 1));
+	aGc->DrawEllipse(TRect(aSize));
+	}
+
+CTSprite *CTCursorTest::CreateTestSpriteLC(RWindowTreeNode &aWindow, const TPoint &aPos, TInt aCount)
+//
+// At the moment aCount must be 1 or 2
+//
+	{
+	TSpriteCreateParams params(TSize(30,70),TPoint(0,0),DrawTestSprite);
+	TSpriteCreateParams paramarray[2];
+	params.iInterval=TTimeIntervalMicroSeconds32(200000);
+
+	paramarray[0]=params;
+	paramarray[1]=params;
+	paramarray[1].iSize=TSize(100,10);
+	CTSprite *sprite=new(ELeave) CTSprite(TheClient->iWs);
+	CleanupStack::PushL(sprite);
+	sprite->ConstructL(aWindow,aPos,aCount,&paramarray[0],0);
+	return(sprite);
+	}
+
+void CTCursorTest::doMoveWindowTestL()
+	{
+	RBlankWindow blankwin(TheClient->iWs);
+	User::LeaveIfError(blankwin.Construct(*TestWin->Win(),1));
+	CleanupStack::PushL(TCleanupItem(CleanUpWindow,&blankwin));
+//
+	blankwin.SetExtent(TPoint(35,165),TSize(40,40));
+	blankwin.SetColor(TRgb::Gray256(220));
+	blankwin.Activate();
+	TheClient->iWs.SetAutoFlush(ETrue);
+	User::After(500000);
+	blankwin.SetPosition(TPoint(25,55));
+	User::After(500000);
+	blankwin.SetPosition(TPoint(30,160));
+	User::After(500000);
+	blankwin.SetPosition(TPoint(12,22));	// Almost totally covering sprite
+	User::After(500000);
+	blankwin.SetPosition(TPoint(-100,-100));	// Totally off the sprite
+	User::After(500000);
+	blankwin.SetPosition(TPoint(10,20));	// Write on top of sprite
+	User::After(500000);
+	blankwin.SetPosition(TPoint(24,24));	// moving off...
+	User::After(500000);
+	blankwin.SetPosition(TPoint(38,28));	// ...
+	User::After(500000);
+	blankwin.SetPosition(TPoint(58,48));	// ...
+	User::After(500000);
+	blankwin.SetPosition(TPoint(92,62));	// ... off
+	User::After(500000);
+	CleanupStack::PopAndDestroy();	// blank window
+	TheClient->iWs.Flush();
+	TheClient->WaitForRedrawsToFinish();
+	TheClient->iWs.Finish();
+
+	TheClient->iWs.SetAutoFlush(EFalse);
+	}
+
+void CTCursorTest::MoveWindowTest1L()
+	{
+	ValidateWin(TestWin,TRgb::Gray256(255));
+// Check it with a static sprite
+	CTSprite * sprite_static = CreateTestSpriteLC(*TestWin->Win(), TPoint(10,20), 1);
+	doMoveWindowTestL();
+	(sprite_static->Sprite()).SetPosition(TPoint(500,500)); //move the sprite out of the viewing area before the window comparison 
+	CleanupStack::PopAndDestroy(1);	// sprite
+// Check it an animated sprite
+	CTSprite * sprite_anim = CreateTestSpriteLC(*TestWin->Win(), TPoint(10,20), 2);
+	doMoveWindowTestL();
+	(sprite_anim->Sprite()).SetPosition(TPoint(500,500)); //move the sprite out of the viewing area before the window comparison
+	CleanupStack::PopAndDestroy(1);	// sprite
+	}
+
+void CTCursorTest::MoveWindowTest2L()
+	{
+	const TSize size(20,40);
+// Check it with a text cursor
+	ValidateWin(TestWin,TRgb::Gray256(255));
+	SetCursor(TPoint(10,25),size,TRgb::Gray256(255),TTextCursor::EFlagNoFlash);
+	doMoveWindowTestL();
+	CancelTextCursor();
+// Check it with an anaimated sprite and a text cursor
+	ValidateWin(TestWin,TRgb::Gray256(255));
+	CTSprite * sprite_anim = CreateTestSpriteLC(*TestWin->Win(), TPoint(10,20), 2);
+	SetCursor(TPoint(10,45),size,TRgb::Gray256(255),TTextCursor::EFlagNoFlash);
+	doMoveWindowTestL();
+	(sprite_anim->Sprite()).SetPosition(TPoint(500,500));
+	CancelTextCursor();
+	CleanupStack::PopAndDestroy(1);	// sprite
+	}
+
+TBool CTCursorTest::IncrementCursorType()
+	{
+	// each screen has it own set of cursor
+	//
+	// the values would be ETypeLast=2 ETypeLastBasic=1009
+	//
+	if (iCursorType == TTextCursor::ETypeFirst)
+		{
+		iCursorType = (TTextCursor::EType)(TTextCursor::ETypeLastBasic + 1 + iTest->iScreenNumber*KNumberOfCustoTextCursors);
+		return ETrue;
+		}
+	else if (iCursorType >= TTextCursor::ETypeLastBasic + (iTest->iScreenNumber+1)*KNumberOfCustoTextCursors)
+		{
+		iCursorType = TTextCursor::ETypeFirst;
+		return EFalse;
+		}
+	else
+		{
+		iCursorType = (TTextCursor::EType)(iCursorType + 1);
+		return ETrue;
+		}
+	}
+
+void CTCursorTest::GeneralTestsL()
+	{
+	const TInt winColor=255;		//Best to use Light Grey that is 170, but this code is bugged and doing so shows them up.
+	ValidateWin(BaseWin,TRgb::Gray256(255));
+	ValidateWin(TestWin,TRgb::Gray256(255));
+	SetCursor(TPoint(-1000,10),TSize(10,30),TRgb::Gray256(255));
+	TheClient->iWs.Flush();
+	SetCursor(TPoint(10,10),TSize(10,30),TRgb::Gray256(255));
+	TheClient->iWs.Flush();
+	TRect rect(15,15,18,25);
+	SetCursorPlusBox(TPoint(10,10),TSize(10,30),TRgb::Gray256(255), &rect);
+	CancelTextCursor();
+//
+	ValidateWin(BaseWin,TRgb::Gray256(255));
+	ValidateWin(TestWin,TRgb::Gray256(255));
+	TheClient->iWs.Flush();
+	for(TInt winType=0;winType<3;winType++)
+		{
+		RWindowBase *cursorwin=NULL;
+		RBackedUpWindow backcursorwin(TheClient->iWs);
+		RWindow backwindow(TheClient->iWs);
+		RBlankWindow backblankwin(TheClient->iWs);
+		switch(winType)
+			{
+			case 0:
+				cursorwin=&backcursorwin;
+				User::LeaveIfError(backcursorwin.Construct(*TestWin->BaseWin(),EGray4,1));
+				break;
+			case 1:
+				cursorwin=&backwindow;
+				User::LeaveIfError(backwindow.Construct(*TestWin->BaseWin(),1));
+				break;
+			case 2:
+				cursorwin=&backblankwin;
+				User::LeaveIfError(backblankwin.Construct(*TestWin->BaseWin(),1));
+				break;
+			}
+		CleanupStack::PushL(TCleanupItem(CleanUpWindow,cursorwin));
+		User::LeaveIfError(cursorwin->SetSizeErr(TestWin->BaseWin()->Size()));
+		cursorwin->Activate();
+//
+		TTextCursor tc;
+		tc.iType=iCursorType;
+		tc.iHeight=30;
+		tc.iAscent=0;
+		tc.iWidth=50;
+		tc.iFlags=0;
+		tc.iColor=TRgb::Gray256(255);
+		TheClient->iGroup->GroupWin()->SetTextCursor(*cursorwin,TPoint(10,10),tc);
+//
+		CreateTestSpriteLC(*cursorwin, TPoint(10,20), 2);
+//
+		if (cursorwin==&backwindow)
+			RedrawWin(backwindow,TRgb::Gray256(255));
+		for(TInt count=0;count<9;count++)
+			{
+			RWindowBase *pwin=NULL;
+			RBackedUpWindow backedup(TheClient->iWs);
+			RWindow window(TheClient->iWs);
+			RBlankWindow blankwin(TheClient->iWs);
+			switch(count%3)
+				{
+				case 0:
+					pwin=&window;
+					window.Construct(*cursorwin,2);
+					window.SetBackgroundColor(TRgb(winColor,winColor,winColor));
+					break;
+				case 1:
+					pwin=&backedup;
+					backedup.Construct(*cursorwin,EGray4,2);
+					break;
+				case 2:
+					pwin=&blankwin;
+					blankwin.Construct(*cursorwin,2);
+					blankwin.SetColor(TRgb(winColor,winColor,winColor));
+					break;
+				}
+			CleanupStack::PushL(TCleanupItem(CleanUpWindow,pwin));
+			pwin->SetExtentErr(TPoint(30,30),TSize(50,80));
+			pwin->Activate();
+			TheClient->iWs.Flush();
+			CleanupStack::PopAndDestroy();	// window
+			if (cursorwin==&backwindow)
+				RedrawWin(backwindow,TRgb::Gray256(255));
+			TheClient->iWs.Flush();
+			TheClient->WaitForRedrawsToFinish();
+			COMPARE_WINDOWS_SOFTFAIL_WINSCW;
+			User::After(200000);	// Wait a fifth of a second to make sure the test is run during different states of flashing
+			}
+		for(TInt count2=0;count2<4;count2++)
+			{
+			cursorwin->SetPosition(TPoint(10,5));
+			TheClient->iWs.Flush();
+			User::After(100000);
+			cursorwin->SetPosition(TPoint(5,10));
+			TheClient->iWs.Flush();
+			User::After(100000);
+			cursorwin->SetPosition(TPoint(0,0));
+			TheClient->iWs.Flush();
+			User::After(100000);
+			TheClient->WaitForRedrawsToFinish();
+			COMPARE_WINDOWS_SOFTFAIL_WINSCW;
+			}
+		CleanupStack::PopAndDestroy(2);	// sprite & window containing sprite and cursor
+		}
+	CancelTextCursor();
+	}
+
+void CTCursorTest::INC040489L()
+	{
+	INFO_PRINTF1(_L("AUTO_TCur INC040489 "));
+	RWindowGroup group1(TheClient->iWs);
+	PushWindowL(&group1);
+	User::LeaveIfError(group1.Construct(ENullWsHandle));
+	RBlankWindow blank1(TheClient->iWs);
+	PushWindowL(&blank1);
+	User::LeaveIfError(blank1.Construct(group1,ENullWsHandle));
+	blank1.SetRequiredDisplayMode(EColor4K);
+	blank1.SetColor(TRgb(250,150,0));
+	blank1.Activate();
+	RWindowGroup group2(TheClient->iWs);
+	PushWindowL(&group2);
+	User::LeaveIfError(group2.Construct(ENullWsHandle));
+	RBlankWindow blank2(TheClient->iWs);
+	PushWindowL(&blank2);
+	User::LeaveIfError(blank2.Construct(group2,ENullWsHandle));
+	blank2.SetRequiredDisplayMode(EColor4K);
+	blank2.SetColor(TRgb(75,200,125));
+	blank2.Activate();
+	TheClient->Flush();
+	INFO_PRINTF1(_L(" Created Windows "));
+	TTextCursor tc;
+	tc.iType=KTextCursorInitialIdValue + iTest->iScreenNumber*KNumberOfCustoTextCursors;
+	tc.iHeight=80;
+	tc.iAscent=10;
+	tc.iWidth=30;
+	tc.iFlags=0;
+	tc.iColor=TRgb::Gray256(255);
+	INFO_PRINTF1(_L(" About to Set Text Cursor 1 "));
+	group2.SetTextCursor(blank2,TPoint(20,20),tc);
+	TheClient->Flush();
+	INFO_PRINTF1(_L(" Set Text Cursor 1 "));
+	User::After(2000000);		//2sec
+	TheClient->iWs.PrepareForSwitchOff();
+	TheClient->Flush();
+	User::After(2000000);		//2sec
+	group1.SetOrdinalPosition(0);
+	group2.CancelTextCursor();
+	TheClient->Flush();
+	INFO_PRINTF1(_L(" Canceled Text Cursor "));
+	User::After(2000000);		//2sec
+	//
+	// Before applying the fix, the following operations makes the Custom Text 
+	// Cursor Sprite invisible (happens even without wserv heartbeat suppression)
+	INFO_PRINTF1(_L(" About to Set Text Cursor 2 "));
+	group1.SetOrdinalPosition(2);
+	group2.SetTextCursor(blank2,TPoint(20,20),tc);
+	TheClient->Flush();
+	INFO_PRINTF1(_L(" Set Text Cursor 2 "));
+	User::After(2000000);		//2sec
+	TRawEvent event;
+	event.Set(TRawEvent::EActive);
+	TheClient->iWs.SimulateRawEvent(event);
+	TheClient->Flush();
+	INFO_PRINTF1(_L(" Simulated Active Event "));
+	User::After(2000000);		//2sec
+	CleanupStack::PopAndDestroy(4, &group1);
+	INFO_PRINTF1(_L(" End of test "));
+	}
+
+void CTCursorTest::CursorUpdatedBeforeWindowRenderedL()
+	{
+	INFO_PRINTF1(_L("CursorUpdatedBeforeWindowRenderedL"));
+	TheClient->iGroup->WinTreeNode()->SetOrdinalPosition(0);
+	// We use some unique looking colors otherwise its harder
+	// to spot which test is which
+	TRgb kAqua(134, 242, 251);
+	
+	iWorkInProgress = new(ELeave) CBlankWindow(kAqua);
+	iComparisonWindow = new(ELeave) CBlankWindow(kAqua);
+	CancelTextCursor();
+	
+	const TSize screenSize=TheClient->iGroup->Size();
+	const TInt kPad = 5;
+	const TInt kThirdOfScreenWidth = screenSize.iWidth/3;
+	const TInt kWinWidth = kThirdOfScreenWidth - 2*kPad;
+	const TInt kWinHeight = screenSize.iHeight - 2*kPad;
+	const TSize kWinSize(kWinWidth, kWinHeight);
+	const TPoint kCursorPos(30, 30);
+	iComparisonWindow->SetUpL(TPoint(2*kThirdOfScreenWidth + kPad, kPad), kWinSize, TheClient->iGroup, *TheClient->iGc);
+	iWorkInProgress->SetUpL(  TPoint(  kThirdOfScreenWidth + kPad, kPad), kWinSize, TheClient->iGroup, *TheClient->iGc);
+	
+	TTextCursor nonFlashingCursor;
+	nonFlashingCursor.iType = TTextCursor::ETypeRectangle;
+	nonFlashingCursor.iHeight=kCursorHeight;
+	nonFlashingCursor.iAscent=0;
+	nonFlashingCursor.iWidth=kCursorWidth;
+	nonFlashingCursor.iFlags=TTextCursor::EFlagNoFlash;
+	nonFlashingCursor.iColor = KRgbBlack; 
+	TheClient->iGroup->GroupWin()->SetTextCursor(*iWorkInProgress->BaseWin(), kCursorPos, nonFlashingCursor);
+	
+	// Up till this point, there has not been a CWsWindow::Render() for iWorkInProgress
+	// because the window has not been invalid
+	
+	/*
+	 * Here is the crux of the test.  We want to create the following condition in a window group:
+	 * 1) None of its windows have yet been Rendered using CWsWindow::Render()
+	 * 2) A text cursor is present
+	 * 3) Focus is lost then received
+	 * 
+	 * It used to be the case that Wserv picked up the handle to the Render Stage Text Cursor
+	 * drawer upon a Refresh caused by Rendering the window.  But drawing the Text Cursor could
+	 * come either from a Window Render or a change to the state of the Text Cursor, such as
+	 * receiving focus in the window.  A bug was experienced when the Text Cursor was drawn in
+	 * a window which never had been rendered.  This meant that the handle was not set up causing
+	 * an assert.
+	 * 
+	 * The code has been modified since then, to setup the handle to the Render Stage Text
+	 * Cursor during Wserv initialisation.  However, to guard against future changes, its
+	 * worthwhile to have this corner case test to ensure it is possible to receive focus
+	 * in a window which has never been rendered.  That is because the text cursor state
+	 * is updated in such circumstances, and that might trigger a draw of the cursor in a
+	 * future version of the text cursor code.
+	 */
+	TheClient->iGroup->WinTreeNode()->SetOrdinalPosition(1);  // lose focus
+	TheClient->iWs.Finish();
+	TheClient->iGroup->WinTreeNode()->SetOrdinalPosition(0); // gain focus
+	TheClient->iWs.Finish();
+	
+	// If we get this far without a panic or assert, we have passed this test.
+	
+	// Now allow CWsWindow::Render() to occur in iWorkInProgress
+	// The reason for doing this is so that when you watch the test
+	// progress you can see visual confirmation via the progress message and
+	// the coloured windows appear on the screen.  Otherwise you would think
+	// that the test had either been skipped or had broken.
+	iWorkInProgress->Invalidate();
+	iWorkInProgress->Redraw();
+	iComparisonWindow->Invalidate();
+	iComparisonWindow->Redraw();
+	TheClient->iWs.Finish();
+	delete iWorkInProgress;
+	iWorkInProgress = NULL;
+	delete iComparisonWindow;
+	iComparisonWindow = NULL;
+	INFO_PRINTF1(_L("End of test"));
+	}
+
+void CTCursorTest::INC097774()
+	{
+	TTimeIntervalMicroSeconds32 initialRepeatRate;
+	TTimeIntervalMicroSeconds32 repeatRate;
+	TheClient->iWs.GetKeyboardRepeatRate(initialRepeatRate,repeatRate);
+	
+	//simulates a text cursor moving across the screen as if a user was holding down
+	//a key to scroll the cursor through a section of text.
+	//before applying the fix the cursor only shows up intermittently instead of smoothly
+	//scrolling across the screen.
+	const TSize cursorSize(3,20);
+	const TInt moveInterval=10;
+	SetCursor(TPoint(0,20),cursorSize,TRgb::Gray256(255),TTextCursor::EFlagNoFlash);
+	TheClient->Flush();
+	User::After(initialRepeatRate);
+	for(TInt offset=10;offset<=100;offset+=moveInterval)
+		{
+		SetCursor(TPoint(offset,20),cursorSize,TRgb::Gray256(255),TTextCursor::EFlagNoFlash);
+		TheClient->Flush();
+		User::After(repeatRate);
+		}
+		
+	//simulate clipped text cursor moving accross the screen
+	TRect rect(0,20,3,40);
+	SetCursor(TPoint(0,20),cursorSize,TRgb::Gray256(255),rect,TTextCursor::EFlagNoFlash);
+	TheClient->Flush();
+	User::After(initialRepeatRate);
+	for(TInt offset=10;offset<=100;offset+=moveInterval)
+		{
+		rect.Move(moveInterval,0);
+		SetCursor(TPoint(offset,20),cursorSize,TRgb::Gray256(255),rect,TTextCursor::EFlagNoFlash);
+		TheClient->Flush();
+		User::After(repeatRate);
+		}	
+	}
+/** What happens when a cursor becomes off-screen when the screen is resized/rotated? 
+ * 
+ * 
+ **/
+void CTCursorTest::INC117232()
+	{
+	const TInt initialRepeatRate=300000;	// 3/10 seconds should be long enough to update everything!
+	TInt currMode=TheClient->iScreen->CurrentScreenMode();
+	TInt testMode=currMode;
+	TPixelsTwipsAndRotation currModeSize;
+	TheClient->iScreen->GetScreenModeSizeAndRotation(currMode, currModeSize);
+	//find a (rotated) mode where the dimensions of the screen shrank
+	for (TInt mode=0;mode<TheClient->iScreenModes.Count();mode++)
+		{
+		TPixelsTwipsAndRotation testModeSize;
+		TheClient->iScreen->GetScreenModeSizeAndRotation(mode,testModeSize);
+		if (	testModeSize.iPixelSize.iWidth<currModeSize.iPixelSize.iWidth-10
+			||	testModeSize.iPixelSize.iHeight<currModeSize.iPixelSize.iHeight-10
+			)
+			{
+			testMode=mode;
+			break;
+			}
+		}
+	if (testMode==currMode)
+		{
+		_LIT(KLog,"No smaller screen-size modes available - INC117232 test skipped");
+		LOG_MESSAGE(KLog);
+		//iStep->SetTestStepResult(EInconclusive);		//With this line the whole test fails which is too drastic
+		return;
+		}
+	//enable a cursor on the bottom right corner of the screen
+	TestWin->SetFullScreenExtL();
+	TheClient->Flush();
+	iCursorType=TTextCursor::ETypeRectangle;
+	SetCursor(TPoint(-20,-20)+TestWin->Size(),TSize(40,40),KRgbDarkMagenta,TTextCursor::EFlagNoFlash);
+	TheClient->Flush();
+	User::After(initialRepeatRate);
+	//shrink the screen
+	TheClient->iScreen->SetScreenMode(testMode);
+	TheClient->iScreen->SetAppScreenMode(testMode);
+	//The defect was that WServ would now crash! 
+	TheClient->Flush();
+	User::After(initialRepeatRate);
+	//Set everything back
+	TheClient->iScreen->SetScreenMode(currMode);
+	TheClient->iScreen->SetAppScreenMode(currMode);
+	TheClient->Flush();
+	User::After(initialRepeatRate);
+	}
+
+#ifdef TEST_GRAPHICS_WSERV_TAUTOSERVER_NGA
+/**
+ * Sets up a text cursor whose attributes indicate it should not be flashing
+ * and then checks to ensure this is the actual behaviour.
+ */
+void CTCursorTest::TextCursorNoFlashTestL()
+	{
+	TheClient->iGroup->WinTreeNode()->SetOrdinalPosition(0);
+	// We use some unique looking colors otherwise its harder
+	// to spot which test is which
+	TRgb kGentleYellow(251, 249, 198);
+	TRgb kGentlePink(253, 196, 221);
+	
+	iWorkInProgress = new(ELeave) CBlankWindow(kGentleYellow);
+	iComparisonWindow = new(ELeave) CBlankWindow(kGentleYellow);
+	CancelTextCursor();
+	TheClient->Flush();
+	
+	const TSize screenSize=TheClient->iGroup->Size();
+	const TInt kPad = 5;
+	const TInt kThirdOfScreenWidth = screenSize.iWidth/3;
+	const TInt kWinWidth = kThirdOfScreenWidth - 2*kPad;
+	const TInt kWinHeight = screenSize.iHeight - 2*kPad;
+	const TSize kWinSize(kWinWidth, kWinHeight);
+	const TPoint kCursorPos(30, 30);
+	iWorkInProgress->SetUpL(  TPoint(  kThirdOfScreenWidth + kPad, kPad), kWinSize, TheClient->iGroup, *TheClient->iGc);
+	iComparisonWindow->SetUpL(TPoint(2*kThirdOfScreenWidth + kPad, kPad), kWinSize, TheClient->iGroup, *TheClient->iGc);
+	
+	TTextCursor nonFlashingCursor;
+	
+	nonFlashingCursor.iType = TTextCursor::ETypeRectangle;
+	nonFlashingCursor.iHeight=kCursorHeight;
+	nonFlashingCursor.iAscent=0;
+	nonFlashingCursor.iWidth=kCursorWidth;
+	nonFlashingCursor.iFlags=TTextCursor::EFlagNoFlash;
+	nonFlashingCursor.iColor = kGentlePink; // We expect a Flicker Buffer Render Stage to ignore this color
+	
+	iWorkInProgress->Invalidate();
+	iWorkInProgress->Redraw();
+	iComparisonWindow->Invalidate();
+	iComparisonWindow->Redraw();
+	
+	DrawTextCursorSimilarToRenderStage(*TheClient->iGc, *iComparisonWindow->Win(), kCursorPos, nonFlashingCursor);
+	TheClient->iGroup->GroupWin()->SetTextCursor(*iWorkInProgress->BaseWin(), kCursorPos, nonFlashingCursor);
+	TheClient->Flush();
+		
+	CheckCursorDoesNotFlash(iWorkInProgress->BaseWin()->Size());
+	
+	delete iWorkInProgress;
+	iWorkInProgress = NULL;
+	delete iComparisonWindow;
+	iComparisonWindow = NULL;
+	}
+
+void CTCursorTest::TextCursorFlashTestL()
+	{
+	TheClient->iGroup->WinTreeNode()->SetOrdinalPosition(0);
+	// We use some unique looking colors otherwise its harder
+	// to spot which test is which
+	TRgb kMildPurple(218, 155, 244);
+	TRgb kPaleGreen(146, 190, 12);
+	
+	iWorkInProgress = new(ELeave) CBlankWindow(kMildPurple);
+	iComparisonWindow = new(ELeave) CBlankWindow(kMildPurple);
+	CancelTextCursor();
+	TheClient->Flush();
+	
+	const TSize screenSize=TheClient->iGroup->Size();
+	const TInt kPad = 5;
+	const TInt kThirdOfScreenWidth = screenSize.iWidth/3;
+	const TInt kWinWidth = kThirdOfScreenWidth - 2*kPad;
+	const TInt kWinHeight = screenSize.iHeight - 2*kPad;
+	const TSize kWinSize(kWinWidth, kWinHeight);
+	const TPoint kCursorPos(30, 30);
+	iWorkInProgress->SetUpL(  TPoint(  kThirdOfScreenWidth + kPad, kPad), kWinSize, TheClient->iGroup, *TheClient->iGc);
+	iComparisonWindow->SetUpL(TPoint(2*kThirdOfScreenWidth + kPad, kPad), kWinSize, TheClient->iGroup, *TheClient->iGc);
+	
+	TTextCursor flashingCursor;
+	
+	flashingCursor.iType = TTextCursor::ETypeRectangle;
+	flashingCursor.iHeight=kCursorHeight;
+	flashingCursor.iAscent=0;
+	flashingCursor.iWidth=kCursorWidth;
+	flashingCursor.iFlags=0; // implies that cursor SHOULD flash
+	flashingCursor.iColor = kPaleGreen; // We expect a Flicker Buffer Render Stage to ignore this color
+
+	iWorkInProgress->Invalidate();
+	iWorkInProgress->Redraw();
+	iComparisonWindow->Invalidate();
+	iComparisonWindow->Redraw();
+	
+	DrawTextCursorSimilarToRenderStage(*TheClient->iGc, *iComparisonWindow->Win(), kCursorPos, flashingCursor);
+	TheClient->iGroup->GroupWin()->SetTextCursor(*iWorkInProgress->BaseWin(), kCursorPos, flashingCursor);
+	TheClient->Flush();
+	
+	CheckCursorDoesFlash(kCursorPos, flashingCursor, kMildPurple);
+	CancelTextCursor();
+	TheClient->Flush();
+	
+	delete iWorkInProgress;
+	iWorkInProgress = NULL;
+	delete iComparisonWindow;
+	iComparisonWindow = NULL;
+	}
+
+void CTCursorTest::DrawTextCursorSimilarToRenderStage(CWindowGc& aGc, RWindow& aWin, const TPoint& aPos, const TTextCursor& aTextCursor)
+	{
+	// This method duplicates the way in which the default FlickerBuffer Render
+	// Stage draws a Text Cursor of ETypeRectangle.  @see CFbRenderStage::DrawTextCursor
+	// This code must be kept in sync with the FlickerBuffer Render Stage
+	
+	ASSERT(aTextCursor.iType == TTextCursor::ETypeRectangle);
+	const TRect updatedRegion(aPos,TSize(aTextCursor.iWidth,aTextCursor.iHeight));
+	aWin.Invalidate();
+	aWin.BeginRedraw();
+	aGc.Activate(aWin);
+	aGc.Clear();
+	aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
+	aGc.SetBrushColor(KRgbBlack);
+	aGc.SetPenStyle(CGraphicsContext::ENullPen);
+	aGc.Clear(updatedRegion);
+	aGc.Deactivate();
+	aWin.EndRedraw();
+	}
+
+void CTCursorTest::CheckCursorDoesNotFlash(const TSize& aSize)
+	{
+	const TInt kSampleTime = 100000; // one tenth of a second
+	const TInt kSampleLimit = 100;
+	TInt sampleIteration = 0;
+	TBool comparisonOkay = EFalse;
+	
+	while (sampleIteration < kSampleLimit)
+		{	
+		comparisonOkay = DoCheckRect(iWorkInProgress, iComparisonWindow, TRect(TPoint(), aSize), CWsScreenDevice::EIncludeTextCursor);
+		if (!comparisonOkay)
+			{
+			INFO_PRINTF2(_L("CheckCursorDoesNotFlash difference found after %d milliseconds"), sampleIteration*100);
+			break;
+			}
+		sampleIteration++;
+		User::After(kSampleTime);
+		}
+	TEST(comparisonOkay);
+	}
+
+void CTCursorTest::UpdateCountersOnCursorTransition(
+		const TBool	aTransitionedToOn,
+		TTime& 		aNow,
+		TInt64&		aDeltaTime,
+		TTime&		aLastDeltaTime,
+		TInt&		aWarmUpIterations,
+		const TInt&	aFlashChangeTime,
+		const TInt&	aToleranceMargin,
+		TInt&		aSampleNumber,
+		TInt&		aToleranceViolations
+		)
+	{
+	_LIT(KTxtOn,	" On");
+	_LIT(KTxtOff,	"Off");
+	TBufC<3> transitionType;	
+	transitionType = aTransitionedToOn ? KTxtOn : KTxtOff;
+	
+	aNow.UniversalTime();
+	aDeltaTime = aNow.MicroSecondsFrom(aLastDeltaTime).Int64();
+	aLastDeltaTime = aNow;
+	
+	if (aWarmUpIterations > 0)
+		{
+		aWarmUpIterations--;
+		}
+	else
+		{
+		if (aDeltaTime > aFlashChangeTime + aToleranceMargin ||
+				aDeltaTime < aFlashChangeTime - aToleranceMargin)
+			{
+			INFO_PRINTF5(_L(" Iteration %d, Cursor %S after %d, errorDelta %d microseconds"),
+					aSampleNumber, &transitionType, I64INT(aDeltaTime), I64INT(aDeltaTime - aFlashChangeTime));
+			aToleranceViolations++;
+			}
+		}
+	}
+void CTCursorTest::CheckCursorDoesFlash(const TPoint& aPos, const TTextCursor& aTextCursor, TRgb /* aBackgroundColor */)
+	{	
+	
+	/**
+	 * Quality of Service based thresholding
+	 * 
+	 * The idea behind this test is to identify tolerances which would either
+	 * cause the test to fail when the user would perceive the text cursor as
+	 * not flashing uniformly, or would point to an unexpected delay outside
+	 * the way the flashing (and scheduling of animations) is supposed to work.
+	 * 
+	 * Potentially the cursor can be late if we miss a V-SYNC from hardware.  In
+	 * such cases we expect to see the cursor on the next frame.  Since the V-SYNC
+	 * is typically 1/50 second, a tolerance of two frames, or 1/25 second is reasonable.
+	 * 
+	 * If the cursor is delayed longer than this, say a long time of 1 second, but this
+	 * does not happen too often, then the user is likely to still be happy.  So we
+	 * set the period of testing to 60 seconds, and set the violations limit to 2.
+	 */
+	const TInt kOneSecond = 1000000;
+	const TInt kFlashPeriod = kOneSecond; 		// comprises one "ON" and one "OFF"
+	const TInt kToleranceFactor = 25; 			// meaning 1/25 of a Flash Period
+	const TInt kNumberTestFlashPeriods = 60;	// meaning 60 Flash Periods worth of testing
+	const TInt kMaximumToleranceViolations = 2;	// number of times an occassional flash may be late or early
+	
+	const TInt kToleranceMargin = kFlashPeriod / kToleranceFactor;
+	const TInt kNumberSamples = kNumberTestFlashPeriods * kToleranceFactor;
+	const TInt kFlashChangeTime = kFlashPeriod / 2;
+	
+	// The first couple of changes to the cursor should be ignored because
+	// when the test is started, the cursor may have been on for a while.
+	// Then when the cursor goes off, it appears to have switched to the
+	// off state too early.  We therefore ignore the first two changes
+	// so we start cleanly.
+	TInt warmUpIterations = 2;
+	
+	// Empirically we see that cursors mostly flash with good timeliness apart from
+	// occasional events causing them to be either early or late.  In order to keep
+	// a tight tolerance (1/50 second is around the screen refresh time) but still
+	// allow for the occasional variance (seen to be 1/23 second) we use a counter
+	// toleranceViolations < kMaximumToleranceViolations
+	TInt toleranceViolations = 0;
+	TBool cursorShownLastTime = EFalse;
+	TBool cursorShown = EFalse;
+	TTime lastDeltaTime;
+	TTime now;
+	TInt64 deltaTime = 0;
+	lastDeltaTime.UniversalTime();
+	now.UniversalTime();
+
+	TRect textCursorRect(TRect(aPos, TSize(aTextCursor.iWidth, aTextCursor.iHeight)));
+
+	for (TInt sampleNumber = 0; sampleNumber < kNumberSamples; sampleNumber++)
+		{
+		cursorShown = DoCheckRect(iWorkInProgress, iComparisonWindow, textCursorRect, CWsScreenDevice::EIncludeTextCursor);
+
+		if (cursorShown && !cursorShownLastTime)
+			{
+			cursorShownLastTime = ETrue;
+			UpdateCountersOnCursorTransition(
+					cursorShownLastTime, now, deltaTime, lastDeltaTime, warmUpIterations, kFlashChangeTime,
+					kToleranceMargin, sampleNumber, toleranceViolations);
+			}
+		else if (!cursorShown && cursorShownLastTime)
+			{
+			cursorShownLastTime = EFalse;
+			UpdateCountersOnCursorTransition(
+					cursorShownLastTime, now, deltaTime, lastDeltaTime, warmUpIterations, kFlashChangeTime,
+					kToleranceMargin, sampleNumber, toleranceViolations);
+			}
+
+		if (toleranceViolations > kMaximumToleranceViolations)
+			break;
+
+		User::After(kToleranceMargin);
+		}
+	// Check was some flashing
+	TEST_SOFTFAIL_WINSCW(warmUpIterations == 0);
+	// Check cursor flashed on and off, regularly and on-time
+	TEST_SOFTFAIL_WINSCW(toleranceViolations <= kMaximumToleranceViolations);
+	}
+#endif // TEST_GRAPHICS_WSERV_TAUTOSERVER_NGA
+
+void CTCursorTest::MakeCursors(TTextCursor& aTextCursor, TTextCursor& aCustomCursor)
+	{
+	aCustomCursor.iType = KTextCursorInitialIdValue + iTest->iScreenNumber*KNumberOfCustoTextCursors; // custom text cursor
+	aCustomCursor.iAscent=0;
+	aCustomCursor.iHeight=kCursorHeight;
+	aCustomCursor.iWidth=kCursorWidth;
+	aCustomCursor.iFlags=TTextCursor::EFlagNoFlash; 
+	aCustomCursor.iColor=TRgb::Color256(217);	
+		
+	// Create a standard cursor for the tests
+	aTextCursor.iType = TTextCursor::ETypeRectangle; // Normal rectangular text cursor
+	aTextCursor.iHeight=kCursorHeight;
+	aTextCursor.iAscent=0;
+	aTextCursor.iWidth=kCursorWidth;
+	aTextCursor.iFlags=TTextCursor::EFlagNoFlash;
+	}
+
+void CTCursorTest::StartDoubleCursorTestL(TInt aTestNumber)
+	{
+	// general setup
+	CBlankWindow* win1=new(ELeave) CBlankWindow(KRgbWhite);
+	CleanupStack::PushL(win1);
+
+	win1->SetUpL(kWin1TopLeft,kWinSize,TheClient->iGroup,*TheClient->iGc,EColor64K);
+	
+	win1->Redraw();
+	
+	// Create the second window
+	CBlankWindow* win2=new(ELeave) CBlankWindow(KRgbWhite);
+	CleanupStack::PushL(win2);
+
+	win2->SetUpL(kWin2TopLeft,kWinSize,TheClient->iGroup,*TheClient->iGc,EColor64K);
+	win2->Redraw();
+
+	// Create normal and custom cursor for the tests
+	TTextCursor textCursor;
+	TTextCursor customCursor;
+	MakeCursors(textCursor, customCursor);
+
+	TheClient->Flush();
+	CWindowGc* winGc = TheClient->iGc;	
+
+	switch(aTestNumber)
+		{
+		case 1:
+		CheckNoDoubleCursorTest1L(win1, win2, textCursor, customCursor, winGc);
+		break;
+		
+		case 2:
+		CheckNoDoubleCursorTest2L(win1, win2, textCursor, customCursor, winGc);
+		break;
+		
+		case 3:
+		CheckNoDoubleCursorTest3L(win1, win2, textCursor, customCursor, winGc);
+		break;
+		
+		default:
+		TEST(EFalse);
+		break;
+		}
+	CleanupStack::PopAndDestroy(2); 	
+	}
+
+// DEF098704
+void CTCursorTest::CheckNoDoubleCursorTest1L(CBlankWindow* aWin1, CBlankWindow* aWin2, TTextCursor& /*aTextCursor*/, TTextCursor& aCustomCursor, CWindowGc* aWinGc)
+	{
+	// Test that changing the focus of a custom text cursor does not leave that cursor drawn where it was (INC093898)
+
+	TheClient->iGroup->GroupWin()->SetTextCursor(*aWin1->BaseWin(),TPoint(),aCustomCursor);
+		
+	// Bit blit the TEST_BITMAP_NAME image to the second window to use as a comparison
+	// this is the same image that the custom cursor is using
+	CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
+	CleanupStack::PushL(bitmap);
+	TEST(KErrNone == bitmap->Load(TEST_BITMAP_NAME,0,ETrue)); 
+
+	aWinGc->Activate(*aWin2->Win());
+	TRect updateArea(TPoint(0,0), bitmap->SizeInPixels());
+	aWin2->Win()->Invalidate(updateArea);
+	aWin2->Win()->BeginRedraw(updateArea);
+	aWinGc->BitBlt(TPoint(0,0),bitmap); 
+	aWinGc->Deactivate();
+	aWin2->Win()->EndRedraw();
+	TheClient->Flush();
+	doCheckNoDoubleCursor(aWin1,aWin2,kWin1TopLeft,kWin2TopLeft,aCustomCursor,bitmap->SizeInPixels(),CWsScreenDevice::EIncludeSprite);
+	CleanupStack::PopAndDestroy(1); // bitmap
+	}
+
+// DEF098704
+void CTCursorTest::CheckNoDoubleCursorTest2L(CBlankWindow* aWin1, CBlankWindow* aWin2, TTextCursor& /*aTextCursor*/, TTextCursor& aCustomCursor, CWindowGc* aWinGc)
+	{
+	//TEST 2: Checks that no artifacts are left behind when a text cursor is moved from under a transparent sprite
+	
+	// Construct the window win1 with a transparent sprite
+	
+	// Clear the top and bottom windows
+	ResetWindows(aWinGc,aWin1,aWin2);	
+	
+	// Create a bitmap and a corresponding bitmap mask
+	CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
+	CleanupStack::PushL(bitmap);
+	TEST(KErrNone == bitmap->Load(TEST_BITMAP_NAME,0,ETrue)); 
+	CBitmap* spriteBitmap=CBitmap::NewL(kWinSize,EColor256);
+	CleanupStack::PushL(spriteBitmap);
+	spriteBitmap->Gc().SetBrushColor(KRgbBlack);
+	spriteBitmap->Gc().SetBrushStyle(CGraphicsContext::ESolidBrush);
+	spriteBitmap->Gc().SetPenStyle(CGraphicsContext::ESolidPen); 
+	spriteBitmap->Gc().DrawRect(TRect(kWinSize));
+	CBitmap* mask=CBitmap::NewL(kWinSize,EColor256);
+	CleanupStack::PushL(mask);
+	mask->Gc().SetBrushStyle(CGraphicsContext::ESolidBrush);
+	mask->Gc().SetBrushColor(KRgbBlack);
+	mask->Gc().DrawRect(TRect(kWinSize));	
+	
+	// Create a sprite
+	RWsSprite sprite = RWsSprite(TheClient->iWs);
+	CleanupClosePushL(sprite);
+	TEST(KErrNone == sprite.Construct(*aWin1->BaseWin(),TPoint(),0));
+	
+	// Add the bitmap to the sprite
+	TSpriteMember member;
+	member.iInvertMask=EFalse;
+	member.iDrawMode=CGraphicsContext::EDrawModePEN;
+	member.iOffset=TPoint();
+	member.iInterval=TTimeIntervalMicroSeconds32(0);
+	member.iBitmap = &spriteBitmap->Bitmap();
+	member.iMaskBitmap = &mask->Bitmap(); 
+	TEST(KErrNone == sprite.AppendMember(member));
+	
+	// Activate the sprite in win1
+	TEST(KErrNone == sprite.Activate());
+	
+	// Put a cursor in win1
+	TheClient->iGroup->GroupWin()->SetTextCursor(*aWin1->BaseWin(),TPoint(),aCustomCursor);
+	
+	// Bit blit the matching bitmap to the bottom window
+	TRect bitmapArea(TPoint(0,0), bitmap->SizeInPixels());
+	aWin2->Win()->Invalidate(bitmapArea);
+	aWin2->Win()->BeginRedraw(bitmapArea);
+	aWinGc->Activate(*aWin2->Win());
+	aWinGc->BitBlt(TPoint(),bitmap); 
+	aWinGc->Deactivate();
+	aWin2->Win()->EndRedraw();
+		
+	TheClient->Flush();
+	doCheckNoDoubleCursor(aWin1,aWin2,kWin1TopLeft,kWin2TopLeft,aCustomCursor,bitmap->SizeInPixels(),CWsScreenDevice::EIncludeSprite);
+	CleanupStack::PopAndDestroy(4); // sprite, mask, spriteBitmap, bitmap
+	}
+
+// DEF098704		
+void CTCursorTest::CheckNoDoubleCursorTest3L(CBlankWindow* aWin1, CBlankWindow* aWin2, TTextCursor& aTextCursor,TTextCursor& aCustomCursor, CWindowGc* aWinGc)
+	{
+	//
+	// TEST 3: Test a flashing text cursor does not leave artifacts when a redraw + change position happens during
+	// the time the cursor flashing 'off'
+	// 
+	// This test moves a flashing cursor a number of times over a two second period to a seconds position.
+	// it does it a number of times so some of the redraws will occur during the 'flash off' period
+	// We then compare the 'after' position to what we expect
+	// 
+	// There are four possible outcomes when we look at the bitmap after the redraw + move
+	// Position 1 is the original position, position 2 is the new position after the redraw
+	// 
+	// cursor artifact @ pos1 and flashed on cursor @ pos2
+	// cursor artifact at pos1 and flashed off cursor @ pos2
+	// no artifact at pos1 and flashed off cursor @ pos2
+	// no artifact at pos1 and flashed on cursor @ pos2
+	// 
+	// any artifacts left over will cause the complete test to fail.
+	//
+	
+	//
+	// PART A: 
+	aTextCursor.iFlags=0; 	// flashing
+
+	ResetWindows(aWinGc,aWin1,aWin2);	
+	TestForArtifacts(aWin1, aTextCursor);
+	
+	//
+	// PART B - For a non-custom text cursor
+	aCustomCursor.iFlags=0; // flashing
+
+	ResetWindows(aWinGc,aWin1,aWin2);	
+	TestForArtifacts(aWin1, aCustomCursor);	
+	}
+	
+// moves the cursor between two positions while flashing and tests no artifacts are left at the position it moved from
+// The moves take place in a loop so it is tested happening when the cursor is flashed on and also off
+void CTCursorTest::TestForArtifacts(CBlankWindow* aWin1, TTextCursor& aCursor)
+	{
+	const TInt KIterations = 30;
+	const TPoint kStartPos(0,0);
+	const TPoint kMoveToPos(200,0);
+	TRect r1(kWin1TopLeft,kCursorSize);
+	TRect r2(kWin2TopLeft,kCursorSize);
+	const TPoint kWin1TopLeft; 
+	const TPoint kWin2TopLeft; 
+	const TSize aCursorSize;
+
+	TheClient->iGroup->GroupWin()->SetTextCursor(*aWin1->BaseWin(),kStartPos,aCursor);
+	TheClient->Flush();
+
+	TInt initialRepeatRate = 1000000; 
+	const TInt KIncrement = 30000;
+	TInt i=0;
+
+	for(i=0; i<KIterations; i++)		
+		{
+		// move the cursor to its new position
+		TheClient->iGroup->GroupWin()->SetTextCursor(*aWin1->BaseWin(),kMoveToPos,aCursor);
+		TheClient->Flush();
+
+		User::After(initialRepeatRate);
+		
+		// check no artifact was left in position 1 by comparing against (blank) win2
+		if(!TheClient->iScreen->RectCompare( r1,r2, CWsScreenDevice::EIncludeTextCursor))
+			{
+			break; // detected an artifact remaining, test failed
+			}
+
+		// move the cursor back to its start position, this resets the flash timer which is why we increment initialRepeatRate 
+		TheClient->iGroup->GroupWin()->SetTextCursor(*aWin1->BaseWin(),kStartPos,aCursor);
+		TheClient->Flush();
+		initialRepeatRate += KIncrement;
+		}
+		
+		// if all went well i should equal KIterations, if it doesnt its because we detected 
+		// an artifact and quit the test early
+	TEST_SOFTFAIL_WINSCW(i==KIterations);
+	}
+	
+
+// Tests the two windows match, moves the cursor off win 1 then tests they no longer match 		
+void CTCursorTest::doCheckNoDoubleCursor(CBlankWindow* aWin1,
+											CBlankWindow* aWin2,
+											const TPoint& aWin1Tl,
+											const TPoint& aWin2Tl,
+											const TTextCursor& aCursor,
+											const TSize& aCursorSize,
+											CWsScreenDevice::TSpriteInCompare aFlags)
+	{
+	TRect r1(aWin1Tl,aCursorSize);
+	TRect r2(aWin2Tl,aCursorSize);
+	
+	TInt compareTries = 0;
+	const TInt compareLimit = 5;
+	
+	TBool correctComparison = EFalse;
+	while (!correctComparison && compareTries < compareLimit)
+		{
+		compareTries++;
+		User::After(500000);
+		correctComparison = TheClient->iScreen->RectCompare(r1,r2, aFlags);
+		}
+
+	INFO_PRINTF3(_L("Result Before %d (attempts %d)"), correctComparison, compareTries);
+	TEST_SOFTFAIL_WINSCW(correctComparison);
+
+	
+	// Change the focus off win1, by drawing the text cursor on the second window
+	TheClient->iGroup->GroupWin()->SetTextCursor(*aWin2->BaseWin(),aWin2Tl,aCursor);
+	TheClient->Flush();
+
+	// Cause a redraw
+	aWin1->CTWin::DrawNow();
+	TheClient->WaitForRedrawsToFinish();
+
+	// make sure any cursor has actually moved	
+	User::After(1000000); // 1 sec
+	
+	TBool resultAfter;
+	resultAfter = !TheClient->iScreen->RectCompare(r1,r2, aFlags);
+	INFO_PRINTF2(_L("Result After %d"), resultAfter);
+	TEST_SOFTFAIL_WINSCW(resultAfter);
+	}	
+
+// resets the windows to their initial state
+void CTCursorTest::ResetWindows(CWindowGc* aWinGc,CBlankWindow* aWin1,CBlankWindow* aWin2)
+	{
+	TheClient->iGroup->GroupWin()->CancelTextCursor();
+	aWinGc->Activate(*aWin1->Win());
+	aWinGc->Reset();
+	aWinGc->Clear();
+	aWinGc->Deactivate();
+
+	aWin1->Invalidate();
+	aWin1->Redraw();
+	aWin2->Invalidate();
+	aWin2->Redraw();
+	TheClient->Flush();
+	}
+	
+void CTCursorTest::RunTestCaseL(TInt /*aCurTestCase*/)
+	{
+	TBool deleteMove=EFalse;
+	((CTCursorTestStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName);
+
+	switch(++iTest->iState)
+		{
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-0241
+
+@SYMDEF				DEF081259
+
+@SYMTestCaseDesc    Test the text cursor functions properly as a window is moved
+
+@SYMTestPriority    High
+
+@SYMTestStatus      Implemented
+
+@SYMTestActions     Move a window about the screen and meanwhile check the text
+					cursor functions correctly
+
+@SYMTestExpectedResults The text cursor functions correctly as the window is moved
+*/
+	case 1:
+		((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-0241"));
+		while (!deleteMove)
+			{
+			if (iCursorType==TTextCursor::ETypeFirst)
+				iTest->LogSubTest(_L("Cursor 1"));
+			if (MoveWindow())
+				{
+				if (IncrementCursorType())
+					{
+					ResetMoveWindowsL();
+					}
+				else
+					{
+					DeleteMoveWindows();
+					deleteMove =true;
+					}
+				}
+			}
+		break;
+
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-0242
+
+@SYMDEF				DEF081259
+
+@SYMTestCaseDesc    Test the text cursor functions properly as the window is scrolled
+
+@SYMTestPriority    High
+
+@SYMTestStatus      Implemented
+
+@SYMTestActions     Scroll the window and meanwhile check the text cursor functions correctly
+
+@SYMTestExpectedResults The text cursor functions correctly as the window is scrolled
+*/
+		case 2:
+			((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-0242"));
+			iTest->LogSubTest(_L("Cursor 2"));
+			iCursorType=TTextCursor::ETypeRectangle;
+			ScrollTest();
+			iCursorType=TTextCursor::ETypeFirst;
+			break;
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-0244
+
+@SYMDEF				DEF081259
+
+@SYMTestCaseDesc    Test the text cursor functions properly as a blank window is moved
+
+@SYMTestPriority    High
+
+@SYMTestStatus      Implemented
+
+@SYMTestActions     Move a blank window about the screen and meanwhile check the text
+					cursor functions correctly
+
+@SYMTestExpectedResults The text cursor functions correctly as the blank window is moved
+*/
+		case 3:
+			((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-0244"));
+			iTest->LogSubTest(_L("Move window1"));
+			MoveWindowTest1L();
+			break;
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-0245
+
+@SYMDEF				DEF081259
+
+@SYMTestCaseDesc    Test that a non flashing text cursor functions properly as a 
+					blank window is moved
+
+@SYMTestPriority    High
+
+@SYMTestStatus      Implemented
+
+@SYMTestActions     Move a blank window about the screen and meanwhile check that a non
+					flashing text cursor functions correctly
+
+@SYMTestExpectedResults The text cursor functions correctly as the blank window is moved
+*/
+		case 4:
+			((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-0245"));
+			while (IncrementCursorType())
+				{
+				iTest->LogSubTest(_L("Move window2"));
+				MoveWindowTest2L();
+				}
+			break;		
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-0247
+
+@SYMDEF				DEF081259
+
+@SYMTestCaseDesc    Tests a Custom Text Cursor Sprite visibility after wserv hearbeat suppression
+					REQUIREMENT:	INC040489.
+
+@SYMTestPriority    High
+
+@SYMTestStatus      Implemented
+
+@SYMTestActions     Create a window group with an associated window for it, then activate it.
+					Create another window group with an associated window along with a custom cursor, 
+					then active it. Make a call to suppress the wserv hearbeat, which will stop 
+					the custom cursor from flashing with flash ON state. Bring the first window 
+					group to the foreground and cancel the custom test cursor in the second window group.
+					After that, put the first window group to the background and set the custom test 
+					cursor in the second window group. Simulate a raw key event to start 
+					the wserv heartbeat, which will make the custom cursor flashing.
+
+@SYMTestExpectedResults The Custom text cursor in the second window group should be visible and flashing, 
+						when it comes to the foreground after the first window group sent to the background.
+*/
+		case 5:
+			((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-0247"));
+			iTest->LogSubTest(_L("Custom Text Cursor Sprite visibility"));
+			INC040489L();
+			break;
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-2095-0015
+
+@SYMTestCaseDesc    Text Cursor allows Update before Rendering the owning window
+
+@SYMTestPriority    Normal
+
+@SYMTestStatus      Implemented
+
+@SYMTestActions     Create a window group and two windows, one with a Text Cursor.
+					Stimulate a state change in the Text Cursor by receiving
+					window focus, but before the Window has ever been Rendered.
+					This shakes out logic in RWsTextCursor which depends on
+					side effects arising from having executed CWsWindow::Render()
+					
+@SYMTestExpectedResults 
+					There should be no panic or assertion.
+*/
+		case 6:
+			((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-2095-0015"));
+			iTest->LogSubTest(_L("Update before Render"));
+			CursorUpdatedBeforeWindowRenderedL();
+			break;
+
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-0248
+
+@SYMDEF  			DEF081259
+
+@SYMTestCaseDesc    Tests a bad use of text cursor functionality from a client.
+					REQ 1079, CR RDEF-5F7Q24 (10/04/2003).
+
+@SYMTestPriority    High
+
+@SYMTestStatus      Implemented
+
+@SYMTestActions     This test case checks whether the window server is able to detect a bad
+					use of the text cursor functionality (including the custom text cursor)
+					by a client.
+					This test case launches several threads and each of them will try
+					to use the text cursor functionality in a non-proper way.
+
+@SYMTestExpectedResults Each new thread has panic code associated to it. This is the expected panic when
+						the thread dies.
+						The thread once launched is expected to panic and the returning panic code should
+						match the expected one.
+*/
+		case 7:
+			((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-0248"));
+			iTest->LogSubTest(_L("Panic"));
+			TestPanicsL();
+			break;
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-0400
+
+@SYMDEF				PDEF099013
+
+@SYMTestCaseDesc    Cursor moves slowly in text editors. 
+
+@SYMTestPriority    High
+
+@SYMTestStatus      Implemented
+
+@SYMTestActions     This test case is a VISUAL TEST only on whether a scrolling text cursor is drawn to the
+					screen correctly. 2 types of cursor are checked both clipped and non clipped cursors.
+					In each case the test simulates a text cursor moving across the screen as if a user were
+					holding down a key to scroll the cursor through a section of text.
+
+@SYMTestExpectedResults The text cursor in both cases should scroll smoothly to the centre of the screen.
+						In versions prior to this fix the cursor was not correctly drawn and appeared to move 	
+						slowly.
+*/
+		case 8:
+			((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-0400"));
+			iTest->LogSubTest(_L("Text Cursor Update Tests"));
+			INC097774();
+			break;	
+		
+/**
+@SYMTestCaseID		GRAPHICS-WSERV-0401
+
+@SYMDEF  			DEF098704
+
+@SYMTestCaseDesc    Test code for implemented fix to remove double cursors 
+					
+@SYMTestPriority    Normal
+
+@SYMTestStatus      Implemented
+
+@SYMTestActions     This test case tests for artifacts left over when normal/custon flashing/non-flashing cursors are drawn.
+					Test that changing the focus of a custom text cursor does not leave that cursor drawn where it was (INC093898)
+
+@SYMTestExpectedResults 
+*/			
+	case 9:
+		((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-0401"));
+		iTest->LogSubTest(_L("Double cursors test 1"));
+		StartDoubleCursorTestL(1);
+		break;
+
+	/**
+	@SYMTestCaseID		GRAPHICS-WSERV-0402
+
+	@SYMDEF				DEF098704
+
+	@SYMTestCaseDesc    Test code for implemented fix to remove double cursors 
+
+	@SYMTestPriority    Normal
+
+	@SYMTestStatus      Implemented
+
+	@SYMTestActions     Checks that no artifacts are left behind when a text cursor is moved from under a transparent sprite
+
+	@SYMTestExpectedResults 
+	*/
+	case 10:
+		((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-0402"));
+		iTest->LogSubTest(_L("Double cursors test 2"));
+		StartDoubleCursorTestL(2);
+		break;
+
+	/**
+	@SYMTestCaseID		GRAPHICS-WSERV-0403
+
+	@SYMDEF				DEF098704
+
+	@SYMTestCaseDesc    Test code for implemented fix to remove double cursors 
+						
+	@SYMTestPriority    Normal
+
+	@SYMTestStatus      Implemented
+
+	@SYMTestActions     This test moves a flashing cursor a number of times over a two second period to a seconds position.
+						it does it a number of times so some of the redraws will occur during the 'flash off' period
+						We then compare the 'after' position to what we expect
+
+	@SYMTestExpectedResults 
+	*/
+	case 11:
+		((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-0403"));
+		iTest->LogSubTest(_L("Double cursors test 3"));
+		StartDoubleCursorTestL(3);
+		break;
+
+	/**
+	@SYMTestCaseID		GRAPHICS-WSERV-0483
+
+	@SYMDEF				INC117232
+
+	@SYMTestCaseDesc    Test code: Refreshing cursors becoming offscreen due to screen size change should not panic 
+
+	@SYMTestPriority    Normal
+
+	@SYMTestStatus      Implemented
+
+	@SYMTestActions     Create a cursor on bottom right of screen, change to a screen mode that excludes that coordinate
+
+	@SYMTestExpectedResults 
+						The server should not panic.
+	*/
+	case 12:
+		((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-0483"));
+		iTest->LogSubTest(_L("Screen resize invalidate cursor off-screen"));
+		INC117232();
+		break;
+
+	/**
+	@SYMTestCaseID		GRAPHICS-WSERV-2095-0016
+
+	@SYMTestCaseDesc    Text Cursor flag TTextCursor::EFlagNoFlash honored 
+
+	@SYMTestPriority    Normal
+
+	@SYMTestStatus      Implemented
+
+	@SYMTestActions     Create a text cursor with the TTextCursor::EFlagNoFlash setting.  Observe the screen over
+						a short period of time to verify that it remains continuously in the Flash ON state.
+
+	@SYMTestExpectedResults 
+						The text cursor should be always shown.
+	*/
+	case 13:
+	#ifdef TEST_GRAPHICS_WSERV_TAUTOSERVER_NGA
+		((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-2095-0016"));
+		iTest->LogSubTest(_L("Text cursor EFlagNoFlash test"));
+		TextCursorNoFlashTestL();
+	#endif
+		break;
+
+	/**
+	@SYMTestCaseID		GRAPHICS-WSERV-2095-0009
+
+	@SYMTestCaseDesc    Text Cursor flashes when flag value is 0
+
+	@SYMTestPriority    Normal
+
+	@SYMTestStatus      Implemented
+
+	@SYMTestActions     Create a text cursor with the 0 flag setting.  Observe the screen over
+						a short period of time to verify that the cursor flashes ON and OFF at
+						the correct period of one second.
+
+	@SYMTestExpectedResults 
+						The text cursor should flash.
+	*/
+	case 14:
+	#ifdef TEST_GRAPHICS_WSERV_TAUTOSERVER_NGA
+		((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-2095-0009"));
+		iTest->LogSubTest(_L("Text cursor will Flash test"));
+		TextCursorFlashTestL();
+	#endif
+		break;
+
+	/**
+	@SYMTestCaseID		GRAPHICS-WSERV-2095-0017
+
+	@SYMTestCaseDesc    Text Cursor handles different valid Cursor Setttings
+
+	@SYMTestPriority    Normal
+
+	@SYMTestStatus      Implemented
+
+	@SYMTestActions     Create a text cursor and then issue a SetTextCursor.  Then repeatedly
+						call SetTextCursor, varying the arguments relating to the Text Cursor
+						as well as keeping the arguments the same on one occassion.
+
+	@SYMTestExpectedResults 
+						The system should not panic as the arguments supplied are never invalid.
+	*/
+	case 15:
+		((CTCursorTestStep*)iStep)->SetTestStepID(_L("GRAPHICS-WSERV-2095-0017"));
+		iTest->LogSubTest(_L("SetTextCursor test"));
+		TextCursorSetLCoverageTests();
+		break;
+
+		default:
+			((CTCursorTestStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName);
+			((CTCursorTestStep*)iStep)->CloseTMSGraphicsStep();
+			TestComplete();
+			break;
+		}
+	((CTCursorTestStep*)iStep)->RecordTestResultL();
+	}
+
+__WS_CONSTRUCT_STEP__(CursorTest)