fbs/fontandbitmapserver/tfbs/tglyphatlas.cpp
changeset 116 171fae344dd4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fbs/fontandbitmapserver/tfbs/tglyphatlas.cpp	Fri Jul 16 11:45:55 2010 +0300
@@ -0,0 +1,284 @@
+// Copyright (c) 2009-2010 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:
+//
+
+/**
+ @file
+ @internalComponent - Internal Symbian test code
+*/
+
+#include "tglyphatlas.h"
+#include "TFBS.H"
+#include "glyphatlastestwrapper.h"
+
+_LIT(KTypefaceName, "DejaVu Sans Condensed");
+_LIT(KMonoTypefaceName, "DejaVu Sans Mono");
+const TInt KNumGlyphCodesLatin = 96;
+
+
+CTGlyphAtlas::CTGlyphAtlas(CTestStep* aStep):
+	CTGraphicsBase(aStep),
+	iFbs(NULL),
+	iTs(NULL),
+	iGlyphCodesLatin(NULL),
+	iFont(NULL)
+	{
+	}
+
+void CTGlyphAtlas::ConstructL()
+	{
+	iFbs = RFbsSession::GetSession();
+	iTs = (CFbsTypefaceStore*)CFbsTypefaceStore::NewL(NULL);
+	User::LeaveIfError(iTs->GetNearestFontToDesignHeightInPixels((CFont*&)iFont, TFontSpec(KTypefaceName, 15)));
+	User::LeaveIfError(iTs->GetNearestFontToDesignHeightInPixels((CFont*&)iFont2, TFontSpec(KMonoTypefaceName, 8)));
+	
+	iGlyphCodesLatin = new(ELeave) TUint[KNumGlyphCodesLatin];
+	for (TInt ii = 0; ii < KNumGlyphCodesLatin; ++ii)
+		{
+		iGlyphCodesLatin[ii] = ii+32; // ASCII characters from 0020 to 007F
+		}
+
+	INFO_PRINTF1(_L("FBSERV Glyph Atlas Testing"));
+	}
+
+CTGlyphAtlas::~CTGlyphAtlas()
+	{
+	if (iTs)
+		{
+		iTs->ReleaseFont(iFont);
+		}
+	delete iTs;
+	delete[] iGlyphCodesLatin;
+	}
+
+void CTGlyphAtlas::RunTestCaseL(TInt aCurTestCase)
+	{
+	((CTGlyphAtlasStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName);
+	switch(aCurTestCase)
+		{
+	case 1:
+		((CTGlyphAtlasStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0663"));
+		TestFullCache();
+		break;
+	case 2:
+		((CTGlyphAtlasStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0664"));
+		TestFontReleased();
+		break;
+	default:
+		((CTGlyphAtlasStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName);
+		((CTGlyphAtlasStep*)iStep)->CloseTMSGraphicsStep();
+		TestComplete();		
+		break;
+		}
+	((CTGlyphAtlasStep*)iStep)->RecordTestResultL();
+	}
+
+/**
+@SYMTestCaseID		GRAPHICS-FBSERV-0663
+@SYMTestPriority	High
+@SYMTestType		UT
+@SYMTestStatus		Implemented
+@SYMPREQ			PREQ2678
+
+@SYMTestCaseDesc
+	Shows that when the glyph atlas reaches its memory limit, any new added 
+	glyphs will cause the eviction of the least recently used glyphs.
+	The new glyph will be added successfully.
+
+@SYMTestActions
+	i. Create a glyph atlas with a memory limit of 1000 bytes.
+	ii. Add glyphs to the atlas such that its memory consumption reaches the limit.
+	iii. Add one more glyph.
+	iv. Call CGlyphAtlas::GetGlyph() for the last glyph added.
+	v. Call CGlyphAtlas::GetGlyph() for the least recently used glyphs to check 
+		that it has been evicted.
+	vi. Delete glyph atlas
+
+@SYMTestExpectedResults
+	Each glyph is added successfully.
+	CGlyphAtlas::GetGlyph() returns KErrNone for the last glyph added.
+	CGlyphAtlas::GetGlyph() returns KErrNotFound for the least recently used glyph.
+*/
+void CTGlyphAtlas::TestFullCache()
+	{
+	INFO_PRINTF1(_L("Test full cache eviction"));
+
+	__UHEAP_MARK;
+	// Fill cache up using expected size of glyph using AddGlyph.
+	const TInt KMaxAtlasSizeInBytes = 1000;
+	CGlyphAtlasTestWrapper* atlas = NULL;
+	TRAPD(ret, atlas = CGlyphAtlasTestWrapper::NewL(KMaxAtlasSizeInBytes));
+	TESTNOERROR(ret);
+	if (KErrNone != ret)
+		{
+		return;
+		}
+	TOpenFontCharMetrics charMetrics;
+	TGlyphImageInfo imageInfo;
+	TSize bitmapSize;
+	const TUint8* bitmapData = NULL;
+	TInt glyphIndex = 0;
+	TBool atlasFull = EFalse;
+	CBitmapFont* bmFont = CTFbsFont::FontAddress(iFont);
+	// Fill up atlas by adding glyphs.
+	// Next glyph shold tip the atlas over the memory limit.
+	// Glyphs are added in ascending glyph code order.
+	// Leave at least one glyph so that we can guarantee that we can add one more unique glyph.
+	while (glyphIndex < KNumGlyphCodesLatin-1 && !atlasFull)
+		{
+		iFont->GetCharacterData(iGlyphCodesLatin[glyphIndex], charMetrics, bitmapData, bitmapSize);
+		TInt sizeInBytes = charMetrics.Height() * charMetrics.Width();
+		if (atlas->SizeInBytes() + sizeInBytes <= KMaxAtlasSizeInBytes)
+			{
+			CGlyphAtlas::TAddGlyphArgs args(bitmapData, iGlyphCodesLatin[glyphIndex++], charMetrics);
+			TESTNOERROR(atlas->AddGlyph(*bmFont, args, imageInfo));
+			}
+		else
+			{
+			atlasFull = ETrue;
+			}
+		}
+	TEST(atlasFull);
+
+	// check least recently used page contains the first glyph in glyph codes
+	TUint leastUsedGlyphCode = iGlyphCodesLatin[0];
+	TEST(atlas->LruPageContainsGlyph(leastUsedGlyphCode));
+
+	// To ensure that the test does not pass if a FIFO eviction policy occurs,
+	// get the least recently used glyph so that it is moved internally.
+	TESTNOERROR(atlas->GetGlyph(*bmFont, leastUsedGlyphCode, imageInfo));
+
+	// glyphIndex, bitmapData and charMetrics now current for next glyph which 
+	// will take the atlas over the cache limit.
+	CGlyphAtlas::TAddGlyphArgs args(bitmapData, iGlyphCodesLatin[glyphIndex], charMetrics);
+	TESTNOERROR(atlas->AddGlyph(*bmFont, args, imageInfo));
+
+	// check that searching for most recently added glyph is successful
+	TGlyphImageInfo newInfo;
+	TESTNOERROR(atlas->GetGlyph(*bmFont, iGlyphCodesLatin[glyphIndex], newInfo));
+
+	// check atlas size is still under the limit
+	TEST(atlas->SizeInBytes() <= KMaxAtlasSizeInBytes);
+
+	// check that the pages which were evicted contained the least used glyphs
+	// i.e. searching for these returns KErrNotFound
+	TInt err = KErrNotFound;
+	TInt index = 1;
+	for (; KErrNotFound == err && index <= glyphIndex; ++index)
+		{
+		err = atlas->GetGlyph(*bmFont, iGlyphCodesLatin[index], newInfo);
+		}
+	TESTNOERROR(err);
+	// first found glyph should be greater than glyph at index 1
+	TEST(index-1 > 1);
+	
+	// check that the remaining pages contained the least used glyphs
+	for (; index <= glyphIndex; ++index)
+		{
+		TESTNOERROR(atlas->GetGlyph(*bmFont, iGlyphCodesLatin[index], newInfo));
+		}
+
+	delete atlas;
+	__UHEAP_MARKEND;
+	}
+
+
+/**
+@SYMTestCaseID		GRAPHICS-FBSERV-0664
+@SYMTestPriority	High
+@SYMTestType		UT
+@SYMTestStatus		Implemented
+@SYMPREQ			PREQ2678
+
+@SYMTestCaseDesc
+	Shows that CGlyphAtlas::FontReleased() does actually delete all the glyphs 
+	associated with the released font and leaves glyphs associated with other 
+	fonts untouched.
+
+@SYMTestActions
+	i. Create a glyph atlas with no memory limit.
+	ii. Add glyphs for two different fonts to the atlas.
+	iii. Check all glyphs for both fonts were successfully added.
+	iv. Call CGlyphAtlas::ReleaseFont for one of the fonts.
+	v. Check that there are no glyphs associated with the released font.
+	vi. Call CGlyphAtlas::ReleaseFont for the remaining font.
+	vii Check that there are no glyphs associated with the released font and 
+		that the atlas is empty.
+	viii Delete the glyph atlas.
+	
+@SYMTestExpectedResults
+	After each font is released, there are no glyphs associated with that font 
+	left in the atlas.
+*/
+void CTGlyphAtlas::TestFontReleased()
+	{
+	INFO_PRINTF1(_L("Test behaviour of CGlyphAtlas::FontReleased()"));
+
+	__UHEAP_MARK;
+	CGlyphAtlasTestWrapper* atlas = NULL;
+	TRAPD(ret, atlas = CGlyphAtlasTestWrapper::NewL(KGlyphAtlasNoCacheLimit));
+	TESTNOERROR(ret);
+	if (KErrNone != ret)
+		{
+		return;
+		}
+	TOpenFontCharMetrics charMetrics;
+	TGlyphImageInfo imageInfo;
+	TSize bitmapSize;
+	const TUint8* bitmapData = NULL;
+	CBitmapFont* bmFont = CTFbsFont::FontAddress(iFont);
+	CBitmapFont* bmFont2 = CTFbsFont::FontAddress(iFont2);
+	for (TInt glyphIndex = 0; glyphIndex < KNumGlyphCodesLatin; ++glyphIndex)
+		{
+		iFont->GetCharacterData(iGlyphCodesLatin[glyphIndex], charMetrics, bitmapData, bitmapSize);
+		CGlyphAtlas::TAddGlyphArgs args(bitmapData, iGlyphCodesLatin[glyphIndex], charMetrics);
+		TESTNOERROR(atlas->AddGlyph(*bmFont, args, imageInfo));
+
+		iFont2->GetCharacterData(iGlyphCodesLatin[KNumGlyphCodesLatin-1-glyphIndex], charMetrics, bitmapData, bitmapSize);
+		CGlyphAtlas::TAddGlyphArgs args2(bitmapData, iGlyphCodesLatin[glyphIndex], charMetrics);
+		TESTNOERROR(atlas->AddGlyph(*bmFont2, args2, imageInfo));
+		}
+	// check there are font entries for these 2 fonts
+	TEST(2 == atlas->FontCount());
+
+	// check actual number of glyphs in atlas for each font is as expected
+	TEST(KNumGlyphCodesLatin == atlas->GlyphCountByFont(bmFont));
+	TEST(KNumGlyphCodesLatin == atlas->GlyphCountByFont(bmFont2));
+	TEST(2*KNumGlyphCodesLatin == atlas->GlyphCount());
+
+	// release one font and check number of glyphs in atlas for each font 
+	// is as expected
+	atlas->FontReleased(*bmFont);
+	TEST(1 == atlas->FontCount());
+	TEST(0 == atlas->GlyphCountByFont(bmFont));
+	TEST(KNumGlyphCodesLatin == atlas->GlyphCountByFont(bmFont2));
+	TEST(KNumGlyphCodesLatin == atlas->GlyphCount());
+
+	// release one font and check number of glyphs in atlas for each font 
+	// is as expected
+	atlas->FontReleased(*bmFont2);
+	TEST(0 == atlas->FontCount());
+	TEST(0 == atlas->GlyphCountByFont(bmFont));
+	TEST(0 == atlas->GlyphCountByFont(bmFont2));
+	TEST(0 == atlas->GlyphCount());
+
+	delete atlas;
+
+	__UHEAP_MARKEND;
+	}
+
+
+
+//--------------
+__CONSTRUCT_STEP__(GlyphAtlas)