fep/frontendprocessor/test/feps/tfep2be.cpp
changeset 0 eb1f2e154e89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fep/frontendprocessor/test/feps/tfep2be.cpp	Tue Feb 02 01:02:04 2010 +0200
@@ -0,0 +1,560 @@
+// Copyright (c) 2005-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
+ @internalComponent
+*/
+
+#include <e32std.h>
+#include <e32base.h>
+#include <e32math.h>
+#include <e32svr.h>
+#include <bitstd.h>
+#include <bitdev.h>
+#include <fbs.h>
+#include <w32adll.h>
+
+#include "tfep2be.h"
+#include "tfep2com.h"
+
+#define DEBUGGING_MESSAGES
+
+// numeric constants
+
+const TInt KPanicClientFromServer=1; // must be greater than zero (CTstHandWritingRecognizer::OfferRawEvent assumes this to be true)
+
+// literal constant text
+
+#if defined(_DEBUG)
+_LIT(KLitTFEP2BE, "TFEP2BE");
+#endif
+
+// local and global functions
+
+#if defined(_DEBUG)
+
+enum TPanic
+	{
+	EPanicUnexpectedError=1,
+	EPanicBadDataInDllTls,
+	EPanicUnexpectedRawEvent,
+	EPanicTimerActive1,
+	EPanicTimerActive2,
+	EPanicNoPendingCharactersToMove,
+	EPanicUnexpectedNullPointer1,
+	EPanicUnexpectedNullPointer2,
+	EPanicBadGranularity,
+	EPanicAlreadyConstructed,
+	EPanicNonAlignedDescriptorLength1,
+	EPanicNonAlignedDescriptorLength2,
+	EPanicNonAlignedDescriptorMaximumLength,
+	EPanicBadDescriptorLength,
+	EPanicBadNumberOfCharacters1,
+	EPanicBadNumberOfCharacters2
+	};
+
+LOCAL_C void Panic(TPanic aPanic)
+	{
+	User::Panic(KLitTFEP2BE, aPanic);
+	}
+
+#endif
+
+LOCAL_C void PanicClientFromServer()
+	{
+	User::Leave(KPanicClientFromServer);
+	}
+
+LOCAL_C void HandleErrorIfErrorL(MAnimGeneralFunctions& aFunctions, TInt aError)
+	{
+	switch (aError)
+		{
+	case KErrNone:
+		break;
+	case KPanicClientFromServer:
+		aFunctions.Panic();
+		break;
+	default:
+		User::Leave(aError);
+		break;
+		}
+	}
+
+LOCAL_C void HandleErrorIfError(MAnimGeneralFunctions& aFunctions, TInt aError)
+	{
+	switch (aError)
+		{
+	case KErrNone:
+		break;
+	case KPanicClientFromServer:
+		aFunctions.Panic();
+		break;
+	default:
+#if defined(_DEBUG)
+		Panic(EPanicUnexpectedError);
+#endif
+		break;
+		}
+	}
+
+GLDEF_C TInt E32Dll(
+					)
+	{
+	return KErrNone;
+	}
+
+// CTstHandWritingRecognizer
+
+CTstHandWritingRecognizer::CTstHandWritingRecognizer()
+	:iFlags(0),
+	 iArrayOfPolyLines(12),
+	 iArrayOfCharactersPending(10),
+	 iTimeOutTimer(NULL),
+	 iMessage_RequestForNotificationOfStartOfTransaction(),
+	 iMessage_RequestForCharacters(),
+	 iMaximumLengthOfClientSideCharacterBuffer(0),
+	 iMainBitmap(NULL),
+	 iMaskBitmap(NULL),
+	 iGraphicsContext(NULL)
+	{
+	}
+
+CTstHandWritingRecognizer::~CTstHandWritingRecognizer()
+	{
+	iFunctions->GetRawEvents(EFalse);
+	iSpriteFunctions->Activate(EFalse);
+	if (iFlags&EFlagReferenceCountIncremented)
+		{
+		SBitmapHandlesWithReferenceCount* const bitmapHandlesWithReferenceCount=STATIC_CAST(SBitmapHandlesWithReferenceCount*, Dll::Tls());
+		__ASSERT_DEBUG((bitmapHandlesWithReferenceCount!=NULL) && (bitmapHandlesWithReferenceCount->iReferenceCount>0), Panic(EPanicBadDataInDllTls));
+		--bitmapHandlesWithReferenceCount->iReferenceCount;
+		if (bitmapHandlesWithReferenceCount->iReferenceCount==0)
+			{
+			delete bitmapHandlesWithReferenceCount;
+			Dll::SetTls(NULL);
+			}
+		}
+	iArrayOfPolyLines.ResetAndDestroy();
+	iArrayOfPolyLines.Close();
+	iArrayOfCharactersPending.Close();
+	delete iTimeOutTimer;
+	delete iGraphicsContext;
+	delete iMainBitmap;
+	delete iMaskBitmap;
+	}
+
+void CTstHandWritingRecognizer::HandleTimeOut()
+	{
+	TRAPD(error, DoRecognitionL());
+	CompleteRequestForCharacters(error);
+	}
+
+void CTstHandWritingRecognizer::ConstructLP(TAny* /*aParameters*/)
+	{
+	// this functions does not actually construct anything, but simply writes the bitmap handles stored in Dll::Tls() (if any) to the client's descriptor
+	STstBitmapHandles bitmapHandles(0, 0);
+	const SBitmapHandlesWithReferenceCount* const bitmapHandlesWithReferenceCount=REINTERPRET_CAST(const SBitmapHandlesWithReferenceCount*, Dll::Tls());
+	if (bitmapHandlesWithReferenceCount!=NULL)
+		{
+		bitmapHandles=bitmapHandlesWithReferenceCount->iBitmapHandles;
+		}
+	iFunctions->Message()->WriteL(EIpcSlot, TPckgC<STstBitmapHandles>(bitmapHandles));
+	}
+
+TInt CTstHandWritingRecognizer::CommandReplyLP(TInt aOpcode, TAny* aParameters)
+	{
+	switch (aOpcode)
+		{
+	case EHandWritingRecognizerCommandFinishConstructionL:
+		{
+		__ASSERT_ALWAYS(iFlags==0, PanicClientFromServer());
+		iFunctions->SetSync(MAnimGeneralFunctions::ESyncNone);
+		iSpriteFunctions->SizeChangedL();
+		iArrayOfCharactersPending.ConstructL();
+		iTimeOutTimer=CTimeOutTimer::NewL(*this);
+		const TSpriteMember* const spriteMember=iSpriteFunctions->GetSpriteMember(0);
+		__ASSERT_ALWAYS((spriteMember!=NULL) && (spriteMember->iBitmap!=NULL) && (spriteMember->iMaskBitmap!=NULL), PanicClientFromServer());
+		const STstBitmapHandles bitmapHandles(spriteMember->iBitmap->Handle(), spriteMember->iMaskBitmap->Handle());
+		SBitmapHandlesWithReferenceCount* bitmapHandlesWithReferenceCount=STATIC_CAST(SBitmapHandlesWithReferenceCount*, Dll::Tls());
+		if (bitmapHandlesWithReferenceCount!=NULL)
+			{
+			__ASSERT_ALWAYS((bitmapHandlesWithReferenceCount->iBitmapHandles.iMain==bitmapHandles.iMain) && (bitmapHandlesWithReferenceCount->iBitmapHandles.iMask==bitmapHandles.iMask), PanicClientFromServer());
+			++bitmapHandlesWithReferenceCount->iReferenceCount;
+			}
+		else
+			{
+			bitmapHandlesWithReferenceCount=new(ELeave) SBitmapHandlesWithReferenceCount;
+			CleanupStack::PushL(bitmapHandlesWithReferenceCount);
+			bitmapHandlesWithReferenceCount->iBitmapHandles=bitmapHandles;
+			bitmapHandlesWithReferenceCount->iReferenceCount=1;
+			User::LeaveIfError(Dll::SetTls(bitmapHandlesWithReferenceCount));
+			CleanupStack::Pop(); // bitmapHandlesWithReferenceCount
+			}
+		iFlags|=EFlagReferenceCountIncremented;
+#if defined(DEBUGGING_MESSAGES)
+		RDebug::Print(_L("reference-count of the bitmap handles: %d"), bitmapHandlesWithReferenceCount->iReferenceCount);
+#endif
+		iMainBitmap=CFbsBitmapDevice::NewL(spriteMember->iBitmap);
+		iMaskBitmap=CFbsBitmapDevice::NewL(spriteMember->iMaskBitmap);
+		iGraphicsContext=CFbsBitGc::NewL();
+		iGraphicsContext->SetBrushStyle(CGraphicsContext::ESolidBrush);
+		iGraphicsContext->SetBrushColor(KRgbWhite);
+		iGraphicsContext->SetPenStyle(CGraphicsContext::ESolidPen);
+		iGraphicsContext->SetPenColor(KRgbBlack);
+		}
+		break;
+	case EHandWritingRecognizerCommandRequestNotificationOfStartOfTransaction:
+		__ASSERT_ALWAYS(iMessage_RequestForNotificationOfStartOfTransaction.IsNull(), PanicClientFromServer());
+		iMessage_RequestForNotificationOfStartOfTransaction=*iFunctions->Message();
+		__ASSERT_ALWAYS(!iMessage_RequestForNotificationOfStartOfTransaction.IsNull(), PanicClientFromServer());
+		break;
+	case EHandWritingRecognizerCommandCancelRequestForNotificationOfStartOfTransaction:
+		if (!iMessage_RequestForNotificationOfStartOfTransaction.IsNull())
+			{
+			iMessage_RequestForNotificationOfStartOfTransaction.Complete(KErrCancel);
+			}
+		break;
+	case EHandWritingRecognizerCommandRequestCharacters:
+		__ASSERT_ALWAYS(iMessage_RequestForCharacters.IsNull() && (iMaximumLengthOfClientSideCharacterBuffer==0), PanicClientFromServer());
+		iMessage_RequestForCharacters=*iFunctions->Message();
+		iMaximumLengthOfClientSideCharacterBuffer=iFunctions->Message()->GetDesMaxLength(EAsyncIpcSlot);
+		__ASSERT_ALWAYS((!iMessage_RequestForCharacters.IsNull()) && (iMaximumLengthOfClientSideCharacterBuffer>=STATIC_CAST(TInt, sizeof(TUint))), PanicClientFromServer());
+		if (iArrayOfCharactersPending.Count()>0)
+			{
+			TRAPD(error, MovePendingCharactersToClientBufferL());
+			CompleteRequestForCharacters(error);
+			}
+		else
+			{
+			iFunctions->GetRawEvents(ETrue);
+			iSpriteFunctions->Activate(ETrue);
+			}
+		break;
+	case EHandWritingRecognizerCommandCancelRequestForCharacters:
+		if (!iMessage_RequestForCharacters.IsNull())
+			{
+			CompleteRequestForCharacters(KErrCancel);
+			}
+		break;
+	case EHandWritingRecognizerCommandSetUpperCase:
+		{
+		STstParametersForHandWritingRecognizerCommandSetUpperCase* const parameters=REINTERPRET_CAST(STstParametersForHandWritingRecognizerCommandSetUpperCase*, aParameters);
+		if (parameters->iUpperCase)
+			{
+			iFlags|=EFlagUpperCase;
+			}
+		else
+			{
+			iFlags&=~EFlagUpperCase;
+			}
+		}
+		break;
+	default:
+		PanicClientFromServer();
+		break;
+		}
+	return KErrNone; // dummy return to prevent compiler error
+	}
+
+TBool CTstHandWritingRecognizer::OfferRawEventLP(const TRawEvent& aRawEvent)
+	{
+	__ASSERT_DEBUG(!iMessage_RequestForCharacters.IsNull(), Panic(EPanicUnexpectedRawEvent));
+	switch (aRawEvent.Type())
+		{
+	case TRawEvent::EPointerMove:
+		{
+		if (iFlags&EFlagPointerIsDown) // this test is needed in the cases where (i) the TRawEvent::EPointerMove event occurs when the pointer is not "down" (this is possible for some pointing devices, e.g. a mouse), and (ii) there was a "leave" when handling the TRawEvent::EButton1Down event
+			{
+			__ASSERT_DEBUG(!iTimeOutTimer->IsActive(), Panic(EPanicTimerActive1));
+			const TPoint thisPoint=aRawEvent.Pos();
+			CArrayFix<TPoint>& polyLine=*iArrayOfPolyLines[iArrayOfPolyLines.Count()-1];
+			polyLine.AppendL(thisPoint);
+			const TPoint previousPoint=polyLine[polyLine.Count()-2];
+			TRect rectangleDrawnTo;
+			DrawLine(*iMainBitmap, rectangleDrawnTo, EPenWidthForMainBitmap, previousPoint, thisPoint);
+			TRect temp;
+			DrawLine(*iMaskBitmap, temp, EPenWidthForMaskBitmap, previousPoint, thisPoint);
+			rectangleDrawnTo.BoundingRect(temp);
+			Plot(*iMainBitmap, temp, EPenWidthForMainBitmap, thisPoint);
+			rectangleDrawnTo.BoundingRect(temp);
+			Plot(*iMaskBitmap, temp, EPenWidthForMaskBitmap, thisPoint);
+			rectangleDrawnTo.BoundingRect(temp);
+			iSpriteFunctions->UpdateMember(0, rectangleDrawnTo, EFalse);
+			}
+		}
+		return ETrue;
+	case TRawEvent::EButton1Down:
+		{
+		iTimeOutTimer->Cancel();
+		const TPoint thisPoint=aRawEvent.Pos();
+		CArrayFix<TPoint>* const polyLine=new(ELeave) CArrayFixSeg<TPoint>(50);
+		CleanupStack::PushL(polyLine);
+		polyLine->AppendL(thisPoint);
+		User::LeaveIfError(iArrayOfPolyLines.Append(polyLine));
+		CleanupStack::Pop(); // polyLine
+		TRect rectangleDrawnTo;
+		Plot(*iMainBitmap, rectangleDrawnTo, EPenWidthForMainBitmap, thisPoint);
+		TRect temp;
+		Plot(*iMaskBitmap, temp, EPenWidthForMaskBitmap, thisPoint);
+		rectangleDrawnTo.BoundingRect(temp);
+		iSpriteFunctions->UpdateMember(0, rectangleDrawnTo, EFalse);
+		iFlags|=EFlagPointerIsDown;
+		if ((iArrayOfPolyLines.Count()==1) && (!iMessage_RequestForNotificationOfStartOfTransaction.IsNull()))
+			{
+			iMessage_RequestForNotificationOfStartOfTransaction.Complete(KErrNone);
+			}
+		}
+		return ETrue;
+	case TRawEvent::EButton1Up:
+		if (iFlags&EFlagPointerIsDown) // this test is needed in the case where there was a "leave" when handling the TRawEvent::EButton1Down event
+			{
+			__ASSERT_DEBUG(!iTimeOutTimer->IsActive(), Panic(EPanicTimerActive2));
+			iTimeOutTimer->After(ETimeOutInMicroSeconds);
+			iFlags&=~EFlagPointerIsDown;
+			}
+		return ETrue;
+	default:
+		return EFalse;
+		}
+	}
+
+void CTstHandWritingRecognizer::DoRecognitionL()
+	{
+	TInt i;
+	TInt minimumX=KMaxTInt;
+	TInt maximumX=KMinTInt;
+	for (i=iArrayOfPolyLines.Count()-1; i>=0; --i)
+		{
+		const CArrayFix<TPoint>& polyLine=*iArrayOfPolyLines[i];
+		for (TInt j=polyLine.Count()-1; j>=0; --j)
+			{
+			const TInt x=polyLine[j].iX;
+			if (minimumX>x)
+				{
+				minimumX=x;
+				}
+			if (maximumX<x)
+				{
+				maximumX=x;
+				}
+			}
+		}
+	const TInt numberOfCharacters=((maximumX-minimumX)/80)+1;
+	TTime homeTime;
+	homeTime.HomeTime();
+	TInt64 seedForRandomNumber=homeTime.Int64();
+	const TUint baseCharacter=(iFlags&EFlagUpperCase)? 'A': 'a';
+	for (i=0; i<numberOfCharacters; ++i)
+		{
+		iArrayOfCharactersPending.AppendL(baseCharacter+(Math::Rand(seedForRandomNumber)%26));
+		}
+	MovePendingCharactersToClientBufferL();
+	}
+
+void CTstHandWritingRecognizer::MovePendingCharactersToClientBufferL()
+	{
+	__ASSERT_DEBUG(iArrayOfCharactersPending.Count()>0, Panic(EPanicNoPendingCharactersToMove));
+	__ASSERT_DEBUG((!iMessage_RequestForCharacters.IsNull()) && (iMaximumLengthOfClientSideCharacterBuffer>=STATIC_CAST(TInt, sizeof(TUint))), Panic(EPanicUnexpectedNullPointer1));
+	const TInt numberOfCharactersToMove=Min(iArrayOfCharactersPending.Count(), iMaximumLengthOfClientSideCharacterBuffer/sizeof(TUint));
+	iMessage_RequestForCharacters.WriteL(EAsyncIpcSlot, iArrayOfCharactersPending.DescriptorFromStart(numberOfCharactersToMove), 0);
+	iArrayOfCharactersPending.RemoveFromStart(numberOfCharactersToMove);
+	}
+
+void CTstHandWritingRecognizer::CompleteRequestForCharacters(TInt aErrorCode)
+	{
+	__ASSERT_DEBUG((!iMessage_RequestForCharacters.IsNull()) && (iMaximumLengthOfClientSideCharacterBuffer>=STATIC_CAST(TInt, sizeof(TUint))), Panic(EPanicUnexpectedNullPointer2));
+	iArrayOfPolyLines.ResetAndDestroy();
+	iArrayOfCharactersPending.Reset();
+	iTimeOutTimer->Cancel();
+	iMessage_RequestForCharacters.Complete(aErrorCode);
+	iMaximumLengthOfClientSideCharacterBuffer=NULL;
+	iFunctions->GetRawEvents(EFalse);
+	iSpriteFunctions->Activate(EFalse);
+	ClearBitmap(*iMainBitmap);
+	ClearBitmap(*iMaskBitmap);
+	// there is no need to call iSpriteFunctions->UpdateMember as the sprite has just been de-activated (3 lines above)
+	}
+
+void CTstHandWritingRecognizer::ClearBitmap(CFbsBitmapDevice& aBitmap)
+	{
+	iGraphicsContext->Activate(&aBitmap);
+	iGraphicsContext->Clear();
+	}
+
+void CTstHandWritingRecognizer::DrawLine(CFbsBitmapDevice& aBitmap, TRect& aRectangleDrawnTo, TInt aPenSize, const TPoint& aPoint1, const TPoint& aPoint2)
+	{
+	iGraphicsContext->Activate(&aBitmap);
+	iGraphicsContext->SetPenSize(TSize(aPenSize, aPenSize));
+	iGraphicsContext->DrawLine(aPoint1, aPoint2);
+	iGraphicsContext->RectDrawnTo(aRectangleDrawnTo);
+	}
+
+void CTstHandWritingRecognizer::Plot(CFbsBitmapDevice& aBitmap, TRect& aRectangleDrawnTo, TInt aPenSize, const TPoint& aPoint)
+	{
+	iGraphicsContext->Activate(&aBitmap);
+	iGraphicsContext->SetPenSize(TSize(aPenSize, aPenSize));
+	iGraphicsContext->Plot(aPoint);
+	iGraphicsContext->RectDrawnTo(aRectangleDrawnTo);
+	}
+
+void CTstHandWritingRecognizer::ConstructL(TAny* aParameters)
+	{
+	TRAPD(error, ConstructLP(aParameters));
+	HandleErrorIfErrorL(*iFunctions, error);
+	}
+
+TInt CTstHandWritingRecognizer::CommandReplyL(TInt aOpcode, TAny* aParameters)
+	{
+	TInt returnVal=0; // dummy initialization to prevent compiler warning
+	TRAPD(error, returnVal=CommandReplyLP(aOpcode, aParameters));
+	HandleErrorIfErrorL(*iFunctions, error);
+	return returnVal;
+	}
+
+void CTstHandWritingRecognizer::Command(TInt, TAny*)
+	{
+	iFunctions->Panic();
+	}
+
+void CTstHandWritingRecognizer::Animate(TDateTime*)
+	{
+	}
+
+TBool CTstHandWritingRecognizer::OfferRawEvent(const TRawEvent& aRawEvent)
+	{
+	TBool returnVal=0; // dummy initialization to prevent compiler warning
+	TRAPD(error, returnVal=OfferRawEventLP(aRawEvent));
+	if (error>=0) // if error is a KErrXxxxx, ignore it (as OfferRawEvent cannot leave)
+		{
+		HandleErrorIfError(*iFunctions, error);
+		}
+	return returnVal;
+	}
+
+// CTstHandWritingRecognizer::RFlatArrayOfCharacters
+
+CTstHandWritingRecognizer::RFlatArrayOfCharacters::RFlatArrayOfCharacters(TInt aGranularity)
+	:iGranularity(aGranularity),
+	 iDescriptor(NULL)
+	{
+	__ASSERT_DEBUG(aGranularity>0, Panic(EPanicBadGranularity));
+	}
+
+void CTstHandWritingRecognizer::RFlatArrayOfCharacters::ConstructL()
+	{
+	__ASSERT_DEBUG(iDescriptor==NULL, Panic(EPanicAlreadyConstructed));
+	iDescriptor=HBufC8::NewL(iGranularity*sizeof(TUint));
+	}
+
+void CTstHandWritingRecognizer::RFlatArrayOfCharacters::Close()
+	{
+	delete iDescriptor;
+	iDescriptor=NULL;
+	}
+
+void CTstHandWritingRecognizer::RFlatArrayOfCharacters::AppendL(TUint aCharacter)
+	{
+	const TInt oldDescriptorLength=iDescriptor->Length();
+	__ASSERT_DEBUG(oldDescriptorLength%sizeof(TUint)==0, Panic(EPanicNonAlignedDescriptorLength1));
+	const TInt oldDescriptorMaximumLength=iDescriptor->Des().MaxLength();
+	__ASSERT_DEBUG(oldDescriptorMaximumLength%sizeof(TUint)==0, Panic(EPanicNonAlignedDescriptorMaximumLength));
+	if (oldDescriptorLength>=oldDescriptorMaximumLength)
+		{
+		iDescriptor=iDescriptor->ReAllocL(oldDescriptorLength+(iGranularity*sizeof(TUint)));
+		}
+	TPtr8 descriptor(iDescriptor->Des());
+	__ASSERT_DEBUG(oldDescriptorLength==descriptor.Length(), Panic(EPanicBadDescriptorLength));
+	descriptor.SetLength(oldDescriptorLength+sizeof(TUint));
+	*REINTERPRET_CAST(TUint*, CONST_CAST(TUint8*, descriptor.Ptr()+oldDescriptorLength))=aCharacter;
+	}
+
+TInt CTstHandWritingRecognizer::RFlatArrayOfCharacters::Count() const
+	{
+	const TInt descriptorLength=iDescriptor->Length();
+	__ASSERT_DEBUG(descriptorLength%sizeof(TUint)==0, Panic(EPanicNonAlignedDescriptorLength2));
+	return descriptorLength/sizeof(TUint);
+	}
+
+TPtrC8 CTstHandWritingRecognizer::RFlatArrayOfCharacters::DescriptorFromStart(TInt aNumberOfCharacters) const
+	{
+	__ASSERT_DEBUG((aNumberOfCharacters>0) && (aNumberOfCharacters<=Count()), Panic(EPanicBadNumberOfCharacters1));
+	return iDescriptor->Left(aNumberOfCharacters*sizeof(TUint));
+	}
+
+void CTstHandWritingRecognizer::RFlatArrayOfCharacters::RemoveFromStart(TInt aNumberOfCharacters)
+	{
+	__ASSERT_DEBUG((aNumberOfCharacters>0) && (aNumberOfCharacters<=Count()), Panic(EPanicBadNumberOfCharacters2));
+	TPtr8 descriptor(iDescriptor->Des());
+	descriptor.Delete(0, aNumberOfCharacters*sizeof(TUint));
+	// we could "iDescriptor=iDescriptor->ReAllocL" here to free up unused memory, but it's probably not worth it as iDescriptor will never grow very large
+	}
+
+void CTstHandWritingRecognizer::RFlatArrayOfCharacters::Reset()
+	{
+	TPtr8 descriptor(iDescriptor->Des());
+	descriptor.SetLength(0);
+	// we could "iDescriptor=iDescriptor->ReAllocL" here to free up unused memory, but it's probably not worth it as iDescriptor will never grow very large
+	}
+
+// CTstHandWritingRecognizer::CTimeOutTimer
+
+CTstHandWritingRecognizer::CTimeOutTimer* CTstHandWritingRecognizer::CTimeOutTimer::NewL(CTstHandWritingRecognizer& aHandWritingRecognizer)
+	{
+	CTimeOutTimer* const timeOutTimer=new(ELeave) CTimeOutTimer(aHandWritingRecognizer);
+	CleanupStack::PushL(timeOutTimer);
+	CActiveScheduler::Add(timeOutTimer);
+	timeOutTimer->ConstructL();
+	CleanupStack::Pop(); // timeOutTimer
+	return timeOutTimer;
+	}
+
+CTstHandWritingRecognizer::CTimeOutTimer::~CTimeOutTimer()
+	{
+	Cancel();
+	}
+
+CTstHandWritingRecognizer::CTimeOutTimer::CTimeOutTimer(CTstHandWritingRecognizer& aHandWritingRecognizer)
+	:CTimer(EPriorityLow),
+	 iHandWritingRecognizer(aHandWritingRecognizer)
+	{
+	}
+
+void CTstHandWritingRecognizer::CTimeOutTimer::RunL()
+	{
+	iHandWritingRecognizer.HandleTimeOut();
+	}
+
+// CTstDll
+
+CAnim* CTstDll::CreateInstanceL(TInt aType)
+	{
+	switch (aType)
+		{
+	case EAnimTypeHandWritingRecognizer:
+		return new(ELeave) CTstHandWritingRecognizer;
+	default:
+		User::Leave(KErrArgument);
+		return NULL; // dummy return to prevent compiler error
+		}
+	}
+
+// the exported function
+
+EXPORT_C CAnimDll* CreateCAnimDllL()
+	{
+	return new(ELeave) CTstDll;
+	}
+