textrendering/textformatting/test/src/TCustomCharMapping.cpp
changeset 0 1fb32624e06b
child 51 a7c938434754
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/textformatting/test/src/TCustomCharMapping.cpp	Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,529 @@
+/*
+* 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: 
+*
+*/
+
+
+#include "TGraphicsContext.h"
+#include <e32std.h>
+#include <e32test.h>
+#include <frmtlay.h>
+#include <frmtview.h>
+#include <frmconst.h>
+#include <txtlaydc.h>
+#include <txtetext.h>
+#include <w32std.h>
+
+namespace LocalToFile
+{
+
+_LIT(KTCustomCharMapping, "TCustomCharMapping");
+const TInt KDisplayWidth = 202;
+const TInt KDisplayHeight = 100;
+const TInt KPictureCharacter = 0xFFFC;
+RTest test(KTCustomCharMapping);
+
+enum TTestNum
+	{
+	EDefaultBehaviourInvisible = 0,
+	EDefaultBehaviourVisible = 1,
+	ECustomRemappingInvisible = 2,
+	ECustomRemappingVisible = 3,
+	ENewTest = 4  //Test remapping with no custom remapper and some flags explicitly set to invisible
+	};
+
+
+class CPinkSquare : public CPicture
+	{
+public:
+	// Size of square in twips.
+	// 600 is 15 pixels using the standard test graphics device at
+	// its default resolution.
+	enum { KWidth = 600, KHeight = 600 };
+	CPinkSquare()
+		{}
+	void Draw(CGraphicsContext& aGc, const TPoint& aTopLeft, const TRect& aClipRect, MGraphicsDeviceMap* aMap) const
+		{
+		// This picture is a magenta square
+		TPoint size(KWidth, KHeight);
+		if (aMap)
+			size = aMap->TwipsToPixels(size);
+		TRect rect(aTopLeft, aTopLeft + size);
+		aGc.SetClippingRect(aClipRect);
+		aGc.SetDrawMode(CGraphicsContext::EDrawModePEN);
+		aGc.SetPenColor(KRgbMagenta);
+		aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
+		aGc.SetBrushColor(KRgbMagenta);
+		aGc.DrawRect(rect);
+		}
+	void ExternalizeL(RWriteStream&) const
+		{}
+	void GetOriginalSizeInTwips(TSize& a) const
+		{
+		a.iWidth = CPinkSquare::KWidth;
+		a.iHeight = CPinkSquare::KHeight;
+		}
+	};
+
+_LIT(KEnd, "\x2029");
+class TDocModel : public MLayDoc
+	{
+public:
+	TDocModel(const TDesC& aDes)
+	 :	iDes(&aDes), iParagraphFormat(0)
+		{}
+	void SetParagraphFormat(CParaFormat* a)
+		{
+		iParagraphFormat = a;
+		}
+	// From MLayDoc
+	TInt LdDocumentLength() const
+		{ return iDes->Length(); }
+	TInt LdToParagraphStart(TInt& a) const
+		{
+		TInt curr = a;
+		if (a < LdDocumentLength())
+			{
+			a = iDes->Left(a).LocateReverse(0x2029);
+			a = a < 0? 0 : a + 1;
+			}
+		return curr - a;
+		}
+	void GetParagraphFormatL(CParaFormat* aFormat, TInt) const
+		{
+		if (iParagraphFormat)
+			{
+			aFormat->CopyL(*iParagraphFormat);
+			return;
+			}
+		aFormat->Reset();
+		TTabStop tabStop;
+		tabStop.iTwipsPosition = 1000;
+		tabStop.iType = TTabStop::ELeftTab;
+		aFormat->StoreTabL(tabStop);
+		}
+	void GetChars(TPtrC& aView,TCharFormat& aFormat, TInt aStartPos)const
+		{
+		TCharFormat cf;
+		aFormat = cf;
+		if (aStartPos == LdDocumentLength())
+			aView.Set(KEnd);
+		else
+			aView.Set(iDes->Mid(aStartPos));
+		}
+	TInt GetPictureSizeInTwips(TSize& aSize, TInt aPos) const
+		{
+		if ((*iDes)[aPos] != KPictureCharacter)
+			return KErrNotFound;
+		aSize.iWidth = CPinkSquare::KWidth;
+		aSize.iHeight = CPinkSquare::KHeight;
+		return KErrNone;
+		}
+	CPicture* PictureHandleL(TInt aPos, TForcePictureLoad) const
+		{
+		if ((*iDes)[aPos] != KPictureCharacter)
+			return 0;
+		return new(ELeave) CPinkSquare;
+		}
+	TBool EnquirePageBreak(TInt aPos, TInt aLength)const
+		{
+		return iDes->Mid(aPos, aLength).Locate(0x000C) < 0?
+			EFalse : ETrue;
+		}
+	TBool SelectParagraphLabel(TInt)
+		{ return EFalse; }
+	void CancelSelectLabel()
+		{}
+private:
+	const TDesC* iDes;
+	CParaFormat* iParagraphFormat;
+	};
+}
+using namespace LocalToFile;
+
+class CTestTextView	// slightly naughty
+	{
+public:
+	static void SetContextForFlickerFreeRedraw(CTextView* aView, CBitmapContext* aContext)
+		{
+		aView->iOffScreenContext = aContext;
+		}
+	};
+
+
+static const TInt KTestCases = 5;
+static const TInt KVariants = 2;
+
+// For tests 0 to 3 the source string consists of:
+// 'Y' <hard space> 'Z' <normal space> <non-breaking hyphen> <zero width space>
+static const TPtrC KTestStrings[KTestCases][KVariants] =
+	{
+		{	// Test remapping with no custom remapper and flags set to invisible
+			// The non-breaking hyphen is turned into a normal hyphen
+			// The zero width space disappears (0xFFFF) and the hard space becomes a normal space
+			// All done by MTmCustom::Map()
+		_S("\x0059\x00A0\x005A\x0020\x2011\x200B"),
+		_S("\xFFFF\x0059\x0020\x005A\x0020\x002D\xFFFF\xFFFF"),
+		},
+		{	// Test remapping with no custom remapper and flags set to visible
+			// The non-breaking hyphen becomes a tilde
+			// The normal space and the zero width space become visible middle dots
+			// The hard (non-breaking) space becomes a degree sign
+			// The paragraph sign becomes a pilcrow
+			// All done by MTmCustom::Map()
+		_S("\x0059\x00A0\x005A\x0020\x2011\x200B"),
+		_S("\xFFFF\x0059\x00B0\x005A\x00B7\x007E\x00B7\x00B6\xFFFF"),
+		},
+		{	// Test remapping with custom remapper and flags set to invisible
+			// The non-breaking hyphen is turned into a normal hyphen
+			// The zero width space disappears (0xFFFF) and the hard space becomes a normal space
+			// All done by MTmCustom::Map()
+			// The hard (non-breaking) space becomes a caret
+			// This is done by the custom remapper
+		_S("\x0059\x00A0\x005A\x0020\x2011\x200B"),
+		_S("\xFFFF\x0059\x005E\x005A\x0020\x002D\xFFFF\xFFFF"),
+		},
+		{	// Test remapping with custom remapper and flags set to visible
+			// The non-breaking hyphen becomes a tilde
+			// The zero width space become visible middle dots
+			// All done by MTmCustom::Map()
+			// The normal space remains a normal (invisible) space because default behaviour is overidden
+			// The hard (non-breaking) space becomes a caret
+			// The paragraph sign becomes a capital P
+			// All done by the custom remapper
+		_S("\x0059\x00A0\x005A\x0020\x2011\x200B"),
+		_S("\xFFFF\x0059\x005E\x005A\x0020\x007E\x00B7\x0050\xFFFF"),
+		},
+		{
+			// Test remapping with no custom remapper and some flags explicitly set to invisible
+			// The non-breaking hyphen is turned into a normal hyphen
+			// The zero width space disappears (0xFFFF) and the hard space becomes a normal space
+			// All done by MTmCustom::Map()
+		_S("\x0059\x00A0\x005A\x0020\x2011\x200B"),
+		_S("\xFFFF\x0059\x0020\x005A\x0020\x002D\xFFFF\xFFFF"),
+		}
+	};
+
+
+class CCustomRemapper : public MFormCustomInvisibleCharacterRemapper
+	{
+public:
+	static CCustomRemapper* NewL();
+	~CCustomRemapper();
+	TUint Remap(TUint aChar, const TNonPrintingCharVisibility aNonPrintingCharVisibility, const TLayDocTextSource& aLayDoc);
+private:
+	CCustomRemapper();
+	};
+
+	CCustomRemapper* CCustomRemapper::NewL()
+		{
+		CCustomRemapper* me = new(ELeave) CCustomRemapper;
+		return me;
+		}
+
+	CCustomRemapper::~CCustomRemapper()
+		{
+		}
+
+	TUint CCustomRemapper::Remap(TUint aChar, const TNonPrintingCharVisibility aNonPrintingCharVisibility, const TLayDocTextSource& aLayDoc)
+		{
+		switch (aChar)
+			{
+			case CEditableText::EParagraphDelimiter:
+				if (aNonPrintingCharVisibility.ParagraphDelimitersVisible())
+					return 0x0050; // capital P - override when visible
+				break;
+
+			case CEditableText::ESpace:
+				return aChar; // don't remap but don't pass it on - override default
+				// break statement was removed.
+
+			case CEditableText::ENonBreakingSpace:
+				return 0x005E; // Caret - override always - visible or not
+				// break statement was removed.
+			default:
+				break; // do nothing
+			}
+
+		// If not mapping special characters, or not mapping this particular character, use the default mapping.
+		return DefaultMapping(aChar, aNonPrintingCharVisibility, aLayDoc);
+		}
+
+	CCustomRemapper::CCustomRemapper()
+		{
+		}
+
+void DoTestL(TDes& aText, CTextLayout* /*aLayout*/, CTestGraphicsDevice* aDevice, CTextView* aView, TTestNum aTestNum)
+	{
+	aText = KTestStrings[aTestNum][0];
+	aDevice->LineArray().ResetLineArray();
+	aView->HandleGlobalChangeL();
+	const TTestGCDisplayLine* line1 = &(aDevice->LineArray().Line(0));
+	const TTestGCDisplayLine* line2 = aDevice->LineArray().Find(KTestStrings[aTestNum][1]);
+	test(0 != line1);
+	test(0 != line2);
+	// Can't always do a direct comparison of lines because same string
+	// may appear in more than one line, so compare contents
+	test(line1->iLineData.Compare(line2->iLineData) == 0);
+	}
+
+
+/**
+@SYMTestCaseID SYSLIB-FORM-CT-0147
+@SYMTestCaseDesc Test installation and deinstallation of custom remapper
+@SYMTestPriority High
+@SYMTestActions  Test installation and deinstallation of custom remapper
+@SYMTestExpectedResults The test must not fail.
+@SYMPREQ 1128 Placeholders for invisible characers in rich text shall be customizable
+*/
+void RunInstallationTestsL()
+	{
+	// Note: If you need to move these heap checks any further "in" to focus
+	// on a specific test then you will have to move all the setup code in as
+	// well - and still preserve the two different display widths in use
+	test.Next(_L(" @SYMTestCaseID:SYSLIB-FORM-CT-0147 "));
+	__UHEAP_MARK;
+	CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
+	CleanupStack::PushL(scheduler);
+	CActiveScheduler::Install(scheduler);
+	TBuf<100> text;
+	TDocModel docModel(text);
+	TRect displayRect(0, 0, KDisplayWidth, KDisplayHeight);
+	CTextLayout* layout = CTextLayout::NewL(&docModel, displayRect.Width());
+	CleanupStack::PushL(layout);
+	CTestGraphicsDevice* device = CTestGraphicsDevice::NewL(displayRect.Size(), 0);
+	CleanupStack::PushL(device);
+	CTextView* view = CTextView::NewL(layout, displayRect, device, device, 0, 0, 0);
+	CleanupStack::PushL(view);
+	// This is used to force the use of CTestGraphicsContext instead of a normal one
+	CWindowGc* offScreenContext;
+	User::LeaveIfError(device->CreateContext(offScreenContext));
+	CleanupStack::PushL(offScreenContext);
+	CTestTextView::SetContextForFlickerFreeRedraw(view, offScreenContext);
+
+	// OK, let's get down to testing
+	MFormCustomInvisibleCharacterRemapper* remapper;
+	// read what the ptr is set to - check it is null
+	remapper = layout->GetCustomInvisibleCharacterRemapper();
+	test.Next(_L("Test uninstalled"));
+	test(remapper == NULL);
+
+	// install a custom remapper - get the ptr - check it is set
+	MFormCustomInvisibleCharacterRemapper* customRemapper = CCustomRemapper::NewL();
+	layout->SetCustomInvisibleCharacterRemapper(customRemapper);
+	remapper = layout->GetCustomInvisibleCharacterRemapper();
+	test.Next(_L("Test installed"));
+	test(remapper == customRemapper);
+
+	// set the ptr back to null (deinstall) - get the ptr - check it is null
+	layout->SetCustomInvisibleCharacterRemapper(NULL);
+	remapper = layout->GetCustomInvisibleCharacterRemapper();
+	test.Next(_L("Test uninstalled again"));
+	test(remapper == NULL);
+
+	delete customRemapper;
+
+	CleanupStack::PopAndDestroy(offScreenContext);
+	CleanupStack::PopAndDestroy(view);
+	CleanupStack::PopAndDestroy(device);
+	CleanupStack::PopAndDestroy(layout);
+	CleanupStack::PopAndDestroy(scheduler);
+	__UHEAP_MARKEND;
+	}
+
+
+/**
+@SYMTestCaseID SYSLIB-FORM-CT-0148
+@SYMTestCaseDesc Test behaviour without custom remapper installed
+@SYMTestPriority High
+@SYMTestActions  Test behaviour without custom remapper installed
+@SYMTestExpectedResults The test must not fail.
+@SYMPREQ 1128 Placeholders for invisible characers in rich text shall be customizable
+*/
+void RunDefaultBehaviourTestsL()
+	{
+	test.Next(_L(" @SYMTestCaseID:SYSLIB-FORM-CT-0148 "));
+	CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
+	CleanupStack::PushL(scheduler);
+	CActiveScheduler::Install(scheduler);
+	TBuf<100> text;
+	TDocModel docModel(text);
+	TRect displayRect(0, 0, KDisplayWidth, KDisplayHeight);
+	CTextLayout* layout = CTextLayout::NewL(&docModel, displayRect.Width());
+	CleanupStack::PushL(layout);
+	CTestGraphicsDevice* device = CTestGraphicsDevice::NewL(displayRect.Size(), 0);
+	CleanupStack::PushL(device);
+	CTextView* view = CTextView::NewL(layout, displayRect, device, device, 0, 0, 0);
+	CleanupStack::PushL(view);
+	// This is used to force the use of CTestGraphicsContext instead of a normal one
+	CWindowGc* offScreenContext;
+	User::LeaveIfError(device->CreateContext(offScreenContext));
+	CleanupStack::PushL(offScreenContext);
+	CTestTextView::SetContextForFlickerFreeRedraw(view, offScreenContext);
+
+	// Start by making sure no custom remapper is installed
+	MFormCustomInvisibleCharacterRemapper* remapper;
+	remapper = layout->GetCustomInvisibleCharacterRemapper();
+	test(remapper == NULL);
+
+	// Set all invisible characters to be invisible
+	TNonPrintingCharVisibility visibility;
+	visibility.SetNoneVisible();
+	layout->SetNonPrintingCharsVisibility(visibility);
+
+	// Test remapping with no custom remapper and flags set to invisible
+	test.Next(_L("Test uninstalled behaviour - flags invisible"));
+	DoTestL(text, layout, device, view, EDefaultBehaviourInvisible);
+
+	// Now set all invisible characters to be visible
+	visibility.SetAllVisible();
+	layout->SetNonPrintingCharsVisibility(visibility);
+
+	// Test remapping with no custom remapper and flags set to visible
+	test.Next(_L("Test uninstalled behaviour - flags visible"));
+	DoTestL(text, layout, device, view, EDefaultBehaviourVisible);
+
+	// Test remapping with no custom remapper and some flags explicitly set to invisible
+	test.Next(_L("Test uninstalled behaviour - some flags invisible"));
+	//Set all invisible characters to be visible
+	visibility.SetAllVisible();
+	//Set some attributes explicitly to be invisible
+	visibility.SetSpacesVisible(EFalse);
+	visibility.SetTabsVisible(EFalse);
+	visibility.SetPotentialHyphensVisible(EFalse);
+	visibility.SetParagraphDelimitersVisible(EFalse);
+	visibility.SetPageBreaksVisible(EFalse);
+	visibility.SetNonBreakingSpacesVisible(EFalse);
+	visibility.SetNonBreakingHyphensVisible(EFalse);
+	visibility.SetLineBreaksVisible(EFalse);
+	layout->SetNonPrintingCharsVisibility(visibility);
+	//Test if the visibility is set accordingly
+	DoTestL(text, layout, device, view, ENewTest);
+
+	CleanupStack::PopAndDestroy(offScreenContext);
+	CleanupStack::PopAndDestroy(view);
+	CleanupStack::PopAndDestroy(device);
+	CleanupStack::PopAndDestroy(layout);
+	CleanupStack::PopAndDestroy(scheduler);
+	}
+
+
+/**
+@SYMTestCaseID SYSLIB-FORM-CT-0149
+@SYMTestCaseDesc Test behaviour with custom remapper installed
+@SYMTestPriority High
+@SYMTestActions  Test behaviour with custom remapper installed
+@SYMTestExpectedResults The test must not fail.
+@SYMPREQ 1128 Placeholders for invisible characers in rich text shall be customizable
+*/
+void RunCustomBehaviourTestsL()
+	{
+	// Note: If you need to move these heap checks any further "in" to focus
+	// on a specific test then you will have to move all the setup code in as
+	// well - and still preserve the two different display widths in use
+	test.Next(_L(" @SYMTestCaseID:SYSLIB-FORM-CT-0149 "));
+	__UHEAP_MARK;
+	CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
+	CleanupStack::PushL(scheduler);
+	CActiveScheduler::Install(scheduler);
+	TBuf<100> text;
+	TDocModel docModel(text);
+	TRect displayRect(0, 0, KDisplayWidth, KDisplayHeight);
+	CTextLayout* layout = CTextLayout::NewL(&docModel, displayRect.Width());
+	CleanupStack::PushL(layout);
+	CTestGraphicsDevice* device = CTestGraphicsDevice::NewL(displayRect.Size(), 0);
+	CleanupStack::PushL(device);
+	CTextView* view = CTextView::NewL(layout, displayRect, device, device, 0, 0, 0);
+	CleanupStack::PushL(view);
+	// This is used to force the use of CTestGraphicsContext instead of a normal one
+	CWindowGc* offScreenContext;
+	User::LeaveIfError(device->CreateContext(offScreenContext));
+	CleanupStack::PushL(offScreenContext);
+	CTestTextView::SetContextForFlickerFreeRedraw(view, offScreenContext);
+
+	// We need to install a custom remapper
+	MFormCustomInvisibleCharacterRemapper* remapper;
+	MFormCustomInvisibleCharacterRemapper* customRemapper = CCustomRemapper::NewL();
+	layout->SetCustomInvisibleCharacterRemapper(customRemapper);
+	remapper = layout->GetCustomInvisibleCharacterRemapper();
+	test(remapper == customRemapper);
+
+	// Set all invisible characters to be invisible
+	TNonPrintingCharVisibility visibility;
+	visibility.SetNoneVisible();
+	layout->SetNonPrintingCharsVisibility(visibility);
+
+	// Test remapping with custom remapper and flags set to invisible
+	test.Next(_L("Test installed behaviour - flags invisible"));
+	DoTestL(text, layout, device, view, ECustomRemappingInvisible);
+
+	// Now set all invisible characters to be visible
+	visibility.SetAllVisible();
+	layout->SetNonPrintingCharsVisibility(visibility);
+
+	// Test remapping with custom remapper and flags set to visible
+	test.Next(_L("Test installed behaviour - flags visible"));
+	DoTestL(text, layout, device, view, ECustomRemappingVisible);
+
+	// Now we are finished deinstall and delete it
+	layout->SetCustomInvisibleCharacterRemapper(NULL);
+	remapper = layout->GetCustomInvisibleCharacterRemapper();
+	test(remapper == NULL);
+	delete customRemapper;
+
+	CleanupStack::PopAndDestroy(offScreenContext);
+	CleanupStack::PopAndDestroy(view);
+	CleanupStack::PopAndDestroy(device);
+	CleanupStack::PopAndDestroy(layout);
+	CleanupStack::PopAndDestroy(scheduler);
+	__UHEAP_MARKEND;
+	}
+
+
+TInt E32Main()
+	{
+	__UHEAP_MARK;
+	test.Title();
+	static CTrapCleanup* TrapCleanup = CTrapCleanup::New();
+	test.Start(_L("Test installation/deinstallatiion"));
+	TInt error = RFbsSession::Connect();
+	if (error == KErrNotFound)
+		{
+		FbsStartup();
+		error = RFbsSession::Connect();
+		}
+	test(error == KErrNone);
+	TRAP(error, RunInstallationTestsL());
+	test(error == KErrNone);
+	test.Next(_L("Test uninstalled behaviour"));
+	TRAP(error, RunDefaultBehaviourTestsL());
+	test(error == KErrNone);
+	test.Next(_L("Test behaviour with custom remapper installed"));
+	TRAP(error, RunCustomBehaviourTestsL());
+	test(error == KErrNone);
+	RFbsSession::Disconnect();
+	test.End();
+	delete TrapCleanup;
+	test.Close();
+	__UHEAP_MARKEND;
+	User::Heap().Check();
+	return error;
+	}
+
+
+#if defined(__WINS__)
+EXPORT_C TInt EntryPoint(TAny*) {return E32Main();}
+#endif
+