windowing/windowserver/test/t_stress/src/comparison.cpp
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/test/t_stress/src/comparison.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,906 @@
+// Copyright (c) 2008-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:
+//
+
+/**
+ @file
+ @test
+ @internalComponent
+*/
+ 
+
+#include <e32std.h>
+#include <fbs.h>
+
+#include "test_step_logger.h"
+#include "comparison.h"
+#include "utils.h"
+#include "compwin.h"
+#include "crpwin.h"
+#include "edgedwin.h"
+#include "coordinatewin.h"
+#include "backedupwin.h"
+#include "enormouswin.h"
+#include "animatedwin.h"
+#include "spritewin.h"
+#include "panic.h"
+
+
+const TInt KSteps = 10;
+
+CComparison::COperationTimer::COperationTimer(CComparison* aComp):CTimer(0), iComp(aComp)
+{}
+
+void CComparison::COperationTimer::ConstructL()
+	{
+	CTimer::ConstructL();
+	}
+
+void CComparison::COperationTimer::DoCancel()
+	{}
+
+void CComparison::COperationTimer::RunL()
+	{
+	iComp->Tick();
+	}
+
+
+/*-------------------------------------------------------------------------*/
+// COneShotCompare
+CComparison::COneShotCompare* CComparison::COneShotCompare::NewL(TInt aPriority, CComparison& aComparison)
+	{
+	return new(ELeave)CComparison::COneShotCompare(aPriority, aComparison);
+	}
+
+CComparison::COneShotCompare::COneShotCompare(TInt aPriority, CComparison& aComparison)
+	:CAsyncOneShot(aPriority), iComparison(aComparison)
+	{
+	}
+
+void CComparison::COneShotCompare::RunL()
+	{
+	iComparison.iScreen->CopyScreenToBitmap(iComparison.iScreenBitmap);
+	iComparison.SetVerifyTick(User::NTickCount());
+	iComparison.Verify(iComparison.iScreenBitmap);
+	}
+/*-------------------------------------------------------------------------*/
+
+_LIT(KConfigurationWindowSuffix, "-Window");
+
+/*******************************************************************************
+This is the stresslet itself
+*******************************************************************************/
+CComparison * CComparison::NewLC(MTestStepReporter& aReporter)
+	{
+	CComparison * self = new (ELeave) CComparison(aReporter);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+void CComparison::ConstructL()
+	{
+	iWatchCat = CTestExecWatchCat::NewL( CExecutionContext::ECtxRandomAndRecord );
+	}
+
+CComparison::CComparison (MTestStepReporter& aReporter):
+	CStresslet(aReporter), iDifferenceBitmap(NULL), iDifferenceDevice(NULL), iOneShotCompare(NULL)
+	{
+	}
+
+/**
+ Sets stress-test configuration (read from ini file).
+ @param aRunData configuration data
+ @param aConfFactory a factory interface for creating "section" readers. These
+ are used to supply configuration data for each window type.
+ */
+void CComparison::SetRunDataL(const TRunData& aRunData, MTestStepConfigurationContextFactory* aConfFactory)
+	{
+	iData = aRunData;
+	User::LeaveIfError(iFs.Connect());
+	iFs.MkDirAll(iData.loggingPath);
+	iWatchCat->SetLoggingPathL(iData.loggingPath);
+
+	//each window type can have its own configuration
+	MTestStepConfigurationContext* context; //context created by the factory argument
+	RBuf section; //section name (window-type + "-window"
+	section.Create(32);
+	CleanupStack::PushL(&section);
+
+	struct STestStepConfEntry
+		{
+		const TPtrC8 iType;	//section name
+		void (*iFunc)(const MTestStepConfigurationContext*); //configuration loader
+		} confLoaders[] = 
+		{
+			{KCommonWindowType(),    CCompWin::LoadConfiguration},
+			{KAnimatedWindowType(),   CAnimatedWin::LoadConfiguration},
+			{KBackedupWindowType(),   CBackedupWin::LoadConfiguration},
+			{KCoordinateWindowType(), CCoordinateWin::LoadConfiguration},
+			{KCrpWindowType(),        CCrpWin::LoadConfiguration},
+			{KEdgedWindowType(),      CEdgedWin::LoadConfiguration},
+			{KEnormousWindowType(),   CEnormousWin::LoadConfiguration},
+			{KSpritedWindowType(),    CSpritedWin::LoadConfiguration}
+		};
+
+	for (int i=0; i<sizeof(confLoaders)/sizeof(STestStepConfEntry); i++)
+		{
+		section.Copy(confLoaders[i].iType);
+		section.Append(KConfigurationWindowSuffix);
+		context = aConfFactory->GetConfigurationContextLC(section);
+		confLoaders[i].iFunc(context);
+		CleanupStack::PopAndDestroy(context);
+		}
+	
+	CleanupStack::Pop(&section);
+	}
+
+void CComparison::StartL()
+	{
+	iStartTime.UniversalTime();
+	if (iData.randomSeed > -1)
+		{
+		//use seed from ini file
+		iFirstSeed = iData.randomSeed;
+		}
+	else 
+		{
+		// randomize seed by time
+		iFirstSeed = iStartTime.Int64();
+		}
+	TRnd::SetSeed(iFirstSeed);
+	
+	iWasOk = ETrue;
+	iMode = EAct;
+	iErrorNum = 0;
+	iWinGroup=new(ELeave) RWindowGroup(Session());
+	User::LeaveIfError(iWinGroup->Construct( (TUint32)(iWinGroup) ));
+	iWinGroup->SetOrdinalPosition(0,0);
+
+	//make sure at least minNumWindows are created, or if it's zero no limit
+	iNumWindowsLeft = iData.minNumWindows;
+
+	iScreen = new (ELeave) CWsScreenDevice(Session());	
+	User::LeaveIfError(iScreen->Construct(0));
+	TDisplayMode screenMode = iScreen->DisplayMode();
+	
+	iScreenBitmap = new (ELeave) CFbsBitmap;
+	iScreenBitmap->Create(TSize(iData.windowWidth, iData.windowHeight), screenMode);
+	
+	iBackground = new(ELeave) RBlankWindow(Session());
+	iBackground->Construct(*iWinGroup,reinterpret_cast<TUint32>(iBackground));
+	iBackground->SetColor(KRgbBlack);
+	iBackground->SetExtent(TPoint(0,0), TSize(iData.windowWidth, iData.windowHeight));
+	iBackground->SetOrdinalPosition(0);
+	iBackground->Activate();
+
+	iCurrentBmp = 0;
+	iLastBmp = 1;
+	iBmpGc = CFbsBitGc::NewL();
+	for (TInt bmp = 0; bmp < 2; ++bmp)
+		{
+		iBitmap[bmp] = new (ELeave) CFbsBitmap;
+		iBitmap[bmp]->Create(TSize(iData.windowWidth, iData.windowHeight), screenMode); //EColor16MU); //
+		iDevice[bmp] = CFbsBitmapDevice::NewL(iBitmap[bmp]);
+		//clear bitmap background
+		iBmpGc->Activate(iDevice[bmp]);
+		iBmpGc->Reset();
+		iBmpGc->SetPenStyle(CGraphicsContext::ENullPen);
+		iBmpGc->SetBrushColor(KRgbBlack);
+		iBmpGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
+		TPoint origin(0,0);
+		TRect rect(origin, TSize(iData.windowWidth, iData.windowHeight));
+		iBmpGc->DrawRect(rect);
+		}
+
+	iDifferenceBitmap = new (ELeave) CFbsBitmap;
+	iDifferenceBitmap->Create(TSize(iData.windowWidth, iData.windowHeight), screenMode); //EColor16MU); //
+	iDifferenceDevice = CFbsBitmapDevice::NewL(iDifferenceBitmap);
+
+	iTimer = new(ELeave) COperationTimer(this);
+	iTimer->ConstructL();
+	CActiveScheduler::Add (iTimer);
+	iTimer->After(iData.initPeriod);
+	}
+
+/**
+ Simulate a Left key stroke
+ */
+void CComparison::Touch()
+	{
+	User::ResetInactivityTime();
+
+	TRawEvent keyDown;  
+	keyDown.Set(TRawEvent::EKeyDown,EStdKeyLeftArrow);
+	Session().SimulateRawEvent(keyDown);
+	
+	TRawEvent keyUp;
+	keyUp.Set(TRawEvent::EKeyUp,EStdKeyLeftArrow);
+	Session().SimulateRawEvent(keyUp);
+	}
+
+/**
+ Non leaving version of TickL that reports failures
+ */
+TInt CComparison::Tick()
+	{
+	TRAPD(err, TickL());
+	if (err)
+		{
+		REPORT_EVENT( EFalse );
+		}
+	return err;
+	}
+
+/**
+ Called periodically 
+ */
+void CComparison::TickL()
+	{
+	if (iMustConclude)
+		{
+		WriteLog();
+		ConcludeNow();
+		return;
+		}
+	if (0 == iTestNum % 100)
+		{
+		Touch();
+		}
+	DoStuffL();
+	if (iStuffDone)
+		{
+		++iTestNum;
+		}
+	}
+
+/**
+ Dispatch work to selected operation by mode
+ */
+void CComparison::DoStuffL()
+	{
+	iStuffDone = EFalse;
+	switch (iMode)
+		{
+		case EAct:
+			ActL();
+			break;
+		case EMove:
+			MoveL();
+			break;
+		case EResize:
+			ResizeL();
+			break;
+		};
+	if (iWasOk && iData.compareBitmaps && iStuffDone)
+		{
+		Session().Flush();
+		// schedule a delayed compare, will take place after all updates to windows
+		if (iOneShotCompare == NULL)
+			{
+			iOneShotCompare = CComparison::COneShotCompare::NewL(EPriorityMuchLess, *this);
+			}
+		iOneShotCompare->Call();
+		}
+	else
+		{
+		if (iTestNum > iData.maxRunCycles && iNumWindowsLeft == 0)
+			{
+			iMustConclude = ETrue;
+			}
+		iTimer->After(iData.period);
+		}
+	Session().Flush();
+
+	Session().Finish(); 
+	}
+	
+/**
+ Performs a random operation on a random window
+ Operation can be one of create, destroy, move, bring to front/back,
+ resize, tick, toggle-visibility
+ */
+void CComparison::ActL()
+	{
+	TInt action = TRnd::rnd(EACount);
+	if (iWindows.Count() == 0)
+		{
+		action = 0;
+		}
+	
+	iBehaviour.iWin = RandomWindow();
+	iAct = static_cast<TAct>(action);
+	switch(iAct)
+		{
+		case EACreate:
+			CreateWindowL();
+			break;
+		case EADestroy:
+			DestroyWindow();
+			break;
+		case EAMove:
+			MoveWindow();
+			break;
+		case EAFront:
+			BringWindowToFrontL();
+			break;
+		case EABack:
+			SendWindowToBackL();
+			break;
+		case EAResize:
+			ResizeWindow();
+			break;
+		case EATick:
+			TickWindowL();
+			break;
+		case EAToggleVisible:
+			ToggleVisible();
+			break;
+		} //lint !e787 enum constant TAct::EACount not used within switch
+	}
+
+void CComparison::MoveL()
+	{
+	if (iBehaviour.iCount < 1)
+		{
+		iMode = EAct;
+		}
+	else
+		{
+		TPoint pos = iBehaviour.iWin->Pos() + iBehaviour.iPos;
+		iBehaviour.iWin->SetPos(pos);
+		--iBehaviour.iCount;
+		iStuffDone = ETrue;
+		}
+	}
+
+void CComparison::ResizeL()
+	{
+	if (iBehaviour.iCount < 1)
+		{
+		iMode = EAct;
+		}
+	else
+		{
+		TSize size = iBehaviour.iWin->Size();
+		size.iWidth += iBehaviour.iPos.iX;
+		size.iHeight += iBehaviour.iPos.iY;
+		iBehaviour.iWin->SetSize(size);
+		--iBehaviour.iCount;
+		iStuffDone = ETrue;
+		}
+	}
+
+/**
+ Sets the position for a future window-move command, the actual move will be 
+ done in the next step 
+ */
+void CComparison::MoveWindow()
+	{
+	__UHEAP_MARK;
+	if (iBehaviour.iWin)
+		{
+		TPoint pos = TPoint(TRnd::rnd(KPosLimit), TRnd::rnd(KPosLimit));
+		pos.iX -= iBehaviour.iWin->Size().iWidth / 2;
+		pos.iY -= iBehaviour.iWin->Size().iHeight / 2;
+		iBehaviour.iPos = pos - iBehaviour.iWin->Pos();
+		iBehaviour.iCount = KSteps;
+		iBehaviour.iPos.iX /= iBehaviour.iCount;
+		iBehaviour.iPos.iY /= iBehaviour.iCount;
+		iMode = EMove;
+		}
+	__UHEAP_MARKEND;
+	}
+
+/**
+ Sets the size for a future window-resize command, the actual resize will be 
+ done in the next step 
+ */
+void CComparison::ResizeWindow()
+	{
+	__UHEAP_MARK;
+	if (iBehaviour.iWin)
+		{
+		TPoint newsize = TPoint(TRnd::rnd(KPosLimit), TRnd::rnd(KPosLimit));
+		TPoint oldsize;
+		oldsize.iX = iBehaviour.iWin->Size().iWidth;
+		oldsize.iY = iBehaviour.iWin->Size().iHeight;
+		iBehaviour.iPos = newsize - oldsize;
+		iBehaviour.iCount = KSteps;
+		iBehaviour.iPos.iX /= iBehaviour.iCount;
+		iBehaviour.iPos.iY /= iBehaviour.iCount;
+		iMode = EResize;
+		}
+	__UHEAP_MARKEND;
+	}
+
+void CComparison::BringWindowToFrontL()
+	{
+	__UHEAP_MARK;
+	CCompWin* win = iBehaviour.iWin;
+	if (win)
+		{
+		win->BringToFrontL();
+		TInt pos = FindTopWindow(win);
+		if (pos >= 0)
+			{
+			iWindows.Remove(pos);
+			iWindows.Append(win);
+			}
+		iStuffDone = ETrue;
+		}
+	__UHEAP_MARKEND;
+	}
+	
+void CComparison::SendWindowToBackL()
+	{
+	__UHEAP_MARK;
+	TInt ord = iBackground->OrdinalPosition();
+	if (ord > 0)
+		{
+		CCompWin* win = iBehaviour.iWin;
+		if (win)
+			{
+			TInt pos = FindTopWindow(win);
+			if (pos >= 0)
+				{
+				iWindows.Remove(pos);
+				iWindows.Insert(win, 0);
+				win->Window()->SetOrdinalPosition(ord - 1);
+				}
+			else
+				{
+				win->SendToBackL();
+				}
+			iStuffDone = ETrue;
+			}
+		}
+	__UHEAP_MARKEND;
+	}
+
+TInt CComparison::FindTopWindow(CCompWin* win)
+	{
+	return iWindows.Find(win);
+	}
+	
+/**
+ Returns a random window (which may be a NULL window)
+*/
+CCompWin * CComparison::RandomWindow()
+	{
+	if (iWindows.Count() == 0)
+		{
+		return 0;
+		}
+	
+	TInt num = TRnd::rnd(iWindows.Count() + 1);
+	
+	if (num == iWindows.Count())
+		{
+		return 0;
+		}
+	else
+		{
+		return iWindows[num]->RandomWindow();
+		}
+	}
+
+void CComparison::CreateWindowL()
+	{
+	CCompWin* parent = iBehaviour.iWin;
+	CCompWin* win = CCompWin::NewLC(Session(), iWinGroup, parent, WindowGc());
+	iBehaviour.iWin = win;
+	if (!parent)
+		{
+		iWindows.AppendL(win);
+		}
+	CleanupStack::Pop(win);
+	if (iNumWindowsLeft > 0)	//decrement window count
+		{
+		--iNumWindowsLeft;
+		}
+	iStuffDone = ETrue;
+	}	
+
+void CComparison::DestroyWindow()
+	{
+	CCompWin* win = iBehaviour.iWin;
+	if (win)
+		{
+		TInt num = iWindows.Find(win);
+		if (num != KErrNotFound)
+			{
+			iWindows.Remove(num);
+			}
+		delete win;
+		iBehaviour.iWin = 0; // rby added
+		iStuffDone = ETrue;
+		}
+	}	
+
+void CComparison::TickWindowL()
+	{
+	CCompWin* win = iBehaviour.iWin;
+	if (win)
+		{
+		if (win->TickL())
+			{
+			iStuffDone = ETrue;
+			}
+		}
+	}
+	
+void CComparison::ToggleVisible()
+	{
+	__UHEAP_MARK;
+	CCompWin* win = iBehaviour.iWin;
+	if (win)
+		{
+		win->ToggleVisible();
+		iStuffDone = ETrue;
+		}
+	__UHEAP_MARKEND;
+	}
+
+void CComparison::HandleRedraw(TWsRedrawEvent &aEvent)
+	{
+	__UHEAP_MARK;
+	if (aEvent.Handle() != reinterpret_cast<TUint32>(iBackground))
+		{
+		reinterpret_cast<CCompWin*>(aEvent.Handle())->HandleRedraw(aEvent);
+		}
+	Session().Flush();
+	__UHEAP_MARKEND;
+	}
+
+void CComparison::HandleEvent(TWsEvent &/*aEvent*/)
+	{	
+	}
+
+/**
+ Compares two bitmaps. Comparison is done on a pixel-by-pixel basis.
+ If the bitmaps are of different sizes, the smaller axis of each is used for
+ comparison (top-left subregions).
+ First different pixel is stored in internally.
+ @return ETrue if bitmaps match, EFalse otherwise.
+*/
+TBool CComparison::BitmapsMatch(const CFbsBitmap * aBitmap1, const CFbsBitmap * aBitmap2)
+	{
+	TDisplayMode mode1 = aBitmap1->DisplayMode();
+	TDisplayMode mode2 = aBitmap2->DisplayMode();
+	
+	TSize bmpSize = aBitmap1->SizeInPixels();
+	TSize bmpSize2 = aBitmap2->SizeInPixels();
+	if (bmpSize2.iWidth < bmpSize.iWidth)
+		{
+		bmpSize.iWidth = bmpSize2.iWidth;
+		}
+	if (bmpSize2.iHeight < bmpSize.iHeight)
+		{
+		bmpSize.iHeight = bmpSize2.iHeight;
+		}
+	
+	TRgb c1;
+	TRgb c2;
+	for (TInt y=0; y < bmpSize.iHeight; y++)
+		{
+		for (TInt x=0; x < bmpSize.iWidth; x++)
+			{
+			TPoint point(x, y);
+			aBitmap1->GetPixel(c1, point);
+			aBitmap2->GetPixel(c2, point);
+			if (c1 != c2)
+       			{
+       			iPixel1 = c1.Value();
+       			iPixel2 = c2.Value();
+       			iPixelPos = point;
+				return EFalse;
+				}
+			}		
+		}
+	return ETrue;		
+	}
+void CComparison::Verify(CFbsBitmap * aServerBmp)
+	{	
+	//Copy the currentBmp to lastBmp
+	TInt dataStride = iBitmap[iCurrentBmp]->DataStride();
+	TInt sizeInByte = dataStride * iBitmap[iCurrentBmp]->SizeInPixels().iHeight;
+	TUint32* bitmapAddressSource = iBitmap[iCurrentBmp]->DataAddress();
+	TUint32* bitmapAddressTarget = iBitmap[iLastBmp]->DataAddress();
+	memcpy(bitmapAddressTarget, bitmapAddressSource, sizeInByte);
+	// This method is only used by the animation and sprite windows; ignores 
+	// comparisons for times that are too close to the sprite change. But as the 
+	// difference error drifts, there is no point relying on it.
+	if (!WindowsReadyForVerification())
+		{
+		Tick();
+		return;
+		}
+
+	if (iWasOk)
+		{
+		DrawBitmap();
+		
+		const TBool bmpMatch = BitmapsMatch(aServerBmp, iBitmap[iCurrentBmp]);
+		REPORT_EVENT( bmpMatch );
+		
+#ifdef __WINSCW__		
+		if ( !bmpMatch )
+			{
+			__DEBUGGER();
+			}
+#endif
+		
+		if (!iData.saveOnlyDifferent || !bmpMatch)
+			{
+			TBuf<128> fileName;
+			fileName.Append(iData.loggingPath);
+			fileName.Append(_L("Stresslet_Comparison_"));
+			if (iData.saveOnlyDifferent)
+				{
+				fileName.AppendNumFixedWidthUC((TUint)iErrorNum, EDecimal, 3);
+				}
+			else
+				{
+				fileName.AppendNumFixedWidthUC((TUint)iTestNum, EDecimal, 3);
+				}
+			TInt baseLength = fileName.Length();
+			
+			//previous is saved only when saving different bitmaps 
+			//otherwise it is always the same as the previous expected
+			if (iData.saveOnlyDifferent)
+				{
+				fileName.Append(_L("_Previous.mbm"));
+				__ASSERT_ALWAYS(KErrNone == iBitmap[iLastBmp]->Save(fileName), Panic(EPanic6));
+				}
+			
+			fileName.SetLength(baseLength);
+			fileName.Append(_L("_Expected.mbm"));
+			__ASSERT_ALWAYS(KErrNone == iBitmap[iCurrentBmp]->Save(fileName), Panic(EPanic7));
+			
+			fileName.SetLength(baseLength);
+			fileName.Append(_L("_Screen.mbm"));
+			__ASSERT_ALWAYS(KErrNone == aServerBmp->Save(fileName), Panic(EPanic8));
+
+			//store difference between expected and screen bitmaps (XOR image)
+			if (iData.saveDifferenceBitmap)
+				{
+				iBmpGc->Activate(iDifferenceDevice);
+				iBmpGc->Reset();
+				iBmpGc->SetDrawMode(CGraphicsContext::EDrawModePEN);
+				iBmpGc->BitBlt(TPoint(0,0), iBitmap[iCurrentBmp]);
+				iBmpGc->SetDrawMode(CGraphicsContext::EDrawModeXOR);
+				iBmpGc->BitBlt(TPoint(0,0), aServerBmp);
+				iBmpGc->Reset();
+				fileName.SetLength(baseLength);
+				fileName.Append(_L("_Difference.mbm"));
+				__ASSERT_ALWAYS(KErrNone == iDifferenceBitmap->Save(fileName), Panic(EPanic19));
+				}
+			
+			fileName.SetLength(baseLength);
+			fileName.Append(_L("_info.txt"));
+			RFile file;
+			TInt err = file.Create(iFs, fileName, EFileWrite);
+			if (err != KErrNone)
+				err = file.Replace(iFs, fileName, EFileWrite);
+			if (err == KErrNone)
+				{
+				TBuf8<128> info;
+				info.Append(_L8("Seed = "));
+				info.AppendNum(iFirstSeed);
+				info.Append(_L8("\n"));
+				file.Write(info);
+				info.SetLength(0);
+				TTime now;
+				now.UniversalTime();
+				info.Append(_L8(" Runtime = "));
+				info.AppendNum(now.MicroSecondsFrom(iStartTime).Int64() / 1000);
+				info.Append(_L8(" ms\r\n"));
+				file.Write(info);
+				info.SetLength(0);
+				info.Append(_L8("Action = ["));
+				info.AppendNum((TInt64)iAct);
+				info.Append(_L8("]   Mode = ["));
+				info.AppendNum((TInt64)iMode);
+				info.Append(_L8("]   Test = ["));
+				info.AppendNum((TInt64)iTestNum);
+				info.Append(_L8("]\r\n"));
+				file.Write(info);
+				info.SetLength(0);
+				info.Append(_L8("Pixel at ["));
+				info.AppendNum((TInt64)iPixelPos.iX);
+				info.Append(_L8(","));
+				info.AppendNum((TInt64)iPixelPos.iY);
+				info.Append(_L8("] mismatch screen 0x"));
+				info.AppendNum((TInt64)iPixel1, EHex);
+				info.Append(_L8(" != bitmap 0x"));
+				info.AppendNum((TInt64)iPixel2, EHex);
+				info.Append(_L8("\r\n\r\n"));
+				file.Write(info);
+				
+				TPoint zero(0,0);
+				for (TInt num = 0; num < iWindows.Count(); ++num)
+					{
+					iWindows[num]->Dump(file, zero, 0, iBehaviour.iWin);
+					info.SetLength(0);
+					info.Append(_L8("\r\n"));
+					file.Write(info);
+					}				
+				file.Close();
+				}
+			else
+				{
+				//failed create logfile
+				__ASSERT_ALWAYS(EFalse, Panic(EPanic9));
+				}
+			
+			if (!bmpMatch)
+				{
+				++iErrorNum;
+				}
+			}
+		}	
+	if ((iTestNum > iData.maxRunCycles && iNumWindowsLeft == 0) || !iWasOk)
+		{
+		iMustConclude = ETrue;
+		}
+	iTimer->After(iData.period);
+	}
+
+/**
+Write information(eg. seed, starttime, endtime and time elapse) to Stresslet_Log.txt file 
+*/
+void CComparison::WriteLog()
+	{
+	TBuf<128> fileName;
+	fileName.Append(iData.loggingPath);
+	fileName.Append(_L("Stresslet_Log.txt"));
+	RFile file;
+	TInt err = file.Create(iFs, fileName, EFileWrite);
+	if (err != KErrNone)
+		{
+		err = file.Replace(iFs, fileName, EFileWrite);
+		}
+	if (err == KErrNone)
+		{
+		TBuf8<128> info;
+		info.Append(_L8("Seed = "));
+		info.AppendNum(iFirstSeed);
+		info.Append(_L8("\r\n"));
+		file.Write(info);
+		info.SetLength(0);
+		TBuf<40> dateTimeString;
+	    _LIT(KFormat2,"%D%M%Y%/0%1%/1%2%/2%3%/3 %:0%H%:1%T%:2%S.%C%:3");
+	    iStartTime.FormatL(dateTimeString,KFormat2);
+		info.Append(_L8("StartTime = "));
+		info.Append(dateTimeString);
+		info.Append(_L8("\r\n"));
+		TTime now;
+		now.UniversalTime();
+		now.FormatL(dateTimeString,KFormat2);
+		info.Append(_L8("Endtime = "));
+		info.Append(dateTimeString);
+		info.Append(_L8("\r\n"));
+		info.Append(_L8("Elapse = "));
+		info.AppendNum(now.MicroSecondsFrom(iStartTime).Int64() / 1000);
+		info.Append(_L8(" ms\r\n"));
+		file.Write(info);
+		file.Close();
+		}
+	}
+/**
+ Returns true if all visible windows are ready for verification
+ */
+TBool CComparison::WindowsReadyForVerification() const
+	{
+	TBool res = ETrue;
+	TInt idx = 0;
+	while ( idx < iWindows.Count() && res )
+		{
+		if ( iWindows[ idx ]->IsVisible() )
+			{
+			res = iWindows[ idx ]->QueryReadyForVerification();
+			}
+		idx++;
+		}
+	return res;
+	}
+
+/**
+ Calls all windows to draw themselves on a bitmap
+ */
+void CComparison::DrawBitmap()
+	{
+	iBmpGc->Activate(iDevice[iCurrentBmp]);
+	iBmpGc->Reset();
+
+	// clear background area
+	iBmpGc->SetPenStyle(CGraphicsContext::ENullPen);
+	iBmpGc->SetBrushColor(KRgbBlack);
+	iBmpGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
+
+	TPoint origin(0,0);
+	TRect rect(origin, TSize(iData.windowWidth, iData.windowHeight));
+
+	//create a region containing all screen, subtract all visible windows
+	RRegion backClipping(rect);
+	if (!iData.clearAllBackground)
+		{
+		for (TInt num = 0; num < iWindows.Count(); ++num)
+			{
+			if (iWindows[num]->IsVisible())
+				iWindows[num]->SubSelfFromRegion(backClipping, rect, origin);
+			}
+		}
+	
+	//clip drawing to background only & clear
+	iBmpGc->SetClippingRegion(backClipping);
+	iBmpGc->DrawRect(rect);
+	//go back to no clipping
+	iBmpGc->CancelClipping();
+	backClipping.Close();
+
+	for (TInt num = 0; num < iWindows.Count(); ++num)
+		{
+		if (iWindows[num]->IsVisible())
+			{
+			iWindows[num]->ClearBitmapBackground(iBmpGc, rect, origin);
+			iWindows[num]->DrawBitmap(iBmpGc, rect, origin);
+			}
+		}
+	}
+	
+void CComparison::SetVerifyTick(TUint32 aTick)
+	{
+	for (TInt num = 0; num < iWindows.Count(); ++num)
+		{
+		if (iWindows[num]->IsVisible())
+			iWindows[num]->SetVerifyTick(aTick);
+		}
+	}
+
+CComparison::~CComparison()
+	{
+	iFs.Close();
+	
+	if (iBackground)
+		{
+		iBackground->Close();
+		delete iBackground;
+		}	
+	
+	iWindows.ResetAndDestroy();
+	if (iWinGroup)
+		{
+		iWinGroup->Close();
+		delete iWinGroup;
+		}
+
+	delete iOneShotCompare; //delayed compare
+
+	delete iDifferenceDevice;
+	delete iDifferenceBitmap;
+	
+	for (TInt bmp = 0; bmp < 2; ++bmp)
+		{
+		delete iDevice[bmp];
+		delete iBitmap[bmp];
+		}
+	
+	delete iBmpGc;
+	delete iTimer;
+
+	delete iScreenBitmap;
+	delete iScreen;
+	}