os/textandloc/textrendering/textformatting/test/src/TCustomCharMapping.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /*
     2 * Copyright (c) 2005-2010 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: 
    15 *
    16 */
    17 
    18 #include <e32std.h>
    19 #include <e32test.h>
    20 #include <frmtlay.h>
    21 #include <frmtview.h>
    22 #include <frmconst.h>
    23 #include <txtlaydc.h>
    24 #include <txtetext.h>
    25 #include <w32std.h>
    26 #include "TGraphicsContext.h"
    27 #include "tcustomcharmapping.h"
    28 
    29 namespace LocalToTCustomCharMapping
    30 {
    31 class CPinkSquare : public CPicture
    32 	{
    33 public:
    34 	// Size of square in twips.
    35 	// 600 is 15 pixels using the standard test graphics device at
    36 	// its default resolution.
    37 	enum { KWidth = 600, KHeight = 600 };
    38 	CPinkSquare()
    39 		{}
    40 	void Draw(CGraphicsContext& aGc, const TPoint& aTopLeft, const TRect& aClipRect, MGraphicsDeviceMap* aMap) const
    41 		{
    42 		// This picture is a magenta square
    43 		TPoint size(KWidth, KHeight);
    44 		if (aMap)
    45 			size = aMap->TwipsToPixels(size);
    46 		TRect rect(aTopLeft, aTopLeft + size);
    47 		aGc.SetClippingRect(aClipRect);
    48 		aGc.SetDrawMode(CGraphicsContext::EDrawModePEN);
    49 		aGc.SetPenColor(KRgbMagenta);
    50 		aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
    51 		aGc.SetBrushColor(KRgbMagenta);
    52 		aGc.DrawRect(rect);
    53 		}
    54 	void ExternalizeL(RWriteStream&) const
    55 		{}
    56 	void GetOriginalSizeInTwips(TSize& a) const
    57 		{
    58 		a.iWidth = CPinkSquare::KWidth;
    59 		a.iHeight = CPinkSquare::KHeight;
    60 		}
    61 	};
    62 
    63 _LIT(KEnd, "\x2029");
    64 class TDocModel : public MLayDoc
    65 	{
    66 public:
    67 	TDocModel(const TDesC& aDes)
    68 	 :	iDes(&aDes), iParagraphFormat(0)
    69 		{}
    70 	void SetParagraphFormat(CParaFormat* a)
    71 		{
    72 		iParagraphFormat = a;
    73 		}
    74 	// From MLayDoc
    75 	TInt LdDocumentLength() const
    76 		{ return iDes->Length(); }
    77 	TInt LdToParagraphStart(TInt& a) const
    78 		{
    79 		TInt curr = a;
    80 		if (a < LdDocumentLength())
    81 			{
    82 			a = iDes->Left(a).LocateReverse(0x2029);
    83 			a = a < 0? 0 : a + 1;
    84 			}
    85 		return curr - a;
    86 		}
    87 	void GetParagraphFormatL(CParaFormat* aFormat, TInt) const
    88 		{
    89 		if (iParagraphFormat)
    90 			{
    91 			aFormat->CopyL(*iParagraphFormat);
    92 			return;
    93 			}
    94 		aFormat->Reset();
    95 		TTabStop tabStop;
    96 		tabStop.iTwipsPosition = 1000;
    97 		tabStop.iType = TTabStop::ELeftTab;
    98 		aFormat->StoreTabL(tabStop);
    99 		}
   100 	void GetChars(TPtrC& aView,TCharFormat& aFormat, TInt aStartPos)const
   101 		{
   102 		TCharFormat cf;
   103 		aFormat = cf;
   104 		if (aStartPos == LdDocumentLength())
   105 			aView.Set(KEnd);
   106 		else
   107 			aView.Set(iDes->Mid(aStartPos));
   108 		}
   109 	TInt GetPictureSizeInTwips(TSize& aSize, TInt aPos) const
   110 		{
   111 		if ((*iDes)[aPos] != KPictureCharacter)
   112 			return KErrNotFound;
   113 		aSize.iWidth = CPinkSquare::KWidth;
   114 		aSize.iHeight = CPinkSquare::KHeight;
   115 		return KErrNone;
   116 		}
   117 	CPicture* PictureHandleL(TInt aPos, TForcePictureLoad) const
   118 		{
   119 		if ((*iDes)[aPos] != KPictureCharacter)
   120 			return 0;
   121 		return new(ELeave) CPinkSquare;
   122 		}
   123 	TBool EnquirePageBreak(TInt aPos, TInt aLength)const
   124 		{
   125 		return iDes->Mid(aPos, aLength).Locate(0x000C) < 0?
   126 			EFalse : ETrue;
   127 		}
   128 	TBool SelectParagraphLabel(TInt)
   129 		{ return EFalse; }
   130 	void CancelSelectLabel()
   131 		{}
   132 private:
   133 	const TDesC* iDes;
   134 	CParaFormat* iParagraphFormat;
   135 	};
   136 }
   137 using namespace LocalToTCustomCharMapping;
   138 
   139 class CTestTextView	// slightly naughty
   140 	{
   141 public:
   142 	static void SetContextForFlickerFreeRedraw(CTextView* aView, CBitmapContext* aContext)
   143 		{
   144 		aView->iOffScreenContext = aContext;
   145 		}
   146 	};
   147 
   148 
   149 static const TInt KTestCases = 5;
   150 static const TInt KVariants = 2;
   151 
   152 // For tests 0 to 3 the source string consists of:
   153 // 'Y' <hard space> 'Z' <normal space> <non-breaking hyphen> <zero width space>
   154 static const TPtrC KTestStrings[KTestCases][KVariants] =
   155 	{
   156 		{	// Test remapping with no custom remapper and flags set to invisible
   157 			// The non-breaking hyphen is turned into a normal hyphen
   158 			// The zero width space disappears (0xFFFF) and the hard space becomes a normal space
   159 			// All done by MTmCustom::Map()
   160 		_S("\x0059\x00A0\x005A\x0020\x2011\x200B"),
   161 		_S("\xFFFF\x0059\x0020\x005A\x0020\x002D\xFFFF\xFFFF"),
   162 		},
   163 		{	// Test remapping with no custom remapper and flags set to visible
   164 			// The non-breaking hyphen becomes a tilde
   165 			// The normal space and the zero width space become visible middle dots
   166 			// The hard (non-breaking) space becomes a degree sign
   167 			// The paragraph sign becomes a pilcrow
   168 			// All done by MTmCustom::Map()
   169 		_S("\x0059\x00A0\x005A\x0020\x2011\x200B"),
   170 		_S("\xFFFF\x0059\x00B0\x005A\x00B7\x007E\x00B7\x00B6\xFFFF"),
   171 		},
   172 		{	// Test remapping with custom remapper and flags set to invisible
   173 			// The non-breaking hyphen is turned into a normal hyphen
   174 			// The zero width space disappears (0xFFFF) and the hard space becomes a normal space
   175 			// All done by MTmCustom::Map()
   176 			// The hard (non-breaking) space becomes a caret
   177 			// This is done by the custom remapper
   178 		_S("\x0059\x00A0\x005A\x0020\x2011\x200B"),
   179 		_S("\xFFFF\x0059\x005E\x005A\x0020\x002D\xFFFF\xFFFF"),
   180 		},
   181 		{	// Test remapping with custom remapper and flags set to visible
   182 			// The non-breaking hyphen becomes a tilde
   183 			// The zero width space become visible middle dots
   184 			// All done by MTmCustom::Map()
   185 			// The normal space remains a normal (invisible) space because default behaviour is overidden
   186 			// The hard (non-breaking) space becomes a caret
   187 			// The paragraph sign becomes a capital P
   188 			// All done by the custom remapper
   189 		_S("\x0059\x00A0\x005A\x0020\x2011\x200B"),
   190 		_S("\xFFFF\x0059\x005E\x005A\x0020\x007E\x00B7\x0050\xFFFF"),
   191 		},
   192 		{
   193 			// Test remapping with no custom remapper and some flags explicitly set to invisible
   194 			// The non-breaking hyphen is turned into a normal hyphen
   195 			// The zero width space disappears (0xFFFF) and the hard space becomes a normal space
   196 			// All done by MTmCustom::Map()
   197 		_S("\x0059\x00A0\x005A\x0020\x2011\x200B"),
   198 		_S("\xFFFF\x0059\x0020\x005A\x0020\x002D\xFFFF\xFFFF"),
   199 		}
   200 	};
   201 
   202 
   203 class CCustomRemapper : public MFormCustomInvisibleCharacterRemapper
   204 	{
   205 public:
   206 	static CCustomRemapper* NewL();
   207 	~CCustomRemapper();
   208 	TUint Remap(TUint aChar, const TNonPrintingCharVisibility aNonPrintingCharVisibility, const TLayDocTextSource& aLayDoc);
   209 private:
   210 	CCustomRemapper();
   211 	};
   212 
   213 	CCustomRemapper* CCustomRemapper::NewL()
   214 		{
   215 		CCustomRemapper* me = new(ELeave) CCustomRemapper;
   216 		return me;
   217 		}
   218 
   219 	CCustomRemapper::~CCustomRemapper()
   220 		{
   221 		}
   222 
   223 	TUint CCustomRemapper::Remap(TUint aChar, const TNonPrintingCharVisibility aNonPrintingCharVisibility, const TLayDocTextSource& aLayDoc)
   224 		{
   225 		switch (aChar)
   226 			{
   227 			case CEditableText::EParagraphDelimiter:
   228 				if (aNonPrintingCharVisibility.ParagraphDelimitersVisible())
   229 					return 0x0050; // capital P - override when visible
   230 				break;
   231 
   232 			case CEditableText::ESpace:
   233 				return aChar; // don't remap but don't pass it on - override default
   234 				// break statement was removed.
   235 
   236 			case CEditableText::ENonBreakingSpace:
   237 				return 0x005E; // Caret - override always - visible or not
   238 				// break statement was removed.
   239 			default:
   240 				break; // do nothing
   241 			}
   242 
   243 		// If not mapping special characters, or not mapping this particular character, use the default mapping.
   244 		return DefaultMapping(aChar, aNonPrintingCharVisibility, aLayDoc);
   245 		}
   246 
   247 	CCustomRemapper::CCustomRemapper()
   248 		{
   249 		}
   250 
   251 void CTCustomCharMappingStep::DoTestL(TDes& aText, CTextLayout* /*aLayout*/, CTestGraphicsDevice* aDevice, CTextView* aView, TTestNum aTestNum)
   252 	{
   253 	aText = KTestStrings[aTestNum][0];
   254 	aDevice->LineArray().ResetLineArray();
   255 	aView->HandleGlobalChangeL();
   256 	const TTestGCDisplayLine* line1 = &(aDevice->LineArray().Line(0));
   257 	const TTestGCDisplayLine* line2 = aDevice->LineArray().Find(KTestStrings[aTestNum][1]);
   258 	TEST(0 != line1);
   259 	TEST(0 != line2);
   260 	// Can't always do a direct comparison of lines because same string
   261 	// may appear in more than one line, so compare contents
   262 	TEST(line1->iLineData.Compare(line2->iLineData) == 0);
   263 	}
   264 
   265 
   266 /**
   267 @SYMTestCaseID SYSLIB-FORM-CT-0147
   268 @SYMTestCaseDesc Test installation and deinstallation of custom remapper
   269 @SYMTestPriority High
   270 @SYMTestActions  Test installation and deinstallation of custom remapper
   271 @SYMTestExpectedResults The test must not fail.
   272 @SYMPREQ 1128 Placeholders for invisible characers in rich text shall be customizable
   273 */
   274 void CTCustomCharMappingStep::RunInstallationTestsL()
   275 	{
   276 	// Note: If you need to move these heap checks any further "in" to focus
   277 	// on a specific test then you will have to move all the setup code in as
   278 	// well - and still preserve the two different display widths in use
   279     INFO_PRINTF1(_L(" @SYMTestCaseID:SYSLIB-FORM-CT-0147 "));
   280 	__UHEAP_MARK;
   281 	CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
   282 	CleanupStack::PushL(scheduler);
   283 	CActiveScheduler::Install(scheduler);
   284 	TBuf<100> text;
   285 	TDocModel docModel(text);
   286 	TRect displayRect(0, 0, KDisplayWidth, KDisplayHeight);
   287 	CTextLayout* layout = CTextLayout::NewL(&docModel, displayRect.Width());
   288 	CleanupStack::PushL(layout);
   289 	CTestGraphicsDevice* device = CTestGraphicsDevice::NewL(displayRect.Size(), 0);
   290 	CleanupStack::PushL(device);
   291 	CTextView* view = CTextView::NewL(layout, displayRect, device, device, 0, 0, 0);
   292 	CleanupStack::PushL(view);
   293 	// This is used to force the use of CTestGraphicsContext instead of a normal one
   294 	CWindowGc* offScreenContext;
   295 	User::LeaveIfError(device->CreateContext(offScreenContext));
   296 	CleanupStack::PushL(offScreenContext);
   297 	CTestTextView::SetContextForFlickerFreeRedraw(view, offScreenContext);
   298 
   299 	// OK, let's get down to testing
   300 	MFormCustomInvisibleCharacterRemapper* remapper;
   301 	// read what the ptr is set to - check it is null
   302 	remapper = layout->GetCustomInvisibleCharacterRemapper();
   303 	INFO_PRINTF1(_L("Test uninstalled"));
   304 	TEST(remapper == NULL);
   305 
   306 	// install a custom remapper - get the ptr - check it is set
   307 	MFormCustomInvisibleCharacterRemapper* customRemapper = CCustomRemapper::NewL();
   308 	layout->SetCustomInvisibleCharacterRemapper(customRemapper);
   309 	remapper = layout->GetCustomInvisibleCharacterRemapper();
   310 	INFO_PRINTF1(_L("Test installed"));
   311 	TEST(remapper == customRemapper);
   312 
   313 	// set the ptr back to null (deinstall) - get the ptr - check it is null
   314 	layout->SetCustomInvisibleCharacterRemapper(NULL);
   315 	remapper = layout->GetCustomInvisibleCharacterRemapper();
   316 	INFO_PRINTF1(_L("Test uninstalled again"));
   317 	TEST(remapper == NULL);
   318 
   319 	delete customRemapper;
   320 
   321 	CleanupStack::PopAndDestroy(offScreenContext);
   322 	CleanupStack::PopAndDestroy(view);
   323 	CleanupStack::PopAndDestroy(device);
   324 	CleanupStack::PopAndDestroy(layout);
   325 	CleanupStack::PopAndDestroy(scheduler);
   326 	__UHEAP_MARKEND;
   327 	}
   328 
   329 
   330 /**
   331 @SYMTestCaseID SYSLIB-FORM-CT-0148
   332 @SYMTestCaseDesc Test behaviour without custom remapper installed
   333 @SYMTestPriority High
   334 @SYMTestActions  Test behaviour without custom remapper installed
   335 @SYMTestExpectedResults The test must not fail.
   336 @SYMPREQ 1128 Placeholders for invisible characers in rich text shall be customizable
   337 */
   338 void CTCustomCharMappingStep::RunDefaultBehaviourTestsL()
   339 	{
   340     INFO_PRINTF1(_L(" @SYMTestCaseID:SYSLIB-FORM-CT-0148 "));
   341 	CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
   342 	CleanupStack::PushL(scheduler);
   343 	CActiveScheduler::Install(scheduler);
   344 	TBuf<100> text;
   345 	TDocModel docModel(text);
   346 	TRect displayRect(0, 0, KDisplayWidth, KDisplayHeight);
   347 	CTextLayout* layout = CTextLayout::NewL(&docModel, displayRect.Width());
   348 	CleanupStack::PushL(layout);
   349 	CTestGraphicsDevice* device = CTestGraphicsDevice::NewL(displayRect.Size(), 0);
   350 	CleanupStack::PushL(device);
   351 	CTextView* view = CTextView::NewL(layout, displayRect, device, device, 0, 0, 0);
   352 	CleanupStack::PushL(view);
   353 	// This is used to force the use of CTestGraphicsContext instead of a normal one
   354 	CWindowGc* offScreenContext;
   355 	User::LeaveIfError(device->CreateContext(offScreenContext));
   356 	CleanupStack::PushL(offScreenContext);
   357 	CTestTextView::SetContextForFlickerFreeRedraw(view, offScreenContext);
   358 
   359 	// Start by making sure no custom remapper is installed
   360 	MFormCustomInvisibleCharacterRemapper* remapper;
   361 	remapper = layout->GetCustomInvisibleCharacterRemapper();
   362 	TEST(remapper == NULL);
   363 
   364 	// Set all invisible characters to be invisible
   365 	TNonPrintingCharVisibility visibility;
   366 	visibility.SetNoneVisible();
   367 	layout->SetNonPrintingCharsVisibility(visibility);
   368 
   369 	// Test remapping with no custom remapper and flags set to invisible
   370 	INFO_PRINTF1(_L("Test uninstalled behaviour - flags invisible"));
   371 	DoTestL(text, layout, device, view, EDefaultBehaviourInvisible);
   372 
   373 	// Now set all invisible characters to be visible
   374 	visibility.SetAllVisible();
   375 	layout->SetNonPrintingCharsVisibility(visibility);
   376 
   377 	// Test remapping with no custom remapper and flags set to visible
   378 	INFO_PRINTF1(_L("Test uninstalled behaviour - flags visible"));
   379 	DoTestL(text, layout, device, view, EDefaultBehaviourVisible);
   380 
   381 	// Test remapping with no custom remapper and some flags explicitly set to invisible
   382 	INFO_PRINTF1(_L("Test uninstalled behaviour - some flags invisible"));
   383 	//Set all invisible characters to be visible
   384 	visibility.SetAllVisible();
   385 	//Set some attributes explicitly to be invisible
   386 	visibility.SetSpacesVisible(EFalse);
   387 	visibility.SetTabsVisible(EFalse);
   388 	visibility.SetPotentialHyphensVisible(EFalse);
   389 	visibility.SetParagraphDelimitersVisible(EFalse);
   390 	visibility.SetPageBreaksVisible(EFalse);
   391 	visibility.SetNonBreakingSpacesVisible(EFalse);
   392 	visibility.SetNonBreakingHyphensVisible(EFalse);
   393 	visibility.SetLineBreaksVisible(EFalse);
   394 	layout->SetNonPrintingCharsVisibility(visibility);
   395 	//Test if the visibility is set accordingly
   396 	DoTestL(text, layout, device, view, ENewTest);
   397 
   398 	CleanupStack::PopAndDestroy(offScreenContext);
   399 	CleanupStack::PopAndDestroy(view);
   400 	CleanupStack::PopAndDestroy(device);
   401 	CleanupStack::PopAndDestroy(layout);
   402 	CleanupStack::PopAndDestroy(scheduler);
   403 	}
   404 
   405 
   406 /**
   407 @SYMTestCaseID SYSLIB-FORM-CT-0149
   408 @SYMTestCaseDesc Test behaviour with custom remapper installed
   409 @SYMTestPriority High
   410 @SYMTestActions  Test behaviour with custom remapper installed
   411 @SYMTestExpectedResults The test must not fail.
   412 @SYMPREQ 1128 Placeholders for invisible characers in rich text shall be customizable
   413 */
   414 void CTCustomCharMappingStep::RunCustomBehaviourTestsL()
   415 	{
   416 	// Note: If you need to move these heap checks any further "in" to focus
   417 	// on a specific test then you will have to move all the setup code in as
   418 	// well - and still preserve the two different display widths in use
   419     INFO_PRINTF1(_L(" @SYMTestCaseID:SYSLIB-FORM-CT-0149 "));
   420 	__UHEAP_MARK;
   421 	CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
   422 	CleanupStack::PushL(scheduler);
   423 	CActiveScheduler::Install(scheduler);
   424 	TBuf<100> text;
   425 	TDocModel docModel(text);
   426 	TRect displayRect(0, 0, KDisplayWidth, KDisplayHeight);
   427 	CTextLayout* layout = CTextLayout::NewL(&docModel, displayRect.Width());
   428 	CleanupStack::PushL(layout);
   429 	CTestGraphicsDevice* device = CTestGraphicsDevice::NewL(displayRect.Size(), 0);
   430 	CleanupStack::PushL(device);
   431 	CTextView* view = CTextView::NewL(layout, displayRect, device, device, 0, 0, 0);
   432 	CleanupStack::PushL(view);
   433 	// This is used to force the use of CTestGraphicsContext instead of a normal one
   434 	CWindowGc* offScreenContext;
   435 	User::LeaveIfError(device->CreateContext(offScreenContext));
   436 	CleanupStack::PushL(offScreenContext);
   437 	CTestTextView::SetContextForFlickerFreeRedraw(view, offScreenContext);
   438 
   439 	// We need to install a custom remapper
   440 	MFormCustomInvisibleCharacterRemapper* remapper;
   441 	MFormCustomInvisibleCharacterRemapper* customRemapper = CCustomRemapper::NewL();
   442 	layout->SetCustomInvisibleCharacterRemapper(customRemapper);
   443 	remapper = layout->GetCustomInvisibleCharacterRemapper();
   444 	TEST(remapper == customRemapper);
   445 
   446 	// Set all invisible characters to be invisible
   447 	TNonPrintingCharVisibility visibility;
   448 	visibility.SetNoneVisible();
   449 	layout->SetNonPrintingCharsVisibility(visibility);
   450 
   451 	// Test remapping with custom remapper and flags set to invisible
   452 	INFO_PRINTF1(_L("Test installed behaviour - flags invisible"));
   453 	DoTestL(text, layout, device, view, ECustomRemappingInvisible);
   454 
   455 	// Now set all invisible characters to be visible
   456 	visibility.SetAllVisible();
   457 	layout->SetNonPrintingCharsVisibility(visibility);
   458 
   459 	// Test remapping with custom remapper and flags set to visible
   460 	INFO_PRINTF1(_L("Test installed behaviour - flags visible"));
   461 	DoTestL(text, layout, device, view, ECustomRemappingVisible);
   462 
   463 	// Now we are finished deinstall and delete it
   464 	layout->SetCustomInvisibleCharacterRemapper(NULL);
   465 	remapper = layout->GetCustomInvisibleCharacterRemapper();
   466 	TEST(remapper == NULL);
   467 	delete customRemapper;
   468 
   469 	CleanupStack::PopAndDestroy(offScreenContext);
   470 	CleanupStack::PopAndDestroy(view);
   471 	CleanupStack::PopAndDestroy(device);
   472 	CleanupStack::PopAndDestroy(layout);
   473 	CleanupStack::PopAndDestroy(scheduler);
   474 	__UHEAP_MARKEND;
   475 	}
   476 
   477 CTCustomCharMappingStep::CTCustomCharMappingStep()
   478     {
   479     
   480     }
   481 
   482 TVerdict CTCustomCharMappingStep::doTestStepL()
   483     {
   484     SetTestStepResult(EPass);
   485     INFO_PRINTF1(_L("Test installation/deinstallatiion"));
   486     TInt error = RFbsSession::Connect();
   487     if (error == KErrNotFound)
   488         {
   489         FbsStartup();
   490         error = RFbsSession::Connect();
   491         }
   492     TEST(error == KErrNone);
   493     TRAP(error, RunInstallationTestsL());
   494     TEST(error == KErrNone);
   495     INFO_PRINTF1(_L("Test uninstalled behaviour"));
   496     TRAP(error, RunDefaultBehaviourTestsL());
   497     TEST(error == KErrNone);
   498     INFO_PRINTF1(_L("Test behaviour with custom remapper installed"));
   499     TRAP(error, RunCustomBehaviourTestsL());
   500     TEST(error == KErrNone);
   501     RFbsSession::Disconnect();
   502     return TestStepResult();
   503     }