First public contribution.
2 * Copyright (c) 2005-2010 Nokia Corporation and/or its subsidiary(-ies).
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".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
26 #include "TGraphicsContext.h"
27 #include "tcustomcharmapping.h"
29 namespace LocalToTCustomCharMapping
31 class CPinkSquare : public CPicture
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 };
40 void Draw(CGraphicsContext& aGc, const TPoint& aTopLeft, const TRect& aClipRect, MGraphicsDeviceMap* aMap) const
42 // This picture is a magenta square
43 TPoint size(KWidth, KHeight);
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);
54 void ExternalizeL(RWriteStream&) const
56 void GetOriginalSizeInTwips(TSize& a) const
58 a.iWidth = CPinkSquare::KWidth;
59 a.iHeight = CPinkSquare::KHeight;
64 class TDocModel : public MLayDoc
67 TDocModel(const TDesC& aDes)
68 : iDes(&aDes), iParagraphFormat(0)
70 void SetParagraphFormat(CParaFormat* a)
75 TInt LdDocumentLength() const
76 { return iDes->Length(); }
77 TInt LdToParagraphStart(TInt& a) const
80 if (a < LdDocumentLength())
82 a = iDes->Left(a).LocateReverse(0x2029);
87 void GetParagraphFormatL(CParaFormat* aFormat, TInt) const
91 aFormat->CopyL(*iParagraphFormat);
96 tabStop.iTwipsPosition = 1000;
97 tabStop.iType = TTabStop::ELeftTab;
98 aFormat->StoreTabL(tabStop);
100 void GetChars(TPtrC& aView,TCharFormat& aFormat, TInt aStartPos)const
104 if (aStartPos == LdDocumentLength())
107 aView.Set(iDes->Mid(aStartPos));
109 TInt GetPictureSizeInTwips(TSize& aSize, TInt aPos) const
111 if ((*iDes)[aPos] != KPictureCharacter)
113 aSize.iWidth = CPinkSquare::KWidth;
114 aSize.iHeight = CPinkSquare::KHeight;
117 CPicture* PictureHandleL(TInt aPos, TForcePictureLoad) const
119 if ((*iDes)[aPos] != KPictureCharacter)
121 return new(ELeave) CPinkSquare;
123 TBool EnquirePageBreak(TInt aPos, TInt aLength)const
125 return iDes->Mid(aPos, aLength).Locate(0x000C) < 0?
128 TBool SelectParagraphLabel(TInt)
130 void CancelSelectLabel()
134 CParaFormat* iParagraphFormat;
137 using namespace LocalToTCustomCharMapping;
139 class CTestTextView // slightly naughty
142 static void SetContextForFlickerFreeRedraw(CTextView* aView, CBitmapContext* aContext)
144 aView->iOffScreenContext = aContext;
149 static const TInt KTestCases = 5;
150 static const TInt KVariants = 2;
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] =
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"),
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"),
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"),
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"),
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"),
203 class CCustomRemapper : public MFormCustomInvisibleCharacterRemapper
206 static CCustomRemapper* NewL();
208 TUint Remap(TUint aChar, const TNonPrintingCharVisibility aNonPrintingCharVisibility, const TLayDocTextSource& aLayDoc);
213 CCustomRemapper* CCustomRemapper::NewL()
215 CCustomRemapper* me = new(ELeave) CCustomRemapper;
219 CCustomRemapper::~CCustomRemapper()
223 TUint CCustomRemapper::Remap(TUint aChar, const TNonPrintingCharVisibility aNonPrintingCharVisibility, const TLayDocTextSource& aLayDoc)
227 case CEditableText::EParagraphDelimiter:
228 if (aNonPrintingCharVisibility.ParagraphDelimitersVisible())
229 return 0x0050; // capital P - override when visible
232 case CEditableText::ESpace:
233 return aChar; // don't remap but don't pass it on - override default
234 // break statement was removed.
236 case CEditableText::ENonBreakingSpace:
237 return 0x005E; // Caret - override always - visible or not
238 // break statement was removed.
243 // If not mapping special characters, or not mapping this particular character, use the default mapping.
244 return DefaultMapping(aChar, aNonPrintingCharVisibility, aLayDoc);
247 CCustomRemapper::CCustomRemapper()
251 void CTCustomCharMappingStep::DoTestL(TDes& aText, CTextLayout* /*aLayout*/, CTestGraphicsDevice* aDevice, CTextView* aView, TTestNum aTestNum)
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]);
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);
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
274 void CTCustomCharMappingStep::RunInstallationTestsL()
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 "));
281 CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
282 CleanupStack::PushL(scheduler);
283 CActiveScheduler::Install(scheduler);
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);
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);
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);
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);
319 delete customRemapper;
321 CleanupStack::PopAndDestroy(offScreenContext);
322 CleanupStack::PopAndDestroy(view);
323 CleanupStack::PopAndDestroy(device);
324 CleanupStack::PopAndDestroy(layout);
325 CleanupStack::PopAndDestroy(scheduler);
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
338 void CTCustomCharMappingStep::RunDefaultBehaviourTestsL()
340 INFO_PRINTF1(_L(" @SYMTestCaseID:SYSLIB-FORM-CT-0148 "));
341 CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
342 CleanupStack::PushL(scheduler);
343 CActiveScheduler::Install(scheduler);
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);
359 // Start by making sure no custom remapper is installed
360 MFormCustomInvisibleCharacterRemapper* remapper;
361 remapper = layout->GetCustomInvisibleCharacterRemapper();
362 TEST(remapper == NULL);
364 // Set all invisible characters to be invisible
365 TNonPrintingCharVisibility visibility;
366 visibility.SetNoneVisible();
367 layout->SetNonPrintingCharsVisibility(visibility);
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);
373 // Now set all invisible characters to be visible
374 visibility.SetAllVisible();
375 layout->SetNonPrintingCharsVisibility(visibility);
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);
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);
398 CleanupStack::PopAndDestroy(offScreenContext);
399 CleanupStack::PopAndDestroy(view);
400 CleanupStack::PopAndDestroy(device);
401 CleanupStack::PopAndDestroy(layout);
402 CleanupStack::PopAndDestroy(scheduler);
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
414 void CTCustomCharMappingStep::RunCustomBehaviourTestsL()
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 "));
421 CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
422 CleanupStack::PushL(scheduler);
423 CActiveScheduler::Install(scheduler);
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);
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);
446 // Set all invisible characters to be invisible
447 TNonPrintingCharVisibility visibility;
448 visibility.SetNoneVisible();
449 layout->SetNonPrintingCharsVisibility(visibility);
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);
455 // Now set all invisible characters to be visible
456 visibility.SetAllVisible();
457 layout->SetNonPrintingCharsVisibility(visibility);
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);
463 // Now we are finished deinstall and delete it
464 layout->SetCustomInvisibleCharacterRemapper(NULL);
465 remapper = layout->GetCustomInvisibleCharacterRemapper();
466 TEST(remapper == NULL);
467 delete customRemapper;
469 CleanupStack::PopAndDestroy(offScreenContext);
470 CleanupStack::PopAndDestroy(view);
471 CleanupStack::PopAndDestroy(device);
472 CleanupStack::PopAndDestroy(layout);
473 CleanupStack::PopAndDestroy(scheduler);
477 CTCustomCharMappingStep::CTCustomCharMappingStep()
482 TVerdict CTCustomCharMappingStep::doTestStepL()
484 SetTestStepResult(EPass);
485 INFO_PRINTF1(_L("Test installation/deinstallatiion"));
486 TInt error = RFbsSession::Connect();
487 if (error == KErrNotFound)
490 error = RFbsSession::Connect();
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();