textrendering/textformatting/test/src/tformhindi.cpp
changeset 0 1fb32624e06b
child 16 748ec5531811
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/textformatting/test/src/tformhindi.cpp	Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,393 @@
+/*
+* 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 <e32test.h>
+#include <frmtlay.h>
+#include <frmtview.h>
+#include <txtlaydc.h>
+#include <fbs.h>
+#include <w32std.h>
+#include <bitdev.h>
+#include <txtrich.h>
+
+namespace LocalToFile {
+
+_LIT(KTformhindi, "tformhindi");
+const TInt KDisplayWidth = 100;
+const TInt KDisplayHeight = 100;
+RTest test(KTformhindi);
+_LIT(KDevanagariFontName, "Devanagari OT Eval");
+
+}
+using namespace LocalToFile;
+
+_LIT(KTestDeva, "|\x915\x94d\x92b|\x907|\x920\x94d\x920|");
+_LIT(KTestBidi, "|\x915|\x644|\x920|");
+_LIT(KTestDeva2, "|\x917|\x91c|\x92f\x93f|\x924\x94d\x932\x940|\x917|");
+
+static const TInt KZeroWidthJoiner = 0x200d;
+
+/** Test that the deletions occur in expected places.
+Expected places should be marked by '|' (pipe character).
+These will be removed prior to the test.
+@internalComponent
+*/
+void TestDeletePosition(const TDesC& aTestText, CRichText* aRichText,
+	CTextView* aTextView)
+	{
+	TBuf<100> text;
+	TInt positions[20];
+	TInt positionCount = 0;
+
+	TInt ttlen = aTestText.Length();
+	for (TInt i = 0; i != ttlen; ++i)
+		{
+		TInt c = aTestText[i];
+		if (c == '|')
+			{
+			positions[positionCount] = text.Length();
+			++positionCount;
+			}
+		else
+			text.Append(c);
+		}
+
+	aRichText->Reset();
+	aRichText->InsertL(0, text);
+	TCharFormat format(KDevanagariFontName, 200);
+	TCharFormatMask mask;
+	mask.SetAttrib(EAttFontTypeface);
+	aRichText->ApplyCharFormatL(format, mask, 0, text.Length());
+	aTextView->FormatTextL();
+
+	for (TInt j = 0; j < positionCount - 1; ++j)
+		{
+		aTextView->SetDocPosL(positions[j], EFalse);
+		TInt pos = aTextView->GetForwardDeletePositionL().HigherPos();
+		test(pos == positions[j + 1]);
+		aTextView->SetDocPosL(positions[j], ETrue);
+		pos = aTextView->GetForwardDeletePositionL().HigherPos();
+		test(pos == positions[j + 1]);
+		aTextView->SetDocPosL(positions[j + 1], EFalse);
+		pos = aTextView->GetBackwardDeletePositionL().LowerPos();
+		test(pos == positions[j]);
+		aTextView->SetDocPosL(positions[j + 1], ETrue);
+		pos = aTextView->GetBackwardDeletePositionL().LowerPos();
+		test(pos == positions[j]);
+		}
+
+	aRichText->Reset();
+	}
+
+
+// DEF101191: FORM always splits chunks at ZWJ character
+
+class CPDEF_101617_CustomDraw : public MFormCustomDraw
+{
+public:
+	CPDEF_101617_CustomDraw() :
+		iLeftChunk(),
+		iRightChunk(),
+		iChunk(0)
+		{
+		}
+	virtual ~CPDEF_101617_CustomDraw() {}
+
+	void setExpectedChunk(const TDesC& aChunk)
+	{
+		iLeftChunk = aChunk;
+		iRightChunk.Zero();
+		iChunk = 0;
+	}
+	void setExpectedChunks(const TDesC& aLeftChunk, const TDesC& aRightChunk)
+	{
+		iLeftChunk = aLeftChunk;
+		iRightChunk = aRightChunk;
+		iChunk = 0;
+	}
+
+	// MFormCustomDraw
+	virtual void DrawText(const TParam& /*aParam*/, const TLineInfo& /*aLineInfo*/, const TCharFormat& /*aFormat*/,
+		const TDesC& aText, const TPoint& /*aTextOrigin*/, TInt /*aExtraPixels*/) const
+		{
+		TBool containsZWJ = EFalse;
+
+		TBuf<100> text;
+		TInt len = aText.Length();
+		for (TInt i = 0; i < len; i++)
+			{
+			// remove 0xffff
+			if (0xffff != aText[i])
+				{
+				text.Append(aText[i]);
+				if (KZeroWidthJoiner == aText[i])
+					{
+					containsZWJ = ETrue;
+					}
+				}
+			}
+
+		// check that the text was splitted as expected
+		if (containsZWJ || iChunk > 0)
+			{
+			// the first chunk with a LZW should be equal to iLeftChunk
+			if (0 == iChunk)
+				{
+				test(text == iLeftChunk);
+				iChunk++;
+				}
+			// the following chunk should be equal to iRightChunk, if it is not-null.
+			else if (1 == iChunk && iRightChunk.Size() > 0)
+				{
+				test(text == iRightChunk);
+				iChunk++;
+				}
+			// just ignore the following chunks
+			}
+		}
+
+private:
+	TBuf<100> iLeftChunk;
+	TBuf<100> iRightChunk;
+	mutable TInt iChunk; // modified in a const method
+};
+
+void PDEF_101617_DefectL(CRichText* aRichText, CTextView* aTextView)
+	{
+	TCharFormat format(KDevanagariFontName, 200);
+	TCharFormatMask mask;
+	mask.SetAttrib(EAttFontTypeface);
+
+	CPDEF_101617_CustomDraw* customDrawer = new CPDEF_101617_CustomDraw;
+	CleanupStack::PushL(customDrawer);
+
+	CTextLayout* layout = const_cast<CTextLayout*>(aTextView->Layout());
+	layout->SetCustomDraw(customDrawer);
+
+	TRect rect(0, 0, 300, 100);
+
+	// 1. test the sequence Sha, Virama, ZWJ, Va,Sha, EndOfParagraph
+	_LIT(KTestDevaZWJ1, "\x0936\x094d\x200d\x0935\x0936\x2029");
+	TPtrC text1(KTestDevaZWJ1().Ptr(), KTestDevaZWJ1().Length());
+
+	// the text should not be split and should remain a single chunk...
+	_LIT(KTestDevaZWJ1_LeftChunk, "\x0936\x094d\x200d\x0935\x0936");
+
+	customDrawer->setExpectedChunk(KTestDevaZWJ1_LeftChunk);
+
+	aRichText->Reset();
+	aRichText->InsertL(0, text1);
+	aRichText->ApplyCharFormatL(format, mask, 0, text1.Length());
+	aTextView->FormatTextL();
+	aTextView->DrawL(rect);
+
+
+	// 2. test the sequence Sha,ZWJ,Virama, Va, EndOfParagraph
+	_LIT(KTestDevaZWJ2, "\x0936\x200d\x094d\x0935\x2029");
+	TPtrC text2(KTestDevaZWJ2().Ptr(), KTestDevaZWJ2().Length());
+
+	// the text should be split at the bidirectionality change
+	_LIT(KTestDevaZWJ2_LeftChunk, "\x0936\x200d\x094d\x0935");
+
+	customDrawer->setExpectedChunk(KTestDevaZWJ2_LeftChunk);
+
+	aRichText->Reset();
+	aRichText->InsertL(0, text2);
+	aRichText->ApplyCharFormatL(format, mask, 0, text2.Length());
+	aTextView->FormatTextL();
+	aTextView->DrawL(rect);
+
+	// 3. test the sequence Sha, Virama, ZWJ,Alef(Hebrew) EndOfParagraph
+	_LIT(KTestDevaZWJ3, "\x0936\x094d\x200d\x05D0\x2029");
+	TPtrC text3(KTestDevaZWJ3().Ptr(), KTestDevaZWJ3().Length());
+
+	// the text should be split keeping ZWJ (0x200d) at the end of the first chunk...
+	_LIT(KTestDevaZWJ3_LeftChunk, "\x0936\x094d\x200d");
+	// ... and placing another ZWJ at the start of the second chunk (right to left text)
+	_LIT(KTestDevaZWJ3_RightChunk, "\x05D0\x200d");
+
+	customDrawer->setExpectedChunks(KTestDevaZWJ3_LeftChunk, KTestDevaZWJ3_RightChunk);
+
+	aRichText->Reset();
+	aRichText->InsertL(0, text3);
+	aRichText->ApplyCharFormatL(format, mask, 0, text3.Length());
+	aTextView->FormatTextL();
+	aTextView->DrawL(rect);
+
+	// 4. test the sequence Sha, Virama, ZWJ, Va,Alef(Hebrew) EndOfParagraph
+	_LIT(KTestDevaZWJ4, "\x0936\x094d\x200d\x0935\x05D0\x2029");
+	TPtrC text4(KTestDevaZWJ4().Ptr(), KTestDevaZWJ4().Length());
+
+	// the text should be split at the bidirectionality change
+	_LIT(KTestDevaZWJ4_LeftChunk, "\x0936\x094d\x200d\x0935");
+	_LIT(KTestDevaZWJ4_RightChunk, "\x05D0");
+
+	customDrawer->setExpectedChunks(KTestDevaZWJ4_LeftChunk, KTestDevaZWJ4_RightChunk);
+
+	aRichText->Reset();
+	aRichText->InsertL(0, text4);
+	aRichText->ApplyCharFormatL(format, mask, 0, text4.Length());
+	aTextView->FormatTextL();
+	aTextView->DrawL(rect);
+
+	aRichText->Reset();
+
+	layout->SetCustomDraw(NULL);
+	CleanupStack::PopAndDestroy(customDrawer);
+	}
+
+
+/** @SYMTestCaseID SYSLIB-FORM-UT-1532
+@SYMTestCaseDesc
+	Test delete-by-syllable within Hindi text.
+@SYMTestPriority High
+@SYMTestActions
+	Format some Devanagari, test result of calling GetForwardDeletePositionL
+	and GetBackwardDeletePositionL for various inputs.
+@SYMTestExpectedResults
+	Success if the font "Devanagari OT Eval" is present, Not Run if it is not.
+	This font is licensed to Symbian by Monotype Imaging Ltd. for internal
+	testing only and so is not distributed with the SDK. Therefore users
+	outside of Symbian will experience Not Run unless they have also
+	obtained this font.
+@SYMPREQ PREQ18 */
+void TestTextViewL(CRichText* aRichText,
+	CTextView* aTextView)
+	{
+	// Test devanagari delete-by-syllable
+	test.Start(_L(" @SYMTestCaseID:SYSLIB-FORM-UT-1532 Test some simple Hindi "));
+	TestDeletePosition(KTestDeva, aRichText, aTextView);
+
+	// Test Bidi
+	// The Arabic character is not present in this font, not even
+	// as a fallback glyph. This allows us to exercise a fixes for
+	// a latent defect.
+	test.Next(_L("Test with characters not in font"));
+	TestDeletePosition(KTestBidi, aRichText, aTextView);
+
+	// Test sample suggested by customer
+	test.Next(_L("Test Hindi #2"));
+	TestDeletePosition(KTestDeva2, aRichText, aTextView);
+
+	// regression test for PDEF101617: FORM always splits chunks at ZWJ character
+	test.Next(_L("Regression test: PDEF101617"));
+	PDEF_101617_DefectL(aRichText, aTextView);
+
+	test.End();
+	}
+
+void TestL(CFbsScreenDevice* aDevice)
+	{
+	CParaFormatLayer* paraFormat = CParaFormatLayer::NewL();
+	CleanupStack::PushL(paraFormat);
+	CCharFormatLayer* charFormat = CCharFormatLayer::NewL();
+	CleanupStack::PushL(charFormat);
+	CRichText* text = CRichText::NewL(paraFormat, charFormat);
+	CleanupStack::PushL(text);
+	TRect displayRect(0, 0, KDisplayWidth, KDisplayHeight);
+	CTextLayout* layout = CTextLayout::NewL(text, displayRect.Width());
+	CleanupStack::PushL(layout);
+	CTextView* view = CTextView::NewL(layout, displayRect,
+		aDevice, aDevice, 0, 0, 0);
+	CleanupStack::PushL(view);
+	TestTextViewL(text, view);
+	CleanupStack::PopAndDestroy(view);
+	CleanupStack::PopAndDestroy(layout);
+	CleanupStack::PopAndDestroy(text);
+	CleanupStack::PopAndDestroy(charFormat);
+	CleanupStack::PopAndDestroy(paraFormat);
+	}
+
+void MainL()
+	{
+	TInt error = RFbsSession::Connect();
+	if (error == KErrNotFound)
+		{
+		FbsStartup();
+		User::LeaveIfError(RFbsSession::Connect());
+		}
+	CFbsScreenDevice* screenDevice = 0;
+	
+	TRAP(error, screenDevice = CFbsScreenDevice::NewL(0,EColor16M));
+	if (error == KErrNotSupported)
+		TRAP(error, screenDevice = CFbsScreenDevice::NewL(0,EColor16MA));
+	if (error == KErrNotSupported)
+		TRAP(error, screenDevice = CFbsScreenDevice::NewL(0,EColor16MU));
+	if (error == KErrNotSupported)
+		TRAP(error, screenDevice = CFbsScreenDevice::NewL(0,EColor64K));
+	if (error == KErrNotSupported)
+		TRAP(error, screenDevice = CFbsScreenDevice::NewL(0,EColor4K));
+	if (error == KErrNotSupported)
+		TRAP(error, screenDevice = CFbsScreenDevice::NewL(0,EColor256));
+	if (error == KErrNotSupported)
+		TRAP(error, screenDevice = CFbsScreenDevice::NewL(0,EColor16));
+	if (error == KErrNotSupported)
+		TRAP(error, screenDevice = CFbsScreenDevice::NewL(0,EGray256));
+	if (error == KErrNotSupported)
+		TRAP(error, screenDevice = CFbsScreenDevice::NewL(0,EGray16));
+	if (error == KErrNotSupported)
+		TRAP(error, screenDevice = CFbsScreenDevice::NewL(0,EGray4));
+	if (error == KErrNotSupported)
+		screenDevice = CFbsScreenDevice::NewL(0,EGray2);
+	
+	CleanupStack::PushL(screenDevice);
+	screenDevice->ChangeScreenDevice(0);
+	screenDevice->SetAutoUpdate(ETrue);
+	CGraphicsContext* gc;
+	User::LeaveIfError(screenDevice->CreateContext(gc));
+	CleanupStack::PushL(gc);
+	TFontSpec fs(KDevanagariFontName, 16);
+	CFont* devaFont;
+	User::LeaveIfError(screenDevice->GetNearestFontInPixels(devaFont, fs));
+	TFontSpec fontSpec = devaFont->FontSpecInTwips();
+	if(0 != fontSpec.iTypeface.iName.Compare(KDevanagariFontName))
+		{
+		// Test font not found.
+		User::Leave(KErrNotFound);
+		}
+	CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
+	CleanupStack::PushL(scheduler);
+	CActiveScheduler::Install(scheduler);
+
+	// We know that we have everything we need now, so we'll start the test!
+	// A failure before this point would show up in the logs as "not run" rather
+	// than "failed".
+	test.Title();
+	test.Start(_L("Test forward/backward delete for Hindi"));
+	TRAP(error, TestL(screenDevice));
+	test.End();
+	test.Close();
+	CleanupStack::PopAndDestroy(scheduler);
+	CleanupStack::PopAndDestroy(gc);
+	CleanupStack::PopAndDestroy(screenDevice);
+	RFbsSession::Disconnect();
+	User::LeaveIfError(error);
+	}
+
+TInt E32Main()
+	{
+	static CTrapCleanup* TrapCleanup = CTrapCleanup::New();
+	if (!TrapCleanup)
+		return KErrNoMemory;
+	TRAPD(error, MainL());
+	delete TrapCleanup;
+	return error;
+	}