diff -r 000000000000 -r 1fb32624e06b textrendering/textformatting/test/src/TCustomCharMapping.cpp --- /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 +#include +#include +#include +#include +#include +#include +#include + +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' 'Z' +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 +