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