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