--- /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
+